|
|
1.1 ! root 1: /* ! 2: * Sun RPC is a product of Sun Microsystems, Inc. and is provided for ! 3: * unrestricted use provided that this legend is included on all tape ! 4: * media and as a part of the software program in whole or part. Users ! 5: * may copy or modify Sun RPC without charge, but are not authorized ! 6: * to license or distribute it to anyone else except as part of a product or ! 7: * program developed by the user. ! 8: * ! 9: * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE ! 10: * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR ! 11: * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. ! 12: * ! 13: * Sun RPC is provided with no support and without any obligation on the ! 14: * part of Sun Microsystems, Inc. to assist in its use, correction, ! 15: * modification or enhancement. ! 16: * ! 17: * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE ! 18: * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC ! 19: * OR ANY PART THEREOF. ! 20: * ! 21: * In no event will Sun Microsystems, Inc. be liable for any lost revenue ! 22: * or profits or other special, indirect and consequential damages, even if ! 23: * Sun has been advised of the possibility of such damages. ! 24: * ! 25: * Sun Microsystems, Inc. ! 26: * 2550 Garcia Avenue ! 27: * Mountain View, California 94043 ! 28: */ ! 29: #ifndef lint ! 30: static char sccsid[] = "@(#)clnt_udp.c 1.5 85/03/17 Copyr 1984 Sun Micro"; ! 31: #endif ! 32: ! 33: /* ! 34: * clnt_udp.c, Implements a UPD/IP based, client side RPC. ! 35: * ! 36: * Copyright (C) 1984, Sun Microsystems, Inc. ! 37: */ ! 38: ! 39: #include <stdio.h> ! 40: #include "types.h" ! 41: #include <sys/socket.h> ! 42: #include <sys/time.h> ! 43: #include <netinet/in.h> ! 44: #include <netdb.h> ! 45: #include <errno.h> ! 46: #include "xdr.h" ! 47: #include "auth.h" ! 48: #include "clnt.h" ! 49: #include "rpc_msg.h" ! 50: #include "pmap_clnt.h" ! 51: ! 52: char *malloc(); ! 53: extern int errno; ! 54: long random(); ! 55: ! 56: /* ! 57: * UDP bases client side rpc operations ! 58: */ ! 59: static enum clnt_stat clntudp_call(); ! 60: static void clntudp_abort(); ! 61: static void clntudp_geterr(); ! 62: static bool_t clntudp_freeres(); ! 63: static void clntudp_destroy(); ! 64: ! 65: static struct clnt_ops udp_ops = { ! 66: clntudp_call, ! 67: clntudp_abort, ! 68: clntudp_geterr, ! 69: clntudp_freeres, ! 70: clntudp_destroy ! 71: }; ! 72: ! 73: /* ! 74: * Private data kept per client handle ! 75: */ ! 76: struct cu_data { ! 77: int cu_sock; ! 78: struct sockaddr_in cu_raddr; ! 79: int cu_rlen; ! 80: struct timeval cu_wait; ! 81: struct rpc_err cu_error; ! 82: XDR cu_outxdrs; ! 83: u_int cu_xdrpos; ! 84: char cu_outbuf[UDPMSGSIZE]; ! 85: char cu_inbuf[UDPMSGSIZE]; ! 86: }; ! 87: ! 88: /* ! 89: * Create a UDP based client handle. ! 90: * If *sockp<0, *sockp is set to a newly created UPD socket. ! 91: * If raddr->sin_port is 0 a binder on the remote machine ! 92: * is consulted for the correct port number. ! 93: * NB: It is the clients responsibility to close *sockp. ! 94: * NB: The rpch->cl_auth is initialized to null authentication. ! 95: * Caller may wish to set this something more useful. ! 96: * ! 97: * wait is the amount of time used between retransmitting a call if ! 98: * no response has been heard; retransmition occurs until the actual ! 99: * rpc call times out. ! 100: */ ! 101: CLIENT * ! 102: clntudp_create(raddr, program, version, wait, sockp) ! 103: struct sockaddr_in *raddr; ! 104: u_long program; ! 105: u_long version; ! 106: struct timeval wait; ! 107: register int *sockp; ! 108: { ! 109: CLIENT *cl; ! 110: register struct cu_data *cu; ! 111: struct timeval now; ! 112: struct rpc_msg call_msg; ! 113: ! 114: cl = (CLIENT *)mem_alloc(sizeof(CLIENT)); ! 115: if (cl == NULL) { ! 116: fprintf(stderr, "clntudp_create: out of memory\n"); ! 117: rpc_createerr.cf_stat = RPC_SYSTEMERROR; ! 118: rpc_createerr.cf_error.re_errno = errno; ! 119: goto fooy; ! 120: } ! 121: cu = (struct cu_data *)mem_alloc(sizeof(*cu)); ! 122: if (cu == NULL) { ! 123: fprintf(stderr, "clntudp_create: out of memory\n"); ! 124: rpc_createerr.cf_stat = RPC_SYSTEMERROR; ! 125: rpc_createerr.cf_error.re_errno = errno; ! 126: goto fooy; ! 127: } ! 128: ! 129: (void)gettimeofday(&now, (struct timezone *)0); ! 130: if (raddr->sin_port == 0) { ! 131: u_short port; ! 132: if ((port = ! 133: pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) { ! 134: goto fooy; ! 135: } ! 136: raddr->sin_port = htons(port); ! 137: } ! 138: cl->cl_ops = &udp_ops; ! 139: cl->cl_private = (caddr_t)cu; ! 140: cu->cu_raddr = *raddr; ! 141: cu->cu_rlen = sizeof (cu->cu_raddr); ! 142: cu->cu_wait = wait; ! 143: call_msg.rm_xid = getpid() ^ (int)random() ^ now.tv_sec ^ now.tv_usec; ! 144: call_msg.rm_direction = CALL; ! 145: call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; ! 146: call_msg.rm_call.cb_prog = program; ! 147: call_msg.rm_call.cb_vers = version; ! 148: xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, ! 149: UDPMSGSIZE, XDR_ENCODE); ! 150: if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { ! 151: goto fooy; ! 152: } ! 153: cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); ! 154: cu->cu_sock = (*sockp < 0) ? ! 155: (*sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) : ! 156: *sockp; ! 157: if (cu->cu_sock < 0) { ! 158: rpc_createerr.cf_stat = RPC_SYSTEMERROR; ! 159: rpc_createerr.cf_error.re_errno = errno; ! 160: goto fooy; ! 161: } ! 162: cl->cl_auth = authnone_create(); ! 163: return (cl); ! 164: fooy: ! 165: mem_free((caddr_t)cu, sizeof(*cu)); ! 166: mem_free((caddr_t)cl, sizeof(CLIENT)); ! 167: return ((CLIENT *)NULL); ! 168: } ! 169: ! 170: static enum clnt_stat ! 171: clntudp_call(cl, proc, xargs, argsp, xresults, resultsp, timeout) ! 172: register CLIENT *cl; /* client handle */ ! 173: u_long proc; /* procedure number */ ! 174: xdrproc_t xargs; /* xdr routine for args */ ! 175: caddr_t argsp; /* pointer to args */ ! 176: xdrproc_t xresults; /* xdr routine for results */ ! 177: caddr_t resultsp; /* pointer to results */ ! 178: struct timeval timeout; /* seconds to wait before giving up */ ! 179: { ! 180: register struct cu_data *cu = (struct cu_data *)cl->cl_private; ! 181: register XDR *xdrs; ! 182: register int outlen; ! 183: register int inlen; ! 184: int readfds, fromlen; ! 185: register int mask; ! 186: struct sockaddr_in from; ! 187: struct rpc_msg reply_msg; ! 188: XDR reply_xdrs; ! 189: struct timeval time_waited; ! 190: bool_t ok; ! 191: ! 192: call_again: ! 193: time_waited.tv_sec = 0; ! 194: time_waited.tv_usec = 0; ! 195: xdrs = &(cu->cu_outxdrs); ! 196: xdrs->x_op = XDR_ENCODE; ! 197: XDR_SETPOS(xdrs, cu->cu_xdrpos); ! 198: /* ! 199: * the transaction is the first thing in the out buffer ! 200: */ ! 201: (*(u_short *)(cu->cu_outbuf))++; ! 202: if ((! XDR_PUTLONG(xdrs, (long *)&proc)) || ! 203: (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || ! 204: (! (*xargs)(xdrs, argsp))) ! 205: return (cu->cu_error.re_status = RPC_CANTENCODEARGS); ! 206: outlen = (int)XDR_GETPOS(xdrs); ! 207: while (TRUE) { ! 208: ! 209: if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0, ! 210: (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen) ! 211: != outlen) { ! 212: cu->cu_error.re_errno = errno; ! 213: return (cu->cu_error.re_status = RPC_CANTSEND); ! 214: } ! 215: /* ! 216: * sub-optimal code appears inside the loop because we have ! 217: * some clock time to spare while the packets are in flight. ! 218: * (We assume that this is actually only executed once.) ! 219: */ ! 220: reply_msg.acpted_rply.ar_verf = _null_auth; ! 221: reply_msg.acpted_rply.ar_results.where = resultsp; ! 222: reply_msg.acpted_rply.ar_results.proc = xresults; ! 223: mask = 1 << cu->cu_sock; ! 224: rcv_again: ! 225: readfds = mask; ! 226: switch (select(32, &readfds, (int *)NULL, (int *)NULL, ! 227: &(cu->cu_wait))) { ! 228: ! 229: case 0: ! 230: time_waited.tv_sec += cu->cu_wait.tv_sec; ! 231: time_waited.tv_usec += cu->cu_wait.tv_usec; ! 232: while (time_waited.tv_usec >= 1000000) { ! 233: time_waited.tv_sec++; ! 234: time_waited.tv_usec -= 1000000; ! 235: } ! 236: if ((time_waited.tv_sec < timeout.tv_sec) || ! 237: ((time_waited.tv_sec == timeout.tv_sec) && ! 238: (time_waited.tv_usec < timeout.tv_usec))) ! 239: continue; ! 240: return (cu->cu_error.re_status = RPC_TIMEDOUT); ! 241: ! 242: case -1: ! 243: if (errno == EINTR) ! 244: goto rcv_again; ! 245: cu->cu_error.re_errno = errno; ! 246: return (cu->cu_error.re_status = RPC_CANTRECV); ! 247: } ! 248: if ((readfds & mask) == 0) ! 249: goto rcv_again; ! 250: tryagain: ! 251: fromlen = sizeof(struct sockaddr); ! 252: inlen = recvfrom(cu->cu_sock, cu->cu_inbuf, UDPMSGSIZE, 0, ! 253: (struct sockaddr *)&from, &fromlen); ! 254: if (inlen < 0) { ! 255: if (errno == EINTR) ! 256: goto tryagain; ! 257: cu->cu_error.re_errno = errno; ! 258: return (cu->cu_error.re_status = RPC_CANTRECV); ! 259: } ! 260: if (inlen < sizeof(u_long)) ! 261: goto rcv_again; ! 262: /* see if reply transaction id matches sent id */ ! 263: if (*((u_long *)(cu->cu_inbuf)) != *((u_long *)(cu->cu_outbuf))) ! 264: goto rcv_again; ! 265: /* we now assume we have the proper reply */ ! 266: break; ! 267: } ! 268: ! 269: /* ! 270: * now decode and validate the response ! 271: */ ! 272: xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)inlen, XDR_DECODE); ! 273: ok = xdr_replymsg(&reply_xdrs, &reply_msg); ! 274: /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ ! 275: if (ok) { ! 276: _seterr_reply(&reply_msg, &(cu->cu_error)); ! 277: if (cu->cu_error.re_status == RPC_SUCCESS) { ! 278: if (! AUTH_VALIDATE(cl->cl_auth, ! 279: &reply_msg.acpted_rply.ar_verf)) { ! 280: cu->cu_error.re_status = RPC_AUTHERROR; ! 281: cu->cu_error.re_why = AUTH_INVALIDRESP; ! 282: } ! 283: if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { ! 284: xdrs->x_op = XDR_FREE; ! 285: (void)xdr_opaque_auth(xdrs, ! 286: &(reply_msg.acpted_rply.ar_verf)); ! 287: } ! 288: } /* end successful completion */ ! 289: else { ! 290: /* maybe our credentials need to be refreshed ... */ ! 291: if (AUTH_REFRESH(cl->cl_auth)) ! 292: goto call_again; ! 293: } /* end of unsuccessful completion */ ! 294: } /* end of valid reply message */ ! 295: else { ! 296: cu->cu_error.re_status = RPC_CANTDECODERES; ! 297: } ! 298: return (cu->cu_error.re_status); ! 299: } ! 300: ! 301: static void ! 302: clntudp_geterr(cl, errp) ! 303: CLIENT *cl; ! 304: struct rpc_err *errp; ! 305: { ! 306: register struct cu_data *cu = (struct cu_data *)cl->cl_private; ! 307: ! 308: *errp = cu->cu_error; ! 309: } ! 310: ! 311: ! 312: static bool_t ! 313: clntudp_freeres(cl, xdr_res, res_ptr) ! 314: CLIENT *cl; ! 315: xdrproc_t xdr_res; ! 316: caddr_t res_ptr; ! 317: { ! 318: register struct cu_data *cu = (struct cu_data *)cl->cl_private; ! 319: register XDR *xdrs = &(cu->cu_outxdrs); ! 320: ! 321: xdrs->x_op = XDR_FREE; ! 322: return ((*xdr_res)(xdrs, res_ptr)); ! 323: } ! 324: ! 325: static void ! 326: clntudp_abort(/*h*/) ! 327: /*CLIENT *h;*/ ! 328: { ! 329: } ! 330: ! 331: static void ! 332: clntudp_destroy(cl) ! 333: CLIENT *cl; ! 334: { ! 335: register struct cu_data *cu = (struct cu_data *)cl->cl_private; ! 336: ! 337: XDR_DESTROY(&(cu->cu_outxdrs)); ! 338: mem_free((caddr_t)cu, sizeof(*cu)); ! 339: mem_free((caddr_t)cl, sizeof(CLIENT)); ! 340: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.