1 /* $NetBSD: clnt_dg.c,v 1.4 2000/07/14 08:40:41 fvdl 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 * Copyright (c) 1986-1991 by Sun Microsystems Inc.
35 #if defined(LIBC_SCCS) && !defined(lint)
36 #ident "@(#)clnt_dg.c 1.23 94/04/22 SMI"
37 static char sccsid[] = "@(#)clnt_dg.c 1.19 89/03/16 Copyr 1988 Sun Micro";
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
43 * Implements a connectionless client side RPC.
46 #include "namespace.h"
47 #include "reentrant.h"
48 #include <sys/types.h>
49 #include <sys/event.h>
51 #include <sys/socket.h>
52 #include <sys/ioctl.h>
53 #include <arpa/inet.h>
61 #include "un-namespace.h"
66 #ifdef _FREEFALL_CONFIG
68 * Disable RPC exponential back-off for FreeBSD.org systems.
70 #define RPC_MAX_BACKOFF 1 /* second */
72 #define RPC_MAX_BACKOFF 30 /* seconds */
76 static struct clnt_ops *clnt_dg_ops(void);
77 static bool_t time_not_ok(struct timeval *);
78 static enum clnt_stat clnt_dg_call(CLIENT *, rpcproc_t, xdrproc_t, void *,
79 xdrproc_t, void *, struct timeval);
80 static void clnt_dg_geterr(CLIENT *, struct rpc_err *);
81 static bool_t clnt_dg_freeres(CLIENT *, xdrproc_t, void *);
82 static void clnt_dg_abort(CLIENT *);
83 static bool_t clnt_dg_control(CLIENT *, u_int, void *);
84 static void clnt_dg_destroy(CLIENT *);
90 * This machinery implements per-fd locks for MT-safety. It is not
91 * sufficient to do per-CLIENT handle locks for MT-safety because a
92 * user may create more than one CLIENT handle with the same fd behind
93 * it. Therfore, we allocate an array of flags (dg_fd_locks), protected
94 * by the clnt_fd_lock mutex, and an array (dg_cv) of condition variables
95 * similarly protected. Dg_fd_lock[fd] == 1 => a call is activte on some
96 * CLIENT handle created for that fd.
97 * The current implementation holds locks across the entire RPC and reply,
98 * including retransmissions. Yes, this is silly, and as soon as this
99 * code is proven to work, this should be the first thing fixed. One step
102 static int *dg_fd_locks;
103 static cond_t *dg_cv;
104 #define release_fd_lock(fd, mask) { \
105 mutex_lock(&clnt_fd_lock); \
106 dg_fd_locks[fd] = 0; \
107 mutex_unlock(&clnt_fd_lock); \
108 thr_sigsetmask(SIG_SETMASK, &(mask), NULL); \
109 cond_signal(&dg_cv[fd]); \
112 static const char mem_err_clnt_dg[] = "clnt_dg_create: out of memory";
114 /* VARIABLES PROTECTED BY clnt_fd_lock: dg_fd_locks, dg_cv */
117 * Private data kept per client handle
120 int cu_fd; /* connections fd */
121 bool_t cu_closeit; /* opened by library */
122 struct sockaddr_storage cu_raddr; /* remote address */
124 struct timeval cu_wait; /* retransmit interval */
125 struct timeval cu_total; /* total time for the call */
126 struct rpc_err cu_error;
129 u_int cu_sendsz; /* send size */
131 u_int cu_recvsz; /* recv size */
133 int cu_connect; /* Use connect(). */
134 int cu_connected; /* Have done connect(). */
135 struct kevent cu_kin;
141 * Connection less client creation returns with client handle parameters.
142 * Default options are set, which the user can change using clnt_control().
143 * fd should be open and bound.
144 * NB: The rpch->cl_auth is initialized to null authentication.
145 * Caller may wish to set this something more useful.
147 * sendsz and recvsz are the maximum allowable packet sizes that can be
148 * sent and received. Normally they are the same, but they can be
149 * changed to improve the program efficiency and buffer allocation.
150 * If they are 0, use the transport default.
152 * If svcaddr is NULL, returns NULL.
155 clnt_dg_create(fd, svcaddr, program, version, sendsz, recvsz)
156 int fd; /* open file descriptor */
157 const struct netbuf *svcaddr; /* servers address */
158 rpcprog_t program; /* program number */
159 rpcvers_t version; /* version number */
160 u_int sendsz; /* buffer recv size */
161 u_int recvsz; /* buffer send size */
163 CLIENT *cl = NULL; /* client handle */
164 struct cu_data *cu = NULL; /* private data */
166 struct rpc_msg call_msg;
169 struct __rpc_sockinfo si;
172 sigfillset(&newmask);
173 thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
174 mutex_lock(&clnt_fd_lock);
175 if (dg_fd_locks == (int *) NULL) {
178 int dtbsize = __rpc_dtbsize();
180 fd_allocsz = dtbsize * sizeof (int);
181 dg_fd_locks = (int *) mem_alloc(fd_allocsz);
182 if (dg_fd_locks == (int *) NULL) {
183 mutex_unlock(&clnt_fd_lock);
184 thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
187 memset(dg_fd_locks, '\0', fd_allocsz);
189 cv_allocsz = dtbsize * sizeof (cond_t);
190 dg_cv = (cond_t *) mem_alloc(cv_allocsz);
191 if (dg_cv == (cond_t *) NULL) {
192 mem_free(dg_fd_locks, fd_allocsz);
193 dg_fd_locks = (int *) NULL;
194 mutex_unlock(&clnt_fd_lock);
195 thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
200 for (i = 0; i < dtbsize; i++)
201 cond_init(&dg_cv[i], 0, (void *) 0);
205 mutex_unlock(&clnt_fd_lock);
206 thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
208 if (svcaddr == NULL) {
209 rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
213 if (!__rpc_fd2sockinfo(fd, &si)) {
214 rpc_createerr.cf_stat = RPC_TLIERROR;
215 rpc_createerr.cf_error.re_errno = 0;
219 * Find the receive and the send size
221 sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz);
222 recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz);
223 if ((sendsz == 0) || (recvsz == 0)) {
224 rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */
225 rpc_createerr.cf_error.re_errno = 0;
229 if ((cl = mem_alloc(sizeof (CLIENT))) == NULL)
232 * Should be multiple of 4 for XDR.
234 sendsz = ((sendsz + 3) / 4) * 4;
235 recvsz = ((recvsz + 3) / 4) * 4;
236 cu = mem_alloc(sizeof (*cu) + sendsz + recvsz);
239 (void) memcpy(&cu->cu_raddr, svcaddr->buf, (size_t)svcaddr->len);
240 cu->cu_rlen = svcaddr->len;
241 cu->cu_outbuf = &cu->cu_inbuf[recvsz];
242 /* Other values can also be set through clnt_control() */
243 cu->cu_wait.tv_sec = 15; /* heuristically chosen */
244 cu->cu_wait.tv_usec = 0;
245 cu->cu_total.tv_sec = -1;
246 cu->cu_total.tv_usec = -1;
247 cu->cu_sendsz = sendsz;
248 cu->cu_recvsz = recvsz;
249 cu->cu_async = FALSE;
250 cu->cu_connect = FALSE;
251 cu->cu_connected = FALSE;
252 (void) gettimeofday(&now, NULL);
253 call_msg.rm_xid = __RPC_GETXID(&now);
254 call_msg.rm_call.cb_prog = program;
255 call_msg.rm_call.cb_vers = version;
256 xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, sendsz, XDR_ENCODE);
257 if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) {
258 rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */
259 rpc_createerr.cf_error.re_errno = 0;
262 cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs));
264 /* XXX fvdl - do we still want this? */
266 (void)bindresvport_sa(fd, (struct sockaddr *)svcaddr->buf);
268 _ioctl(fd, FIONBIO, (char *)(void *)&one);
271 * By default, closeit is always FALSE. It is users responsibility
272 * to do a close on it, else the user may use clnt_control
273 * to let clnt_destroy do it for him/her.
275 cu->cu_closeit = FALSE;
277 cl->cl_ops = clnt_dg_ops();
278 cl->cl_private = (caddr_t)(void *)cu;
279 cl->cl_auth = authnone_create();
283 EV_SET(&cu->cu_kin, cu->cu_fd, EVFILT_READ, EV_ADD, 0, 0, 0);
286 warnx(mem_err_clnt_dg);
287 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
288 rpc_createerr.cf_error.re_errno = errno;
291 mem_free(cl, sizeof (CLIENT));
293 mem_free(cu, sizeof (*cu) + sendsz + recvsz);
298 static enum clnt_stat
299 clnt_dg_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout)
300 CLIENT *cl; /* client handle */
301 rpcproc_t proc; /* procedure number */
302 xdrproc_t xargs; /* xdr routine for args */
303 void *argsp; /* pointer to args */
304 xdrproc_t xresults; /* xdr routine for results */
305 void *resultsp; /* pointer to results */
306 struct timeval utimeout; /* seconds to wait before giving up */
308 struct cu_data *cu = (struct cu_data *)cl->cl_private;
311 struct rpc_msg reply_msg;
314 int nrefreshes = 2; /* number of times to refresh cred */
315 struct timeval timeout;
316 struct timeval retransmit_time;
317 struct timeval next_sendtime, starttime, time_waited, tv;
323 socklen_t inlen, salen;
325 int kin_len, n, rpc_lock_value;
329 sigfillset(&newmask);
330 thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
331 mutex_lock(&clnt_fd_lock);
332 while (dg_fd_locks[cu->cu_fd])
333 cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock);
338 dg_fd_locks[cu->cu_fd] = rpc_lock_value;
339 mutex_unlock(&clnt_fd_lock);
340 if (cu->cu_total.tv_usec == -1) {
341 timeout = utimeout; /* use supplied timeout */
343 timeout = cu->cu_total; /* use default timeout */
346 if (cu->cu_connect && !cu->cu_connected) {
347 if (_connect(cu->cu_fd, (struct sockaddr *)&cu->cu_raddr,
349 cu->cu_error.re_errno = errno;
350 cu->cu_error.re_status = RPC_CANTSEND;
353 cu->cu_connected = 1;
355 if (cu->cu_connected) {
359 sa = (struct sockaddr *)&cu->cu_raddr;
362 time_waited.tv_sec = 0;
363 time_waited.tv_usec = 0;
364 retransmit_time = next_sendtime = cu->cu_wait;
365 gettimeofday(&starttime, NULL);
367 /* Clean up in case the last call ended in a longjmp(3) call. */
370 if ((cu->cu_kq = kqueue()) < 0) {
371 cu->cu_error.re_errno = errno;
372 cu->cu_error.re_status = RPC_CANTSEND;
378 xdrs = &(cu->cu_outxdrs);
379 if (cu->cu_async == TRUE && xargs == NULL)
381 xdrs->x_op = XDR_ENCODE;
382 XDR_SETPOS(xdrs, cu->cu_xdrpos);
384 * the transaction is the first thing in the out buffer
385 * XXX Yes, and it's in network byte order, so we should to
386 * be careful when we increment it, shouldn't we.
388 xid = ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf));
390 *(u_int32_t *)(void *)(cu->cu_outbuf) = htonl(xid);
392 if ((! XDR_PUTINT32(xdrs, &proc)) ||
393 (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
394 (! (*xargs)(xdrs, argsp))) {
395 cu->cu_error.re_status = RPC_CANTENCODEARGS;
398 outlen = (size_t)XDR_GETPOS(xdrs);
401 if (_sendto(cu->cu_fd, cu->cu_outbuf, outlen, 0, sa, salen) != outlen) {
402 cu->cu_error.re_errno = errno;
403 cu->cu_error.re_status = RPC_CANTSEND;
408 * Hack to provide rpc-based message passing
410 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
411 cu->cu_error.re_status = RPC_TIMEDOUT;
418 * sub-optimal code appears here because we have
419 * some clock time to spare while the packets are in flight.
420 * (We assume that this is actually only executed once.)
422 reply_msg.acpted_rply.ar_verf = _null_auth;
423 reply_msg.acpted_rply.ar_results.where = resultsp;
424 reply_msg.acpted_rply.ar_results.proc = xresults;
427 /* Decide how long to wait. */
428 if (timercmp(&next_sendtime, &timeout, <))
429 timersub(&next_sendtime, &time_waited, &tv);
431 timersub(&timeout, &time_waited, &tv);
432 if (tv.tv_sec < 0 || tv.tv_usec < 0)
433 tv.tv_sec = tv.tv_usec = 0;
434 TIMEVAL_TO_TIMESPEC(&tv, &ts);
436 n = _kevent(cu->cu_kq, &cu->cu_kin, kin_len, &kv, 1, &ts);
437 /* We don't need to register the event again. */
441 if (kv.flags & EV_ERROR) {
442 cu->cu_error.re_errno = kv.data;
443 cu->cu_error.re_status = RPC_CANTRECV;
446 /* We have some data now */
448 recvlen = _recvfrom(cu->cu_fd, cu->cu_inbuf,
449 cu->cu_recvsz, 0, NULL, NULL);
450 } while (recvlen < 0 && errno == EINTR);
451 if (recvlen < 0 && errno != EWOULDBLOCK) {
452 cu->cu_error.re_errno = errno;
453 cu->cu_error.re_status = RPC_CANTRECV;
456 if (recvlen >= sizeof(u_int32_t) &&
457 (cu->cu_async == TRUE ||
458 *((u_int32_t *)(void *)(cu->cu_inbuf)) ==
459 *((u_int32_t *)(void *)(cu->cu_outbuf)))) {
460 /* We now assume we have the proper reply. */
464 if (n == -1 && errno != EINTR) {
465 cu->cu_error.re_errno = errno;
466 cu->cu_error.re_status = RPC_CANTRECV;
469 gettimeofday(&tv, NULL);
470 timersub(&tv, &starttime, &time_waited);
472 /* Check for timeout. */
473 if (timercmp(&time_waited, &timeout, >)) {
474 cu->cu_error.re_status = RPC_TIMEDOUT;
478 /* Retransmit if necessary. */
479 if (timercmp(&time_waited, &next_sendtime, >)) {
480 /* update retransmit_time */
481 if (retransmit_time.tv_sec < RPC_MAX_BACKOFF)
482 timeradd(&retransmit_time, &retransmit_time,
484 timeradd(&next_sendtime, &retransmit_time,
489 inlen = (socklen_t)recvlen;
492 * now decode and validate the response
495 xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)recvlen, XDR_DECODE);
496 ok = xdr_replymsg(&reply_xdrs, &reply_msg);
497 /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */
499 if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
500 (reply_msg.acpted_rply.ar_stat == SUCCESS))
501 cu->cu_error.re_status = RPC_SUCCESS;
503 _seterr_reply(&reply_msg, &(cu->cu_error));
505 if (cu->cu_error.re_status == RPC_SUCCESS) {
506 if (! AUTH_VALIDATE(cl->cl_auth,
507 &reply_msg.acpted_rply.ar_verf)) {
508 cu->cu_error.re_status = RPC_AUTHERROR;
509 cu->cu_error.re_why = AUTH_INVALIDRESP;
511 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
512 xdrs->x_op = XDR_FREE;
513 (void) xdr_opaque_auth(xdrs,
514 &(reply_msg.acpted_rply.ar_verf));
516 } /* end successful completion */
518 * If unsuccesful AND error is an authentication error
519 * then refresh credentials and try again, else break
521 else if (cu->cu_error.re_status == RPC_AUTHERROR)
522 /* maybe our credentials need to be refreshed ... */
523 if (nrefreshes > 0 &&
524 AUTH_REFRESH(cl->cl_auth, &reply_msg)) {
528 /* end of unsuccessful completion */
529 } /* end of valid reply message */
531 cu->cu_error.re_status = RPC_CANTDECODERES;
538 release_fd_lock(cu->cu_fd, mask);
539 return (cu->cu_error.re_status);
543 clnt_dg_geterr(cl, errp)
545 struct rpc_err *errp;
547 struct cu_data *cu = (struct cu_data *)cl->cl_private;
549 *errp = cu->cu_error;
553 clnt_dg_freeres(cl, xdr_res, res_ptr)
558 struct cu_data *cu = (struct cu_data *)cl->cl_private;
559 XDR *xdrs = &(cu->cu_outxdrs);
564 sigfillset(&newmask);
565 thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
566 mutex_lock(&clnt_fd_lock);
567 while (dg_fd_locks[cu->cu_fd])
568 cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock);
569 xdrs->x_op = XDR_FREE;
570 dummy = (*xdr_res)(xdrs, res_ptr);
571 mutex_unlock(&clnt_fd_lock);
572 thr_sigsetmask(SIG_SETMASK, &mask, NULL);
573 cond_signal(&dg_cv[cu->cu_fd]);
585 clnt_dg_control(cl, request, info)
590 struct cu_data *cu = (struct cu_data *)cl->cl_private;
596 sigfillset(&newmask);
597 thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
598 mutex_lock(&clnt_fd_lock);
599 while (dg_fd_locks[cu->cu_fd])
600 cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock);
605 dg_fd_locks[cu->cu_fd] = rpc_lock_value;
606 mutex_unlock(&clnt_fd_lock);
609 cu->cu_closeit = TRUE;
610 release_fd_lock(cu->cu_fd, mask);
612 case CLSET_FD_NCLOSE:
613 cu->cu_closeit = FALSE;
614 release_fd_lock(cu->cu_fd, mask);
618 /* for other requests which use info */
620 release_fd_lock(cu->cu_fd, mask);
625 if (time_not_ok((struct timeval *)info)) {
626 release_fd_lock(cu->cu_fd, mask);
629 cu->cu_total = *(struct timeval *)info;
632 *(struct timeval *)info = cu->cu_total;
634 case CLGET_SERVER_ADDR: /* Give him the fd address */
635 /* Now obsolete. Only for backward compatibility */
636 (void) memcpy(info, &cu->cu_raddr, (size_t)cu->cu_rlen);
638 case CLSET_RETRY_TIMEOUT:
639 if (time_not_ok((struct timeval *)info)) {
640 release_fd_lock(cu->cu_fd, mask);
643 cu->cu_wait = *(struct timeval *)info;
645 case CLGET_RETRY_TIMEOUT:
646 *(struct timeval *)info = cu->cu_wait;
649 *(int *)info = cu->cu_fd;
652 addr = (struct netbuf *)info;
653 addr->buf = &cu->cu_raddr;
654 addr->len = cu->cu_rlen;
655 addr->maxlen = sizeof cu->cu_raddr;
657 case CLSET_SVC_ADDR: /* set to new address */
658 addr = (struct netbuf *)info;
659 if (addr->len < sizeof cu->cu_raddr) {
660 release_fd_lock(cu->cu_fd, mask);
663 (void) memcpy(&cu->cu_raddr, addr->buf, addr->len);
664 cu->cu_rlen = addr->len;
668 * use the knowledge that xid is the
669 * first element in the call structure *.
670 * This will get the xid of the PREVIOUS call
673 ntohl(*(u_int32_t *)(void *)cu->cu_outbuf);
677 /* This will set the xid of the NEXT call */
678 *(u_int32_t *)(void *)cu->cu_outbuf =
679 htonl(*(u_int32_t *)info - 1);
680 /* decrement by 1 as clnt_dg_call() increments once */
685 * This RELIES on the information that, in the call body,
686 * the version number field is the fifth field from the
687 * begining of the RPC header. MUST be changed if the
688 * call_struct is changed
691 ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf +
692 4 * BYTES_PER_XDR_UNIT));
696 *(u_int32_t *)(void *)(cu->cu_outbuf + 4 * BYTES_PER_XDR_UNIT)
697 = htonl(*(u_int32_t *)info);
702 * This RELIES on the information that, in the call body,
703 * the program number field is the fourth field from the
704 * begining of the RPC header. MUST be changed if the
705 * call_struct is changed
708 ntohl(*(u_int32_t *)(void *)(cu->cu_outbuf +
709 3 * BYTES_PER_XDR_UNIT));
713 *(u_int32_t *)(void *)(cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT)
714 = htonl(*(u_int32_t *)info);
717 cu->cu_async = *(int *)info;
720 cu->cu_connect = *(int *)info;
723 release_fd_lock(cu->cu_fd, mask);
726 release_fd_lock(cu->cu_fd, mask);
734 struct cu_data *cu = (struct cu_data *)cl->cl_private;
735 int cu_fd = cu->cu_fd;
739 sigfillset(&newmask);
740 thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
741 mutex_lock(&clnt_fd_lock);
742 while (dg_fd_locks[cu_fd])
743 cond_wait(&dg_cv[cu_fd], &clnt_fd_lock);
748 XDR_DESTROY(&(cu->cu_outxdrs));
749 mem_free(cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz));
750 if (cl->cl_netid && cl->cl_netid[0])
751 mem_free(cl->cl_netid, strlen(cl->cl_netid) +1);
752 if (cl->cl_tp && cl->cl_tp[0])
753 mem_free(cl->cl_tp, strlen(cl->cl_tp) +1);
754 mem_free(cl, sizeof (CLIENT));
755 mutex_unlock(&clnt_fd_lock);
756 thr_sigsetmask(SIG_SETMASK, &mask, NULL);
757 cond_signal(&dg_cv[cu_fd]);
760 static struct clnt_ops *
763 static struct clnt_ops ops;
767 /* VARIABLES PROTECTED BY ops_lock: ops */
769 sigfillset(&newmask);
770 thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
771 mutex_lock(&ops_lock);
772 if (ops.cl_call == NULL) {
773 ops.cl_call = clnt_dg_call;
774 ops.cl_abort = clnt_dg_abort;
775 ops.cl_geterr = clnt_dg_geterr;
776 ops.cl_freeres = clnt_dg_freeres;
777 ops.cl_destroy = clnt_dg_destroy;
778 ops.cl_control = clnt_dg_control;
780 mutex_unlock(&ops_lock);
781 thr_sigsetmask(SIG_SETMASK, &mask, NULL);
786 * Make sure that the time is not garbage. -1 value is allowed.
792 return (t->tv_sec < -1 || t->tv_sec > 100000000 ||
793 t->tv_usec < -1 || t->tv_usec > 1000000);