2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3 * unrestricted use provided that this legend is included on all tape
4 * media and as a part of the software program in whole or part. Users
5 * may copy or modify Sun RPC without charge, but are not authorized
6 * to license or distribute it to anyone else except as part of a product or
7 * program developed by the user.
9 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
13 * Sun RPC is provided with no support and without any obligation on the
14 * part of Sun Microsystems, Inc. to assist in its use, correction,
15 * modification or enhancement.
17 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19 * OR ANY PART THEREOF.
21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22 * or profits or other special, indirect and consequential damages, even if
23 * Sun has been advised of the possibility of such damages.
25 * Sun Microsystems, Inc.
27 * Mountain View, California 94043
28 * @(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro; 2.2 88/08/01 4.0 RPCSRC
29 * @(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro
30 * $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $
31 * $FreeBSD: src/lib/libc/rpc/clnt_vc.c,v 1.20 2006/09/09 22:18:57 mbr Exp $
36 * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
38 * Copyright (C) 1984, Sun Microsystems, Inc.
40 * TCP based RPC supports 'batched calls'.
41 * A sequence of calls may be batched-up in a send buffer. The rpc call
42 * return immediately to the client even though the call was not necessarily
43 * sent. The batching occurs if the results' xdr routine is NULL (0) AND
44 * the rpc timeout value is zero (see clnt.h, rpc).
46 * Clients should NOT casually batch calls that in fact return results; that is,
47 * the server side should be aware that a call is batched and not produce any
48 * return message. Batched calls that produce many result messages can
49 * deadlock (netlock) the client and the server....
51 * Now go hang yourself.
54 #include "namespace.h"
55 #include "reentrant.h"
56 #include <sys/types.h>
58 #include <sys/syslog.h>
59 #include <sys/socket.h>
63 #include <arpa/inet.h>
75 #include "un-namespace.h"
79 #define MCALL_MSG_SIZE 24
83 struct cmsgcred cmcred
;
86 static void clnt_vc_abort(CLIENT
*);
87 static enum clnt_stat
clnt_vc_call(CLIENT
*, rpcproc_t
, xdrproc_t
, void *,
88 xdrproc_t
, void *, struct timeval
);
89 static bool_t
clnt_vc_control(CLIENT
*, u_int
, void *);
90 static void clnt_vc_destroy(CLIENT
*);
91 static bool_t
clnt_vc_freeres(CLIENT
*, xdrproc_t
, void *);
92 static void clnt_vc_geterr(CLIENT
*, struct rpc_err
*);
93 static struct clnt_ops
*clnt_vc_ops(void);
94 static int __msgread(int, void *, size_t);
95 static int __msgwrite(int, void *, size_t);
96 static int read_vc(void *, void *, int);
97 static bool_t
time_not_ok(struct timeval
*);
98 static int write_vc(void *, void *, int);
101 int ct_fd
; /* connection's fd */
102 bool_t ct_closeit
; /* close it on destroy */
103 struct timeval ct_wait
; /* wait interval in milliseconds */
104 bool_t ct_waitset
; /* wait set by clnt_control? */
105 struct netbuf ct_addr
; /* remote addr */
106 struct rpc_err ct_error
;
108 char ct_mcallc
[MCALL_MSG_SIZE
]; /* marshalled callmsg */
111 u_int ct_mpos
; /* pos after marshal */
112 XDR ct_xdrs
; /* XDR stream */
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.
127 static int *vc_fd_locks
;
128 static cond_t
*vc_cv
;
129 #define release_fd_lock(fd, mask) { \
130 mutex_lock(&clnt_fd_lock); \
131 vc_fd_locks[fd] = 0; \
132 mutex_unlock(&clnt_fd_lock); \
133 thr_sigsetmask(SIG_SETMASK, &(mask), (sigset_t *) NULL); \
134 cond_signal(&vc_cv[fd]); \
137 static const char clnt_vc_errstr
[] = "%s : %s";
138 static const char clnt_vc_str
[] = "clnt_vc_create";
139 static const char clnt_read_vc_str
[] = "read_vc";
140 static const char __no_mem_str
[] = "out of memory";
143 * Create a client handle for a connection.
144 * Default options are set, which the user can change using clnt_control()'s.
145 * The rpc/vc package does buffering similar to stdio, so the client
146 * must pick send and receive buffer sizes, 0 => use the default.
147 * NB: fd is copied into a private area.
148 * NB: The rpch->cl_auth is set null authentication. Caller may wish to
149 * set this something more useful.
151 * fd should be an open socket
154 clnt_vc_create(int fd
, /* open file descriptor */
155 const struct netbuf
*raddr
, /* servers address */
156 const rpcprog_t prog
, /* program number */
157 const rpcvers_t vers
, /* version number */
158 u_int sendsz
, /* buffer recv size */
159 u_int recvsz
) /* buffer send size */
161 CLIENT
*cl
; /* client handle */
162 struct ct_data
*ct
= NULL
; /* client handle */
164 struct rpc_msg call_msg
;
165 static u_int32_t disrupt
;
168 struct sockaddr_storage ss
;
170 struct __rpc_sockinfo si
;
173 disrupt
= (u_int32_t
)(long)raddr
;
175 cl
= (CLIENT
*)mem_alloc(sizeof (*cl
));
176 ct
= (struct ct_data
*)mem_alloc(sizeof (*ct
));
177 if ((cl
== (CLIENT
*)NULL
) || (ct
== (struct ct_data
*)NULL
)) {
178 syslog(LOG_ERR
, clnt_vc_errstr
, clnt_vc_str
, __no_mem_str
);
179 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
180 rpc_createerr
.cf_error
.re_errno
= errno
;
183 ct
->ct_addr
.buf
= NULL
;
184 sigfillset(&newmask
);
185 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
186 mutex_lock(&clnt_fd_lock
);
187 if (vc_fd_locks
== (int *) NULL
) {
188 int cv_allocsz
, fd_allocsz
;
189 int dtbsize
= __rpc_dtbsize();
191 fd_allocsz
= dtbsize
* sizeof (int);
192 vc_fd_locks
= (int *) mem_alloc(fd_allocsz
);
193 if (vc_fd_locks
== (int *) NULL
) {
194 mutex_unlock(&clnt_fd_lock
);
195 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
198 memset(vc_fd_locks
, '\0', fd_allocsz
);
200 assert(vc_cv
== (cond_t
*) NULL
);
201 cv_allocsz
= dtbsize
* sizeof (cond_t
);
202 vc_cv
= (cond_t
*) mem_alloc(cv_allocsz
);
203 if (vc_cv
== (cond_t
*) NULL
) {
204 mem_free(vc_fd_locks
, fd_allocsz
);
205 vc_fd_locks
= (int *) NULL
;
206 mutex_unlock(&clnt_fd_lock
);
207 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
212 for (i
= 0; i
< dtbsize
; i
++)
213 cond_init(&vc_cv
[i
], 0, (void *) 0);
216 assert(vc_cv
!= (cond_t
*) NULL
);
219 * XXX - fvdl connecting while holding a mutex?
222 if (_getpeername(fd
, (struct sockaddr
*)(void *)&ss
, &slen
) < 0) {
223 if (errno
!= ENOTCONN
) {
224 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
225 rpc_createerr
.cf_error
.re_errno
= errno
;
226 mutex_unlock(&clnt_fd_lock
);
227 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
230 if (_connect(fd
, (struct sockaddr
*)raddr
->buf
, raddr
->len
) < 0){
231 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
232 rpc_createerr
.cf_error
.re_errno
= errno
;
233 mutex_unlock(&clnt_fd_lock
);
234 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
238 mutex_unlock(&clnt_fd_lock
);
239 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
240 if (!__rpc_fd2sockinfo(fd
, &si
))
243 ct
->ct_closeit
= FALSE
;
246 * Set up private data struct
249 ct
->ct_wait
.tv_usec
= 0;
250 ct
->ct_waitset
= FALSE
;
251 ct
->ct_addr
.buf
= malloc(raddr
->maxlen
);
252 if (ct
->ct_addr
.buf
== NULL
)
254 memcpy(ct
->ct_addr
.buf
, raddr
->buf
, raddr
->len
);
255 ct
->ct_addr
.len
= raddr
->maxlen
;
256 ct
->ct_addr
.maxlen
= raddr
->maxlen
;
259 * Initialize call message
261 gettimeofday(&now
, NULL
);
262 call_msg
.rm_xid
= ((u_int32_t
)++disrupt
) ^ __RPC_GETXID(&now
);
263 call_msg
.rm_direction
= CALL
;
264 call_msg
.rm_call
.cb_rpcvers
= RPC_MSG_VERSION
;
265 call_msg
.rm_call
.cb_prog
= (u_int32_t
)prog
;
266 call_msg
.rm_call
.cb_vers
= (u_int32_t
)vers
;
269 * pre-serialize the static part of the call msg and stash it away
271 xdrmem_create(&(ct
->ct_xdrs
), ct
->ct_u
.ct_mcallc
, MCALL_MSG_SIZE
,
273 if (! xdr_callhdr(&(ct
->ct_xdrs
), &call_msg
)) {
274 if (ct
->ct_closeit
) {
279 ct
->ct_mpos
= XDR_GETPOS(&(ct
->ct_xdrs
));
280 XDR_DESTROY(&(ct
->ct_xdrs
));
283 * Create a client handle which uses xdrrec for serialization
284 * and authnone for authentication.
286 cl
->cl_ops
= clnt_vc_ops();
288 cl
->cl_auth
= authnone_create();
289 sendsz
= __rpc_get_t_size(si
.si_af
, si
.si_proto
, (int)sendsz
);
290 recvsz
= __rpc_get_t_size(si
.si_af
, si
.si_proto
, (int)recvsz
);
291 xdrrec_create(&(ct
->ct_xdrs
), sendsz
, recvsz
,
292 cl
->cl_private
, read_vc
, write_vc
);
299 mem_free(ct
->ct_addr
.buf
, ct
->ct_addr
.len
);
300 mem_free(ct
, sizeof (struct ct_data
));
303 mem_free(cl
, sizeof (CLIENT
));
305 return ((CLIENT
*)NULL
);
308 static enum clnt_stat
309 clnt_vc_call(CLIENT
*cl
, rpcproc_t proc
, xdrproc_t xdr_args
, void *args_ptr
,
310 xdrproc_t xdr_results
, void *results_ptr
, struct timeval timeout
)
312 struct ct_data
*ct
= (struct ct_data
*) cl
->cl_private
;
313 XDR
*xdrs
= &(ct
->ct_xdrs
);
314 struct rpc_msg reply_msg
;
316 u_int32_t
*msg_x_id
= &ct
->ct_u
.ct_mcalli
; /* yuk */
319 sigset_t mask
, newmask
;
324 sigfillset(&newmask
);
325 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
326 mutex_lock(&clnt_fd_lock
);
327 while (vc_fd_locks
[ct
->ct_fd
])
328 cond_wait(&vc_cv
[ct
->ct_fd
], &clnt_fd_lock
);
333 vc_fd_locks
[ct
->ct_fd
] = rpc_lock_value
;
334 mutex_unlock(&clnt_fd_lock
);
335 if (!ct
->ct_waitset
) {
336 /* If time is not within limits, we ignore it. */
337 if (time_not_ok(&timeout
) == FALSE
)
338 ct
->ct_wait
= timeout
;
342 (xdr_results
== NULL
&& timeout
.tv_sec
== 0
343 && timeout
.tv_usec
== 0) ? FALSE
: TRUE
;
346 xdrs
->x_op
= XDR_ENCODE
;
347 ct
->ct_error
.re_status
= RPC_SUCCESS
;
348 x_id
= ntohl(--(*msg_x_id
));
350 if ((! XDR_PUTBYTES(xdrs
, ct
->ct_u
.ct_mcallc
, ct
->ct_mpos
)) ||
351 (! XDR_PUTINT32(xdrs
, &proc
)) ||
352 (! AUTH_MARSHALL(cl
->cl_auth
, xdrs
)) ||
353 (! (*xdr_args
)(xdrs
, args_ptr
))) {
354 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
355 ct
->ct_error
.re_status
= RPC_CANTENCODEARGS
;
356 xdrrec_endofrecord(xdrs
, TRUE
);
357 release_fd_lock(ct
->ct_fd
, mask
);
358 return (ct
->ct_error
.re_status
);
360 if (! xdrrec_endofrecord(xdrs
, shipnow
)) {
361 release_fd_lock(ct
->ct_fd
, mask
);
362 return (ct
->ct_error
.re_status
= RPC_CANTSEND
);
365 release_fd_lock(ct
->ct_fd
, mask
);
366 return (RPC_SUCCESS
);
369 * Hack to provide rpc-based message passing
371 if (timeout
.tv_sec
== 0 && timeout
.tv_usec
== 0) {
372 release_fd_lock(ct
->ct_fd
, mask
);
373 return(ct
->ct_error
.re_status
= RPC_TIMEDOUT
);
378 * Keep receiving until we get a valid transaction id
380 xdrs
->x_op
= XDR_DECODE
;
382 reply_msg
.acpted_rply
.ar_verf
= _null_auth
;
383 reply_msg
.acpted_rply
.ar_results
.where
= NULL
;
384 reply_msg
.acpted_rply
.ar_results
.proc
= (xdrproc_t
)xdr_void
;
385 if (! xdrrec_skiprecord(xdrs
)) {
386 release_fd_lock(ct
->ct_fd
, mask
);
387 return (ct
->ct_error
.re_status
);
389 /* now decode and validate the response header */
390 if (! xdr_replymsg(xdrs
, &reply_msg
)) {
391 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
393 release_fd_lock(ct
->ct_fd
, mask
);
394 return (ct
->ct_error
.re_status
);
396 if (reply_msg
.rm_xid
== x_id
)
403 _seterr_reply(&reply_msg
, &(ct
->ct_error
));
404 if (ct
->ct_error
.re_status
== RPC_SUCCESS
) {
405 if (! AUTH_VALIDATE(cl
->cl_auth
,
406 &reply_msg
.acpted_rply
.ar_verf
)) {
407 ct
->ct_error
.re_status
= RPC_AUTHERROR
;
408 ct
->ct_error
.re_why
= AUTH_INVALIDRESP
;
409 } else if (! (*xdr_results
)(xdrs
, results_ptr
)) {
410 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
411 ct
->ct_error
.re_status
= RPC_CANTDECODERES
;
413 /* free verifier ... */
414 if (reply_msg
.acpted_rply
.ar_verf
.oa_base
!= NULL
) {
415 xdrs
->x_op
= XDR_FREE
;
416 xdr_opaque_auth(xdrs
, &(reply_msg
.acpted_rply
.ar_verf
));
418 } /* end successful completion */
420 /* maybe our credentials need to be refreshed ... */
421 if (refreshes
-- && AUTH_REFRESH(cl
->cl_auth
, &reply_msg
))
423 } /* end of unsuccessful completion */
424 release_fd_lock(ct
->ct_fd
, mask
);
425 return (ct
->ct_error
.re_status
);
429 clnt_vc_geterr(CLIENT
*cl
, struct rpc_err
*errp
)
434 assert(errp
!= NULL
);
436 ct
= (struct ct_data
*) cl
->cl_private
;
437 *errp
= ct
->ct_error
;
441 clnt_vc_freeres(CLIENT
*cl
, xdrproc_t xdr_res
, void *res_ptr
)
451 ct
= (struct ct_data
*)cl
->cl_private
;
452 xdrs
= &(ct
->ct_xdrs
);
454 sigfillset(&newmask
);
455 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
456 mutex_lock(&clnt_fd_lock
);
457 while (vc_fd_locks
[ct
->ct_fd
])
458 cond_wait(&vc_cv
[ct
->ct_fd
], &clnt_fd_lock
);
459 xdrs
->x_op
= XDR_FREE
;
460 dummy
= (*xdr_res
)(xdrs
, res_ptr
);
461 mutex_unlock(&clnt_fd_lock
);
462 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
463 cond_signal(&vc_cv
[ct
->ct_fd
]);
470 clnt_vc_abort(CLIENT
*cl
)
475 clnt_vc_control(CLIENT
*cl
, u_int request
, void *info
)
485 ct
= (struct ct_data
*)cl
->cl_private
;
487 sigfillset(&newmask
);
488 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
489 mutex_lock(&clnt_fd_lock
);
490 while (vc_fd_locks
[ct
->ct_fd
])
491 cond_wait(&vc_cv
[ct
->ct_fd
], &clnt_fd_lock
);
496 vc_fd_locks
[ct
->ct_fd
] = rpc_lock_value
;
497 mutex_unlock(&clnt_fd_lock
);
501 ct
->ct_closeit
= TRUE
;
502 release_fd_lock(ct
->ct_fd
, mask
);
504 case CLSET_FD_NCLOSE
:
505 ct
->ct_closeit
= FALSE
;
506 release_fd_lock(ct
->ct_fd
, mask
);
512 /* for other requests which use info */
514 release_fd_lock(ct
->ct_fd
, mask
);
519 if (time_not_ok((struct timeval
*)info
)) {
520 release_fd_lock(ct
->ct_fd
, mask
);
523 ct
->ct_wait
= *(struct timeval
*)infop
;
524 ct
->ct_waitset
= TRUE
;
527 *(struct timeval
*)infop
= ct
->ct_wait
;
529 case CLGET_SERVER_ADDR
:
530 memcpy(info
, ct
->ct_addr
.buf
, (size_t)ct
->ct_addr
.len
);
533 *(int *)info
= ct
->ct_fd
;
536 /* The caller should not free this memory area */
537 *(struct netbuf
*)info
= ct
->ct_addr
;
539 case CLSET_SVC_ADDR
: /* set to new address */
540 release_fd_lock(ct
->ct_fd
, mask
);
544 * use the knowledge that xid is the
545 * first element in the call structure
546 * This will get the xid of the PREVIOUS call
549 ntohl(*(u_int32_t
*)(void *)&ct
->ct_u
.ct_mcalli
);
552 /* This will set the xid of the NEXT call */
553 *(u_int32_t
*)(void *)&ct
->ct_u
.ct_mcalli
=
554 htonl(*((u_int32_t
*)info
) + 1);
555 /* increment by 1 as clnt_vc_call() decrements once */
559 * This RELIES on the information that, in the call body,
560 * the version number field is the fifth field from the
561 * begining of the RPC header. MUST be changed if the
562 * call_struct is changed
565 ntohl(*(u_int32_t
*)(void *)(ct
->ct_u
.ct_mcallc
+
566 4 * BYTES_PER_XDR_UNIT
));
570 *(u_int32_t
*)(void *)(ct
->ct_u
.ct_mcallc
+
571 4 * BYTES_PER_XDR_UNIT
) =
572 htonl(*(u_int32_t
*)info
);
577 * This RELIES on the information that, in the call body,
578 * the program number field is the fourth field from the
579 * begining of the RPC header. MUST be changed if the
580 * call_struct is changed
583 ntohl(*(u_int32_t
*)(void *)(ct
->ct_u
.ct_mcallc
+
584 3 * BYTES_PER_XDR_UNIT
));
588 *(u_int32_t
*)(void *)(ct
->ct_u
.ct_mcallc
+
589 3 * BYTES_PER_XDR_UNIT
) =
590 htonl(*(u_int32_t
*)info
);
594 release_fd_lock(ct
->ct_fd
, mask
);
597 release_fd_lock(ct
->ct_fd
, mask
);
603 clnt_vc_destroy(CLIENT
*cl
)
605 struct ct_data
*ct
= (struct ct_data
*) cl
->cl_private
;
606 int ct_fd
= ct
->ct_fd
;
612 ct
= (struct ct_data
*) cl
->cl_private
;
614 sigfillset(&newmask
);
615 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
616 mutex_lock(&clnt_fd_lock
);
617 while (vc_fd_locks
[ct_fd
])
618 cond_wait(&vc_cv
[ct_fd
], &clnt_fd_lock
);
619 if (ct
->ct_closeit
&& ct
->ct_fd
!= -1) {
622 XDR_DESTROY(&(ct
->ct_xdrs
));
624 free(ct
->ct_addr
.buf
);
625 mem_free(ct
, sizeof(struct ct_data
));
626 mem_free(cl
, sizeof(CLIENT
));
627 mutex_unlock(&clnt_fd_lock
);
628 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
629 cond_signal(&vc_cv
[ct_fd
]);
633 * Interface between xdr serializer and tcp connection.
634 * Behaves like the system calls, read & write, but keeps some error state
635 * around for the rpc level.
638 read_vc(void *ctp
, void *buf
, int len
)
642 struct ct_data
*ct
= (struct ct_data
*)ctp
;
644 int milliseconds
= (int)((ct
->ct_wait
.tv_sec
* 1000) +
645 (ct
->ct_wait
.tv_usec
/ 1000));
652 switch (_poll(&fd
, 1, milliseconds
)) {
654 ct
->ct_error
.re_status
= RPC_TIMEDOUT
;
660 ct
->ct_error
.re_status
= RPC_CANTRECV
;
661 ct
->ct_error
.re_errno
= errno
;
668 if ((_getpeername(ct
->ct_fd
, &sa
, &sal
) == 0) &&
669 (sa
.sa_family
== AF_LOCAL
)) {
670 len
= __msgread(ct
->ct_fd
, buf
, (size_t)len
);
672 len
= _read(ct
->ct_fd
, buf
, (size_t)len
);
678 ct
->ct_error
.re_errno
= ECONNRESET
;
679 ct
->ct_error
.re_status
= RPC_CANTRECV
;
680 len
= -1; /* it's really an error */
684 ct
->ct_error
.re_errno
= errno
;
685 ct
->ct_error
.re_status
= RPC_CANTRECV
;
692 write_vc(void *ctp
, void *buf
, int len
)
696 struct ct_data
*ct
= (struct ct_data
*)ctp
;
700 if ((_getpeername(ct
->ct_fd
, &sa
, &sal
) == 0) &&
701 (sa
.sa_family
== AF_LOCAL
)) {
702 for (cnt
= len
; cnt
> 0; cnt
-= i
, buf
= (char *)buf
+ i
) {
703 if ((i
= __msgwrite(ct
->ct_fd
, buf
,
704 (size_t)cnt
)) == -1) {
705 ct
->ct_error
.re_errno
= errno
;
706 ct
->ct_error
.re_status
= RPC_CANTSEND
;
711 for (cnt
= len
; cnt
> 0; cnt
-= i
, buf
= (char *)buf
+ i
) {
712 if ((i
= _write(ct
->ct_fd
, buf
, (size_t)cnt
)) == -1) {
713 ct
->ct_error
.re_errno
= errno
;
714 ct
->ct_error
.re_status
= RPC_CANTSEND
;
722 static struct clnt_ops
*
725 static struct clnt_ops ops
;
726 sigset_t mask
, newmask
;
728 /* VARIABLES PROTECTED BY ops_lock: ops */
730 sigfillset(&newmask
);
731 thr_sigsetmask(SIG_SETMASK
, &newmask
, &mask
);
732 mutex_lock(&ops_lock
);
733 if (ops
.cl_call
== NULL
) {
734 ops
.cl_call
= clnt_vc_call
;
735 ops
.cl_abort
= clnt_vc_abort
;
736 ops
.cl_geterr
= clnt_vc_geterr
;
737 ops
.cl_freeres
= clnt_vc_freeres
;
738 ops
.cl_destroy
= clnt_vc_destroy
;
739 ops
.cl_control
= clnt_vc_control
;
741 mutex_unlock(&ops_lock
);
742 thr_sigsetmask(SIG_SETMASK
, &(mask
), NULL
);
747 * Make sure that the time is not garbage. -1 value is disallowed.
748 * Note this is different from time_not_ok in clnt_dg.c
751 time_not_ok(struct timeval
*t
)
753 return (t
->tv_sec
<= -1 || t
->tv_sec
> 100000000 ||
754 t
->tv_usec
<= -1 || t
->tv_usec
> 1000000);
758 __msgread(int sock
, void *buf
, size_t cnt
)
764 char control
[CMSG_SPACE(sizeof(struct cmsgcred
))];
767 bzero((char *)&cm
, sizeof(cm
));
768 iov
[0].iov_base
= buf
;
769 iov
[0].iov_len
= cnt
;
775 msg
.msg_control
= (caddr_t
)&cm
;
776 msg
.msg_controllen
= CMSG_SPACE(sizeof(struct cmsgcred
));
779 return(_recvmsg(sock
, &msg
, 0));
783 __msgwrite(int sock
, void *buf
, size_t cnt
)
789 char control
[CMSG_SPACE(sizeof(struct cmsgcred
))];
792 bzero((char *)&cm
, sizeof(cm
));
793 iov
[0].iov_base
= buf
;
794 iov
[0].iov_len
= cnt
;
796 cm
.cmsg
.cmsg_type
= SCM_CREDS
;
797 cm
.cmsg
.cmsg_level
= SOL_SOCKET
;
798 cm
.cmsg
.cmsg_len
= CMSG_LEN(sizeof(struct cmsgcred
));
804 msg
.msg_control
= (caddr_t
)&cm
;
805 msg
.msg_controllen
= CMSG_SPACE(sizeof(struct cmsgcred
));
808 return(_sendmsg(sock
, &msg
, 0));