• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <rpc/rpc.h>
2 #include <arpa/inet.h>
3 #include <errno.h>
4 #include <debug.h>
5 
6 extern int r_open(const char *router);
7 extern void r_close(int handle);
8 extern int r_read(int handle, char *buf, uint32 size);
9 extern int r_write(int handle, const char *buf, uint32 size);
10 extern int r_control(int handle, const uint32 cmd, void *arg);
11 
xdr_std_destroy(xdr_s_type * xdr)12 static void xdr_std_destroy(xdr_s_type *xdr)
13 {
14     /* whatever */
15 }
16 
xdr_std_control(xdr_s_type * xdr,int request,void * info)17 static bool_t xdr_std_control(xdr_s_type *xdr, int request, void *info)
18 {
19     return r_control(xdr->fd, request, info);
20 }
21 
xdr_std_msg_done(xdr_s_type * xdr)22 static bool_t xdr_std_msg_done(xdr_s_type *xdr)
23 {
24     /* whatever */
25     return TRUE;
26 }
27 
28 /* Outgoing message control functions */
xdr_std_msg_start(xdr_s_type * xdr,rpc_msg_e_type rpc_msg_type)29 static bool_t xdr_std_msg_start(xdr_s_type *xdr,
30                                  rpc_msg_e_type rpc_msg_type)
31 {
32 
33     /* xid is does not matter under our set of assumptions: that for a single
34      * program/version channel, communication is synchronous.  If several
35      * processes attempt to call functions on a program, then the rpcrouter
36      * driver will ensure that the calls are properly muxed, because the
37      * processes will have separate PIDs, and the rpcrouter driver uses PIDs to
38      * keep track of RPC transactions.  For multiple threads in the same
39      * process accessing the same program, we serialize access in clnt_call()
40      * by locking a mutex around the RPC call.  If threads in the same process
41      * call into different programs, then there is no issue, again because of
42      * the use of a mutex in clnt_call().
43      *
44      * NOTE: This comment assumes that the only way we talk to the RPC router
45      *       from a client is by using clnt_call(), which is the case for all
46      *       client code generated by rpcgen().
47      *
48      * NOTE: The RPC router driver will soon be able to open a separate device
49      *       file for each program/version channel.  This will allow for
50      *       natural multiplexing among clients, as we won't have to rely on
51      *       the mutex for the case where different programs are being called
52      *       into by separate threads in the same process.  When this happens,
53      *       we'll need to optimize the RPC library to add a separate mutex for
54      *       each program/version channel, which will require some sort of
55      *       registry.
56      */
57 
58     if (rpc_msg_type == RPC_MSG_CALL) xdr->xid++;
59 
60     /* We start writing into the outgoing-message buffer at index 32, because
61        we need to write header information before we send the message.  The
62        header information includes the destination address and the pacmark
63        header.
64     */
65     xdr->out_next = (RPC_OFFSET+2)*sizeof(uint32);
66 
67     /* we write the pacmark header when we send the message. */
68     ((uint32 *)xdr->out_msg)[RPC_OFFSET] = htonl(xdr->xid);
69     /* rpc call or reply? */
70     ((uint32 *)xdr->out_msg)[RPC_OFFSET+1] = htonl(rpc_msg_type);
71 
72     return TRUE;
73 }
74 
xdr_std_msg_abort(xdr_s_type * xdr)75 static bool_t xdr_std_msg_abort(xdr_s_type *xdr)
76 {
77     /* dummy */
78     return TRUE;
79 }
80 
81 /* Can be used to send both calls and replies. */
82 
83 extern bool_t xdr_recv_reply_header(xdr_s_type *xdr, rpc_reply_header *reply);
84 
85 #include <stdio.h>
86 
xdr_std_msg_send(xdr_s_type * xdr)87 static bool_t xdr_std_msg_send(xdr_s_type *xdr)
88 {
89     /* Send the RPC packet. */
90     if (r_write(xdr->fd, (void *)xdr->out_msg, xdr->out_next) !=
91             xdr->out_next)
92         return FALSE;
93 
94     return TRUE;
95 }
96 
xdr_std_read(xdr_s_type * xdr)97 static bool_t xdr_std_read(xdr_s_type *xdr)
98 {
99     xdr->in_len = r_read(xdr->fd, (void *)xdr->in_msg, RPCROUTER_MSGSIZE_MAX);
100     if (xdr->in_len < 0) return FALSE;
101 
102     if (xdr->in_len < (RPC_OFFSET+2)*4) {
103         xdr->in_len = -1;
104         return FALSE;
105     }
106 
107     xdr->in_next = (RPC_OFFSET+2)*4;
108     return TRUE;
109 }
110 
111 /* Message data functions */
xdr_std_send_uint32(xdr_s_type * xdr,const uint32 * value)112 static bool_t xdr_std_send_uint32(xdr_s_type *xdr, const uint32 *value)
113 {
114     if (xdr->out_next >= RPCROUTER_MSGSIZE_MAX - 3) return FALSE;
115     *(int32 *)(xdr->out_msg + xdr->out_next) = htonl(*value);
116     xdr->out_next += 4;
117     return TRUE;
118 }
119 
xdr_std_send_int8(xdr_s_type * xdr,const int8 * value)120 static bool_t xdr_std_send_int8(xdr_s_type *xdr, const int8 *value)
121 {
122     uint32 val = *value;
123     return xdr_std_send_uint32(xdr, &val);
124 }
125 
xdr_std_send_uint8(xdr_s_type * xdr,const uint8 * value)126 static bool_t xdr_std_send_uint8(xdr_s_type *xdr, const uint8 *value)
127 {
128     uint32 val = *value;
129     return xdr_std_send_uint32(xdr, &val);
130 }
131 
xdr_std_send_int16(xdr_s_type * xdr,const int16 * value)132 static bool_t xdr_std_send_int16(xdr_s_type *xdr, const int16 *value)
133 {
134     uint32 val = *value;
135     return xdr_std_send_uint32(xdr, &val);
136 }
137 
xdr_std_send_uint16(xdr_s_type * xdr,const uint16 * value)138 static bool_t xdr_std_send_uint16(xdr_s_type *xdr, const uint16 *value)
139 {
140     uint32 val = *value;
141     return xdr_std_send_uint32(xdr, &val);
142 }
143 
xdr_std_send_int32(xdr_s_type * xdr,const int32 * value)144 static bool_t xdr_std_send_int32(xdr_s_type *xdr, const int32 *value)
145 {
146     return xdr_std_send_uint32(xdr, (uint32_t *)value);
147 }
148 
xdr_std_send_bytes(xdr_s_type * xdr,const uint8 * buf,uint32 len)149 static bool_t xdr_std_send_bytes(xdr_s_type *xdr, const uint8 *buf,
150                                    uint32 len)
151 {
152     if (xdr->out_next + len > RPCROUTER_MSGSIZE_MAX) return FALSE;
153     while(len--)
154         xdr->out_msg[xdr->out_next++] = *buf++;
155     while(xdr->out_next % 4)
156         xdr->out_msg[xdr->out_next++] = 0;
157     return TRUE;
158 }
159 
160 #if 0
161 #include <unwind.h>
162 typedef struct
163 {
164     size_t count;
165     intptr_t* addrs;
166 } stack_crawl_state_t;
167 
168 static _Unwind_Reason_Code trace_function(_Unwind_Context *context, void *arg)
169 {
170     stack_crawl_state_t* state = (stack_crawl_state_t*)arg;
171     if (state->count) {
172         intptr_t ip = (intptr_t)_Unwind_GetIP(context);
173         if (ip) {
174             state->addrs[0] = ip;
175             state->addrs++;
176             state->count--;
177         }
178     }
179     return _URC_NO_REASON;
180 }
181 
182 static inline
183 int get_backtrace(intptr_t* addrs, size_t max_entries)
184 {
185     stack_crawl_state_t state;
186     state.count = max_entries;
187     state.addrs = (intptr_t*)addrs;
188     _Unwind_Backtrace(trace_function, (void*)&state);
189     return max_entries - state.count;
190 }
191 #endif
192 
xdr_std_recv_uint32(xdr_s_type * xdr,uint32 * value)193 static bool_t xdr_std_recv_uint32(xdr_s_type *xdr, uint32 *value)
194 {
195 #if 0
196     intptr_t *trace[20], *tr;
197     int nc = get_backtrace(trace, 20);
198     tr = trace;
199     while(nc--)
200         D("\t%02d: %p\n", nc, *tr++);
201 #endif
202 
203     if (xdr->in_next + 4 > xdr->in_len) { return FALSE; }
204     if (value) *value = ntohl(*(uint32 *)(xdr->in_msg + xdr->in_next));
205     xdr->in_next += 4;
206     return TRUE;
207 }
208 
209 #define RECEIVE                                 \
210     uint32 val;                                 \
211     if (xdr_std_recv_uint32(xdr, &val)) {       \
212         *value = val;                           \
213         return TRUE;                            \
214     }                                           \
215     return FALSE
216 
xdr_std_recv_int8(xdr_s_type * xdr,int8 * value)217 static bool_t xdr_std_recv_int8(xdr_s_type *xdr, int8 *value)
218 {
219     RECEIVE;
220 }
221 
xdr_std_recv_uint8(xdr_s_type * xdr,uint8 * value)222 static bool_t xdr_std_recv_uint8(xdr_s_type *xdr, uint8 *value)
223 {
224     RECEIVE;
225 }
226 
xdr_std_recv_int16(xdr_s_type * xdr,int16 * value)227 static bool_t xdr_std_recv_int16(xdr_s_type *xdr, int16 *value)
228 {
229     RECEIVE;
230 }
231 
xdr_std_recv_uint16(xdr_s_type * xdr,uint16 * value)232 static bool_t xdr_std_recv_uint16(xdr_s_type *xdr, uint16 *value)
233 {
234     RECEIVE;
235 }
236 
237 #undef RECEIVE
238 
xdr_std_recv_int32(xdr_s_type * xdr,int32 * value)239 static bool_t xdr_std_recv_int32(xdr_s_type *xdr, int32 *value)
240 {
241     return xdr_std_recv_uint32(xdr, (uint32 * )value);
242 }
243 
xdr_std_recv_bytes(xdr_s_type * xdr,uint8 * buf,uint32 len)244 static bool_t xdr_std_recv_bytes(xdr_s_type *xdr, uint8 *buf, uint32 len)
245 {
246     if (xdr->in_next + (int)len > xdr->in_len) return FALSE;
247     if (buf) memcpy(buf, &xdr->in_msg[xdr->in_next], len);
248     xdr->in_next += len;
249     xdr->in_next = (xdr->in_next + 3) & ~3;
250     return TRUE;
251 }
252 
253 const xdr_ops_s_type xdr_std_xops = {
254 
255     xdr_std_destroy,
256     xdr_std_control,
257     xdr_std_read,
258     xdr_std_msg_done,
259     xdr_std_msg_start,
260     xdr_std_msg_abort,
261     xdr_std_msg_send,
262 
263     xdr_std_send_int8,
264     xdr_std_send_uint8,
265     xdr_std_send_int16,
266     xdr_std_send_uint16,
267     xdr_std_send_int32,
268     xdr_std_send_uint32,
269     xdr_std_send_bytes,
270     xdr_std_recv_int8,
271     xdr_std_recv_uint8,
272     xdr_std_recv_int16,
273     xdr_std_recv_uint16,
274     xdr_std_recv_int32,
275     xdr_std_recv_uint32,
276     xdr_std_recv_bytes,
277 };
278 
xdr_init_common(const char * router,int is_client)279 xdr_s_type *xdr_init_common(const char *router, int is_client)
280 {
281     xdr_s_type *xdr = (xdr_s_type *)calloc(1, sizeof(xdr_s_type));
282 
283     xdr->xops = &xdr_std_xops;
284 
285     xdr->fd = r_open(router);
286     if (xdr->fd < 0) {
287         E("ERROR OPENING [%s]: %s\n", router, strerror(errno));
288         free(xdr);
289         return NULL;
290     }
291     xdr->is_client = is_client;
292 
293     D("OPENED [%s] fd %d\n", router, xdr->fd);
294     return xdr;
295 }
296 
xdr_clone(xdr_s_type * other)297 xdr_s_type *xdr_clone(xdr_s_type *other)
298 {
299     xdr_s_type *xdr = (xdr_s_type *)calloc(1, sizeof(xdr_s_type));
300 
301     xdr->xops = &xdr_std_xops;
302 
303     xdr->fd = dup(other->fd);
304     if (xdr->fd < 0) {
305         E("ERROR DUPLICATING FD %d: %s\n", other->fd, strerror(errno));
306         free(xdr);
307         return NULL;
308     }
309 
310     xdr->xid = xdr->xid;
311     xdr->x_prog = other->x_prog;
312     xdr->x_vers = other->x_vers;
313     xdr->is_client = other->is_client;
314 
315     D("CLONED fd %d --> %d\n", other->fd, xdr->fd);
316     return xdr;
317 }
318 
xdr_destroy_common(xdr_s_type * xdr)319 void xdr_destroy_common(xdr_s_type *xdr)
320 {
321     D("CLOSING fd %d\n", xdr->fd);
322     r_close(xdr->fd);
323     free(xdr);
324 }
325