2 * The contents of this file are subject to the Sun Standards
3 * License Version 1.0 the (the "License";) You may not use
4 * this file except in compliance with the License. You may
5 * obtain a copy of the License at lib/libc/rpc/LICENSE
7 * Software distributed under the License is distributed on
8 * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
9 * express or implied. See the License for the specific
10 * language governing rights and limitations under the License.
12 * The Original Code is Copyright 1998 by Sun Microsystems, Inc
14 * The Initial Developer of the Original Code is: Sun
17 * All Rights Reserved.
19 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
20 * unrestricted use provided that this legend is included on all tape
21 * media and as a part of the software program in whole or part. Users
22 * may copy or modify Sun RPC without charge, but are not authorized
23 * to license or distribute it to anyone else except as part of a product or
24 * program developed by the user.
26 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
27 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
30 * Sun RPC is provided with no support and without any obligation on the
31 * part of Sun Microsystems, Inc. to assist in its use, correction,
32 * modification or enhancement.
34 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
35 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
36 * OR ANY PART THEREOF.
38 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
39 * or profits or other special, indirect and consequential damages, even if
40 * Sun has been advised of the possibility of such damages.
42 * Sun Microsystems, Inc.
44 * Mountain View, California 94043
46 * @(#)clnt_generic.c 1.4 87/08/11 (C) 1987 SMI
47 * @(#)clnt_generic.c 2.2 88/08/01 4.0 RPCSRC
48 * @(#)clnt_generic.c 1.40 99/04/21 SMI
49 * $NetBSD: clnt_generic.c,v 1.18 2000/07/06 03:10:34 christos Exp $
50 * $FreeBSD: src/lib/libc/rpc/clnt_generic.c,v 1.15 2004/10/16 06:11:34 obrien Exp $
51 * $DragonFly: src/lib/libc/rpc/clnt_generic.c,v 1.4 2005/01/31 22:29:38 dillon Exp $
55 * Copyright (c) 1986-1996,1998 by Sun Microsystems, Inc.
56 * All rights reserved.
58 #include "namespace.h"
59 #include "reentrant.h"
60 #include <sys/types.h>
61 #include <sys/fcntl.h>
62 #include <sys/socket.h>
63 #include <netinet/in.h>
64 #include <netinet/tcp.h>
70 #include <rpc/nettype.h>
74 #include "un-namespace.h"
77 extern bool_t
__rpc_is_local_host(const char *);
78 int __rpc_raise_fd(int);
86 * Generic client creation with version checking the value of
87 * vers_out is set to the highest server supported value
88 * vers_low <= vers_out <= vers_high AND an error results
89 * if this can not be done.
91 * It calls clnt_create_vers_timed() with a NULL value for the timeout
92 * pointer, which indicates that the default timeout should be used.
95 clnt_create_vers(const char *hostname
, rpcprog_t prog
, rpcvers_t
*vers_out
,
96 rpcvers_t vers_low
, rpcvers_t vers_high
, const char *nettype
)
99 return (clnt_create_vers_timed(hostname
, prog
, vers_out
, vers_low
,
100 vers_high
, nettype
, NULL
));
104 * This the routine has the same definition as clnt_create_vers(),
105 * except it takes an additional timeout parameter - a pointer to
106 * a timeval structure. A NULL value for the pointer indicates
107 * that the default timeout value should be used.
110 clnt_create_vers_timed(const char *hostname
, rpcprog_t prog
,
111 rpcvers_t
*vers_out
, rpcvers_t vers_low
, rpcvers_t vers_high
,
112 const char *nettype
, const struct timeval
*tp
)
116 enum clnt_stat rpc_stat
;
117 struct rpc_err rpcerr
;
119 clnt
= clnt_create_timed(hostname
, prog
, vers_high
, nettype
, tp
);
125 rpc_stat
= clnt_call(clnt
, NULLPROC
, (xdrproc_t
)xdr_void
,
126 (char *)NULL
, (xdrproc_t
)xdr_void
, (char *)NULL
, to
);
127 if (rpc_stat
== RPC_SUCCESS
) {
128 *vers_out
= vers_high
;
131 while (rpc_stat
== RPC_PROGVERSMISMATCH
&& vers_high
> vers_low
) {
132 unsigned int minvers
, maxvers
;
134 clnt_geterr(clnt
, &rpcerr
);
135 minvers
= rpcerr
.re_vers
.low
;
136 maxvers
= rpcerr
.re_vers
.high
;
137 if (maxvers
< vers_high
)
141 if (minvers
> vers_low
)
143 if (vers_low
> vers_high
) {
146 CLNT_CONTROL(clnt
, CLSET_VERS
, (char *)&vers_high
);
147 rpc_stat
= clnt_call(clnt
, NULLPROC
, (xdrproc_t
)xdr_void
,
148 (char *)NULL
, (xdrproc_t
)xdr_void
,
150 if (rpc_stat
== RPC_SUCCESS
) {
151 *vers_out
= vers_high
;
155 clnt_geterr(clnt
, &rpcerr
);
158 rpc_createerr
.cf_stat
= rpc_stat
;
159 rpc_createerr
.cf_error
= rpcerr
;
165 * Top level client creation routine.
166 * Generic client creation: takes (servers name, program-number, nettype) and
167 * returns client handle. Default options are set, which the user can
168 * change using the rpc equivalent of _ioctl()'s.
170 * It tries for all the netids in that particular class of netid until
172 * XXX The error message in the case of failure will be the one
173 * pertaining to the last create error.
175 * It calls clnt_create_timed() with the default timeout.
178 clnt_create(const char *hostname
, rpcprog_t prog
, rpcvers_t vers
,
182 return (clnt_create_timed(hostname
, prog
, vers
, nettype
, NULL
));
186 * This the routine has the same definition as clnt_create(),
187 * except it takes an additional timeout parameter - a pointer to
188 * a timeval structure. A NULL value for the pointer indicates
189 * that the default timeout value should be used.
191 * This function calls clnt_tp_create_timed().
194 clnt_create_timed(const char *hostname
, rpcprog_t prog
, rpcvers_t vers
,
195 const char *netclass
, const struct timeval
*tp
)
197 struct netconfig
*nconf
;
200 enum clnt_stat save_cf_stat
= RPC_SUCCESS
;
201 struct rpc_err save_cf_error
;
202 char nettype_array
[NETIDLEN
];
203 char *nettype
= &nettype_array
[0];
205 if (netclass
== NULL
)
208 size_t len
= strlen(netclass
);
209 if (len
>= sizeof (nettype_array
)) {
210 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
213 strcpy(nettype
, netclass
);
216 if ((handle
= __rpc_setconf((char *)nettype
)) == NULL
) {
217 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
220 rpc_createerr
.cf_stat
= RPC_SUCCESS
;
221 while (clnt
== NULL
) {
222 if ((nconf
= __rpc_getconf(handle
)) == NULL
) {
223 if (rpc_createerr
.cf_stat
== RPC_SUCCESS
)
224 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
228 printf("trying netid %s\n", nconf
->nc_netid
);
230 clnt
= clnt_tp_create_timed(hostname
, prog
, vers
, nconf
, tp
);
235 * Since we didn't get a name-to-address
236 * translation failure here, we remember
237 * this particular error. The object of
238 * this is to enable us to return to the
239 * caller a more-specific error than the
240 * unhelpful ``Name to address translation
241 * failed'' which might well occur if we
242 * merely returned the last error (because
243 * the local loopbacks are typically the
244 * last ones in /etc/netconfig and the most
245 * likely to be unable to translate a host
246 * name). We also check for a more
247 * meaningful error than ``unknown host
248 * name'' for the same reasons.
250 if (rpc_createerr
.cf_stat
!= RPC_N2AXLATEFAILURE
&&
251 rpc_createerr
.cf_stat
!= RPC_UNKNOWNHOST
) {
252 save_cf_stat
= rpc_createerr
.cf_stat
;
253 save_cf_error
= rpc_createerr
.cf_error
;
258 * Attempt to return an error more specific than ``Name to address
259 * translation failed'' or ``unknown host name''
261 if ((rpc_createerr
.cf_stat
== RPC_N2AXLATEFAILURE
||
262 rpc_createerr
.cf_stat
== RPC_UNKNOWNHOST
) &&
263 (save_cf_stat
!= RPC_SUCCESS
)) {
264 rpc_createerr
.cf_stat
= save_cf_stat
;
265 rpc_createerr
.cf_error
= save_cf_error
;
267 __rpc_endconf(handle
);
272 * Generic client creation: takes (servers name, program-number, netconf) and
273 * returns client handle. Default options are set, which the user can
274 * change using the rpc equivalent of _ioctl()'s : clnt_control()
275 * It finds out the server address from rpcbind and calls clnt_tli_create().
277 * It calls clnt_tp_create_timed() with the default timeout.
280 clnt_tp_create(const char *hostname
, rpcprog_t prog
, rpcvers_t vers
,
281 const struct netconfig
*nconf
)
284 return (clnt_tp_create_timed(hostname
, prog
, vers
, nconf
, NULL
));
288 * This has the same definition as clnt_tp_create(), except it
289 * takes an additional parameter - a pointer to a timeval structure.
290 * A NULL value for the timeout pointer indicates that the default
291 * value for the timeout should be used.
294 clnt_tp_create_timed(const char *hostname
, rpcprog_t prog
, rpcvers_t vers
,
295 const struct netconfig
*nconf
, const struct timeval
*tp
)
297 struct netbuf
*svcaddr
; /* servers address */
298 CLIENT
*cl
= NULL
; /* client handle */
301 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
306 * Get the address of the server
308 if ((svcaddr
= __rpcb_findaddr_timed(prog
, vers
,
309 (struct netconfig
*)nconf
, (char *)hostname
,
310 &cl
, (struct timeval
*)tp
)) == NULL
) {
311 /* appropriate error number is set by rpcbind libraries */
315 cl
= clnt_tli_create(RPC_ANYFD
, nconf
, svcaddr
,
318 /* Reuse the CLIENT handle and change the appropriate fields */
319 if (CLNT_CONTROL(cl
, CLSET_SVC_ADDR
, (void *)svcaddr
) == TRUE
) {
320 if (cl
->cl_netid
== NULL
)
321 cl
->cl_netid
= strdup(nconf
->nc_netid
);
322 if (cl
->cl_tp
== NULL
)
323 cl
->cl_tp
= strdup(nconf
->nc_device
);
324 CLNT_CONTROL(cl
, CLSET_PROG
, (void *)&prog
);
325 CLNT_CONTROL(cl
, CLSET_VERS
, (void *)&vers
);
328 cl
= clnt_tli_create(RPC_ANYFD
, nconf
, svcaddr
,
338 * Generic client creation: returns client handle.
339 * Default options are set, which the user can
340 * change using the rpc equivalent of _ioctl()'s : clnt_control().
341 * If fd is RPC_ANYFD, it will be opened using nconf.
342 * It will be bound if not so.
343 * If sizes are 0; appropriate defaults will be chosen.
346 clnt_tli_create(int fd
, const struct netconfig
*nconf
,
347 struct netbuf
*svcaddr
, rpcprog_t prog
, rpcvers_t vers
,
348 uint sendsz
, uint recvsz
)
350 CLIENT
*cl
; /* client handle */
351 bool_t madefd
= FALSE
; /* whether fd opened here */
354 struct __rpc_sockinfo si
;
355 extern int __rpc_minfd
;
357 if (fd
== RPC_ANYFD
) {
359 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
363 fd
= __rpc_nconf2fd(nconf
);
367 if (fd
< __rpc_minfd
)
368 fd
= __rpc_raise_fd(fd
);
370 servtype
= nconf
->nc_semantics
;
371 if (!__rpc_fd2sockinfo(fd
, &si
))
373 bindresvport(fd
, NULL
);
375 if (!__rpc_fd2sockinfo(fd
, &si
))
377 servtype
= __rpc_socktype2seman(si
.si_socktype
);
378 if (servtype
== -1) {
379 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
384 if (si
.si_af
!= ((struct sockaddr
*)svcaddr
->buf
)->sa_family
) {
385 rpc_createerr
.cf_stat
= RPC_UNKNOWNHOST
; /* XXX */
391 cl
= clnt_vc_create(fd
, svcaddr
, prog
, vers
, sendsz
, recvsz
);
393 case NC_TPI_COTS_ORD
:
394 if (nconf
&& ((strcmp(nconf
->nc_protofmly
, "inet") == 0))) {
395 _setsockopt(fd
, IPPROTO_TCP
, TCP_NODELAY
, &one
,
398 cl
= clnt_vc_create(fd
, svcaddr
, prog
, vers
, sendsz
, recvsz
);
401 cl
= clnt_dg_create(fd
, svcaddr
, prog
, vers
, sendsz
, recvsz
);
408 goto err1
; /* borrow errors from clnt_dg/vc creates */
410 cl
->cl_netid
= strdup(nconf
->nc_netid
);
411 cl
->cl_tp
= strdup(nconf
->nc_device
);
417 CLNT_CONTROL(cl
, CLSET_FD_CLOSE
, NULL
);
418 /* CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL); */
424 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
425 rpc_createerr
.cf_error
.re_errno
= errno
;
432 * To avoid conflicts with the "magic" file descriptors (0, 1, and 2),
433 * we try to not use them. The __rpc_raise_fd() routine will dup
434 * a descriptor to a higher value. If we fail to do it, we continue
435 * to use the old one (and hope for the best).
440 __rpc_raise_fd(int fd
)
444 if (fd
>= __rpc_minfd
)
447 if ((nfd
= _fcntl(fd
, F_DUPFD
, __rpc_minfd
)) == -1)
450 if (_fsync(nfd
) == -1) {
455 if (_close(fd
) == -1) {
456 /* this is okay, we will syslog an error, then use the new fd */
457 syslog(LOG_ERR
, "could not close() fd %d; mem & fd leak", fd
);