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_tcp.c 1.5 85/03/17 Copyr 1984 Sun Micro"; 31: #endif 32: 33: /* 34: * clnt_tcp.c, Implements a TCP/IP based, client side RPC. 35: * 36: * Copyright (C) 1984, Sun Microsystems, Inc. 37: * 38: * TCP based RPC supports 'batched calls'. 39: * A sequence of calls may be batched-up in a send buffer. The rpc call 40: * return immediately to the client even though the call was not necessarily 41: * sent. The batching occurs iff the results' xdr routine is NULL (0) AND 42: * the rpc timeout value is zero (see clnt.h, rpc). 43: * 44: * Clients should NOT casually batch calls that in fact return results; that is, 45: * the server side should be aware that a call is batched and not produce any 46: * return message. Batched calls that produce many result messages can 47: * deadlock (netlock) the client and the server.... 48: * 49: * Now go hang yourself. 50: */ 51: 52: #include <stdio.h> 53: #include "types.h" 54: #include <sys/socket.h> 55: #include <sys/time.h> 56: #include <netinet/in.h> 57: #include <netdb.h> 58: #include <errno.h> 59: #include "xdr.h" 60: #include "auth.h" 61: #include "clnt.h" 62: #include "rpc_msg.h" 63: #include "pmap_clnt.h" 64: 65: #define MCALL_MSG_SIZE 24 66: 67: char *malloc(); 68: extern int errno; 69: long random(); 70: 71: static int readtcp(); 72: static int writetcp(); 73: 74: static enum clnt_stat clnttcp_call(); 75: static void clnttcp_abort(); 76: static void clnttcp_geterr(); 77: static bool_t clnttcp_freeres(); 78: static void clnttcp_destroy(); 79: 80: static struct clnt_ops tcp_ops = { 81: clnttcp_call, 82: clnttcp_abort, 83: clnttcp_geterr, 84: clnttcp_freeres, 85: clnttcp_destroy 86: }; 87: 88: struct ct_data { 89: int ct_sock; 90: struct timeval ct_wait; 91: struct rpc_err ct_error; 92: char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */ 93: u_int ct_mpos; /* pos after marshal */ 94: XDR ct_xdrs; 95: }; 96: 97: /* 98: * Create a client handle for a tcp/ip connection. 99: * If *sockp<0, *sockp is set to a newly created TCP socket and it is 100: * connected to raddr. If *sockp non-negative then 101: * raddr is ignored. The rpc/tcp package does buffering 102: * similar to stdio, so the client must pick send and receive buffer sizes,]; 103: * 0 => use the default. 104: * If raddr->sin_port is 0, then a binder on the remote machine is 105: * consulted for the right port number. 106: * NB: *sockp is copied into a private area. 107: * NB: It is the clients responsibility to close *sockp. 108: * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this 109: * something more useful. 110: */ 111: CLIENT * 112: clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) 113: struct sockaddr_in *raddr; 114: u_long prog; 115: u_long vers; 116: register int *sockp; 117: u_int sendsz; 118: u_int recvsz; 119: { 120: CLIENT *h; 121: register struct ct_data *ct; 122: struct timeval now; 123: struct rpc_msg call_msg; 124: 125: h = (CLIENT *)mem_alloc(sizeof(*h)); 126: if (h == NULL) { 127: fprintf(stderr, "clnttcp_create: out of memory\n"); 128: rpc_createerr.cf_stat = RPC_SYSTEMERROR; 129: rpc_createerr.cf_error.re_errno = errno; 130: goto fooy; 131: } 132: ct = (struct ct_data *)mem_alloc(sizeof(*ct)); 133: if (ct == NULL) { 134: fprintf(stderr, "clnttcp_create: out of memory\n"); 135: rpc_createerr.cf_stat = RPC_SYSTEMERROR; 136: rpc_createerr.cf_error.re_errno = errno; 137: goto fooy; 138: } 139: 140: /* 141: * If no port number given ask the pmap for one 142: */ 143: if (raddr->sin_port == 0) { 144: u_short port; 145: if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) { 146: mem_free((caddr_t)ct, sizeof(struct ct_data)); 147: mem_free((caddr_t)h, sizeof(CLIENT)); 148: return ((CLIENT *)NULL); 149: } 150: raddr->sin_port = htons(port); 151: } 152: 153: /* 154: * If no socket given, open one 155: */ 156: if (*sockp < 0) { 157: if (((*sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 158: || (connect(*sockp, (struct sockaddr *)raddr, 159: sizeof(*raddr)) < 0)) { 160: rpc_createerr.cf_stat = RPC_SYSTEMERROR; 161: rpc_createerr.cf_error.re_errno = errno; 162: goto fooy; 163: } 164: } 165: 166: /* 167: * Set up private data struct 168: */ 169: ct->ct_sock = *sockp; 170: ct->ct_wait.tv_usec = 0; 171: 172: /* 173: * Initialize call message 174: */ 175: (void)gettimeofday(&now, (struct timezone *)0); 176: call_msg.rm_xid = getpid() ^ (int)random() ^ now.tv_sec ^ now.tv_usec; 177: call_msg.rm_direction = CALL; 178: call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 179: call_msg.rm_call.cb_prog = prog; 180: call_msg.rm_call.cb_vers = vers; 181: 182: /* 183: * pre-serialize the staic part of the call msg and stash it away 184: */ 185: xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, 186: XDR_ENCODE); 187: if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { 188: goto fooy; 189: } 190: ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); 191: XDR_DESTROY(&(ct->ct_xdrs)); 192: 193: /* 194: * Create a client handle which uses xdrrec for serialization 195: * and authnone for authentication. 196: */ 197: xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, 198: (caddr_t)ct, readtcp, writetcp); 199: h->cl_ops = &tcp_ops; 200: h->cl_private = (caddr_t) ct; 201: h->cl_auth = authnone_create(); 202: return (h); 203: 204: fooy: 205: /* 206: * Something goofed, free stuff and barf 207: */ 208: mem_free((caddr_t)ct, sizeof(struct ct_data)); 209: mem_free((caddr_t)h, sizeof(CLIENT)); 210: (void)close(*sockp); 211: return ((CLIENT *)NULL); 212: } 213: 214: static enum clnt_stat 215: clnttcp_call(h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout) 216: register CLIENT *h; 217: u_long proc; 218: xdrproc_t xdr_args; 219: caddr_t args_ptr; 220: xdrproc_t xdr_results; 221: caddr_t results_ptr; 222: struct timeval timeout; 223: { 224: register struct ct_data *ct = (struct ct_data *) h->cl_private; 225: register XDR *xdrs = &(ct->ct_xdrs); 226: struct rpc_msg reply_msg; 227: u_long x_id; 228: u_long *msg_x_id = (u_long *)(ct->ct_mcall); /* yuk */ 229: register bool_t shipnow; 230: 231: ct->ct_wait = timeout; 232: shipnow = 233: (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0 234: && timeout.tv_usec == 0) ? FALSE : TRUE; 235: 236: call_again: 237: xdrs->x_op = XDR_ENCODE; 238: ct->ct_error.re_status = RPC_SUCCESS; 239: x_id = ntohl(--(*msg_x_id)); 240: if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) || 241: (! XDR_PUTLONG(xdrs, (long *)&proc)) || 242: (! AUTH_MARSHALL(h->cl_auth, xdrs)) || 243: (! (*xdr_args)(xdrs, args_ptr))) { 244: if (ct->ct_error.re_status == RPC_SUCCESS) 245: ct->ct_error.re_status = RPC_CANTENCODEARGS; 246: (void)xdrrec_endofrecord(xdrs, TRUE); 247: return (ct->ct_error.re_status); 248: } 249: if (! xdrrec_endofrecord(xdrs, shipnow)) 250: return (ct->ct_error.re_status = RPC_CANTSEND); 251: if (! shipnow) 252: return (RPC_SUCCESS); 253: xdrs->x_op = XDR_DECODE; 254: 255: /* 256: * Keep receiving until we get a valid transaction id 257: */ 258: while (TRUE) { 259: reply_msg.acpted_rply.ar_verf = _null_auth; 260: reply_msg.acpted_rply.ar_results.where = NULL; 261: reply_msg.acpted_rply.ar_results.proc = xdr_void; 262: if (! xdrrec_skiprecord(xdrs)) 263: return (ct->ct_error.re_status); 264: /* now decode and validate the response header */ 265: if (! xdr_replymsg(xdrs, &reply_msg)) { 266: if (ct->ct_error.re_status == RPC_SUCCESS) 267: continue; 268: return (ct->ct_error.re_status); 269: } 270: if (reply_msg.rm_xid == x_id) 271: break; 272: } 273: 274: /* 275: * process header 276: */ 277: _seterr_reply(&reply_msg, &(ct->ct_error)); 278: if (ct->ct_error.re_status == RPC_SUCCESS) { 279: if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) { 280: ct->ct_error.re_status = RPC_AUTHERROR; 281: ct->ct_error.re_why = AUTH_INVALIDRESP; 282: } else if (! (*xdr_results)(xdrs, results_ptr)) { 283: if (ct->ct_error.re_status == RPC_SUCCESS) 284: ct->ct_error.re_status = RPC_CANTDECODERES; 285: } 286: /* free verifier ... */ 287: if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 288: xdrs->x_op = XDR_FREE; 289: (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); 290: } 291: } /* end successful completion */ 292: else { 293: /* maybe our credentials need to be refreshed ... */ 294: if (AUTH_REFRESH(h->cl_auth)) 295: goto call_again; 296: } /* end of unsuccessful completion */ 297: return (ct->ct_error.re_status); 298: } 299: 300: static void 301: clnttcp_geterr(h, errp) 302: CLIENT *h; 303: struct rpc_err *errp; 304: { 305: register struct ct_data *ct = 306: (struct ct_data *) h->cl_private; 307: 308: *errp = ct->ct_error; 309: } 310: 311: static bool_t 312: clnttcp_freeres(cl, xdr_res, res_ptr) 313: CLIENT *cl; 314: xdrproc_t xdr_res; 315: caddr_t res_ptr; 316: { 317: register struct ct_data *ct = (struct ct_data *)cl->cl_private; 318: register XDR *xdrs = &(ct->ct_xdrs); 319: 320: xdrs->x_op = XDR_FREE; 321: return ((*xdr_res)(xdrs, res_ptr)); 322: } 323: 324: static void 325: clnttcp_abort() 326: { 327: } 328: 329: static void 330: clnttcp_destroy(h) 331: CLIENT *h; 332: { 333: register struct ct_data *ct = 334: (struct ct_data *) h->cl_private; 335: 336: XDR_DESTROY(&(ct->ct_xdrs)); 337: mem_free((caddr_t)ct, sizeof(struct ct_data)); 338: mem_free((caddr_t)h, sizeof(CLIENT)); 339: } 340: 341: /* 342: * Interface between xdr serializer and tcp connection. 343: * Behaves like the system calls, read & write, but keeps some error state 344: * around for the rpc level. 345: */ 346: static int 347: readtcp(ct, buf, len) 348: register struct ct_data *ct; 349: caddr_t buf; 350: register int len; 351: { 352: register int mask = 1 << (ct->ct_sock); 353: int readfds; 354: 355: while (TRUE) { 356: readfds = mask; 357: switch (select(32, &readfds, (int*)NULL, (int*)NULL, 358: &(ct->ct_wait))) { 359: 360: case 0: 361: ct->ct_error.re_status = RPC_TIMEDOUT; 362: return (-1); 363: 364: case -1: 365: if (errno == EINTR) 366: continue; 367: ct->ct_error.re_status = RPC_CANTRECV; 368: ct->ct_error.re_errno = errno; 369: return (-1); 370: } 371: if (readfds == mask) 372: break; 373: } 374: if ((len = read(ct->ct_sock, buf, len)) == -1) { 375: ct->ct_error.re_errno = errno; 376: ct->ct_error.re_status = RPC_CANTRECV; 377: } 378: return (len); 379: } 380: 381: static int 382: writetcp(ct, buf, len) 383: struct ct_data *ct; 384: caddr_t buf; 385: int len; 386: { 387: register int i, cnt; 388: 389: for (cnt = len; cnt > 0; cnt -= i, buf += i) { 390: if ((i = write(ct->ct_sock, buf, cnt)) == -1) { 391: ct->ct_error.re_errno = errno; 392: ct->ct_error.re_status = RPC_CANTSEND; 393: return (-1); 394: } 395: } 396: return (len); 397: }