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: }