diff options
Diffstat (limited to 'lib/libc/rpc/clnt_tcp.c')
| -rw-r--r-- | lib/libc/rpc/clnt_tcp.c | 178 |
1 files changed, 145 insertions, 33 deletions
diff --git a/lib/libc/rpc/clnt_tcp.c b/lib/libc/rpc/clnt_tcp.c index efc041ab8db3..cfb3746d2897 100644 --- a/lib/libc/rpc/clnt_tcp.c +++ b/lib/libc/rpc/clnt_tcp.c @@ -5,23 +5,23 @@ * may copy or modify Sun RPC without charge, but are not authorized * to license or distribute it to anyone else except as part of a product or * program developed by the user. - * + * * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. - * + * * Sun RPC is provided with no support and without any obligation on the * part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. - * + * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC * OR ANY PART THEREOF. - * + * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even if * Sun has been advised of the possibility of such damages. - * + * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 @@ -30,9 +30,9 @@ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";*/ /*static char *sccsid = "from: @(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC";*/ -static char *rcsid = "$Id: clnt_tcp.c,v 1.1 1993/10/27 05:40:24 paul Exp $"; +static char *rcsid = "$Id: clnt_tcp.c,v 1.7 1996/12/30 14:36:17 peter Exp $"; #endif - + /* * clnt_tcp.c, Implements a TCP/IP based, client side RPC. * @@ -53,6 +53,9 @@ static char *rcsid = "$Id: clnt_tcp.c,v 1.1 1993/10/27 05:40:24 paul Exp $"; */ #include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> #include <rpc/rpc.h> #include <sys/socket.h> #include <netdb.h> @@ -61,8 +64,6 @@ static char *rcsid = "$Id: clnt_tcp.c,v 1.1 1993/10/27 05:40:24 paul Exp $"; #define MCALL_MSG_SIZE 24 -extern int errno; - static int readtcp(); static int writetcp(); @@ -87,7 +88,7 @@ struct ct_data { bool_t ct_closeit; struct timeval ct_wait; bool_t ct_waitset; /* wait set by clnt_control? */ - struct sockaddr_in ct_addr; + struct sockaddr_in ct_addr; struct rpc_err ct_error; char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */ u_int ct_mpos; /* pos after marshal */ @@ -118,9 +119,13 @@ clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) u_int recvsz; { CLIENT *h; - register struct ct_data *ct; + register struct ct_data *ct = NULL; struct timeval now; struct rpc_msg call_msg; + static u_int32_t disrupt; + + if (disrupt == 0) + disrupt = (u_int32_t)(long)raddr; h = (CLIENT *)mem_alloc(sizeof(*h)); if (h == NULL) { @@ -161,7 +166,8 @@ clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) sizeof(*raddr)) < 0)) { rpc_createerr.cf_stat = RPC_SYSTEMERROR; rpc_createerr.cf_error.re_errno = errno; - (void)close(*sockp); + if (*sockp != -1) + (void)close(*sockp); goto fooy; } ct->ct_closeit = TRUE; @@ -181,14 +187,14 @@ clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) * Initialize call message */ (void)gettimeofday(&now, (struct timezone *)0); - 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 = prog; call_msg.rm_call.cb_vers = vers; /* - * pre-serialize the staic part of the call msg and stash it away + * pre-serialize the static part of the call msg and stash it away */ xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, XDR_ENCODE); @@ -216,8 +222,10 @@ fooy: /* * Something goofed, free stuff and barf */ - mem_free((caddr_t)ct, sizeof(struct ct_data)); - mem_free((caddr_t)h, sizeof(CLIENT)); + if (ct) + mem_free((caddr_t)ct, sizeof(struct ct_data)); + if (h) + mem_free((caddr_t)h, sizeof(CLIENT)); return ((CLIENT *)NULL); } @@ -235,7 +243,7 @@ clnttcp_call(h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout) register XDR *xdrs = &(ct->ct_xdrs); struct rpc_msg reply_msg; u_long x_id; - u_long *msg_x_id = (u_long *)(ct->ct_mcall); /* yuk */ + u_int32_t *msg_x_id = (u_int32_t *)(ct->ct_mcall); /* yuk */ register bool_t shipnow; int refreshes = 2; @@ -347,6 +355,7 @@ clnttcp_abort() { } + static bool_t clnttcp_control(cl, request, info) CLIENT *cl; @@ -354,18 +363,102 @@ clnttcp_control(cl, request, info) char *info; { register struct ct_data *ct = (struct ct_data *)cl->cl_private; + register struct timeval *tv; + int len; switch (request) { + case CLSET_FD_CLOSE: + ct->ct_closeit = TRUE; + break; + case CLSET_FD_NCLOSE: + ct->ct_closeit = FALSE; + break; case CLSET_TIMEOUT: - ct->ct_wait = *(struct timeval *)info; + if (info == NULL) + return(FALSE); + tv = (struct timeval *)info; + ct->ct_wait.tv_sec = tv->tv_sec; + ct->ct_wait.tv_usec = tv->tv_usec; ct->ct_waitset = TRUE; break; case CLGET_TIMEOUT: + if (info == NULL) + return(FALSE); *(struct timeval *)info = ct->ct_wait; break; case CLGET_SERVER_ADDR: + if (info == NULL) + return(FALSE); *(struct sockaddr_in *)info = ct->ct_addr; break; + case CLGET_FD: + if (info == NULL) + return(FALSE); + *(int *)info = ct->ct_sock; + break; + case CLGET_XID: + /* + * use the knowledge that xid is the + * first element in the call structure *. + * This will get the xid of the PREVIOUS call + */ + if (info == NULL) + return(FALSE); + *(u_long *)info = ntohl(*(u_long *)ct->ct_mcall); + break; + case CLSET_XID: + /* This will set the xid of the NEXT call */ + if (info == NULL) + return(FALSE); + *(u_long *)ct->ct_mcall = htonl(*(u_long *)info - 1); + /* decrement by 1 as clnttcp_call() increments once */ + case CLGET_VERS: + /* + * This RELIES on the information that, in the call body, + * the version number field is the fifth field from the + * begining of the RPC header. MUST be changed if the + * call_struct is changed + */ + if (info == NULL) + return(FALSE); + *(u_long *)info = ntohl(*(u_long *)(ct->ct_mcall + + 4 * BYTES_PER_XDR_UNIT)); + break; + case CLSET_VERS: + if (info == NULL) + return(FALSE); + *(u_long *)(ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT) + = htonl(*(u_long *)info); + break; + case CLGET_PROG: + /* + * This RELIES on the information that, in the call body, + * the program number field is the field from the + * begining of the RPC header. MUST be changed if the + * call_struct is changed + */ + if (info == NULL) + return(FALSE); + *(u_long *)info = ntohl(*(u_long *)(ct->ct_mcall + + 3 * BYTES_PER_XDR_UNIT)); + break; + case CLSET_PROG: + if (info == NULL) + return(FALSE); + *(u_long *)(ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT) + = htonl(*(u_long *)info); + break; + case CLGET_LOCAL_ADDR: + len = sizeof(struct sockaddr); + if (getsockname(ct->ct_sock, (struct sockaddr *)info, &len) <0) + return(FALSE); + break; + case CLGET_RETRY_TIMEOUT: + case CLSET_RETRY_TIMEOUT: + case CLGET_SVC_ADDR: + case CLSET_SVC_ADDR: + case CLSET_PUSH_TIMOD: + case CLSET_POP_TIMOD: default: return (FALSE); } @@ -399,35 +492,54 @@ readtcp(ct, buf, len) caddr_t buf; register int len; { -#ifdef FD_SETSIZE - fd_set mask; - fd_set readfds; + fd_set *fds, readfds; + struct timeval start, after, duration, delta, tmp, tv; + int r, save_errno; if (len == 0) return (0); - FD_ZERO(&mask); - FD_SET(ct->ct_sock, &mask); -#else - register int mask = 1 << (ct->ct_sock); - int readfds; - if (len == 0) - return (0); + if (ct->ct_sock + 1 > FD_SETSIZE) { + int bytes = howmany(ct->ct_sock + 1, NFDBITS) * sizeof(fd_mask); + fds = (fd_set *)malloc(bytes); + if (fds == NULL) + return (-1); + memset(fds, 0, bytes); + } else { + fds = &readfds; + FD_ZERO(fds); + } -#endif /* def FD_SETSIZE */ + gettimeofday(&start, NULL); + delta = ct->ct_wait; while (TRUE) { - readfds = mask; - switch (select(_rpc_dtablesize(), &readfds, (int*)NULL, (int*)NULL, - &(ct->ct_wait))) { + /* XXX we know the other bits are still clear */ + FD_SET(ct->ct_sock, fds); + tv = delta; /* in case select writes back */ + r = select(ct->ct_sock+1, fds, NULL, NULL, &tv); + save_errno = errno; + + gettimeofday(&after, NULL); + timersub(&start, &after, &duration); + timersub(&delta, &duration, &tmp); + delta = tmp; + if (delta.tv_sec < 0 || !timerisset(&delta)) + r = 0; + + switch (r) { case 0: + if (fds != &readfds) + free(fds); ct->ct_error.re_status = RPC_TIMEDOUT; return (-1); case -1: if (errno == EINTR) continue; + if (fds != &readfds) + free(fds); ct->ct_error.re_status = RPC_CANTRECV; - ct->ct_error.re_errno = errno; + ct->ct_error.re_errno = save_errno; return (-1); } break; |
