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