1 /* $NetBSD: clnt_dg.c,v 1.29 2013/05/07 21:08:44 christos Exp $ */
4 * Copyright (c) 2010, Oracle America, Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials
15 * provided with the distribution.
16 * * Neither the name of the "Oracle America, Inc." nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * Copyright (c) 1986-1991 by Sun Microsystems Inc.
37 /* #ident "@(#)clnt_dg.c 1.23 94/04/22 SMI" */
39 #include <sys/cdefs.h>
40 #if defined(LIBC_SCCS) && !defined(lint)
42 static char sccsid
[] = "@(#)clnt_dg.c 1.19 89/03/16 Copyr 1988 Sun Micro";
44 __RCSID("$NetBSD: clnt_dg.c,v 1.29 2013/05/07 21:08:44 christos Exp $");
49 * Implements a connectionless client side RPC.
52 #include "namespace.h"
53 #include "reentrant.h"
55 #include <sys/types.h>
57 #include <sys/socket.h>
58 #include <sys/ioctl.h>
68 #include "svc_fdset.h"
69 #include "rpc_internal.h"
72 __weak_alias(clnt_dg_create
,_clnt_dg_create
)
75 #define RPC_MAX_BACKOFF 30 /* seconds */
78 static struct clnt_ops
*clnt_dg_ops(void);
79 static bool_t
time_not_ok(struct timeval
*);
80 static enum clnt_stat
clnt_dg_call(CLIENT
*, rpcproc_t
, xdrproc_t
,
81 const char *, xdrproc_t
, caddr_t
, struct timeval
);
82 static void clnt_dg_geterr(CLIENT
*, struct rpc_err
*);
83 static bool_t
clnt_dg_freeres(CLIENT
*, xdrproc_t
, caddr_t
);
84 static void clnt_dg_abort(CLIENT
*);
85 static bool_t
clnt_dg_control(CLIENT
*, u_int
, char *);
86 static void clnt_dg_destroy(CLIENT
*);
92 * This machinery implements per-fd locks for MT-safety. It is not
93 * sufficient to do per-CLIENT handle locks for MT-safety because a
94 * user may create more than one CLIENT handle with the same fd behind
95 * it. Therfore, we allocate an array of flags (dg_fd_locks), protected
96 * by the clnt_fd_lock mutex, and an array (dg_cv) of condition variables
97 * similarly protected. Dg_fd_lock[fd] == 1 => a call is activte on some
98 * CLIENT handle created for that fd.
99 * The current implementation holds locks across the entire RPC and reply,
100 * including retransmissions. Yes, this is silly, and as soon as this
101 * code is proven to work, this should be the first thing fixed. One step
104 static int *dg_fd_locks
;
106 #define __rpc_lock_value __isthreaded;
107 extern mutex_t clnt_fd_lock
;
108 static cond_t
*dg_cv
;
109 #define release_fd_lock(fd, mask) { \
110 mutex_lock(&clnt_fd_lock); \
111 dg_fd_locks[fd] = 0; \
112 mutex_unlock(&clnt_fd_lock); \
113 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); \
114 cond_signal(&dg_cv[fd]); \
117 #define release_fd_lock(fd,mask)
118 #define __rpc_lock_value 0
121 static const char mem_err_clnt_dg
[] = "clnt_dg_create: out of memory";
123 /* VARIABLES PROTECTED BY clnt_fd_lock: dg_fd_locks, dg_cv */
126 * Private data kept per client handle
129 int cu_fd
; /* connections fd */
130 bool_t cu_closeit
; /* opened by library */
131 struct sockaddr_storage cu_raddr
; /* remote address */
133 struct timeval cu_wait
; /* retransmit interval */
134 struct timeval cu_total
; /* total time for the call */
135 struct rpc_err cu_error
;
138 u_int cu_sendsz
; /* send size */
140 u_int cu_recvsz
; /* recv size */
141 struct pollfd cu_pfdp
;
146 * Connection less client creation returns with client handle parameters.
147 * Default options are set, which the user can change using clnt_control().
148 * fd should be open and bound.
149 * NB: The rpch->cl_auth is initialized to null authentication.
150 * Caller may wish to set this something more useful.
152 * sendsz and recvsz are the maximum allowable packet sizes that can be
153 * sent and received. Normally they are the same, but they can be
154 * changed to improve the program efficiency and buffer allocation.
155 * If they are 0, use the transport default.
157 * If svcaddr is NULL, returns NULL.
161 int fd
, /* open file descriptor */
162 const struct netbuf
*svcaddr
, /* servers address */
163 rpcprog_t program
, /* program number */
164 rpcvers_t version
, /* version number */
165 u_int sendsz
, /* buffer recv size */
166 u_int recvsz
) /* buffer send size */
168 CLIENT
*cl
= NULL
; /* client handle */
169 struct cu_data
*cu
= NULL
; /* private data */
170 struct rpc_msg call_msg
;
175 struct __rpc_sockinfo si
;
178 __clnt_sigfillset(&newmask
);
179 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
180 mutex_lock(&clnt_fd_lock
);
181 if (dg_fd_locks
== NULL
) {
186 int dtbsize
= __rpc_dtbsize();
188 fd_allocsz
= dtbsize
* sizeof (int);
189 dg_fd_locks
= mem_alloc(fd_allocsz
);
190 if (dg_fd_locks
== NULL
) {
193 memset(dg_fd_locks
, '\0', fd_allocsz
);
196 cv_allocsz
= dtbsize
* sizeof (cond_t
);
197 dg_cv
= mem_alloc(cv_allocsz
);
199 mem_free(dg_fd_locks
, fd_allocsz
);
205 for (i
= 0; i
< dtbsize
; i
++)
206 cond_init(&dg_cv
[i
], 0, (void *) 0);
211 mutex_unlock(&clnt_fd_lock
);
212 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
214 if (svcaddr
== NULL
) {
215 rpc_createerr
.cf_stat
= RPC_UNKNOWNADDR
;
219 if (!__rpc_fd2sockinfo(fd
, &si
)) {
220 rpc_createerr
.cf_stat
= RPC_TLIERROR
;
221 rpc_createerr
.cf_error
.re_errno
= 0;
225 * Find the receive and the send size
227 sendsz
= __rpc_get_t_size(si
.si_af
, si
.si_proto
, (int)sendsz
);
228 recvsz
= __rpc_get_t_size(si
.si_af
, si
.si_proto
, (int)recvsz
);
229 if ((sendsz
== 0) || (recvsz
== 0)) {
230 rpc_createerr
.cf_stat
= RPC_TLIERROR
; /* XXX */
231 rpc_createerr
.cf_error
.re_errno
= 0;
235 if ((cl
= mem_alloc(sizeof (CLIENT
))) == NULL
)
238 * Should be multiple of 4 for XDR.
240 sendsz
= ((sendsz
+ 3) / 4) * 4;
241 recvsz
= ((recvsz
+ 3) / 4) * 4;
242 cu
= malloc(sizeof (*cu
) + sendsz
+ recvsz
);
245 memset(cu
, 0, sizeof(*cu
));
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() */
251 cu
->cu_wait
.tv_sec
= 15; /* heuristically chosen */
252 cu
->cu_wait
.tv_usec
= 0;
254 cu
->cu_wait
.tv_sec
= 0; /* for testing, 10x / second */
255 cu
->cu_wait
.tv_usec
= 100000;
257 cu
->cu_total
.tv_sec
= -1;
258 cu
->cu_total
.tv_usec
= -1;
259 cu
->cu_sendsz
= sendsz
;
260 cu
->cu_recvsz
= recvsz
;
261 call_msg
.rm_xid
= __RPC_GETXID();
262 call_msg
.rm_call
.cb_prog
= program
;
263 call_msg
.rm_call
.cb_vers
= version
;
264 xdrmem_create(&(cu
->cu_outxdrs
), cu
->cu_outbuf
, sendsz
, XDR_ENCODE
);
265 if (! xdr_callhdr(&(cu
->cu_outxdrs
), &call_msg
)) {
266 rpc_createerr
.cf_stat
= RPC_CANTENCODEARGS
; /* XXX */
267 rpc_createerr
.cf_error
.re_errno
= 0;
270 cu
->cu_xdrpos
= XDR_GETPOS(&(cu
->cu_outxdrs
));
272 /* XXX fvdl - do we still want this? */
274 (void)bindresvport_sa(fd
, (struct sockaddr
*)svcaddr
->buf
);
276 ioctl(fd
, FIONBIO
, (char *)(void *)&one
);
279 * By default, closeit is always FALSE. It is users responsibility
280 * to do a close on it, else the user may use clnt_control
281 * to let clnt_destroy do it for him/her.
283 cu
->cu_closeit
= FALSE
;
285 cu
->cu_pfdp
.fd
= cu
->cu_fd
;
286 cu
->cu_pfdp
.events
= POLLIN
| POLLPRI
| POLLRDNORM
| POLLRDBAND
;
287 cl
->cl_ops
= clnt_dg_ops();
288 cl
->cl_private
= (caddr_t
)(void *)cu
;
289 cl
->cl_auth
= authnone_create();
294 mutex_unlock(&clnt_fd_lock
);
295 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
297 warnx(mem_err_clnt_dg
);
298 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
299 rpc_createerr
.cf_error
.re_errno
= errno
;
302 mem_free(cl
, sizeof (CLIENT
));
304 mem_free(cu
, sizeof (*cu
) + sendsz
+ recvsz
);
309 static enum clnt_stat
311 CLIENT
* cl
, /* client handle */
312 rpcproc_t proc
, /* procedure number */
313 xdrproc_t xargs
, /* xdr routine for args */
314 const char * argsp
, /* pointer to args */
315 xdrproc_t xresults
, /* xdr routine for results */
316 caddr_t resultsp
, /* pointer to results */
317 struct timeval utimeout
) /* seconds to wait before giving up */
322 struct rpc_msg reply_msg
;
325 int nrefreshes
= 2; /* number of times to refresh cred */
326 struct timeval timeout
;
327 struct timeval retransmit_time
;
328 struct timeval next_sendtime
, starttime
, time_waited
, tv
;
330 sigset_t mask
, *maskp
= &mask
;
332 sigset_t
*maskp
= NULL
;
339 _DIAGASSERT(cl
!= NULL
);
341 cu
= (struct cu_data
*)cl
->cl_private
;
343 __clnt_sigfillset(&newmask
);
344 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
345 mutex_lock(&clnt_fd_lock
);
346 while (dg_fd_locks
[cu
->cu_fd
])
347 cond_wait(&dg_cv
[cu
->cu_fd
], &clnt_fd_lock
);
348 dg_fd_locks
[cu
->cu_fd
] = __rpc_lock_value
;
349 mutex_unlock(&clnt_fd_lock
);
350 if (cu
->cu_total
.tv_usec
== -1) {
351 timeout
= utimeout
; /* use supplied timeout */
353 timeout
= cu
->cu_total
; /* use default timeout */
356 time_waited
.tv_sec
= 0;
357 time_waited
.tv_usec
= 0;
358 retransmit_time
= next_sendtime
= cu
->cu_wait
;
359 gettimeofday(&starttime
, NULL
);
362 xdrs
= &(cu
->cu_outxdrs
);
363 xdrs
->x_op
= XDR_ENCODE
;
364 XDR_SETPOS(xdrs
, cu
->cu_xdrpos
);
366 * the transaction is the first thing in the out buffer
368 (*(u_int32_t
*)(void *)(cu
->cu_outbuf
))++;
369 if ((! XDR_PUTINT32(xdrs
, (int32_t *)&proc
)) ||
370 (! AUTH_MARSHALL(cl
->cl_auth
, xdrs
)) ||
371 (! (*xargs
)(xdrs
, __UNCONST(argsp
)))) {
372 cu
->cu_error
.re_status
= RPC_CANTENCODEARGS
;
375 outlen
= (size_t)XDR_GETPOS(xdrs
);
378 if ((size_t)sendto(cu
->cu_fd
, cu
->cu_outbuf
, outlen
, 0,
379 (struct sockaddr
*)(void *)&cu
->cu_raddr
, (socklen_t
)cu
->cu_rlen
)
381 cu
->cu_error
.re_errno
= errno
;
382 cu
->cu_error
.re_status
= RPC_CANTSEND
;
387 * Hack to provide rpc-based message passing
389 if (timeout
.tv_sec
== 0 && timeout
.tv_usec
== 0) {
390 cu
->cu_error
.re_status
= RPC_TIMEDOUT
;
394 * sub-optimal code appears here because we have
395 * some clock time to spare while the packets are in flight.
396 * (We assume that this is actually only executed once.)
398 reply_msg
.acpted_rply
.ar_verf
= _null_auth
;
399 reply_msg
.acpted_rply
.ar_results
.where
= resultsp
;
400 reply_msg
.acpted_rply
.ar_results
.proc
= xresults
;
404 /* Decide how long to wait. */
405 if (timercmp(&next_sendtime
, &timeout
, <))
406 timersub(&next_sendtime
, &time_waited
, &tv
);
408 timersub(&timeout
, &time_waited
, &tv
);
409 if (tv
.tv_sec
< 0 || tv
.tv_usec
< 0)
410 tv
.tv_sec
= tv
.tv_usec
= 0;
411 TIMEVAL_TO_TIMESPEC(&tv
, &ts
);
413 n
= pollts(&cu
->cu_pfdp
, 1, &ts
, maskp
);
415 /* We have some data now */
417 recvlen
= recvfrom(cu
->cu_fd
, cu
->cu_inbuf
,
418 cu
->cu_recvsz
, 0, NULL
, NULL
);
419 } while (recvlen
< 0 && errno
== EINTR
);
421 if (recvlen
< 0 && errno
!= EWOULDBLOCK
) {
422 cu
->cu_error
.re_errno
= errno
;
423 cu
->cu_error
.re_status
= RPC_CANTRECV
;
426 if (recvlen
>= (ssize_t
)sizeof(uint32_t)) {
427 if (memcmp(cu
->cu_inbuf
, cu
->cu_outbuf
,
428 sizeof(uint32_t)) == 0)
429 /* Assume we have the proper reply. */
434 cu
->cu_error
.re_errno
= errno
;
435 cu
->cu_error
.re_status
= RPC_CANTRECV
;
439 gettimeofday(&tv
, NULL
);
440 timersub(&tv
, &starttime
, &time_waited
);
442 /* Check for timeout. */
443 if (timercmp(&time_waited
, &timeout
, >)) {
444 cu
->cu_error
.re_status
= RPC_TIMEDOUT
;
448 /* Retransmit if necessary. */
449 if (timercmp(&time_waited
, &next_sendtime
, >)) {
450 /* update retransmit_time */
451 if (retransmit_time
.tv_sec
< RPC_MAX_BACKOFF
)
452 timeradd(&retransmit_time
, &retransmit_time
,
454 timeradd(&next_sendtime
, &retransmit_time
,
461 * now decode and validate the response
464 xdrmem_create(&reply_xdrs
, cu
->cu_inbuf
, (u_int
)recvlen
, XDR_DECODE
);
465 ok
= xdr_replymsg(&reply_xdrs
, &reply_msg
);
466 /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */
468 if ((reply_msg
.rm_reply
.rp_stat
== MSG_ACCEPTED
) &&
469 (reply_msg
.acpted_rply
.ar_stat
== SUCCESS
))
470 cu
->cu_error
.re_status
= RPC_SUCCESS
;
472 _seterr_reply(&reply_msg
, &(cu
->cu_error
));
474 if (cu
->cu_error
.re_status
== RPC_SUCCESS
) {
475 if (! AUTH_VALIDATE(cl
->cl_auth
,
476 &reply_msg
.acpted_rply
.ar_verf
)) {
477 cu
->cu_error
.re_status
= RPC_AUTHERROR
;
478 cu
->cu_error
.re_why
= AUTH_INVALIDRESP
;
480 if (reply_msg
.acpted_rply
.ar_verf
.oa_base
!= NULL
) {
481 xdrs
->x_op
= XDR_FREE
;
482 (void) xdr_opaque_auth(xdrs
,
483 &(reply_msg
.acpted_rply
.ar_verf
));
485 } /* end successful completion */
487 * If unsuccesful AND error is an authentication error
488 * then refresh credentials and try again, else break
490 else if (cu
->cu_error
.re_status
== RPC_AUTHERROR
)
491 /* maybe our credentials need to be refreshed ... */
492 if (nrefreshes
> 0 && AUTH_REFRESH(cl
->cl_auth
)) {
496 /* end of unsuccessful completion */
497 } /* end of valid reply message */
499 cu
->cu_error
.re_status
= RPC_CANTDECODERES
;
503 release_fd_lock(cu
->cu_fd
, mask
);
504 return (cu
->cu_error
.re_status
);
508 clnt_dg_geterr(CLIENT
*cl
, struct rpc_err
*errp
)
512 _DIAGASSERT(cl
!= NULL
);
513 _DIAGASSERT(errp
!= NULL
);
515 cu
= (struct cu_data
*)cl
->cl_private
;
516 *errp
= cu
->cu_error
;
520 clnt_dg_freeres(CLIENT
*cl
, xdrproc_t xdr_res
, caddr_t res_ptr
)
530 _DIAGASSERT(cl
!= NULL
);
531 cu
= (struct cu_data
*)cl
->cl_private
;
532 xdrs
= &(cu
->cu_outxdrs
);
534 __clnt_sigfillset(&newmask
);
535 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
536 mutex_lock(&clnt_fd_lock
);
537 while (dg_fd_locks
[cu
->cu_fd
])
538 cond_wait(&dg_cv
[cu
->cu_fd
], &clnt_fd_lock
);
539 xdrs
->x_op
= XDR_FREE
;
540 dummy
= (*xdr_res
)(xdrs
, res_ptr
);
541 mutex_unlock(&clnt_fd_lock
);
542 thr_sigsetmask(SIG_SETMASK
, &mask
, NULL
);
543 cond_signal(&dg_cv
[cu
->cu_fd
]);
549 clnt_dg_abort(CLIENT
*h
)
554 clnt_dg_control(CLIENT
*cl
, u_int request
, char *info
)
563 _DIAGASSERT(cl
!= NULL
);
564 /* info is handled below */
566 cu
= (struct cu_data
*)cl
->cl_private
;
568 __clnt_sigfillset(&newmask
);
569 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
570 mutex_lock(&clnt_fd_lock
);
571 while (dg_fd_locks
[cu
->cu_fd
])
572 cond_wait(&dg_cv
[cu
->cu_fd
], &clnt_fd_lock
);
573 dg_fd_locks
[cu
->cu_fd
] = __rpc_lock_value
;
574 mutex_unlock(&clnt_fd_lock
);
577 cu
->cu_closeit
= TRUE
;
578 release_fd_lock(cu
->cu_fd
, mask
);
580 case CLSET_FD_NCLOSE
:
581 cu
->cu_closeit
= FALSE
;
582 release_fd_lock(cu
->cu_fd
, mask
);
586 /* for other requests which use info */
588 release_fd_lock(cu
->cu_fd
, mask
);
593 if (time_not_ok((struct timeval
*)(void *)info
)) {
594 release_fd_lock(cu
->cu_fd
, mask
);
597 cu
->cu_total
= *(struct timeval
*)(void *)info
;
600 *(struct timeval
*)(void *)info
= cu
->cu_total
;
602 case CLGET_SERVER_ADDR
: /* Give him the fd address */
603 /* Now obsolete. Only for backward compatibility */
604 (void) memcpy(info
, &cu
->cu_raddr
, (size_t)cu
->cu_rlen
);
606 case CLSET_RETRY_TIMEOUT
:
607 if (time_not_ok((struct timeval
*)(void *)info
)) {
608 release_fd_lock(cu
->cu_fd
, mask
);
611 cu
->cu_wait
= *(struct timeval
*)(void *)info
;
613 case CLGET_RETRY_TIMEOUT
:
614 *(struct timeval
*)(void *)info
= cu
->cu_wait
;
617 *(int *)(void *)info
= cu
->cu_fd
;
620 addr
= (struct netbuf
*)(void *)info
;
621 addr
->buf
= &cu
->cu_raddr
;
622 addr
->len
= cu
->cu_rlen
;
623 addr
->maxlen
= sizeof cu
->cu_raddr
;
625 case CLSET_SVC_ADDR
: /* set to new address */
626 addr
= (struct netbuf
*)(void *)info
;
627 if (addr
->len
< sizeof cu
->cu_raddr
) {
628 release_fd_lock(cu
->cu_fd
, mask
);
631 (void) memcpy(&cu
->cu_raddr
, addr
->buf
, (size_t)addr
->len
);
632 cu
->cu_rlen
= addr
->len
;
636 * use the knowledge that xid is the
637 * first element in the call structure *.
638 * This will get the xid of the PREVIOUS call
640 *(u_int32_t
*)(void *)info
=
641 ntohl(*(u_int32_t
*)(void *)cu
->cu_outbuf
);
645 /* This will set the xid of the NEXT call */
646 *(u_int32_t
*)(void *)cu
->cu_outbuf
=
647 htonl(*(u_int32_t
*)(void *)info
- 1);
648 /* decrement by 1 as clnt_dg_call() increments once */
653 * This RELIES on the information that, in the call body,
654 * the version number field is the fifth field from the
655 * begining of the RPC header. MUST be changed if the
656 * call_struct is changed
658 *(u_int32_t
*)(void *)info
=
659 ntohl(*(u_int32_t
*)(void *)(cu
->cu_outbuf
+
660 4 * BYTES_PER_XDR_UNIT
));
664 *(u_int32_t
*)(void *)(cu
->cu_outbuf
+ 4 * BYTES_PER_XDR_UNIT
)
665 = htonl(*(u_int32_t
*)(void *)info
);
670 * This RELIES on the information that, in the call body,
671 * the program number field is the fourth field from the
672 * begining of the RPC header. MUST be changed if the
673 * call_struct is changed
675 *(u_int32_t
*)(void *)info
=
676 ntohl(*(u_int32_t
*)(void *)(cu
->cu_outbuf
+
677 3 * BYTES_PER_XDR_UNIT
));
681 *(u_int32_t
*)(void *)(cu
->cu_outbuf
+ 3 * BYTES_PER_XDR_UNIT
)
682 = htonl(*(u_int32_t
*)(void *)info
);
686 release_fd_lock(cu
->cu_fd
, mask
);
689 release_fd_lock(cu
->cu_fd
, mask
);
694 clnt_dg_destroy(CLIENT
*cl
)
703 _DIAGASSERT(cl
!= NULL
);
705 cu
= (struct cu_data
*)cl
->cl_private
;
708 __clnt_sigfillset(&newmask
);
709 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
710 mutex_lock(&clnt_fd_lock
);
711 while (dg_fd_locks
[cu_fd
])
712 cond_wait(&dg_cv
[cu_fd
], &clnt_fd_lock
);
715 XDR_DESTROY(&(cu
->cu_outxdrs
));
716 mem_free(cu
, (sizeof (*cu
) + cu
->cu_sendsz
+ cu
->cu_recvsz
));
717 if (cl
->cl_netid
&& cl
->cl_netid
[0])
718 mem_free(cl
->cl_netid
, strlen(cl
->cl_netid
) +1);
719 if (cl
->cl_tp
&& cl
->cl_tp
[0])
720 mem_free(cl
->cl_tp
, strlen(cl
->cl_tp
) +1);
721 mem_free(cl
, sizeof (CLIENT
));
722 mutex_unlock(&clnt_fd_lock
);
723 thr_sigsetmask(SIG_SETMASK
, &mask
, NULL
);
724 cond_signal(&dg_cv
[cu_fd
]);
727 static struct clnt_ops
*
730 static struct clnt_ops ops
;
732 extern mutex_t ops_lock
;
737 /* VARIABLES PROTECTED BY ops_lock: ops */
739 __clnt_sigfillset(&newmask
);
740 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
741 mutex_lock(&ops_lock
);
742 if (ops
.cl_call
== NULL
) {
743 ops
.cl_call
= clnt_dg_call
;
744 ops
.cl_abort
= clnt_dg_abort
;
745 ops
.cl_geterr
= clnt_dg_geterr
;
746 ops
.cl_freeres
= clnt_dg_freeres
;
747 ops
.cl_destroy
= clnt_dg_destroy
;
748 ops
.cl_control
= clnt_dg_control
;
750 mutex_unlock(&ops_lock
);
751 thr_sigsetmask(SIG_SETMASK
, &mask
, NULL
);
756 * Make sure that the time is not garbage. -1 value is allowed.
759 time_not_ok(struct timeval
*t
)
762 _DIAGASSERT(t
!= NULL
);
764 return (t
->tv_sec
< -1 || t
->tv_sec
> 100000000 ||
765 t
->tv_usec
< -1 || t
->tv_usec
> 1000000);