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