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
29 * @(#)clnt_unix.c 1.37 87/10/05 Copyr 1984 Sun Micro
30 * @(#)clnt_unix.c 2.2 88/08/01 4.0 RPCSRC
31 * $FreeBSD: src/lib/libc/rpc/clnt_unix.c,v 1.5 2000/01/27 23:06:37 jasone Exp $
32 * $DragonFly: src/lib/libc/rpc/clnt_unix.c,v 1.5 2005/11/13 12:27:04 swildner Exp $
36 * clnt_unix.c, Implements a AF_UNIX based, client side RPC.
38 * Copyright (C) 1984, Sun Microsystems, Inc.
40 * AF_UNIX 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"
61 #include <sys/socket.h>
65 #include <rpc/pmap_clnt.h>
66 #include "un-namespace.h"
68 #define MCALL_MSG_SIZE 24
70 static int readunix();
71 static int writeunix();
73 static enum clnt_stat
clntunix_call();
74 static void clntunix_abort();
75 static void clntunix_geterr();
76 static bool_t
clntunix_freeres();
77 static bool_t
clntunix_control();
78 static void clntunix_destroy();
80 static struct clnt_ops unix_ops
= {
92 struct timeval ct_wait
;
93 bool_t ct_waitset
; /* wait set by clnt_control? */
94 struct sockaddr_un ct_addr
;
95 struct rpc_err ct_error
;
96 char ct_mcall
[MCALL_MSG_SIZE
]; /* marshalled callmsg */
97 u_int ct_mpos
; /* pos after marshal */
102 * Create a client handle for a unix/ip connection.
103 * If *sockp<0, *sockp is set to a newly created TCP socket and it is
104 * connected to raddr. If *sockp non-negative then
105 * raddr is ignored. The rpc/unix package does buffering
106 * similar to stdio, so the client must pick send and receive buffer sizes,];
107 * 0 => use the default.
108 * If raddr->sin_port is 0, then a binder on the remote machine is
109 * consulted for the right port number.
110 * NB: *sockp is copied into a private area.
111 * NB: It is the clients responsibility to close *sockp.
112 * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this
113 * something more useful.
116 clntunix_create(struct sockaddr_un
*raddr
, u_long prog
, u_long vers
, int *sockp
,
117 u_int sendsz
, u_int recvsz
)
120 struct ct_data
*ct
= NULL
;
122 struct rpc_msg call_msg
;
123 static u_int32_t disrupt
;
127 disrupt
= (u_int32_t
)(long)raddr
;
129 h
= (CLIENT
*)mem_alloc(sizeof(*h
));
131 fprintf(stderr
, "clntunix_create: out of memory\n");
132 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
133 rpc_createerr
.cf_error
.re_errno
= errno
;
136 ct
= (struct ct_data
*)mem_alloc(sizeof(*ct
));
138 fprintf(stderr
, "clntunix_create: out of memory\n");
139 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
140 rpc_createerr
.cf_error
.re_errno
= errno
;
145 * If no socket given, open one
148 *sockp
= _socket(AF_UNIX
, SOCK_STREAM
, 0);
149 len
= strlen(raddr
->sun_path
) + sizeof(raddr
->sun_family
) +
150 sizeof(raddr
->sun_len
) + 1;
151 raddr
->sun_len
= len
;
153 || (_connect(*sockp
, (struct sockaddr
*)raddr
, len
) < 0)) {
154 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
155 rpc_createerr
.cf_error
.re_errno
= errno
;
160 ct
->ct_closeit
= TRUE
;
162 ct
->ct_closeit
= FALSE
;
166 * Set up private data struct
168 ct
->ct_sock
= *sockp
;
169 ct
->ct_wait
.tv_usec
= 0;
170 ct
->ct_waitset
= FALSE
;
171 ct
->ct_addr
= *raddr
;
174 * Initialize call message
176 gettimeofday(&now
, (struct timezone
*)0);
177 call_msg
.rm_xid
= (++disrupt
) ^ getpid() ^ now
.tv_sec
^ now
.tv_usec
;
178 call_msg
.rm_direction
= CALL
;
179 call_msg
.rm_call
.cb_rpcvers
= RPC_MSG_VERSION
;
180 call_msg
.rm_call
.cb_prog
= prog
;
181 call_msg
.rm_call
.cb_vers
= vers
;
184 * pre-serialize the static part of the call msg and stash it away
186 xdrmem_create(&(ct
->ct_xdrs
), ct
->ct_mcall
, MCALL_MSG_SIZE
,
188 if (! xdr_callhdr(&(ct
->ct_xdrs
), &call_msg
)) {
189 if (ct
->ct_closeit
) {
194 ct
->ct_mpos
= XDR_GETPOS(&(ct
->ct_xdrs
));
195 XDR_DESTROY(&(ct
->ct_xdrs
));
198 * Create a client handle which uses xdrrec for serialization
199 * and authnone for authentication.
201 xdrrec_create(&(ct
->ct_xdrs
), sendsz
, recvsz
,
202 (caddr_t
)ct
, readunix
, writeunix
);
203 h
->cl_ops
= &unix_ops
;
204 h
->cl_private
= (caddr_t
) ct
;
205 h
->cl_auth
= authnone_create();
210 * Something goofed, free stuff and barf
213 mem_free((caddr_t
)ct
, sizeof(struct ct_data
));
215 mem_free((caddr_t
)h
, sizeof(CLIENT
));
216 return ((CLIENT
*)NULL
);
219 static enum clnt_stat
220 clntunix_call(CLIENT
*h
, u_long proc
, xdrproc_t xdr_args
, caddr_t args_ptr
,
221 xdrproc_t xdr_results
, caddr_t results_ptr
,
222 struct timeval timeout
)
224 struct ct_data
*ct
= (struct ct_data
*) h
->cl_private
;
225 XDR
*xdrs
= &(ct
->ct_xdrs
);
226 struct rpc_msg reply_msg
;
228 u_int32_t
*msg_x_id
= (u_int32_t
*)(ct
->ct_mcall
); /* yuk */
232 if (!ct
->ct_waitset
) {
233 ct
->ct_wait
= timeout
;
237 (xdr_results
== (xdrproc_t
)0 && timeout
.tv_sec
== 0
238 && timeout
.tv_usec
== 0) ? FALSE
: TRUE
;
241 xdrs
->x_op
= XDR_ENCODE
;
242 ct
->ct_error
.re_status
= RPC_SUCCESS
;
243 x_id
= ntohl(--(*msg_x_id
));
244 if ((! XDR_PUTBYTES(xdrs
, ct
->ct_mcall
, ct
->ct_mpos
)) ||
245 (! XDR_PUTLONG(xdrs
, (long *)&proc
)) ||
246 (! AUTH_MARSHALL(h
->cl_auth
, xdrs
)) ||
247 (! (*xdr_args
)(xdrs
, args_ptr
))) {
248 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
249 ct
->ct_error
.re_status
= RPC_CANTENCODEARGS
;
250 xdrrec_endofrecord(xdrs
, TRUE
);
251 return (ct
->ct_error
.re_status
);
253 if (! xdrrec_endofrecord(xdrs
, shipnow
))
254 return (ct
->ct_error
.re_status
= RPC_CANTSEND
);
256 return (RPC_SUCCESS
);
258 * Hack to provide rpc-based message passing
260 if (timeout
.tv_sec
== 0 && timeout
.tv_usec
== 0) {
261 return(ct
->ct_error
.re_status
= RPC_TIMEDOUT
);
266 * Keep receiving until we get a valid transaction id
268 xdrs
->x_op
= XDR_DECODE
;
270 reply_msg
.acpted_rply
.ar_verf
= _null_auth
;
271 reply_msg
.acpted_rply
.ar_results
.where
= NULL
;
272 reply_msg
.acpted_rply
.ar_results
.proc
= xdr_void
;
273 if (! xdrrec_skiprecord(xdrs
))
274 return (ct
->ct_error
.re_status
);
275 /* now decode and validate the response header */
276 if (! xdr_replymsg(xdrs
, &reply_msg
)) {
277 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
279 return (ct
->ct_error
.re_status
);
281 if (reply_msg
.rm_xid
== x_id
)
288 _seterr_reply(&reply_msg
, &(ct
->ct_error
));
289 if (ct
->ct_error
.re_status
== RPC_SUCCESS
) {
290 if (! AUTH_VALIDATE(h
->cl_auth
, &reply_msg
.acpted_rply
.ar_verf
)) {
291 ct
->ct_error
.re_status
= RPC_AUTHERROR
;
292 ct
->ct_error
.re_why
= AUTH_INVALIDRESP
;
293 } else if (! (*xdr_results
)(xdrs
, results_ptr
)) {
294 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
295 ct
->ct_error
.re_status
= RPC_CANTDECODERES
;
297 /* free verifier ... */
298 if (reply_msg
.acpted_rply
.ar_verf
.oa_base
!= NULL
) {
299 xdrs
->x_op
= XDR_FREE
;
300 xdr_opaque_auth(xdrs
, &(reply_msg
.acpted_rply
.ar_verf
));
302 } /* end successful completion */
304 /* maybe our credentials need to be refreshed ... */
305 if (refreshes
-- && AUTH_REFRESH(h
->cl_auth
))
307 } /* end of unsuccessful completion */
308 return (ct
->ct_error
.re_status
);
312 clntunix_geterr(CLIENT
*h
, struct rpc_err
*errp
)
315 (struct ct_data
*) h
->cl_private
;
317 *errp
= ct
->ct_error
;
321 clntunix_freeres(CLIENT
*cl
, xdrproc_t xdr_res
, caddr_t res_ptr
)
323 struct ct_data
*ct
= (struct ct_data
*)cl
->cl_private
;
324 XDR
*xdrs
= &(ct
->ct_xdrs
);
326 xdrs
->x_op
= XDR_FREE
;
327 return ((*xdr_res
)(xdrs
, res_ptr
));
337 clntunix_control(CLIENT
*cl
, int request
, char *info
)
339 struct ct_data
*ct
= (struct ct_data
*)cl
->cl_private
;
345 ct
->ct_closeit
= TRUE
;
347 case CLSET_FD_NCLOSE
:
348 ct
->ct_closeit
= FALSE
;
353 tv
= (struct timeval
*)info
;
354 ct
->ct_wait
.tv_sec
= tv
->tv_sec
;
355 ct
->ct_wait
.tv_usec
= tv
->tv_usec
;
356 ct
->ct_waitset
= TRUE
;
361 *(struct timeval
*)info
= ct
->ct_wait
;
363 case CLGET_SERVER_ADDR
:
366 *(struct sockaddr_un
*)info
= ct
->ct_addr
;
371 *(int *)info
= ct
->ct_sock
;
375 * use the knowledge that xid is the
376 * first element in the call structure *.
377 * This will get the xid of the PREVIOUS call
381 *(u_long
*)info
= ntohl(*(u_long
*)ct
->ct_mcall
);
384 /* This will set the xid of the NEXT call */
387 *(u_long
*)ct
->ct_mcall
= htonl(*(u_long
*)info
- 1);
388 /* decrement by 1 as clntunix_call() increments once */
391 * This RELIES on the information that, in the call body,
392 * the version number field is the fifth field from the
393 * begining of the RPC header. MUST be changed if the
394 * call_struct is changed
398 *(u_long
*)info
= ntohl(*(u_long
*)(ct
->ct_mcall
+
399 4 * BYTES_PER_XDR_UNIT
));
404 *(u_long
*)(ct
->ct_mcall
+ 4 * BYTES_PER_XDR_UNIT
)
405 = htonl(*(u_long
*)info
);
409 * This RELIES on the information that, in the call body,
410 * the program number field is the field from the
411 * begining of the RPC header. MUST be changed if the
412 * call_struct is changed
416 *(u_long
*)info
= ntohl(*(u_long
*)(ct
->ct_mcall
+
417 3 * BYTES_PER_XDR_UNIT
));
422 *(u_long
*)(ct
->ct_mcall
+ 3 * BYTES_PER_XDR_UNIT
)
423 = htonl(*(u_long
*)info
);
425 case CLGET_LOCAL_ADDR
:
426 len
= sizeof(struct sockaddr
);
427 if (_getsockname(ct
->ct_sock
, (struct sockaddr
*)info
, &len
) <0)
430 case CLGET_RETRY_TIMEOUT
:
431 case CLSET_RETRY_TIMEOUT
:
434 case CLSET_PUSH_TIMOD
:
435 case CLSET_POP_TIMOD
:
444 clntunix_destroy(CLIENT
*h
)
447 (struct ct_data
*) h
->cl_private
;
449 if (ct
->ct_closeit
) {
452 XDR_DESTROY(&(ct
->ct_xdrs
));
453 mem_free((caddr_t
)ct
, sizeof(struct ct_data
));
454 mem_free((caddr_t
)h
, sizeof(CLIENT
));
458 * _read() and _write() are replaced with _recvmsg()/_sendmsg() so that
459 * we can pass ancillary control data. In this case, the data constists
460 * of credential information which the kernel will fill in for us.
461 * XXX: This code is specific to FreeBSD and will not work on other
462 * platforms without the requisite kernel modifications.
466 struct cmsgcred cmcred
;
470 __msgread(int sock
, void *buf
, size_t cnt
)
476 bzero((char *)&cm
, sizeof(cm
));
477 iov
[0].iov_base
= buf
;
478 iov
[0].iov_len
= cnt
;
484 msg
.msg_control
= (caddr_t
)&cm
;
485 msg
.msg_controllen
= sizeof(struct cmessage
);
488 return(_recvmsg(sock
, &msg
, 0));
492 __msgwrite(int sock
, void *buf
, size_t cnt
)
498 bzero((char *)&cm
, sizeof(cm
));
499 iov
[0].iov_base
= buf
;
500 iov
[0].iov_len
= cnt
;
502 cm
.cmsg
.cmsg_type
= SCM_CREDS
;
503 cm
.cmsg
.cmsg_level
= SOL_SOCKET
;
504 cm
.cmsg
.cmsg_len
= sizeof(struct cmessage
);
510 msg
.msg_control
= (caddr_t
)&cm
;
511 msg
.msg_controllen
= sizeof(struct cmessage
);
514 return(_sendmsg(sock
, &msg
, 0));
518 * Interface between xdr serializer and unix connection.
519 * Behaves like the system calls, read & write, but keeps some error state
520 * around for the rpc level.
523 readunix(struct ct_data
*ct
, caddr_t buf
, int len
)
525 fd_set
*fds
, readfds
;
526 struct timeval start
, after
, duration
, delta
, tmp
, tv
;
532 if (ct
->ct_sock
+ 1 > FD_SETSIZE
) {
533 int bytes
= howmany(ct
->ct_sock
+ 1, NFDBITS
) * sizeof(fd_mask
);
534 fds
= (fd_set
*)malloc(bytes
);
537 memset(fds
, 0, bytes
);
543 gettimeofday(&start
, NULL
);
546 /* XXX we know the other bits are still clear */
547 FD_SET(ct
->ct_sock
, fds
);
548 tv
= delta
; /* in case select writes back */
549 r
= _select(ct
->ct_sock
+1, fds
, NULL
, NULL
, &tv
);
552 gettimeofday(&after
, NULL
);
553 timersub(&start
, &after
, &duration
);
554 timersub(&delta
, &duration
, &tmp
);
556 if (delta
.tv_sec
< 0 || !timerisset(&delta
))
563 ct
->ct_error
.re_status
= RPC_TIMEDOUT
;
571 ct
->ct_error
.re_status
= RPC_CANTRECV
;
572 ct
->ct_error
.re_errno
= save_errno
;
577 switch (len
= __msgread(ct
->ct_sock
, buf
, len
)) {
581 ct
->ct_error
.re_errno
= ECONNRESET
;
582 ct
->ct_error
.re_status
= RPC_CANTRECV
;
583 len
= -1; /* it's really an error */
587 ct
->ct_error
.re_errno
= errno
;
588 ct
->ct_error
.re_status
= RPC_CANTRECV
;
595 writeunix(struct ct_data
*ct
, caddr_t buf
, int len
)
599 for (cnt
= len
; cnt
> 0; cnt
-= i
, buf
+= i
) {
600 if ((i
= __msgwrite(ct
->ct_sock
, buf
, cnt
)) == -1) {
601 ct
->ct_error
.re_errno
= errno
;
602 ct
->ct_error
.re_status
= RPC_CANTSEND
;