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