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