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