Annotation of 43BSDReno/lib/librpc/clnt_udp.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_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: }

unix.superglobalmegacorp.com

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