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