Replace all casts of NULL to something with NULL.
[dragonfly.git] / lib / libc / rpc / clnt_generic.c
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
6  *
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.
11  *
12  * The Original Code is Copyright 1998 by Sun Microsystems, Inc
13  *
14  * The Initial Developer of the Original Code is:  Sun
15  * Microsystems, Inc.
16  *
17  * All Rights Reserved.
18  *
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.
25  *
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.
29  *
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.
33  *
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.
37  *
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.
41  *
42  * Sun Microsystems, Inc.
43  * 2550 Garcia Avenue
44  * Mountain View, California  94043
45  *
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 $
52  */
53
54 /*
55  * Copyright (c) 1986-1996,1998 by Sun Microsystems, Inc.
56  * All rights reserved.
57  */
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>
65 #include <stdio.h>
66 #include <errno.h>
67 #include <netdb.h>
68 #include <syslog.h>
69 #include <rpc/rpc.h>
70 #include <rpc/nettype.h>
71 #include <string.h>
72 #include <stdlib.h>
73 #include <unistd.h>
74 #include "un-namespace.h"
75 #include "rpc_com.h"
76
77 extern bool_t   __rpc_is_local_host(const char *);
78 int             __rpc_raise_fd(int);
79
80 #ifndef NETIDLEN
81 #define NETIDLEN 32
82 #endif
83
84
85 /*
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.
90  *
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.
93  */
94 CLIENT *
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)
97 {
98
99         return (clnt_create_vers_timed(hostname, prog, vers_out, vers_low,
100                                 vers_high, nettype, NULL));
101 }
102
103 /*
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.
108  */
109 CLIENT *
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)
113 {
114         CLIENT *clnt;
115         struct timeval to;
116         enum clnt_stat rpc_stat;
117         struct rpc_err rpcerr;
118
119         clnt = clnt_create_timed(hostname, prog, vers_high, nettype, tp);
120         if (clnt == NULL) {
121                 return (NULL);
122         }
123         to.tv_sec = 10;
124         to.tv_usec = 0;
125         rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void,
126                         NULL, (xdrproc_t)xdr_void, NULL, to);
127         if (rpc_stat == RPC_SUCCESS) {
128                 *vers_out = vers_high;
129                 return (clnt);
130         }
131         while (rpc_stat == RPC_PROGVERSMISMATCH && vers_high > vers_low) {
132                 unsigned int minvers, maxvers;
133
134                 clnt_geterr(clnt, &rpcerr);
135                 minvers = rpcerr.re_vers.low;
136                 maxvers = rpcerr.re_vers.high;
137                 if (maxvers < vers_high)
138                         vers_high = maxvers;
139                 else
140                         vers_high--;
141                 if (minvers > vers_low)
142                         vers_low = minvers;
143                 if (vers_low > vers_high) {
144                         goto error;
145                 }
146                 CLNT_CONTROL(clnt, CLSET_VERS, (char *)&vers_high);
147                 rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void,
148                                 NULL, (xdrproc_t)xdr_void,
149                                 NULL, to);
150                 if (rpc_stat == RPC_SUCCESS) {
151                         *vers_out = vers_high;
152                         return (clnt);
153                 }
154         }
155         clnt_geterr(clnt, &rpcerr);
156
157 error:
158         rpc_createerr.cf_stat = rpc_stat;
159         rpc_createerr.cf_error = rpcerr;
160         clnt_destroy(clnt);
161         return (NULL);
162 }
163
164 /*
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.
169  *
170  * It tries for all the netids in that particular class of netid until
171  * it succeeds.
172  * XXX The error message in the case of failure will be the one
173  * pertaining to the last create error.
174  *
175  * It calls clnt_create_timed() with the default timeout.
176  */
177 CLIENT *
178 clnt_create(const char *hostname, rpcprog_t prog, rpcvers_t vers,
179     const char *nettype)
180 {
181
182         return (clnt_create_timed(hostname, prog, vers, nettype, NULL));
183 }
184
185 /*
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.
190  *
191  * This function calls clnt_tp_create_timed().
192  */
193 CLIENT *
194 clnt_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers,
195     const char *netclass, const struct timeval *tp)
196 {
197         struct netconfig *nconf;
198         CLIENT *clnt = NULL;
199         void *handle;
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];
204
205         if (netclass == NULL)
206                 nettype = NULL;
207         else {
208                 size_t len = strlen(netclass);
209                 if (len >= sizeof (nettype_array)) {
210                         rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
211                         return (NULL);
212                 }
213                 strcpy(nettype, netclass);
214         }
215
216         if ((handle = __rpc_setconf((char *)nettype)) == NULL) {
217                 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
218                 return (NULL);
219         }
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;
225                         break;
226                 }
227 #ifdef CLNT_DEBUG
228                 printf("trying netid %s\n", nconf->nc_netid);
229 #endif
230                 clnt = clnt_tp_create_timed(hostname, prog, vers, nconf, tp);
231                 if (clnt)
232                         break;
233                 else
234                         /*
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.
249                          */
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;
254                         }
255         }
256
257         /*
258          *      Attempt to return an error more specific than ``Name to address
259          *      translation failed'' or ``unknown host name''
260          */
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;
266         }
267         __rpc_endconf(handle);
268         return (clnt);
269 }
270
271 /*
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().
276  *
277  * It calls clnt_tp_create_timed() with the default timeout.
278  */
279 CLIENT *
280 clnt_tp_create(const char *hostname, rpcprog_t prog, rpcvers_t vers,
281     const struct netconfig *nconf)
282 {
283
284         return (clnt_tp_create_timed(hostname, prog, vers, nconf, NULL));
285 }
286
287 /*
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.
292  */
293 CLIENT *
294 clnt_tp_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers,
295     const struct netconfig *nconf, const struct timeval *tp)
296 {
297         struct netbuf *svcaddr;                 /* servers address */
298         CLIENT *cl = NULL;                      /* client handle */
299
300         if (nconf == NULL) {
301                 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
302                 return (NULL);
303         }
304
305         /*
306          * Get the address of the server
307          */
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 */
312                 return (NULL);
313         }
314         if (cl == NULL) {
315                 cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
316                                         prog, vers, 0, 0);
317         } else {
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);
326                 } else {
327                         CLNT_DESTROY(cl);
328                         cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
329                                         prog, vers, 0, 0);
330                 }
331         }
332         free(svcaddr->buf);
333         free(svcaddr);
334         return (cl);
335 }
336
337 /*
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.
344  */
345 CLIENT *
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)
349 {
350         CLIENT *cl;                     /* client handle */
351         bool_t madefd = FALSE;          /* whether fd opened here */
352         long servtype;
353         int one = 1;
354         struct __rpc_sockinfo si;
355         extern int __rpc_minfd;
356
357         if (fd == RPC_ANYFD) {
358                 if (nconf == NULL) {
359                         rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
360                         return (NULL);
361                 }
362
363                 fd = __rpc_nconf2fd(nconf);
364
365                 if (fd == -1)
366                         goto err;
367                 if (fd < __rpc_minfd)
368                         fd = __rpc_raise_fd(fd);
369                 madefd = TRUE;
370                 servtype = nconf->nc_semantics;
371                 if (!__rpc_fd2sockinfo(fd, &si))
372                         goto err;
373                 bindresvport(fd, NULL);
374         } else {
375                 if (!__rpc_fd2sockinfo(fd, &si))
376                         goto err;
377                 servtype = __rpc_socktype2seman(si.si_socktype);
378                 if (servtype == -1) {
379                         rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
380                         return (NULL);
381                 }
382         }
383
384         if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) {
385                 rpc_createerr.cf_stat = RPC_UNKNOWNHOST;        /* XXX */
386                 goto err1;
387         }
388
389         switch (servtype) {
390         case NC_TPI_COTS:
391                 cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
392                 break;
393         case NC_TPI_COTS_ORD:
394                 if (nconf && ((strcmp(nconf->nc_protofmly, "inet") == 0))) {
395                         _setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one,
396                             sizeof (one));
397                 }
398                 cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
399                 break;
400         case NC_TPI_CLTS:
401                 cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz);
402                 break;
403         default:
404                 goto err;
405         }
406
407         if (cl == NULL)
408                 goto err1; /* borrow errors from clnt_dg/vc creates */
409         if (nconf) {
410                 cl->cl_netid = strdup(nconf->nc_netid);
411                 cl->cl_tp = strdup(nconf->nc_device);
412         } else {
413                 cl->cl_netid = "";
414                 cl->cl_tp = "";
415         }
416         if (madefd) {
417                 CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
418 /*              CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL);  */
419         };
420
421         return (cl);
422
423 err:
424         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
425         rpc_createerr.cf_error.re_errno = errno;
426 err1:   if (madefd)
427                 _close(fd);
428         return (NULL);
429 }
430
431 /*
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).
436  */
437 int __rpc_minfd = 3;
438
439 int
440 __rpc_raise_fd(int fd)
441 {
442         int nfd;
443
444         if (fd >= __rpc_minfd)
445                 return (fd);
446
447         if ((nfd = _fcntl(fd, F_DUPFD, __rpc_minfd)) == -1)
448                 return (fd);
449
450         if (_fsync(nfd) == -1) {
451                 _close(nfd);
452                 return (fd);
453         }
454
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);
458         }
459
460         return (nfd);
461 }