Home | History | Annotate | Download | only in librpc
      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 
     12 static void xdr_std_destroy(xdr_s_type *xdr)
     13 {
     14     /* whatever */
     15 }
     16 
     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 
     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 */
     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 
     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 
     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 
     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 */
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    217 static bool_t xdr_std_recv_int8(xdr_s_type *xdr, int8 *value)
    218 {
    219     RECEIVE;
    220 }
    221 
    222 static bool_t xdr_std_recv_uint8(xdr_s_type *xdr, uint8 *value)
    223 {
    224     RECEIVE;
    225 }
    226 
    227 static bool_t xdr_std_recv_int16(xdr_s_type *xdr, int16 *value)
    228 {
    229     RECEIVE;
    230 }
    231 
    232 static bool_t xdr_std_recv_uint16(xdr_s_type *xdr, uint16 *value)
    233 {
    234     RECEIVE;
    235 }
    236 
    237 #undef RECEIVE
    238 
    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 
    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 
    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 
    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 
    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