|
|
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_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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.