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.
29 * Copyright (c) 1986-1991 by Sun Microsystems Inc.
33 * Implements a connectionless client side RPC.
36 //#include <pthread.h>
37 #include <reentrant.h>
38 #include <sys/types.h>
39 //#include <sys/socket.h>
41 //#include <sys/poll.h>
43 //#include <sys/time.h>
45 //#include <sys/ioctl.h>
47 //#include <arpa/inet.h>
59 #include <asm/types.h>
60 #include <linux/errqueue.h>
65 #define MAX_DEFAULT_FDS 20000
67 static struct clnt_ops
*clnt_dg_ops(void);
68 static bool_t
time_not_ok(struct timeval
*);
69 static enum clnt_stat
clnt_dg_call(CLIENT
*, rpcproc_t
, xdrproc_t
, void *,
70 xdrproc_t
, void *, struct timeval
);
71 static void clnt_dg_geterr(CLIENT
*, struct rpc_err
*);
72 static bool_t
clnt_dg_freeres(CLIENT
*, xdrproc_t
, void *);
73 static void clnt_dg_abort(CLIENT
*);
74 static bool_t
clnt_dg_control(CLIENT
*, u_int
, void *);
75 static void clnt_dg_destroy(CLIENT
*);
79 * This machinery implements per-fd locks for MT-safety. It is not
80 * sufficient to do per-CLIENT handle locks for MT-safety because a
81 * user may create more than one CLIENT handle with the same fd behind
82 * it. Therfore, we allocate an array of flags (dg_fd_locks), protected
83 * by the clnt_fd_lock mutex, and an array (dg_cv) of condition variables
84 * similarly protected. Dg_fd_lock[fd] == 1 => a call is activte on some
85 * CLIENT handle created for that fd.
86 * The current implementation holds locks across the entire RPC and reply,
87 * including retransmissions. Yes, this is silly, and as soon as this
88 * code is proven to work, this should be the first thing fixed. One step
91 static int *dg_fd_locks
;
92 extern mutex_t clnt_fd_lock
;
95 #define release_fd_lock(fd, mask) { \
96 mutex_lock(&clnt_fd_lock); \
97 dg_fd_locks[fd] = 0; \
98 mutex_unlock(&clnt_fd_lock); \
99 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); \
100 cond_signal(&dg_cv[fd]); \
103 /* XXX Needs Windows signal/event stuff XXX */
104 #define release_fd_lock(fd, mask) { \
105 mutex_lock(&clnt_fd_lock); \
106 dg_fd_locks[WINSOCK_HANDLE_HASH(fd)] = 0; \
107 mutex_unlock(&clnt_fd_lock); \
109 cond_signal(&dg_cv[WINSOCK_HANDLE_HASH(fd)]); \
113 static const char mem_err_clnt_dg
[] = "clnt_dg_create: out of memory";
115 /* VARIABLES PROTECTED BY clnt_fd_lock: dg_fd_locks, dg_cv */
118 * Private data kept per client handle
121 SOCKET cu_fd
; /* connections fd */
122 bool_t cu_closeit
; /* opened by library */
123 struct sockaddr_storage cu_raddr
; /* remote address */
125 struct timeval cu_wait
; /* retransmit interval */
126 struct timeval cu_total
; /* total time for the call */
127 struct rpc_err cu_error
;
130 u_int cu_sendsz
; /* send size */
132 u_int cu_recvsz
; /* recv size */
134 int cu_connect
; /* Use connect(). */
135 int cu_connected
; /* Have done connect(). */
140 * Connection less client creation returns with client handle parameters.
141 * Default options are set, which the user can change using clnt_control().
142 * fd should be open and bound.
143 * NB: The rpch->cl_auth is initialized to null authentication.
144 * Caller may wish to set this something more useful.
146 * sendsz and recvsz are the maximum allowable packet sizes that can be
147 * sent and received. Normally they are the same, but they can be
148 * changed to improve the program efficiency and buffer allocation.
149 * If they are 0, use the transport default.
151 * If svcaddr is NULL, returns NULL.
154 clnt_dg_create(fd
, svcaddr
, program
, version
, sendsz
, recvsz
)
155 SOCKET fd
; /* open file descriptor */
156 const struct netbuf
*svcaddr
; /* servers address */
157 rpcprog_t program
; /* program number */
158 rpcvers_t version
; /* version number */
159 u_int sendsz
; /* buffer recv size */
160 u_int recvsz
; /* buffer send size */
162 CLIENT
*cl
= NULL
; /* client handle */
163 struct cu_data
*cu
= NULL
; /* private data */
165 struct rpc_msg call_msg
;
170 /* XXX Need Windows signal/event stuff here XXX */
172 struct __rpc_sockinfo si
;
176 sigfillset(&newmask
);
177 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
179 /* XXX Need Windows signal/event stuff here XXX */
181 mutex_lock(&clnt_fd_lock
);
182 if (dg_fd_locks
== (int *) NULL
) {
185 int dtbsize
= __rpc_dtbsize();
187 fd_allocsz
= dtbsize
* sizeof (int);
188 dg_fd_locks
= (int *) mem_alloc(fd_allocsz
);
189 if (dg_fd_locks
== (int *) NULL
) {
190 mutex_unlock(&clnt_fd_lock
);
191 // thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
194 memset(dg_fd_locks
, 0, fd_allocsz
);
196 cv_allocsz
= dtbsize
* sizeof (cond_t
);
197 dg_cv
= (cond_t
*) mem_alloc(cv_allocsz
);
198 if (dg_cv
== (cond_t
*) NULL
) {
199 mem_free(dg_fd_locks
, fd_allocsz
);
200 dg_fd_locks
= (int *) NULL
;
201 mutex_unlock(&clnt_fd_lock
);
202 // thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
207 for (i
= 0; i
< dtbsize
; i
++)
208 cond_init(&dg_cv
[i
], 0, (void *) 0);
212 mutex_unlock(&clnt_fd_lock
);
213 // thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
215 if (svcaddr
== NULL
) {
216 rpc_createerr
.cf_stat
= RPC_UNKNOWNADDR
;
220 if (!__rpc_fd2sockinfo(fd
, &si
)) {
221 rpc_createerr
.cf_stat
= RPC_TLIERROR
;
222 rpc_createerr
.cf_error
.re_errno
= 0;
226 * Find the receive and the send size
228 sendsz
= __rpc_get_t_size(si
.si_af
, si
.si_proto
, (int)sendsz
);
229 recvsz
= __rpc_get_t_size(si
.si_af
, si
.si_proto
, (int)recvsz
);
230 if ((sendsz
== 0) || (recvsz
== 0)) {
231 rpc_createerr
.cf_stat
= RPC_TLIERROR
; /* XXX */
232 rpc_createerr
.cf_error
.re_errno
= 0;
236 if ((cl
= mem_alloc(sizeof (CLIENT
))) == NULL
)
239 * Should be multiple of 4 for XDR.
241 sendsz
= ((sendsz
+ 3) / 4) * 4;
242 recvsz
= ((recvsz
+ 3) / 4) * 4;
243 cu
= mem_alloc(sizeof (*cu
) + sendsz
+ recvsz
);
246 (void) memcpy(&cu
->cu_raddr
, svcaddr
->buf
, (size_t)svcaddr
->len
);
247 cu
->cu_rlen
= svcaddr
->len
;
248 cu
->cu_outbuf
= &cu
->cu_inbuf
[recvsz
];
249 /* Other values can also be set through clnt_control() */
250 cu
->cu_wait
.tv_sec
= 15; /* heuristically chosen */
251 cu
->cu_wait
.tv_usec
= 0;
252 cu
->cu_total
.tv_sec
= -1;
253 cu
->cu_total
.tv_usec
= -1;
254 cu
->cu_sendsz
= sendsz
;
255 cu
->cu_recvsz
= recvsz
;
256 cu
->cu_async
= FALSE
;
257 cu
->cu_connect
= FALSE
;
258 cu
->cu_connected
= FALSE
;
259 (void) gettimeofday(&now
, NULL
);
260 // call_msg.rm_xid = __RPC_GETXID(&now);
262 call_msg
.rm_xid
= ((u_int32_t
)_getpid() ^ (u_int32_t
)(&now
)->tv_sec
^ (u_int32_t
)(&now
)->tv_usec
);
263 call_msg
.rm_call
.cb_prog
= program
;
264 call_msg
.rm_call
.cb_vers
= version
;
265 xdrmem_create(&(cu
->cu_outxdrs
), cu
->cu_outbuf
, sendsz
, XDR_ENCODE
);
266 if (! xdr_callhdr(&(cu
->cu_outxdrs
), &call_msg
)) {
267 rpc_createerr
.cf_stat
= RPC_CANTENCODEARGS
; /* XXX */
268 rpc_createerr
.cf_error
.re_errno
= 0;
271 cu
->cu_xdrpos
= XDR_GETPOS(&(cu
->cu_outxdrs
));
273 /* XXX fvdl - do we still want this? */
275 (void)bindresvport_sa(fd
, (struct sockaddr
*)svcaddr
->buf
);
280 setsockopt(fd
, SOL_IP
, IP_RECVERR
, &on
, sizeof(on
));
283 ioctlsocket(fd
, FIONBIO
, &one
);
285 * By default, closeit is always FALSE. It is users responsibility
286 * to do a close on it, else the user may use clnt_control
287 * to let clnt_destroy do it for him/her.
289 cu
->cu_closeit
= FALSE
;
291 cl
->cl_ops
= clnt_dg_ops();
292 cl
->cl_private
= (caddr_t
)(void *)cu
;
293 cl
->cl_auth
= authnone_create();
299 //warnx(mem_err_clnt_dg);
300 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
301 rpc_createerr
.cf_error
.re_errno
= errno
;
304 mem_free(cl
, sizeof (CLIENT
));
306 mem_free(cu
, sizeof (*cu
) + sendsz
+ recvsz
);
311 static enum clnt_stat
312 clnt_dg_call(cl
, proc
, xargs
, argsp
, xresults
, resultsp
, utimeout
)
313 CLIENT
*cl
; /* client handle */
314 rpcproc_t proc
; /* procedure number */
315 xdrproc_t xargs
; /* xdr routine for args */
316 void *argsp
; /* pointer to args */
317 xdrproc_t xresults
; /* xdr routine for results */
318 void *resultsp
; /* pointer to results */
319 struct timeval utimeout
; /* seconds to wait before giving up */
321 struct cu_data
*cu
= (struct cu_data
*)cl
->cl_private
;
324 struct rpc_msg reply_msg
;
327 int nrefreshes
= 2; /* number of times to refresh cred */
328 struct timeval timeout
;
330 int total_time
, nextsend_time
, tv
=0;
336 /* XXX Need Windows signal/event stuff here XXX */
338 socklen_t inlen
, salen
;
341 u_int32_t xid
, inval
, outval
;
345 sigfillset(&newmask
);
346 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
348 /* XXX Need Windows signal/event stuff here XXX */
350 mutex_lock(&clnt_fd_lock
);
351 while (dg_fd_locks
[WINSOCK_HANDLE_HASH(cu
->cu_fd
)])
352 cond_wait(&dg_cv
[WINSOCK_HANDLE_HASH(cu
->cu_fd
)], &clnt_fd_lock
);
354 dg_fd_locks
[WINSOCK_HANDLE_HASH(cu
->cu_fd
)] = rpc_lock_value
;
355 mutex_unlock(&clnt_fd_lock
);
356 if (cu
->cu_total
.tv_usec
== -1) {
357 timeout
= utimeout
; /* use supplied timeout */
359 timeout
= cu
->cu_total
; /* use default timeout */
361 total_time
= timeout
.tv_sec
* 1000 + timeout
.tv_usec
/ 1000;
362 nextsend_time
= cu
->cu_wait
.tv_sec
* 1000 + cu
->cu_wait
.tv_usec
/ 1000;
364 if (cu
->cu_connect
&& !cu
->cu_connected
) {
365 if (connect(cu
->cu_fd
, (struct sockaddr
*)&cu
->cu_raddr
,
367 cu
->cu_error
.re_errno
= errno
;
368 cu
->cu_error
.re_status
= RPC_CANTSEND
;
371 cu
->cu_connected
= 1;
373 if (cu
->cu_connected
) {
377 sa
= (struct sockaddr
*)&cu
->cu_raddr
;
381 /* Clean up in case the last call ended in a longjmp(3) call. */
383 xdrs
= &(cu
->cu_outxdrs
);
384 if (cu
->cu_async
== TRUE
&& xargs
== NULL
)
386 xdrs
->x_op
= XDR_ENCODE
;
387 XDR_SETPOS(xdrs
, cu
->cu_xdrpos
);
389 * the transaction is the first thing in the out buffer
390 * XXX Yes, and it's in network byte order, so we should to
391 * be careful when we increment it, shouldn't we.
393 xid
= ntohl(*(u_int32_t
*)(void *)(cu
->cu_outbuf
));
395 *(u_int32_t
*)(void *)(cu
->cu_outbuf
) = htonl(xid
);
397 if ((! XDR_PUTINT32(xdrs
, (int32_t *)&proc
)) ||
398 (! AUTH_MARSHALL(cl
->cl_auth
, xdrs
, NULL
)) ||
399 (! (*xargs
)(xdrs
, argsp
))) {
400 cu
->cu_error
.re_status
= RPC_CANTENCODEARGS
;
403 outlen
= (size_t)XDR_GETPOS(xdrs
);
406 * Hack to provide rpc-based message passing
408 if (timeout
.tv_sec
== 0 && timeout
.tv_usec
== 0) {
409 cu
->cu_error
.re_status
= RPC_TIMEDOUT
;
414 if (total_time
<= 0) {
415 cu
->cu_error
.re_status
= RPC_TIMEDOUT
;
418 nextsend_time
= cu
->cu_wait
.tv_sec
* 1000 + cu
->cu_wait
.tv_usec
/ 1000;
419 if (sendto(cu
->cu_fd
, cu
->cu_outbuf
, (int)outlen
, 0, sa
, salen
) != outlen
) {
420 cu
->cu_error
.re_errno
= errno
;
421 cu
->cu_error
.re_status
= RPC_CANTSEND
;
428 * sub-optimal code appears here because we have
429 * some clock time to spare while the packets are in flight.
430 * (We assume that this is actually only executed once.)
432 reply_msg
.acpted_rply
.ar_verf
= _null_auth
;
433 reply_msg
.acpted_rply
.ar_results
.where
= resultsp
;
434 reply_msg
.acpted_rply
.ar_results
.proc
= xresults
;
439 while (total_time
> 0) {
440 tv
= total_time
< nextsend_time
? total_time
: nextsend_time
;
442 switch (poll(&fd
, 1, tv
)) {
445 #error Not supported!
447 /* ReactOS: use select instead of poll */
449 struct timeval timeout
;
452 FD_SET(cu
->cu_fd
, &infd
);
455 timeout
.tv_usec
= tv
* 1000;
457 switch (select(0, &infd
, NULL
, NULL
, &timeout
)) {
462 // XXX CHECK THIS FOR WINDOWS!
466 cu
->cu_error
.re_status
= RPC_CANTRECV
;
467 cu
->cu_error
.re_errno
= errno
;
473 if (fd
.revents
& POLLERR
)
476 struct cmsghdr
*cmsg
;
477 struct sock_extended_err
*e
;
478 struct sockaddr_in err_addr
;
479 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&cu
->cu_raddr
;
481 char *cbuf
= (char *) alloca (outlen
+ 256);
484 iov
.iov_base
= cbuf
+ 256;
485 iov
.iov_len
= outlen
;
486 msg
.msg_name
= (void *) &err_addr
;
487 msg
.msg_namelen
= sizeof (err_addr
);
491 msg
.msg_control
= cbuf
;
492 msg
.msg_controllen
= 256;
493 ret
= recvmsg (cu
->cu_fd
, &msg
, MSG_ERRQUEUE
);
495 && memcmp (cbuf
+ 256, cu
->cu_outbuf
, ret
) == 0
496 && (msg
.msg_flags
& MSG_ERRQUEUE
)
497 && ((msg
.msg_namelen
== 0
499 || (msg
.msg_namelen
== sizeof (err_addr
)
500 && err_addr
.sin_family
== AF_INET
501 && memcmp (&err_addr
.sin_addr
, &sin
->sin_addr
,
502 sizeof (err_addr
.sin_addr
)) == 0
503 && err_addr
.sin_port
== sin
->sin_port
)))
504 for (cmsg
= CMSG_FIRSTHDR (&msg
); cmsg
;
505 cmsg
= CMSG_NXTHDR (&msg
, cmsg
))
506 if (cmsg
->cmsg_level
== SOL_IP
&& cmsg
->cmsg_type
== IP_RECVERR
)
508 e
= (struct sock_extended_err
*) CMSG_DATA(cmsg
);
509 cu
->cu_error
.re_errno
= e
->ee_errno
;
510 release_fd_lock(cu
->cu_fd
, mask
);
511 return (cu
->cu_error
.re_status
= RPC_CANTRECV
);
516 /* We have some data now */
518 recvlen
= recvfrom(cu
->cu_fd
, cu
->cu_inbuf
,
519 cu
->cu_recvsz
, 0, NULL
, NULL
);
520 errno
= WSAGetLastError();
521 } while (recvlen
== SOCKET_ERROR
&& errno
== WSAEINTR
);
522 if (recvlen
== SOCKET_ERROR
&& errno
!= WSAEWOULDBLOCK
) {
523 cu
->cu_error
.re_errno
= errno
;
524 cu
->cu_error
.re_status
= RPC_CANTRECV
;
528 if (recvlen
< sizeof(u_int32_t
)) {
533 if (cu
->cu_async
== TRUE
)
534 inlen
= (socklen_t
)recvlen
;
536 memcpy(&inval
, cu
->cu_inbuf
, sizeof(u_int32_t
));
537 memcpy(&outval
, cu
->cu_outbuf
, sizeof(u_int32_t
));
538 if (inval
!= outval
) {
542 inlen
= (socklen_t
)recvlen
;
546 * now decode and validate the response
549 xdrmem_create(&reply_xdrs
, cu
->cu_inbuf
, (u_int
)recvlen
, XDR_DECODE
);
550 ok
= xdr_replymsg(&reply_xdrs
, &reply_msg
);
551 /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */
553 if ((reply_msg
.rm_reply
.rp_stat
== MSG_ACCEPTED
) &&
554 (reply_msg
.acpted_rply
.ar_stat
== SUCCESS
))
555 cu
->cu_error
.re_status
= RPC_SUCCESS
;
557 _seterr_reply(&reply_msg
, &(cu
->cu_error
));
559 if (cu
->cu_error
.re_status
== RPC_SUCCESS
) {
560 if (! AUTH_VALIDATE(cl
->cl_auth
,
561 &reply_msg
.acpted_rply
.ar_verf
, 0)) {
562 cu
->cu_error
.re_status
= RPC_AUTHERROR
;
563 cu
->cu_error
.re_why
= AUTH_INVALIDRESP
;
565 if (reply_msg
.acpted_rply
.ar_verf
.oa_base
!= NULL
) {
566 xdrs
->x_op
= XDR_FREE
;
567 (void) xdr_opaque_auth(xdrs
,
568 &(reply_msg
.acpted_rply
.ar_verf
));
570 } /* end successful completion */
572 * If unsuccesful AND error is an authentication error
573 * then refresh credentials and try again, else break
575 else if (cu
->cu_error
.re_status
== RPC_AUTHERROR
)
576 /* maybe our credentials need to be refreshed ... */
577 if (nrefreshes
> 0 &&
578 AUTH_REFRESH(cl
->cl_auth
, &reply_msg
)) {
582 /* end of unsuccessful completion */
583 } /* end of valid reply message */
585 cu
->cu_error
.re_status
= RPC_CANTDECODERES
;
589 release_fd_lock(cu
->cu_fd
, mask
);
590 return (cu
->cu_error
.re_status
);
594 clnt_dg_geterr(cl
, errp
)
596 struct rpc_err
*errp
;
598 struct cu_data
*cu
= (struct cu_data
*)cl
->cl_private
;
600 *errp
= cu
->cu_error
;
604 clnt_dg_freeres(cl
, xdr_res
, res_ptr
)
609 struct cu_data
*cu
= (struct cu_data
*)cl
->cl_private
;
610 XDR
*xdrs
= &(cu
->cu_outxdrs
);
616 sigfillset(&newmask
);
617 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
619 /* XXX Need Windows signal/event stuff here XXX */
621 mutex_lock(&clnt_fd_lock
);
622 while (dg_fd_locks
[WINSOCK_HANDLE_HASH(cu
->cu_fd
)])
623 cond_wait(&dg_cv
[WINSOCK_HANDLE_HASH(cu
->cu_fd
)], &clnt_fd_lock
);
624 xdrs
->x_op
= XDR_FREE
;
625 dummy
= (*xdr_res
)(xdrs
, res_ptr
);
626 mutex_unlock(&clnt_fd_lock
);
627 // thr_sigsetmask(SIG_SETMASK, &mask, NULL);
628 cond_signal(&dg_cv
[WINSOCK_HANDLE_HASH(cu
->cu_fd
)]);
640 clnt_dg_control(cl
, request
, info
)
645 struct cu_data
*cu
= (struct cu_data
*)cl
->cl_private
;
651 /* XXX Need Windows signal/event stuff here XXX */
656 sigfillset(&newmask
);
657 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
659 /* XXX Need Windows signal/event stuff here XXX */
661 mutex_lock(&clnt_fd_lock
);
662 while (dg_fd_locks
[WINSOCK_HANDLE_HASH(cu
->cu_fd
)])
663 cond_wait(&dg_cv
[WINSOCK_HANDLE_HASH(cu
->cu_fd
)], &clnt_fd_lock
);
665 dg_fd_locks
[WINSOCK_HANDLE_HASH(cu
->cu_fd
)] = rpc_lock_value
;
666 mutex_unlock(&clnt_fd_lock
);
669 cu
->cu_closeit
= TRUE
;
670 release_fd_lock(cu
->cu_fd
, mask
);
672 case CLSET_FD_NCLOSE
:
673 cu
->cu_closeit
= FALSE
;
674 release_fd_lock(cu
->cu_fd
, mask
);
678 /* for other requests which use info */
680 release_fd_lock(cu
->cu_fd
, mask
);
685 if (time_not_ok((struct timeval
*)info
)) {
686 release_fd_lock(cu
->cu_fd
, mask
);
689 cu
->cu_total
= *(struct timeval
*)info
;
692 *(struct timeval
*)info
= cu
->cu_total
;
694 case CLGET_SERVER_ADDR
: /* Give him the fd address */
695 /* Now obsolete. Only for backward compatibility */
696 (void) memcpy(info
, &cu
->cu_raddr
, (size_t)cu
->cu_rlen
);
698 case CLSET_RETRY_TIMEOUT
:
699 if (time_not_ok((struct timeval
*)info
)) {
700 release_fd_lock(cu
->cu_fd
, mask
);
703 cu
->cu_wait
= *(struct timeval
*)info
;
705 case CLGET_RETRY_TIMEOUT
:
706 *(struct timeval
*)info
= cu
->cu_wait
;
709 *(SOCKET
*)info
= cu
->cu_fd
;
712 addr
= (struct netbuf
*)info
;
713 addr
->buf
= &cu
->cu_raddr
;
714 addr
->len
= cu
->cu_rlen
;
715 addr
->maxlen
= sizeof cu
->cu_raddr
;
717 case CLSET_SVC_ADDR
: /* set to new address */
718 addr
= (struct netbuf
*)info
;
719 if (addr
->len
< sizeof cu
->cu_raddr
) {
720 release_fd_lock(cu
->cu_fd
, mask
);
723 (void) memcpy(&cu
->cu_raddr
, addr
->buf
, addr
->len
);
724 cu
->cu_rlen
= addr
->len
;
728 * use the knowledge that xid is the
729 * first element in the call structure *.
730 * This will get the xid of the PREVIOUS call
733 ntohl(*(u_int32_t
*)(void *)cu
->cu_outbuf
);
737 /* This will set the xid of the NEXT call */
738 *(u_int32_t
*)(void *)cu
->cu_outbuf
=
739 htonl(*(u_int32_t
*)info
- 1);
740 /* decrement by 1 as clnt_dg_call() increments once */
745 * This RELIES on the information that, in the call body,
746 * the version number field is the fifth field from the
747 * begining of the RPC header. MUST be changed if the
748 * call_struct is changed
751 ntohl(*(u_int32_t
*)(void *)(cu
->cu_outbuf
+
752 4 * BYTES_PER_XDR_UNIT
));
756 *(u_int32_t
*)(void *)(cu
->cu_outbuf
+ 4 * BYTES_PER_XDR_UNIT
)
757 = htonl(*(u_int32_t
*)info
);
762 * This RELIES on the information that, in the call body,
763 * the program number field is the fourth field from the
764 * begining of the RPC header. MUST be changed if the
765 * call_struct is changed
768 ntohl(*(u_int32_t
*)(void *)(cu
->cu_outbuf
+
769 3 * BYTES_PER_XDR_UNIT
));
773 *(u_int32_t
*)(void *)(cu
->cu_outbuf
+ 3 * BYTES_PER_XDR_UNIT
)
774 = htonl(*(u_int32_t
*)info
);
777 cu
->cu_async
= *(int *)info
;
780 cu
->cu_connect
= *(int *)info
;
783 release_fd_lock(cu
->cu_fd
, mask
);
786 release_fd_lock(cu
->cu_fd
, mask
);
794 struct cu_data
*cu
= (struct cu_data
*)cl
->cl_private
;
795 SOCKET cu_fd
= cu
->cu_fd
;
800 sigfillset(&newmask
);
801 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
803 /* XXX Need Windows signal/event stuff here XXX */
805 mutex_lock(&clnt_fd_lock
);
806 while (dg_fd_locks
[WINSOCK_HANDLE_HASH(cu_fd
)])
807 cond_wait(&dg_cv
[WINSOCK_HANDLE_HASH(cu_fd
)], &clnt_fd_lock
);
809 (void)closesocket(cu_fd
);
810 XDR_DESTROY(&(cu
->cu_outxdrs
));
811 mem_free(cu
, (sizeof (*cu
) + cu
->cu_sendsz
+ cu
->cu_recvsz
));
812 if (cl
->cl_netid
&& cl
->cl_netid
[0])
813 mem_free(cl
->cl_netid
, strlen(cl
->cl_netid
) +1);
814 if (cl
->cl_tp
&& cl
->cl_tp
[0])
815 mem_free(cl
->cl_tp
, strlen(cl
->cl_tp
) +1);
816 mem_free(cl
, sizeof (CLIENT
));
817 mutex_unlock(&clnt_fd_lock
);
818 // thr_sigsetmask(SIG_SETMASK, &mask, NULL);
819 cond_signal(&dg_cv
[WINSOCK_HANDLE_HASH(cu_fd
)]);
822 static struct clnt_ops
*
825 static struct clnt_ops ops
;
826 extern mutex_t ops_lock
;
831 /* VARIABLES PROTECTED BY ops_lock: ops */
833 sigfillset(&newmask
);
834 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
836 /* XXX Need Windows signal/event stuff here XXX */
838 mutex_lock(&ops_lock
);
839 if (ops
.cl_call
== NULL
) {
840 ops
.cl_call
= clnt_dg_call
;
841 ops
.cl_abort
= clnt_dg_abort
;
842 ops
.cl_geterr
= clnt_dg_geterr
;
843 ops
.cl_freeres
= clnt_dg_freeres
;
844 ops
.cl_destroy
= clnt_dg_destroy
;
845 ops
.cl_control
= clnt_dg_control
;
847 mutex_unlock(&ops_lock
);
848 // thr_sigsetmask(SIG_SETMASK, &mask, NULL);
853 * Make sure that the time is not garbage. -1 value is allowed.
859 return (t
->tv_sec
< -1 || t
->tv_sec
> 100000000 ||
860 t
->tv_usec
< -1 || t
->tv_usec
> 1000000);