| #include <rpc/rpc.h> |
| #include <arpa/inet.h> |
| #include <errno.h> |
| #include <debug.h> |
| |
| extern int r_open(const char *router); |
| extern void r_close(int handle); |
| extern int r_read(int handle, char *buf, uint32 size); |
| extern int r_write(int handle, const char *buf, uint32 size); |
| extern int r_control(int handle, const uint32 cmd, void *arg); |
| |
| static void xdr_std_destroy(xdr_s_type *xdr) |
| { |
| /* whatever */ |
| } |
| |
| static bool_t xdr_std_control(xdr_s_type *xdr, int request, void *info) |
| { |
| return r_control(xdr->fd, request, info); |
| } |
| |
| static bool_t xdr_std_msg_done(xdr_s_type *xdr) |
| { |
| /* whatever */ |
| return TRUE; |
| } |
| |
| /* Outgoing message control functions */ |
| static bool_t xdr_std_msg_start(xdr_s_type *xdr, |
| rpc_msg_e_type rpc_msg_type) |
| { |
| |
| /* xid is does not matter under our set of assumptions: that for a single |
| * program/version channel, communication is synchronous. If several |
| * processes attempt to call functions on a program, then the rpcrouter |
| * driver will ensure that the calls are properly muxed, because the |
| * processes will have separate PIDs, and the rpcrouter driver uses PIDs to |
| * keep track of RPC transactions. For multiple threads in the same |
| * process accessing the same program, we serialize access in clnt_call() |
| * by locking a mutex around the RPC call. If threads in the same process |
| * call into different programs, then there is no issue, again because of |
| * the use of a mutex in clnt_call(). |
| * |
| * NOTE: This comment assumes that the only way we talk to the RPC router |
| * from a client is by using clnt_call(), which is the case for all |
| * client code generated by rpcgen(). |
| * |
| * NOTE: The RPC router driver will soon be able to open a separate device |
| * file for each program/version channel. This will allow for |
| * natural multiplexing among clients, as we won't have to rely on |
| * the mutex for the case where different programs are being called |
| * into by separate threads in the same process. When this happens, |
| * we'll need to optimize the RPC library to add a separate mutex for |
| * each program/version channel, which will require some sort of |
| * registry. |
| */ |
| |
| if (rpc_msg_type == RPC_MSG_CALL) xdr->xid++; |
| |
| /* We start writing into the outgoing-message buffer at index 32, because |
| we need to write header information before we send the message. The |
| header information includes the destination address and the pacmark |
| header. |
| */ |
| xdr->out_next = (RPC_OFFSET+2)*sizeof(uint32); |
| |
| /* we write the pacmark header when we send the message. */ |
| ((uint32 *)xdr->out_msg)[RPC_OFFSET] = htonl(xdr->xid); |
| /* rpc call or reply? */ |
| ((uint32 *)xdr->out_msg)[RPC_OFFSET+1] = htonl(rpc_msg_type); |
| |
| return TRUE; |
| } |
| |
| static bool_t xdr_std_msg_abort(xdr_s_type *xdr) |
| { |
| /* dummy */ |
| return TRUE; |
| } |
| |
| /* Can be used to send both calls and replies. */ |
| |
| extern bool_t xdr_recv_reply_header(xdr_s_type *xdr, rpc_reply_header *reply); |
| |
| #include <stdio.h> |
| |
| static bool_t xdr_std_msg_send(xdr_s_type *xdr) |
| { |
| /* Send the RPC packet. */ |
| if (r_write(xdr->fd, (void *)xdr->out_msg, xdr->out_next) != |
| xdr->out_next) |
| return FALSE; |
| |
| return TRUE; |
| } |
| |
| static bool_t xdr_std_read(xdr_s_type *xdr) |
| { |
| xdr->in_len = r_read(xdr->fd, (void *)xdr->in_msg, RPCROUTER_MSGSIZE_MAX); |
| if (xdr->in_len < 0) return FALSE; |
| |
| if (xdr->in_len < (RPC_OFFSET+2)*4) { |
| xdr->in_len = -1; |
| return FALSE; |
| } |
| |
| xdr->in_next = (RPC_OFFSET+2)*4; |
| return TRUE; |
| } |
| |
| /* Message data functions */ |
| static bool_t xdr_std_send_uint32(xdr_s_type *xdr, const uint32 *value) |
| { |
| if (xdr->out_next >= RPCROUTER_MSGSIZE_MAX - 3) return FALSE; |
| *(int32 *)(xdr->out_msg + xdr->out_next) = htonl(*value); |
| xdr->out_next += 4; |
| return TRUE; |
| } |
| |
| static bool_t xdr_std_send_int8(xdr_s_type *xdr, const int8 *value) |
| { |
| uint32 val = *value; |
| return xdr_std_send_uint32(xdr, &val); |
| } |
| |
| static bool_t xdr_std_send_uint8(xdr_s_type *xdr, const uint8 *value) |
| { |
| uint32 val = *value; |
| return xdr_std_send_uint32(xdr, &val); |
| } |
| |
| static bool_t xdr_std_send_int16(xdr_s_type *xdr, const int16 *value) |
| { |
| uint32 val = *value; |
| return xdr_std_send_uint32(xdr, &val); |
| } |
| |
| static bool_t xdr_std_send_uint16(xdr_s_type *xdr, const uint16 *value) |
| { |
| uint32 val = *value; |
| return xdr_std_send_uint32(xdr, &val); |
| } |
| |
| static bool_t xdr_std_send_int32(xdr_s_type *xdr, const int32 *value) |
| { |
| return xdr_std_send_uint32(xdr, (uint32_t *)value); |
| } |
| |
| static bool_t xdr_std_send_bytes(xdr_s_type *xdr, const uint8 *buf, |
| uint32 len) |
| { |
| if (xdr->out_next + len > RPCROUTER_MSGSIZE_MAX) return FALSE; |
| while(len--) |
| xdr->out_msg[xdr->out_next++] = *buf++; |
| while(xdr->out_next % 4) |
| xdr->out_msg[xdr->out_next++] = 0; |
| return TRUE; |
| } |
| |
| #if 0 |
| #include <unwind.h> |
| typedef struct |
| { |
| size_t count; |
| intptr_t* addrs; |
| } stack_crawl_state_t; |
| |
| static _Unwind_Reason_Code trace_function(_Unwind_Context *context, void *arg) |
| { |
| stack_crawl_state_t* state = (stack_crawl_state_t*)arg; |
| if (state->count) { |
| intptr_t ip = (intptr_t)_Unwind_GetIP(context); |
| if (ip) { |
| state->addrs[0] = ip; |
| state->addrs++; |
| state->count--; |
| } |
| } |
| return _URC_NO_REASON; |
| } |
| |
| static inline |
| int get_backtrace(intptr_t* addrs, size_t max_entries) |
| { |
| stack_crawl_state_t state; |
| state.count = max_entries; |
| state.addrs = (intptr_t*)addrs; |
| _Unwind_Backtrace(trace_function, (void*)&state); |
| return max_entries - state.count; |
| } |
| #endif |
| |
| static bool_t xdr_std_recv_uint32(xdr_s_type *xdr, uint32 *value) |
| { |
| #if 0 |
| intptr_t *trace[20], *tr; |
| int nc = get_backtrace(trace, 20); |
| tr = trace; |
| while(nc--) |
| D("\t%02d: %p\n", nc, *tr++); |
| #endif |
| |
| if (xdr->in_next + 4 > xdr->in_len) { return FALSE; } |
| if (value) *value = ntohl(*(uint32 *)(xdr->in_msg + xdr->in_next)); |
| xdr->in_next += 4; |
| return TRUE; |
| } |
| |
| #define RECEIVE \ |
| uint32 val; \ |
| if (xdr_std_recv_uint32(xdr, &val)) { \ |
| *value = val; \ |
| return TRUE; \ |
| } \ |
| return FALSE |
| |
| static bool_t xdr_std_recv_int8(xdr_s_type *xdr, int8 *value) |
| { |
| RECEIVE; |
| } |
| |
| static bool_t xdr_std_recv_uint8(xdr_s_type *xdr, uint8 *value) |
| { |
| RECEIVE; |
| } |
| |
| static bool_t xdr_std_recv_int16(xdr_s_type *xdr, int16 *value) |
| { |
| RECEIVE; |
| } |
| |
| static bool_t xdr_std_recv_uint16(xdr_s_type *xdr, uint16 *value) |
| { |
| RECEIVE; |
| } |
| |
| #undef RECEIVE |
| |
| static bool_t xdr_std_recv_int32(xdr_s_type *xdr, int32 *value) |
| { |
| return xdr_std_recv_uint32(xdr, (uint32 * )value); |
| } |
| |
| static bool_t xdr_std_recv_bytes(xdr_s_type *xdr, uint8 *buf, uint32 len) |
| { |
| if (xdr->in_next + (int)len > xdr->in_len) return FALSE; |
| if (buf) memcpy(buf, &xdr->in_msg[xdr->in_next], len); |
| xdr->in_next += len; |
| xdr->in_next = (xdr->in_next + 3) & ~3; |
| return TRUE; |
| } |
| |
| const xdr_ops_s_type xdr_std_xops = { |
| |
| xdr_std_destroy, |
| xdr_std_control, |
| xdr_std_read, |
| xdr_std_msg_done, |
| xdr_std_msg_start, |
| xdr_std_msg_abort, |
| xdr_std_msg_send, |
| |
| xdr_std_send_int8, |
| xdr_std_send_uint8, |
| xdr_std_send_int16, |
| xdr_std_send_uint16, |
| xdr_std_send_int32, |
| xdr_std_send_uint32, |
| xdr_std_send_bytes, |
| xdr_std_recv_int8, |
| xdr_std_recv_uint8, |
| xdr_std_recv_int16, |
| xdr_std_recv_uint16, |
| xdr_std_recv_int32, |
| xdr_std_recv_uint32, |
| xdr_std_recv_bytes, |
| }; |
| |
| xdr_s_type *xdr_init_common(const char *router, int is_client) |
| { |
| xdr_s_type *xdr = (xdr_s_type *)calloc(1, sizeof(xdr_s_type)); |
| |
| xdr->xops = &xdr_std_xops; |
| |
| xdr->fd = r_open(router); |
| if (xdr->fd < 0) { |
| E("ERROR OPENING [%s]: %s\n", router, strerror(errno)); |
| free(xdr); |
| return NULL; |
| } |
| xdr->is_client = is_client; |
| |
| D("OPENED [%s] fd %d\n", router, xdr->fd); |
| return xdr; |
| } |
| |
| xdr_s_type *xdr_clone(xdr_s_type *other) |
| { |
| xdr_s_type *xdr = (xdr_s_type *)calloc(1, sizeof(xdr_s_type)); |
| |
| xdr->xops = &xdr_std_xops; |
| |
| xdr->fd = dup(other->fd); |
| if (xdr->fd < 0) { |
| E("ERROR DUPLICATING FD %d: %s\n", other->fd, strerror(errno)); |
| free(xdr); |
| return NULL; |
| } |
| |
| xdr->xid = xdr->xid; |
| xdr->x_prog = other->x_prog; |
| xdr->x_vers = other->x_vers; |
| xdr->is_client = other->is_client; |
| |
| D("CLONED fd %d --> %d\n", other->fd, xdr->fd); |
| return xdr; |
| } |
| |
| void xdr_destroy_common(xdr_s_type *xdr) |
| { |
| D("CLOSING fd %d\n", xdr->fd); |
| r_close(xdr->fd); |
| free(xdr); |
| } |