4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
30 * Portions of this source code were derived from Berkeley
31 * 4.3 BSD under license from the Regents of the University of
42 #include <rpc/nettype.h>
47 extern int __td_setnodelay(int);
48 extern bool_t
__rpc_is_local_host(const char *);
49 extern bool_t
__rpc_try_doors(const char *, bool_t
*);
50 extern CLIENT
*_clnt_vc_create_timed(int, struct netbuf
*, rpcprog_t
,
51 rpcvers_t
, uint_t
, uint_t
, const struct timeval
*);
53 CLIENT
*_clnt_tli_create_timed(int, const struct netconfig
*, struct netbuf
*,
54 rpcprog_t
, rpcvers_t
, uint_t
, uint_t
, const struct timeval
*);
61 * Generic client creation with version checking the value of
62 * vers_out is set to the highest server supported value
63 * vers_low <= vers_out <= vers_high AND an error results
64 * if this can not be done.
66 * It calls clnt_create_vers_timed() with a NULL value for the timeout
67 * pointer, which indicates that the default timeout should be used.
70 clnt_create_vers(const char *hostname
, const rpcprog_t prog
,
71 rpcvers_t
*vers_out
, const rpcvers_t vers_low
,
72 const rpcvers_t vers_high
, const char *nettype
)
74 return (clnt_create_vers_timed(hostname
, prog
, vers_out
, vers_low
,
75 vers_high
, nettype
, NULL
));
79 * This routine has the same definition as clnt_create_vers(),
80 * except it takes an additional timeout parameter - a pointer to
81 * a timeval structure. A NULL value for the pointer indicates
82 * that the default timeout value should be used.
85 clnt_create_vers_timed(const char *hostname
, const rpcprog_t prog
,
86 rpcvers_t
*vers_out
, const rpcvers_t vers_low
, const rpcvers_t vers_high
,
87 const char *nettype
, const struct timeval
*tp
)
91 enum clnt_stat rpc_stat
;
92 struct rpc_err rpcerr
;
93 rpcvers_t v_low
, v_high
;
95 clnt
= clnt_create_timed(hostname
, prog
, vers_high
, nettype
, tp
);
104 rpc_stat
= clnt_call(clnt
, NULLPROC
, (xdrproc_t
)xdr_void
,
105 NULL
, (xdrproc_t
)xdr_void
, NULL
, to
);
106 if (rpc_stat
== RPC_SUCCESS
) {
107 *vers_out
= vers_high
;
112 while (rpc_stat
== RPC_PROGVERSMISMATCH
&& v_high
> v_low
) {
113 unsigned int minvers
, maxvers
;
115 clnt_geterr(clnt
, &rpcerr
);
116 minvers
= rpcerr
.re_vers
.low
;
117 maxvers
= rpcerr
.re_vers
.high
;
118 if (maxvers
< v_high
)
124 if (v_low
> v_high
) {
127 CLNT_CONTROL(clnt
, CLSET_VERS
, (char *)&v_high
);
128 rpc_stat
= clnt_call(clnt
, NULLPROC
, (xdrproc_t
)xdr_void
,
129 NULL
, (xdrproc_t
)xdr_void
,
131 if (rpc_stat
== RPC_SUCCESS
) {
136 clnt_geterr(clnt
, &rpcerr
);
139 rpc_createerr
.cf_stat
= rpc_stat
;
140 rpc_createerr
.cf_error
= rpcerr
;
146 * Top level client creation routine.
147 * Generic client creation: takes (servers name, program-number, nettype) and
148 * returns client handle. Default options are set, which the user can
149 * change using the rpc equivalent of ioctl()'s.
151 * It tries for all the netids in that particular class of netid until
153 * XXX The error message in the case of failure will be the one
154 * pertaining to the last create error.
156 * It calls clnt_create_timed() with the default timeout.
159 clnt_create(const char *hostname
, const rpcprog_t prog
, const rpcvers_t vers
,
162 return (clnt_create_timed(hostname
, prog
, vers
, nettype
, NULL
));
166 * This the routine has the same definition as clnt_create(),
167 * except it takes an additional timeout parameter - a pointer to
168 * a timeval structure. A NULL value for the pointer indicates
169 * that the default timeout value should be used.
171 * This function calls clnt_tp_create_timed().
174 clnt_create_timed(const char *hostname
, const rpcprog_t prog
,
175 const rpcvers_t vers
, const char *netclass
, const struct timeval
*tp
)
177 struct netconfig
*nconf
;
180 enum clnt_stat save_cf_stat
= RPC_SUCCESS
;
181 struct rpc_err save_cf_error
;
182 char nettype_array
[NETIDLEN
];
183 char *nettype
= &nettype_array
[0];
186 if (netclass
== NULL
)
189 size_t len
= strlen(netclass
);
190 if (len
>= sizeof (nettype_array
)) {
191 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
194 (void) strcpy(nettype
, netclass
);
198 * Check to see if a rendezvous over doors should be attempted.
200 if (__rpc_try_doors(nettype
, &try_others
)) {
202 * Make sure this is the local host.
204 if (__rpc_is_local_host(hostname
)) {
205 if ((clnt
= clnt_door_create(prog
, vers
, 0)) != NULL
)
208 if (rpc_createerr
.cf_stat
== RPC_SYSTEMERROR
)
210 save_cf_stat
= rpc_createerr
.cf_stat
;
211 save_cf_error
= rpc_createerr
.cf_error
;
214 save_cf_stat
= rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
220 if ((handle
= __rpc_setconf((char *)nettype
)) == NULL
) {
221 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
224 rpc_createerr
.cf_stat
= RPC_SUCCESS
;
225 while (clnt
== NULL
) {
226 if ((nconf
= __rpc_getconf(handle
)) == NULL
) {
227 if (rpc_createerr
.cf_stat
== RPC_SUCCESS
)
228 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
231 clnt
= clnt_tp_create_timed(hostname
, prog
, vers
, nconf
, tp
);
236 * Since we didn't get a name-to-address
237 * translation failure here, we remember
238 * this particular error. The object of
239 * this is to enable us to return to the
240 * caller a more-specific error than the
241 * unhelpful ``Name to address translation
242 * failed'' which might well occur if we
243 * merely returned the last error (because
244 * the local loopbacks are typically the
245 * last ones in /etc/netconfig and the most
246 * likely to be unable to translate a host
247 * name). We also check for a more
248 * meaningful error than ``unknown host
249 * name'' for the same reasons.
251 if (rpc_createerr
.cf_stat
== RPC_SYSTEMERROR
) {
252 syslog(LOG_ERR
, "clnt_create_timed: "
257 if (rpc_createerr
.cf_stat
!= RPC_N2AXLATEFAILURE
&&
258 rpc_createerr
.cf_stat
!= RPC_UNKNOWNHOST
) {
259 save_cf_stat
= rpc_createerr
.cf_stat
;
260 save_cf_error
= rpc_createerr
.cf_error
;
266 * Attempt to return an error more specific than ``Name to address
267 * translation failed'' or ``unknown host name''
269 if ((rpc_createerr
.cf_stat
== RPC_N2AXLATEFAILURE
||
270 rpc_createerr
.cf_stat
== RPC_UNKNOWNHOST
) &&
271 (save_cf_stat
!= RPC_SUCCESS
)) {
272 rpc_createerr
.cf_stat
= save_cf_stat
;
273 rpc_createerr
.cf_error
= save_cf_error
;
275 __rpc_endconf(handle
);
280 * Create a client handle for a well known service or a specific port on
281 * host. This routine bypasses rpcbind and can be use to construct a client
282 * handle to services that are not registered with rpcbind or where the remote
283 * rpcbind is not available, e.g., the remote rpcbind port is blocked by a
284 * firewall. We construct a client handle and then ping the service's NULL
285 * proc to see that the service is really available. If the caller supplies
286 * a non zero port number, the service name is ignored and the port will be
287 * used. A non-zero port number limits the protocol family to inet or inet6.
291 clnt_create_service_timed(const char *host
, const char *service
,
292 const rpcprog_t prog
, const rpcvers_t vers
,
293 const ushort_t port
, const char *netclass
,
294 const struct timeval
*tmout
)
299 struct netconfig
*nconf
;
300 struct nd_hostserv hs
;
301 struct nd_addrlist
*raddrs
;
302 struct t_bind
*tbind
= NULL
;
304 char nettype_array
[NETIDLEN
];
305 char *nettype
= &nettype_array
[0];
306 char *hostname
, *serv
;
310 * handle const of netclass
312 if (netclass
== NULL
)
315 size_t len
= strlen(netclass
);
316 if (len
>= sizeof (nettype_array
)) {
317 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
320 (void) strcpy(nettype
, netclass
);
329 if ((handle
= __rpc_setconf(nettype
)) == NULL
) {
330 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
335 * Sinct host, and service are const
337 if (host
== NULL
|| (hostname
= strdup(host
)) == NULL
) {
338 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
339 rpc_createerr
.cf_error
.re_errno
= (host
? errno
: EINVAL
);
340 rpc_createerr
.cf_error
.re_terrno
= 0;
346 else if ((serv
= strdup(service
? service
: "")) == NULL
) {
348 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
349 rpc_createerr
.cf_error
.re_errno
= errno
;
350 rpc_createerr
.cf_error
.re_terrno
= 0;
354 hs
.h_host
= hostname
;
355 hs
.h_serv
= port
? NULL
: serv
;
358 * Check to see if a rendezvous over doors should be attempted.
360 if (__rpc_try_doors(nettype
, &try_others
)) {
362 * Make sure this is the local host.
364 if (__rpc_is_local_host(hostname
)) {
365 if ((clnt
= clnt_door_create(prog
, vers
, 0)) != NULL
)
367 else if (rpc_createerr
.cf_stat
== RPC_SYSTEMERROR
)
370 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
376 rpc_createerr
.cf_stat
= RPC_SUCCESS
;
377 while (clnt
== NULL
) {
379 if ((nconf
= __rpc_getconf(handle
)) == NULL
) {
380 if (rpc_createerr
.cf_stat
== RPC_SUCCESS
)
381 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
386 if (strcmp(nconf
->nc_protofmly
, NC_INET
) != 0 &&
387 strcmp(nconf
->nc_protofmly
, NC_INET6
) != 0)
391 if ((fd
= t_open(nconf
->nc_device
, O_RDWR
, NULL
)) < 0) {
392 rpc_createerr
.cf_stat
= RPC_TLIERROR
;
393 rpc_createerr
.cf_error
.re_errno
= errno
;
394 rpc_createerr
.cf_error
.re_terrno
= t_errno
;
400 /* LINTED pointer cast */
401 if ((tbind
= (struct t_bind
*)t_alloc(fd
, T_BIND
, T_ADDR
))
404 rpc_createerr
.cf_stat
= RPC_TLIERROR
;
405 rpc_createerr
.cf_error
.re_errno
= errno
;
406 rpc_createerr
.cf_error
.re_terrno
= t_errno
;
410 if (netdir_getbyname(nconf
, &hs
, &raddrs
) != ND_OK
) {
411 if (rpc_createerr
.cf_stat
== RPC_SUCCESS
)
412 rpc_createerr
.cf_stat
= RPC_UNKNOWNHOST
;
414 (void) t_free((char *)tbind
, T_BIND
);
418 (void) memcpy(tbind
->addr
.buf
, raddrs
->n_addrs
->buf
,
419 raddrs
->n_addrs
->len
);
420 tbind
->addr
.len
= raddrs
->n_addrs
->len
;
421 netdir_free((void *)raddrs
, ND_ADDRLIST
);
424 if (strcmp(nconf
->nc_protofmly
, NC_INET
) == 0)
425 /* LINTED pointer alignment */
426 ((struct sockaddr_in
*)
427 tbind
->addr
.buf
)->sin_port
= htons(port
);
428 else if (strcmp(nconf
->nc_protofmly
, NC_INET6
) == 0)
429 /* LINTED pointer alignment */
430 ((struct sockaddr_in6
*)
431 tbind
->addr
.buf
)->sin6_port
= htons(port
);
434 clnt
= _clnt_tli_create_timed(fd
, nconf
, &tbind
->addr
,
435 prog
, vers
, 0, 0, &to
);
439 (void) t_free((char *)tbind
, T_BIND
);
444 (void) CLNT_CONTROL(clnt
, CLSET_FD_CLOSE
, NULL
);
447 * Check if we can reach the server with this clnt handle
448 * Other clnt_create calls do a ping by contacting the
449 * remote rpcbind, here will just try to execute the service's
453 rpc_createerr
.cf_stat
= clnt_call(clnt
, NULLPROC
,
454 xdr_void
, 0, xdr_void
, 0, to
);
456 rpc_createerr
.cf_error
.re_errno
= rpc_callerr
.re_status
;
457 rpc_createerr
.cf_error
.re_terrno
= 0;
459 if (rpc_createerr
.cf_stat
!= RPC_SUCCESS
) {
463 (void) t_free((char *)tbind
, T_BIND
);
469 __rpc_endconf(handle
);
471 (void) t_free((char *)tbind
, T_BIND
);
481 * Generic client creation: takes (servers name, program-number, netconf) and
482 * returns client handle. Default options are set, which the user can
483 * change using the rpc equivalent of ioctl()'s : clnt_control()
484 * It finds out the server address from rpcbind and calls clnt_tli_create().
486 * It calls clnt_tp_create_timed() with the default timeout.
489 clnt_tp_create(const char *hostname
, const rpcprog_t prog
, const rpcvers_t vers
,
490 const struct netconfig
*nconf
)
492 return (clnt_tp_create_timed(hostname
, prog
, vers
, nconf
, NULL
));
496 * This has the same definition as clnt_tp_create(), except it
497 * takes an additional parameter - a pointer to a timeval structure.
498 * A NULL value for the timeout pointer indicates that the default
499 * value for the timeout should be used.
502 clnt_tp_create_timed(const char *hostname
, const rpcprog_t prog
,
503 const rpcvers_t vers
, const struct netconfig
*nconf
,
504 const struct timeval
*tp
)
506 struct netbuf
*svcaddr
; /* servers address */
507 CLIENT
*cl
= NULL
; /* client handle */
508 extern struct netbuf
*__rpcb_findaddr_timed(rpcprog_t
, rpcvers_t
,
509 struct netconfig
*, char *, CLIENT
**, struct timeval
*);
512 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
517 * Get the address of the server
519 if ((svcaddr
= __rpcb_findaddr_timed(prog
, vers
,
520 (struct netconfig
*)nconf
, (char *)hostname
,
521 &cl
, (struct timeval
*)tp
)) == NULL
) {
522 /* appropriate error number is set by rpcbind libraries */
526 cl
= _clnt_tli_create_timed(RPC_ANYFD
, nconf
, svcaddr
,
527 prog
, vers
, 0, 0, tp
);
529 /* Reuse the CLIENT handle and change the appropriate fields */
530 if (CLNT_CONTROL(cl
, CLSET_SVC_ADDR
, (void *)svcaddr
) == TRUE
) {
531 if (cl
->cl_netid
== NULL
) {
532 cl
->cl_netid
= strdup(nconf
->nc_netid
);
533 if (cl
->cl_netid
== NULL
) {
534 netdir_free((char *)svcaddr
, ND_ADDR
);
535 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
537 "clnt_tp_create_timed: "
542 if (cl
->cl_tp
== NULL
) {
543 cl
->cl_tp
= strdup(nconf
->nc_device
);
544 if (cl
->cl_tp
== NULL
) {
545 netdir_free((char *)svcaddr
, ND_ADDR
);
547 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
549 "clnt_tp_create_timed: "
554 (void) CLNT_CONTROL(cl
, CLSET_PROG
, (void *)&prog
);
555 (void) CLNT_CONTROL(cl
, CLSET_VERS
, (void *)&vers
);
558 cl
= _clnt_tli_create_timed(RPC_ANYFD
, nconf
, svcaddr
,
559 prog
, vers
, 0, 0, tp
);
562 netdir_free((char *)svcaddr
, ND_ADDR
);
567 * Generic client creation: returns client handle.
568 * Default options are set, which the user can
569 * change using the rpc equivalent of ioctl()'s : clnt_control().
570 * If fd is RPC_ANYFD, it will be opened using nconf.
571 * It will be bound if not so.
572 * If sizes are 0; appropriate defaults will be chosen.
575 clnt_tli_create(const int fd
, const struct netconfig
*nconf
,
576 struct netbuf
*svcaddr
, const rpcprog_t prog
, const rpcvers_t vers
,
577 const uint_t sendsz
, const uint_t recvsz
)
579 return (_clnt_tli_create_timed(fd
, nconf
, svcaddr
, prog
, vers
, sendsz
,
584 * This has the same definition as clnt_tli_create(), except it
585 * takes an additional parameter - a pointer to a timeval structure.
587 * Not a public interface. This is for clnt_create_timed,
588 * clnt_create_vers_times, clnt_tp_create_timed to pass down the
589 * timeout value to COTS creation routine.
590 * (for bug 4049792: clnt_create_timed does not time out)
593 _clnt_tli_create_timed(int fd
, const struct netconfig
*nconf
,
594 struct netbuf
*svcaddr
, rpcprog_t prog
, rpcvers_t vers
, uint_t sendsz
,
595 uint_t recvsz
, const struct timeval
*tp
)
597 CLIENT
*cl
; /* client handle */
598 struct t_info tinfo
; /* transport info */
599 bool_t madefd
; /* whether fd opened here */
603 if (fd
== RPC_ANYFD
) {
605 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
609 fd
= t_open(nconf
->nc_device
, O_RDWR
, NULL
);
614 if (t_bind(fd
, NULL
, NULL
) == -1)
616 switch (nconf
->nc_semantics
) {
623 case NC_TPI_COTS_ORD
:
624 servtype
= T_COTS_ORD
;
627 if (t_getinfo(fd
, &tinfo
) == -1)
629 servtype
= tinfo
.servtype
;
633 int state
; /* Current state of provider */
636 * Sync the opened fd.
637 * Check whether bound or not, else bind it
639 if (((state
= t_sync(fd
)) == -1) ||
640 ((state
== T_UNBND
) && (t_bind(fd
, NULL
, NULL
) == -1)) ||
641 (t_getinfo(fd
, &tinfo
) == -1))
643 servtype
= tinfo
.servtype
;
649 cl
= _clnt_vc_create_timed(fd
, svcaddr
, prog
, vers
, sendsz
,
653 if (nconf
&& ((strcmp(nconf
->nc_protofmly
, NC_INET
) == 0) ||
654 (strcmp(nconf
->nc_protofmly
, NC_INET6
) == 0))) {
655 retval
= __td_setnodelay(fd
);
659 cl
= _clnt_vc_create_timed(fd
, svcaddr
, prog
, vers
, sendsz
,
663 cl
= clnt_dg_create(fd
, svcaddr
, prog
, vers
, sendsz
, recvsz
);
670 goto err1
; /* borrow errors from clnt_dg/vc creates */
672 cl
->cl_netid
= strdup(nconf
->nc_netid
);
673 if (cl
->cl_netid
== NULL
) {
674 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
675 rpc_createerr
.cf_error
.re_errno
= errno
;
676 rpc_createerr
.cf_error
.re_terrno
= 0;
678 "clnt_tli_create: strdup failed");
681 cl
->cl_tp
= strdup(nconf
->nc_device
);
682 if (cl
->cl_tp
== NULL
) {
684 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
685 rpc_createerr
.cf_error
.re_errno
= errno
;
686 rpc_createerr
.cf_error
.re_terrno
= 0;
688 "clnt_tli_create: strdup failed");
692 struct netconfig
*nc
;
694 if ((nc
= __rpcfd_to_nconf(fd
, servtype
)) != NULL
) {
696 cl
->cl_netid
= strdup(nc
->nc_netid
);
697 if (cl
->cl_netid
== NULL
) {
698 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
699 rpc_createerr
.cf_error
.re_errno
= errno
;
700 rpc_createerr
.cf_error
.re_terrno
= 0;
708 cl
->cl_tp
= strdup(nc
->nc_device
);
709 if (cl
->cl_tp
== NULL
) {
711 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
712 rpc_createerr
.cf_error
.re_errno
= errno
;
713 rpc_createerr
.cf_error
.re_terrno
= 0;
720 freenetconfigent(nc
);
722 if (cl
->cl_netid
== NULL
)
724 if (cl
->cl_tp
== NULL
)
728 (void) CLNT_CONTROL(cl
, CLSET_FD_CLOSE
, NULL
);
729 /* (void) CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL); */
735 rpc_createerr
.cf_stat
= RPC_TLIERROR
;
736 rpc_createerr
.cf_error
.re_errno
= errno
;
737 rpc_createerr
.cf_error
.re_terrno
= t_errno
;
744 * To avoid conflicts with the "magic" file descriptors (0, 1, and 2),
745 * we try to not use them. The __rpc_raise_fd() routine will dup
746 * a descriptor to a higher value. If we fail to do it, we continue
747 * to use the old one (and hope for the best).
750 __rpc_raise_fd(int fd
)
754 if ((nfd
= fcntl(fd
, F_DUPFD
, RPC_MINFD
)) == -1)
757 if (t_sync(nfd
) == -1) {
762 if (t_close(fd
) == -1) {
763 /* this is okay, we will syslog an error, then use the new fd */
764 (void) syslog(LOG_ERR
,
765 "could not t_close() fd %d; mem & fd leak", fd
);