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