1/*	$NetBSD: svc.c,v 1.30 2010/07/08 20:12:37 tron Exp $	*/
2
3/*
4 * Copyright (c) 2010, Oracle America, Inc.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 *     * Redistributions of source code must retain the above copyright
11 *       notice, this list of conditions and the following disclaimer.
12 *     * Redistributions in binary form must reproduce the above
13 *       copyright notice, this list of conditions and the following
14 *       disclaimer in the documentation and/or other materials
15 *       provided with the distribution.
16 *     * Neither the name of the "Oracle America, Inc." nor the names of its
17 *       contributors may be used to endorse or promote products derived
18 *       from this software without specific prior written permission.
19 *
20 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27 *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include <sys/cdefs.h>
35#if defined(LIBC_SCCS) && !defined(lint)
36#if 0
37static char *sccsid = "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro";
38static char *sccsid = "@(#)svc.c	2.4 88/08/11 4.0 RPCSRC";
39#else
40__RCSID("$NetBSD: svc.c,v 1.30 2010/07/08 20:12:37 tron Exp $");
41#endif
42#endif
43
44/*
45 * svc.c, Server-side remote procedure call interface.
46 *
47 * There are two sets of procedures here.  The xprt routines are
48 * for handling transport handles.  The svc routines handle the
49 * list of service routines.
50 *
51 * Copyright (C) 1984, Sun Microsystems, Inc.
52 */
53
54#include "namespace.h"
55#include "reentrant.h"
56#include <sys/types.h>
57#include <sys/poll.h>
58#include <assert.h>
59#include <errno.h>
60#include <stdlib.h>
61#include <string.h>
62#include <err.h>
63
64#include <rpc/rpc.h>
65#ifdef PORTMAP
66#include <rpc/pmap_clnt.h>
67#endif
68
69#include "rpc_internal.h"
70
71#ifdef __weak_alias
72__weak_alias(svc_getreq,_svc_getreq)
73__weak_alias(svc_getreqset,_svc_getreqset)
74__weak_alias(svc_getreq_common,_svc_getreq_common)
75__weak_alias(svc_register,_svc_register)
76__weak_alias(svc_reg,_svc_reg)
77__weak_alias(svc_unreg,_svc_unreg)
78__weak_alias(svc_sendreply,_svc_sendreply)
79__weak_alias(svc_unregister,_svc_unregister)
80__weak_alias(svcerr_auth,_svcerr_auth)
81__weak_alias(svcerr_decode,_svcerr_decode)
82__weak_alias(svcerr_noproc,_svcerr_noproc)
83__weak_alias(svcerr_noprog,_svcerr_noprog)
84__weak_alias(svcerr_progvers,_svcerr_progvers)
85__weak_alias(svcerr_systemerr,_svcerr_systemerr)
86__weak_alias(svcerr_weakauth,_svcerr_weakauth)
87__weak_alias(xprt_register,_xprt_register)
88__weak_alias(xprt_unregister,_xprt_unregister)
89__weak_alias(rpc_control,_rpc_control)
90#endif
91
92SVCXPRT **__svc_xports;
93int __svc_maxrec;
94
95#define	RQCRED_SIZE	400		/* this size is excessive */
96
97#define SVC_VERSQUIET 0x0001		/* keep quiet about vers mismatch */
98#define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET)
99
100#define max(a, b) (a > b ? a : b)
101
102/*
103 * The services list
104 * Each entry represents a set of procedures (an rpc program).
105 * The dispatch routine takes request structs and runs the
106 * apropriate procedure.
107 */
108static struct svc_callout {
109	struct svc_callout *sc_next;
110	rpcprog_t	    sc_prog;
111	rpcvers_t	    sc_vers;
112	char		   *sc_netid;
113	void		    (*sc_dispatch) __P((struct svc_req *, SVCXPRT *));
114} *svc_head;
115
116#ifdef _REENTRANT
117extern rwlock_t svc_lock;
118extern rwlock_t svc_fd_lock;
119#endif
120
121static struct svc_callout *svc_find __P((rpcprog_t, rpcvers_t,
122					 struct svc_callout **, char *));
123static void __xprt_do_unregister __P((SVCXPRT *xprt, bool_t dolock));
124
125/* ***************  SVCXPRT related stuff **************** */
126
127/*
128 * Activate a transport handle.
129 */
130void
131xprt_register(xprt)
132	SVCXPRT *xprt;
133{
134	int sock;
135
136	_DIAGASSERT(xprt != NULL);
137
138	sock = xprt->xp_fd;
139
140	rwlock_wrlock(&svc_fd_lock);
141	if (__svc_xports == NULL) {
142		__svc_xports = mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *));
143		if (__svc_xports == NULL) {
144			warn("xprt_register");
145			goto out;
146		}
147		memset(__svc_xports, '\0', FD_SETSIZE * sizeof(SVCXPRT *));
148	}
149	if (sock < FD_SETSIZE) {
150		__svc_xports[sock] = xprt;
151		FD_SET(sock, &svc_fdset);
152		svc_maxfd = max(svc_maxfd, sock);
153	}
154out:
155	rwlock_unlock(&svc_fd_lock);
156}
157
158void
159xprt_unregister(SVCXPRT *xprt)
160{
161	__xprt_do_unregister(xprt, TRUE);
162}
163
164void
165__xprt_unregister_unlocked(SVCXPRT *xprt)
166{
167	__xprt_do_unregister(xprt, FALSE);
168}
169
170/*
171 * De-activate a transport handle.
172 */
173static void
174__xprt_do_unregister(xprt, dolock)
175	SVCXPRT *xprt;
176	bool_t dolock;
177{
178	int sock;
179
180	_DIAGASSERT(xprt != NULL);
181
182	sock = xprt->xp_fd;
183
184	if (dolock)
185		rwlock_wrlock(&svc_fd_lock);
186	if ((sock < FD_SETSIZE) && (__svc_xports[sock] == xprt)) {
187		__svc_xports[sock] = NULL;
188		FD_CLR(sock, &svc_fdset);
189		if (sock >= svc_maxfd) {
190			for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--)
191				if (__svc_xports[svc_maxfd])
192					break;
193		}
194	}
195	if (dolock)
196		rwlock_unlock(&svc_fd_lock);
197}
198
199/*
200 * Add a service program to the callout list.
201 * The dispatch routine will be called when a rpc request for this
202 * program number comes in.
203 */
204bool_t
205svc_reg(xprt, prog, vers, dispatch, nconf)
206	SVCXPRT *xprt;
207	const rpcprog_t prog;
208	const rpcvers_t vers;
209	void (*dispatch) __P((struct svc_req *, SVCXPRT *));
210	const struct netconfig *nconf;
211{
212	bool_t dummy;
213	struct svc_callout *prev;
214	struct svc_callout *s;
215	struct netconfig *tnconf;
216	char *netid = NULL;
217	int flag = 0;
218
219	_DIAGASSERT(xprt != NULL);
220	/* XXX: dispatch may be NULL ??? */
221
222/* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */
223
224	if (xprt->xp_netid) {
225		netid = strdup(xprt->xp_netid);
226		flag = 1;
227	} else if (nconf && nconf->nc_netid) {
228		netid = strdup(nconf->nc_netid);
229		flag = 1;
230	} else if ((tnconf = __rpcgettp(xprt->xp_fd)) != NULL) {
231		netid = strdup(tnconf->nc_netid);
232		flag = 1;
233		freenetconfigent(tnconf);
234	} /* must have been created with svc_raw_create */
235	if ((netid == NULL) && (flag == 1)) {
236		return (FALSE);
237	}
238
239	rwlock_wrlock(&svc_lock);
240	if ((s = svc_find(prog, vers, &prev, netid)) != NULL) {
241		if (netid)
242			free(netid);
243		if (s->sc_dispatch == dispatch)
244			goto rpcb_it; /* he is registering another xptr */
245		rwlock_unlock(&svc_lock);
246		return (FALSE);
247	}
248	s = mem_alloc(sizeof (struct svc_callout));
249	if (s == NULL) {
250		if (netid)
251			free(netid);
252		rwlock_unlock(&svc_lock);
253		return (FALSE);
254	}
255
256	if ((xprt->xp_netid == NULL) && (flag == 1) && netid)
257		if ((((SVCXPRT *) xprt)->xp_netid = strdup(netid)) == NULL) {
258			warn("svc_reg");
259			mem_free(s, sizeof(struct svc_callout));
260			rwlock_unlock(&svc_lock);
261			return FALSE;
262		}
263
264	s->sc_prog = prog;
265	s->sc_vers = vers;
266	s->sc_dispatch = dispatch;
267	s->sc_netid = netid;
268	s->sc_next = svc_head;
269	svc_head = s;
270
271rpcb_it:
272	rwlock_unlock(&svc_lock);
273	/* now register the information with the local binder service */
274	if (nconf) {
275		dummy = rpcb_set(prog, vers, __UNCONST(nconf),
276		&((SVCXPRT *) xprt)->xp_ltaddr);
277		return (dummy);
278	}
279	return (TRUE);
280}
281
282/*
283 * Remove a service program from the callout list.
284 */
285void
286svc_unreg(prog, vers)
287	const rpcprog_t prog;
288	const rpcvers_t vers;
289{
290	struct svc_callout *prev;
291	struct svc_callout *s;
292
293	/* unregister the information anyway */
294	(void) rpcb_unset(prog, vers, NULL);
295	rwlock_wrlock(&svc_lock);
296	while ((s = svc_find(prog, vers, &prev, NULL)) != NULL) {
297		if (prev == NULL) {
298			svc_head = s->sc_next;
299		} else {
300			prev->sc_next = s->sc_next;
301		}
302		s->sc_next = NULL;
303		if (s->sc_netid)
304			mem_free(s->sc_netid, sizeof (s->sc_netid) + 1);
305		mem_free(s, sizeof (struct svc_callout));
306	}
307	rwlock_unlock(&svc_lock);
308}
309
310/* ********************** CALLOUT list related stuff ************* */
311
312#ifdef PORTMAP
313/*
314 * Add a service program to the callout list.
315 * The dispatch routine will be called when a rpc request for this
316 * program number comes in.
317 */
318bool_t
319svc_register(xprt, prog, vers, dispatch, protocol)
320	SVCXPRT *xprt;
321	u_long prog;
322	u_long vers;
323	void (*dispatch) __P((struct svc_req *, SVCXPRT *));
324	int protocol;
325{
326	struct svc_callout *prev;
327	struct svc_callout *s;
328
329	_DIAGASSERT(xprt != NULL);
330	_DIAGASSERT(dispatch != NULL);
331
332	if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) !=
333	    NULL) {
334		if (s->sc_dispatch == dispatch)
335			goto pmap_it;  /* he is registering another xptr */
336		return (FALSE);
337	}
338	s = mem_alloc(sizeof(struct svc_callout));
339	if (s == NULL) {
340		return (FALSE);
341	}
342	s->sc_prog = (rpcprog_t)prog;
343	s->sc_vers = (rpcvers_t)vers;
344	s->sc_dispatch = dispatch;
345	s->sc_next = svc_head;
346	svc_head = s;
347pmap_it:
348	/* now register the information with the local binder service */
349	if (protocol) {
350		return (pmap_set(prog, vers, protocol, xprt->xp_port));
351	}
352	return (TRUE);
353}
354
355/*
356 * Remove a service program from the callout list.
357 */
358void
359svc_unregister(prog, vers)
360	u_long prog;
361	u_long vers;
362{
363	struct svc_callout *prev;
364	struct svc_callout *s;
365
366	if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) ==
367	    NULL)
368		return;
369	if (prev == NULL) {
370		svc_head = s->sc_next;
371	} else {
372		prev->sc_next = s->sc_next;
373	}
374	s->sc_next = NULL;
375	mem_free(s, sizeof(struct svc_callout));
376	/* now unregister the information with the local binder service */
377	(void)pmap_unset(prog, vers);
378}
379#endif /* PORTMAP */
380
381/*
382 * Search the callout list for a program number, return the callout
383 * struct.
384 */
385static struct svc_callout *
386svc_find(prog, vers, prev, netid)
387	rpcprog_t prog;
388	rpcvers_t vers;
389	struct svc_callout **prev;
390	char *netid;
391{
392	struct svc_callout *s, *p;
393
394	_DIAGASSERT(prev != NULL);
395	/* netid is handled below */
396
397	p = NULL;
398	for (s = svc_head; s != NULL; s = s->sc_next) {
399		if (((s->sc_prog == prog) && (s->sc_vers == vers)) &&
400		    ((netid == NULL) || (s->sc_netid == NULL) ||
401		    (strcmp(netid, s->sc_netid) == 0)))
402			break;
403		p = s;
404	}
405	*prev = p;
406	return (s);
407}
408
409/* ******************* REPLY GENERATION ROUTINES  ************ */
410
411/*
412 * Send a reply to an rpc request
413 */
414bool_t
415svc_sendreply(xprt, xdr_results, xdr_location)
416	SVCXPRT *xprt;
417	xdrproc_t xdr_results;
418	const char *xdr_location;
419{
420	struct rpc_msg rply;
421
422	_DIAGASSERT(xprt != NULL);
423
424	rply.rm_direction = REPLY;
425	rply.rm_reply.rp_stat = MSG_ACCEPTED;
426	rply.acpted_rply.ar_verf = xprt->xp_verf;
427	rply.acpted_rply.ar_stat = SUCCESS;
428	rply.acpted_rply.ar_results.where = xdr_location;
429	rply.acpted_rply.ar_results.proc = xdr_results;
430	return (SVC_REPLY(xprt, &rply));
431}
432
433/*
434 * No procedure error reply
435 */
436void
437svcerr_noproc(xprt)
438	SVCXPRT *xprt;
439{
440	struct rpc_msg rply;
441
442	_DIAGASSERT(xprt != NULL);
443
444	rply.rm_direction = REPLY;
445	rply.rm_reply.rp_stat = MSG_ACCEPTED;
446	rply.acpted_rply.ar_verf = xprt->xp_verf;
447	rply.acpted_rply.ar_stat = PROC_UNAVAIL;
448	SVC_REPLY(xprt, &rply);
449}
450
451/*
452 * Can't decode args error reply
453 */
454void
455svcerr_decode(xprt)
456	SVCXPRT *xprt;
457{
458	struct rpc_msg rply;
459
460	_DIAGASSERT(xprt != NULL);
461
462	rply.rm_direction = REPLY;
463	rply.rm_reply.rp_stat = MSG_ACCEPTED;
464	rply.acpted_rply.ar_verf = xprt->xp_verf;
465	rply.acpted_rply.ar_stat = GARBAGE_ARGS;
466	SVC_REPLY(xprt, &rply);
467}
468
469/*
470 * Some system error
471 */
472void
473svcerr_systemerr(xprt)
474	SVCXPRT *xprt;
475{
476	struct rpc_msg rply;
477
478	_DIAGASSERT(xprt != NULL);
479
480	rply.rm_direction = REPLY;
481	rply.rm_reply.rp_stat = MSG_ACCEPTED;
482	rply.acpted_rply.ar_verf = xprt->xp_verf;
483	rply.acpted_rply.ar_stat = SYSTEM_ERR;
484	SVC_REPLY(xprt, &rply);
485}
486
487#if 0
488/*
489 * Tell RPC package to not complain about version errors to the client.	 This
490 * is useful when revving broadcast protocols that sit on a fixed address.
491 * There is really one (or should be only one) example of this kind of
492 * protocol: the portmapper (or rpc binder).
493 */
494void
495__svc_versquiet_on(xprt)
496	SVCXPRT *xprt;
497{
498	u_long	tmp;
499
500	_DIAGASSERT(xprt != NULL);
501
502	tmp = ((u_long) xprt->xp_p3) | SVC_VERSQUIET;
503	xprt->xp_p3 = (caddr_t) tmp;
504}
505
506void
507__svc_versquiet_off(xprt)
508	SVCXPRT *xprt;
509{
510	u_long	tmp;
511
512	_DIAGASSERT(xprt != NULL);
513
514	tmp = ((u_long) xprt->xp_p3) & ~SVC_VERSQUIET;
515	xprt->xp_p3 = (caddr_t) tmp;
516}
517
518void
519svc_versquiet(xprt)
520	SVCXPRT *xprt;
521{
522	__svc_versquiet_on(xprt);
523}
524
525int
526__svc_versquiet_get(xprt)
527	SVCXPRT *xprt;
528{
529
530	_DIAGASSERT(xprt != NULL);
531
532	return ((int) xprt->xp_p3) & SVC_VERSQUIET;
533}
534#endif
535
536/*
537 * Authentication error reply
538 */
539void
540svcerr_auth(xprt, why)
541	SVCXPRT *xprt;
542	enum auth_stat why;
543{
544	struct rpc_msg rply;
545
546	_DIAGASSERT(xprt != NULL);
547
548	rply.rm_direction = REPLY;
549	rply.rm_reply.rp_stat = MSG_DENIED;
550	rply.rjcted_rply.rj_stat = AUTH_ERROR;
551	rply.rjcted_rply.rj_why = why;
552	SVC_REPLY(xprt, &rply);
553}
554
555/*
556 * Auth too weak error reply
557 */
558void
559svcerr_weakauth(xprt)
560	SVCXPRT *xprt;
561{
562
563	_DIAGASSERT(xprt != NULL);
564
565	svcerr_auth(xprt, AUTH_TOOWEAK);
566}
567
568/*
569 * Program unavailable error reply
570 */
571void
572svcerr_noprog(xprt)
573	SVCXPRT *xprt;
574{
575	struct rpc_msg rply;
576
577	_DIAGASSERT(xprt != NULL);
578
579	rply.rm_direction = REPLY;
580	rply.rm_reply.rp_stat = MSG_ACCEPTED;
581	rply.acpted_rply.ar_verf = xprt->xp_verf;
582	rply.acpted_rply.ar_stat = PROG_UNAVAIL;
583	SVC_REPLY(xprt, &rply);
584}
585
586/*
587 * Program version mismatch error reply
588 */
589void
590svcerr_progvers(xprt, low_vers, high_vers)
591	SVCXPRT *xprt;
592	rpcvers_t low_vers;
593	rpcvers_t high_vers;
594{
595	struct rpc_msg rply;
596
597	_DIAGASSERT(xprt != NULL);
598
599	rply.rm_direction = REPLY;
600	rply.rm_reply.rp_stat = MSG_ACCEPTED;
601	rply.acpted_rply.ar_verf = xprt->xp_verf;
602	rply.acpted_rply.ar_stat = PROG_MISMATCH;
603	rply.acpted_rply.ar_vers.low = (u_int32_t)low_vers;
604	rply.acpted_rply.ar_vers.high = (u_int32_t)high_vers;
605	SVC_REPLY(xprt, &rply);
606}
607
608/* ******************* SERVER INPUT STUFF ******************* */
609
610/*
611 * Get server side input from some transport.
612 *
613 * Statement of authentication parameters management:
614 * This function owns and manages all authentication parameters, specifically
615 * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
616 * the "cooked" credentials (rqst->rq_clntcred).
617 * However, this function does not know the structure of the cooked
618 * credentials, so it make the following assumptions:
619 *   a) the structure is contiguous (no pointers), and
620 *   b) the cred structure size does not exceed RQCRED_SIZE bytes.
621 * In all events, all three parameters are freed upon exit from this routine.
622 * The storage is trivially management on the call stack in user land, but
623 * is mallocated in kernel land.
624 */
625
626void
627svc_getreq(rdfds)
628	int rdfds;
629{
630	fd_set readfds;
631
632	FD_ZERO(&readfds);
633	readfds.fds_bits[0] = (unsigned int)rdfds;
634	svc_getreqset(&readfds);
635}
636
637void
638svc_getreqset(readfds)
639	fd_set *readfds;
640{
641	uint32_t mask, *maskp;
642	int sock, bit, fd;
643
644	_DIAGASSERT(readfds != NULL);
645
646	maskp = readfds->fds_bits;
647	for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) {
648	    for (mask = *maskp++; (bit = ffs((int)mask)) != 0;
649		mask ^= (1 << (bit - 1))) {
650		/* sock has input waiting */
651		fd = sock + bit - 1;
652		svc_getreq_common(fd);
653	    }
654	}
655}
656
657void
658svc_getreq_common(fd)
659	int fd;
660{
661	SVCXPRT *xprt;
662	struct svc_req r;
663	struct rpc_msg msg;
664	int prog_found;
665	rpcvers_t low_vers;
666	rpcvers_t high_vers;
667	enum xprt_stat stat;
668	char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE];
669
670	msg.rm_call.cb_cred.oa_base = cred_area;
671	msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
672	r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]);
673
674	rwlock_rdlock(&svc_fd_lock);
675	xprt = __svc_xports[fd];
676	rwlock_unlock(&svc_fd_lock);
677	if (xprt == NULL)
678		/* But do we control sock? */
679		return;
680	/* now receive msgs from xprtprt (support batch calls) */
681	do {
682		if (SVC_RECV(xprt, &msg)) {
683
684			/* now find the exported program and call it */
685			struct svc_callout *s;
686			enum auth_stat why;
687
688			r.rq_xprt = xprt;
689			r.rq_prog = msg.rm_call.cb_prog;
690			r.rq_vers = msg.rm_call.cb_vers;
691			r.rq_proc = msg.rm_call.cb_proc;
692			r.rq_cred = msg.rm_call.cb_cred;
693			/* first authenticate the message */
694			if ((why = _authenticate(&r, &msg)) != AUTH_OK) {
695				svcerr_auth(xprt, why);
696				goto call_done;
697			}
698			/* now match message with a registered service*/
699			prog_found = FALSE;
700			low_vers = (rpcvers_t) -1L;
701			high_vers = (rpcvers_t) 0L;
702			for (s = svc_head; s != NULL; s = s->sc_next) {
703				if (s->sc_prog == r.rq_prog) {
704					if (s->sc_vers == r.rq_vers) {
705						(*s->sc_dispatch)(&r, xprt);
706						goto call_done;
707					}  /* found correct version */
708					prog_found = TRUE;
709					if (s->sc_vers < low_vers)
710						low_vers = s->sc_vers;
711					if (s->sc_vers > high_vers)
712						high_vers = s->sc_vers;
713				}   /* found correct program */
714			}
715			/*
716			 * if we got here, the program or version
717			 * is not served ...
718			 */
719			if (prog_found)
720				svcerr_progvers(xprt, low_vers, high_vers);
721			else
722				 svcerr_noprog(xprt);
723			/* Fall through to ... */
724		}
725		/*
726		 * Check if the xprt has been disconnected in a
727		 * recursive call in the service dispatch routine.
728		 * If so, then break.
729		 */
730		rwlock_rdlock(&svc_fd_lock);
731		if (xprt != __svc_xports[fd]) {
732			rwlock_unlock(&svc_fd_lock);
733			break;
734		}
735		rwlock_unlock(&svc_fd_lock);
736call_done:
737		if ((stat = SVC_STAT(xprt)) == XPRT_DIED){
738			SVC_DESTROY(xprt);
739			break;
740		}
741	} while (stat == XPRT_MOREREQS);
742}
743
744
745void
746svc_getreq_poll(pfdp, pollretval)
747	struct pollfd	*pfdp;
748	int	pollretval;
749{
750	int i;
751	int fds_found;
752
753	_DIAGASSERT(pfdp != NULL);
754
755	for (i = fds_found = 0; fds_found < pollretval; i++) {
756		struct pollfd *p = &pfdp[i];
757
758		if (p->revents) {
759			/* fd has input waiting */
760			fds_found++;
761			/*
762			 *	We assume that this function is only called
763			 *	via someone select()ing from svc_fdset or
764			 *	pollts()ing from svc_pollset[].  Thus it's safe
765			 *	to handle the POLLNVAL event by simply turning
766			 *	the corresponding bit off in svc_fdset.  The
767			 *	svc_pollset[] array is derived from svc_fdset
768			 *	and so will also be updated eventually.
769			 *
770			 *	XXX Should we do an xprt_unregister() instead?
771			 */
772			if (p->revents & POLLNVAL) {
773				rwlock_wrlock(&svc_fd_lock);
774				FD_CLR(p->fd, &svc_fdset);
775				rwlock_unlock(&svc_fd_lock);
776			} else
777				svc_getreq_common(p->fd);
778		}
779	}
780}
781
782bool_t
783rpc_control(int what, void *arg)
784{
785	int val;
786
787	switch (what) {
788	case RPC_SVC_CONNMAXREC_SET:
789		val = *(int *)arg;
790		if (val <= 0)
791			return FALSE;
792		__svc_maxrec = val;
793		return TRUE;
794	case RPC_SVC_CONNMAXREC_GET:
795		*(int *)arg = __svc_maxrec;
796		return TRUE;
797	default:
798		break;
799	}
800	return FALSE;
801}
802