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) 32static char *sccsid2 = "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro"; 33static char *sccsid = "@(#)svc.c 2.4 88/08/11 4.0 RPCSRC"; 34#endif 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD: stable/10/lib/libc/rpc/svc.c 318327 2017-05-15 23:13:49Z brooks $"); 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 */ 79static 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 87SVCXPRT **__svc_xports; 88int __svc_maxrec; 89 90static struct svc_callout *svc_find(rpcprog_t, rpcvers_t, 91 struct svc_callout **, char *); 92static void __xprt_do_unregister (SVCXPRT *xprt, bool_t dolock); 93 94/* *************** SVCXPRT related stuff **************** */ 95 96/* 97 * Activate a transport handle. 98 */ 99void 100xprt_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 + 1) * sizeof(SVCXPRT *)); 112 if (__svc_xports == NULL) { 113 rwlock_unlock(&svc_fd_lock); 114 return; 115 } 116 memset(__svc_xports, '\0', (FD_SETSIZE + 1) * 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 } else if (sock == FD_SETSIZE) 123 __svc_xports[sock] = xprt; 124 rwlock_unlock(&svc_fd_lock); 125} 126 127void 128xprt_unregister(SVCXPRT *xprt) 129{ 130 __xprt_do_unregister(xprt, TRUE); 131} 132 133void 134__xprt_unregister_unlocked(SVCXPRT *xprt) 135{ 136 __xprt_do_unregister(xprt, FALSE); 137} 138 139/* 140 * De-activate a transport handle. 141 */ 142static void 143__xprt_do_unregister(SVCXPRT *xprt, 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 } else if ((sock == FD_SETSIZE) && (__svc_xports[sock] == xprt)) 162 __svc_xports[sock] = NULL; 163 if (dolock) 164 rwlock_unlock(&svc_fd_lock); 165} 166 167/* 168 * Add a service program to the callout list. 169 * The dispatch routine will be called when a rpc request for this 170 * program number comes in. 171 */ 172bool_t 173svc_reg(SVCXPRT *xprt, const rpcprog_t prog, const rpcvers_t vers, 174 void (*dispatch)(struct svc_req *, SVCXPRT *), 175 const struct netconfig *nconf) 176{ 177 bool_t dummy; 178 struct svc_callout *prev; 179 struct svc_callout *s; 180 struct netconfig *tnconf; 181 char *netid = NULL; 182 int flag = 0; 183 184/* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */ 185 186 if (xprt->xp_netid) { 187 netid = strdup(xprt->xp_netid); 188 flag = 1; 189 } else if (nconf && nconf->nc_netid) { 190 netid = strdup(nconf->nc_netid); 191 flag = 1; 192 } else if ((tnconf = __rpcgettp(xprt->xp_fd)) != NULL) { 193 netid = strdup(tnconf->nc_netid); 194 flag = 1; 195 freenetconfigent(tnconf); 196 } /* must have been created with svc_raw_create */ 197 if ((netid == NULL) && (flag == 1)) { 198 return (FALSE); 199 } 200 201 rwlock_wrlock(&svc_lock); 202 if ((s = svc_find(prog, vers, &prev, netid)) != NULL) { 203 free(netid); 204 if (s->sc_dispatch == dispatch) 205 goto rpcb_it; /* he is registering another xptr */ 206 rwlock_unlock(&svc_lock); 207 return (FALSE); 208 } 209 s = mem_alloc(sizeof (struct svc_callout)); 210 if (s == NULL) { 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 226rpcb_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 */ 241void 242svc_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 */ 272bool_t 273svc_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; 298pmap_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 */ 309void 310svc_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 */ 334static struct svc_callout * 335svc_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 */ 359bool_t 360svc_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 */ 379void 380svcerr_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 */ 396void 397svcerr_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 */ 413void 414svcerr_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 */ 434void 435__svc_versquiet_on(SVCXPRT *xprt) 436{ 437 438 SVC_EXT(xprt)->xp_flags |= SVC_VERSQUIET; 439} 440 441void 442__svc_versquiet_off(SVCXPRT *xprt) 443{ 444 445 SVC_EXT(xprt)->xp_flags &= ~SVC_VERSQUIET; 446} 447 448void 449svc_versquiet(SVCXPRT *xprt) 450{ 451 __svc_versquiet_on(xprt); 452} 453 454int 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 */ 465void 466svcerr_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 */ 482void 483svcerr_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 */ 494void 495svcerr_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 */ 511void 512svcerr_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 */ 533SVCXPRT * 534svc_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 */ 558void 559svc_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 584void 585svc_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 594void 595svc_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 614void 615svc_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); 700call_done: 701 if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ 702 SVC_DESTROY(xprt); 703 break; 704 } 705 } while (stat == XPRT_MOREREQS); 706} 707 708 709void 710svc_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 742bool_t 743rpc_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