1 /* $NetBSD: svc.c,v 1.21 2000/07/06 03:10:35 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2009, Sun Microsystems, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * - Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * - Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * - Neither the name of Sun Microsystems, Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #if defined(LIBC_SCCS) && !defined(lint) 32 static char *sccsid2 = "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro"; 33 static char *sccsid = "@(#)svc.c 2.4 88/08/11 4.0 RPCSRC"; 34 #endif 35 #include <sys/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 38 /* 39 * svc.c, Server-side remote procedure call interface. 40 * 41 * There are two sets of procedures here. The xprt routines are 42 * for handling transport handles. The svc routines handle the 43 * list of service routines. 44 * 45 * Copyright (C) 1984, Sun Microsystems, Inc. 46 */ 47 48 #include "namespace.h" 49 #include "reentrant.h" 50 #include <sys/types.h> 51 #include <sys/poll.h> 52 #include <assert.h> 53 #include <errno.h> 54 #include <stdlib.h> 55 #include <string.h> 56 57 #include <rpc/rpc.h> 58 #ifdef PORTMAP 59 #include <rpc/pmap_clnt.h> 60 #endif /* PORTMAP */ 61 #include "un-namespace.h" 62 63 #include "rpc_com.h" 64 #include "mt_misc.h" 65 66 #define RQCRED_SIZE 400 /* this size is excessive */ 67 68 #define SVC_VERSQUIET 0x0001 /* keep quiet about vers mismatch */ 69 #define version_keepquiet(xp) (SVC_EXT(xp)->xp_flags & SVC_VERSQUIET) 70 71 #define max(a, b) (a > b ? a : b) 72 73 /* 74 * The services list 75 * Each entry represents a set of procedures (an rpc program). 76 * The dispatch routine takes request structs and runs the 77 * apropriate procedure. 78 */ 79 static struct svc_callout { 80 struct svc_callout *sc_next; 81 rpcprog_t sc_prog; 82 rpcvers_t sc_vers; 83 char *sc_netid; 84 void (*sc_dispatch)(struct svc_req *, SVCXPRT *); 85 } *svc_head; 86 87 SVCXPRT **__svc_xports; 88 int __svc_maxrec; 89 90 static struct svc_callout *svc_find(rpcprog_t, rpcvers_t, 91 struct svc_callout **, char *); 92 static void __xprt_do_unregister (SVCXPRT *xprt, bool_t dolock); 93 94 /* *************** SVCXPRT related stuff **************** */ 95 96 /* 97 * Activate a transport handle. 98 */ 99 void 100 xprt_register(xprt) 101 SVCXPRT *xprt; 102 { 103 int sock; 104 105 assert(xprt != NULL); 106 107 sock = xprt->xp_fd; 108 109 rwlock_wrlock(&svc_fd_lock); 110 if (__svc_xports == NULL) { 111 __svc_xports = (SVCXPRT **) 112 mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *)); 113 if (__svc_xports == NULL) { 114 rwlock_unlock(&svc_fd_lock); 115 return; 116 } 117 memset(__svc_xports, '\0', FD_SETSIZE * sizeof(SVCXPRT *)); 118 } 119 if (sock < FD_SETSIZE) { 120 __svc_xports[sock] = xprt; 121 FD_SET(sock, &svc_fdset); 122 svc_maxfd = max(svc_maxfd, sock); 123 } 124 rwlock_unlock(&svc_fd_lock); 125 } 126 127 void 128 xprt_unregister(SVCXPRT *xprt) 129 { 130 __xprt_do_unregister(xprt, TRUE); 131 } 132 133 void 134 __xprt_unregister_unlocked(SVCXPRT *xprt) 135 { 136 __xprt_do_unregister(xprt, FALSE); 137 } 138 139 /* 140 * De-activate a transport handle. 141 */ 142 static void 143 __xprt_do_unregister(xprt, dolock) 144 SVCXPRT *xprt; 145 bool_t dolock; 146 { 147 int sock; 148 149 assert(xprt != NULL); 150 151 sock = xprt->xp_fd; 152 153 if (dolock) 154 rwlock_wrlock(&svc_fd_lock); 155 if ((sock < FD_SETSIZE) && (__svc_xports[sock] == xprt)) { 156 __svc_xports[sock] = NULL; 157 FD_CLR(sock, &svc_fdset); 158 if (sock >= svc_maxfd) { 159 for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--) 160 if (__svc_xports[svc_maxfd]) 161 break; 162 } 163 } 164 if (dolock) 165 rwlock_unlock(&svc_fd_lock); 166 } 167 168 /* 169 * Add a service program to the callout list. 170 * The dispatch routine will be called when a rpc request for this 171 * program number comes in. 172 */ 173 bool_t 174 svc_reg(xprt, prog, vers, dispatch, nconf) 175 SVCXPRT *xprt; 176 const rpcprog_t prog; 177 const rpcvers_t vers; 178 void (*dispatch)(struct svc_req *, SVCXPRT *); 179 const struct netconfig *nconf; 180 { 181 bool_t dummy; 182 struct svc_callout *prev; 183 struct svc_callout *s; 184 struct netconfig *tnconf; 185 char *netid = NULL; 186 int flag = 0; 187 188 /* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */ 189 190 if (xprt->xp_netid) { 191 netid = strdup(xprt->xp_netid); 192 flag = 1; 193 } else if (nconf && nconf->nc_netid) { 194 netid = strdup(nconf->nc_netid); 195 flag = 1; 196 } else if ((tnconf = __rpcgettp(xprt->xp_fd)) != NULL) { 197 netid = strdup(tnconf->nc_netid); 198 flag = 1; 199 freenetconfigent(tnconf); 200 } /* must have been created with svc_raw_create */ 201 if ((netid == NULL) && (flag == 1)) { 202 return (FALSE); 203 } 204 205 rwlock_wrlock(&svc_lock); 206 if ((s = svc_find(prog, vers, &prev, netid)) != NULL) { 207 if (netid) 208 free(netid); 209 if (s->sc_dispatch == dispatch) 210 goto rpcb_it; /* he is registering another xptr */ 211 rwlock_unlock(&svc_lock); 212 return (FALSE); 213 } 214 s = mem_alloc(sizeof (struct svc_callout)); 215 if (s == NULL) { 216 if (netid) 217 free(netid); 218 rwlock_unlock(&svc_lock); 219 return (FALSE); 220 } 221 222 s->sc_prog = prog; 223 s->sc_vers = vers; 224 s->sc_dispatch = dispatch; 225 s->sc_netid = netid; 226 s->sc_next = svc_head; 227 svc_head = s; 228 229 if ((xprt->xp_netid == NULL) && (flag == 1) && netid) 230 ((SVCXPRT *) xprt)->xp_netid = strdup(netid); 231 232 rpcb_it: 233 rwlock_unlock(&svc_lock); 234 /* now register the information with the local binder service */ 235 if (nconf) { 236 /*LINTED const castaway*/ 237 dummy = rpcb_set(prog, vers, (struct netconfig *) nconf, 238 &((SVCXPRT *) xprt)->xp_ltaddr); 239 return (dummy); 240 } 241 return (TRUE); 242 } 243 244 /* 245 * Remove a service program from the callout list. 246 */ 247 void 248 svc_unreg(prog, vers) 249 const rpcprog_t prog; 250 const rpcvers_t vers; 251 { 252 struct svc_callout *prev; 253 struct svc_callout *s; 254 255 /* unregister the information anyway */ 256 (void) rpcb_unset(prog, vers, NULL); 257 rwlock_wrlock(&svc_lock); 258 while ((s = svc_find(prog, vers, &prev, NULL)) != NULL) { 259 if (prev == NULL) { 260 svc_head = s->sc_next; 261 } else { 262 prev->sc_next = s->sc_next; 263 } 264 s->sc_next = NULL; 265 if (s->sc_netid) 266 mem_free(s->sc_netid, sizeof (s->sc_netid) + 1); 267 mem_free(s, sizeof (struct svc_callout)); 268 } 269 rwlock_unlock(&svc_lock); 270 } 271 272 /* ********************** CALLOUT list related stuff ************* */ 273 274 #ifdef PORTMAP 275 /* 276 * Add a service program to the callout list. 277 * The dispatch routine will be called when a rpc request for this 278 * program number comes in. 279 */ 280 bool_t 281 svc_register(xprt, prog, vers, dispatch, protocol) 282 SVCXPRT *xprt; 283 u_long prog; 284 u_long vers; 285 void (*dispatch)(struct svc_req *, SVCXPRT *); 286 int protocol; 287 { 288 struct svc_callout *prev; 289 struct svc_callout *s; 290 291 assert(xprt != NULL); 292 assert(dispatch != NULL); 293 294 if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) != 295 NULL) { 296 if (s->sc_dispatch == dispatch) 297 goto pmap_it; /* he is registering another xptr */ 298 return (FALSE); 299 } 300 s = mem_alloc(sizeof(struct svc_callout)); 301 if (s == NULL) { 302 return (FALSE); 303 } 304 s->sc_prog = (rpcprog_t)prog; 305 s->sc_vers = (rpcvers_t)vers; 306 s->sc_dispatch = dispatch; 307 s->sc_next = svc_head; 308 svc_head = s; 309 pmap_it: 310 /* now register the information with the local binder service */ 311 if (protocol) { 312 return (pmap_set(prog, vers, protocol, xprt->xp_port)); 313 } 314 return (TRUE); 315 } 316 317 /* 318 * Remove a service program from the callout list. 319 */ 320 void 321 svc_unregister(prog, vers) 322 u_long prog; 323 u_long vers; 324 { 325 struct svc_callout *prev; 326 struct svc_callout *s; 327 328 if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) == 329 NULL) 330 return; 331 if (prev == NULL) { 332 svc_head = s->sc_next; 333 } else { 334 prev->sc_next = s->sc_next; 335 } 336 s->sc_next = NULL; 337 mem_free(s, sizeof(struct svc_callout)); 338 /* now unregister the information with the local binder service */ 339 (void)pmap_unset(prog, vers); 340 } 341 #endif /* PORTMAP */ 342 343 /* 344 * Search the callout list for a program number, return the callout 345 * struct. 346 */ 347 static struct svc_callout * 348 svc_find(prog, vers, prev, netid) 349 rpcprog_t prog; 350 rpcvers_t vers; 351 struct svc_callout **prev; 352 char *netid; 353 { 354 struct svc_callout *s, *p; 355 356 assert(prev != NULL); 357 358 p = NULL; 359 for (s = svc_head; s != NULL; s = s->sc_next) { 360 if (((s->sc_prog == prog) && (s->sc_vers == vers)) && 361 ((netid == NULL) || (s->sc_netid == NULL) || 362 (strcmp(netid, s->sc_netid) == 0))) 363 break; 364 p = s; 365 } 366 *prev = p; 367 return (s); 368 } 369 370 /* ******************* REPLY GENERATION ROUTINES ************ */ 371 372 /* 373 * Send a reply to an rpc request 374 */ 375 bool_t 376 svc_sendreply(xprt, xdr_results, xdr_location) 377 SVCXPRT *xprt; 378 xdrproc_t xdr_results; 379 void * xdr_location; 380 { 381 struct rpc_msg rply; 382 383 assert(xprt != NULL); 384 385 rply.rm_direction = REPLY; 386 rply.rm_reply.rp_stat = MSG_ACCEPTED; 387 rply.acpted_rply.ar_verf = xprt->xp_verf; 388 rply.acpted_rply.ar_stat = SUCCESS; 389 rply.acpted_rply.ar_results.where = xdr_location; 390 rply.acpted_rply.ar_results.proc = xdr_results; 391 return (SVC_REPLY(xprt, &rply)); 392 } 393 394 /* 395 * No procedure error reply 396 */ 397 void 398 svcerr_noproc(xprt) 399 SVCXPRT *xprt; 400 { 401 struct rpc_msg rply; 402 403 assert(xprt != NULL); 404 405 rply.rm_direction = REPLY; 406 rply.rm_reply.rp_stat = MSG_ACCEPTED; 407 rply.acpted_rply.ar_verf = xprt->xp_verf; 408 rply.acpted_rply.ar_stat = PROC_UNAVAIL; 409 SVC_REPLY(xprt, &rply); 410 } 411 412 /* 413 * Can't decode args error reply 414 */ 415 void 416 svcerr_decode(xprt) 417 SVCXPRT *xprt; 418 { 419 struct rpc_msg rply; 420 421 assert(xprt != NULL); 422 423 rply.rm_direction = REPLY; 424 rply.rm_reply.rp_stat = MSG_ACCEPTED; 425 rply.acpted_rply.ar_verf = xprt->xp_verf; 426 rply.acpted_rply.ar_stat = GARBAGE_ARGS; 427 SVC_REPLY(xprt, &rply); 428 } 429 430 /* 431 * Some system error 432 */ 433 void 434 svcerr_systemerr(xprt) 435 SVCXPRT *xprt; 436 { 437 struct rpc_msg rply; 438 439 assert(xprt != NULL); 440 441 rply.rm_direction = REPLY; 442 rply.rm_reply.rp_stat = MSG_ACCEPTED; 443 rply.acpted_rply.ar_verf = xprt->xp_verf; 444 rply.acpted_rply.ar_stat = SYSTEM_ERR; 445 SVC_REPLY(xprt, &rply); 446 } 447 448 #if 0 449 /* 450 * Tell RPC package to not complain about version errors to the client. This 451 * is useful when revving broadcast protocols that sit on a fixed address. 452 * There is really one (or should be only one) example of this kind of 453 * protocol: the portmapper (or rpc binder). 454 */ 455 void 456 __svc_versquiet_on(xprt) 457 SVCXPRT *xprt; 458 { 459 460 SVC_EXT(xprt)->xp_flags |= SVC_VERSQUIET; 461 } 462 463 void 464 __svc_versquiet_off(xprt) 465 SVCXPRT *xprt; 466 { 467 468 SVC_EXT(xprt)->xp_flags &= ~SVC_VERSQUIET; 469 } 470 471 void 472 svc_versquiet(xprt) 473 SVCXPRT *xprt; 474 { 475 __svc_versquiet_on(xprt); 476 } 477 478 int 479 __svc_versquiet_get(xprt) 480 SVCXPRT *xprt; 481 { 482 483 return (SVC_EXT(xprt)->xp_flags & SVC_VERSQUIET); 484 } 485 #endif 486 487 /* 488 * Authentication error reply 489 */ 490 void 491 svcerr_auth(xprt, why) 492 SVCXPRT *xprt; 493 enum auth_stat why; 494 { 495 struct rpc_msg rply; 496 497 assert(xprt != NULL); 498 499 rply.rm_direction = REPLY; 500 rply.rm_reply.rp_stat = MSG_DENIED; 501 rply.rjcted_rply.rj_stat = AUTH_ERROR; 502 rply.rjcted_rply.rj_why = why; 503 SVC_REPLY(xprt, &rply); 504 } 505 506 /* 507 * Auth too weak error reply 508 */ 509 void 510 svcerr_weakauth(xprt) 511 SVCXPRT *xprt; 512 { 513 514 assert(xprt != NULL); 515 516 svcerr_auth(xprt, AUTH_TOOWEAK); 517 } 518 519 /* 520 * Program unavailable error reply 521 */ 522 void 523 svcerr_noprog(xprt) 524 SVCXPRT *xprt; 525 { 526 struct rpc_msg rply; 527 528 assert(xprt != NULL); 529 530 rply.rm_direction = REPLY; 531 rply.rm_reply.rp_stat = MSG_ACCEPTED; 532 rply.acpted_rply.ar_verf = xprt->xp_verf; 533 rply.acpted_rply.ar_stat = PROG_UNAVAIL; 534 SVC_REPLY(xprt, &rply); 535 } 536 537 /* 538 * Program version mismatch error reply 539 */ 540 void 541 svcerr_progvers(xprt, low_vers, high_vers) 542 SVCXPRT *xprt; 543 rpcvers_t low_vers; 544 rpcvers_t high_vers; 545 { 546 struct rpc_msg rply; 547 548 assert(xprt != NULL); 549 550 rply.rm_direction = REPLY; 551 rply.rm_reply.rp_stat = MSG_ACCEPTED; 552 rply.acpted_rply.ar_verf = xprt->xp_verf; 553 rply.acpted_rply.ar_stat = PROG_MISMATCH; 554 rply.acpted_rply.ar_vers.low = (u_int32_t)low_vers; 555 rply.acpted_rply.ar_vers.high = (u_int32_t)high_vers; 556 SVC_REPLY(xprt, &rply); 557 } 558 559 /* 560 * Allocate a new server transport structure. All fields are 561 * initialized to zero and xp_p3 is initialized to point at an 562 * extension structure to hold various flags and authentication 563 * parameters. 564 */ 565 SVCXPRT * 566 svc_xprt_alloc() 567 { 568 SVCXPRT *xprt; 569 SVCXPRT_EXT *ext; 570 571 xprt = mem_alloc(sizeof(SVCXPRT)); 572 if (xprt == NULL) 573 return (NULL); 574 memset(xprt, 0, sizeof(SVCXPRT)); 575 ext = mem_alloc(sizeof(SVCXPRT_EXT)); 576 if (ext == NULL) { 577 mem_free(xprt, sizeof(SVCXPRT)); 578 return (NULL); 579 } 580 memset(ext, 0, sizeof(SVCXPRT_EXT)); 581 xprt->xp_p3 = ext; 582 ext->xp_auth.svc_ah_ops = &svc_auth_null_ops; 583 584 return (xprt); 585 } 586 587 /* 588 * Free a server transport structure. 589 */ 590 void 591 svc_xprt_free(xprt) 592 SVCXPRT *xprt; 593 { 594 595 mem_free(xprt->xp_p3, sizeof(SVCXPRT_EXT)); 596 mem_free(xprt, sizeof(SVCXPRT)); 597 } 598 599 /* ******************* SERVER INPUT STUFF ******************* */ 600 601 /* 602 * Get server side input from some transport. 603 * 604 * Statement of authentication parameters management: 605 * This function owns and manages all authentication parameters, specifically 606 * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and 607 * the "cooked" credentials (rqst->rq_clntcred). 608 * However, this function does not know the structure of the cooked 609 * credentials, so it make the following assumptions: 610 * a) the structure is contiguous (no pointers), and 611 * b) the cred structure size does not exceed RQCRED_SIZE bytes. 612 * In all events, all three parameters are freed upon exit from this routine. 613 * The storage is trivially management on the call stack in user land, but 614 * is mallocated in kernel land. 615 */ 616 617 void 618 svc_getreq(rdfds) 619 int rdfds; 620 { 621 fd_set readfds; 622 623 FD_ZERO(&readfds); 624 readfds.fds_bits[0] = rdfds; 625 svc_getreqset(&readfds); 626 } 627 628 void 629 svc_getreqset(readfds) 630 fd_set *readfds; 631 { 632 int bit, fd; 633 fd_mask mask, *maskp; 634 int sock; 635 636 assert(readfds != NULL); 637 638 maskp = readfds->fds_bits; 639 for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) { 640 for (mask = *maskp++; (bit = ffsl(mask)) != 0; 641 mask ^= (1ul << (bit - 1))) { 642 /* sock has input waiting */ 643 fd = sock + bit - 1; 644 svc_getreq_common(fd); 645 } 646 } 647 } 648 649 void 650 svc_getreq_common(fd) 651 int fd; 652 { 653 SVCXPRT *xprt; 654 struct svc_req r; 655 struct rpc_msg msg; 656 int prog_found; 657 rpcvers_t low_vers; 658 rpcvers_t high_vers; 659 enum xprt_stat stat; 660 char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE]; 661 662 msg.rm_call.cb_cred.oa_base = cred_area; 663 msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); 664 r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]); 665 666 rwlock_rdlock(&svc_fd_lock); 667 xprt = __svc_xports[fd]; 668 rwlock_unlock(&svc_fd_lock); 669 if (xprt == NULL) 670 /* But do we control sock? */ 671 return; 672 /* now receive msgs from xprtprt (support batch calls) */ 673 do { 674 if (SVC_RECV(xprt, &msg)) { 675 676 /* now find the exported program and call it */ 677 struct svc_callout *s; 678 enum auth_stat why; 679 680 r.rq_xprt = xprt; 681 r.rq_prog = msg.rm_call.cb_prog; 682 r.rq_vers = msg.rm_call.cb_vers; 683 r.rq_proc = msg.rm_call.cb_proc; 684 r.rq_cred = msg.rm_call.cb_cred; 685 /* first authenticate the message */ 686 if ((why = _authenticate(&r, &msg)) != AUTH_OK) { 687 /* 688 * RPCSEC_GSS uses this return code 689 * for requests that form part of its 690 * context establishment protocol and 691 * should not be dispatched to the 692 * application. 693 */ 694 if (why != RPCSEC_GSS_NODISPATCH) 695 svcerr_auth(xprt, why); 696 goto call_done; 697 } 698 /* now match message with a registered service*/ 699 prog_found = FALSE; 700 low_vers = (rpcvers_t) -1L; 701 high_vers = (rpcvers_t) 0L; 702 for (s = svc_head; s != NULL; s = s->sc_next) { 703 if (s->sc_prog == r.rq_prog) { 704 if (s->sc_vers == r.rq_vers) { 705 (*s->sc_dispatch)(&r, xprt); 706 goto call_done; 707 } /* found correct version */ 708 prog_found = TRUE; 709 if (s->sc_vers < low_vers) 710 low_vers = s->sc_vers; 711 if (s->sc_vers > high_vers) 712 high_vers = s->sc_vers; 713 } /* found correct program */ 714 } 715 /* 716 * if we got here, the program or version 717 * is not served ... 718 */ 719 if (prog_found) 720 svcerr_progvers(xprt, low_vers, high_vers); 721 else 722 svcerr_noprog(xprt); 723 /* Fall through to ... */ 724 } 725 /* 726 * Check if the xprt has been disconnected in a 727 * recursive call in the service dispatch routine. 728 * If so, then break. 729 */ 730 rwlock_rdlock(&svc_fd_lock); 731 if (xprt != __svc_xports[fd]) { 732 rwlock_unlock(&svc_fd_lock); 733 break; 734 } 735 rwlock_unlock(&svc_fd_lock); 736 call_done: 737 if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ 738 SVC_DESTROY(xprt); 739 break; 740 } 741 } while (stat == XPRT_MOREREQS); 742 } 743 744 745 void 746 svc_getreq_poll(pfdp, pollretval) 747 struct pollfd *pfdp; 748 int pollretval; 749 { 750 int i; 751 int fds_found; 752 753 for (i = fds_found = 0; fds_found < pollretval; i++) { 754 struct pollfd *p = &pfdp[i]; 755 756 if (p->revents) { 757 /* fd has input waiting */ 758 fds_found++; 759 /* 760 * We assume that this function is only called 761 * via someone _select()ing from svc_fdset or 762 * _poll()ing from svc_pollset[]. Thus it's safe 763 * to handle the POLLNVAL event by simply turning 764 * the corresponding bit off in svc_fdset. The 765 * svc_pollset[] array is derived from svc_fdset 766 * and so will also be updated eventually. 767 * 768 * XXX Should we do an xprt_unregister() instead? 769 */ 770 if (p->revents & POLLNVAL) { 771 rwlock_wrlock(&svc_fd_lock); 772 FD_CLR(p->fd, &svc_fdset); 773 rwlock_unlock(&svc_fd_lock); 774 } else 775 svc_getreq_common(p->fd); 776 } 777 } 778 } 779 780 bool_t 781 rpc_control(int what, void *arg) 782 { 783 int val; 784 785 switch (what) { 786 case RPC_SVC_CONNMAXREC_SET: 787 val = *(int *)arg; 788 if (val <= 0) 789 return FALSE; 790 __svc_maxrec = val; 791 return TRUE; 792 case RPC_SVC_CONNMAXREC_GET: 793 *(int *)arg = __svc_maxrec; 794 return TRUE; 795 default: 796 break; 797 } 798 return FALSE; 799 } 800