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