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 $
54 * Copyright (c) 1986-1996,1998 by Sun Microsystems, Inc.
55 * All rights reserved.
57 #include "namespace.h"
58 #include "reentrant.h"
59 #include <sys/types.h>
60 #include <sys/fcntl.h>
61 #include <sys/socket.h>
62 #include <netinet/in.h>
63 #include <netinet/tcp.h>
69 #include <rpc/nettype.h>
73 #include "un-namespace.h"
76 extern bool_t
__rpc_is_local_host(const char *);
77 int __rpc_raise_fd(int);
85 * Generic client creation with version checking the value of
86 * vers_out is set to the highest server supported value
87 * vers_low <= vers_out <= vers_high AND an error results
88 * if this can not be done.
90 * It calls clnt_create_vers_timed() with a NULL value for the timeout
91 * pointer, which indicates that the default timeout should be used.
94 clnt_create_vers(const char *hostname
, rpcprog_t prog
, rpcvers_t
*vers_out
,
95 rpcvers_t vers_low
, rpcvers_t vers_high
, const char *nettype
)
98 return (clnt_create_vers_timed(hostname
, prog
, vers_out
, vers_low
,
99 vers_high
, nettype
, NULL
));
103 * This the routine has the same definition as clnt_create_vers(),
104 * except it takes an additional timeout parameter - a pointer to
105 * a timeval structure. A NULL value for the pointer indicates
106 * that the default timeout value should be used.
109 clnt_create_vers_timed(const char *hostname
, rpcprog_t prog
,
110 rpcvers_t
*vers_out
, rpcvers_t vers_low
, rpcvers_t vers_high
,
111 const char *nettype
, const struct timeval
*tp
)
115 enum clnt_stat rpc_stat
;
116 struct rpc_err rpcerr
;
118 clnt
= clnt_create_timed(hostname
, prog
, vers_high
, nettype
, tp
);
124 rpc_stat
= clnt_call(clnt
, NULLPROC
, (xdrproc_t
)xdr_void
,
125 NULL
, (xdrproc_t
)xdr_void
, NULL
, to
);
126 if (rpc_stat
== RPC_SUCCESS
) {
127 *vers_out
= vers_high
;
130 while (rpc_stat
== RPC_PROGVERSMISMATCH
&& vers_high
> vers_low
) {
131 unsigned int minvers
, maxvers
;
133 clnt_geterr(clnt
, &rpcerr
);
134 minvers
= rpcerr
.re_vers
.low
;
135 maxvers
= rpcerr
.re_vers
.high
;
136 if (maxvers
< vers_high
)
140 if (minvers
> vers_low
)
142 if (vers_low
> vers_high
) {
145 CLNT_CONTROL(clnt
, CLSET_VERS
, (char *)&vers_high
);
146 rpc_stat
= clnt_call(clnt
, NULLPROC
, (xdrproc_t
)xdr_void
,
147 NULL
, (xdrproc_t
)xdr_void
,
149 if (rpc_stat
== RPC_SUCCESS
) {
150 *vers_out
= vers_high
;
154 clnt_geterr(clnt
, &rpcerr
);
157 rpc_createerr
.cf_stat
= rpc_stat
;
158 rpc_createerr
.cf_error
= rpcerr
;
164 * Top level client creation routine.
165 * Generic client creation: takes (servers name, program-number, nettype) and
166 * returns client handle. Default options are set, which the user can
167 * change using the rpc equivalent of _ioctl()'s.
169 * It tries for all the netids in that particular class of netid until
171 * XXX The error message in the case of failure will be the one
172 * pertaining to the last create error.
174 * It calls clnt_create_timed() with the default timeout.
177 clnt_create(const char *hostname
, rpcprog_t prog
, rpcvers_t vers
,
181 return (clnt_create_timed(hostname
, prog
, vers
, nettype
, NULL
));
185 * This the routine has the same definition as clnt_create(),
186 * except it takes an additional timeout parameter - a pointer to
187 * a timeval structure. A NULL value for the pointer indicates
188 * that the default timeout value should be used.
190 * This function calls clnt_tp_create_timed().
193 clnt_create_timed(const char *hostname
, rpcprog_t prog
, rpcvers_t vers
,
194 const char *netclass
, const struct timeval
*tp
)
196 struct netconfig
*nconf
;
199 enum clnt_stat save_cf_stat
= RPC_SUCCESS
;
200 struct rpc_err save_cf_error
;
201 char nettype_array
[NETIDLEN
];
202 char *nettype
= &nettype_array
[0];
204 if (netclass
== NULL
)
207 size_t len
= strlen(netclass
);
208 if (len
>= sizeof (nettype_array
)) {
209 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
212 strcpy(nettype
, netclass
);
215 if ((handle
= __rpc_setconf((char *)nettype
)) == NULL
) {
216 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
219 rpc_createerr
.cf_stat
= RPC_SUCCESS
;
220 while (clnt
== NULL
) {
221 if ((nconf
= __rpc_getconf(handle
)) == NULL
) {
222 if (rpc_createerr
.cf_stat
== RPC_SUCCESS
)
223 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
227 printf("trying netid %s\n", nconf
->nc_netid
);
229 clnt
= clnt_tp_create_timed(hostname
, prog
, vers
, nconf
, tp
);
234 * Since we didn't get a name-to-address
235 * translation failure here, we remember
236 * this particular error. The object of
237 * this is to enable us to return to the
238 * caller a more-specific error than the
239 * unhelpful ``Name to address translation
240 * failed'' which might well occur if we
241 * merely returned the last error (because
242 * the local loopbacks are typically the
243 * last ones in /etc/netconfig and the most
244 * likely to be unable to translate a host
245 * name). We also check for a more
246 * meaningful error than ``unknown host
247 * name'' for the same reasons.
249 if (rpc_createerr
.cf_stat
!= RPC_N2AXLATEFAILURE
&&
250 rpc_createerr
.cf_stat
!= RPC_UNKNOWNHOST
) {
251 save_cf_stat
= rpc_createerr
.cf_stat
;
252 save_cf_error
= rpc_createerr
.cf_error
;
257 * Attempt to return an error more specific than ``Name to address
258 * translation failed'' or ``unknown host name''
260 if ((rpc_createerr
.cf_stat
== RPC_N2AXLATEFAILURE
||
261 rpc_createerr
.cf_stat
== RPC_UNKNOWNHOST
) &&
262 (save_cf_stat
!= RPC_SUCCESS
)) {
263 rpc_createerr
.cf_stat
= save_cf_stat
;
264 rpc_createerr
.cf_error
= save_cf_error
;
266 __rpc_endconf(handle
);
271 * Generic client creation: takes (servers name, program-number, netconf) and
272 * returns client handle. Default options are set, which the user can
273 * change using the rpc equivalent of _ioctl()'s : clnt_control()
274 * It finds out the server address from rpcbind and calls clnt_tli_create().
276 * It calls clnt_tp_create_timed() with the default timeout.
279 clnt_tp_create(const char *hostname
, rpcprog_t prog
, rpcvers_t vers
,
280 const struct netconfig
*nconf
)
283 return (clnt_tp_create_timed(hostname
, prog
, vers
, nconf
, NULL
));
287 * This has the same definition as clnt_tp_create(), except it
288 * takes an additional parameter - a pointer to a timeval structure.
289 * A NULL value for the timeout pointer indicates that the default
290 * value for the timeout should be used.
293 clnt_tp_create_timed(const char *hostname
, rpcprog_t prog
, rpcvers_t vers
,
294 const struct netconfig
*nconf
, const struct timeval
*tp
)
296 struct netbuf
*svcaddr
; /* servers address */
297 CLIENT
*cl
= NULL
; /* client handle */
300 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
305 * Get the address of the server
307 if ((svcaddr
= __rpcb_findaddr_timed(prog
, vers
,
308 (struct netconfig
*)nconf
, (char *)hostname
,
309 &cl
, (struct timeval
*)tp
)) == NULL
) {
310 /* appropriate error number is set by rpcbind libraries */
314 cl
= clnt_tli_create(RPC_ANYFD
, nconf
, svcaddr
,
317 /* Reuse the CLIENT handle and change the appropriate fields */
318 if (CLNT_CONTROL(cl
, CLSET_SVC_ADDR
, (void *)svcaddr
) == TRUE
) {
319 if (cl
->cl_netid
== NULL
)
320 cl
->cl_netid
= strdup(nconf
->nc_netid
);
321 if (cl
->cl_tp
== NULL
)
322 cl
->cl_tp
= strdup(nconf
->nc_device
);
323 CLNT_CONTROL(cl
, CLSET_PROG
, (void *)&prog
);
324 CLNT_CONTROL(cl
, CLSET_VERS
, (void *)&vers
);
327 cl
= clnt_tli_create(RPC_ANYFD
, nconf
, svcaddr
,
337 * Generic client creation: returns client handle.
338 * Default options are set, which the user can
339 * change using the rpc equivalent of _ioctl()'s : clnt_control().
340 * If fd is RPC_ANYFD, it will be opened using nconf.
341 * It will be bound if not so.
342 * If sizes are 0; appropriate defaults will be chosen.
345 clnt_tli_create(int fd
, const struct netconfig
*nconf
,
346 struct netbuf
*svcaddr
, rpcprog_t prog
, rpcvers_t vers
,
347 uint sendsz
, uint recvsz
)
349 CLIENT
*cl
; /* client handle */
350 bool_t madefd
= FALSE
; /* whether fd opened here */
353 struct __rpc_sockinfo si
;
354 extern int __rpc_minfd
;
356 if (fd
== RPC_ANYFD
) {
358 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
362 fd
= __rpc_nconf2fd(nconf
);
366 if (fd
< __rpc_minfd
)
367 fd
= __rpc_raise_fd(fd
);
369 servtype
= nconf
->nc_semantics
;
370 if (!__rpc_fd2sockinfo(fd
, &si
))
372 bindresvport(fd
, NULL
);
374 if (!__rpc_fd2sockinfo(fd
, &si
))
376 servtype
= __rpc_socktype2seman(si
.si_socktype
);
377 if (servtype
== -1) {
378 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
383 if (si
.si_af
!= ((struct sockaddr
*)svcaddr
->buf
)->sa_family
) {
384 rpc_createerr
.cf_stat
= RPC_UNKNOWNHOST
; /* XXX */
390 cl
= clnt_vc_create(fd
, svcaddr
, prog
, vers
, sendsz
, recvsz
);
392 case NC_TPI_COTS_ORD
:
393 if (nconf
&& ((strcmp(nconf
->nc_protofmly
, "inet") == 0))) {
394 _setsockopt(fd
, IPPROTO_TCP
, TCP_NODELAY
, &one
,
397 cl
= clnt_vc_create(fd
, svcaddr
, prog
, vers
, sendsz
, recvsz
);
400 cl
= clnt_dg_create(fd
, svcaddr
, prog
, vers
, sendsz
, recvsz
);
407 goto err1
; /* borrow errors from clnt_dg/vc creates */
409 cl
->cl_netid
= strdup(nconf
->nc_netid
);
410 cl
->cl_tp
= strdup(nconf
->nc_device
);
416 CLNT_CONTROL(cl
, CLSET_FD_CLOSE
, NULL
);
417 /* CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL); */
423 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
424 rpc_createerr
.cf_error
.re_errno
= errno
;
431 * To avoid conflicts with the "magic" file descriptors (0, 1, and 2),
432 * we try to not use them. The __rpc_raise_fd() routine will dup
433 * a descriptor to a higher value. If we fail to do it, we continue
434 * to use the old one (and hope for the best).
439 __rpc_raise_fd(int fd
)
443 if (fd
>= __rpc_minfd
)
446 if ((nfd
= _fcntl(fd
, F_DUPFD
, __rpc_minfd
)) == -1)
449 if (_fsync(nfd
) == -1) {
454 if (_close(fd
) == -1) {
455 /* this is okay, we will syslog an error, then use the new fd */
456 syslog(LOG_ERR
, "could not close() fd %d; mem & fd leak", fd
);