aboutsummaryrefslogtreecommitdiffstats
path: root/lib/libc/rpc/svc.c
diff options
context:
space:
mode:
authorAlfred Perlstein <alfred@FreeBSD.org>2001-03-19 12:50:13 +0000
committerAlfred Perlstein <alfred@FreeBSD.org>2001-03-19 12:50:13 +0000
commit8360efbd6c932013ffdb2f83d2f2de4278febb5e (patch)
treeb842b4bf2665ef953be005b10013a2f3daf323c3 /lib/libc/rpc/svc.c
parent1ac2b9fe972a0c73729565f8310fa6eba55718c4 (diff)
downloadsrc-8360efbd6c932013ffdb2f83d2f2de4278febb5e.tar.gz
src-8360efbd6c932013ffdb2f83d2f2de4278febb5e.zip
Bring in a hybrid of SunSoft's transport-independent RPC (TI-RPC) and
associated changes that had to happen to make this possible as well as bugs fixed along the way. Bring in required TLI library routines to support this. Since we don't support TLI we've essentially copied what NetBSD has done, adding a thin layer to emulate direct the TLI calls into BSD socket calls. This is mostly from Sun's tirpc release that was made in 1994, however some fixes were backported from the 1999 release (supposedly only made available after this porting effort was underway). The submitter has agreed to continue on and bring us up to the 1999 release. Several key features are introduced with this update: Client calls are thread safe. (1999 code has server side thread safe) Updated, a more modern interface. Many userland updates were done to bring the code up to par with the recent RPC API. There is an update to the pthreads library, a function pthread_main_np() was added to emulate a function of Sun's threads library. While we're at it, bring in NetBSD's lockd, it's been far too long of a wait. New rpcbind(8) replaces portmap(8) (supporting communication over an authenticated Unix-domain socket, and by default only allowing set and unset requests over that channel). It's much more secure than the old portmapper. Umount(8), mountd(8), mount_nfs(8), nfsd(8) have also been upgraded to support TI-RPC and to support IPV6. Umount(8) is also fixed to unmount pathnames longer than 80 chars, which are currently truncated by the Kernel statfs structure. Submitted by: Martin Blapp <mb@imp.ch> Manpage review: ru Secure RPC implemented by: wpaul
Notes
Notes: svn path=/head/; revision=74462
Diffstat (limited to 'lib/libc/rpc/svc.c')
-rw-r--r--lib/libc/rpc/svc.c583
1 files changed, 403 insertions, 180 deletions
diff --git a/lib/libc/rpc/svc.c b/lib/libc/rpc/svc.c
index 94d6057e6004..6e57245a4dd5 100644
--- a/lib/libc/rpc/svc.c
+++ b/lib/libc/rpc/svc.c
@@ -1,3 +1,5 @@
+/* $NetBSD: svc.c,v 1.21 2000/07/06 03:10:35 christos Exp $ */
+
/*
* Sun RPC is a product of Sun Microsystems, Inc. and is provided for
* unrestricted use provided that this legend is included on all tape
@@ -43,17 +45,30 @@ static char *rcsid = "$FreeBSD$";
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
-#include <string.h>
+#include "reentrant.h"
+#include "namespace.h"
+#include <sys/types.h>
+#include <sys/poll.h>
+#include <assert.h>
+#include <errno.h>
#include <stdlib.h>
+#include <string.h>
+
#include <rpc/rpc.h>
+#ifdef PORTMAP
#include <rpc/pmap_clnt.h>
+#endif /* PORTMAP */
+#include "un-namespace.h"
+
+#include "rpc_com.h"
static SVCXPRT **xports;
-static int xportssize;
-#define NULL_SVC ((struct svc_callout *)0)
#define RQCRED_SIZE 400 /* this size is excessive */
+#define SVC_VERSQUIET 0x0001 /* keep quiet about vers mismatch */
+#define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET)
+
#define max(a, b) (a > b ? a : b)
/*
@@ -64,15 +79,17 @@ static int xportssize;
*/
static struct svc_callout {
struct svc_callout *sc_next;
- u_long sc_prog;
- u_long sc_vers;
- void (*sc_dispatch)();
+ rpcprog_t sc_prog;
+ rpcvers_t sc_vers;
+ char *sc_netid;
+ void (*sc_dispatch) __P((struct svc_req *, SVCXPRT *));
} *svc_head;
-static struct svc_callout *svc_find();
+extern rwlock_t svc_lock;
+extern rwlock_t svc_fd_lock;
-int __svc_fdsetsize = 0;
-fd_set *__svc_fdset = NULL;
+static struct svc_callout *svc_find __P((rpcprog_t, rpcvers_t,
+ struct svc_callout **, char *));
/* *************** SVCXPRT related stuff **************** */
@@ -83,75 +100,161 @@ void
xprt_register(xprt)
SVCXPRT *xprt;
{
- register int sock = xprt->xp_sock;
-
- if (sock + 1 > __svc_fdsetsize) {
- int bytes = howmany(sock + 1, NFDBITS) * sizeof(fd_mask);
- fd_set *fds;
-
- fds = (fd_set *)malloc(bytes);
- memset(fds, 0, bytes);
- if (__svc_fdset) {
- memcpy(fds, __svc_fdset, howmany(__svc_fdsetsize,
- NFDBITS) * sizeof(fd_mask));
- free(__svc_fdset);
- }
- __svc_fdset = fds;
- __svc_fdsetsize = howmany(sock+1, NFDBITS) * NFDBITS;
- }
+ int sock;
+
+ assert(xprt != NULL);
+
+ sock = xprt->xp_fd;
- if (sock < FD_SETSIZE)
+ rwlock_wrlock(&svc_fd_lock);
+ if (xports == NULL) {
+ xports = (SVCXPRT **)
+ mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *));
+ if (xports == NULL)
+ return;
+ memset(xports, '\0', FD_SETSIZE * sizeof(SVCXPRT *));
+ }
+ if (sock < FD_SETSIZE) {
+ xports[sock] = xprt;
FD_SET(sock, &svc_fdset);
- FD_SET(sock, __svc_fdset);
-
- if (xports == NULL || sock + 1 > xportssize) {
- SVCXPRT **xp;
- int size = FD_SETSIZE;
-
- if (sock + 1 > size)
- size = sock + 1;
- xp = (SVCXPRT **)mem_alloc(size * sizeof(SVCXPRT *));
- memset(xp, 0, size * sizeof(SVCXPRT *));
- if (xports) {
- memcpy(xp, xports, xportssize * sizeof(SVCXPRT *));
- free(xports);
- }
- xportssize = size;
- xports = xp;
+ svc_maxfd = max(svc_maxfd, sock);
}
- xports[sock] = xprt;
- svc_maxfd = max(svc_maxfd, sock);
+ rwlock_unlock(&svc_fd_lock);
}
/*
* De-activate a transport handle.
*/
void
-xprt_unregister(xprt)
+xprt_unregister(xprt)
SVCXPRT *xprt;
{
- register int sock = xprt->xp_sock;
-
- if (xports[sock] == xprt) {
- xports[sock] = (SVCXPRT *)0;
- if (sock < FD_SETSIZE)
- FD_CLR(sock, &svc_fdset);
- FD_CLR(sock, __svc_fdset);
- if (sock == svc_maxfd) {
- for (svc_maxfd--; svc_maxfd >= 0; svc_maxfd--)
+ int sock;
+
+ assert(xprt != NULL);
+
+ sock = xprt->xp_fd;
+
+ rwlock_wrlock(&svc_fd_lock);
+ if ((sock < FD_SETSIZE) && (xports[sock] == xprt)) {
+ xports[sock] = NULL;
+ FD_CLR(sock, &svc_fdset);
+ if (sock >= svc_maxfd) {
+ for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--)
if (xports[svc_maxfd])
break;
}
- /*
- * XXX could use svc_maxfd as a hint to
- * decrease the size of __svc_fdset
- */
}
+ rwlock_unlock(&svc_fd_lock);
}
+/*
+ * Add a service program to the callout list.
+ * The dispatch routine will be called when a rpc request for this
+ * program number comes in.
+ */
+bool_t
+svc_reg(xprt, prog, vers, dispatch, nconf)
+ SVCXPRT *xprt;
+ const rpcprog_t prog;
+ const rpcvers_t vers;
+ void (*dispatch) __P((struct svc_req *, SVCXPRT *));
+ const struct netconfig *nconf;
+{
+ bool_t dummy;
+ struct svc_callout *prev;
+ struct svc_callout *s;
+ struct netconfig *tnconf;
+ char *netid = NULL;
+ int flag = 0;
+
+/* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */
+
+ if (xprt->xp_netid) {
+ netid = strdup(xprt->xp_netid);
+ flag = 1;
+ } else if (nconf && nconf->nc_netid) {
+ netid = strdup(nconf->nc_netid);
+ flag = 1;
+ } else if ((tnconf = __rpcgettp(xprt->xp_fd)) != NULL) {
+ netid = strdup(tnconf->nc_netid);
+ flag = 1;
+ freenetconfigent(tnconf);
+ } /* must have been created with svc_raw_create */
+ if ((netid == NULL) && (flag == 1)) {
+ return (FALSE);
+ }
+
+ rwlock_wrlock(&svc_lock);
+ if ((s = svc_find(prog, vers, &prev, netid)) != NULL) {
+ if (netid)
+ free(netid);
+ if (s->sc_dispatch == dispatch)
+ goto rpcb_it; /* he is registering another xptr */
+ rwlock_unlock(&svc_lock);
+ return (FALSE);
+ }
+ s = mem_alloc(sizeof (struct svc_callout));
+ if (s == NULL) {
+ if (netid)
+ free(netid);
+ rwlock_unlock(&svc_lock);
+ return (FALSE);
+ }
+
+ s->sc_prog = prog;
+ s->sc_vers = vers;
+ s->sc_dispatch = dispatch;
+ s->sc_netid = netid;
+ s->sc_next = svc_head;
+ svc_head = s;
+
+ if ((xprt->xp_netid == NULL) && (flag == 1) && netid)
+ ((SVCXPRT *) xprt)->xp_netid = strdup(netid);
+
+rpcb_it:
+ rwlock_unlock(&svc_lock);
+ /* now register the information with the local binder service */
+ if (nconf) {
+ /*LINTED const castaway*/
+ dummy = rpcb_set(prog, vers, (struct netconfig *) nconf,
+ &((SVCXPRT *) xprt)->xp_ltaddr);
+ return (dummy);
+ }
+ return (TRUE);
+}
+
+/*
+ * Remove a service program from the callout list.
+ */
+void
+svc_unreg(prog, vers)
+ const rpcprog_t prog;
+ const rpcvers_t vers;
+{
+ struct svc_callout *prev;
+ struct svc_callout *s;
+
+ /* unregister the information anyway */
+ (void) rpcb_unset(prog, vers, NULL);
+ rwlock_wrlock(&svc_lock);
+ while ((s = svc_find(prog, vers, &prev, NULL)) != NULL) {
+ if (prev == NULL) {
+ svc_head = s->sc_next;
+ } else {
+ prev->sc_next = s->sc_next;
+ }
+ s->sc_next = NULL;
+ if (s->sc_netid)
+ mem_free(s->sc_netid, sizeof (s->sc_netid) + 1);
+ mem_free(s, sizeof (struct svc_callout));
+ }
+ rwlock_unlock(&svc_lock);
+}
/* ********************** CALLOUT list related stuff ************* */
+#ifdef PORTMAP
/*
* Add a service program to the callout list.
* The dispatch routine will be called when a rpc request for this
@@ -162,23 +265,27 @@ svc_register(xprt, prog, vers, dispatch, protocol)
SVCXPRT *xprt;
u_long prog;
u_long vers;
- void (*dispatch)();
+ void (*dispatch) __P((struct svc_req *, SVCXPRT *));
int protocol;
{
struct svc_callout *prev;
- register struct svc_callout *s;
+ struct svc_callout *s;
+
+ assert(xprt != NULL);
+ assert(dispatch != NULL);
- if ((s = svc_find(prog, vers, &prev)) != NULL_SVC) {
+ if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) !=
+ NULL) {
if (s->sc_dispatch == dispatch)
goto pmap_it; /* he is registering another xptr */
return (FALSE);
}
- s = (struct svc_callout *)mem_alloc(sizeof(struct svc_callout));
- if (s == (struct svc_callout *)0) {
+ s = mem_alloc(sizeof(struct svc_callout));
+ if (s == NULL) {
return (FALSE);
}
- s->sc_prog = prog;
- s->sc_vers = vers;
+ s->sc_prog = (rpcprog_t)prog;
+ s->sc_vers = (rpcvers_t)vers;
s->sc_dispatch = dispatch;
s->sc_next = svc_head;
svc_head = s;
@@ -199,40 +306,46 @@ svc_unregister(prog, vers)
u_long vers;
{
struct svc_callout *prev;
- register struct svc_callout *s;
+ struct svc_callout *s;
- if ((s = svc_find(prog, vers, &prev)) == NULL_SVC)
+ if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) ==
+ NULL)
return;
- if (prev == NULL_SVC) {
+ if (prev == NULL) {
svc_head = s->sc_next;
} else {
prev->sc_next = s->sc_next;
}
- s->sc_next = NULL_SVC;
- mem_free((char *) s, (u_int) sizeof(struct svc_callout));
+ s->sc_next = NULL;
+ mem_free(s, sizeof(struct svc_callout));
/* now unregister the information with the local binder service */
(void)pmap_unset(prog, vers);
}
+#endif /* PORTMAP */
/*
* Search the callout list for a program number, return the callout
* struct.
*/
static struct svc_callout *
-svc_find(prog, vers, prev)
- u_long prog;
- u_long vers;
+svc_find(prog, vers, prev, netid)
+ rpcprog_t prog;
+ rpcvers_t vers;
struct svc_callout **prev;
+ char *netid;
{
- register struct svc_callout *s, *p;
+ struct svc_callout *s, *p;
+
+ assert(prev != NULL);
- p = NULL_SVC;
- for (s = svc_head; s != NULL_SVC; s = s->sc_next) {
- if ((s->sc_prog == prog) && (s->sc_vers == vers))
- goto done;
+ p = NULL;
+ for (s = svc_head; s != NULL; s = s->sc_next) {
+ if (((s->sc_prog == prog) && (s->sc_vers == vers)) &&
+ ((netid == NULL) || (s->sc_netid == NULL) ||
+ (strcmp(netid, s->sc_netid) == 0)))
+ break;
p = s;
}
-done:
*prev = p;
return (s);
}
@@ -244,19 +357,21 @@ done:
*/
bool_t
svc_sendreply(xprt, xdr_results, xdr_location)
- register SVCXPRT *xprt;
+ SVCXPRT *xprt;
xdrproc_t xdr_results;
caddr_t xdr_location;
{
- struct rpc_msg rply;
+ struct rpc_msg rply;
- rply.rm_direction = REPLY;
- rply.rm_reply.rp_stat = MSG_ACCEPTED;
- rply.acpted_rply.ar_verf = xprt->xp_verf;
+ assert(xprt != NULL);
+
+ rply.rm_direction = REPLY;
+ rply.rm_reply.rp_stat = MSG_ACCEPTED;
+ rply.acpted_rply.ar_verf = xprt->xp_verf;
rply.acpted_rply.ar_stat = SUCCESS;
rply.acpted_rply.ar_results.where = xdr_location;
rply.acpted_rply.ar_results.proc = xdr_results;
- return (SVC_REPLY(xprt, &rply));
+ return (SVC_REPLY(xprt, &rply));
}
/*
@@ -264,10 +379,12 @@ svc_sendreply(xprt, xdr_results, xdr_location)
*/
void
svcerr_noproc(xprt)
- register SVCXPRT *xprt;
+ SVCXPRT *xprt;
{
struct rpc_msg rply;
+ assert(xprt != NULL);
+
rply.rm_direction = REPLY;
rply.rm_reply.rp_stat = MSG_ACCEPTED;
rply.acpted_rply.ar_verf = xprt->xp_verf;
@@ -280,15 +397,17 @@ svcerr_noproc(xprt)
*/
void
svcerr_decode(xprt)
- register SVCXPRT *xprt;
+ SVCXPRT *xprt;
{
- struct rpc_msg rply;
+ struct rpc_msg rply;
- rply.rm_direction = REPLY;
- rply.rm_reply.rp_stat = MSG_ACCEPTED;
+ assert(xprt != NULL);
+
+ rply.rm_direction = REPLY;
+ rply.rm_reply.rp_stat = MSG_ACCEPTED;
rply.acpted_rply.ar_verf = xprt->xp_verf;
rply.acpted_rply.ar_stat = GARBAGE_ARGS;
- SVC_REPLY(xprt, &rply);
+ SVC_REPLY(xprt, &rply);
}
/*
@@ -296,17 +415,61 @@ svcerr_decode(xprt)
*/
void
svcerr_systemerr(xprt)
- register SVCXPRT *xprt;
+ SVCXPRT *xprt;
{
- struct rpc_msg rply;
+ struct rpc_msg rply;
- rply.rm_direction = REPLY;
- rply.rm_reply.rp_stat = MSG_ACCEPTED;
+ assert(xprt != NULL);
+
+ rply.rm_direction = REPLY;
+ rply.rm_reply.rp_stat = MSG_ACCEPTED;
rply.acpted_rply.ar_verf = xprt->xp_verf;
rply.acpted_rply.ar_stat = SYSTEM_ERR;
- SVC_REPLY(xprt, &rply);
+ SVC_REPLY(xprt, &rply);
}
+#if 0
+/*
+ * Tell RPC package to not complain about version errors to the client. This
+ * is useful when revving broadcast protocols that sit on a fixed address.
+ * There is really one (or should be only one) example of this kind of
+ * protocol: the portmapper (or rpc binder).
+ */
+void
+__svc_versquiet_on(xprt)
+ SVCXPRT *xprt;
+{
+ u_long tmp;
+
+ tmp = ((u_long) xprt->xp_p3) | SVC_VERSQUIET;
+ xprt->xp_p3 = (caddr_t) tmp;
+}
+
+void
+__svc_versquiet_off(xprt)
+ SVCXPRT *xprt;
+{
+ u_long tmp;
+
+ tmp = ((u_long) xprt->xp_p3) & ~SVC_VERSQUIET;
+ xprt->xp_p3 = (caddr_t) tmp;
+}
+
+void
+svc_versquiet(xprt)
+ SVCXPRT *xprt;
+{
+ __svc_versquiet_on(xprt);
+}
+
+int
+__svc_versquiet_get(xprt)
+ SVCXPRT *xprt;
+{
+ return ((int) xprt->xp_p3) & SVC_VERSQUIET;
+}
+#endif
+
/*
* Authentication error reply
*/
@@ -317,6 +480,8 @@ svcerr_auth(xprt, why)
{
struct rpc_msg rply;
+ assert(xprt != NULL);
+
rply.rm_direction = REPLY;
rply.rm_reply.rp_stat = MSG_DENIED;
rply.rjcted_rply.rj_stat = AUTH_ERROR;
@@ -332,21 +497,25 @@ svcerr_weakauth(xprt)
SVCXPRT *xprt;
{
+ assert(xprt != NULL);
+
svcerr_auth(xprt, AUTH_TOOWEAK);
}
/*
* Program unavailable error reply
*/
-void
+void
svcerr_noprog(xprt)
- register SVCXPRT *xprt;
+ SVCXPRT *xprt;
{
- struct rpc_msg rply;
+ struct rpc_msg rply;
- rply.rm_direction = REPLY;
- rply.rm_reply.rp_stat = MSG_ACCEPTED;
- rply.acpted_rply.ar_verf = xprt->xp_verf;
+ assert(xprt != NULL);
+
+ rply.rm_direction = REPLY;
+ rply.rm_reply.rp_stat = MSG_ACCEPTED;
+ rply.acpted_rply.ar_verf = xprt->xp_verf;
rply.acpted_rply.ar_stat = PROG_UNAVAIL;
SVC_REPLY(xprt, &rply);
}
@@ -354,20 +523,22 @@ svcerr_noprog(xprt)
/*
* Program version mismatch error reply
*/
-void
+void
svcerr_progvers(xprt, low_vers, high_vers)
- register SVCXPRT *xprt;
- u_long low_vers;
- u_long high_vers;
+ SVCXPRT *xprt;
+ rpcvers_t low_vers;
+ rpcvers_t high_vers;
{
struct rpc_msg rply;
+ assert(xprt != NULL);
+
rply.rm_direction = REPLY;
rply.rm_reply.rp_stat = MSG_ACCEPTED;
rply.acpted_rply.ar_verf = xprt->xp_verf;
rply.acpted_rply.ar_stat = PROG_MISMATCH;
- rply.acpted_rply.ar_vers.low = low_vers;
- rply.acpted_rply.ar_vers.high = high_vers;
+ rply.acpted_rply.ar_vers.low = (u_int32_t)low_vers;
+ rply.acpted_rply.ar_vers.high = (u_int32_t)high_vers;
SVC_REPLY(xprt, &rply);
}
@@ -404,90 +575,142 @@ void
svc_getreqset(readfds)
fd_set *readfds;
{
- svc_getreqset2(readfds, FD_SETSIZE);
+ int bit, fd;
+ fd_mask mask, *maskp;
+ int sock;
+
+ assert(readfds != NULL);
+
+ maskp = readfds->fds_bits;
+ for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) {
+ for (mask = *maskp++; (bit = ffs(mask)) != 0;
+ mask ^= (1 << (bit - 1))) {
+ /* sock has input waiting */
+ fd = sock + bit - 1;
+ svc_getreq_common(fd);
+ }
+ }
}
void
-svc_getreqset2(readfds, width)
- fd_set *readfds;
- int width;
+svc_getreq_common(fd)
+ int fd;
{
- enum xprt_stat stat;
+ SVCXPRT *xprt;
+ struct svc_req r;
struct rpc_msg msg;
int prog_found;
- u_long low_vers;
- u_long high_vers;
- struct svc_req r;
- register SVCXPRT *xprt;
- register int bit;
- register int sock;
- register fd_mask mask, *maskp;
+ rpcvers_t low_vers;
+ rpcvers_t high_vers;
+ enum xprt_stat stat;
char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE];
+
msg.rm_call.cb_cred.oa_base = cred_area;
msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]);
-
- maskp = readfds->fds_bits;
- for (sock = 0; sock < width; sock += NFDBITS) {
- for (mask = *maskp++; (bit = ffs(mask)); mask ^= (1 << (bit - 1))) {
- /* sock has input waiting */
- xprt = xports[sock + bit - 1];
- if (xprt == NULL)
- /* But do we control sock? */
- continue;
- /* now receive msgs from xprtprt (support batch calls) */
- do {
- if (SVC_RECV(xprt, &msg)) {
-
- /* now find the exported program and call it */
- register struct svc_callout *s;
- enum auth_stat why;
-
- r.rq_xprt = xprt;
- r.rq_prog = msg.rm_call.cb_prog;
- r.rq_vers = msg.rm_call.cb_vers;
- r.rq_proc = msg.rm_call.cb_proc;
- r.rq_cred = msg.rm_call.cb_cred;
- /* first authenticate the message */
- if ((why= _authenticate(&r, &msg)) != AUTH_OK) {
- svcerr_auth(xprt, why);
- goto call_done;
- }
- /* now match message with a registered service*/
- prog_found = FALSE;
- low_vers = (u_long) - 1;
- high_vers = 0;
- for (s = svc_head; s != NULL_SVC; s = s->sc_next) {
- if (s->sc_prog == r.rq_prog) {
- if (s->sc_vers == r.rq_vers) {
- (*s->sc_dispatch)(&r, xprt);
- goto call_done;
- } /* found correct version */
- prog_found = TRUE;
- if (s->sc_vers < low_vers)
- low_vers = s->sc_vers;
- if (s->sc_vers > high_vers)
- high_vers = s->sc_vers;
- } /* found correct program */
- }
- /*
- * if we got here, the program or version
- * is not served ...
- */
- if (prog_found)
- svcerr_progvers(xprt,
- low_vers, high_vers);
- else
- svcerr_noprog(xprt);
- /* Fall through to ... */
+ rwlock_rdlock(&svc_fd_lock);
+ xprt = xports[fd];
+ rwlock_unlock(&svc_fd_lock);
+ if (xprt == NULL)
+ /* But do we control sock? */
+ return;
+ /* now receive msgs from xprtprt (support batch calls) */
+ do {
+ if (SVC_RECV(xprt, &msg)) {
+
+ /* now find the exported program and call it */
+ struct svc_callout *s;
+ enum auth_stat why;
+
+ r.rq_xprt = xprt;
+ r.rq_prog = msg.rm_call.cb_prog;
+ r.rq_vers = msg.rm_call.cb_vers;
+ r.rq_proc = msg.rm_call.cb_proc;
+ r.rq_cred = msg.rm_call.cb_cred;
+ /* first authenticate the message */
+ if ((why = _authenticate(&r, &msg)) != AUTH_OK) {
+ svcerr_auth(xprt, why);
+ goto call_done;
}
- call_done:
- if ((stat = SVC_STAT(xprt)) == XPRT_DIED){
- SVC_DESTROY(xprt);
- break;
+ /* now match message with a registered service*/
+ prog_found = FALSE;
+ low_vers = (rpcvers_t) -1L;
+ high_vers = (rpcvers_t) 0L;
+ for (s = svc_head; s != NULL; s = s->sc_next) {
+ if (s->sc_prog == r.rq_prog) {
+ if (s->sc_vers == r.rq_vers) {
+ (*s->sc_dispatch)(&r, xprt);
+ goto call_done;
+ } /* found correct version */
+ prog_found = TRUE;
+ if (s->sc_vers < low_vers)
+ low_vers = s->sc_vers;
+ if (s->sc_vers > high_vers)
+ high_vers = s->sc_vers;
+ } /* found correct program */
}
- } while (stat == XPRT_MOREREQS);
- }
+ /*
+ * if we got here, the program or version
+ * is not served ...
+ */
+ if (prog_found)
+ svcerr_progvers(xprt, low_vers, high_vers);
+ else
+ svcerr_noprog(xprt);
+ /* Fall through to ... */
+ }
+ /*
+ * Check if the xprt has been disconnected in a
+ * recursive call in the service dispatch routine.
+ * If so, then break.
+ */
+ rwlock_rdlock(&svc_fd_lock);
+ if (xprt != xports[fd]) {
+ rwlock_unlock(&svc_fd_lock);
+ break;
+ }
+ rwlock_unlock(&svc_fd_lock);
+call_done:
+ if ((stat = SVC_STAT(xprt)) == XPRT_DIED){
+ SVC_DESTROY(xprt);
+ break;
+ }
+ } while (stat == XPRT_MOREREQS);
+}
+
+
+void
+svc_getreq_poll(pfdp, pollretval)
+ struct pollfd *pfdp;
+ int pollretval;
+{
+ int i;
+ int fds_found;
+
+ for (i = fds_found = 0; fds_found < pollretval; i++) {
+ struct pollfd *p = &pfdp[i];
+
+ if (p->revents) {
+ /* fd has input waiting */
+ fds_found++;
+ /*
+ * We assume that this function is only called
+ * via someone _select()ing from svc_fdset or
+ * _poll()ing from svc_pollset[]. Thus it's safe
+ * to handle the POLLNVAL event by simply turning
+ * the corresponding bit off in svc_fdset. The
+ * svc_pollset[] array is derived from svc_fdset
+ * and so will also be updated eventually.
+ *
+ * XXX Should we do an xprt_unregister() instead?
+ */
+ if (p->revents & POLLNVAL) {
+ rwlock_wrlock(&svc_fd_lock);
+ FD_CLR(p->fd, &svc_fdset);
+ rwlock_unlock(&svc_fd_lock);
+ } else
+ svc_getreq_common(p->fd);
+ }
}
}