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