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 * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
32 * Copyright (C) 1984, Sun Microsystems, Inc.
34 * TCP based RPC supports 'batched calls'.
35 * A sequence of calls may be batched-up in a send buffer. The rpc call
36 * return immediately to the client even though the call was not necessarily
37 * sent. The batching occurs if the results' xdr routine is NULL (0) AND
38 * the rpc timeout value is zero (see clnt.h, rpc).
40 * Clients should NOT casually batch calls that in fact return results; that is,
41 * the server side should be aware that a call is batched and not produce any
42 * return message. Batched calls that produce many result messages can
43 * deadlock (netlock) the client and the server....
45 * Now go hang yourself.
48 /* NFSv4.1 client for Windows
49 * Copyright © 2012 The Regents of the University of Michigan
51 * Olga Kornievskaia <aglo@umich.edu>
52 * Casey Bodley <cbodley@umich.edu>
54 * This library is free software; you can redistribute it and/or modify it
55 * under the terms of the GNU Lesser General Public License as published by
56 * the Free Software Foundation; either version 2.1 of the License, or (at
57 * your option) any later version.
59 * This library is distributed in the hope that it will be useful, but
60 * without any warranty; without even the implied warranty of merchantability
61 * or fitness for a particular purpose. See the GNU Lesser General Public
62 * License for more details.
64 * You should have received a copy of the GNU Lesser General Public License
65 * along with this library; if not, write to the Free Software Foundation,
66 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
70 //#include <pthread.h>
72 #include <reentrant.h>
73 #include <sys/types.h>
74 //#include <sys/poll.h>
75 //#include <sys/syslog.h>
77 //#include <sys/uio.h>
78 //#include <sys/socket.h>
79 //#include <arpa/inet.h>
94 #define MCALL_MSG_SIZE 24
96 #define CMGROUP_MAX 16
97 #define SCM_CREDS 0x03 /* process creds (struct cmsgcred) */
100 * Credentials structure, used to verify the identity of a peer
101 * process that has sent us a message. This is allocated by the
102 * peer process but filled in by the kernel. This prevents the
103 * peer from lying about its identity. (Note that cmcred_groups[0]
104 * is the effective GID.)
107 pid_t cmcred_pid
; /* PID of sending process */
108 uid_t cmcred_uid
; /* real UID of sending process */
109 uid_t cmcred_euid
; /* effective UID of sending process */
110 gid_t cmcred_gid
; /* real GID of sending process */
111 short cmcred_ngroups
; /* number or groups */
112 gid_t cmcred_groups
[CMGROUP_MAX
]; /* groups */
117 struct cmsgcred cmcred
;
120 static enum clnt_stat
clnt_vc_call(CLIENT
*, rpcproc_t
, xdrproc_t
, void *,
121 xdrproc_t
, void *, struct timeval
);
122 static void clnt_vc_geterr(CLIENT
*, struct rpc_err
*);
123 static bool_t
clnt_vc_freeres(CLIENT
*, xdrproc_t
, void *);
124 static void clnt_vc_abort(CLIENT
*);
125 static bool_t
clnt_vc_control(CLIENT
*, u_int
, void *);
126 static void clnt_vc_destroy(CLIENT
*);
127 static struct clnt_ops
*clnt_vc_ops(void);
128 static bool_t
time_not_ok(struct timeval
*);
129 static int read_vc(void *, void *, int);
130 static int write_vc(void *, void *, int);
133 int ct_fd
; /* connection's fd */
134 bool_t ct_closeit
; /* close it on destroy */
135 struct timeval ct_wait
; /* wait interval in milliseconds */
136 bool_t ct_waitset
; /* wait set by clnt_control? */
137 struct netbuf ct_addr
; /* remote addr */
138 struct rpc_err ct_error
;
140 char ct_mcallc
[MCALL_MSG_SIZE
]; /* marshalled callmsg */
143 u_int ct_mpos
; /* pos after marshal */
144 XDR ct_xdrs
; /* XDR stream */
145 struct rpc_msg reply_msg
;
146 bool_t use_stored_reply_msg
;
150 * This machinery implements per-fd locks for MT-safety. It is not
151 * sufficient to do per-CLIENT handle locks for MT-safety because a
152 * user may create more than one CLIENT handle with the same fd behind
153 * it. Therfore, we allocate an array of flags (vc_fd_locks), protected
154 * by the clnt_fd_lock mutex, and an array (vc_cv) of condition variables
155 * similarly protected. Vc_fd_lock[fd] == 1 => a call is active on some
156 * CLIENT handle created for that fd.
157 * The current implementation holds locks across the entire RPC and reply.
158 * Yes, this is silly, and as soon as this code is proven to work, this
159 * should be the first thing fixed. One step at a time.
161 static int *vc_fd_locks
;
162 extern mutex_t clnt_fd_lock
;
163 static cond_t
*vc_cv
;
165 #define release_fd_lock(fd, mask) { \
166 mutex_lock(&clnt_fd_lock); \
167 vc_fd_locks[fd] = 0; \
168 mutex_unlock(&clnt_fd_lock); \
169 thr_sigsetmask(SIG_SETMASK, &(mask), (sigset_t *) NULL); \
170 cond_signal(&vc_cv[fd]); \
173 /* XXX Need Windows signal/event stuff XXX */
174 #define release_fd_lock(fd, mask) { \
175 mutex_lock(&clnt_fd_lock); \
176 vc_fd_locks[WINSOCK_HANDLE_HASH(fd)] = 0; \
177 mutex_unlock(&clnt_fd_lock); \
179 cond_broadcast(&vc_cv[WINSOCK_HANDLE_HASH(fd)]); \
183 #define acquire_fd_lock(fd) { \
184 mutex_lock(&clnt_fd_lock); \
185 while (vc_fd_locks[WINSOCK_HANDLE_HASH(fd)] && \
186 vc_fd_locks[WINSOCK_HANDLE_HASH(fd)] != GetCurrentThreadId()) \
187 cond_wait(&vc_cv[WINSOCK_HANDLE_HASH(fd)], &clnt_fd_lock); \
188 vc_fd_locks[WINSOCK_HANDLE_HASH(fd)] = GetCurrentThreadId(); \
189 mutex_unlock(&clnt_fd_lock); \
192 static const char clnt_vc_errstr
[] = "%s : %s";
193 static const char clnt_vc_str
[] = "clnt_vc_create";
194 static const char clnt_read_vc_str
[] = "read_vc";
195 static const char __no_mem_str
[] = "out of memory";
197 /* callback thread */
198 #define CALLBACK_TIMEOUT 5000
199 #define RQCRED_SIZE 400 /* this size is excessive */
200 static unsigned int WINAPI
clnt_cb_thread(void *args
)
202 int status
= NO_ERROR
;
203 CLIENT
*cl
= (CLIENT
*)args
;
204 struct ct_data
*ct
= (struct ct_data
*) cl
->cl_private
;
205 XDR
*xdrs
= &(ct
->ct_xdrs
);
206 long saved_timeout_sec
= ct
->ct_wait
.tv_sec
;
207 long saved_timeout_usec
= ct
->ct_wait
.tv_usec
;
208 struct rpc_msg reply_msg
;
209 char cred_area
[2 * MAX_AUTH_BYTES
+ RQCRED_SIZE
];
211 fprintf(stderr
/*stdout*/, "%04x: Creating callback thread\n", GetCurrentThreadId());
215 mutex_lock(&clnt_fd_lock
);
216 while (vc_fd_locks
[WINSOCK_HANDLE_HASH(ct
->ct_fd
)] ||
217 !ct
->use_stored_reply_msg
||
218 (ct
->use_stored_reply_msg
&& ct
->reply_msg
.rm_direction
!= CALL
)) {
221 if (!cond_wait_timed(&vc_cv
[WINSOCK_HANDLE_HASH(ct
->ct_fd
)], &clnt_fd_lock
,
223 if (!vc_fd_locks
[WINSOCK_HANDLE_HASH(ct
->ct_fd
)])
226 vc_fd_locks
[WINSOCK_HANDLE_HASH(ct
->ct_fd
)] = GetCurrentThreadId();
227 mutex_unlock(&clnt_fd_lock
);
230 fprintf(stdout
, "%04x: callback received shutdown signal\n", GetCurrentThreadId());
231 release_fd_lock(ct
->ct_fd
, mask
);
235 saved_timeout_sec
= ct
->ct_wait
.tv_sec
;
236 saved_timeout_usec
= ct
->ct_wait
.tv_usec
;
237 xdrs
->x_op
= XDR_DECODE
;
238 if (ct
->use_stored_reply_msg
&& ct
->reply_msg
.rm_direction
== CALL
) {
239 goto process_rpc_call
;
240 } else if (!ct
->use_stored_reply_msg
) {
241 ct
->ct_wait
.tv_sec
= ct
->ct_wait
.tv_usec
= 0;
242 __xdrrec_setnonblock(xdrs
, 0);
243 if (!xdrrec_skiprecord(xdrs
))
245 if (!xdr_getxiddir(xdrs
, &ct
->reply_msg
)) {
248 if (ct
->reply_msg
.rm_direction
== CALL
) {
249 goto process_rpc_call
;
251 if (ct
->reply_msg
.rm_direction
== REPLY
)
252 ct
->use_stored_reply_msg
= TRUE
;
253 goto skip_setlastfrag
;
256 goto skip_setlastfrag
;
259 //call to get call headers
260 ct
->use_stored_reply_msg
= FALSE
;
261 ct
->reply_msg
.rm_call
.cb_cred
.oa_base
= cred_area
;
262 ct
->reply_msg
.rm_call
.cb_verf
.oa_base
= &(cred_area
[MAX_AUTH_BYTES
]);
263 if (!xdr_getcallbody(xdrs
, &ct
->reply_msg
)) {
264 fprintf(stderr
, "%04x: xdr_getcallbody failed\n", GetCurrentThreadId());
267 fprintf(stdout
, "%04x: callbody: rpcvers %d cb_prog %d cb_vers %d cb_proc %d\n",
268 GetCurrentThreadId(),
269 ct
->reply_msg
.rm_call
.cb_rpcvers
, ct
->reply_msg
.rm_call
.cb_prog
,
270 ct
->reply_msg
.rm_call
.cb_vers
, ct
->reply_msg
.rm_call
.cb_proc
);
271 header
.rq_prog
= ct
->reply_msg
.rm_call
.cb_prog
;
272 header
.rq_vers
= ct
->reply_msg
.rm_call
.cb_vers
;
273 header
.rq_proc
= ct
->reply_msg
.rm_call
.cb_proc
;
275 status
= (*cl
->cb_fn
)(cl
->cb_args
, &header
, &res
);
277 fprintf(stderr
, "%04x: callback function failed with %d\n", status
);
280 xdrs
->x_op
= XDR_ENCODE
;
281 __xdrrec_setblock(xdrs
);
282 reply_msg
.rm_xid
= ct
->reply_msg
.rm_xid
;
283 fprintf(stdout
, "%04x: cb: replying to xid %d\n", GetCurrentThreadId(),
284 ct
->reply_msg
.rm_xid
);
285 ct
->reply_msg
.rm_xid
= 0;
286 reply_msg
.rm_direction
= REPLY
;
287 reply_msg
.rm_reply
.rp_stat
= MSG_ACCEPTED
;
288 reply_msg
.acpted_rply
.ar_verf
= _null_auth
;
289 reply_msg
.acpted_rply
.ar_stat
= status
;
290 reply_msg
.acpted_rply
.ar_results
.where
= NULL
;
291 reply_msg
.acpted_rply
.ar_results
.proc
= (xdrproc_t
)xdr_void
;
292 xdr_replymsg(xdrs
, &reply_msg
);
294 (*cl
->cb_xdr
)(xdrs
, res
); /* encode the results */
295 xdrs
->x_op
= XDR_FREE
;
296 (*cl
->cb_xdr
)(xdrs
, res
); /* free the results */
298 if (! xdrrec_endofrecord(xdrs
, 1)) {
299 fprintf(stderr
, "%04x: failed to send REPLY\n", GetCurrentThreadId());
302 ct
->reply_msg
.rm_direction
= -1;
303 xdrrec_setlastfrag(xdrs
);
305 ct
->ct_wait
.tv_sec
= saved_timeout_sec
;
306 ct
->ct_wait
.tv_usec
= saved_timeout_usec
;
307 release_fd_lock(ct
->ct_fd
, mask
);
313 * Create a client handle for a connection.
314 * Default options are set, which the user can change using clnt_control()'s.
315 * The rpc/vc package does buffering similar to stdio, so the client
316 * must pick send and receive buffer sizes, 0 => use the default.
317 * NB: fd is copied into a private area.
318 * NB: The rpch->cl_auth is set null authentication. Caller may wish to
319 * set this something more useful.
321 * fd should be an open socket
324 clnt_vc_create(fd
, raddr
, prog
, vers
, sendsz
, recvsz
, cb_xdr
, cb_fn
, cb_args
)
325 int fd
; /* open file descriptor */
326 const struct netbuf
*raddr
; /* servers address */
327 const rpcprog_t prog
; /* program number */
328 const rpcvers_t vers
; /* version number */
329 u_int sendsz
; /* buffer recv size */
330 u_int recvsz
; /* buffer send size */
331 int (*cb_xdr
)(void *, void *); /* if not NULL, point to function to xdr CB args */
332 int (*cb_fn
)(void *, void *, void **); /* if not NULL, pointer to function to handle RPC_CALLs */
333 void *cb_args
; /* if not NULL, pointer to pass into cb_fn */
335 CLIENT
*cl
; /* client handle */
336 struct ct_data
*ct
= NULL
; /* client handle */
338 struct rpc_msg call_msg
;
339 static u_int32_t disrupt
;
344 /* XXX Need Windows signal/event stuff XXX */
346 struct sockaddr_storage ss
;
348 struct __rpc_sockinfo si
;
351 disrupt
= PtrToUlong(raddr
);
353 cl
= (CLIENT
*)mem_alloc(sizeof (*cl
));
354 ct
= (struct ct_data
*)mem_alloc(sizeof (*ct
));
355 if ((cl
== (CLIENT
*)NULL
) || (ct
== (struct ct_data
*)NULL
)) {
356 // (void) syslog(LOG_ERR, clnt_vc_errstr,
357 // clnt_vc_str, __no_mem_str);
358 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
359 rpc_createerr
.cf_error
.re_errno
= errno
;
362 ct
->ct_addr
.buf
= NULL
;
364 sigfillset(&newmask
);
365 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
367 /* XXX Need Windows signal/event stuff XXX */
369 mutex_lock(&clnt_fd_lock
);
370 if (vc_fd_locks
== (int *) NULL
) {
371 int cv_allocsz
, fd_allocsz
;
372 int dtbsize
= __rpc_dtbsize();
374 fd_allocsz
= dtbsize
* sizeof (int);
375 vc_fd_locks
= (int *) mem_alloc(fd_allocsz
);
376 if (vc_fd_locks
== (int *) NULL
) {
377 mutex_unlock(&clnt_fd_lock
);
378 // thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
381 memset(vc_fd_locks
, 0, fd_allocsz
);
383 assert(vc_cv
== (cond_t
*) NULL
);
384 cv_allocsz
= dtbsize
* sizeof (cond_t
);
385 vc_cv
= (cond_t
*) mem_alloc(cv_allocsz
);
386 if (vc_cv
== (cond_t
*) NULL
) {
387 mem_free(vc_fd_locks
, fd_allocsz
);
388 vc_fd_locks
= (int *) NULL
;
389 mutex_unlock(&clnt_fd_lock
);
390 // thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
395 for (i
= 0; i
< dtbsize
; i
++)
396 cond_init(&vc_cv
[i
], 0, (void *) 0);
399 assert(vc_cv
!= (cond_t
*) NULL
);
402 * XXX - fvdl connecting while holding a mutex?
405 if (getpeername(fd
, (struct sockaddr
*)&ss
, &slen
) == SOCKET_ERROR
) {
406 errno
= WSAGetLastError();
407 if (errno
!= WSAENOTCONN
) {
408 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
409 rpc_createerr
.cf_error
.re_errno
= errno
;
410 mutex_unlock(&clnt_fd_lock
);
411 // thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
414 if (connect(fd
, (struct sockaddr
*)raddr
->buf
, raddr
->len
) == SOCKET_ERROR
){
415 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
416 rpc_createerr
.cf_error
.re_errno
= WSAGetLastError();
417 mutex_unlock(&clnt_fd_lock
);
418 // thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
422 mutex_unlock(&clnt_fd_lock
);
423 if (!__rpc_fd2sockinfo(fd
, &si
))
425 // thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
427 ct
->ct_closeit
= FALSE
;
430 * Set up private data struct
433 ct
->ct_wait
.tv_usec
= 0;
434 ct
->ct_waitset
= FALSE
;
435 ct
->ct_addr
.buf
= malloc(raddr
->maxlen
);
436 if (ct
->ct_addr
.buf
== NULL
)
438 memcpy(ct
->ct_addr
.buf
, raddr
->buf
, raddr
->len
);
439 ct
->ct_addr
.len
= raddr
->len
;
440 ct
->ct_addr
.maxlen
= raddr
->maxlen
;
441 ct
->use_stored_reply_msg
= FALSE
;
444 * Initialize call message
446 (void)gettimeofday(&now
, NULL
);
447 call_msg
.rm_xid
= ((u_int32_t
)++disrupt
) ^ __RPC_GETXID(&now
);
448 call_msg
.rm_direction
= CALL
;
449 call_msg
.rm_call
.cb_rpcvers
= RPC_MSG_VERSION
;
450 call_msg
.rm_call
.cb_prog
= (u_int32_t
)prog
;
451 call_msg
.rm_call
.cb_vers
= (u_int32_t
)vers
;
454 * pre-serialize the static part of the call msg and stash it away
456 xdrmem_create(&(ct
->ct_xdrs
), ct
->ct_u
.ct_mcallc
, MCALL_MSG_SIZE
,
458 if (! xdr_callhdr(&(ct
->ct_xdrs
), &call_msg
)) {
459 if (ct
->ct_closeit
) {
460 (void)closesocket(fd
);
464 ct
->ct_mpos
= XDR_GETPOS(&(ct
->ct_xdrs
));
465 XDR_DESTROY(&(ct
->ct_xdrs
));
468 * Create a client handle which uses xdrrec for serialization
469 * and authnone for authentication.
471 cl
->cl_ops
= clnt_vc_ops();
473 cl
->cl_auth
= authnone_create();
474 sendsz
= __rpc_get_t_size(si
.si_af
, si
.si_proto
, (int)sendsz
);
475 recvsz
= __rpc_get_t_size(si
.si_af
, si
.si_proto
, (int)recvsz
);
476 xdrrec_create(&(ct
->ct_xdrs
), sendsz
, recvsz
,
477 cl
->cl_private
, read_vc
, write_vc
);
479 if (cb_xdr
&& cb_fn
&& cb_args
) {
482 cl
->cb_args
= cb_args
;
483 cl
->cb_thread
= (HANDLE
)_beginthreadex(NULL
,
484 0, clnt_cb_thread
, cl
, 0, NULL
);
485 if (cl
->cb_thread
== INVALID_HANDLE_VALUE
) {
486 fprintf(stderr
, "_beginthreadex failed %d\n", GetLastError());
489 fprintf(stdout
, "%04x: started the callback thread %04x\n",
490 GetCurrentThreadId(), cl
->cb_thread
);
492 cl
->cb_thread
= INVALID_HANDLE_VALUE
;
499 mem_free(ct
->ct_addr
.buf
, ct
->ct_addr
.len
);
500 mem_free(ct
, sizeof (struct ct_data
));
503 mem_free(cl
, sizeof (CLIENT
));
505 return ((CLIENT
*)NULL
);
508 static enum clnt_stat
509 clnt_vc_call(cl
, proc
, xdr_args
, args_ptr
, xdr_results
, results_ptr
, timeout
)
514 xdrproc_t xdr_results
;
516 struct timeval timeout
;
518 struct ct_data
*ct
= (struct ct_data
*) cl
->cl_private
;
519 XDR
*xdrs
= &(ct
->ct_xdrs
);
521 u_int32_t
*msg_x_id
= &ct
->ct_u
.ct_mcalli
; /* yuk */
523 static int refreshes
= 2;
525 time_t start_send
, time_now
;
527 sigset_t mask
, newmask
;
529 /* XXX Need Windows signal/event stuff XXX */
531 enum clnt_stat status
;
536 sigfillset(&newmask
);
537 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
539 /* XXX Need Windows signal/event stuff XXX */
542 acquire_fd_lock(ct
->ct_fd
);
544 if (!ct
->ct_waitset
) {
545 /* If time is not within limits, we ignore it. */
546 if (time_not_ok(&timeout
) == FALSE
)
547 ct
->ct_wait
= timeout
;
551 (xdr_results
== NULL
&& timeout
.tv_sec
== 0
552 && timeout
.tv_usec
== 0) ? FALSE
: TRUE
;
555 __xdrrec_setblock(xdrs
);
556 xdrs
->x_op
= XDR_ENCODE
;
557 ct
->ct_error
.re_status
= RPC_SUCCESS
;
558 x_id
= ntohl(--(*msg_x_id
));
560 if ((! XDR_PUTBYTES(xdrs
, ct
->ct_u
.ct_mcallc
, ct
->ct_mpos
)) ||
561 (! XDR_PUTINT32(xdrs
, (int32_t *)&proc
)) ||
562 (! AUTH_MARSHALL(cl
->cl_auth
, xdrs
, &seq
)) ||
563 (! AUTH_WRAP(cl
->cl_auth
, xdrs
, xdr_args
, args_ptr
))) {
564 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
565 ct
->ct_error
.re_status
= RPC_CANTENCODEARGS
;
566 (void)xdrrec_endofrecord(xdrs
, TRUE
);
570 if (! xdrrec_endofrecord(xdrs
, shipnow
)) {
571 ct
->ct_error
.re_status
= RPC_CANTSEND
;
575 release_fd_lock(ct
->ct_fd
, mask
);
576 return (RPC_SUCCESS
);
580 if (cl
->cb_thread
!= INVALID_HANDLE_VALUE
)
581 release_fd_lock(ct
->ct_fd
, mask
);
584 * Keep receiving until we get a valid transaction id
590 if (cl
->cb_thread
!= INVALID_HANDLE_VALUE
) {
591 mutex_lock(&clnt_fd_lock
);
592 while ((vc_fd_locks
[WINSOCK_HANDLE_HASH(ct
->ct_fd
)] &&
593 vc_fd_locks
[WINSOCK_HANDLE_HASH(ct
->ct_fd
)] != GetCurrentThreadId()) ||
594 (ct
->reply_msg
.rm_xid
&& ct
->reply_msg
.rm_xid
!= x_id
))
595 cond_wait(&vc_cv
[WINSOCK_HANDLE_HASH(ct
->ct_fd
)], &clnt_fd_lock
);
596 vc_fd_locks
[WINSOCK_HANDLE_HASH(ct
->ct_fd
)] = GetCurrentThreadId();
597 mutex_unlock(&clnt_fd_lock
);
600 __xdrrec_setnonblock(xdrs
, 0);
601 xdrs
->x_op
= XDR_DECODE
;
602 ct
->reply_msg
.acpted_rply
.ar_verf
= _null_auth
;
603 ct
->reply_msg
.acpted_rply
.ar_results
.where
= NULL
;
604 ct
->reply_msg
.acpted_rply
.ar_results
.proc
= (xdrproc_t
)xdr_void
;
605 if (!ct
->use_stored_reply_msg
) {
606 if (!xdrrec_skiprecord(xdrs
)) {
607 if (ct
->ct_error
.re_status
!= RPC_CANTRECV
) {
609 if (time_now
- start_send
>= timeout
.tv_sec
) {
610 ct
->ct_error
.re_status
= RPC_TIMEDOUT
;
614 if (cl
->cb_thread
!= INVALID_HANDLE_VALUE
)
616 release_fd_lock(ct
->ct_fd
, mask
);
622 if (!xdr_getxiddir(xdrs
, &ct
->reply_msg
)) {
623 if (ct
->ct_error
.re_status
== RPC_SUCCESS
) {
625 if (cl
->cb_thread
!= INVALID_HANDLE_VALUE
)
627 release_fd_lock(ct
->ct_fd
, mask
);
634 if (ct
->reply_msg
.rm_direction
!= REPLY
) {
635 if (cl
->cb_thread
== INVALID_HANDLE_VALUE
) {
636 ct
->reply_msg
.rm_xid
= 0;
638 ct
->use_stored_reply_msg
= TRUE
;
640 release_fd_lock(ct
->ct_fd
, mask
);
645 if (ct
->reply_msg
.rm_xid
== x_id
) {
646 ct
->use_stored_reply_msg
= FALSE
;
647 ct
->reply_msg
.rm_xid
= 0;
648 if (!xdr_getreplyunion(xdrs
, &ct
->reply_msg
))
654 if (time_now
- start_send
>= timeout
.tv_sec
) {
655 ct
->ct_error
.re_status
= RPC_TIMEDOUT
;
658 ct
->use_stored_reply_msg
= TRUE
;
660 if (cl
->cb_thread
!= INVALID_HANDLE_VALUE
)
662 release_fd_lock(ct
->ct_fd
, mask
);
670 _seterr_reply(&ct
->reply_msg
, &(ct
->ct_error
));
671 if (ct
->ct_error
.re_status
== RPC_SUCCESS
) {
672 if (! AUTH_VALIDATE(cl
->cl_auth
,
673 &ct
->reply_msg
.acpted_rply
.ar_verf
, seq
)) {
674 ct
->ct_error
.re_status
= RPC_AUTHERROR
;
675 ct
->ct_error
.re_why
= AUTH_INVALIDRESP
;
677 else if (! AUTH_UNWRAP(cl
->cl_auth
, xdrs
, xdr_results
, results_ptr
, seq
)) {
678 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
679 ct
->ct_error
.re_status
= RPC_CANTDECODERES
;
681 /* free verifier ... */
682 if (ct
->reply_msg
.acpted_rply
.ar_verf
.oa_base
!= NULL
) {
683 xdrs
->x_op
= XDR_FREE
;
684 (void)xdr_opaque_auth(xdrs
,
685 &(ct
->reply_msg
.acpted_rply
.ar_verf
));
687 } /* end successful completion */
689 if (ct
->reply_msg
.acpted_rply
.ar_verf
.oa_base
!= NULL
) {
690 xdrs
->x_op
= XDR_FREE
;
691 (void)xdr_opaque_auth(xdrs
,
692 &(ct
->reply_msg
.acpted_rply
.ar_verf
));
694 /* maybe our credentials need to be refreshed ... */
695 if (refreshes
-- > 0 && AUTH_REFRESH(cl
->cl_auth
, &ct
->reply_msg
))
697 } /* end of unsuccessful completion */
698 ct
->reply_msg
.rm_direction
= -1;
700 status
= ct
->ct_error
.re_status
;
701 release_fd_lock(ct
->ct_fd
, mask
);
706 clnt_vc_geterr(cl
, errp
)
708 struct rpc_err
*errp
;
713 assert(errp
!= NULL
);
715 ct
= (struct ct_data
*) cl
->cl_private
;
716 *errp
= ct
->ct_error
;
720 clnt_vc_freeres(cl
, xdr_res
, res_ptr
)
732 /* XXX Need Windows signal/event stuff XXX */
737 ct
= (struct ct_data
*)cl
->cl_private
;
738 xdrs
= &(ct
->ct_xdrs
);
741 sigfillset(&newmask
);
742 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
744 /* XXX Need Windows signal/event stuff XXX */
746 mutex_lock(&clnt_fd_lock
);
747 while (vc_fd_locks
[WINSOCK_HANDLE_HASH(ct
->ct_fd
)])
748 cond_wait(&vc_cv
[WINSOCK_HANDLE_HASH(ct
->ct_fd
)], &clnt_fd_lock
);
749 xdrs
->x_op
= XDR_FREE
;
750 dummy
= (*xdr_res
)(xdrs
, res_ptr
);
751 mutex_unlock(&clnt_fd_lock
);
752 // thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
753 cond_signal(&vc_cv
[WINSOCK_HANDLE_HASH(ct
->ct_fd
)]);
766 clnt_vc_control(cl
, request
, info
)
777 /* XXX Need Windows signal/event stuff XXX */
782 ct
= (struct ct_data
*)cl
->cl_private
;
785 sigfillset(&newmask
);
786 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
788 /* XXX Need Windows signal/event stuff XXX */
790 acquire_fd_lock(ct
->ct_fd
);
794 ct
->ct_closeit
= TRUE
;
795 release_fd_lock(ct
->ct_fd
, mask
);
797 case CLSET_FD_NCLOSE
:
798 ct
->ct_closeit
= FALSE
;
799 release_fd_lock(ct
->ct_fd
, mask
);
805 /* for other requests which use info */
807 release_fd_lock(ct
->ct_fd
, mask
);
812 if (time_not_ok((struct timeval
*)info
)) {
813 release_fd_lock(ct
->ct_fd
, mask
);
816 ct
->ct_wait
= *(struct timeval
*)infop
;
817 ct
->ct_waitset
= TRUE
;
820 *(struct timeval
*)infop
= ct
->ct_wait
;
822 case CLGET_SERVER_ADDR
:
823 (void) memcpy(info
, ct
->ct_addr
.buf
, (size_t)ct
->ct_addr
.len
);
826 *(int *)info
= ct
->ct_fd
;
829 /* The caller should not free this memory area */
830 *(struct netbuf
*)info
= ct
->ct_addr
;
832 case CLSET_SVC_ADDR
: /* set to new address */
833 release_fd_lock(ct
->ct_fd
, mask
);
837 * use the knowledge that xid is the
838 * first element in the call structure
839 * This will get the xid of the PREVIOUS call
842 ntohl(*(u_int32_t
*)(void *)&ct
->ct_u
.ct_mcalli
);
845 /* This will set the xid of the NEXT call */
846 *(u_int32_t
*)(void *)&ct
->ct_u
.ct_mcalli
=
847 htonl(*((u_int32_t
*)info
) + 1);
848 /* increment by 1 as clnt_vc_call() decrements once */
852 * This RELIES on the information that, in the call body,
853 * the version number field is the fifth field from the
854 * begining of the RPC header. MUST be changed if the
855 * call_struct is changed
858 ntohl(*(u_int32_t
*)(void *)(ct
->ct_u
.ct_mcallc
+
859 4 * BYTES_PER_XDR_UNIT
));
863 *(u_int32_t
*)(void *)(ct
->ct_u
.ct_mcallc
+
864 4 * BYTES_PER_XDR_UNIT
) =
865 htonl(*(u_int32_t
*)info
);
870 * This RELIES on the information that, in the call body,
871 * the program number field is the fourth field from the
872 * begining of the RPC header. MUST be changed if the
873 * call_struct is changed
876 ntohl(*(u_int32_t
*)(void *)(ct
->ct_u
.ct_mcallc
+
877 3 * BYTES_PER_XDR_UNIT
));
881 *(u_int32_t
*)(void *)(ct
->ct_u
.ct_mcallc
+
882 3 * BYTES_PER_XDR_UNIT
) =
883 htonl(*(u_int32_t
*)info
);
887 release_fd_lock(ct
->ct_fd
, mask
);
890 release_fd_lock(ct
->ct_fd
, mask
);
899 struct ct_data
*ct
= (struct ct_data
*) cl
->cl_private
;
900 int ct_fd
= ct
->ct_fd
;
905 /* XXX Need Windows signal/event stuff XXX */
910 ct
= (struct ct_data
*) cl
->cl_private
;
913 sigfillset(&newmask
);
914 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
916 /* XXX Need Windows signal/event stuff XXX */
918 mutex_lock(&clnt_fd_lock
);
919 while (vc_fd_locks
[WINSOCK_HANDLE_HASH(ct_fd
)])
920 cond_wait(&vc_cv
[WINSOCK_HANDLE_HASH(ct_fd
)], &clnt_fd_lock
);
922 if (cl
->cb_thread
!= INVALID_HANDLE_VALUE
) {
924 fprintf(stdout
, "%04x: sending shutdown to callback thread %04x\n",
925 GetCurrentThreadId(), cl
->cb_thread
);
927 mutex_unlock(&clnt_fd_lock
);
928 cond_signal(&vc_cv
[WINSOCK_HANDLE_HASH(ct_fd
)]);
929 status
= WaitForSingleObject(cl
->cb_thread
, INFINITE
);
930 fprintf(stdout
, "%04x: terminated callback thread\n", GetCurrentThreadId());
931 mutex_lock(&clnt_fd_lock
);
932 while (vc_fd_locks
[WINSOCK_HANDLE_HASH(ct_fd
)])
933 cond_wait(&vc_cv
[WINSOCK_HANDLE_HASH(ct_fd
)], &clnt_fd_lock
);
936 if (ct
->ct_closeit
&& ct
->ct_fd
!= -1) {
937 (void)closesocket(ct
->ct_fd
);
939 XDR_DESTROY(&(ct
->ct_xdrs
));
941 free(ct
->ct_addr
.buf
);
942 mem_free(ct
, sizeof(struct ct_data
));
943 if (cl
->cl_netid
&& cl
->cl_netid
[0])
944 mem_free(cl
->cl_netid
, strlen(cl
->cl_netid
) +1);
945 if (cl
->cl_tp
&& cl
->cl_tp
[0])
946 mem_free(cl
->cl_tp
, strlen(cl
->cl_tp
) +1);
947 mem_free(cl
, sizeof(CLIENT
));
948 mutex_unlock(&clnt_fd_lock
);
949 // thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
950 cond_signal(&vc_cv
[WINSOCK_HANDLE_HASH(ct_fd
)]);
954 * Interface between xdr serializer and tcp connection.
955 * Behaves like the system calls, read & write, but keeps some error state
956 * around for the rpc level.
959 read_vc(ctp
, buf
, len
)
968 struct ct_data
*ct
= (struct ct_data
*)ctp
;
970 int milliseconds
= ct
->ct_wait
.tv_usec
;
978 switch (poll(&fd
, 1, milliseconds
)) {
980 /* ReactOS: use select instead of poll */
982 struct timeval timeout
;
985 FD_SET(ct
->ct_fd
, &infd
);
988 timeout
.tv_usec
= milliseconds
* 1000;
990 switch (select(0, &infd
, NULL
, NULL
, &timeout
)) {
994 ct
->ct_error
.re_status
= RPC_TIMEDOUT
;
998 errno
= WSAGetLastError();
999 if (errno
== WSAEINTR
)
1001 ct
->ct_error
.re_status
= RPC_CANTRECV
;
1002 ct
->ct_error
.re_errno
= errno
;
1008 len
= recv(ct
->ct_fd
, buf
, (size_t)len
, 0);
1009 errno
= WSAGetLastError();
1014 ct
->ct_error
.re_errno
= WSAECONNRESET
;
1015 ct
->ct_error
.re_status
= RPC_CANTRECV
;
1016 len
= -1; /* it's really an error */
1020 ct
->ct_error
.re_errno
= errno
;
1021 ct
->ct_error
.re_status
= RPC_CANTRECV
;
1029 write_vc(ctp
, buf
, len
)
1031 write_vc(ctp
, ptr
, len
)
1041 struct ct_data
*ct
= (struct ct_data
*)ctp
;
1047 for (cnt
= len
; cnt
> 0; cnt
-= i
, buf
+= i
) {
1048 if ((i
= send(ct
->ct_fd
, buf
, (size_t)cnt
, 0)) == SOCKET_ERROR
) {
1049 ct
->ct_error
.re_errno
= WSAGetLastError();
1050 ct
->ct_error
.re_status
= RPC_CANTSEND
;
1057 static struct clnt_ops
*
1060 static struct clnt_ops ops
;
1061 extern mutex_t ops_lock
;
1063 sigset_t mask
, newmask
;
1065 /* VARIABLES PROTECTED BY ops_lock: ops */
1067 sigfillset(&newmask
);
1068 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
1070 /* XXX Need Windows signal/event stuff XXX */
1072 mutex_lock(&ops_lock
);
1073 if (ops
.cl_call
== NULL
) {
1074 ops
.cl_call
= clnt_vc_call
;
1075 ops
.cl_abort
= clnt_vc_abort
;
1076 ops
.cl_geterr
= clnt_vc_geterr
;
1077 ops
.cl_freeres
= clnt_vc_freeres
;
1078 ops
.cl_destroy
= clnt_vc_destroy
;
1079 ops
.cl_control
= clnt_vc_control
;
1081 mutex_unlock(&ops_lock
);
1082 // thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
1087 * Make sure that the time is not garbage. -1 value is disallowed.
1088 * Note this is different from time_not_ok in clnt_dg.c
1094 return (t
->tv_sec
<= -1 || t
->tv_sec
> 100000000 ||
1095 t
->tv_usec
<= -1 || t
->tv_usec
> 1000000);