usched: Implement LWP lazy migration support.
[dragonfly.git] / lib / libc / rpc / clnt_generic.c
blobcb208fd0df3a6bbcde6c60262de801c6778afc0a
1 /*
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
15 * Microsystems, Inc.
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.
43 * 2550 Garcia Avenue
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>
64 #include <stdio.h>
65 #include <errno.h>
66 #include <netdb.h>
67 #include <syslog.h>
68 #include <rpc/rpc.h>
69 #include <rpc/nettype.h>
70 #include <string.h>
71 #include <stdlib.h>
72 #include <unistd.h>
73 #include "un-namespace.h"
74 #include "rpc_com.h"
76 extern bool_t __rpc_is_local_host(const char *);
77 int __rpc_raise_fd(int);
79 #ifndef NETIDLEN
80 #define NETIDLEN 32
81 #endif
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.
93 CLIENT *
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.
108 CLIENT *
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)
113 CLIENT *clnt;
114 struct timeval to;
115 enum clnt_stat rpc_stat;
116 struct rpc_err rpcerr;
118 clnt = clnt_create_timed(hostname, prog, vers_high, nettype, tp);
119 if (clnt == NULL) {
120 return (NULL);
122 to.tv_sec = 10;
123 to.tv_usec = 0;
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;
128 return (clnt);
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)
137 vers_high = maxvers;
138 else
139 vers_high--;
140 if (minvers > vers_low)
141 vers_low = minvers;
142 if (vers_low > vers_high) {
143 goto error;
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,
148 NULL, to);
149 if (rpc_stat == RPC_SUCCESS) {
150 *vers_out = vers_high;
151 return (clnt);
154 clnt_geterr(clnt, &rpcerr);
156 error:
157 rpc_createerr.cf_stat = rpc_stat;
158 rpc_createerr.cf_error = rpcerr;
159 clnt_destroy(clnt);
160 return (NULL);
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
170 * it succeeds.
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.
176 CLIENT *
177 clnt_create(const char *hostname, rpcprog_t prog, rpcvers_t vers,
178 const char *nettype)
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().
192 CLIENT *
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;
197 CLIENT *clnt = NULL;
198 void *handle;
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)
205 nettype = NULL;
206 else {
207 size_t len = strlen(netclass);
208 if (len >= sizeof (nettype_array)) {
209 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
210 return (NULL);
212 strcpy(nettype, netclass);
215 if ((handle = __rpc_setconf((char *)nettype)) == NULL) {
216 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
217 return (NULL);
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;
224 break;
226 #ifdef CLNT_DEBUG
227 printf("trying netid %s\n", nconf->nc_netid);
228 #endif
229 clnt = clnt_tp_create_timed(hostname, prog, vers, nconf, tp);
230 if (clnt)
231 break;
232 else
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);
267 return (clnt);
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.
278 CLIENT *
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.
292 CLIENT *
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 */
299 if (nconf == NULL) {
300 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
301 return (NULL);
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 */
311 return (NULL);
313 if (cl == NULL) {
314 cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
315 prog, vers, 0, 0);
316 } else {
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);
325 } else {
326 CLNT_DESTROY(cl);
327 cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
328 prog, vers, 0, 0);
331 free(svcaddr->buf);
332 free(svcaddr);
333 return (cl);
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.
344 CLIENT *
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 */
351 long servtype;
352 int one = 1;
353 struct __rpc_sockinfo si;
354 extern int __rpc_minfd;
356 if (fd == RPC_ANYFD) {
357 if (nconf == NULL) {
358 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
359 return (NULL);
362 fd = __rpc_nconf2fd(nconf);
364 if (fd == -1)
365 goto err;
366 if (fd < __rpc_minfd)
367 fd = __rpc_raise_fd(fd);
368 madefd = TRUE;
369 servtype = nconf->nc_semantics;
370 if (!__rpc_fd2sockinfo(fd, &si))
371 goto err;
372 bindresvport(fd, NULL);
373 } else {
374 if (!__rpc_fd2sockinfo(fd, &si))
375 goto err;
376 servtype = __rpc_socktype2seman(si.si_socktype);
377 if (servtype == -1) {
378 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
379 return (NULL);
383 if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) {
384 rpc_createerr.cf_stat = RPC_UNKNOWNHOST; /* XXX */
385 goto err1;
388 switch (servtype) {
389 case NC_TPI_COTS:
390 cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
391 break;
392 case NC_TPI_COTS_ORD:
393 if (nconf && ((strcmp(nconf->nc_protofmly, "inet") == 0))) {
394 _setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one,
395 sizeof (one));
397 cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
398 break;
399 case NC_TPI_CLTS:
400 cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz);
401 break;
402 default:
403 goto err;
406 if (cl == NULL)
407 goto err1; /* borrow errors from clnt_dg/vc creates */
408 if (nconf) {
409 cl->cl_netid = strdup(nconf->nc_netid);
410 cl->cl_tp = strdup(nconf->nc_device);
411 } else {
412 cl->cl_netid = "";
413 cl->cl_tp = "";
415 if (madefd) {
416 CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
417 /* CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL); */
420 return (cl);
422 err:
423 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
424 rpc_createerr.cf_error.re_errno = errno;
425 err1: if (madefd)
426 _close(fd);
427 return (NULL);
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).
436 int __rpc_minfd = 3;
439 __rpc_raise_fd(int fd)
441 int nfd;
443 if (fd >= __rpc_minfd)
444 return (fd);
446 if ((nfd = _fcntl(fd, F_DUPFD, __rpc_minfd)) == -1)
447 return (fd);
449 if (_fsync(nfd) == -1) {
450 _close(nfd);
451 return (fd);
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);
459 return (nfd);