diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc/rpc/LICENSE | 335 | ||||
-rw-r--r-- | lib/libc/rpc/Makefile.inc | 3 | ||||
-rw-r--r-- | lib/libc/rpc/clnt_generic.c | 234 | ||||
-rw-r--r-- | lib/libc/rpc/rpc_clnt_create.3 | 45 | ||||
-rw-r--r-- | lib/libc/rpc/rpcb_clnt.c | 149 |
5 files changed, 670 insertions, 96 deletions
diff --git a/lib/libc/rpc/LICENSE b/lib/libc/rpc/LICENSE new file mode 100644 index 0000000..5f1205c --- /dev/null +++ b/lib/libc/rpc/LICENSE @@ -0,0 +1,335 @@ +$FreeBSD$ + +Sun Industry Standards Source License 1.0 + +DEFINITIONS + +1.1. "Commercial Use" means distribution or otherwise +making the Original Code available to a third party. + +1.2. "Contributor Version" means the combination of the +Original Code, and the Modifications made by that particular +Contributor. + +1.3. "Electronic Distribution Mechanism" means a mechanism +generally accepted in the software development community for +the electronic transfer of data. + +1.4. "Executable" means Original Code in any form other +than Source Code. + +1.5. "Initial Developer" means the individual or entity +identified as the Initial Developer in the Source Code +notice required by 2 (Exhibit A) + +1.6. "Larger Work" means a work which combines Original +Code or portions thereof with code not governed by the terms +of this License. + +1.7. "License" means this document. + +1.8. "Licensable" means having the right to grant, to the +maximum extent possible, whether at the time of the initial +grant or subsequently acquired, any and all of the rights +conveyed herein. + +1.9. "Modifications" means any addition to or deletion from +the substance or structure of either the Original Code or +any previous Modifications. A Modification is: + +A. Any addition to or deletion from the contents of a file +containing Original Code or previous Modifications. + +B. Any new file that contains any part of the Original Code +or previous Modifications. . + +1.10. "Original Code" means Source Code of computer +software code which is described in the Source Code notice +required by Exhibit A as Original Code. + +1.11. "Patent Claims" means any patent claims, now owned or +hereafter acquired, including without limitation, method, +process, and apparatus claims, in any patent Licensable by +grantor. + +1.12. "Source Code" means the preferred form of the +Original Code for making modifications to it, including all +modules it contains, plus any associated interface +definition files, or scripts used to control compilation and +installation of an Executable. + +1.13. "Standards" means the standard identified in Exhibit +B or a subsequent version of such standard. + +1.14. "You" or "Your" means an individual or a legal entity +exercising rights under, and complying with all of the terms +of, this License or a future version of this License issued +under Section 6.1. For legal entities, "You" includes any +entity which controls, is controlled by, or is under common +control with You. For purposes of this definition, +"control" means (a) the power, direct or indirect, to cause +the direction or management of such entity, whether by +contract or otherwise, or (b) ownership of more than fifty +percent (50%) of the outstanding shares or beneficial +ownership of such entity. + +2.0 SOURCE CODE LICENSE + +2.1 The Initial Developer Grant: The Initial Developer +hereby grants You a world-wide, royalty-free, non-exclusive +license, subject to third party intellectual property +claims: + +a) under intellectual property rights (other than patent or +trademark) Licensable by Initial Developer to use, +reproduce, modify, display, perform, sub license and +distribute the Original Code (or portions thereof )with or +without Modifications, and/or as part of a Larger Work; and + +b) under Patents Claims infringed by the making, using or +selling of Original Code, to make, have made, use, practice, +sell, and offer for sale, and/or otherwise dispose of the +Original Code (or portions thereof). + +c) the licenses granted in this Section 2.1(a ) and (b) are +effective on the date Initial Developer first distributes +Original Code under the terms of this License. + +d) Notwithstanding Section 2.1(b )above, no patent license +is granted: 1) for code that You delete from the Original +Code; 2) separate from the Original Code; or 3) for +infringements caused by: i) the modification of the +Original Code or + +ii) the combination of the Original Code with other software +or devices, including but not limited to Modifications. + +3.0 DISTRIBUTION OBLIGATIONS + +3.1 Application of License. The Source Code version of +Original Code may be distributed only under the terms of +this License or a future version of this License released +under Section 6.1, and You must include a copy of this +License with every copy of the Source Code You distribute. +You may not offer or impose any terms on any Source Code +version that alters or restricts the applicable version of +this License or the recipient's rights hereunder. Your +license for shipment of the Contributor Version is +conditioned upon your full compliance with this Section. +The Modifications which you create must comply with all +requirements set out by the Standards body in effect 120 +days before You ship the Contributor Version. In the event +that the Modifications do not meet such requirements, You +agree to publish (i) any deviation from the Standards +protocol resulting from implementation of your Modifications +and (ii) a reference implementation of Your Modifications, +and to make any such deviation and reference implementation +available to all third parties under the same terms as the +license on a royalty free basis within thirty (30) days of +Your first customer shipment of Your Modifications. + +3.2 Required Notices. You must duplicate the notice in +Exhibit A in each file of the Source Code. If it is not +possible to put such notice in a particular Source Code file +due to its structure, then You must include such notice in a +location (such as a relevant directory ) where a user would +be likely to look for such a notice. If You created one or +more Modifications ) You may add your name as a Contributor +to the notice described in Exhibit A. You must also +duplicate this License in any documentation for the Source +Code where You describe recipients' rights or ownership +rights relating to Initial Code. You may choose to offer, +and to charge a fee for, warranty, support, indemnity or +liability obligations to one or more recipients of Your +version of the Code. However, You may do so only + +on Your own behalf, and not on behalf of the Initial +Developer. You must make it absolutely clear than any such +warranty, support, indemnity or liability obligation is +offered by You alone, and You hereby agree to indemnify the +Initial Developer for any liability incurred by the Initial +Developer as a result of warranty, support, indemnity or +liability terms You offer. + +3.3 Distribution of Executable Versions. You may distribute +Original Code in Executable and Source form only if the +requirements of Section 3.1 and 3.2 have been met for that +Original Code, and if You include a notice stating that the +Source Code version of the Original Code is available under +the terms of this License. The notice must be conspicuously +included in any notice in an Executable or Source versions, +related documentation or collateral in which You describe +recipients' rights relating to the Original Code. You may +distribute the Executable and Source versions of Your +version of the Code or ownership rights under a license of +Your choice, which may contain terms different from this +License, provided that You are in compliance with the terms +of this License. If You distribute the Executable and +Source versions under a different license You must make it +absolutely clear that any terms which differ from this +License are offered by You alone, not by the Initial +Developer . You hereby agree to indemnify the Initial +Developer for any liability incurred by the Initial +Developer as a result of any such terms You offer . + +3.4 Larger Works. You may create a Larger Work by combining +Original Code with other code not governed by the terms of +this License and distribute the Larger Work as a single +product. In such a case, You must make sure the +requirements of this License are fulfilled for the Original +Code. + +4.0 INABILITY TO COMPLY DUE TO STATUTE OR REGULATION + +If it is impossible for You to comply with any of the terms +of this License with respect to some or all of the Original +Code due to statute, judicial order, or regulation then You +must: + +a) comply with the terms of this License to the maximum +extent possible; and + +b) describe the limitations and the code they affect. Such +description must be included in the LEGAL file described in +Section 3.2 and must be included with all distributions of +the Source Code. Except to the extent prohibited by statute +or regulation, such description must be sufficiently +detailed for a recipient of ordinary skill to be able to +understand it. + +5.0 APPLICATION OF THIS LICENSE This License applies to code +to which the Initial Developer has attached the notice in +Exhibit A and to related Modifications as set out in Section +3.1. + +6.0 VERSIONS OF THE LICENSE + +6.1 New Versions. Sun Microsystems, Inc. Sun may publish +revised and/or new versions of the License from time to +time. Each version will be given a distinguishing version +number . + +6.2 Effect of New Versions. Once Original Code has been +published under a particular version of the License, You may +always continue to use it under the terms of that version. +You may also choose to use such Original Code under the +terms of any subsequent version of the License published by +Sun. No one other than Sun has the right to modify the +terms applicable to Original Code. + +7. DISCLAIMER OF W ARRANTY. ORIGINAL CODE IS PROVIDED +UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY OF +ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT +LIMITATION, WARRANTIES THAT THE ORIGINAL CODE IS FREE OF +DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR +NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND +PERFORMANCE OF THE ORIGINAL CODE IS WITH YOU. SHOULD ANY +ORIGINAL CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE +INITIAL DEVELOPER )ASSUME THE COST OF ANY NECESSARY +SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF +WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO +USE OF ANY ORIGINAL CODE IS AUTHORIZED HEREUNDER EXCEPT +UNDER THIS DISCLAIMER. + +8.0 TERMINATION + +8.1 This License and the rights granted hereunder will +terminate automatically if You fail to comply with terms +herein and fail to cure such breach within 30 days of +becoming aware of the breach. All sublicenses to the +Original Code which are properly granted shall survive any +termination of this License. Provisions which, by their +nature, must remain in effect beyond the termination of this +License shall survive. + +8.2 .In the event of termination under Section 8.1 above, +all end user license agreements (excluding distributors and +resellers) which have been validly granted by You or any +distributor hereunder prior to termination shall survive +termination. + +9.0 LIMIT OF LIABILITY UNDER NO CIRCUMSTANCES AND UNDER NO +LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE) ,CONTRACT, +OR OTHER WISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER +CONTRIBUTOR, OR ANY DISTRIBUTOR OF ORIGINAL CODE, OR ANY +SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR +ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR +LOSS OF GOOD WILL, WORK STOPPAGE, COMPUTER FAILURE OR +MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR +LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE +POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY +SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY +RESULTING FROM SUCH PARTYS NEGLIGENCE TO THE EXTENT +APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME +JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF +INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND +LIMITATION MAY NOT APPLY TO YOU. + +10.0 U .S. GOVERNMENT END USERS U.S. Government: If this +Software is being acquired by or on behalf of the U.S. +Government or by a U.S. Government prime contractor or +subcontractor (at any tier), then the Government's rights in +the Software and accompanying documentation shall be only as +set forth in this license; this is in accordance with 48 C.F +.R. 227.7201 through 227.7202-4 (for Department of Defense +(DoD) acquisitions )and with 48 C.F.R.2.101 and 12.212( for +non-DoD acquisitions). + +11.0 MISCELLANEOUS This License represents the complete +agreement concerning subject matter hereof. If any +provision of this License is held to be unenforceable, such +provision shall be reformed only to the extent necessary to +make it enforceable. This License shall be governed by +California law provisions (except to the extent applicable +law, if any, provides otherwise), excluding its +conflict-of-law provisions. With respect to disputes in +which at least one party is a citizen of, or an entity +chartered or registered to do business in the United States +of America, any litigation relating to this License shall be +subject to the jurisdiction of the Federal Courts of the +Northern District of California, with venue lying in Santa +Clara County, California, with the losing party responsible +for costs, including without limitation, court costs and +reasonable attorneys fees and expenses. The application of +the United Nations Convention on Contracts for the +International Sale of Goods is expressly excluded. Any law +or regulation which provides that the language of a contract +shall be construed against the drafter shall not apply to +this License. + +EXHIBIT A - Sun Standards + +"The contents of this file are subject to the Sun Standards +License Version 1.0 the (the "License";) You may not use +this file except in compliance with the License. You may +obtain a copy of the License at +_______________________________. + + Software distributed under the License is distributed on +an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either +express or implied. See the License for the specific +language governing rights and limitations under the License. + +The Original Code is Copyright 1998 by Sun Microsystems, Inc + +The Initial Developer of the Original Code is: Sun +Microsystems, Inc. + +Portions created by _____________________________ are +Copyright ______________________________. + +All Rights Reserved. + +Contributors: ______________________________________. + +EXHIBIT B - Sun Standards + +The Standard is defined as the following IETF RFCs: + +RFC1831: RPC: Remote Procedure Call Protocol Specification +Version 2 RFC1832: XDR: External Data REpresentation +Standard RFC1833: Binding Protocols for ONC RPC Version 2 +RFC2078: Generic Security Service Application Program +Interface, Version 2 RFC2203: RPCSEC_GSS Protocol +Specification RFC2695: Authentication Mechanisms for ONC RPC diff --git a/lib/libc/rpc/Makefile.inc b/lib/libc/rpc/Makefile.inc index 5234e89..3f2903f 100644 --- a/lib/libc/rpc/Makefile.inc +++ b/lib/libc/rpc/Makefile.inc @@ -78,7 +78,9 @@ MLINKS+= bindresvport.3 bindresvport_sa.3 \ rpc_clnt_calls.3 clnt_geterr.3 \ rpc_clnt_create.3 clnt_control.3 \ rpc_clnt_create.3 clnt_create.3 \ + rpc_clnt_create.3 clnt_create_timed.3 \ rpc_clnt_create.3 clnt_create_vers.3 \ + rpc_clnt_create.3 clnt_create_vers_timed.3 \ rpc_clnt_create.3 clnt_destroy.3 \ rpc_clnt_create.3 clnt_pcreateerror.3 \ rpc_clnt_create.3 clnt_spcreateerror.3 \ @@ -86,6 +88,7 @@ MLINKS+= bindresvport.3 bindresvport_sa.3 \ rpc_clnt_create.3 clnt_raw_create.3 \ rpc_clnt_create.3 clnt_tli_create.3 \ rpc_clnt_create.3 clnt_tp_create.3 \ + rpc_clnt_create.3 clnt_tp_create_timed.3 \ rpc_clnt_create.3 clnt_vc_create.3 \ rpc_svc_calls.3 svc_dg_enablecache.3 \ rpc_svc_calls.3 svc_exit.3 \ diff --git a/lib/libc/rpc/clnt_generic.c b/lib/libc/rpc/clnt_generic.c index 4147871..d249df6 100644 --- a/lib/libc/rpc/clnt_generic.c +++ b/lib/libc/rpc/clnt_generic.c @@ -1,6 +1,23 @@ /* $NetBSD: clnt_generic.c,v 1.18 2000/07/06 03:10:34 christos Exp $ */ /* + * The contents of this file are subject to the Sun Standards + * License Version 1.0 the (the "License";) You may not use + * this file except in compliance with the License. You may + * obtain a copy of the License at lib/libc/rpc/LICENSE + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is Copyright 1998 by Sun Microsystems, Inc + * + * The Initial Developer of the Original Code is: Sun + * Microsystems, Inc. + * + * All Rights Reserved. + * * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. Users @@ -29,7 +46,7 @@ * Mountain View, California 94043 */ -/* #ident "@(#)clnt_generic.c 1.20 94/05/03 SMI" */ +/* #ident "@(#)clnt_generic.c 1.40 99/04/21 SMI" */ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)clnt_generic.c 1.4 87/08/11 (C) 1987 SMI";*/ @@ -39,17 +56,20 @@ __FBSDID("$FreeBSD$"); /* - * Copyright (c) 1986-1991 by Sun Microsystems Inc. + * Copyright (c) 1986-1996,1998 by Sun Microsystems, Inc. + * All rights reserved. */ #include "namespace.h" #include "reentrant.h" #include <sys/types.h> +#include <sys/fcntl.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <stdio.h> #include <errno.h> #include <netdb.h> +#include <syslog.h> #include <rpc/rpc.h> #include <rpc/nettype.h> #include <string.h> @@ -58,55 +78,79 @@ __FBSDID("$FreeBSD$"); #include "un-namespace.h" #include "rpc_com.h" +extern bool_t __rpc_is_local_host(const char *); +int __rpc_raise_fd(int); + +#ifndef NETIDLEN +#define NETIDLEN 32 +#endif + + /* * Generic client creation with version checking the value of * vers_out is set to the highest server supported value * vers_low <= vers_out <= vers_high AND an error results * if this can not be done. + * + * It calls clnt_create_vers_timed() with a NULL value for the timeout + * pointer, which indicates that the default timeout should be used. */ CLIENT * -clnt_create_vers(hostname, prog, vers_out, vers_low, vers_high, nettype) - const char *hostname; - rpcprog_t prog; - rpcvers_t *vers_out; - rpcvers_t vers_low; - rpcvers_t vers_high; - const char *nettype; +clnt_create_vers(const char *hostname, rpcprog_t prog, rpcvers_t *vers_out, + rpcvers_t vers_low, rpcvers_t vers_high, const char *nettype) +{ + + return (clnt_create_vers_timed(hostname, prog, vers_out, vers_low, + vers_high, nettype, NULL)); +} + +/* + * This the routine has the same definition as clnt_create_vers(), + * except it takes an additional timeout parameter - a pointer to + * a timeval structure. A NULL value for the pointer indicates + * that the default timeout value should be used. + */ +CLIENT * +clnt_create_vers_timed(const char *hostname, rpcprog_t prog, + rpcvers_t *vers_out, rpcvers_t vers_low, rpcvers_t vers_high, + const char *nettype, const struct timeval *tp) { CLIENT *clnt; struct timeval to; enum clnt_stat rpc_stat; struct rpc_err rpcerr; - clnt = clnt_create(hostname, prog, vers_high, nettype); + clnt = clnt_create_timed(hostname, prog, vers_high, nettype, tp); if (clnt == NULL) { return (NULL); } to.tv_sec = 10; to.tv_usec = 0; - rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, - (char *) NULL, (xdrproc_t) xdr_void, (char *) NULL, to); + rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void, + (char *)NULL, (xdrproc_t)xdr_void, (char *)NULL, to); if (rpc_stat == RPC_SUCCESS) { *vers_out = vers_high; return (clnt); } - if (rpc_stat == RPC_PROGVERSMISMATCH) { - unsigned long minvers, maxvers; + while (rpc_stat == RPC_PROGVERSMISMATCH && vers_high > vers_low) { + unsigned int minvers, maxvers; clnt_geterr(clnt, &rpcerr); minvers = rpcerr.re_vers.low; maxvers = rpcerr.re_vers.high; if (maxvers < vers_high) - vers_high = (rpcvers_t)maxvers; + vers_high = maxvers; + else + vers_high--; if (minvers > vers_low) - vers_low = (rpcvers_t)minvers; + vers_low = minvers; if (vers_low > vers_high) { goto error; } - CLNT_CONTROL(clnt, CLSET_VERS, (char *)(void *)&vers_high); - rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, - (char *) NULL, (xdrproc_t) xdr_void, - (char *) NULL, to); + CLNT_CONTROL(clnt, CLSET_VERS, (char *)&vers_high); + rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void, + (char *)NULL, (xdrproc_t)xdr_void, + (char *)NULL, to); if (rpc_stat == RPC_SUCCESS) { *vers_out = vers_high; return (clnt); @@ -132,23 +176,48 @@ error: * XXX The error message in the case of failure will be the one * pertaining to the last create error. * - * It calls clnt_tp_create(); + * It calls clnt_create_timed() with the default timeout. */ CLIENT * -clnt_create(hostname, prog, vers, nettype) - const char *hostname; /* server name */ - rpcprog_t prog; /* program number */ - rpcvers_t vers; /* version number */ - const char *nettype; /* net type */ +clnt_create(const char *hostname, rpcprog_t prog, rpcvers_t vers, + const char *nettype) +{ + + return (clnt_create_timed(hostname, prog, vers, nettype, NULL)); +} + +/* + * This the routine has the same definition as clnt_create(), + * except it takes an additional timeout parameter - a pointer to + * a timeval structure. A NULL value for the pointer indicates + * that the default timeout value should be used. + * + * This function calls clnt_tp_create_timed(). + */ +CLIENT * +clnt_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers, + const char *netclass, const struct timeval *tp) { struct netconfig *nconf; CLIENT *clnt = NULL; void *handle; enum clnt_stat save_cf_stat = RPC_SUCCESS; struct rpc_err save_cf_error; + char nettype_array[NETIDLEN]; + char *nettype = &nettype_array[0]; + if (netclass == NULL) + nettype = NULL; + else { + size_t len = strlen(netclass); + if (len >= sizeof (nettype_array)) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + strcpy(nettype, netclass); + } - if ((handle = __rpc_setconf(nettype)) == NULL) { + if ((handle = __rpc_setconf((char *)nettype)) == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; return (NULL); } @@ -162,7 +231,7 @@ clnt_create(hostname, prog, vers, nettype) #ifdef CLNT_DEBUG printf("trying netid %s\n", nconf->nc_netid); #endif - clnt = clnt_tp_create(hostname, prog, vers, nconf); + clnt = clnt_tp_create_timed(hostname, prog, vers, nconf, tp); if (clnt) break; else @@ -178,9 +247,12 @@ clnt_create(hostname, prog, vers, nettype) * the local loopbacks are typically the * last ones in /etc/netconfig and the most * likely to be unable to translate a host - * name). + * name). We also check for a more + * meaningful error than ``unknown host + * name'' for the same reasons. */ - if (rpc_createerr.cf_stat != RPC_N2AXLATEFAILURE) { + if (rpc_createerr.cf_stat != RPC_N2AXLATEFAILURE && + rpc_createerr.cf_stat != RPC_UNKNOWNHOST) { save_cf_stat = rpc_createerr.cf_stat; save_cf_error = rpc_createerr.cf_error; } @@ -188,10 +260,11 @@ clnt_create(hostname, prog, vers, nettype) /* * Attempt to return an error more specific than ``Name to address - * translation failed'' + * translation failed'' or ``unknown host name'' */ - if ((rpc_createerr.cf_stat == RPC_N2AXLATEFAILURE) && - (save_cf_stat != RPC_SUCCESS)) { + if ((rpc_createerr.cf_stat == RPC_N2AXLATEFAILURE || + rpc_createerr.cf_stat == RPC_UNKNOWNHOST) && + (save_cf_stat != RPC_SUCCESS)) { rpc_createerr.cf_stat = save_cf_stat; rpc_createerr.cf_error = save_cf_error; } @@ -203,14 +276,27 @@ clnt_create(hostname, prog, vers, nettype) * Generic client creation: takes (servers name, program-number, netconf) and * returns client handle. Default options are set, which the user can * change using the rpc equivalent of _ioctl()'s : clnt_control() - * It finds out the server address from rpcbind and calls clnt_tli_create() + * It finds out the server address from rpcbind and calls clnt_tli_create(). + * + * It calls clnt_tp_create_timed() with the default timeout. */ CLIENT * -clnt_tp_create(hostname, prog, vers, nconf) - const char *hostname; /* server name */ - rpcprog_t prog; /* program number */ - rpcvers_t vers; /* version number */ - const struct netconfig *nconf; /* net config struct */ +clnt_tp_create(const char *hostname, rpcprog_t prog, rpcvers_t vers, + const struct netconfig *nconf) +{ + + return (clnt_tp_create_timed(hostname, prog, vers, nconf, NULL)); +} + +/* + * This has the same definition as clnt_tp_create(), except it + * takes an additional parameter - a pointer to a timeval structure. + * A NULL value for the timeout pointer indicates that the default + * value for the timeout should be used. + */ +CLIENT * +clnt_tp_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers, + const struct netconfig *nconf, const struct timeval *tp) { struct netbuf *svcaddr; /* servers address */ CLIENT *cl = NULL; /* client handle */ @@ -223,8 +309,9 @@ clnt_tp_create(hostname, prog, vers, nconf) /* * Get the address of the server */ - if ((svcaddr = __rpcb_findaddr(prog, vers, nconf, hostname, - &cl)) == NULL) { + if ((svcaddr = __rpcb_findaddr_timed(prog, vers, + (struct netconfig *)nconf, (char *)hostname, + &cl, (struct timeval *)tp)) == NULL) { /* appropriate error number is set by rpcbind libraries */ return (NULL); } @@ -260,20 +347,16 @@ clnt_tp_create(hostname, prog, vers, nconf) * If sizes are 0; appropriate defaults will be chosen. */ CLIENT * -clnt_tli_create(fd, nconf, svcaddr, prog, vers, sendsz, recvsz) - int fd; /* fd */ - const struct netconfig *nconf; /* netconfig structure */ - const struct netbuf *svcaddr; /* servers address */ - rpcprog_t prog; /* program number */ - rpcvers_t vers; /* version number */ - u_int sendsz; /* send size */ - u_int recvsz; /* recv size */ +clnt_tli_create(int fd, const struct netconfig *nconf, + struct netbuf *svcaddr, rpcprog_t prog, rpcvers_t vers, + uint sendsz, uint recvsz) { CLIENT *cl; /* client handle */ bool_t madefd = FALSE; /* whether fd opened here */ long servtype; int one = 1; struct __rpc_sockinfo si; + extern int __rpc_minfd; if (fd == RPC_ANYFD) { if (nconf == NULL) { @@ -285,12 +368,12 @@ clnt_tli_create(fd, nconf, svcaddr, prog, vers, sendsz, recvsz) if (fd == -1) goto err; - + if (fd < __rpc_minfd) + fd = __rpc_raise_fd(fd); madefd = TRUE; servtype = nconf->nc_semantics; if (!__rpc_fd2sockinfo(fd, &si)) goto err; - bindresvport(fd, NULL); } else { if (!__rpc_fd2sockinfo(fd, &si)) @@ -298,9 +381,8 @@ clnt_tli_create(fd, nconf, svcaddr, prog, vers, sendsz, recvsz) servtype = __rpc_socktype2seman(si.si_socktype); if (servtype == -1) { rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; - return NULL; + return (NULL); } - } if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) { @@ -309,14 +391,15 @@ clnt_tli_create(fd, nconf, svcaddr, prog, vers, sendsz, recvsz) } switch (servtype) { - case NC_TPI_COTS_ORD: + case NC_TPI_COTS: cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz); - if (!nconf || !cl) - break; - /* XXX fvdl - is this useful? */ - if (strncmp(nconf->nc_protofmly, "inet", 4) == 0) + break; + case NC_TPI_COTS_ORD: + if (nconf && ((strcmp(nconf->nc_protofmly, "inet") == 0))) { _setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof (one)); + } + cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz); break; case NC_TPI_CLTS: cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz); @@ -336,7 +419,7 @@ clnt_tli_create(fd, nconf, svcaddr, prog, vers, sendsz, recvsz) } if (madefd) { (void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL); -/* (void) CLNT_CONTROL(cl, CLSET_POP_TIMOD, (char *) NULL); */ +/* (void) CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL); */ }; return (cl); @@ -348,3 +431,36 @@ err1: if (madefd) (void)_close(fd); return (NULL); } + +/* + * To avoid conflicts with the "magic" file descriptors (0, 1, and 2), + * we try to not use them. The __rpc_raise_fd() routine will dup + * a descriptor to a higher value. If we fail to do it, we continue + * to use the old one (and hope for the best). + */ +int __rpc_minfd = 3; + +int +__rpc_raise_fd(int fd) +{ + int nfd; + + if (fd >= __rpc_minfd) + return (fd); + + if ((nfd = _fcntl(fd, F_DUPFD, __rpc_minfd)) == -1) + return (fd); + + if (_fsync(nfd) == -1) { + _close(nfd); + return (fd); + } + + if (_close(fd) == -1) { + /* this is okay, we will syslog an error, then use the new fd */ + (void) syslog(LOG_ERR, + "could not close() fd %d; mem & fd leak", fd); + } + + return (nfd); +} diff --git a/lib/libc/rpc/rpc_clnt_create.3 b/lib/libc/rpc/rpc_clnt_create.3 index 4f6e90c..d353168 100644 --- a/lib/libc/rpc/rpc_clnt_create.3 +++ b/lib/libc/rpc/rpc_clnt_create.3 @@ -11,7 +11,9 @@ .Nm rpc_clnt_create , .Nm clnt_control , .Nm clnt_create , +.Nm clnt_create_timed , .Nm clnt_create_vers , +.Nm clnt_create_vers_timed , .Nm clnt_destroy , .Nm clnt_dg_create , .Nm clnt_pcreateerror , @@ -19,6 +21,7 @@ .Nm clnt_spcreateerror , .Nm clnt_tli_create , .Nm clnt_tp_create , +.Nm clnt_tp_create_timed , .Nm clnt_vc_create , .Nm rpc_createerr .Nd "library routines for dealing with creation and manipulation of" @@ -33,7 +36,11 @@ handles .Ft "CLIENT *" .Fn clnt_create "const char * host" "const rpcprog_t prognum" "const rpcvers_t versnum" "const char *nettype" .Ft "CLIENT *" +.Fn clnt_create_timed "const char * host" "const rpcprog_t prognum" "const rpcvers_t versnum" "const char *nettype" "const struct timeval *timeout" +.Ft "CLIENT *" .Fn clnt_create_vers "const char * host" "const rpcprog_t prognum" "rpcvers_t *vers_outp" "const rpcvers_t vers_low" "const rpcvers_t vers_high" "const char *nettype" +.Ft "CLIENT *" +.Fn clnt_create_vers_timed "const char * host" "const rpcprog_t prognum" "rpcvers_t *vers_outp" "const rpcvers_t vers_low" "const rpcvers_t vers_high" "char *nettype" "const struct timeval *timeout" .Ft void .Fn clnt_destroy "CLIENT *clnt" .Ft "CLIENT *" @@ -49,6 +56,8 @@ handles .Ft "CLIENT *" .Fn clnt_tp_create "const char * host" "const rpcprog_t prognum" "const rpcvers_t versnum" "const struct netconfig *netconf" .Ft "CLIENT *" +.Fn clnt_tp_create_timed "const char * host" "const rpcprog_t prognum" "const rpcvers_t versnum" "const struct netconfig *netconf" "const struct timeval *timeout" +.Ft "CLIENT *" .Fn clnt_vc_create "const int fildes" "const struct netbuf *svcaddr" "const rpcprog_t prognum" "const rpcvers_t versnum" "const u_int sendsz" "const u_int recvsz" .Sh DESCRIPTION RPC library routines allow C language programs to make procedure @@ -158,6 +167,17 @@ This mismatch will be discovered by a .Fn clnt_call later (see .Xr rpc_clnt_calls 3 ) . +.It Fn clnt_create_timed +Generic client creation routine which is similar to +.Fn clnt_create +but which also has the additional parameter +.Fa timeout +that specifies the maximum amount of time allowed for +each transport class tried. In all other respects, the +.Fn clnt_create_timed +call behaves exactly like the +.Fn clnt_create +call. .It Fn clnt_create_vers Generic client creation routine which is similar to .Fn clnt_create @@ -213,6 +233,17 @@ However, does this for you and returns a valid handle only if a version within the range supplied is supported by the server. +.It Fn clnt_create_vers_timed +Generic client creation routine which is similar to +.Fn clnt_create_vers +but which also has the additional parameter +.Fa timeout +that specifies the maximum amount of time allowed for +each transport class tried. In all other respects, the +.Fn clnt_create_vers_timed +call behaves exactly like the +.Fn clnt_create_vers +call. .It Fn clnt_destroy A function macro that destroys the client's RPC handle. Destruction usually involves deallocation @@ -393,6 +424,20 @@ if it fails. The .Fn clnt_pcreateerror routine can be used to print the reason for failure. +.It Fn clnt_tp_create_timed +Like +.Fn clnt_tp_create +except +.Fn clnt_tp_create_timed +has the extra parameter +.Fa timeout +which specifies the maximum time allowed for +for the creation attempt to succeed. +In all other respects, the +.Fn clnt_tp_create_timed +call behaves exactly like the +.Fn clnt_tp_create +call. .It Fn clnt_vc_create This routine creates an RPC client for the remote program diff --git a/lib/libc/rpc/rpcb_clnt.c b/lib/libc/rpc/rpcb_clnt.c index c4db751..b47f36b 100644 --- a/lib/libc/rpc/rpcb_clnt.c +++ b/lib/libc/rpc/rpcb_clnt.c @@ -1,6 +1,23 @@ /* $NetBSD: rpcb_clnt.c,v 1.6 2000/07/16 06:41:43 itojun Exp $ */ /* + * The contents of this file are subject to the Sun Standards + * License Version 1.0 the (the "License";) You may not use + * this file except in compliance with the License. You may + * obtain a copy of the License at lib/libc/rpc/LICENSE + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is Copyright 1998 by Sun Microsystems, Inc + * + * The Initial Developer of the Original Code is: Sun + * Microsystems, Inc. + * + * All Rights Reserved. + * * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. Users @@ -75,6 +92,7 @@ __FBSDID("$FreeBSD$"); static struct timeval tottimeout = { 60, 0 }; static const struct timeval rmttimeout = { 3, 0 }; +static struct timeval rpcbrmttime = { 15, 0 }; extern bool_t xdr_wrapstring(XDR *, char **); @@ -654,6 +672,47 @@ got_entry(relp, nconf) } /* + * Quick check to see if rpcbind is up. Tries to connect over + * local transport. + */ +bool_t +__rpcbind_is_up() +{ + struct netconfig *nconf; + struct sockaddr_un sun; + void *localhandle; + int sock; + + nconf = NULL; + localhandle = setnetconfig(); + while (nconf = getnetconfig(localhandle)){ + if (nconf->nc_protofmly != NULL && + strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) + break; + } + if (nconf == NULL) + return (FALSE); + + endnetconfig(localhandle); + + memset(&sun, 0, sizeof sun); + sock = _socket(AF_LOCAL, SOCK_STREAM, 0); + if (sock < 0) + return (FALSE); + sun.sun_family = AF_LOCAL; + strncpy(sun.sun_path, _PATH_RPCBINDSOCK, sizeof(sun.sun_path)); + sun.sun_len = SUN_LEN(&sun); + + if (_connect(sock, (struct sockaddr *)&sun, sun.sun_len) < 0) { + _close(sock); + return (FALSE); + } + + _close(sock); + return (TRUE); +} + +/* * An internal function which optimizes rpcb_getaddr function. It also * returns the client handle that it uses to contact the remote rpcbind. * @@ -672,13 +731,15 @@ got_entry(relp, nconf) * starts working properly. Also look under clnt_vc.c. */ struct netbuf * -__rpcb_findaddr(program, version, nconf, host, clpp) +__rpcb_findaddr_timed(program, version, nconf, host, clpp, tp) rpcprog_t program; rpcvers_t version; const struct netconfig *nconf; const char *host; CLIENT **clpp; + struct timeval *tp; { + static bool_t check_rpcbind = TRUE; CLIENT *client = NULL; RPCB parms; enum clnt_stat clnt_st; @@ -696,6 +757,12 @@ __rpcb_findaddr(program, version, nconf, host, clpp) parms.r_addr = NULL; + /* + * Use default total timeout if no timeout is specified. + */ + if (tp == NULL) + tp = &tottimeout; + #ifdef PORTMAP /* Try version 2 for TCP or UDP */ if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { @@ -710,22 +777,31 @@ __rpcb_findaddr(program, version, nconf, host, clpp) */ if (strcmp(nconf->nc_proto, NC_TCP) == 0) { struct netconfig *newnconf; + void *handle; - if ((newnconf = getnetconfigent("udp")) == NULL) { + if ((handle = getnetconfigent("udp")) == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + if ((newnconf = __rpc_getconf(handle)) == NULL) { + __rpc_endconf(handle); rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; return (NULL); } client = getclnthandle(host, newnconf, &parms.r_addr); - freenetconfigent(newnconf); + __rpc_endconf(handle); } else { client = getclnthandle(host, nconf, &parms.r_addr); } - if (client == NULL) { + if (client == NULL) return (NULL); - } - /* Set the version */ - CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&pmapvers); + /* + * Set version and retry timeout. + */ + CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime); + CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers); + pmapparms.pm_prog = program; pmapparms.pm_vers = version; pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ? @@ -734,7 +810,7 @@ __rpcb_findaddr(program, version, nconf, host, clpp) clnt_st = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT, (xdrproc_t) xdr_pmap, (caddr_t)(void *)&pmapparms, (xdrproc_t) xdr_u_short, (caddr_t)(void *)&port, - tottimeout); + *tp); if (clnt_st != RPC_SUCCESS) { if ((clnt_st == RPC_PROGVERSMISMATCH) || (clnt_st == RPC_PROGUNAVAIL)) @@ -748,7 +824,7 @@ __rpcb_findaddr(program, version, nconf, host, clpp) goto error; } port = htons(port); - CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)(void *)&remote); + CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote); if (((address = (struct netbuf *) malloc(sizeof (struct netbuf))) == NULL) || ((address->buf = (char *) @@ -771,6 +847,20 @@ __rpcb_findaddr(program, version, nconf, host, clpp) try_rpcbind: /* + * Check if rpcbind is up. This prevents needless delays when + * accessing applications such as the keyserver while booting + * disklessly. + */ + if (check_rpcbind && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { + if (!__rpcbind_is_up()) { + rpc_createerr.cf_stat = RPC_PMAPFAILURE; + rpc_createerr.cf_error.re_errno = 0; + goto error; + } + check_rpcbind = FALSE; + } + + /* * Now we try version 4 and then 3. * We also send the remote system the address we used to * contact it in case it can help to connect back with us @@ -785,33 +875,17 @@ try_rpcbind: /* * If a COTS transport is being used, try getting address via CLTS * transport. This works only with version 4. - * NOTE: This is being done for all transports EXCEPT LOOPBACK - * because with loopback the cost to go to a COTS is same as - * the cost to go through CLTS, plus you get the advantage of - * finding out immediately if the local rpcbind process is dead. */ -#if 1 - if ((nconf->nc_semantics == NC_TPI_COTS_ORD || - nconf->nc_semantics == NC_TPI_COTS) && - (strcmp(nconf->nc_protofmly, NC_LOOPBACK) != 0)) { -#else - if (client != NULL) { - CLNT_DESTROY(client); - client = NULL; - } - if (nconf->nc_semantics == NC_TPI_CLTS) { -#endif + if (nconf->nc_semantics == NC_TPI_COTS_ORD || + nconf->nc_semantics == NC_TPI_COTS) { + void *handle; struct netconfig *nconf_clts; rpcb_entry_list_ptr relp = NULL; if (client == NULL) { /* This did not go through the above PORTMAP/TCP code */ -#if 1 if ((handle = __rpc_setconf("datagram_v")) != NULL) { -#else - if ((handle = __rpc_setconf("circuit_v")) != NULL) { -#endif while ((nconf_clts = __rpc_getconf(handle)) != NULL) { if (strcmp(nconf_clts->nc_protofmly, @@ -839,10 +913,13 @@ try_rpcbind: /*LINTED const castaway*/ parms.r_addr = (char *) &nullstring[0]; /* for XDRing */ } + + CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime); + clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDRLIST, (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, (xdrproc_t) xdr_rpcb_entry_list_ptr, - (char *)(void *)&relp, tottimeout); + (char *)(void *)&relp, *tp); if (clnt_st == RPC_SUCCESS) { if ((address = got_entry(relp, nconf)) != NULL) { xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr, @@ -873,12 +950,8 @@ try_rpcbind: regular_rpcbind: /* Now the same transport is to be used to get the address */ -#if 1 if (client && ((nconf->nc_semantics == NC_TPI_COTS_ORD) || (nconf->nc_semantics == NC_TPI_COTS))) { -#else - if (client && nconf->nc_semantics == NC_TPI_CLTS) { -#endif /* A CLTS type of client - destroy it */ CLNT_DESTROY(client); client = NULL; @@ -896,13 +969,14 @@ regular_rpcbind: } /* First try from start_vers and then version 3 (RPCBVERS) */ + + CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *) &rpcbrmttime); for (vers = start_vers; vers >= RPCBVERS; vers--) { /* Set the version */ CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDR, (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, - (xdrproc_t) xdr_wrapstring, (char *)(void *) &ua, - tottimeout); + (xdrproc_t) xdr_wrapstring, (char *)(void *) &ua, *tp); if (clnt_st == RPC_SUCCESS) { if ((ua == NULL) || (ua[0] == NULL)) { /* address unknown */ @@ -989,8 +1063,9 @@ rpcb_getaddr(program, version, nconf, address, host) { struct netbuf *na; - if ((na = __rpcb_findaddr(program, version, nconf, - host, (CLIENT **) NULL)) == NULL) + if ((na = __rpcb_findaddr_timed(program, version, + (struct netconfig *) nconf, (char *) host, + (CLIENT **) NULL, (struct timeval *) NULL)) == NULL) return (FALSE); if (na->len > address->maxlen) { |