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