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