1 /* $NetBSD: svc.c,v 1.31 2012/03/20 17:14:50 matt 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 #include <sys/cdefs.h> 33 #if defined(LIBC_SCCS) && !defined(lint) 34 #if 0 35 static char *sccsid = "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro"; 36 static char *sccsid = "@(#)svc.c 2.4 88/08/11 4.0 RPCSRC"; 37 #else 38 __RCSID("$NetBSD: svc.c,v 1.31 2012/03/20 17:14:50 matt Exp $"); 39 #endif 40 #endif 41 42 /* 43 * svc.c, Server-side remote procedure call interface. 44 * 45 * There are two sets of procedures here. The xprt routines are 46 * for handling transport handles. The svc routines handle the 47 * list of service routines. 48 * 49 * Copyright (C) 1984, Sun Microsystems, Inc. 50 */ 51 52 #include "namespace.h" 53 #include "reentrant.h" 54 #include <sys/types.h> 55 #include <sys/poll.h> 56 #include <assert.h> 57 #include <errno.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <err.h> 61 62 #include <rpc/rpc.h> 63 #ifdef PORTMAP 64 #include <rpc/pmap_clnt.h> 65 #endif 66 67 #include "rpc_internal.h" 68 69 #ifdef __weak_alias 70 __weak_alias(svc_getreq,_svc_getreq) 71 __weak_alias(svc_getreqset,_svc_getreqset) 72 __weak_alias(svc_getreq_common,_svc_getreq_common) 73 __weak_alias(svc_register,_svc_register) 74 __weak_alias(svc_reg,_svc_reg) 75 __weak_alias(svc_unreg,_svc_unreg) 76 __weak_alias(svc_sendreply,_svc_sendreply) 77 __weak_alias(svc_unregister,_svc_unregister) 78 __weak_alias(svcerr_auth,_svcerr_auth) 79 __weak_alias(svcerr_decode,_svcerr_decode) 80 __weak_alias(svcerr_noproc,_svcerr_noproc) 81 __weak_alias(svcerr_noprog,_svcerr_noprog) 82 __weak_alias(svcerr_progvers,_svcerr_progvers) 83 __weak_alias(svcerr_systemerr,_svcerr_systemerr) 84 __weak_alias(svcerr_weakauth,_svcerr_weakauth) 85 __weak_alias(xprt_register,_xprt_register) 86 __weak_alias(xprt_unregister,_xprt_unregister) 87 __weak_alias(rpc_control,_rpc_control) 88 #endif 89 90 SVCXPRT **__svc_xports; 91 int __svc_maxrec; 92 93 #define RQCRED_SIZE 400 /* this size is excessive */ 94 95 #define SVC_VERSQUIET 0x0001 /* keep quiet about vers mismatch */ 96 #define version_keepquiet(xp) ((u_long)(xp)->xp_p3 & SVC_VERSQUIET) 97 98 #define max(a, b) (a > b ? a : b) 99 100 /* 101 * The services list 102 * Each entry represents a set of procedures (an rpc program). 103 * The dispatch routine takes request structs and runs the 104 * apropriate procedure. 105 */ 106 static struct svc_callout { 107 struct svc_callout *sc_next; 108 rpcprog_t sc_prog; 109 rpcvers_t sc_vers; 110 char *sc_netid; 111 void (*sc_dispatch)(struct svc_req *, SVCXPRT *); 112 } *svc_head; 113 114 #ifdef _REENTRANT 115 extern rwlock_t svc_lock; 116 extern rwlock_t svc_fd_lock; 117 #endif 118 119 static struct svc_callout *svc_find(rpcprog_t, rpcvers_t, 120 struct svc_callout **, char *); 121 static void __xprt_do_unregister(SVCXPRT *xprt, bool_t dolock); 122 123 /* *************** SVCXPRT related stuff **************** */ 124 125 /* 126 * Activate a transport handle. 127 */ 128 void 129 xprt_register(SVCXPRT *xprt) 130 { 131 int sock; 132 133 _DIAGASSERT(xprt != NULL); 134 135 sock = xprt->xp_fd; 136 137 rwlock_wrlock(&svc_fd_lock); 138 if (__svc_xports == NULL) { 139 __svc_xports = mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *)); 140 if (__svc_xports == NULL) { 141 warn("xprt_register"); 142 goto out; 143 } 144 memset(__svc_xports, '\0', FD_SETSIZE * sizeof(SVCXPRT *)); 145 } 146 if (sock < FD_SETSIZE) { 147 __svc_xports[sock] = xprt; 148 FD_SET(sock, &svc_fdset); 149 svc_maxfd = max(svc_maxfd, sock); 150 } 151 out: 152 rwlock_unlock(&svc_fd_lock); 153 } 154 155 void 156 xprt_unregister(SVCXPRT *xprt) 157 { 158 __xprt_do_unregister(xprt, TRUE); 159 } 160 161 void 162 __xprt_unregister_unlocked(SVCXPRT *xprt) 163 { 164 __xprt_do_unregister(xprt, FALSE); 165 } 166 167 /* 168 * De-activate a transport handle. 169 */ 170 static void 171 __xprt_do_unregister(SVCXPRT *xprt, bool_t dolock) 172 { 173 int sock; 174 175 _DIAGASSERT(xprt != NULL); 176 177 sock = xprt->xp_fd; 178 179 if (dolock) 180 rwlock_wrlock(&svc_fd_lock); 181 if ((sock < FD_SETSIZE) && (__svc_xports[sock] == xprt)) { 182 __svc_xports[sock] = NULL; 183 FD_CLR(sock, &svc_fdset); 184 if (sock >= svc_maxfd) { 185 for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--) 186 if (__svc_xports[svc_maxfd]) 187 break; 188 } 189 } 190 if (dolock) 191 rwlock_unlock(&svc_fd_lock); 192 } 193 194 /* 195 * Add a service program to the callout list. 196 * The dispatch routine will be called when a rpc request for this 197 * program number comes in. 198 */ 199 bool_t 200 svc_reg(SVCXPRT *xprt, const rpcprog_t prog, const rpcvers_t vers, 201 void (*dispatch)(struct svc_req *, SVCXPRT *), 202 const struct netconfig *nconf) 203 { 204 bool_t dummy; 205 struct svc_callout *prev; 206 struct svc_callout *s; 207 struct netconfig *tnconf; 208 char *netid = NULL; 209 int flag = 0; 210 211 _DIAGASSERT(xprt != NULL); 212 /* XXX: dispatch may be NULL ??? */ 213 214 /* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */ 215 216 if (xprt->xp_netid) { 217 netid = strdup(xprt->xp_netid); 218 flag = 1; 219 } else if (nconf && nconf->nc_netid) { 220 netid = strdup(nconf->nc_netid); 221 flag = 1; 222 } else if ((tnconf = __rpcgettp(xprt->xp_fd)) != NULL) { 223 netid = strdup(tnconf->nc_netid); 224 flag = 1; 225 freenetconfigent(tnconf); 226 } /* must have been created with svc_raw_create */ 227 if ((netid == NULL) && (flag == 1)) { 228 return (FALSE); 229 } 230 231 rwlock_wrlock(&svc_lock); 232 if ((s = svc_find(prog, vers, &prev, netid)) != NULL) { 233 if (netid) 234 free(netid); 235 if (s->sc_dispatch == dispatch) 236 goto rpcb_it; /* he is registering another xptr */ 237 rwlock_unlock(&svc_lock); 238 return (FALSE); 239 } 240 s = mem_alloc(sizeof (struct svc_callout)); 241 if (s == NULL) { 242 if (netid) 243 free(netid); 244 rwlock_unlock(&svc_lock); 245 return (FALSE); 246 } 247 248 if ((xprt->xp_netid == NULL) && (flag == 1) && netid) 249 if ((((SVCXPRT *) xprt)->xp_netid = strdup(netid)) == NULL) { 250 warn("svc_reg"); 251 mem_free(s, sizeof(struct svc_callout)); 252 rwlock_unlock(&svc_lock); 253 return FALSE; 254 } 255 256 s->sc_prog = prog; 257 s->sc_vers = vers; 258 s->sc_dispatch = dispatch; 259 s->sc_netid = netid; 260 s->sc_next = svc_head; 261 svc_head = s; 262 263 rpcb_it: 264 rwlock_unlock(&svc_lock); 265 /* now register the information with the local binder service */ 266 if (nconf) { 267 dummy = rpcb_set(prog, vers, __UNCONST(nconf), 268 &((SVCXPRT *) xprt)->xp_ltaddr); 269 return (dummy); 270 } 271 return (TRUE); 272 } 273 274 /* 275 * Remove a service program from the callout list. 276 */ 277 void 278 svc_unreg(const rpcprog_t prog, const rpcvers_t vers) 279 { 280 struct svc_callout *prev; 281 struct svc_callout *s; 282 283 /* unregister the information anyway */ 284 (void) rpcb_unset(prog, vers, NULL); 285 rwlock_wrlock(&svc_lock); 286 while ((s = svc_find(prog, vers, &prev, NULL)) != NULL) { 287 if (prev == NULL) { 288 svc_head = s->sc_next; 289 } else { 290 prev->sc_next = s->sc_next; 291 } 292 s->sc_next = NULL; 293 if (s->sc_netid) 294 mem_free(s->sc_netid, sizeof (s->sc_netid) + 1); 295 mem_free(s, sizeof (struct svc_callout)); 296 } 297 rwlock_unlock(&svc_lock); 298 } 299 300 /* ********************** CALLOUT list related stuff ************* */ 301 302 #ifdef PORTMAP 303 /* 304 * Add a service program to the callout list. 305 * The dispatch routine will be called when a rpc request for this 306 * program number comes in. 307 */ 308 bool_t 309 svc_register(SVCXPRT *xprt, u_long prog, u_long vers, 310 void (*dispatch)(struct svc_req *, SVCXPRT *), int protocol) 311 { 312 struct svc_callout *prev; 313 struct svc_callout *s; 314 315 _DIAGASSERT(xprt != NULL); 316 _DIAGASSERT(dispatch != NULL); 317 318 if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) != 319 NULL) { 320 if (s->sc_dispatch == dispatch) 321 goto pmap_it; /* he is registering another xptr */ 322 return (FALSE); 323 } 324 s = mem_alloc(sizeof(struct svc_callout)); 325 if (s == NULL) { 326 return (FALSE); 327 } 328 s->sc_prog = (rpcprog_t)prog; 329 s->sc_vers = (rpcvers_t)vers; 330 s->sc_dispatch = dispatch; 331 s->sc_next = svc_head; 332 svc_head = s; 333 pmap_it: 334 /* now register the information with the local binder service */ 335 if (protocol) { 336 return (pmap_set(prog, vers, protocol, xprt->xp_port)); 337 } 338 return (TRUE); 339 } 340 341 /* 342 * Remove a service program from the callout list. 343 */ 344 void 345 svc_unregister(u_long prog, u_long vers) 346 { 347 struct svc_callout *prev; 348 struct svc_callout *s; 349 350 if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) == 351 NULL) 352 return; 353 if (prev == NULL) { 354 svc_head = s->sc_next; 355 } else { 356 prev->sc_next = s->sc_next; 357 } 358 s->sc_next = NULL; 359 mem_free(s, sizeof(struct svc_callout)); 360 /* now unregister the information with the local binder service */ 361 (void)pmap_unset(prog, vers); 362 } 363 #endif /* PORTMAP */ 364 365 /* 366 * Search the callout list for a program number, return the callout 367 * struct. 368 */ 369 static struct svc_callout * 370 svc_find(rpcprog_t prog, rpcvers_t vers, struct svc_callout **prev, char *netid) 371 { 372 struct svc_callout *s, *p; 373 374 _DIAGASSERT(prev != NULL); 375 /* netid is handled below */ 376 377 p = NULL; 378 for (s = svc_head; s != NULL; s = s->sc_next) { 379 if (((s->sc_prog == prog) && (s->sc_vers == vers)) && 380 ((netid == NULL) || (s->sc_netid == NULL) || 381 (strcmp(netid, s->sc_netid) == 0))) 382 break; 383 p = s; 384 } 385 *prev = p; 386 return (s); 387 } 388 389 /* ******************* REPLY GENERATION ROUTINES ************ */ 390 391 /* 392 * Send a reply to an rpc request 393 */ 394 bool_t 395 svc_sendreply(SVCXPRT *xprt, xdrproc_t xdr_results, const char *xdr_location) 396 { 397 struct rpc_msg rply; 398 399 _DIAGASSERT(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 = SUCCESS; 405 rply.acpted_rply.ar_results.where = xdr_location; 406 rply.acpted_rply.ar_results.proc = xdr_results; 407 return (SVC_REPLY(xprt, &rply)); 408 } 409 410 /* 411 * No procedure error reply 412 */ 413 void 414 svcerr_noproc(SVCXPRT *xprt) 415 { 416 struct rpc_msg rply; 417 418 _DIAGASSERT(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 = PROC_UNAVAIL; 424 SVC_REPLY(xprt, &rply); 425 } 426 427 /* 428 * Can't decode args error reply 429 */ 430 void 431 svcerr_decode(SVCXPRT *xprt) 432 { 433 struct rpc_msg rply; 434 435 _DIAGASSERT(xprt != NULL); 436 437 rply.rm_direction = REPLY; 438 rply.rm_reply.rp_stat = MSG_ACCEPTED; 439 rply.acpted_rply.ar_verf = xprt->xp_verf; 440 rply.acpted_rply.ar_stat = GARBAGE_ARGS; 441 SVC_REPLY(xprt, &rply); 442 } 443 444 /* 445 * Some system error 446 */ 447 void 448 svcerr_systemerr(SVCXPRT *xprt) 449 { 450 struct rpc_msg rply; 451 452 _DIAGASSERT(xprt != NULL); 453 454 rply.rm_direction = REPLY; 455 rply.rm_reply.rp_stat = MSG_ACCEPTED; 456 rply.acpted_rply.ar_verf = xprt->xp_verf; 457 rply.acpted_rply.ar_stat = SYSTEM_ERR; 458 SVC_REPLY(xprt, &rply); 459 } 460 461 #if 0 462 /* 463 * Tell RPC package to not complain about version errors to the client. This 464 * is useful when revving broadcast protocols that sit on a fixed address. 465 * There is really one (or should be only one) example of this kind of 466 * protocol: the portmapper (or rpc binder). 467 */ 468 void 469 __svc_versquiet_on(SVCXPRT *xprt) 470 { 471 u_long tmp; 472 473 _DIAGASSERT(xprt != NULL); 474 475 tmp = ((u_long) xprt->xp_p3) | SVC_VERSQUIET; 476 xprt->xp_p3 = (caddr_t) tmp; 477 } 478 479 void 480 __svc_versquiet_off(SVCXPRT *xprt) 481 { 482 u_long tmp; 483 484 _DIAGASSERT(xprt != NULL); 485 486 tmp = ((u_long) xprt->xp_p3) & ~SVC_VERSQUIET; 487 xprt->xp_p3 = (caddr_t) tmp; 488 } 489 490 void 491 svc_versquiet(SVCXPRT *xprt) 492 { 493 __svc_versquiet_on(xprt); 494 } 495 496 int 497 __svc_versquiet_get(SVCXPRT *xprt) 498 { 499 500 _DIAGASSERT(xprt != NULL); 501 502 return ((int) xprt->xp_p3) & SVC_VERSQUIET; 503 } 504 #endif 505 506 /* 507 * Authentication error reply 508 */ 509 void 510 svcerr_auth(SVCXPRT *xprt, enum auth_stat why) 511 { 512 struct rpc_msg rply; 513 514 _DIAGASSERT(xprt != NULL); 515 516 rply.rm_direction = REPLY; 517 rply.rm_reply.rp_stat = MSG_DENIED; 518 rply.rjcted_rply.rj_stat = AUTH_ERROR; 519 rply.rjcted_rply.rj_why = why; 520 SVC_REPLY(xprt, &rply); 521 } 522 523 /* 524 * Auth too weak error reply 525 */ 526 void 527 svcerr_weakauth(SVCXPRT *xprt) 528 { 529 530 _DIAGASSERT(xprt != NULL); 531 532 svcerr_auth(xprt, AUTH_TOOWEAK); 533 } 534 535 /* 536 * Program unavailable error reply 537 */ 538 void 539 svcerr_noprog(SVCXPRT *xprt) 540 { 541 struct rpc_msg rply; 542 543 _DIAGASSERT(xprt != NULL); 544 545 rply.rm_direction = REPLY; 546 rply.rm_reply.rp_stat = MSG_ACCEPTED; 547 rply.acpted_rply.ar_verf = xprt->xp_verf; 548 rply.acpted_rply.ar_stat = PROG_UNAVAIL; 549 SVC_REPLY(xprt, &rply); 550 } 551 552 /* 553 * Program version mismatch error reply 554 */ 555 void 556 svcerr_progvers(SVCXPRT *xprt, rpcvers_t low_vers, rpcvers_t high_vers) 557 { 558 struct rpc_msg rply; 559 560 _DIAGASSERT(xprt != NULL); 561 562 rply.rm_direction = REPLY; 563 rply.rm_reply.rp_stat = MSG_ACCEPTED; 564 rply.acpted_rply.ar_verf = xprt->xp_verf; 565 rply.acpted_rply.ar_stat = PROG_MISMATCH; 566 rply.acpted_rply.ar_vers.low = (u_int32_t)low_vers; 567 rply.acpted_rply.ar_vers.high = (u_int32_t)high_vers; 568 SVC_REPLY(xprt, &rply); 569 } 570 571 /* ******************* SERVER INPUT STUFF ******************* */ 572 573 /* 574 * Get server side input from some transport. 575 * 576 * Statement of authentication parameters management: 577 * This function owns and manages all authentication parameters, specifically 578 * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and 579 * the "cooked" credentials (rqst->rq_clntcred). 580 * However, this function does not know the structure of the cooked 581 * credentials, so it make the following assumptions: 582 * a) the structure is contiguous (no pointers), and 583 * b) the cred structure size does not exceed RQCRED_SIZE bytes. 584 * In all events, all three parameters are freed upon exit from this routine. 585 * The storage is trivially management on the call stack in user land, but 586 * is mallocated in kernel land. 587 */ 588 589 void 590 svc_getreq(int rdfds) 591 { 592 fd_set readfds; 593 594 FD_ZERO(&readfds); 595 readfds.fds_bits[0] = (unsigned int)rdfds; 596 svc_getreqset(&readfds); 597 } 598 599 void 600 svc_getreqset(fd_set *readfds) 601 { 602 uint32_t mask, *maskp; 603 int sock, bit, fd; 604 605 _DIAGASSERT(readfds != NULL); 606 607 maskp = readfds->fds_bits; 608 for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) { 609 for (mask = *maskp++; (bit = ffs((int)mask)) != 0; 610 mask ^= (1 << (bit - 1))) { 611 /* sock has input waiting */ 612 fd = sock + bit - 1; 613 svc_getreq_common(fd); 614 } 615 } 616 } 617 618 void 619 svc_getreq_common(int fd) 620 { 621 SVCXPRT *xprt; 622 struct svc_req r; 623 struct rpc_msg msg; 624 int prog_found; 625 rpcvers_t low_vers; 626 rpcvers_t high_vers; 627 enum xprt_stat stat; 628 char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE]; 629 630 msg.rm_call.cb_cred.oa_base = cred_area; 631 msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); 632 r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]); 633 634 rwlock_rdlock(&svc_fd_lock); 635 xprt = __svc_xports[fd]; 636 rwlock_unlock(&svc_fd_lock); 637 if (xprt == NULL) 638 /* But do we control sock? */ 639 return; 640 /* now receive msgs from xprtprt (support batch calls) */ 641 do { 642 if (SVC_RECV(xprt, &msg)) { 643 644 /* now find the exported program and call it */ 645 struct svc_callout *s; 646 enum auth_stat why; 647 648 r.rq_xprt = xprt; 649 r.rq_prog = msg.rm_call.cb_prog; 650 r.rq_vers = msg.rm_call.cb_vers; 651 r.rq_proc = msg.rm_call.cb_proc; 652 r.rq_cred = msg.rm_call.cb_cred; 653 /* first authenticate the message */ 654 if ((why = _authenticate(&r, &msg)) != AUTH_OK) { 655 svcerr_auth(xprt, why); 656 goto call_done; 657 } 658 /* now match message with a registered service*/ 659 prog_found = FALSE; 660 low_vers = (rpcvers_t) -1L; 661 high_vers = (rpcvers_t) 0L; 662 for (s = svc_head; s != NULL; s = s->sc_next) { 663 if (s->sc_prog == r.rq_prog) { 664 if (s->sc_vers == r.rq_vers) { 665 (*s->sc_dispatch)(&r, xprt); 666 goto call_done; 667 } /* found correct version */ 668 prog_found = TRUE; 669 if (s->sc_vers < low_vers) 670 low_vers = s->sc_vers; 671 if (s->sc_vers > high_vers) 672 high_vers = s->sc_vers; 673 } /* found correct program */ 674 } 675 /* 676 * if we got here, the program or version 677 * is not served ... 678 */ 679 if (prog_found) 680 svcerr_progvers(xprt, low_vers, high_vers); 681 else 682 svcerr_noprog(xprt); 683 /* Fall through to ... */ 684 } 685 /* 686 * Check if the xprt has been disconnected in a 687 * recursive call in the service dispatch routine. 688 * If so, then break. 689 */ 690 rwlock_rdlock(&svc_fd_lock); 691 if (xprt != __svc_xports[fd]) { 692 rwlock_unlock(&svc_fd_lock); 693 break; 694 } 695 rwlock_unlock(&svc_fd_lock); 696 call_done: 697 if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ 698 SVC_DESTROY(xprt); 699 break; 700 } 701 } while (stat == XPRT_MOREREQS); 702 } 703 704 705 void 706 svc_getreq_poll(struct pollfd *pfdp, int pollretval) 707 { 708 int i; 709 int fds_found; 710 711 _DIAGASSERT(pfdp != NULL); 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 * pollts()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