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

Defined functions

clnttcp_abort defined in line 324; used 2 times
clnttcp_call defined in line 214; used 2 times
clnttcp_destroy defined in line 329; used 2 times
clnttcp_freeres defined in line 311; used 2 times
clnttcp_geterr defined in line 300; used 2 times
readtcp defined in line 346; used 2 times
writetcp defined in line 381; used 2 times

Defined variables

sccsid defined in line 30; never used
tcp_ops defined in line 80; used 1 times

Defined struct's

ct_data defined in line 88; used 30 times

Defined macros

MCALL_MSG_SIZE defined in line 65; used 2 times
Last modified: 1985-04-19
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1689
Valid CSS Valid XHTML 1.0 Strict