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 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 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 197 xprt_unregister(SVCXPRT *xprt) 198 { 199 __xprt_do_unregister(xprt, TRUE); 200 } 201 202 void 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 669 svc_getreqset(fd_set *readfds) 670 { 671 svc_getreqset2(readfds, FD_SETSIZE); 672 } 673 674 void 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 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 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