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