4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
28 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
29 * Copyright (c) 2016 by Delphix. All rights reserved.
32 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
33 /* All Rights Reserved */
35 * Portions of this source code were derived from Berkeley
36 * 4.3 BSD under license from the Regents of the University of
40 * Copyright 2014 Shruti V Sampat <shrutisampat@gmail.com>
44 * Implements a connectionless client side RPC.
54 #include <sys/types.h>
55 #include <sys/kstat.h>
59 #include <sys/types.h>
64 extern int __rpc_timeval_to_msec(struct timeval
*);
65 extern bool_t
xdr_opaque_auth(XDR
*, struct opaque_auth
*);
66 extern bool_t
__rpc_gss_wrap(AUTH
*, char *, uint_t
, XDR
*, bool_t (*)(),
68 extern bool_t
__rpc_gss_unwrap(AUTH
*, XDR
*, bool_t (*)(), caddr_t
);
71 static struct clnt_ops
*clnt_dg_ops(void);
72 static bool_t
time_not_ok(struct timeval
*);
75 * This machinery implements per-fd locks for MT-safety. It is not
76 * sufficient to do per-CLIENT handle locks for MT-safety because a
77 * user may create more than one CLIENT handle with the same fd behind
80 * The current implementation holds locks across the entire RPC and reply,
81 * including retransmissions. Yes, this is silly, and as soon as this
82 * code is proven to work, this should be the first thing fixed. One step
87 * FD Lock handle used by various MT sync. routines
89 static mutex_t dgtbl_lock
= DEFAULTMUTEX
;
90 static void *dgtbl
= NULL
;
92 static const char mem_err_clnt_dg
[] = "clnt_dg_create: out of memory";
95 #define MCALL_MSG_SIZE 24
98 * Private data kept per client handle
101 int cu_fd
; /* connections fd */
102 bool_t cu_closeit
; /* opened by library */
103 struct netbuf cu_raddr
; /* remote address */
104 struct timeval cu_wait
; /* retransmit interval */
105 struct timeval cu_total
; /* total time for the call */
106 struct rpc_err cu_error
;
107 struct t_unitdata
*cu_tr_data
;
109 char *cu_outbuf_start
;
110 char cu_outbuf
[MCALL_MSG_SIZE
];
112 uint_t cu_sendsz
; /* send size */
113 uint_t cu_recvsz
; /* recv size */
118 static int _rcv_unitdata_err(struct cu_data
*cu
);
121 * Connection less client creation returns with client handle parameters.
122 * Default options are set, which the user can change using clnt_control().
123 * fd should be open and bound.
124 * NB: The rpch->cl_auth is initialized to null authentication.
125 * Caller may wish to set this something more useful.
127 * sendsz and recvsz are the maximum allowable packet sizes that can be
128 * sent and received. Normally they are the same, but they can be
129 * changed to improve the program efficiency and buffer allocation.
130 * If they are 0, use the transport default.
132 * If svcaddr is NULL, returns NULL.
135 clnt_dg_create(const int fd
, struct netbuf
*svcaddr
, const rpcprog_t program
,
136 const rpcvers_t version
, const uint_t sendsz
, const uint_t recvsz
)
138 CLIENT
*cl
= NULL
; /* client handle */
139 struct cu_data
*cu
= NULL
; /* private data */
140 struct t_unitdata
*tr_data
;
143 struct rpc_msg call_msg
;
147 sig_mutex_lock(&dgtbl_lock
);
148 if ((dgtbl
== NULL
) && ((dgtbl
= rpc_fd_init()) == NULL
)) {
149 sig_mutex_unlock(&dgtbl_lock
);
152 sig_mutex_unlock(&dgtbl_lock
);
154 if (svcaddr
== NULL
) {
155 rpc_createerr
.cf_stat
= RPC_UNKNOWNADDR
;
158 if (t_getinfo(fd
, &tinfo
) == -1) {
159 rpc_createerr
.cf_stat
= RPC_TLIERROR
;
160 rpc_createerr
.cf_error
.re_errno
= 0;
161 rpc_createerr
.cf_error
.re_terrno
= t_errno
;
165 * Setup to rcv datagram error, we ignore any errors returned from
166 * __rpc_tli_set_options() as SO_DGRAM_ERRIND is only relevant to
167 * udp/udp6 transports and this point in the code we only know that
168 * we are using a connection less transport.
170 if (tinfo
.servtype
== T_CLTS
)
171 (void) __rpc_tli_set_options(fd
, SOL_SOCKET
, SO_DGRAM_ERRIND
,
174 * Find the receive and the send size
176 ssz
= __rpc_get_t_size((int)sendsz
, tinfo
.tsdu
);
177 rsz
= __rpc_get_t_size((int)recvsz
, tinfo
.tsdu
);
178 if ((ssz
== 0) || (rsz
== 0)) {
179 rpc_createerr
.cf_stat
= RPC_TLIERROR
; /* XXX */
180 rpc_createerr
.cf_error
.re_errno
= 0;
181 rpc_createerr
.cf_error
.re_terrno
= 0;
185 if ((cl
= malloc(sizeof (CLIENT
))) == NULL
)
188 * Should be multiple of 4 for XDR.
190 ssz
= ((ssz
+ 3) / 4) * 4;
191 rsz
= ((rsz
+ 3) / 4) * 4;
192 cu
= malloc(sizeof (*cu
) + ssz
+ rsz
);
195 if ((cu
->cu_raddr
.buf
= malloc(svcaddr
->len
)) == NULL
)
197 (void) memcpy(cu
->cu_raddr
.buf
, svcaddr
->buf
, (size_t)svcaddr
->len
);
198 cu
->cu_raddr
.len
= cu
->cu_raddr
.maxlen
= svcaddr
->len
;
199 cu
->cu_outbuf_start
= &cu
->cu_inbuf
[rsz
];
200 /* Other values can also be set through clnt_control() */
201 cu
->cu_wait
.tv_sec
= 15; /* heuristically chosen */
202 cu
->cu_wait
.tv_usec
= 0;
203 cu
->cu_total
.tv_sec
= -1;
204 cu
->cu_total
.tv_usec
= -1;
207 (void) gettimeofday(&now
, NULL
);
208 call_msg
.rm_xid
= getpid() ^ now
.tv_sec
^ now
.tv_usec
;
209 call_msg
.rm_call
.cb_prog
= program
;
210 call_msg
.rm_call
.cb_vers
= version
;
211 xdrmem_create(&(cu
->cu_outxdrs
), cu
->cu_outbuf
, ssz
, XDR_ENCODE
);
212 if (!xdr_callhdr(&(cu
->cu_outxdrs
), &call_msg
)) {
213 rpc_createerr
.cf_stat
= RPC_CANTENCODEARGS
; /* XXX */
214 rpc_createerr
.cf_error
.re_errno
= 0;
215 rpc_createerr
.cf_error
.re_terrno
= 0;
218 cu
->cu_xdrpos
= XDR_GETPOS(&(cu
->cu_outxdrs
));
219 XDR_DESTROY(&(cu
->cu_outxdrs
));
220 xdrmem_create(&(cu
->cu_outxdrs
), cu
->cu_outbuf_start
, ssz
, XDR_ENCODE
);
221 /* LINTED pointer alignment */
222 tr_data
= (struct t_unitdata
*)t_alloc(fd
, T_UNITDATA
, T_ADDR
| T_OPT
);
223 if (tr_data
== NULL
) {
226 tr_data
->udata
.maxlen
= cu
->cu_recvsz
;
227 tr_data
->udata
.buf
= cu
->cu_inbuf
;
228 cu
->cu_tr_data
= tr_data
;
231 * By default, closeit is always FALSE. It is users responsibility
232 * to do a t_close on it, else the user may use clnt_control
233 * to let clnt_destroy do it for them.
235 cu
->cu_closeit
= FALSE
;
237 cl
->cl_ops
= clnt_dg_ops();
238 cl
->cl_private
= (caddr_t
)cu
;
239 cl
->cl_auth
= authnone_create();
242 cu
->pfdp
.fd
= cu
->cu_fd
;
243 cu
->pfdp
.events
= MASKVAL
;
246 (void) syslog(LOG_ERR
, mem_err_clnt_dg
);
247 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
248 rpc_createerr
.cf_error
.re_errno
= errno
;
249 rpc_createerr
.cf_error
.re_terrno
= 0;
254 free(cu
->cu_raddr
.buf
);
261 static enum clnt_stat
262 clnt_dg_call(CLIENT
*cl
, rpcproc_t proc
, xdrproc_t xargs
, caddr_t argsp
,
263 xdrproc_t xresults
, caddr_t resultsp
, struct timeval utimeout
)
265 /* LINTED pointer alignment */
266 struct cu_data
*cu
= (struct cu_data
*)cl
->cl_private
;
269 struct rpc_msg reply_msg
;
271 struct timeval time_waited
;
273 int nrefreshes
= 2; /* number of times to refresh cred */
274 struct timeval timeout
;
275 struct timeval retransmit_time
;
276 struct timeval poll_time
;
277 struct timeval startime
, curtime
;
278 struct t_unitdata tu_data
;
279 int res
; /* result of operations */
282 if (rpc_fd_lock(dgtbl
, cu
->cu_fd
)) {
283 rpc_callerr
.re_status
= RPC_FAILED
;
284 rpc_callerr
.re_errno
= errno
;
285 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
289 if (cu
->cu_total
.tv_usec
== -1) {
290 timeout
= utimeout
; /* use supplied timeout */
292 timeout
= cu
->cu_total
; /* use default timeout */
295 time_waited
.tv_sec
= 0;
296 time_waited
.tv_usec
= 0;
297 retransmit_time
= cu
->cu_wait
;
299 tu_data
.addr
= cu
->cu_raddr
;
302 xdrs
= &(cu
->cu_outxdrs
);
303 xdrs
->x_op
= XDR_ENCODE
;
306 * Due to little endian byte order, it is necessary to convert to host
307 * format before incrementing xid.
309 /* LINTED pointer cast */
310 x_id
= ntohl(*(uint32_t *)(cu
->cu_outbuf
)) + 1; /* set XID */
311 /* LINTED pointer cast */
312 *(uint32_t *)cu
->cu_outbuf
= htonl(x_id
);
314 if (cl
->cl_auth
->ah_cred
.oa_flavor
!= RPCSEC_GSS
) {
315 if ((!XDR_PUTBYTES(xdrs
, cu
->cu_outbuf
, cu
->cu_xdrpos
)) ||
316 (!XDR_PUTINT32(xdrs
, (int32_t *)&proc
)) ||
317 (!AUTH_MARSHALL(cl
->cl_auth
, xdrs
)) ||
318 (!xargs(xdrs
, argsp
))) {
319 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
320 return (rpc_callerr
.re_status
= RPC_CANTENCODEARGS
);
323 /* LINTED pointer alignment */
324 uint32_t *u
= (uint32_t *)&cu
->cu_outbuf
[cu
->cu_xdrpos
];
325 IXDR_PUT_U_INT32(u
, proc
);
326 if (!__rpc_gss_wrap(cl
->cl_auth
, cu
->cu_outbuf
,
327 ((char *)u
) - cu
->cu_outbuf
, xdrs
, xargs
, argsp
)) {
328 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
329 return (rpc_callerr
.re_status
= RPC_CANTENCODEARGS
);
332 outlen
= (int)XDR_GETPOS(xdrs
);
335 tu_data
.udata
.buf
= cu
->cu_outbuf_start
;
336 tu_data
.udata
.len
= outlen
;
338 if (t_sndudata(cu
->cu_fd
, &tu_data
) == -1) {
339 rpc_callerr
.re_terrno
= t_errno
;
340 rpc_callerr
.re_errno
= errno
;
341 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
342 return (rpc_callerr
.re_status
= RPC_CANTSEND
);
346 * Hack to provide rpc-based message passing
348 if (timeout
.tv_sec
== 0 && timeout
.tv_usec
== 0) {
349 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
350 return (rpc_callerr
.re_status
= RPC_TIMEDOUT
);
353 * sub-optimal code appears here because we have
354 * some clock time to spare while the packets are in flight.
355 * (We assume that this is actually only executed once.)
357 reply_msg
.acpted_rply
.ar_verf
= _null_auth
;
358 reply_msg
.acpted_rply
.ar_results
.where
= NULL
;
359 reply_msg
.acpted_rply
.ar_results
.proc
= xdr_void
;
362 * Set polling time so that we don't wait for
363 * longer than specified by the total time to wait,
364 * or the retransmit time.
366 poll_time
.tv_sec
= timeout
.tv_sec
- time_waited
.tv_sec
;
367 poll_time
.tv_usec
= timeout
.tv_usec
- time_waited
.tv_usec
;
368 while (poll_time
.tv_usec
< 0) {
369 poll_time
.tv_usec
+= 1000000;
373 if (poll_time
.tv_sec
< 0 || (poll_time
.tv_sec
== 0 &&
374 poll_time
.tv_usec
== 0)) {
376 * this could happen if time_waited >= timeout
378 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
379 return (rpc_callerr
.re_status
= RPC_TIMEDOUT
);
382 if (poll_time
.tv_sec
> retransmit_time
.tv_sec
||
383 (poll_time
.tv_sec
== retransmit_time
.tv_sec
&&
384 poll_time
.tv_usec
> retransmit_time
.tv_usec
))
385 poll_time
= retransmit_time
;
390 (void) gettimeofday(&startime
, NULL
);
392 switch (poll(&cu
->pfdp
, 1,
393 __rpc_timeval_to_msec(&poll_time
))) {
395 if (errno
!= EINTR
&& errno
!= EAGAIN
) {
396 rpc_callerr
.re_errno
= errno
;
397 rpc_callerr
.re_terrno
= 0;
398 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
399 return (rpc_callerr
.re_status
= RPC_CANTRECV
);
407 timeout
: (void) gettimeofday(&curtime
, NULL
);
408 time_waited
.tv_sec
+= curtime
.tv_sec
- startime
.tv_sec
;
409 time_waited
.tv_usec
+= curtime
.tv_usec
-
411 while (time_waited
.tv_usec
>= 1000000) {
412 time_waited
.tv_usec
-= 1000000;
413 time_waited
.tv_sec
++;
415 while (time_waited
.tv_usec
< 0) {
416 time_waited
.tv_usec
+= 1000000;
417 time_waited
.tv_sec
--;
421 * decrement time left to poll by same amount
423 poll_time
.tv_sec
-= curtime
.tv_sec
- startime
.tv_sec
;
424 poll_time
.tv_usec
-= curtime
.tv_usec
- startime
.tv_usec
;
425 while (poll_time
.tv_usec
>= 1000000) {
426 poll_time
.tv_usec
-= 1000000;
429 while (poll_time
.tv_usec
< 0) {
430 poll_time
.tv_usec
+= 1000000;
435 * if there's time left to poll, poll again
437 if (poll_time
.tv_sec
> 0 ||
438 (poll_time
.tv_sec
== 0 && poll_time
.tv_usec
> 0))
442 * if there's more time left, retransmit;
443 * otherwise, return timeout error
445 if (time_waited
.tv_sec
< timeout
.tv_sec
||
446 (time_waited
.tv_sec
== timeout
.tv_sec
&&
447 time_waited
.tv_usec
< timeout
.tv_usec
)) {
449 * update retransmit_time
451 retransmit_time
.tv_usec
*= 2;
452 retransmit_time
.tv_sec
*= 2;
453 while (retransmit_time
.tv_usec
>= 1000000) {
454 retransmit_time
.tv_usec
-= 1000000;
455 retransmit_time
.tv_sec
++;
457 if (retransmit_time
.tv_sec
>= RPC_MAX_BACKOFF
) {
458 retransmit_time
.tv_sec
=
460 retransmit_time
.tv_usec
= 0;
463 * redo AUTH_MARSHAL if AUTH_DES or RPCSEC_GSS.
465 if (cl
->cl_auth
->ah_cred
.oa_flavor
==
467 cl
->cl_auth
->ah_cred
.oa_flavor
==
473 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
474 return (rpc_callerr
.re_status
= RPC_TIMEDOUT
);
480 if (cu
->pfdp
.revents
& POLLNVAL
|| (cu
->pfdp
.revents
== 0)) {
481 rpc_callerr
.re_status
= RPC_CANTRECV
;
483 * Note: we're faking errno here because we
484 * previously would have expected select() to
485 * return -1 with errno EBADF. Poll(BA_OS)
486 * returns 0 and sets the POLLNVAL revents flag
489 rpc_callerr
.re_errno
= errno
= EBADF
;
490 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
494 /* We have some data now */
496 int moreflag
; /* flag indicating more data */
500 res
= t_rcvudata(cu
->cu_fd
, cu
->cu_tr_data
, &moreflag
);
502 if (moreflag
& T_MORE
) {
504 * Drop this packet. I aint got any
508 /* I should not really be doing this */
511 * XXX: Not really Buffer overflow in the
516 } while (res
< 0 && (t_errno
== TSYSERR
&& errno
== EINTR
));
518 int err
, errnoflag
= FALSE
;
520 if (t_errno
== TSYSERR
&& errno
== EWOULDBLOCK
)
522 if (t_errno
== TSYSERR
&& errno
== EAGAIN
)
525 if (t_errno
== TLOOK
) {
526 if ((err
= _rcv_unitdata_err(cu
)) == 0)
531 rpc_callerr
.re_terrno
= t_errno
;
533 if (errnoflag
== FALSE
)
534 rpc_callerr
.re_errno
= errno
;
535 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
536 return (rpc_callerr
.re_status
= RPC_CANTRECV
);
538 if (cu
->cu_tr_data
->udata
.len
< (uint_t
)sizeof (uint32_t))
540 /* see if reply transaction id matches sent id */
541 /* LINTED pointer alignment */
542 if (*((uint32_t *)(cu
->cu_inbuf
)) !=
543 /* LINTED pointer alignment */
544 *((uint32_t *)(cu
->cu_outbuf
)))
546 /* we now assume we have the proper reply */
551 * now decode and validate the response
554 xdrmem_create(&reply_xdrs
, cu
->cu_inbuf
,
555 (uint_t
)cu
->cu_tr_data
->udata
.len
, XDR_DECODE
);
556 ok
= xdr_replymsg(&reply_xdrs
, &reply_msg
);
557 /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */
559 if ((reply_msg
.rm_reply
.rp_stat
== MSG_ACCEPTED
) &&
560 (reply_msg
.acpted_rply
.ar_stat
== SUCCESS
))
561 rpc_callerr
.re_status
= RPC_SUCCESS
;
563 __seterr_reply(&reply_msg
, &(rpc_callerr
));
565 if (rpc_callerr
.re_status
== RPC_SUCCESS
) {
566 if (!AUTH_VALIDATE(cl
->cl_auth
,
567 &reply_msg
.acpted_rply
.ar_verf
)) {
568 rpc_callerr
.re_status
= RPC_AUTHERROR
;
569 rpc_callerr
.re_why
= AUTH_INVALIDRESP
;
570 } else if (cl
->cl_auth
->ah_cred
.oa_flavor
!=
572 if (!(*xresults
)(&reply_xdrs
, resultsp
)) {
573 if (rpc_callerr
.re_status
==
575 rpc_callerr
.re_status
=
578 } else if (!__rpc_gss_unwrap(cl
->cl_auth
, &reply_xdrs
,
579 xresults
, resultsp
)) {
580 if (rpc_callerr
.re_status
== RPC_SUCCESS
)
581 rpc_callerr
.re_status
=
584 } /* end successful completion */
586 * If unsuccesful AND error is an authentication error
587 * then refresh credentials and try again, else break
589 else if (rpc_callerr
.re_status
== RPC_AUTHERROR
)
590 /* maybe our credentials need to be refreshed ... */
592 AUTH_REFRESH(cl
->cl_auth
, &reply_msg
))
596 * We are setting rpc_callerr here given that
597 * libnsl is not reentrant thereby
598 * reinitializing the TSD. If not set here then
599 * success could be returned even though refresh
602 rpc_callerr
.re_status
= RPC_AUTHERROR
;
604 /* end of unsuccessful completion */
606 if (reply_msg
.rm_reply
.rp_stat
== MSG_ACCEPTED
&&
607 reply_msg
.acpted_rply
.ar_verf
.oa_base
!= NULL
) {
608 xdrs
->x_op
= XDR_FREE
;
609 (void) xdr_opaque_auth(xdrs
,
610 &(reply_msg
.acpted_rply
.ar_verf
));
612 } /* end of valid reply message */
614 rpc_callerr
.re_status
= RPC_CANTDECODERES
;
617 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
618 return (rpc_callerr
.re_status
);
621 static enum clnt_stat
622 clnt_dg_send(CLIENT
*cl
, rpcproc_t proc
, xdrproc_t xargs
, caddr_t argsp
)
624 /* LINTED pointer alignment */
625 struct cu_data
*cu
= (struct cu_data
*)cl
->cl_private
;
628 struct t_unitdata tu_data
;
631 if (rpc_fd_lock(dgtbl
, cu
->cu_fd
)) {
632 rpc_callerr
.re_status
= RPC_FAILED
;
633 rpc_callerr
.re_errno
= errno
;
634 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
638 tu_data
.addr
= cu
->cu_raddr
;
640 xdrs
= &(cu
->cu_outxdrs
);
641 xdrs
->x_op
= XDR_ENCODE
;
644 * Due to little endian byte order, it is necessary to convert to host
645 * format before incrementing xid.
647 /* LINTED pointer alignment */
648 x_id
= ntohl(*(uint32_t *)(cu
->cu_outbuf
)) + 1; /* set XID */
649 /* LINTED pointer cast */
650 *(uint32_t *)cu
->cu_outbuf
= htonl(x_id
);
652 if (cl
->cl_auth
->ah_cred
.oa_flavor
!= RPCSEC_GSS
) {
653 if ((!XDR_PUTBYTES(xdrs
, cu
->cu_outbuf
, cu
->cu_xdrpos
)) ||
654 (!XDR_PUTINT32(xdrs
, (int32_t *)&proc
)) ||
655 (!AUTH_MARSHALL(cl
->cl_auth
, xdrs
)) ||
656 (!xargs(xdrs
, argsp
))) {
657 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
658 return (rpc_callerr
.re_status
= RPC_CANTENCODEARGS
);
661 /* LINTED pointer alignment */
662 uint32_t *u
= (uint32_t *)&cu
->cu_outbuf
[cu
->cu_xdrpos
];
663 IXDR_PUT_U_INT32(u
, proc
);
664 if (!__rpc_gss_wrap(cl
->cl_auth
, cu
->cu_outbuf
,
665 ((char *)u
) - cu
->cu_outbuf
, xdrs
, xargs
, argsp
)) {
666 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
667 return (rpc_callerr
.re_status
= RPC_CANTENCODEARGS
);
670 outlen
= (int)XDR_GETPOS(xdrs
);
672 tu_data
.udata
.buf
= cu
->cu_outbuf_start
;
673 tu_data
.udata
.len
= outlen
;
675 if (t_sndudata(cu
->cu_fd
, &tu_data
) == -1) {
676 rpc_callerr
.re_terrno
= t_errno
;
677 rpc_callerr
.re_errno
= errno
;
678 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
679 return (rpc_callerr
.re_status
= RPC_CANTSEND
);
682 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
683 return (rpc_callerr
.re_status
= RPC_SUCCESS
);
687 clnt_dg_geterr(CLIENT
*cl
, struct rpc_err
*errp
)
694 clnt_dg_freeres(CLIENT
*cl
, xdrproc_t xdr_res
, caddr_t res_ptr
)
696 /* LINTED pointer alignment */
697 struct cu_data
*cu
= (struct cu_data
*)cl
->cl_private
;
698 XDR
*xdrs
= &(cu
->cu_outxdrs
);
701 (void) rpc_fd_lock(dgtbl
, cu
->cu_fd
);
702 xdrs
->x_op
= XDR_FREE
;
703 stat
= (*xdr_res
)(xdrs
, res_ptr
);
704 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
710 clnt_dg_abort(CLIENT
*h
)
715 clnt_dg_control(CLIENT
*cl
, int request
, char *info
)
717 /* LINTED pointer alignment */
718 struct cu_data
*cu
= (struct cu_data
*)cl
->cl_private
;
720 if (rpc_fd_lock(dgtbl
, cu
->cu_fd
)) {
721 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
727 cu
->cu_closeit
= TRUE
;
728 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
730 case CLSET_FD_NCLOSE
:
731 cu
->cu_closeit
= FALSE
;
732 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
736 /* for other requests which use info */
738 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
743 /* LINTED pointer alignment */
744 if (time_not_ok((struct timeval
*)info
)) {
745 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
748 /* LINTED pointer alignment */
749 cu
->cu_total
= *(struct timeval
*)info
;
752 /* LINTED pointer alignment */
753 *(struct timeval
*)info
= cu
->cu_total
;
755 case CLGET_SERVER_ADDR
: /* Give it the fd address */
756 /* Now obsolete. Only for backword compatibility */
757 (void) memcpy(info
, cu
->cu_raddr
.buf
, (size_t)cu
->cu_raddr
.len
);
759 case CLSET_RETRY_TIMEOUT
:
760 /* LINTED pointer alignment */
761 if (time_not_ok((struct timeval
*)info
)) {
762 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
765 /* LINTED pointer alignment */
766 cu
->cu_wait
= *(struct timeval
*)info
;
768 case CLGET_RETRY_TIMEOUT
:
769 /* LINTED pointer alignment */
770 *(struct timeval
*)info
= cu
->cu_wait
;
773 /* LINTED pointer alignment */
774 *(int *)info
= cu
->cu_fd
;
777 /* LINTED pointer alignment */
778 *(struct netbuf
*)info
= cu
->cu_raddr
;
780 case CLSET_SVC_ADDR
: /* set to new address */
781 /* LINTED pointer alignment */
782 addr
= (struct netbuf
*)info
;
783 if (cu
->cu_raddr
.maxlen
< addr
->len
) {
784 free(cu
->cu_raddr
.buf
);
785 if ((cu
->cu_raddr
.buf
= malloc(addr
->len
)) == NULL
) {
786 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
789 cu
->cu_raddr
.maxlen
= addr
->len
;
791 cu
->cu_raddr
.len
= addr
->len
;
792 (void) memcpy(cu
->cu_raddr
.buf
, addr
->buf
, addr
->len
);
796 * use the knowledge that xid is the
797 * first element in the call structure *.
798 * This will get the xid of the PREVIOUS call
800 /* LINTED pointer alignment */
801 *(uint32_t *)info
= ntohl(*(uint32_t *)cu
->cu_outbuf
);
805 /* This will set the xid of the NEXT call */
806 /* LINTED pointer alignment */
807 *(uint32_t *)cu
->cu_outbuf
= htonl(*(uint32_t *)info
- 1);
808 /* decrement by 1 as clnt_dg_call() increments once */
813 * This RELIES on the information that, in the call body,
814 * the version number field is the fifth field from the
815 * begining of the RPC header. MUST be changed if the
816 * call_struct is changed
818 /* LINTED pointer alignment */
819 *(uint32_t *)info
= ntohl(*(uint32_t *)(cu
->cu_outbuf
+
820 4 * BYTES_PER_XDR_UNIT
));
824 /* LINTED pointer alignment */
825 *(uint32_t *)(cu
->cu_outbuf
+ 4 * BYTES_PER_XDR_UNIT
) =
826 /* LINTED pointer alignment */
827 htonl(*(uint32_t *)info
);
832 * This RELIES on the information that, in the call body,
833 * the program number field is the fourth field from the
834 * begining of the RPC header. MUST be changed if the
835 * call_struct is changed
837 /* LINTED pointer alignment */
838 *(uint32_t *)info
= ntohl(*(uint32_t *)(cu
->cu_outbuf
+
839 3 * BYTES_PER_XDR_UNIT
));
843 /* LINTED pointer alignment */
844 *(uint32_t *)(cu
->cu_outbuf
+ 3 * BYTES_PER_XDR_UNIT
) =
845 /* LINTED pointer alignment */
846 htonl(*(uint32_t *)info
);
850 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
853 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
858 clnt_dg_destroy(CLIENT
*cl
)
860 /* LINTED pointer alignment */
861 struct cu_data
*cu
= (struct cu_data
*)cl
->cl_private
;
862 int cu_fd
= cu
->cu_fd
;
864 (void) rpc_fd_lock(dgtbl
, cu_fd
);
866 (void) t_close(cu_fd
);
867 XDR_DESTROY(&(cu
->cu_outxdrs
));
868 cu
->cu_tr_data
->udata
.buf
= NULL
;
869 (void) t_free((char *)cu
->cu_tr_data
, T_UNITDATA
);
870 free(cu
->cu_raddr
.buf
);
872 if (cl
->cl_netid
&& cl
->cl_netid
[0])
874 if (cl
->cl_tp
&& cl
->cl_tp
[0])
877 rpc_fd_unlock(dgtbl
, cu_fd
);
880 static struct clnt_ops
*
883 static struct clnt_ops ops
;
884 extern mutex_t ops_lock
;
886 /* VARIABLES PROTECTED BY ops_lock: ops */
888 sig_mutex_lock(&ops_lock
);
889 if (ops
.cl_call
== NULL
) {
890 ops
.cl_call
= clnt_dg_call
;
891 ops
.cl_send
= clnt_dg_send
;
892 ops
.cl_abort
= clnt_dg_abort
;
893 ops
.cl_geterr
= clnt_dg_geterr
;
894 ops
.cl_freeres
= clnt_dg_freeres
;
895 ops
.cl_destroy
= clnt_dg_destroy
;
896 ops
.cl_control
= clnt_dg_control
;
898 sig_mutex_unlock(&ops_lock
);
903 * Make sure that the time is not garbage. -1 value is allowed.
906 time_not_ok(struct timeval
*t
)
908 return (t
->tv_sec
< -1 || t
->tv_sec
> 100000000 ||
909 t
->tv_usec
< -1 || t
->tv_usec
> 1000000);
913 * Receive a unit data error indication.
914 * Below even when t_alloc() fails we pass uderr=NULL to t_rcvuderr()
915 * so as to just clear the error indication.
919 _rcv_unitdata_err(struct cu_data
*cu
)
922 struct t_uderr
*uderr
;
925 /* LINTED pointer cast */
926 uderr
= (struct t_uderr
*)t_alloc(cu
->cu_fd
, T_UDERROR
, T_ADDR
);
928 if (t_rcvuderr(cu
->cu_fd
, uderr
) == 0) {
932 if (uderr
->addr
.len
!= cu
->cu_raddr
.len
||
933 (memcmp(uderr
->addr
.buf
, cu
->cu_raddr
.buf
,
934 cu
->cu_raddr
.len
))) {
935 (void) t_free((char *)uderr
, T_UDERROR
);
938 rpc_callerr
.re_errno
= uderr
->error
;
939 rpc_callerr
.re_terrno
= TSYSERR
;
940 (void) t_free((char *)uderr
, T_UDERROR
);
943 rpc_callerr
.re_terrno
= old
;
945 (void) t_free((char *)uderr
, T_UDERROR
);