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