ReactOS 0.4.15-dev-7961-gdcf9eb0
clnt_generic.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2009, Sun Microsystems, Inc.
3 * All rights reserved.
4 *
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.
15 *
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.
27 */
28
29/*
30 * Copyright (c) 1986-1996,1998 by Sun Microsystems, Inc.
31 * All rights reserved.
32 */
33
34/* NFSv4.1 client for Windows
35 * Copyright © 2012 The Regents of the University of Michigan
36 *
37 * Olga Kornievskaia <aglo@umich.edu>
38 * Casey Bodley <cbodley@umich.edu>
39 *
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.
44 *
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.
49 *
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
53 */
54
55#include <wintirpc.h>
56//#include <pthread.h>
57#include <reentrant.h>
58#include <sys/types.h>
59//#include <sys/fcntl.h>
60#include <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 <string.h>
67#include <stdlib.h>
68//#include <netdb.h>
69//#include <syslog.h>
70#include <rpc/rpc.h>
71#include <rpc/nettype.h>
72//#include <unistd.h>
73#include "rpc_com.h"
74
75extern bool_t __rpc_is_local_host(const char *);
76#if 0 /* WINDOWS */
77int __rpc_raise_fd(int);
78#endif
79
80#ifndef NETIDLEN
81#define NETIDLEN 32
82#endif
83
84/*
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.
89 *
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.
92 */
93CLIENT *
94clnt_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)
96{
97
98 return (clnt_create_vers_timed(hostname, prog, vers_out, vers_low,
99 vers_high, nettype, NULL));
100}
101
102/*
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.
107 */
108CLIENT *
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)
112{
113 CLIENT *clnt;
114 struct timeval to;
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;
119
120 clnt = clnt_create_timed(hostname, prog, vers_high, nettype, tp);
121 if (clnt == NULL) {
122 return (NULL);
123 }
124 to.tv_sec = 10;
125 to.tv_usec = 0;
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;
130 return (clnt);
131 }
132 while (rpc_stat == RPC_PROGVERSMISMATCH && vers_high > vers_low) {
133 unsigned int minvers, maxvers;
134
135 clnt_geterr(clnt, &rpcerr);
136 minvers = rpcerr.re_vers.low;
137 maxvers = rpcerr.re_vers.high;
138 if (maxvers < vers_high)
139 vers_high = maxvers;
140 else
141 vers_high--;
142 if (minvers > vers_low)
143 vers_low = minvers;
144 if (vers_low > vers_high) {
145 goto error;
146 }
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,
150 (char *)NULL, to);
151 if (rpc_stat == RPC_SUCCESS) {
152 *vers_out = vers_high;
153 return (clnt);
154 }
155 }
156 clnt_geterr(clnt, &rpcerr);
157
158error:
159 rpc_createerr.cf_stat = rpc_stat;
160 rpc_createerr.cf_error = rpcerr;
161 clnt_destroy(clnt);
162 return (NULL);
163}
164
165/*
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.
170 *
171 * It tries for all the netids in that particular class of netid until
172 * it succeeds.
173 * XXX The error message in the case of failure will be the one
174 * pertaining to the last create error.
175 *
176 * It calls clnt_create_timed() with the default timeout.
177 */
178CLIENT *
179clnt_create(const char *hostname, const rpcprog_t prog, const rpcvers_t vers,
180 const char *nettype)
181{
182
183 return (clnt_create_timed(hostname, prog, vers, nettype, NULL));
184}
185
186/*
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.
191 *
192 * This function calls clnt_tp_create_timed().
193 */
194CLIENT *
195clnt_create_timed(const char *hostname, const rpcprog_t prog, const rpcvers_t vers,
196 const char *netclass, const struct timeval *tp)
197{
198 struct netconfig *nconf;
199 CLIENT *clnt = NULL;
200 void *handle;
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];
205
206 if (netclass == NULL)
207 nettype = NULL;
208 else {
209 size_t len = strlen(netclass);
210 if (len >= sizeof (nettype_array)) {
212 return (NULL);
213 }
214 strcpy(nettype, netclass);
215 }
216
217 if ((handle = __rpc_setconf((char *)nettype)) == NULL) {
219 return (NULL);
220 }
222 while (clnt == NULL) {
223 if ((nconf = __rpc_getconf(handle)) == NULL) {
226 break;
227 }
228#ifdef CLNT_DEBUG
229 printf("trying netid %s\n", nconf->nc_netid);
230#endif
231 clnt = clnt_tp_create_timed(hostname, prog, vers, nconf, tp);
232 if (clnt)
233 break;
234 else {
235 /*
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.
250 */
253 save_cf_stat = rpc_createerr.cf_stat;
254 save_cf_error = rpc_createerr.cf_error;
255 }
256 }
257 }
258
259 /*
260 * Attempt to return an error more specific than ``Name to address
261 * translation failed'' or ``unknown host name''
262 */
265 (save_cf_stat != RPC_SUCCESS)) {
266 rpc_createerr.cf_stat = save_cf_stat;
267 rpc_createerr.cf_error = save_cf_error;
268 }
270 return (clnt);
271}
272
273/*
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().
278 *
279 * It calls clnt_tp_create_timed() with the default timeout.
280 */
281CLIENT *
282clnt_tp_create(const char *hostname, const rpcprog_t prog, const rpcvers_t vers,
283 const struct netconfig *nconf)
284{
285 return (clnt_tp_create_timed(hostname, prog, vers, nconf, NULL));
286}
287
288/*
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.
293 */
294CLIENT *
295clnt_tp_create_timed(const char *hostname, const rpcprog_t prog, const rpcvers_t vers,
296 const struct netconfig *nconf, const struct timeval *tp)
297{
298 struct netbuf *svcaddr; /* servers address */
299 CLIENT *cl = NULL; /* client handle */
300
301 if (nconf == NULL) {
303 return (NULL);
304 }
305
306 /*
307 * Get the address of the server
308 */
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 */
313 return (NULL);
314 }
315 if (cl == NULL) {
316 cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
317 prog, vers, 0, 0, NULL, NULL, NULL);
318 } else {
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);
327 } else {
328 CLNT_DESTROY(cl);
329 cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
330 prog, vers, 0, 0, NULL, NULL, NULL);
331 }
332 }
333 free(svcaddr->buf);
334 free(svcaddr);
335 return (cl);
336}
337
338/*
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.
345 */
346CLIENT *
347clnt_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 **),
352 void *callback_args)
353{
354 CLIENT *cl; /* client handle */
355 bool_t madefd = FALSE; /* whether fd opened here */
356 long servtype;
357 BOOL one = TRUE;
358 struct __rpc_sockinfo si;
359 extern int __rpc_minfd;
360 SOCKET fd = fd_in;
361
362 if (fd == RPC_ANYFD) {
363 if (nconf == NULL) {
365 return (NULL);
366 }
367
368 fd = __rpc_nconf2fd(nconf);
369
370 if (fd == INVALID_SOCKET)
371 goto err;
372#if 0
373 if (fd < __rpc_minfd)
374 fd = __rpc_raise_fd(fd);
375#endif
376 madefd = TRUE;
377 servtype = nconf->nc_semantics;
379 if (!__rpc_fd2sockinfo(fd, &si))
380 goto err;
381 } else {
382 if (!__rpc_fd2sockinfo(fd, &si))
383 goto err;
384 servtype = __rpc_socktype2seman(si.si_socktype);
385 if (servtype == -1) {
387 return (NULL);
388 }
389 }
390
391 if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) {
393 goto err1;
394 }
395
396 switch (servtype) {
397 case NC_TPI_COTS:
398 cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz,
399 callback_xdr, callback_function, callback_args);
400 break;
401 case NC_TPI_COTS_ORD:
402 if (nconf &&
403 ((strcmp(nconf->nc_protofmly, "inet") == 0) ||
404 (strcmp(nconf->nc_protofmly, "inet6") == 0))) {
405 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char *)&one,
406 sizeof (one));
407 }
408 cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz,
409 callback_xdr, callback_function, callback_args);
410 break;
411 case NC_TPI_CLTS:
412 cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz);
413 break;
414 default:
415 goto err;
416 }
417
418 if (cl == NULL)
419 goto err1; /* borrow errors from clnt_dg/vc creates */
420 if (nconf) {
421 cl->cl_netid = strdup(nconf->nc_netid);
422 cl->cl_tp = strdup(nconf->nc_device);
423 } else {
424 cl->cl_netid = "";
425 cl->cl_tp = "";
426 }
427 if (madefd) {
429/* (void) CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL); */
430 };
431
432 return (cl);
433
434err:
436 rpc_createerr.cf_error.re_errno = errno;
437err1: if (madefd)
439 return (NULL);
440}
441
442#if 0 /* WINDOWS */
443/*
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).
448 */
449int __rpc_minfd = 3;
450
451int
452__rpc_raise_fd(int fd)
453{
454 int nfd;
455
456 if (fd >= __rpc_minfd)
457 return (fd);
458
459 if ((nfd = fcntl(fd, F_DUPFD, __rpc_minfd)) == -1)
460 return (fd);
461
462 if (fsync(nfd) == -1) {
463 closesocket(nfd);
464 return (fd);
465 }
466
467 if (closesocket(fd) == -1) {
468 /* this is okay, we will syslog an error, then use the new fd */
470 "could not close() fd %d; mem & fd leak", fd);
471 }
472
473 return (nfd);
474}
475#endif
bool_t xdr_void(void)
Definition: xdr.c:92
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
char * hostname
Definition: ftp.c:88
int bindresvport(SOCKET sd, struct sockaddr_in *sin)
Definition: bindresvport.c:53
#define NULLPROC
Definition: clnt.h:294
#define CLSET_VERS
Definition: clnt.h:256
#define clnt_destroy(rh)
Definition: clnt.h:276
#define clnt_call(rh, proc, xargs, argsp, xres, resp, secs)
Definition: clnt.h:202
#define CLSET_SVC_ADDR
Definition: clnt.h:259
#define CLSET_FD_CLOSE
Definition: clnt.h:251
#define CLSET_PROG
Definition: clnt.h:258
#define CLNT_CONTROL(cl, rq, in)
Definition: clnt.h:240
#define clnt_geterr(rh, errp)
Definition: clnt.h:220
#define CLNT_DESTROY(rh)
Definition: clnt.h:275
CLIENT * clnt_dg_create(SOCKET fd, const struct netbuf *svcaddr, rpcprog_t program, rpcvers_t version, u_int sendsz, u_int recvsz)
Definition: clnt_dg.c:154
bool_t __rpc_is_local_host(const char *)
CLIENT * clnt_create_vers(const char *hostname, const rpcprog_t prog, rpcvers_t *vers_out, const rpcvers_t vers_low, const rpcvers_t vers_high, const char *nettype)
Definition: clnt_generic.c:94
CLIENT * clnt_tli_create(const SOCKET fd_in, const struct netconfig *nconf, struct netbuf *svcaddr, const rpcprog_t prog, const rpcvers_t vers, const uint sendsz, const uint recvsz, int(*callback_xdr)(void *, void *), int(*callback_function)(void *, void *, void **), void *callback_args)
Definition: clnt_generic.c:347
CLIENT * clnt_create_vers_timed(const char *hostname, const rpcprog_t prog, rpcvers_t *vers_out, const rpcvers_t vers_low_in, const rpcvers_t vers_high_in, const char *nettype, const struct timeval *tp)
Definition: clnt_generic.c:109
CLIENT * clnt_tp_create(const char *hostname, const rpcprog_t prog, const rpcvers_t vers, const struct netconfig *nconf)
Definition: clnt_generic.c:282
CLIENT * clnt_create(const char *hostname, const rpcprog_t prog, const rpcvers_t vers, const char *nettype)
Definition: clnt_generic.c:179
CLIENT * clnt_tp_create_timed(const char *hostname, const rpcprog_t prog, const rpcvers_t vers, const struct netconfig *nconf, const struct timeval *tp)
Definition: clnt_generic.c:295
#define NETIDLEN
Definition: clnt_generic.c:81
CLIENT * clnt_create_timed(const char *hostname, const rpcprog_t prog, const rpcvers_t vers, const char *netclass, const struct timeval *tp)
Definition: clnt_generic.c:195
clnt_stat
Definition: clnt_stat.h:21
@ RPC_SUCCESS
Definition: clnt_stat.h:22
@ RPC_UNKNOWNHOST
Definition: clnt_stat.h:48
@ RPC_N2AXLATEFAILURE
Definition: clnt_stat.h:59
@ RPC_UNKNOWNPROTO
Definition: clnt_stat.h:49
@ RPC_PROGVERSMISMATCH
Definition: clnt_stat.h:40
@ RPC_SYSTEMERROR
Definition: clnt_stat.h:43
CLIENT * clnt_vc_create(int fd, const struct netbuf *raddr, const rpcprog_t prog, const rpcvers_t vers, u_int sendsz, u_int recvsz, int *cb_xdr, int *cb_fn, void *cb_args)
Definition: clnt_vc.c:324
#define free
Definition: debug_ros.c:5
#define RPC_ANYFD
Definition: svc.h:328
#define NULL
Definition: types.h:112
u_int32_t rpcprog_t
Definition: types.h:104
int32_t bool_t
Definition: types.h:101
UINT32 uint
Definition: types.h:83
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
u_int32_t rpcvers_t
Definition: types.h:105
_In_ uint64_t _In_ uint64_t _In_ uint64_t _In_opt_ traverse_ptr * tp
Definition: btrfs.c:2996
#define IPPROTO_TCP
Definition: ip.h:196
unsigned int BOOL
Definition: ntddk_ex.h:94
#define printf
Definition: freeldr.h:97
GLenum GLsizei len
Definition: glext.h:6722
char * prog
Definition: isohybrid.c:47
#define error(str)
Definition: mkdosfs.c:1605
#define closesocket
Definition: ncftp.h:477
#define NC_TPI_COTS
Definition: netconfig.h:36
#define NC_TPI_CLTS
Definition: netconfig.h:35
#define NC_TPI_COTS_ORD
Definition: netconfig.h:37
#define err(...)
void * __rpc_setconf(char *nettype) const
Definition: rpc_generic.c:305
struct netconfig * __rpc_getconf(void *vhandle)
Definition: rpc_generic.c:348
int __rpc_fd2sockinfo(SOCKET fd, struct __rpc_sockinfo *sip)
Definition: rpc_generic.c:481
void __rpc_endconf(void *vhandle)
Definition: rpc_generic.c:425
SOCKET __rpc_nconf2fd(const struct netconfig *nconf)
Definition: rpc_generic.c:562
#define errno
Definition: errno.h:18
_Check_return_ _CRTIMP char *__cdecl strdup(_In_opt_z_ const char *_Src)
static int fd
Definition: io.c:51
int one
Definition: sehframes.cpp:28
INT WSAAPI setsockopt(IN SOCKET s, IN INT level, IN INT optname, IN CONST CHAR FAR *optval, IN INT optlen)
Definition: sockctrl.c:421
struct netbuf * __rpcb_findaddr_timed(rpcprog_t, rpcvers_t, const struct netconfig *, const char *host, CLIENT **clpp, struct timeval *tp)
Definition: rpcb_clnt.c:709
int __rpc_socktype2seman(int)
Definition: rpc_generic.c:859
char * cl_tp
Definition: clnt.h:144
char * cl_netid
Definition: clnt.h:143
int si_socktype
Definition: types.h:167
ADDRESS_FAMILY si_af
Definition: types.h:165
Definition: types.h:144
void * buf
Definition: types.h:147
unsigned long nc_semantics
Definition: netconfig.h:17
char * nc_netid
Definition: netconfig.h:16
char * nc_protofmly
Definition: netconfig.h:19
char * nc_device
Definition: netconfig.h:21
struct rpc_err cf_error
Definition: clnt.h:497
enum clnt_stat cf_stat
Definition: clnt.h:496
Definition: clnt.h:95
rpcvers_t high
Definition: clnt.h:102
rpcvers_t low
Definition: clnt.h:101
unsigned long tv_sec
Definition: linux.h:1738
unsigned long tv_usec
Definition: linux.h:1739
void syslog(int pri, char *fmt,...)
Definition: syslog.c:261
#define LOG_ERR
Definition: syslog.h:48
#define TCP_NODELAY
Definition: tcpdef.h:117
#define INVALID_SOCKET
Definition: winsock.h:332
UINT_PTR SOCKET
Definition: winsock.h:47
bool_t(* xdrproc_t)(XDR *,...)
Definition: xdr.h:144