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_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro
30 * @(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC
31 * $FreeBSD: src/lib/libc/rpc/clnt_tcp.c,v 1.14 2000/01/27 23:06:36 jasone Exp $
32 * $DragonFly: src/lib/libc/rpc/clnt_tcp.c,v 1.5 2005/11/13 12:27:04 swildner 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"
60 #include <sys/socket.h>
63 #include <rpc/pmap_clnt.h>
64 #include "un-namespace.h"
66 #define MCALL_MSG_SIZE 24
69 static int writetcp();
71 static enum clnt_stat
clnttcp_call();
72 static void clnttcp_abort();
73 static void clnttcp_geterr();
74 static bool_t
clnttcp_freeres();
75 static bool_t
clnttcp_control();
76 static void clnttcp_destroy();
78 static struct clnt_ops tcp_ops
= {
90 struct timeval ct_wait
;
91 bool_t ct_waitset
; /* wait set by clnt_control? */
92 struct sockaddr_in ct_addr
;
93 struct rpc_err ct_error
;
94 char ct_mcall
[MCALL_MSG_SIZE
]; /* marshalled callmsg */
95 u_int ct_mpos
; /* pos after marshal */
100 * Create a client handle for a tcp/ip connection.
101 * If *sockp<0, *sockp is set to a newly created TCP socket and it is
102 * connected to raddr. If *sockp non-negative then
103 * raddr is ignored. The rpc/tcp package does buffering
104 * similar to stdio, so the client must pick send and receive buffer sizes,];
105 * 0 => use the default.
106 * If raddr->sin_port is 0, then a binder on the remote machine is
107 * consulted for the right port number.
108 * NB: *sockp is copied into a private area.
109 * NB: It is the clients responsibility to close *sockp.
110 * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this
111 * something more useful.
114 clnttcp_create(struct sockaddr_in
*raddr
, u_long prog
, u_long vers
, int *sockp
,
115 u_int sendsz
, u_int recvsz
)
118 struct ct_data
*ct
= NULL
;
120 struct rpc_msg call_msg
;
121 static u_int32_t disrupt
;
124 disrupt
= (u_int32_t
)(long)raddr
;
126 h
= (CLIENT
*)mem_alloc(sizeof(*h
));
128 fprintf(stderr
, "clnttcp_create: out of memory\n");
129 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
130 rpc_createerr
.cf_error
.re_errno
= errno
;
133 ct
= (struct ct_data
*)mem_alloc(sizeof(*ct
));
135 fprintf(stderr
, "clnttcp_create: out of memory\n");
136 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
137 rpc_createerr
.cf_error
.re_errno
= errno
;
142 * If no port number given ask the pmap for one
144 if (raddr
->sin_port
== 0) {
146 if ((port
= pmap_getport(raddr
, prog
, vers
, IPPROTO_TCP
)) == 0) {
147 mem_free((caddr_t
)ct
, sizeof(struct ct_data
));
148 mem_free((caddr_t
)h
, sizeof(CLIENT
));
149 return ((CLIENT
*)NULL
);
151 raddr
->sin_port
= htons(port
);
155 * If no socket given, open one
158 *sockp
= _socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
159 bindresvport(*sockp
, (struct sockaddr_in
*)0);
161 || (_connect(*sockp
, (struct sockaddr
*)raddr
,
162 sizeof(*raddr
)) < 0)) {
163 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
164 rpc_createerr
.cf_error
.re_errno
= errno
;
169 ct
->ct_closeit
= TRUE
;
171 ct
->ct_closeit
= FALSE
;
175 * Set up private data struct
177 ct
->ct_sock
= *sockp
;
178 ct
->ct_wait
.tv_usec
= 0;
179 ct
->ct_waitset
= FALSE
;
180 ct
->ct_addr
= *raddr
;
183 * Initialize call message
185 gettimeofday(&now
, (struct timezone
*)0);
186 call_msg
.rm_xid
= (++disrupt
) ^ getpid() ^ now
.tv_sec
^ now
.tv_usec
;
187 call_msg
.rm_direction
= CALL
;
188 call_msg
.rm_call
.cb_rpcvers
= RPC_MSG_VERSION
;
189 call_msg
.rm_call
.cb_prog
= prog
;
190 call_msg
.rm_call
.cb_vers
= vers
;
193 * pre-serialize the static part of the call msg and stash it away
195 xdrmem_create(&(ct
->ct_xdrs
), ct
->ct_mcall
, MCALL_MSG_SIZE
,
197 if (! xdr_callhdr(&(ct
->ct_xdrs
), &call_msg
)) {
198 if (ct
->ct_closeit
) {
203 ct
->ct_mpos
= XDR_GETPOS(&(ct
->ct_xdrs
));
204 XDR_DESTROY(&(ct
->ct_xdrs
));
207 * Create a client handle which uses xdrrec for serialization
208 * and authnone for authentication.
210 xdrrec_create(&(ct
->ct_xdrs
), sendsz
, recvsz
,
211 (caddr_t
)ct
, readtcp
, writetcp
);
212 h
->cl_ops
= &tcp_ops
;
213 h
->cl_private
= (caddr_t
) ct
;
214 h
->cl_auth
= authnone_create();
219 * Something goofed, free stuff and barf
222 mem_free((caddr_t
)ct
, sizeof(struct ct_data
));
224 mem_free((caddr_t
)h
, sizeof(CLIENT
));
225 return ((CLIENT
*)NULL
);
228 static enum clnt_stat
229 clnttcp_call(CLIENT
*h
, u_long proc
, xdrproc_t xdr_args
, caddr_t args_ptr
,
230 xdrproc_t xdr_results
, caddr_t results_ptr
, struct timeval timeout
)
232 struct ct_data
*ct
= (struct ct_data
*) h
->cl_private
;
233 XDR
*xdrs
= &(ct
->ct_xdrs
);
234 struct rpc_msg reply_msg
;
236 u_int32_t
*msg_x_id
= (u_int32_t
*)(ct
->ct_mcall
); /* yuk */
240 if (!ct
->ct_waitset
) {
241 ct
->ct_wait
= timeout
;
245 (xdr_results
== (xdrproc_t
)0 && timeout
.tv_sec
== 0
246 && timeout
.tv_usec
== 0) ? FALSE
: TRUE
;
249 xdrs
->x_op
= XDR_ENCODE
;
250 ct
->ct_error
.re_status
= RPC_SUCCESS
;
251 x_id
= ntohl(--(*msg_x_id
));
252 if ((! XDR_PUTBYTES(xdrs
, ct
->ct_mcall
, ct
->ct_mpos
)) ||
253 (! XDR_PUTLONG(xdrs
, (long *)&proc
)) ||
254 (! AUTH_MARSHALL(h
->cl_auth
, xdrs
)) ||
255 (! (*xdr_args
)(xdrs
, args_ptr
))) {
256 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
257 ct
->ct_error
.re_status
= RPC_CANTENCODEARGS
;
258 xdrrec_endofrecord(xdrs
, TRUE
);
259 return (ct
->ct_error
.re_status
);
261 if (! xdrrec_endofrecord(xdrs
, shipnow
))
262 return (ct
->ct_error
.re_status
= RPC_CANTSEND
);
264 return (RPC_SUCCESS
);
266 * Hack to provide rpc-based message passing
268 if (timeout
.tv_sec
== 0 && timeout
.tv_usec
== 0) {
269 return(ct
->ct_error
.re_status
= RPC_TIMEDOUT
);
274 * Keep receiving until we get a valid transaction id
276 xdrs
->x_op
= XDR_DECODE
;
278 reply_msg
.acpted_rply
.ar_verf
= _null_auth
;
279 reply_msg
.acpted_rply
.ar_results
.where
= NULL
;
280 reply_msg
.acpted_rply
.ar_results
.proc
= xdr_void
;
281 if (! xdrrec_skiprecord(xdrs
))
282 return (ct
->ct_error
.re_status
);
283 /* now decode and validate the response header */
284 if (! xdr_replymsg(xdrs
, &reply_msg
)) {
285 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
287 return (ct
->ct_error
.re_status
);
289 if (reply_msg
.rm_xid
== x_id
)
296 _seterr_reply(&reply_msg
, &(ct
->ct_error
));
297 if (ct
->ct_error
.re_status
== RPC_SUCCESS
) {
298 if (! AUTH_VALIDATE(h
->cl_auth
, &reply_msg
.acpted_rply
.ar_verf
)) {
299 ct
->ct_error
.re_status
= RPC_AUTHERROR
;
300 ct
->ct_error
.re_why
= AUTH_INVALIDRESP
;
301 } else if (! (*xdr_results
)(xdrs
, results_ptr
)) {
302 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
303 ct
->ct_error
.re_status
= RPC_CANTDECODERES
;
305 /* free verifier ... */
306 if (reply_msg
.acpted_rply
.ar_verf
.oa_base
!= NULL
) {
307 xdrs
->x_op
= XDR_FREE
;
308 xdr_opaque_auth(xdrs
, &(reply_msg
.acpted_rply
.ar_verf
));
310 } /* end successful completion */
312 /* maybe our credentials need to be refreshed ... */
313 if (refreshes
-- && AUTH_REFRESH(h
->cl_auth
))
315 } /* end of unsuccessful completion */
316 return (ct
->ct_error
.re_status
);
320 clnttcp_geterr(CLIENT
*h
, struct rpc_err
*errp
)
323 (struct ct_data
*) h
->cl_private
;
325 *errp
= ct
->ct_error
;
329 clnttcp_freeres(CLIENT
*cl
, xdrproc_t xdr_res
, caddr_t res_ptr
)
331 struct ct_data
*ct
= (struct ct_data
*)cl
->cl_private
;
332 XDR
*xdrs
= &(ct
->ct_xdrs
);
334 xdrs
->x_op
= XDR_FREE
;
335 return ((*xdr_res
)(xdrs
, res_ptr
));
345 clnttcp_control(CLIENT
*cl
, int request
, char *info
)
347 struct ct_data
*ct
= (struct ct_data
*)cl
->cl_private
;
353 ct
->ct_closeit
= TRUE
;
355 case CLSET_FD_NCLOSE
:
356 ct
->ct_closeit
= FALSE
;
361 tv
= (struct timeval
*)info
;
362 ct
->ct_wait
.tv_sec
= tv
->tv_sec
;
363 ct
->ct_wait
.tv_usec
= tv
->tv_usec
;
364 ct
->ct_waitset
= TRUE
;
369 *(struct timeval
*)info
= ct
->ct_wait
;
371 case CLGET_SERVER_ADDR
:
374 *(struct sockaddr_in
*)info
= ct
->ct_addr
;
379 *(int *)info
= ct
->ct_sock
;
383 * use the knowledge that xid is the
384 * first element in the call structure *.
385 * This will get the xid of the PREVIOUS call
389 *(u_long
*)info
= ntohl(*(u_long
*)ct
->ct_mcall
);
392 /* This will set the xid of the NEXT call */
395 *(u_long
*)ct
->ct_mcall
= htonl(*(u_long
*)info
- 1);
396 /* decrement by 1 as clnttcp_call() increments once */
399 * This RELIES on the information that, in the call body,
400 * the version number field is the fifth field from the
401 * begining of the RPC header. MUST be changed if the
402 * call_struct is changed
406 *(u_long
*)info
= ntohl(*(u_long
*)(ct
->ct_mcall
+
407 4 * BYTES_PER_XDR_UNIT
));
412 *(u_long
*)(ct
->ct_mcall
+ 4 * BYTES_PER_XDR_UNIT
)
413 = htonl(*(u_long
*)info
);
417 * This RELIES on the information that, in the call body,
418 * the program number field is the field from the
419 * begining of the RPC header. MUST be changed if the
420 * call_struct is changed
424 *(u_long
*)info
= ntohl(*(u_long
*)(ct
->ct_mcall
+
425 3 * BYTES_PER_XDR_UNIT
));
430 *(u_long
*)(ct
->ct_mcall
+ 3 * BYTES_PER_XDR_UNIT
)
431 = htonl(*(u_long
*)info
);
433 case CLGET_LOCAL_ADDR
:
434 len
= sizeof(struct sockaddr
);
435 if (_getsockname(ct
->ct_sock
, (struct sockaddr
*)info
, &len
) <0)
438 case CLGET_RETRY_TIMEOUT
:
439 case CLSET_RETRY_TIMEOUT
:
442 case CLSET_PUSH_TIMOD
:
443 case CLSET_POP_TIMOD
:
452 clnttcp_destroy(CLIENT
*h
)
455 (struct ct_data
*) h
->cl_private
;
457 if (ct
->ct_closeit
) {
460 XDR_DESTROY(&(ct
->ct_xdrs
));
461 mem_free((caddr_t
)ct
, sizeof(struct ct_data
));
462 mem_free((caddr_t
)h
, sizeof(CLIENT
));
466 * Interface between xdr serializer and tcp connection.
467 * Behaves like the system calls, read & write, but keeps some error state
468 * around for the rpc level.
471 readtcp(struct ct_data
*ct
, caddr_t buf
, int len
)
473 fd_set
*fds
, readfds
;
474 struct timeval start
, after
, duration
, delta
, tmp
, tv
;
480 if (ct
->ct_sock
+ 1 > FD_SETSIZE
) {
481 int bytes
= howmany(ct
->ct_sock
+ 1, NFDBITS
) * sizeof(fd_mask
);
482 fds
= (fd_set
*)malloc(bytes
);
485 memset(fds
, 0, bytes
);
491 gettimeofday(&start
, NULL
);
494 /* XXX we know the other bits are still clear */
495 FD_SET(ct
->ct_sock
, fds
);
496 tv
= delta
; /* in case select writes back */
497 r
= _select(ct
->ct_sock
+1, fds
, NULL
, NULL
, &tv
);
500 gettimeofday(&after
, NULL
);
501 timersub(&start
, &after
, &duration
);
502 timersub(&ct
->ct_wait
, &duration
, &tmp
);
504 if (delta
.tv_sec
< 0 || !timerisset(&delta
))
511 ct
->ct_error
.re_status
= RPC_TIMEDOUT
;
519 ct
->ct_error
.re_status
= RPC_CANTRECV
;
520 ct
->ct_error
.re_errno
= save_errno
;
525 switch (len
= _read(ct
->ct_sock
, buf
, len
)) {
529 ct
->ct_error
.re_errno
= ECONNRESET
;
530 ct
->ct_error
.re_status
= RPC_CANTRECV
;
531 len
= -1; /* it's really an error */
535 ct
->ct_error
.re_errno
= errno
;
536 ct
->ct_error
.re_status
= RPC_CANTRECV
;
543 writetcp(struct ct_data
*ct
, caddr_t buf
, int len
)
547 for (cnt
= len
; cnt
> 0; cnt
-= i
, buf
+= i
) {
548 if ((i
= _write(ct
->ct_sock
, buf
, cnt
)) == -1) {
549 ct
->ct_error
.re_errno
= errno
;
550 ct
->ct_error
.re_status
= RPC_CANTSEND
;