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