1#include <rpc/rpc.h>
2#include <arpa/inet.h>
3#include <errno.h>
4#include <debug.h>
5
6extern int r_open(const char *router);
7extern void r_close(int handle);
8extern int r_read(int handle, char *buf, uint32 size);
9extern int r_write(int handle, const char *buf, uint32 size);
10extern int r_control(int handle, const uint32 cmd, void *arg);
11
12static void xdr_std_destroy(xdr_s_type *xdr)
13{
14    /* whatever */
15}
16
17static bool_t xdr_std_control(xdr_s_type *xdr, int request, void *info)
18{
19    return r_control(xdr->fd, request, info);
20}
21
22static bool_t xdr_std_msg_done(xdr_s_type *xdr)
23{
24    /* whatever */
25    return TRUE;
26}
27
28/* Outgoing message control functions */
29static 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
75static 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
83extern bool_t xdr_recv_reply_header(xdr_s_type *xdr, rpc_reply_header *reply);
84
85#include <stdio.h>
86
87static 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
97static 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 */
112static 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
120static 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
126static 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
132static 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
138static 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
144static 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
149static 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>
162typedef struct
163{
164    size_t count;
165    intptr_t* addrs;
166} stack_crawl_state_t;
167
168static _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
182static inline
183int 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
193static 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
217static bool_t xdr_std_recv_int8(xdr_s_type *xdr, int8 *value)
218{
219    RECEIVE;
220}
221
222static bool_t xdr_std_recv_uint8(xdr_s_type *xdr, uint8 *value)
223{
224    RECEIVE;
225}
226
227static bool_t xdr_std_recv_int16(xdr_s_type *xdr, int16 *value)
228{
229    RECEIVE;
230}
231
232static bool_t xdr_std_recv_uint16(xdr_s_type *xdr, uint16 *value)
233{
234    RECEIVE;
235}
236
237#undef RECEIVE
238
239static bool_t xdr_std_recv_int32(xdr_s_type *xdr, int32 *value)
240{
241    return xdr_std_recv_uint32(xdr, (uint32 * )value);
242}
243
244static 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
253const 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
279xdr_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
297xdr_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
319void 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