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