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