From 65d3c627a5fcc1bd1a27d9ef2a2092f8d42f3058 Mon Sep 17 00:00:00 2001 From: Bill Paul Date: Tue, 27 Mar 2001 21:27:33 +0000 Subject: [PATCH] Add a CLSET_ASYNC command, which allows us to (ab)use the clnt_dg transport to make asynchronous RPCs. This is needed to help fix ypbind, which can no longer override the clnt_dg_call() method (formerly the clntudp_call() method) due to all the internal descriptor locking code in TI-RPC. Turning on this flag allows us to send an RPC request, then return immediately, and handle a reply later, rather than being forced to do the request and reply in a single function call. Also fix a byte ordering bug: when clnt_dg_call() increments the XID prior to transmitting a request, it uses the raw value, which is wrong. The XID is stored in network byte order, i.e. big-endian. The CLSET_XID and CLGET_XID commands in clnt_dg_control() use ntohl()/htonl() to get the byte ordering right, but because clnt_dg_call() does not do this, using CLSET_XID/CLGET_XID doesn't actually work, unless you're on a big endian host, which we aren't (yet). Fix clnt_dg_call() to byte swap properly when doing the increment. --- include/rpc/clnt.h | 1 + lib/libc/rpc/clnt_dg.c | 22 +++++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/include/rpc/clnt.h b/include/rpc/clnt.h index 2b0587b169ef..f845e8e346b5 100644 --- a/include/rpc/clnt.h +++ b/include/rpc/clnt.h @@ -228,6 +228,7 @@ struct rpc_timers { */ #define CLSET_RETRY_TIMEOUT 4 /* set retry timeout (timeval) */ #define CLGET_RETRY_TIMEOUT 5 /* get retry timeout (timeval) */ +#define CLSET_ASYNC 19 /* * void diff --git a/lib/libc/rpc/clnt_dg.c b/lib/libc/rpc/clnt_dg.c index f9f56127eb4a..0ee84d8e9ffb 100644 --- a/lib/libc/rpc/clnt_dg.c +++ b/lib/libc/rpc/clnt_dg.c @@ -126,6 +126,7 @@ struct cu_data { char *cu_outbuf; u_int cu_recvsz; /* recv size */ struct pollfd pfdp; + int cu_async; char cu_inbuf[1]; }; @@ -238,6 +239,7 @@ clnt_dg_create(fd, svcaddr, program, version, sendsz, recvsz) cu->cu_total.tv_usec = -1; cu->cu_sendsz = sendsz; cu->cu_recvsz = recvsz; + cu->cu_async = FALSE; (void) gettimeofday(&now, NULL); call_msg.rm_xid = __RPC_GETXID(&now); call_msg.rm_call.cb_prog = program; @@ -312,6 +314,7 @@ clnt_dg_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) socklen_t fromlen, inlen; ssize_t recvlen = 0; int rpc_lock_value; + u_int32_t xid; sigfillset(&newmask); thr_sigsetmask(SIG_SETMASK, &newmask, &mask); @@ -336,12 +339,19 @@ clnt_dg_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) call_again: xdrs = &(cu->cu_outxdrs); + if (cu->cu_async == TRUE && xargs == NULL) + goto get_reply; xdrs->x_op = XDR_ENCODE; XDR_SETPOS(xdrs, cu->cu_xdrpos); /* * the transaction is the first thing in the out buffer + * XXX Yes, and it's in network byte order, so we should to + * be careful when we increment it, shouldn't we. */ - (*(u_int32_t *)(void *)(cu->cu_outbuf))++; + xid = ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf)); + xid++; + *(u_int32_t *)(void *)(cu->cu_outbuf) = htonl(xid); + if ((! XDR_PUTINT32(xdrs, &proc)) || (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || (! (*xargs)(xdrs, argsp))) { @@ -366,6 +376,9 @@ clnt_dg_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) release_fd_lock(cu->cu_fd, mask); return (cu->cu_error.re_status = RPC_TIMEDOUT); } + +get_reply: + /* * sub-optimal code appears here because we have * some clock time to spare while the packets are in flight. @@ -495,7 +508,8 @@ clnt_dg_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) if (recvlen < sizeof (u_int32_t)) continue; /* see if reply transaction id matches sent id */ - if (*((u_int32_t *)(void *)(cu->cu_inbuf)) != + if (cu->cu_async == FALSE && + *((u_int32_t *)(void *)(cu->cu_inbuf)) != *((u_int32_t *)(void *)(cu->cu_outbuf))) continue; /* we now assume we have the proper reply */ @@ -722,7 +736,9 @@ clnt_dg_control(cl, request, info) *(u_int32_t *)(void *)(cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT) = htonl(*(u_int32_t *)(void *)info); break; - + case CLSET_ASYNC: + cu->cu_async = *(int *)(void *)info; + break; default: release_fd_lock(cu->cu_fd, mask); return (FALSE);