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.
31 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
32 /* All Rights Reserved */
34 * Portions of this source code were derived from Berkeley
35 * 4.3 BSD under license from the Regents of the University of
39 * Copyright 2014 Shruti V Sampat <shrutisampat@gmail.com>
43 * Implements a connectionless client side RPC.
53 #include <sys/types.h>
54 #include <sys/kstat.h>
58 #include <sys/types.h>
63 extern int __rpc_timeval_to_msec(struct timeval
*);
64 extern bool_t
xdr_opaque_auth(XDR
*, struct opaque_auth
*);
65 extern bool_t
__rpc_gss_wrap(AUTH
*, char *, uint_t
, XDR
*, bool_t (*)(),
67 extern bool_t
__rpc_gss_unwrap(AUTH
*, XDR
*, bool_t (*)(), caddr_t
);
70 static struct clnt_ops
*clnt_dg_ops(void);
71 static bool_t
time_not_ok(struct timeval
*);
74 * This machinery implements per-fd locks for MT-safety. It is not
75 * sufficient to do per-CLIENT handle locks for MT-safety because a
76 * user may create more than one CLIENT handle with the same fd behind
79 * The current implementation holds locks across the entire RPC and reply,
80 * including retransmissions. Yes, this is silly, and as soon as this
81 * code is proven to work, this should be the first thing fixed. One step
86 * FD Lock handle used by various MT sync. routines
88 static mutex_t dgtbl_lock
= DEFAULTMUTEX
;
89 static void *dgtbl
= NULL
;
91 static const char mem_err_clnt_dg
[] = "clnt_dg_create: out of memory";
94 #define MCALL_MSG_SIZE 24
97 * Private data kept per client handle
100 int cu_fd
; /* connections fd */
101 bool_t cu_closeit
; /* opened by library */
102 struct netbuf cu_raddr
; /* remote address */
103 struct timeval cu_wait
; /* retransmit interval */
104 struct timeval cu_total
; /* total time for the call */
105 struct rpc_err cu_error
;
106 struct t_unitdata
*cu_tr_data
;
108 char *cu_outbuf_start
;
109 char cu_outbuf
[MCALL_MSG_SIZE
];
111 uint_t cu_sendsz
; /* send size */
112 uint_t cu_recvsz
; /* recv size */
117 static int _rcv_unitdata_err(struct cu_data
*cu
);
120 * Connection less client creation returns with client handle parameters.
121 * Default options are set, which the user can change using clnt_control().
122 * fd should be open and bound.
123 * NB: The rpch->cl_auth is initialized to null authentication.
124 * Caller may wish to set this something more useful.
126 * sendsz and recvsz are the maximum allowable packet sizes that can be
127 * sent and received. Normally they are the same, but they can be
128 * changed to improve the program efficiency and buffer allocation.
129 * If they are 0, use the transport default.
131 * If svcaddr is NULL, returns NULL.
134 clnt_dg_create(const int fd
, struct netbuf
*svcaddr
, const rpcprog_t program
,
135 const rpcvers_t version
, const uint_t sendsz
, const uint_t recvsz
)
137 CLIENT
*cl
= NULL
; /* client handle */
138 struct cu_data
*cu
= NULL
; /* private data */
139 struct t_unitdata
*tr_data
;
142 struct rpc_msg call_msg
;
146 sig_mutex_lock(&dgtbl_lock
);
147 if ((dgtbl
== NULL
) && ((dgtbl
= rpc_fd_init()) == NULL
)) {
148 sig_mutex_unlock(&dgtbl_lock
);
151 sig_mutex_unlock(&dgtbl_lock
);
153 if (svcaddr
== NULL
) {
154 rpc_createerr
.cf_stat
= RPC_UNKNOWNADDR
;
157 if (t_getinfo(fd
, &tinfo
) == -1) {
158 rpc_createerr
.cf_stat
= RPC_TLIERROR
;
159 rpc_createerr
.cf_error
.re_errno
= 0;
160 rpc_createerr
.cf_error
.re_terrno
= t_errno
;
164 * Setup to rcv datagram error, we ignore any errors returned from
165 * __rpc_tli_set_options() as SO_DGRAM_ERRIND is only relevant to
166 * udp/udp6 transports and this point in the code we only know that
167 * we are using a connection less transport.
169 if (tinfo
.servtype
== T_CLTS
)
170 (void) __rpc_tli_set_options(fd
, SOL_SOCKET
, SO_DGRAM_ERRIND
,
173 * Find the receive and the send size
175 ssz
= __rpc_get_t_size((int)sendsz
, tinfo
.tsdu
);
176 rsz
= __rpc_get_t_size((int)recvsz
, tinfo
.tsdu
);
177 if ((ssz
== 0) || (rsz
== 0)) {
178 rpc_createerr
.cf_stat
= RPC_TLIERROR
; /* XXX */
179 rpc_createerr
.cf_error
.re_errno
= 0;
180 rpc_createerr
.cf_error
.re_terrno
= 0;
184 if ((cl
= malloc(sizeof (CLIENT
))) == NULL
)
187 * Should be multiple of 4 for XDR.
189 ssz
= ((ssz
+ 3) / 4) * 4;
190 rsz
= ((rsz
+ 3) / 4) * 4;
191 cu
= malloc(sizeof (*cu
) + ssz
+ rsz
);
194 if ((cu
->cu_raddr
.buf
= malloc(svcaddr
->len
)) == NULL
)
196 (void) memcpy(cu
->cu_raddr
.buf
, svcaddr
->buf
, (size_t)svcaddr
->len
);
197 cu
->cu_raddr
.len
= cu
->cu_raddr
.maxlen
= svcaddr
->len
;
198 cu
->cu_outbuf_start
= &cu
->cu_inbuf
[rsz
];
199 /* Other values can also be set through clnt_control() */
200 cu
->cu_wait
.tv_sec
= 15; /* heuristically chosen */
201 cu
->cu_wait
.tv_usec
= 0;
202 cu
->cu_total
.tv_sec
= -1;
203 cu
->cu_total
.tv_usec
= -1;
206 (void) gettimeofday(&now
, NULL
);
207 call_msg
.rm_xid
= getpid() ^ now
.tv_sec
^ now
.tv_usec
;
208 call_msg
.rm_call
.cb_prog
= program
;
209 call_msg
.rm_call
.cb_vers
= version
;
210 xdrmem_create(&(cu
->cu_outxdrs
), cu
->cu_outbuf
, ssz
, XDR_ENCODE
);
211 if (!xdr_callhdr(&(cu
->cu_outxdrs
), &call_msg
)) {
212 rpc_createerr
.cf_stat
= RPC_CANTENCODEARGS
; /* XXX */
213 rpc_createerr
.cf_error
.re_errno
= 0;
214 rpc_createerr
.cf_error
.re_terrno
= 0;
217 cu
->cu_xdrpos
= XDR_GETPOS(&(cu
->cu_outxdrs
));
218 XDR_DESTROY(&(cu
->cu_outxdrs
));
219 xdrmem_create(&(cu
->cu_outxdrs
), cu
->cu_outbuf_start
, ssz
, XDR_ENCODE
);
220 /* LINTED pointer alignment */
221 tr_data
= (struct t_unitdata
*)t_alloc(fd
, T_UNITDATA
, T_ADDR
| T_OPT
);
222 if (tr_data
== NULL
) {
225 tr_data
->udata
.maxlen
= cu
->cu_recvsz
;
226 tr_data
->udata
.buf
= cu
->cu_inbuf
;
227 cu
->cu_tr_data
= tr_data
;
230 * By default, closeit is always FALSE. It is users responsibility
231 * to do a t_close on it, else the user may use clnt_control
232 * to let clnt_destroy do it for him/her.
234 cu
->cu_closeit
= FALSE
;
236 cl
->cl_ops
= clnt_dg_ops();
237 cl
->cl_private
= (caddr_t
)cu
;
238 cl
->cl_auth
= authnone_create();
241 cu
->pfdp
.fd
= cu
->cu_fd
;
242 cu
->pfdp
.events
= MASKVAL
;
245 (void) syslog(LOG_ERR
, mem_err_clnt_dg
);
246 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
247 rpc_createerr
.cf_error
.re_errno
= errno
;
248 rpc_createerr
.cf_error
.re_terrno
= 0;
253 free(cu
->cu_raddr
.buf
);
260 static enum clnt_stat
261 clnt_dg_call(CLIENT
*cl
, rpcproc_t proc
, xdrproc_t xargs
, caddr_t argsp
,
262 xdrproc_t xresults
, caddr_t resultsp
, struct timeval utimeout
)
264 /* LINTED pointer alignment */
265 struct cu_data
*cu
= (struct cu_data
*)cl
->cl_private
;
268 struct rpc_msg reply_msg
;
270 struct timeval time_waited
;
272 int nrefreshes
= 2; /* number of times to refresh cred */
273 struct timeval timeout
;
274 struct timeval retransmit_time
;
275 struct timeval poll_time
;
276 struct timeval startime
, curtime
;
277 struct t_unitdata tu_data
;
278 int res
; /* result of operations */
281 if (rpc_fd_lock(dgtbl
, cu
->cu_fd
)) {
282 rpc_callerr
.re_status
= RPC_FAILED
;
283 rpc_callerr
.re_errno
= errno
;
284 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
288 if (cu
->cu_total
.tv_usec
== -1) {
289 timeout
= utimeout
; /* use supplied timeout */
291 timeout
= cu
->cu_total
; /* use default timeout */
294 time_waited
.tv_sec
= 0;
295 time_waited
.tv_usec
= 0;
296 retransmit_time
= cu
->cu_wait
;
298 tu_data
.addr
= cu
->cu_raddr
;
301 xdrs
= &(cu
->cu_outxdrs
);
302 xdrs
->x_op
= XDR_ENCODE
;
305 * Due to little endian byte order, it is necessary to convert to host
306 * format before incrementing xid.
308 /* LINTED pointer cast */
309 x_id
= ntohl(*(uint32_t *)(cu
->cu_outbuf
)) + 1; /* set XID */
310 /* LINTED pointer cast */
311 *(uint32_t *)cu
->cu_outbuf
= htonl(x_id
);
313 if (cl
->cl_auth
->ah_cred
.oa_flavor
!= RPCSEC_GSS
) {
314 if ((!XDR_PUTBYTES(xdrs
, cu
->cu_outbuf
, cu
->cu_xdrpos
)) ||
315 (!XDR_PUTINT32(xdrs
, (int32_t *)&proc
)) ||
316 (!AUTH_MARSHALL(cl
->cl_auth
, xdrs
)) ||
317 (!xargs(xdrs
, argsp
))) {
318 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
319 return (rpc_callerr
.re_status
= RPC_CANTENCODEARGS
);
322 /* LINTED pointer alignment */
323 uint32_t *u
= (uint32_t *)&cu
->cu_outbuf
[cu
->cu_xdrpos
];
324 IXDR_PUT_U_INT32(u
, proc
);
325 if (!__rpc_gss_wrap(cl
->cl_auth
, cu
->cu_outbuf
,
326 ((char *)u
) - cu
->cu_outbuf
, xdrs
, xargs
, argsp
)) {
327 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
328 return (rpc_callerr
.re_status
= RPC_CANTENCODEARGS
);
331 outlen
= (int)XDR_GETPOS(xdrs
);
334 tu_data
.udata
.buf
= cu
->cu_outbuf_start
;
335 tu_data
.udata
.len
= outlen
;
337 if (t_sndudata(cu
->cu_fd
, &tu_data
) == -1) {
338 rpc_callerr
.re_terrno
= t_errno
;
339 rpc_callerr
.re_errno
= errno
;
340 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
341 return (rpc_callerr
.re_status
= RPC_CANTSEND
);
345 * Hack to provide rpc-based message passing
347 if (timeout
.tv_sec
== 0 && timeout
.tv_usec
== 0) {
348 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
349 return (rpc_callerr
.re_status
= RPC_TIMEDOUT
);
352 * sub-optimal code appears here because we have
353 * some clock time to spare while the packets are in flight.
354 * (We assume that this is actually only executed once.)
356 reply_msg
.acpted_rply
.ar_verf
= _null_auth
;
357 reply_msg
.acpted_rply
.ar_results
.where
= NULL
;
358 reply_msg
.acpted_rply
.ar_results
.proc
= xdr_void
;
361 * Set polling time so that we don't wait for
362 * longer than specified by the total time to wait,
363 * or the retransmit time.
365 poll_time
.tv_sec
= timeout
.tv_sec
- time_waited
.tv_sec
;
366 poll_time
.tv_usec
= timeout
.tv_usec
- time_waited
.tv_usec
;
367 while (poll_time
.tv_usec
< 0) {
368 poll_time
.tv_usec
+= 1000000;
372 if (poll_time
.tv_sec
< 0 || (poll_time
.tv_sec
== 0 &&
373 poll_time
.tv_usec
== 0)) {
375 * this could happen if time_waited >= timeout
377 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
378 return (rpc_callerr
.re_status
= RPC_TIMEDOUT
);
381 if (poll_time
.tv_sec
> retransmit_time
.tv_sec
||
382 (poll_time
.tv_sec
== retransmit_time
.tv_sec
&&
383 poll_time
.tv_usec
> retransmit_time
.tv_usec
))
384 poll_time
= retransmit_time
;
389 (void) gettimeofday(&startime
, NULL
);
391 switch (poll(&cu
->pfdp
, 1,
392 __rpc_timeval_to_msec(&poll_time
))) {
394 if (errno
!= EINTR
&& errno
!= EAGAIN
) {
395 rpc_callerr
.re_errno
= errno
;
396 rpc_callerr
.re_terrno
= 0;
397 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
398 return (rpc_callerr
.re_status
= RPC_CANTRECV
);
406 timeout
: (void) gettimeofday(&curtime
, NULL
);
407 time_waited
.tv_sec
+= curtime
.tv_sec
- startime
.tv_sec
;
408 time_waited
.tv_usec
+= curtime
.tv_usec
-
410 while (time_waited
.tv_usec
>= 1000000) {
411 time_waited
.tv_usec
-= 1000000;
412 time_waited
.tv_sec
++;
414 while (time_waited
.tv_usec
< 0) {
415 time_waited
.tv_usec
+= 1000000;
416 time_waited
.tv_sec
--;
420 * decrement time left to poll by same amount
422 poll_time
.tv_sec
-= curtime
.tv_sec
- startime
.tv_sec
;
423 poll_time
.tv_usec
-= curtime
.tv_usec
- startime
.tv_usec
;
424 while (poll_time
.tv_usec
>= 1000000) {
425 poll_time
.tv_usec
-= 1000000;
428 while (poll_time
.tv_usec
< 0) {
429 poll_time
.tv_usec
+= 1000000;
434 * if there's time left to poll, poll again
436 if (poll_time
.tv_sec
> 0 ||
437 (poll_time
.tv_sec
== 0 && poll_time
.tv_usec
> 0))
441 * if there's more time left, retransmit;
442 * otherwise, return timeout error
444 if (time_waited
.tv_sec
< timeout
.tv_sec
||
445 (time_waited
.tv_sec
== timeout
.tv_sec
&&
446 time_waited
.tv_usec
< timeout
.tv_usec
)) {
448 * update retransmit_time
450 retransmit_time
.tv_usec
*= 2;
451 retransmit_time
.tv_sec
*= 2;
452 while (retransmit_time
.tv_usec
>= 1000000) {
453 retransmit_time
.tv_usec
-= 1000000;
454 retransmit_time
.tv_sec
++;
456 if (retransmit_time
.tv_sec
>= RPC_MAX_BACKOFF
) {
457 retransmit_time
.tv_sec
=
459 retransmit_time
.tv_usec
= 0;
462 * redo AUTH_MARSHAL if AUTH_DES or RPCSEC_GSS.
464 if (cl
->cl_auth
->ah_cred
.oa_flavor
==
466 cl
->cl_auth
->ah_cred
.oa_flavor
==
472 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
473 return (rpc_callerr
.re_status
= RPC_TIMEDOUT
);
479 if (cu
->pfdp
.revents
& POLLNVAL
|| (cu
->pfdp
.revents
== 0)) {
480 rpc_callerr
.re_status
= RPC_CANTRECV
;
482 * Note: we're faking errno here because we
483 * previously would have expected select() to
484 * return -1 with errno EBADF. Poll(BA_OS)
485 * returns 0 and sets the POLLNVAL revents flag
488 rpc_callerr
.re_errno
= errno
= EBADF
;
489 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
493 /* We have some data now */
495 int moreflag
; /* flag indicating more data */
499 res
= t_rcvudata(cu
->cu_fd
, cu
->cu_tr_data
, &moreflag
);
501 if (moreflag
& T_MORE
) {
503 * Drop this packet. I aint got any
507 /* I should not really be doing this */
510 * XXX: Not really Buffer overflow in the
515 } while (res
< 0 && (t_errno
== TSYSERR
&& errno
== EINTR
));
517 int err
, errnoflag
= FALSE
;
519 if (t_errno
== TSYSERR
&& errno
== EWOULDBLOCK
)
521 if (t_errno
== TSYSERR
&& errno
== EAGAIN
)
524 if (t_errno
== TLOOK
) {
525 if ((err
= _rcv_unitdata_err(cu
)) == 0)
530 rpc_callerr
.re_terrno
= t_errno
;
532 if (errnoflag
== FALSE
)
533 rpc_callerr
.re_errno
= errno
;
534 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
535 return (rpc_callerr
.re_status
= RPC_CANTRECV
);
537 if (cu
->cu_tr_data
->udata
.len
< (uint_t
)sizeof (uint32_t))
539 /* see if reply transaction id matches sent id */
540 /* LINTED pointer alignment */
541 if (*((uint32_t *)(cu
->cu_inbuf
)) !=
542 /* LINTED pointer alignment */
543 *((uint32_t *)(cu
->cu_outbuf
)))
545 /* we now assume we have the proper reply */
550 * now decode and validate the response
553 xdrmem_create(&reply_xdrs
, cu
->cu_inbuf
,
554 (uint_t
)cu
->cu_tr_data
->udata
.len
, XDR_DECODE
);
555 ok
= xdr_replymsg(&reply_xdrs
, &reply_msg
);
556 /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */
558 if ((reply_msg
.rm_reply
.rp_stat
== MSG_ACCEPTED
) &&
559 (reply_msg
.acpted_rply
.ar_stat
== SUCCESS
))
560 rpc_callerr
.re_status
= RPC_SUCCESS
;
562 __seterr_reply(&reply_msg
, &(rpc_callerr
));
564 if (rpc_callerr
.re_status
== RPC_SUCCESS
) {
565 if (!AUTH_VALIDATE(cl
->cl_auth
,
566 &reply_msg
.acpted_rply
.ar_verf
)) {
567 rpc_callerr
.re_status
= RPC_AUTHERROR
;
568 rpc_callerr
.re_why
= AUTH_INVALIDRESP
;
569 } else if (cl
->cl_auth
->ah_cred
.oa_flavor
!=
571 if (!(*xresults
)(&reply_xdrs
, resultsp
)) {
572 if (rpc_callerr
.re_status
==
574 rpc_callerr
.re_status
=
577 } else if (!__rpc_gss_unwrap(cl
->cl_auth
, &reply_xdrs
,
578 xresults
, resultsp
)) {
579 if (rpc_callerr
.re_status
== RPC_SUCCESS
)
580 rpc_callerr
.re_status
=
583 } /* end successful completion */
585 * If unsuccesful AND error is an authentication error
586 * then refresh credentials and try again, else break
588 else if (rpc_callerr
.re_status
== RPC_AUTHERROR
)
589 /* maybe our credentials need to be refreshed ... */
591 AUTH_REFRESH(cl
->cl_auth
, &reply_msg
))
595 * We are setting rpc_callerr here given that
596 * libnsl is not reentrant thereby
597 * reinitializing the TSD. If not set here then
598 * success could be returned even though refresh
601 rpc_callerr
.re_status
= RPC_AUTHERROR
;
603 /* end of unsuccessful completion */
605 if (reply_msg
.rm_reply
.rp_stat
== MSG_ACCEPTED
&&
606 reply_msg
.acpted_rply
.ar_verf
.oa_base
!= NULL
) {
607 xdrs
->x_op
= XDR_FREE
;
608 (void) xdr_opaque_auth(xdrs
,
609 &(reply_msg
.acpted_rply
.ar_verf
));
611 } /* end of valid reply message */
613 rpc_callerr
.re_status
= RPC_CANTDECODERES
;
616 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
617 return (rpc_callerr
.re_status
);
620 static enum clnt_stat
621 clnt_dg_send(CLIENT
*cl
, rpcproc_t proc
, xdrproc_t xargs
, caddr_t argsp
)
623 /* LINTED pointer alignment */
624 struct cu_data
*cu
= (struct cu_data
*)cl
->cl_private
;
627 struct t_unitdata tu_data
;
630 if (rpc_fd_lock(dgtbl
, cu
->cu_fd
)) {
631 rpc_callerr
.re_status
= RPC_FAILED
;
632 rpc_callerr
.re_errno
= errno
;
633 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
637 tu_data
.addr
= cu
->cu_raddr
;
639 xdrs
= &(cu
->cu_outxdrs
);
640 xdrs
->x_op
= XDR_ENCODE
;
643 * Due to little endian byte order, it is necessary to convert to host
644 * format before incrementing xid.
646 /* LINTED pointer alignment */
647 x_id
= ntohl(*(uint32_t *)(cu
->cu_outbuf
)) + 1; /* set XID */
648 /* LINTED pointer cast */
649 *(uint32_t *)cu
->cu_outbuf
= htonl(x_id
);
651 if (cl
->cl_auth
->ah_cred
.oa_flavor
!= RPCSEC_GSS
) {
652 if ((!XDR_PUTBYTES(xdrs
, cu
->cu_outbuf
, cu
->cu_xdrpos
)) ||
653 (!XDR_PUTINT32(xdrs
, (int32_t *)&proc
)) ||
654 (!AUTH_MARSHALL(cl
->cl_auth
, xdrs
)) ||
655 (!xargs(xdrs
, argsp
))) {
656 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
657 return (rpc_callerr
.re_status
= RPC_CANTENCODEARGS
);
660 /* LINTED pointer alignment */
661 uint32_t *u
= (uint32_t *)&cu
->cu_outbuf
[cu
->cu_xdrpos
];
662 IXDR_PUT_U_INT32(u
, proc
);
663 if (!__rpc_gss_wrap(cl
->cl_auth
, cu
->cu_outbuf
,
664 ((char *)u
) - cu
->cu_outbuf
, xdrs
, xargs
, argsp
)) {
665 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
666 return (rpc_callerr
.re_status
= RPC_CANTENCODEARGS
);
669 outlen
= (int)XDR_GETPOS(xdrs
);
671 tu_data
.udata
.buf
= cu
->cu_outbuf_start
;
672 tu_data
.udata
.len
= outlen
;
674 if (t_sndudata(cu
->cu_fd
, &tu_data
) == -1) {
675 rpc_callerr
.re_terrno
= t_errno
;
676 rpc_callerr
.re_errno
= errno
;
677 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
678 return (rpc_callerr
.re_status
= RPC_CANTSEND
);
681 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
682 return (rpc_callerr
.re_status
= RPC_SUCCESS
);
686 clnt_dg_geterr(CLIENT
*cl
, struct rpc_err
*errp
)
693 clnt_dg_freeres(CLIENT
*cl
, xdrproc_t xdr_res
, caddr_t res_ptr
)
695 /* LINTED pointer alignment */
696 struct cu_data
*cu
= (struct cu_data
*)cl
->cl_private
;
697 XDR
*xdrs
= &(cu
->cu_outxdrs
);
700 (void) rpc_fd_lock(dgtbl
, cu
->cu_fd
);
701 xdrs
->x_op
= XDR_FREE
;
702 stat
= (*xdr_res
)(xdrs
, res_ptr
);
703 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
709 clnt_dg_abort(CLIENT
*h
)
714 clnt_dg_control(CLIENT
*cl
, int request
, char *info
)
716 /* LINTED pointer alignment */
717 struct cu_data
*cu
= (struct cu_data
*)cl
->cl_private
;
719 if (rpc_fd_lock(dgtbl
, cu
->cu_fd
)) {
720 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
726 cu
->cu_closeit
= TRUE
;
727 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
729 case CLSET_FD_NCLOSE
:
730 cu
->cu_closeit
= FALSE
;
731 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
735 /* for other requests which use info */
737 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
742 /* LINTED pointer alignment */
743 if (time_not_ok((struct timeval
*)info
)) {
744 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
747 /* LINTED pointer alignment */
748 cu
->cu_total
= *(struct timeval
*)info
;
751 /* LINTED pointer alignment */
752 *(struct timeval
*)info
= cu
->cu_total
;
754 case CLGET_SERVER_ADDR
: /* Give him the fd address */
755 /* Now obsolete. Only for backword compatibility */
756 (void) memcpy(info
, cu
->cu_raddr
.buf
, (size_t)cu
->cu_raddr
.len
);
758 case CLSET_RETRY_TIMEOUT
:
759 /* LINTED pointer alignment */
760 if (time_not_ok((struct timeval
*)info
)) {
761 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
764 /* LINTED pointer alignment */
765 cu
->cu_wait
= *(struct timeval
*)info
;
767 case CLGET_RETRY_TIMEOUT
:
768 /* LINTED pointer alignment */
769 *(struct timeval
*)info
= cu
->cu_wait
;
772 /* LINTED pointer alignment */
773 *(int *)info
= cu
->cu_fd
;
776 /* LINTED pointer alignment */
777 *(struct netbuf
*)info
= cu
->cu_raddr
;
779 case CLSET_SVC_ADDR
: /* set to new address */
780 /* LINTED pointer alignment */
781 addr
= (struct netbuf
*)info
;
782 if (cu
->cu_raddr
.maxlen
< addr
->len
) {
783 free(cu
->cu_raddr
.buf
);
784 if ((cu
->cu_raddr
.buf
= malloc(addr
->len
)) == NULL
) {
785 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
788 cu
->cu_raddr
.maxlen
= addr
->len
;
790 cu
->cu_raddr
.len
= addr
->len
;
791 (void) memcpy(cu
->cu_raddr
.buf
, addr
->buf
, addr
->len
);
795 * use the knowledge that xid is the
796 * first element in the call structure *.
797 * This will get the xid of the PREVIOUS call
799 /* LINTED pointer alignment */
800 *(uint32_t *)info
= ntohl(*(uint32_t *)cu
->cu_outbuf
);
804 /* This will set the xid of the NEXT call */
805 /* LINTED pointer alignment */
806 *(uint32_t *)cu
->cu_outbuf
= htonl(*(uint32_t *)info
- 1);
807 /* decrement by 1 as clnt_dg_call() increments once */
812 * This RELIES on the information that, in the call body,
813 * the version number field is the fifth field from the
814 * begining of the RPC header. MUST be changed if the
815 * call_struct is changed
817 /* LINTED pointer alignment */
818 *(uint32_t *)info
= ntohl(*(uint32_t *)(cu
->cu_outbuf
+
819 4 * BYTES_PER_XDR_UNIT
));
823 /* LINTED pointer alignment */
824 *(uint32_t *)(cu
->cu_outbuf
+ 4 * BYTES_PER_XDR_UNIT
) =
825 /* LINTED pointer alignment */
826 htonl(*(uint32_t *)info
);
831 * This RELIES on the information that, in the call body,
832 * the program number field is the fourth field from the
833 * begining of the RPC header. MUST be changed if the
834 * call_struct is changed
836 /* LINTED pointer alignment */
837 *(uint32_t *)info
= ntohl(*(uint32_t *)(cu
->cu_outbuf
+
838 3 * BYTES_PER_XDR_UNIT
));
842 /* LINTED pointer alignment */
843 *(uint32_t *)(cu
->cu_outbuf
+ 3 * BYTES_PER_XDR_UNIT
) =
844 /* LINTED pointer alignment */
845 htonl(*(uint32_t *)info
);
849 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
852 rpc_fd_unlock(dgtbl
, cu
->cu_fd
);
857 clnt_dg_destroy(CLIENT
*cl
)
859 /* LINTED pointer alignment */
860 struct cu_data
*cu
= (struct cu_data
*)cl
->cl_private
;
861 int cu_fd
= cu
->cu_fd
;
863 (void) rpc_fd_lock(dgtbl
, cu_fd
);
865 (void) t_close(cu_fd
);
866 XDR_DESTROY(&(cu
->cu_outxdrs
));
867 cu
->cu_tr_data
->udata
.buf
= NULL
;
868 (void) t_free((char *)cu
->cu_tr_data
, T_UNITDATA
);
869 free(cu
->cu_raddr
.buf
);
871 if (cl
->cl_netid
&& cl
->cl_netid
[0])
873 if (cl
->cl_tp
&& cl
->cl_tp
[0])
876 rpc_fd_unlock(dgtbl
, cu_fd
);
879 static struct clnt_ops
*
882 static struct clnt_ops ops
;
883 extern mutex_t ops_lock
;
885 /* VARIABLES PROTECTED BY ops_lock: ops */
887 sig_mutex_lock(&ops_lock
);
888 if (ops
.cl_call
== NULL
) {
889 ops
.cl_call
= clnt_dg_call
;
890 ops
.cl_send
= clnt_dg_send
;
891 ops
.cl_abort
= clnt_dg_abort
;
892 ops
.cl_geterr
= clnt_dg_geterr
;
893 ops
.cl_freeres
= clnt_dg_freeres
;
894 ops
.cl_destroy
= clnt_dg_destroy
;
895 ops
.cl_control
= clnt_dg_control
;
897 sig_mutex_unlock(&ops_lock
);
902 * Make sure that the time is not garbage. -1 value is allowed.
905 time_not_ok(struct timeval
*t
)
907 return (t
->tv_sec
< -1 || t
->tv_sec
> 100000000 ||
908 t
->tv_usec
< -1 || t
->tv_usec
> 1000000);
912 * Receive a unit data error indication.
913 * Below even when t_alloc() fails we pass uderr=NULL to t_rcvuderr()
914 * so as to just clear the error indication.
918 _rcv_unitdata_err(struct cu_data
*cu
)
921 struct t_uderr
*uderr
;
924 /* LINTED pointer cast */
925 uderr
= (struct t_uderr
*)t_alloc(cu
->cu_fd
, T_UDERROR
, T_ADDR
);
927 if (t_rcvuderr(cu
->cu_fd
, uderr
) == 0) {
931 if (uderr
->addr
.len
!= cu
->cu_raddr
.len
||
932 (memcmp(uderr
->addr
.buf
, cu
->cu_raddr
.buf
,
933 cu
->cu_raddr
.len
))) {
934 (void) t_free((char *)uderr
, T_UDERROR
);
937 rpc_callerr
.re_errno
= uderr
->error
;
938 rpc_callerr
.re_terrno
= TSYSERR
;
939 (void) t_free((char *)uderr
, T_UDERROR
);
942 rpc_callerr
.re_terrno
= old
;
944 (void) t_free((char *)uderr
, T_UDERROR
);