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