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