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";
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 extern int __isthreaded
;
130 #define __rpc_lock_value __isthreaded;
131 extern mutex_t clnt_fd_lock
;
132 static cond_t
*vc_cv
;
133 #define release_fd_lock(fd, mask) { \
134 mutex_lock(&clnt_fd_lock); \
135 vc_fd_locks[fd] = 0; \
136 mutex_unlock(&clnt_fd_lock); \
137 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); \
138 cond_signal(&vc_cv[fd]); \
141 #define release_fd_lock(fd,mask)
142 #define __rpc_lock_value 0
147 * Create a client handle for a connection.
148 * Default options are set, which the user can change using clnt_control()'s.
149 * The rpc/vc package does buffering similar to stdio, so the client
150 * must pick send and receive buffer sizes, 0 => use the default.
151 * NB: fd is copied into a private area.
152 * NB: The rpch->cl_auth is set null authentication. Caller may wish to
153 * set this something more useful.
155 * fd should be an open socket
158 clnt_vc_create(fd
, raddr
, prog
, vers
, sendsz
, recvsz
)
160 const struct netbuf
*raddr
;
167 struct ct_data
*ct
= NULL
;
168 struct rpc_msg call_msg
;
173 struct sockaddr_storage ss
;
175 struct __rpc_sockinfo si
;
177 _DIAGASSERT(raddr
!= NULL
);
179 h
= mem_alloc(sizeof(*h
));
181 warnx("clnt_vc_create: out of memory");
182 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
183 rpc_createerr
.cf_error
.re_errno
= errno
;
186 ct
= mem_alloc(sizeof(*ct
));
188 warnx("clnt_vc_create: out of memory");
189 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
190 rpc_createerr
.cf_error
.re_errno
= errno
;
194 sigfillset(&newmask
);
195 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
197 mutex_lock(&clnt_fd_lock
);
198 if (vc_fd_locks
== NULL
) {
199 size_t cv_allocsz
, fd_allocsz
;
200 int dtbsize
= __rpc_dtbsize();
202 fd_allocsz
= dtbsize
* sizeof (int);
203 vc_fd_locks
= mem_alloc(fd_allocsz
);
204 if (vc_fd_locks
== NULL
) {
205 mutex_unlock(&clnt_fd_lock
);
206 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
209 memset(vc_fd_locks
, '\0', fd_allocsz
);
211 _DIAGASSERT(vc_cv
== NULL
);
212 cv_allocsz
= dtbsize
* sizeof (cond_t
);
213 vc_cv
= mem_alloc(cv_allocsz
);
215 mem_free(vc_fd_locks
, fd_allocsz
);
217 mutex_unlock(&clnt_fd_lock
);
218 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
223 for (i
= 0; i
< dtbsize
; i
++)
224 cond_init(&vc_cv
[i
], 0, (void *) 0);
227 _DIAGASSERT(vc_cv
!= NULL
);
231 * XXX - fvdl connecting while holding a mutex?
234 if (getpeername(fd
, (struct sockaddr
*)(void *)&ss
, &slen
) < 0) {
235 if (errno
!= ENOTCONN
) {
236 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
237 rpc_createerr
.cf_error
.re_errno
= errno
;
238 mutex_unlock(&clnt_fd_lock
);
239 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
242 if (connect(fd
, (struct sockaddr
*)raddr
->buf
, raddr
->len
) < 0){
243 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
244 rpc_createerr
.cf_error
.re_errno
= errno
;
245 mutex_unlock(&clnt_fd_lock
);
246 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
250 mutex_unlock(&clnt_fd_lock
);
251 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
252 if (!__rpc_fd2sockinfo(fd
, &si
))
255 ct
->ct_closeit
= FALSE
;
258 * Set up private data struct
261 ct
->ct_wait
.tv_usec
= 0;
262 ct
->ct_waitset
= FALSE
;
263 ct
->ct_addr
.buf
= malloc((size_t)raddr
->maxlen
);
264 if (ct
->ct_addr
.buf
== NULL
)
266 memcpy(ct
->ct_addr
.buf
, &raddr
->buf
, (size_t)raddr
->len
);
267 ct
->ct_addr
.len
= raddr
->maxlen
;
268 ct
->ct_addr
.maxlen
= raddr
->maxlen
;
271 * Initialize call message
273 call_msg
.rm_xid
= __RPC_GETXID();
274 call_msg
.rm_direction
= CALL
;
275 call_msg
.rm_call
.cb_rpcvers
= RPC_MSG_VERSION
;
276 call_msg
.rm_call
.cb_prog
= (u_int32_t
)prog
;
277 call_msg
.rm_call
.cb_vers
= (u_int32_t
)vers
;
280 * pre-serialize the static part of the call msg and stash it away
282 xdrmem_create(&(ct
->ct_xdrs
), ct
->ct_u
.ct_mcallc
, MCALL_MSG_SIZE
,
284 if (! xdr_callhdr(&(ct
->ct_xdrs
), &call_msg
)) {
285 if (ct
->ct_closeit
) {
290 ct
->ct_mpos
= XDR_GETPOS(&(ct
->ct_xdrs
));
291 XDR_DESTROY(&(ct
->ct_xdrs
));
294 * Create a client handle which uses xdrrec for serialization
295 * and authnone for authentication.
297 h
->cl_ops
= clnt_vc_ops();
299 h
->cl_auth
= authnone_create();
300 sendsz
= __rpc_get_t_size(si
.si_af
, si
.si_proto
, (int)sendsz
);
301 recvsz
= __rpc_get_t_size(si
.si_af
, si
.si_proto
, (int)recvsz
);
302 xdrrec_create(&(ct
->ct_xdrs
), sendsz
, recvsz
,
303 h
->cl_private
, read_vc
, write_vc
);
308 * Something goofed, free stuff and barf
311 mem_free(ct
, sizeof(struct ct_data
));
313 mem_free(h
, sizeof(CLIENT
));
317 static enum clnt_stat
318 clnt_vc_call(h
, proc
, xdr_args
, args_ptr
, xdr_results
, results_ptr
, timeout
)
322 const char *args_ptr
;
323 xdrproc_t xdr_results
;
325 struct timeval timeout
;
329 struct rpc_msg reply_msg
;
335 sigset_t mask
, newmask
;
338 _DIAGASSERT(h
!= NULL
);
340 ct
= (struct ct_data
*) h
->cl_private
;
343 sigfillset(&newmask
);
344 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
345 mutex_lock(&clnt_fd_lock
);
346 while (vc_fd_locks
[ct
->ct_fd
])
347 cond_wait(&vc_cv
[ct
->ct_fd
], &clnt_fd_lock
);
348 vc_fd_locks
[ct
->ct_fd
] = __rpc_lock_value
;
349 mutex_unlock(&clnt_fd_lock
);
352 xdrs
= &(ct
->ct_xdrs
);
353 msg_x_id
= &ct
->ct_u
.ct_mcalli
;
355 if (!ct
->ct_waitset
) {
356 if (time_not_ok(&timeout
) == FALSE
)
357 ct
->ct_wait
= timeout
;
361 (xdr_results
== NULL
&& timeout
.tv_sec
== 0
362 && timeout
.tv_usec
== 0) ? FALSE
: TRUE
;
365 xdrs
->x_op
= XDR_ENCODE
;
366 ct
->ct_error
.re_status
= RPC_SUCCESS
;
367 x_id
= ntohl(--(*msg_x_id
));
368 if ((! XDR_PUTBYTES(xdrs
, ct
->ct_u
.ct_mcallc
, ct
->ct_mpos
)) ||
369 (! XDR_PUTINT32(xdrs
, (int32_t *)&proc
)) ||
370 (! AUTH_MARSHALL(h
->cl_auth
, xdrs
)) ||
371 (! (*xdr_args
)(xdrs
, __UNCONST(args_ptr
)))) {
372 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
373 ct
->ct_error
.re_status
= RPC_CANTENCODEARGS
;
374 (void)xdrrec_endofrecord(xdrs
, TRUE
);
375 release_fd_lock(ct
->ct_fd
, mask
);
376 return (ct
->ct_error
.re_status
);
378 if (! xdrrec_endofrecord(xdrs
, shipnow
)) {
379 release_fd_lock(ct
->ct_fd
, mask
);
380 return (ct
->ct_error
.re_status
= RPC_CANTSEND
);
383 release_fd_lock(ct
->ct_fd
, mask
);
384 return (RPC_SUCCESS
);
387 * Hack to provide rpc-based message passing
389 if (timeout
.tv_sec
== 0 && timeout
.tv_usec
== 0) {
390 release_fd_lock(ct
->ct_fd
, mask
);
391 return(ct
->ct_error
.re_status
= RPC_TIMEDOUT
);
396 * Keep receiving until we get a valid transaction id
398 xdrs
->x_op
= XDR_DECODE
;
400 reply_msg
.acpted_rply
.ar_verf
= _null_auth
;
401 reply_msg
.acpted_rply
.ar_results
.where
= NULL
;
402 reply_msg
.acpted_rply
.ar_results
.proc
= (xdrproc_t
)xdr_void
;
403 if (! xdrrec_skiprecord(xdrs
)) {
404 release_fd_lock(ct
->ct_fd
, mask
);
405 return (ct
->ct_error
.re_status
);
407 /* now decode and validate the response header */
408 if (! xdr_replymsg(xdrs
, &reply_msg
)) {
409 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
411 release_fd_lock(ct
->ct_fd
, mask
);
412 return (ct
->ct_error
.re_status
);
414 if (reply_msg
.rm_xid
== x_id
)
421 _seterr_reply(&reply_msg
, &(ct
->ct_error
));
422 if (ct
->ct_error
.re_status
== RPC_SUCCESS
) {
423 if (! AUTH_VALIDATE(h
->cl_auth
,
424 &reply_msg
.acpted_rply
.ar_verf
)) {
425 ct
->ct_error
.re_status
= RPC_AUTHERROR
;
426 ct
->ct_error
.re_why
= AUTH_INVALIDRESP
;
427 } else if (! (*xdr_results
)(xdrs
, results_ptr
)) {
428 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
429 ct
->ct_error
.re_status
= RPC_CANTDECODERES
;
431 /* free verifier ... */
432 if (reply_msg
.acpted_rply
.ar_verf
.oa_base
!= NULL
) {
433 xdrs
->x_op
= XDR_FREE
;
434 (void)xdr_opaque_auth(xdrs
,
435 &(reply_msg
.acpted_rply
.ar_verf
));
437 } /* end successful completion */
439 /* maybe our credentials need to be refreshed ... */
440 if (refreshes
-- && AUTH_REFRESH(h
->cl_auth
))
442 } /* end of unsuccessful completion */
443 release_fd_lock(ct
->ct_fd
, mask
);
444 return (ct
->ct_error
.re_status
);
448 clnt_vc_geterr(h
, errp
)
450 struct rpc_err
*errp
;
454 _DIAGASSERT(h
!= NULL
);
455 _DIAGASSERT(errp
!= NULL
);
457 ct
= (struct ct_data
*) h
->cl_private
;
458 *errp
= ct
->ct_error
;
462 clnt_vc_freeres(cl
, xdr_res
, res_ptr
)
475 _DIAGASSERT(cl
!= NULL
);
477 ct
= (struct ct_data
*)cl
->cl_private
;
478 xdrs
= &(ct
->ct_xdrs
);
480 sigfillset(&newmask
);
481 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
482 mutex_lock(&clnt_fd_lock
);
484 while (vc_fd_locks
[ct
->ct_fd
])
485 cond_wait(&vc_cv
[ct
->ct_fd
], &clnt_fd_lock
);
488 xdrs
->x_op
= XDR_FREE
;
489 dummy
= (*xdr_res
)(xdrs
, res_ptr
);
490 mutex_unlock(&clnt_fd_lock
);
491 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
492 cond_signal(&vc_cv
[ct
->ct_fd
]);
505 clnt_vc_control(cl
, request
, info
)
517 _DIAGASSERT(cl
!= NULL
);
519 ct
= (struct ct_data
*)cl
->cl_private
;
521 sigfillset(&newmask
);
522 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
523 mutex_lock(&clnt_fd_lock
);
525 while (vc_fd_locks
[ct
->ct_fd
])
526 cond_wait(&vc_cv
[ct
->ct_fd
], &clnt_fd_lock
);
527 vc_fd_locks
[ct
->ct_fd
] = __rpc_lock_value
;
529 mutex_unlock(&clnt_fd_lock
);
533 ct
->ct_closeit
= TRUE
;
534 release_fd_lock(ct
->ct_fd
, mask
);
536 case CLSET_FD_NCLOSE
:
537 ct
->ct_closeit
= FALSE
;
538 release_fd_lock(ct
->ct_fd
, mask
);
544 /* for other requests which use info */
546 release_fd_lock(ct
->ct_fd
, mask
);
551 if (time_not_ok((struct timeval
*)(void *)info
)) {
552 release_fd_lock(ct
->ct_fd
, mask
);
555 ct
->ct_wait
= *(struct timeval
*)infop
;
556 ct
->ct_waitset
= TRUE
;
559 *(struct timeval
*)infop
= ct
->ct_wait
;
561 case CLGET_SERVER_ADDR
:
562 (void) memcpy(info
, ct
->ct_addr
.buf
, (size_t)ct
->ct_addr
.len
);
565 *(int *)(void *)info
= ct
->ct_fd
;
568 /* The caller should not free this memory area */
569 *(struct netbuf
*)(void *)info
= ct
->ct_addr
;
571 case CLSET_SVC_ADDR
: /* set to new address */
572 release_fd_lock(ct
->ct_fd
, mask
);
576 * use the knowledge that xid is the
577 * first element in the call structure
578 * This will get the xid of the PREVIOUS call
580 *(u_int32_t
*)(void *)info
=
581 ntohl(*(u_int32_t
*)(void *)&ct
->ct_u
.ct_mcalli
);
584 /* This will set the xid of the NEXT call */
585 *(u_int32_t
*)(void *)&ct
->ct_u
.ct_mcalli
=
586 htonl(*((u_int32_t
*)(void *)info
) + 1);
587 /* increment by 1 as clnt_vc_call() decrements once */
591 * This RELIES on the information that, in the call body,
592 * the version number field is the fifth field from the
593 * begining of the RPC header. MUST be changed if the
594 * call_struct is changed
596 *(u_int32_t
*)(void *)info
=
597 ntohl(*(u_int32_t
*)(void *)(ct
->ct_u
.ct_mcallc
+
598 4 * BYTES_PER_XDR_UNIT
));
602 *(u_int32_t
*)(void *)(ct
->ct_u
.ct_mcallc
+
603 4 * BYTES_PER_XDR_UNIT
) =
604 htonl(*(u_int32_t
*)(void *)info
);
609 * This RELIES on the information that, in the call body,
610 * the program number field is the fourth field from the
611 * begining of the RPC header. MUST be changed if the
612 * call_struct is changed
614 *(u_int32_t
*)(void *)info
=
615 ntohl(*(u_int32_t
*)(void *)(ct
->ct_u
.ct_mcallc
+
616 3 * BYTES_PER_XDR_UNIT
));
620 *(u_int32_t
*)(void *)(ct
->ct_u
.ct_mcallc
+
621 3 * BYTES_PER_XDR_UNIT
) =
622 htonl(*(u_int32_t
*)(void *)info
);
626 release_fd_lock(ct
->ct_fd
, mask
);
629 release_fd_lock(ct
->ct_fd
, mask
);
645 _DIAGASSERT(cl
!= NULL
);
647 ct
= (struct ct_data
*) cl
->cl_private
;
650 sigfillset(&newmask
);
651 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
652 mutex_lock(&clnt_fd_lock
);
654 while (vc_fd_locks
[ct_fd
])
655 cond_wait(&vc_cv
[ct_fd
], &clnt_fd_lock
);
657 if (ct
->ct_closeit
&& ct
->ct_fd
!= -1) {
658 (void)close(ct
->ct_fd
);
660 XDR_DESTROY(&(ct
->ct_xdrs
));
662 free(ct
->ct_addr
.buf
);
663 mem_free(ct
, sizeof(struct ct_data
));
664 mem_free(cl
, sizeof(CLIENT
));
665 mutex_unlock(&clnt_fd_lock
);
666 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
668 cond_signal(&vc_cv
[ct_fd
]);
672 * Interface between xdr serializer and tcp connection.
673 * Behaves like the system calls, read & write, but keeps some error state
674 * around for the rpc level.
677 read_vc(ctp
, buf
, len
)
682 struct ct_data
*ct
= (struct ct_data
*)(void *)ctp
;
689 TIMEVAL_TO_TIMESPEC(&ct
->ct_wait
, &ts
);
693 switch (pollts(&fd
, 1, &ts
, NULL
)) {
695 ct
->ct_error
.re_status
= RPC_TIMEDOUT
;
701 ct
->ct_error
.re_status
= RPC_CANTRECV
;
702 ct
->ct_error
.re_errno
= errno
;
707 switch (len
= read(ct
->ct_fd
, buf
, (size_t)len
)) {
711 ct
->ct_error
.re_errno
= ECONNRESET
;
712 ct
->ct_error
.re_status
= RPC_CANTRECV
;
713 len
= -1; /* it's really an error */
717 ct
->ct_error
.re_errno
= errno
;
718 ct
->ct_error
.re_status
= RPC_CANTRECV
;
725 write_vc(ctp
, buf
, len
)
730 struct ct_data
*ct
= (struct ct_data
*)(void *)ctp
;
733 for (cnt
= len
; cnt
> 0; cnt
-= i
, buf
+= i
) {
734 if ((i
= write(ct
->ct_fd
, buf
, (size_t)cnt
)) == -1) {
735 ct
->ct_error
.re_errno
= errno
;
736 ct
->ct_error
.re_status
= RPC_CANTSEND
;
743 static struct clnt_ops
*
746 static struct clnt_ops ops
;
748 extern mutex_t ops_lock
;
753 /* VARIABLES PROTECTED BY ops_lock: ops */
755 sigfillset(&newmask
);
756 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
757 mutex_lock(&ops_lock
);
758 if (ops
.cl_call
== NULL
) {
759 ops
.cl_call
= clnt_vc_call
;
760 ops
.cl_abort
= clnt_vc_abort
;
761 ops
.cl_geterr
= clnt_vc_geterr
;
762 ops
.cl_freeres
= clnt_vc_freeres
;
763 ops
.cl_destroy
= clnt_vc_destroy
;
764 ops
.cl_control
= clnt_vc_control
;
766 mutex_unlock(&ops_lock
);
767 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
772 * Make sure that the time is not garbage. -1 value is disallowed.
773 * Note this is different from time_not_ok in clnt_dg.c
780 _DIAGASSERT(t
!= NULL
);
782 return (t
->tv_sec
<= -1 || t
->tv_sec
> 100000000 ||
783 t
->tv_usec
<= -1 || t
->tv_usec
> 1000000);