summaryrefslogtreecommitdiffstats
path: root/lib/libc/rpc/svc.c
diff options
context:
space:
mode:
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 94d6057..6e57245 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);
+ }
}
}
OpenPOWER on IntegriCloud