From acdf726df9abb53422e33ee79f99d1a84e9286c4 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 30 Dec 1996 14:40:34 +0000 Subject: - prototypes now in include file - fix timeout code - better "random" initial transaction id for long running daemons - unlimited number of file descriptors to select(). - 64 bit type safe wire protocol Obtained from: a diff of FreeBSD vs. OpenBSD/NetBSD rpc code. - typo (spelling police :-) - dont die on select() that returns time remaining (on my systems) --- lib/libc/rpc/clnt_udp.c | 113 +++++++++++++++++++++++++++--------------------- 1 file changed, 64 insertions(+), 49 deletions(-) (limited to 'lib/libc/rpc/clnt_udp.c') diff --git a/lib/libc/rpc/clnt_udp.c b/lib/libc/rpc/clnt_udp.c index 28dfddc..2e45f63 100644 --- a/lib/libc/rpc/clnt_udp.c +++ b/lib/libc/rpc/clnt_udp.c @@ -30,7 +30,7 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)clnt_udp.c 1.39 87/08/11 Copyr 1984 Sun Micro";*/ /*static char *sccsid = "from: @(#)clnt_udp.c 2.2 88/08/01 4.0 RPCSRC";*/ -static char *rcsid = "$Id: clnt_udp.c,v 1.6 1995/12/07 12:50:54 bde Exp $"; +static char *rcsid = "$Id: clnt_udp.c,v 1.7 1996/06/10 00:49:16 jraynard Exp $"; #endif /* @@ -50,10 +50,6 @@ static char *rcsid = "$Id: clnt_udp.c,v 1.6 1995/12/07 12:50:54 bde Exp $"; #include #include -int bindresvport(int sd, struct sockaddr_in *); -int _rpc_dtablesize(void); -bool_t xdr_opaque_auth(XDR *, struct opaque_auth *); - /* * UDP bases client side rpc operations */ @@ -122,6 +118,10 @@ clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz) register struct cu_data *cu = NULL; struct timeval now; struct rpc_msg call_msg; + static u_int32_t disrupt; + + if (disrupt == 0) + disrupt = (u_int32_t)(long)raddr; cl = (CLIENT *)mem_alloc(sizeof(CLIENT)); if (cl == NULL) { @@ -159,7 +159,7 @@ clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz) cu->cu_total.tv_usec = -1; cu->cu_sendsz = sendsz; cu->cu_recvsz = recvsz; - call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec; + call_msg.rm_xid = (++disrupt) ^ getpid() ^ now.tv_sec ^ now.tv_usec; call_msg.rm_direction = CALL; call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = program; @@ -179,7 +179,7 @@ clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz) rpc_createerr.cf_error.re_errno = errno; goto fooy; } - /* attempt to bind to prov port */ + /* attempt to bind to priv port */ (void)bindresvport(*sockp, (struct sockaddr_in *)0); /* the sockets rpc controls are non-blocking */ (void)ioctl(*sockp, FIONBIO, (char *) &dontblock); @@ -226,29 +226,33 @@ clntudp_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) register int outlen; register int inlen; int fromlen; -#ifdef FD_SETSIZE - fd_set readfds; - fd_set mask; -#else - int readfds; - register int mask; -#endif /* def FD_SETSIZE */ + fd_set *fds, readfds; struct sockaddr_in from; struct rpc_msg reply_msg; XDR reply_xdrs; - struct timeval time_waited; + struct timeval time_waited, start, after, tmp1, tmp2, tv; bool_t ok; int nrefreshes = 2; /* number of times to refresh cred */ struct timeval timeout; - if (cu->cu_total.tv_usec == -1) { + if (cu->cu_total.tv_usec == -1) timeout = utimeout; /* use supplied timeout */ - } else { + else timeout = cu->cu_total; /* use default timeout */ + + if (cu->cu_sock + 1 > FD_SETSIZE) { + int bytes = howmany(cu->cu_sock + 1, NFDBITS) * sizeof(fd_mask); + fds = (fd_set *)malloc(bytes); + if (fds == NULL) + return (cu->cu_error.re_status = RPC_CANTSEND); + memset(fds, 0, bytes); + } else { + fds = &readfds; + FD_ZERO(fds); } - time_waited.tv_sec = 0; - time_waited.tv_usec = 0; + timerclear(&time_waited); + call_again: xdrs = &(cu->cu_outxdrs); xdrs->x_op = XDR_ENCODE; @@ -259,22 +263,28 @@ call_again: (*(u_short *)(cu->cu_outbuf))++; if ((! XDR_PUTLONG(xdrs, (long *)&proc)) || (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || - (! (*xargs)(xdrs, argsp))) + (! (*xargs)(xdrs, argsp))) { + if (fds != &readfds) + free(fds); return (cu->cu_error.re_status = RPC_CANTENCODEARGS); + } outlen = (int)XDR_GETPOS(xdrs); send_again: if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0, - (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen) - != outlen) { + (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen) != outlen) { cu->cu_error.re_errno = errno; + if (fds != &readfds) + free(fds); return (cu->cu_error.re_status = RPC_CANTSEND); } /* * Hack to provide rpc-based message passing */ - if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { + if (!timerisset(&timeout)) { + if (fds != &readfds) + free(fds); return (cu->cu_error.re_status = RPC_TIMEDOUT); } /* @@ -285,40 +295,41 @@ send_again: reply_msg.acpted_rply.ar_verf = _null_auth; reply_msg.acpted_rply.ar_results.where = resultsp; reply_msg.acpted_rply.ar_results.proc = xresults; -#ifdef FD_SETSIZE - FD_ZERO(&mask); - FD_SET(cu->cu_sock, &mask); -#else - mask = 1 << cu->cu_sock; -#endif /* def FD_SETSIZE */ + + gettimeofday(&start, NULL); for (;;) { - readfds = mask; - switch (select(_rpc_dtablesize(), &readfds, (fd_set *)NULL, - (fd_set *)NULL, &(cu->cu_wait))) { + /* XXX we know the other bits are still clear */ + FD_SET(cu->cu_sock, fds); + tv = cu->cu_wait; + switch (select(cu->cu_sock+1, fds, NULL, NULL, &tv)) { case 0: - time_waited.tv_sec += cu->cu_wait.tv_sec; - time_waited.tv_usec += cu->cu_wait.tv_usec; - while (time_waited.tv_usec >= 1000000) { - time_waited.tv_sec++; - time_waited.tv_usec -= 1000000; - } - if ((time_waited.tv_sec < timeout.tv_sec) || - ((time_waited.tv_sec == timeout.tv_sec) && - (time_waited.tv_usec < timeout.tv_usec))) + timeradd(&time_waited, &cu->cu_wait, &tmp1); + time_waited = tmp1; + if (timercmp(&time_waited, &timeout, <)) goto send_again; + if (fds != &readfds) + free(fds); return (cu->cu_error.re_status = RPC_TIMEDOUT); - /* - * buggy in other cases because time_waited is not being - * updated. - */ case -1: - if (errno == EINTR) - continue; + if (errno == EINTR) { + gettimeofday(&after, NULL); + timersub(&after, &start, &tmp1); + timeradd(&time_waited, &tmp1, &tmp2); + time_waited = tmp2; + if (timercmp(&time_waited, &timeout, <)) + continue; + if (fds != &readfds) + free(fds); + return (cu->cu_error.re_status = RPC_TIMEDOUT); + } cu->cu_error.re_errno = errno; + if (fds != &readfds) + free(fds); return (cu->cu_error.re_status = RPC_CANTRECV); } + do { fromlen = sizeof(struct sockaddr); inlen = recvfrom(cu->cu_sock, cu->cu_inbuf, @@ -329,12 +340,14 @@ send_again: if (errno == EWOULDBLOCK) continue; cu->cu_error.re_errno = errno; + if (fds != &readfds) + free(fds); return (cu->cu_error.re_status = RPC_CANTRECV); } - if (inlen < sizeof(u_long)) + if (inlen < sizeof(u_int32_t)) continue; /* see if reply transaction id matches sent id */ - if (*((u_long *)(cu->cu_inbuf)) != *((u_long *)(cu->cu_outbuf))) + if (*((u_int32_t *)(cu->cu_inbuf)) != *((u_int32_t *)(cu->cu_outbuf))) continue; /* we now assume we have the proper reply */ break; @@ -371,6 +384,8 @@ send_again: else { cu->cu_error.re_status = RPC_CANTDECODERES; } + if (fds != &readfds) + free(fds); return (cu->cu_error.re_status); } -- cgit v1.1