1 /* $NetBSD: clnt_vc.c,v 1.17 2010/12/08 02:06:38 joerg Exp $ */
4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5 * unrestricted use provided that this legend is included on all tape
6 * media and as a part of the software program in whole or part. Users
7 * may copy or modify Sun RPC without charge, but are not authorized
8 * to license or distribute it to anyone else except as part of a product or
9 * program developed by the user.
11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
15 * Sun RPC is provided with no support and without any obligation on the
16 * part of Sun Microsystems, Inc. to assist in its use, correction,
17 * modification or enhancement.
19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21 * OR ANY PART THEREOF.
23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24 * or profits or other special, indirect and consequential damages, even if
25 * Sun has been advised of the possibility of such damages.
27 * Sun Microsystems, Inc.
29 * Mountain View, California 94043
32 #include <sys/cdefs.h>
33 #if defined(LIBC_SCCS) && !defined(lint)
35 static char *sccsid
= "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";
36 static char *sccsid
= "@(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC";
37 static char sccsid
[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro";
39 __RCSID("$NetBSD: clnt_vc.c,v 1.17 2010/12/08 02:06:38 joerg Exp $");
44 * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
46 * Copyright (C) 1984, Sun Microsystems, Inc.
48 * TCP based RPC supports 'batched calls'.
49 * A sequence of calls may be batched-up in a send buffer. The rpc call
50 * return immediately to the client even though the call was not necessarily
51 * sent. The batching occurs if the results' xdr routine is NULL (0) AND
52 * the rpc timeout value is zero (see clnt.h, rpc).
54 * Clients should NOT casually batch calls that in fact return results; that is,
55 * the server side should be aware that a call is batched and not produce any
56 * return message. Batched calls that produce many result messages can
57 * deadlock (netlock) the client and the server....
59 * Now go hang yourself.
62 #include "namespace.h"
63 #include "reentrant.h"
64 #include <sys/types.h>
66 #include <sys/socket.h>
80 #include "rpc_internal.h"
83 __weak_alias(clnt_vc_create
,_clnt_vc_create
)
86 #define MCALL_MSG_SIZE 24
88 static enum clnt_stat clnt_vc_call
__P((CLIENT
*, rpcproc_t
, xdrproc_t
,
89 const char *, xdrproc_t
, caddr_t
, struct timeval
));
90 static void clnt_vc_geterr
__P((CLIENT
*, struct rpc_err
*));
91 static bool_t clnt_vc_freeres
__P((CLIENT
*, xdrproc_t
, caddr_t
));
92 static void clnt_vc_abort
__P((CLIENT
*));
93 static bool_t clnt_vc_control
__P((CLIENT
*, u_int
, char *));
94 static void clnt_vc_destroy
__P((CLIENT
*));
95 static struct clnt_ops
*clnt_vc_ops
__P((void));
96 static bool_t time_not_ok
__P((struct timeval
*));
97 static int read_vc
__P((caddr_t
, caddr_t
, int));
98 static int write_vc
__P((caddr_t
, caddr_t
, int));
103 struct timeval ct_wait
;
104 bool_t ct_waitset
; /* wait set by clnt_control? */
105 struct netbuf ct_addr
;
106 struct rpc_err ct_error
;
108 char ct_mcallc
[MCALL_MSG_SIZE
]; /* marshalled callmsg */
111 u_int ct_mpos
; /* pos after marshal */
116 * This machinery implements per-fd locks for MT-safety. It is not
117 * sufficient to do per-CLIENT handle locks for MT-safety because a
118 * user may create more than one CLIENT handle with the same fd behind
119 * it. Therfore, we allocate an array of flags (vc_fd_locks), protected
120 * by the clnt_fd_lock mutex, and an array (vc_cv) of condition variables
121 * similarly protected. Vc_fd_lock[fd] == 1 => a call is activte on some
122 * CLIENT handle created for that fd.
123 * The current implementation holds locks across the entire RPC and reply.
124 * Yes, this is silly, and as soon as this code is proven to work, this
125 * should be the first thing fixed. One step at a time.
128 static int *vc_fd_locks
;
129 #define __rpc_lock_value __isthreaded;
130 extern mutex_t clnt_fd_lock
;
131 static cond_t
*vc_cv
;
132 #define release_fd_lock(fd, mask) { \
133 mutex_lock(&clnt_fd_lock); \
134 vc_fd_locks[fd] = 0; \
135 mutex_unlock(&clnt_fd_lock); \
136 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); \
137 cond_signal(&vc_cv[fd]); \
140 #define release_fd_lock(fd,mask)
141 #define __rpc_lock_value 0
146 * Create a client handle for a connection.
147 * Default options are set, which the user can change using clnt_control()'s.
148 * The rpc/vc package does buffering similar to stdio, so the client
149 * must pick send and receive buffer sizes, 0 => use the default.
150 * NB: fd is copied into a private area.
151 * NB: The rpch->cl_auth is set null authentication. Caller may wish to
152 * set this something more useful.
154 * fd should be an open socket
157 clnt_vc_create(fd
, raddr
, prog
, vers
, sendsz
, recvsz
)
159 const struct netbuf
*raddr
;
166 struct ct_data
*ct
= NULL
;
167 struct rpc_msg call_msg
;
172 struct sockaddr_storage ss
;
174 struct __rpc_sockinfo si
;
176 _DIAGASSERT(raddr
!= NULL
);
178 h
= mem_alloc(sizeof(*h
));
180 warnx("clnt_vc_create: out of memory");
181 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
182 rpc_createerr
.cf_error
.re_errno
= errno
;
185 ct
= mem_alloc(sizeof(*ct
));
187 warnx("clnt_vc_create: out of memory");
188 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
189 rpc_createerr
.cf_error
.re_errno
= errno
;
193 sigfillset(&newmask
);
194 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
196 mutex_lock(&clnt_fd_lock
);
197 if (vc_fd_locks
== NULL
) {
198 size_t cv_allocsz
, fd_allocsz
;
199 int dtbsize
= __rpc_dtbsize();
201 fd_allocsz
= dtbsize
* sizeof (int);
202 vc_fd_locks
= mem_alloc(fd_allocsz
);
203 if (vc_fd_locks
== NULL
) {
204 mutex_unlock(&clnt_fd_lock
);
205 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
208 memset(vc_fd_locks
, '\0', fd_allocsz
);
210 _DIAGASSERT(vc_cv
== NULL
);
211 cv_allocsz
= dtbsize
* sizeof (cond_t
);
212 vc_cv
= mem_alloc(cv_allocsz
);
214 mem_free(vc_fd_locks
, fd_allocsz
);
216 mutex_unlock(&clnt_fd_lock
);
217 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
222 for (i
= 0; i
< dtbsize
; i
++)
223 cond_init(&vc_cv
[i
], 0, (void *) 0);
226 _DIAGASSERT(vc_cv
!= NULL
);
230 * XXX - fvdl connecting while holding a mutex?
233 if (getpeername(fd
, (struct sockaddr
*)(void *)&ss
, &slen
) < 0) {
234 if (errno
!= ENOTCONN
) {
235 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
236 rpc_createerr
.cf_error
.re_errno
= errno
;
237 mutex_unlock(&clnt_fd_lock
);
238 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
241 if (connect(fd
, (struct sockaddr
*)raddr
->buf
, raddr
->len
) < 0){
242 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
243 rpc_createerr
.cf_error
.re_errno
= errno
;
244 mutex_unlock(&clnt_fd_lock
);
245 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
249 mutex_unlock(&clnt_fd_lock
);
250 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
251 if (!__rpc_fd2sockinfo(fd
, &si
))
254 ct
->ct_closeit
= FALSE
;
257 * Set up private data struct
260 ct
->ct_wait
.tv_usec
= 0;
261 ct
->ct_waitset
= FALSE
;
262 ct
->ct_addr
.buf
= malloc((size_t)raddr
->maxlen
);
263 if (ct
->ct_addr
.buf
== NULL
)
265 memcpy(ct
->ct_addr
.buf
, &raddr
->buf
, (size_t)raddr
->len
);
266 ct
->ct_addr
.len
= raddr
->maxlen
;
267 ct
->ct_addr
.maxlen
= raddr
->maxlen
;
270 * Initialize call message
272 call_msg
.rm_xid
= __RPC_GETXID();
273 call_msg
.rm_direction
= CALL
;
274 call_msg
.rm_call
.cb_rpcvers
= RPC_MSG_VERSION
;
275 call_msg
.rm_call
.cb_prog
= (u_int32_t
)prog
;
276 call_msg
.rm_call
.cb_vers
= (u_int32_t
)vers
;
279 * pre-serialize the static part of the call msg and stash it away
281 xdrmem_create(&(ct
->ct_xdrs
), ct
->ct_u
.ct_mcallc
, MCALL_MSG_SIZE
,
283 if (! xdr_callhdr(&(ct
->ct_xdrs
), &call_msg
)) {
284 if (ct
->ct_closeit
) {
289 ct
->ct_mpos
= XDR_GETPOS(&(ct
->ct_xdrs
));
290 XDR_DESTROY(&(ct
->ct_xdrs
));
293 * Create a client handle which uses xdrrec for serialization
294 * and authnone for authentication.
296 h
->cl_ops
= clnt_vc_ops();
298 h
->cl_auth
= authnone_create();
299 sendsz
= __rpc_get_t_size(si
.si_af
, si
.si_proto
, (int)sendsz
);
300 recvsz
= __rpc_get_t_size(si
.si_af
, si
.si_proto
, (int)recvsz
);
301 xdrrec_create(&(ct
->ct_xdrs
), sendsz
, recvsz
,
302 h
->cl_private
, read_vc
, write_vc
);
307 * Something goofed, free stuff and barf
310 mem_free(ct
, sizeof(struct ct_data
));
312 mem_free(h
, sizeof(CLIENT
));
316 static enum clnt_stat
317 clnt_vc_call(h
, proc
, xdr_args
, args_ptr
, xdr_results
, results_ptr
, timeout
)
321 const char *args_ptr
;
322 xdrproc_t xdr_results
;
324 struct timeval timeout
;
328 struct rpc_msg reply_msg
;
334 sigset_t mask
, newmask
;
337 _DIAGASSERT(h
!= NULL
);
339 ct
= (struct ct_data
*) h
->cl_private
;
342 sigfillset(&newmask
);
343 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
344 mutex_lock(&clnt_fd_lock
);
345 while (vc_fd_locks
[ct
->ct_fd
])
346 cond_wait(&vc_cv
[ct
->ct_fd
], &clnt_fd_lock
);
347 vc_fd_locks
[ct
->ct_fd
] = __rpc_lock_value
;
348 mutex_unlock(&clnt_fd_lock
);
351 xdrs
= &(ct
->ct_xdrs
);
352 msg_x_id
= &ct
->ct_u
.ct_mcalli
;
354 if (!ct
->ct_waitset
) {
355 if (time_not_ok(&timeout
) == FALSE
)
356 ct
->ct_wait
= timeout
;
360 (xdr_results
== NULL
&& timeout
.tv_sec
== 0
361 && timeout
.tv_usec
== 0) ? FALSE
: TRUE
;
364 xdrs
->x_op
= XDR_ENCODE
;
365 ct
->ct_error
.re_status
= RPC_SUCCESS
;
366 x_id
= ntohl(--(*msg_x_id
));
367 if ((! XDR_PUTBYTES(xdrs
, ct
->ct_u
.ct_mcallc
, ct
->ct_mpos
)) ||
368 (! XDR_PUTINT32(xdrs
, (int32_t *)&proc
)) ||
369 (! AUTH_MARSHALL(h
->cl_auth
, xdrs
)) ||
370 (! (*xdr_args
)(xdrs
, __UNCONST(args_ptr
)))) {
371 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
372 ct
->ct_error
.re_status
= RPC_CANTENCODEARGS
;
373 (void)xdrrec_endofrecord(xdrs
, TRUE
);
374 release_fd_lock(ct
->ct_fd
, mask
);
375 return (ct
->ct_error
.re_status
);
377 if (! xdrrec_endofrecord(xdrs
, shipnow
)) {
378 release_fd_lock(ct
->ct_fd
, mask
);
379 return (ct
->ct_error
.re_status
= RPC_CANTSEND
);
382 release_fd_lock(ct
->ct_fd
, mask
);
383 return (RPC_SUCCESS
);
386 * Hack to provide rpc-based message passing
388 if (timeout
.tv_sec
== 0 && timeout
.tv_usec
== 0) {
389 release_fd_lock(ct
->ct_fd
, mask
);
390 return(ct
->ct_error
.re_status
= RPC_TIMEDOUT
);
395 * Keep receiving until we get a valid transaction id
397 xdrs
->x_op
= XDR_DECODE
;
399 reply_msg
.acpted_rply
.ar_verf
= _null_auth
;
400 reply_msg
.acpted_rply
.ar_results
.where
= NULL
;
401 reply_msg
.acpted_rply
.ar_results
.proc
= (xdrproc_t
)xdr_void
;
402 if (! xdrrec_skiprecord(xdrs
)) {
403 release_fd_lock(ct
->ct_fd
, mask
);
404 return (ct
->ct_error
.re_status
);
406 /* now decode and validate the response header */
407 if (! xdr_replymsg(xdrs
, &reply_msg
)) {
408 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
410 release_fd_lock(ct
->ct_fd
, mask
);
411 return (ct
->ct_error
.re_status
);
413 if (reply_msg
.rm_xid
== x_id
)
420 _seterr_reply(&reply_msg
, &(ct
->ct_error
));
421 if (ct
->ct_error
.re_status
== RPC_SUCCESS
) {
422 if (! AUTH_VALIDATE(h
->cl_auth
,
423 &reply_msg
.acpted_rply
.ar_verf
)) {
424 ct
->ct_error
.re_status
= RPC_AUTHERROR
;
425 ct
->ct_error
.re_why
= AUTH_INVALIDRESP
;
426 } else if (! (*xdr_results
)(xdrs
, results_ptr
)) {
427 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
428 ct
->ct_error
.re_status
= RPC_CANTDECODERES
;
430 /* free verifier ... */
431 if (reply_msg
.acpted_rply
.ar_verf
.oa_base
!= NULL
) {
432 xdrs
->x_op
= XDR_FREE
;
433 (void)xdr_opaque_auth(xdrs
,
434 &(reply_msg
.acpted_rply
.ar_verf
));
436 } /* end successful completion */
438 /* maybe our credentials need to be refreshed ... */
439 if (refreshes
-- && AUTH_REFRESH(h
->cl_auth
))
441 } /* end of unsuccessful completion */
442 release_fd_lock(ct
->ct_fd
, mask
);
443 return (ct
->ct_error
.re_status
);
447 clnt_vc_geterr(h
, errp
)
449 struct rpc_err
*errp
;
453 _DIAGASSERT(h
!= NULL
);
454 _DIAGASSERT(errp
!= NULL
);
456 ct
= (struct ct_data
*) h
->cl_private
;
457 *errp
= ct
->ct_error
;
461 clnt_vc_freeres(cl
, xdr_res
, res_ptr
)
474 _DIAGASSERT(cl
!= NULL
);
476 ct
= (struct ct_data
*)cl
->cl_private
;
477 xdrs
= &(ct
->ct_xdrs
);
479 sigfillset(&newmask
);
480 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
481 mutex_lock(&clnt_fd_lock
);
483 while (vc_fd_locks
[ct
->ct_fd
])
484 cond_wait(&vc_cv
[ct
->ct_fd
], &clnt_fd_lock
);
487 xdrs
->x_op
= XDR_FREE
;
488 dummy
= (*xdr_res
)(xdrs
, res_ptr
);
489 mutex_unlock(&clnt_fd_lock
);
490 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
491 cond_signal(&vc_cv
[ct
->ct_fd
]);
504 clnt_vc_control(cl
, request
, info
)
516 _DIAGASSERT(cl
!= NULL
);
518 ct
= (struct ct_data
*)cl
->cl_private
;
520 sigfillset(&newmask
);
521 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
522 mutex_lock(&clnt_fd_lock
);
524 while (vc_fd_locks
[ct
->ct_fd
])
525 cond_wait(&vc_cv
[ct
->ct_fd
], &clnt_fd_lock
);
526 vc_fd_locks
[ct
->ct_fd
] = __rpc_lock_value
;
528 mutex_unlock(&clnt_fd_lock
);
532 ct
->ct_closeit
= TRUE
;
533 release_fd_lock(ct
->ct_fd
, mask
);
535 case CLSET_FD_NCLOSE
:
536 ct
->ct_closeit
= FALSE
;
537 release_fd_lock(ct
->ct_fd
, mask
);
543 /* for other requests which use info */
545 release_fd_lock(ct
->ct_fd
, mask
);
550 if (time_not_ok((struct timeval
*)(void *)info
)) {
551 release_fd_lock(ct
->ct_fd
, mask
);
554 ct
->ct_wait
= *(struct timeval
*)infop
;
555 ct
->ct_waitset
= TRUE
;
558 *(struct timeval
*)infop
= ct
->ct_wait
;
560 case CLGET_SERVER_ADDR
:
561 (void) memcpy(info
, ct
->ct_addr
.buf
, (size_t)ct
->ct_addr
.len
);
564 *(int *)(void *)info
= ct
->ct_fd
;
567 /* The caller should not free this memory area */
568 *(struct netbuf
*)(void *)info
= ct
->ct_addr
;
570 case CLSET_SVC_ADDR
: /* set to new address */
571 release_fd_lock(ct
->ct_fd
, mask
);
575 * use the knowledge that xid is the
576 * first element in the call structure
577 * This will get the xid of the PREVIOUS call
579 *(u_int32_t
*)(void *)info
=
580 ntohl(*(u_int32_t
*)(void *)&ct
->ct_u
.ct_mcalli
);
583 /* This will set the xid of the NEXT call */
584 *(u_int32_t
*)(void *)&ct
->ct_u
.ct_mcalli
=
585 htonl(*((u_int32_t
*)(void *)info
) + 1);
586 /* increment by 1 as clnt_vc_call() decrements once */
590 * This RELIES on the information that, in the call body,
591 * the version number field is the fifth field from the
592 * begining of the RPC header. MUST be changed if the
593 * call_struct is changed
595 *(u_int32_t
*)(void *)info
=
596 ntohl(*(u_int32_t
*)(void *)(ct
->ct_u
.ct_mcallc
+
597 4 * BYTES_PER_XDR_UNIT
));
601 *(u_int32_t
*)(void *)(ct
->ct_u
.ct_mcallc
+
602 4 * BYTES_PER_XDR_UNIT
) =
603 htonl(*(u_int32_t
*)(void *)info
);
608 * This RELIES on the information that, in the call body,
609 * the program number field is the fourth field from the
610 * begining of the RPC header. MUST be changed if the
611 * call_struct is changed
613 *(u_int32_t
*)(void *)info
=
614 ntohl(*(u_int32_t
*)(void *)(ct
->ct_u
.ct_mcallc
+
615 3 * BYTES_PER_XDR_UNIT
));
619 *(u_int32_t
*)(void *)(ct
->ct_u
.ct_mcallc
+
620 3 * BYTES_PER_XDR_UNIT
) =
621 htonl(*(u_int32_t
*)(void *)info
);
625 release_fd_lock(ct
->ct_fd
, mask
);
628 release_fd_lock(ct
->ct_fd
, mask
);
644 _DIAGASSERT(cl
!= NULL
);
646 ct
= (struct ct_data
*) cl
->cl_private
;
649 sigfillset(&newmask
);
650 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
651 mutex_lock(&clnt_fd_lock
);
653 while (vc_fd_locks
[ct_fd
])
654 cond_wait(&vc_cv
[ct_fd
], &clnt_fd_lock
);
656 if (ct
->ct_closeit
&& ct
->ct_fd
!= -1) {
657 (void)close(ct
->ct_fd
);
659 XDR_DESTROY(&(ct
->ct_xdrs
));
661 free(ct
->ct_addr
.buf
);
662 mem_free(ct
, sizeof(struct ct_data
));
663 mem_free(cl
, sizeof(CLIENT
));
664 mutex_unlock(&clnt_fd_lock
);
665 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
667 cond_signal(&vc_cv
[ct_fd
]);
671 * Interface between xdr serializer and tcp connection.
672 * Behaves like the system calls, read & write, but keeps some error state
673 * around for the rpc level.
676 read_vc(ctp
, buf
, len
)
681 struct ct_data
*ct
= (struct ct_data
*)(void *)ctp
;
688 TIMEVAL_TO_TIMESPEC(&ct
->ct_wait
, &ts
);
692 switch (pollts(&fd
, 1, &ts
, NULL
)) {
694 ct
->ct_error
.re_status
= RPC_TIMEDOUT
;
700 ct
->ct_error
.re_status
= RPC_CANTRECV
;
701 ct
->ct_error
.re_errno
= errno
;
706 switch (len
= read(ct
->ct_fd
, buf
, (size_t)len
)) {
710 ct
->ct_error
.re_errno
= ECONNRESET
;
711 ct
->ct_error
.re_status
= RPC_CANTRECV
;
712 len
= -1; /* it's really an error */
716 ct
->ct_error
.re_errno
= errno
;
717 ct
->ct_error
.re_status
= RPC_CANTRECV
;
724 write_vc(ctp
, buf
, len
)
729 struct ct_data
*ct
= (struct ct_data
*)(void *)ctp
;
732 for (cnt
= len
; cnt
> 0; cnt
-= i
, buf
+= i
) {
733 if ((i
= write(ct
->ct_fd
, buf
, (size_t)cnt
)) == -1) {
734 ct
->ct_error
.re_errno
= errno
;
735 ct
->ct_error
.re_status
= RPC_CANTSEND
;
742 static struct clnt_ops
*
745 static struct clnt_ops ops
;
747 extern mutex_t ops_lock
;
752 /* VARIABLES PROTECTED BY ops_lock: ops */
754 sigfillset(&newmask
);
755 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
756 mutex_lock(&ops_lock
);
757 if (ops
.cl_call
== NULL
) {
758 ops
.cl_call
= clnt_vc_call
;
759 ops
.cl_abort
= clnt_vc_abort
;
760 ops
.cl_geterr
= clnt_vc_geterr
;
761 ops
.cl_freeres
= clnt_vc_freeres
;
762 ops
.cl_destroy
= clnt_vc_destroy
;
763 ops
.cl_control
= clnt_vc_control
;
765 mutex_unlock(&ops_lock
);
766 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
771 * Make sure that the time is not garbage. -1 value is disallowed.
772 * Note this is different from time_not_ok in clnt_dg.c
779 _DIAGASSERT(t
!= NULL
);
781 return (t
->tv_sec
<= -1 || t
->tv_sec
> 100000000 ||
782 t
->tv_usec
<= -1 || t
->tv_usec
> 1000000);