2 * Copyright (c) 2009, Sun Microsystems, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * - Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * - Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12 * - Neither the name of Sun Microsystems, Inc. nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
30 * Copyright (c) 1986-1996,1998 by Sun Microsystems, Inc.
31 * All rights reserved.
34 /* NFSv4.1 client for Windows
35 * Copyright © 2012 The Regents of the University of Michigan
37 * Olga Kornievskaia <aglo@umich.edu>
38 * Casey Bodley <cbodley@umich.edu>
40 * This library is free software; you can redistribute it and/or modify it
41 * under the terms of the GNU Lesser General Public License as published by
42 * the Free Software Foundation; either version 2.1 of the License, or (at
43 * your option) any later version.
45 * This library is distributed in the hope that it will be useful, but
46 * without any warranty; without even the implied warranty of merchantability
47 * or fitness for a particular purpose. See the GNU Lesser General Public
48 * License for more details.
50 * You should have received a copy of the GNU Lesser General Public License
51 * along with this library; if not, write to the Free Software Foundation,
52 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
56 //#include <pthread.h>
57 #include <reentrant.h>
58 #include <sys/types.h>
59 //#include <sys/fcntl.h>
61 //#include <sys/socket.h>
62 //#include <netinet/in.h>
63 //#include <netinet/tcp.h>
71 #include <rpc/nettype.h>
75 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
, const rpcprog_t prog
, rpcvers_t
*vers_out
,
95 const rpcvers_t vers_low
, const 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
, const rpcprog_t prog
,
110 rpcvers_t
*vers_out
, const rpcvers_t vers_low_in
, const rpcvers_t vers_high_in
,
111 const char *nettype
, const struct timeval
*tp
)
115 enum clnt_stat rpc_stat
;
116 struct rpc_err rpcerr
;
117 rpcvers_t vers_high
= vers_high_in
;
118 rpcvers_t vers_low
= vers_low_in
;
120 clnt
= clnt_create_timed(hostname
, prog
, vers_high
, nettype
, tp
);
126 rpc_stat
= clnt_call(clnt
, NULLPROC
, (xdrproc_t
)xdr_void
,
127 (char *)NULL
, (xdrproc_t
)xdr_void
, (char *)NULL
, to
);
128 if (rpc_stat
== RPC_SUCCESS
) {
129 *vers_out
= vers_high
;
132 while (rpc_stat
== RPC_PROGVERSMISMATCH
&& vers_high
> vers_low
) {
133 unsigned int minvers
, maxvers
;
135 clnt_geterr(clnt
, &rpcerr
);
136 minvers
= rpcerr
.re_vers
.low
;
137 maxvers
= rpcerr
.re_vers
.high
;
138 if (maxvers
< vers_high
)
142 if (minvers
> vers_low
)
144 if (vers_low
> vers_high
) {
147 CLNT_CONTROL(clnt
, CLSET_VERS
, (char *)&vers_high
);
148 rpc_stat
= clnt_call(clnt
, NULLPROC
, (xdrproc_t
)xdr_void
,
149 (char *)NULL
, (xdrproc_t
)xdr_void
,
151 if (rpc_stat
== RPC_SUCCESS
) {
152 *vers_out
= vers_high
;
156 clnt_geterr(clnt
, &rpcerr
);
159 rpc_createerr
.cf_stat
= rpc_stat
;
160 rpc_createerr
.cf_error
= rpcerr
;
166 * Top level client creation routine.
167 * Generic client creation: takes (servers name, program-number, nettype) and
168 * returns client handle. Default options are set, which the user can
169 * change using the rpc equivalent of _ioctl()'s.
171 * It tries for all the netids in that particular class of netid until
173 * XXX The error message in the case of failure will be the one
174 * pertaining to the last create error.
176 * It calls clnt_create_timed() with the default timeout.
179 clnt_create(const char *hostname
, const rpcprog_t prog
, const rpcvers_t vers
,
183 return (clnt_create_timed(hostname
, prog
, vers
, nettype
, NULL
));
187 * This the routine has the same definition as clnt_create(),
188 * except it takes an additional timeout parameter - a pointer to
189 * a timeval structure. A NULL value for the pointer indicates
190 * that the default timeout value should be used.
192 * This function calls clnt_tp_create_timed().
195 clnt_create_timed(const char *hostname
, const rpcprog_t prog
, const rpcvers_t vers
,
196 const char *netclass
, const struct timeval
*tp
)
198 struct netconfig
*nconf
;
201 enum clnt_stat save_cf_stat
= RPC_SUCCESS
;
202 struct rpc_err save_cf_error
;
203 char nettype_array
[NETIDLEN
];
204 char *nettype
= &nettype_array
[0];
206 if (netclass
== NULL
)
209 size_t len
= strlen(netclass
);
210 if (len
>= sizeof (nettype_array
)) {
211 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
214 strcpy(nettype
, netclass
);
217 if ((handle
= __rpc_setconf((char *)nettype
)) == NULL
) {
218 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
221 rpc_createerr
.cf_stat
= RPC_SUCCESS
;
222 while (clnt
== NULL
) {
223 if ((nconf
= __rpc_getconf(handle
)) == NULL
) {
224 if (rpc_createerr
.cf_stat
== RPC_SUCCESS
)
225 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
229 printf("trying netid %s\n", nconf
->nc_netid
);
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_N2AXLATEFAILURE
&&
252 rpc_createerr
.cf_stat
!= RPC_UNKNOWNHOST
) {
253 save_cf_stat
= rpc_createerr
.cf_stat
;
254 save_cf_error
= rpc_createerr
.cf_error
;
260 * Attempt to return an error more specific than ``Name to address
261 * translation failed'' or ``unknown host name''
263 if ((rpc_createerr
.cf_stat
== RPC_N2AXLATEFAILURE
||
264 rpc_createerr
.cf_stat
== RPC_UNKNOWNHOST
) &&
265 (save_cf_stat
!= RPC_SUCCESS
)) {
266 rpc_createerr
.cf_stat
= save_cf_stat
;
267 rpc_createerr
.cf_error
= save_cf_error
;
269 __rpc_endconf(handle
);
274 * Generic client creation: takes (servers name, program-number, netconf) and
275 * returns client handle. Default options are set, which the user can
276 * change using the rpc equivalent of _ioctl()'s : clnt_control()
277 * It finds out the server address from rpcbind and calls clnt_tli_create().
279 * It calls clnt_tp_create_timed() with the default timeout.
282 clnt_tp_create(const char *hostname
, const rpcprog_t prog
, const rpcvers_t vers
,
283 const struct netconfig
*nconf
)
285 return (clnt_tp_create_timed(hostname
, prog
, vers
, nconf
, NULL
));
289 * This has the same definition as clnt_tp_create(), except it
290 * takes an additional parameter - a pointer to a timeval structure.
291 * A NULL value for the timeout pointer indicates that the default
292 * value for the timeout should be used.
295 clnt_tp_create_timed(const char *hostname
, const rpcprog_t prog
, const rpcvers_t vers
,
296 const struct netconfig
*nconf
, const struct timeval
*tp
)
298 struct netbuf
*svcaddr
; /* servers address */
299 CLIENT
*cl
= NULL
; /* client handle */
302 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
307 * Get the address of the server
309 if ((svcaddr
= __rpcb_findaddr_timed(prog
, vers
,
310 (struct netconfig
*)nconf
, (char *)hostname
,
311 &cl
, (struct timeval
*)tp
)) == NULL
) {
312 /* appropriate error number is set by rpcbind libraries */
316 cl
= clnt_tli_create(RPC_ANYFD
, nconf
, svcaddr
,
317 prog
, vers
, 0, 0, NULL
, NULL
, NULL
);
319 /* Reuse the CLIENT handle and change the appropriate fields */
320 if (CLNT_CONTROL(cl
, CLSET_SVC_ADDR
, (void *)svcaddr
) == TRUE
) {
321 if (cl
->cl_netid
== NULL
)
322 cl
->cl_netid
= strdup(nconf
->nc_netid
);
323 if (cl
->cl_tp
== NULL
)
324 cl
->cl_tp
= strdup(nconf
->nc_device
);
325 (void) CLNT_CONTROL(cl
, CLSET_PROG
, (void *)&prog
);
326 (void) CLNT_CONTROL(cl
, CLSET_VERS
, (void *)&vers
);
329 cl
= clnt_tli_create(RPC_ANYFD
, nconf
, svcaddr
,
330 prog
, vers
, 0, 0, NULL
, NULL
, NULL
);
339 * Generic client creation: returns client handle.
340 * Default options are set, which the user can
341 * change using the rpc equivalent of _ioctl()'s : clnt_control().
342 * If fd is RPC_ANYFD, it will be opened using nconf.
343 * It will be bound if not so.
344 * If sizes are 0; appropriate defaults will be chosen.
347 clnt_tli_create(const SOCKET fd_in
, const struct netconfig
*nconf
,
348 struct netbuf
*svcaddr
, const rpcprog_t prog
, const rpcvers_t vers
,
349 const uint sendsz
, const uint recvsz
,
350 int (*callback_xdr
)(void *, void *),
351 int (*callback_function
)(void *, void *, void **),
354 CLIENT
*cl
; /* client handle */
355 bool_t madefd
= FALSE
; /* whether fd opened here */
358 struct __rpc_sockinfo si
;
359 extern int __rpc_minfd
;
362 if (fd
== RPC_ANYFD
) {
364 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
368 fd
= __rpc_nconf2fd(nconf
);
370 if (fd
== INVALID_SOCKET
)
373 if (fd
< __rpc_minfd
)
374 fd
= __rpc_raise_fd(fd
);
377 servtype
= nconf
->nc_semantics
;
378 bindresvport(fd
, NULL
);
379 if (!__rpc_fd2sockinfo(fd
, &si
))
382 if (!__rpc_fd2sockinfo(fd
, &si
))
384 servtype
= __rpc_socktype2seman(si
.si_socktype
);
385 if (servtype
== -1) {
386 rpc_createerr
.cf_stat
= RPC_UNKNOWNPROTO
;
391 if (si
.si_af
!= ((struct sockaddr
*)svcaddr
->buf
)->sa_family
) {
392 rpc_createerr
.cf_stat
= RPC_UNKNOWNHOST
; /* XXX */
398 cl
= clnt_vc_create(fd
, svcaddr
, prog
, vers
, sendsz
, recvsz
,
399 callback_xdr
, callback_function
, callback_args
);
401 case NC_TPI_COTS_ORD
:
403 ((strcmp(nconf
->nc_protofmly
, "inet") == 0) ||
404 (strcmp(nconf
->nc_protofmly
, "inet6") == 0))) {
405 setsockopt(fd
, IPPROTO_TCP
, TCP_NODELAY
, (const char *)&one
,
408 cl
= clnt_vc_create(fd
, svcaddr
, prog
, vers
, sendsz
, recvsz
,
409 callback_xdr
, callback_function
, callback_args
);
412 cl
= clnt_dg_create(fd
, svcaddr
, prog
, vers
, sendsz
, recvsz
);
419 goto err1
; /* borrow errors from clnt_dg/vc creates */
421 cl
->cl_netid
= strdup(nconf
->nc_netid
);
422 cl
->cl_tp
= strdup(nconf
->nc_device
);
428 (void) CLNT_CONTROL(cl
, CLSET_FD_CLOSE
, NULL
);
429 /* (void) CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL); */
435 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
436 rpc_createerr
.cf_error
.re_errno
= errno
;
438 (void)closesocket(fd
);
444 * To avoid conflicts with the "magic" file descriptors (0, 1, and 2),
445 * we try to not use them. The __rpc_raise_fd() routine will dup
446 * a descriptor to a higher value. If we fail to do it, we continue
447 * to use the old one (and hope for the best).
452 __rpc_raise_fd(int fd
)
456 if (fd
>= __rpc_minfd
)
459 if ((nfd
= fcntl(fd
, F_DUPFD
, __rpc_minfd
)) == -1)
462 if (fsync(nfd
) == -1) {
467 if (closesocket(fd
) == -1) {
468 /* this is okay, we will syslog an error, then use the new fd */
469 (void) syslog(LOG_ERR
,
470 "could not close() fd %d; mem & fd leak", fd
);