Annotation of 43BSD/contrib/sunrpc/clnt_tcp.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.