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]
23 * Copyright 1990 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright (c) 1984, 1986, 1987, 1988, 1989, 1996 AT&T
33 * University Copyright- Copyright (c) 1982, 1986, 1988
34 * The Regents of the University of California
37 * University Acknowledgment- Portions of this document are derived from
38 * software developed by the University of California, Berkeley, and its
42 #pragma ident "%Z%%M% %I% %E% SMI"
45 * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
47 * TCP based RPC supports 'batched calls'.
48 * A sequence of calls may be batched-up in a send buffer. The rpc call
49 * return immediately to the client even though the call was not necessarily
50 * sent. The batching occurs if the results' xdr routine is NULL (0) AND
51 * the rpc timeout value is zero (see clnt.h, rpc).
53 * Clients should NOT casually batch calls that in fact return results; that is,
54 * the server side should be aware that a call is batched and not produce any
55 * return message. Batched calls that produce many result messages can
56 * deadlock (netlock) the client and the server....
58 * Now go hang yourself.
62 #include <sys/socket.h>
66 #include <rpc/pmap_clnt.h>
71 #define MCALL_MSG_SIZE 24
76 static int writetcp();
77 extern int _socket(int, int, int);
78 extern pid_t
getpid();
79 extern int bindresvport(int, struct sockaddr_in
*);
80 extern bool_t
xdr_opaque_auth(XDR
*, struct opaque_auth
*);
81 static struct clnt_ops
*clnttcp_ops();
86 struct timeval ct_wait
;
87 bool_t ct_waitset
; /* wait set by clnt_control? */
88 struct sockaddr_in ct_addr
;
89 struct rpc_err ct_error
;
90 char ct_mcall
[MCALL_MSG_SIZE
]; /* marshalled callmsg */
91 u_int ct_mpos
; /* pos after marshal */
96 * Create a client handle for a tcp/ip connection.
97 * If *sockp<0, *sockp is set to a newly created TCP socket and it is
98 * connected to raddr. If *sockp non-negative then
99 * raddr is ignored. The rpc/tcp package does buffering
100 * similar to stdio, so the client must pick send and receive buffer sizes
101 * 0 => use the default.
102 * If raddr->sin_port is 0, then a binder on the remote machine is
103 * consulted for the right port number.
104 * NB: *sockp is copied into a private area.
105 * NB: It is the clients responsibility to close *sockp.
106 * NB: The rpch->cl_auth is set null authentication. Caller may wish to
107 * set this something more useful.
110 clnttcp_create(raddr
, prog
, vers
, sockp
, sendsz
, recvsz
)
111 struct sockaddr_in
*raddr
;
119 register struct ct_data
*ct
;
121 struct rpc_msg call_msg
;
124 h
= (CLIENT
*)mem_alloc(sizeof (*h
));
126 (void) syslog(LOG_ERR
, "clnttcp_create: out of memory");
127 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
128 rpc_createerr
.cf_error
.re_errno
= errno
;
131 ct
= (struct ct_data
*)mem_alloc(sizeof (*ct
));
133 (void) syslog(LOG_ERR
, "clnttcp_create: out of memory");
134 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
135 rpc_createerr
.cf_error
.re_errno
= errno
;
140 * If no port number given ask the pmap for one
142 if (raddr
->sin_port
== 0) {
144 if ((port
= pmap_getport(raddr
, prog
, vers
, IPPROTO_TCP
))
146 mem_free((caddr_t
)ct
, sizeof (struct ct_data
));
147 mem_free((caddr_t
)h
, sizeof (CLIENT
));
148 return ((CLIENT
*)NULL
);
150 raddr
->sin_port
= htons(port
);
154 * If no socket given, open one
157 *sockp
= _socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
158 i
= bindresvport(*sockp
, (struct sockaddr_in
*)0);
160 (connect(*sockp
, (struct sockaddr
*)raddr
,
161 sizeof (*raddr
)) < 0)) {
162 rpc_createerr
.cf_stat
= RPC_SYSTEMERROR
;
163 rpc_createerr
.cf_error
.re_errno
= errno
;
164 (void) close(*sockp
);
167 ct
->ct_closeit
= TRUE
;
169 ct
->ct_closeit
= FALSE
;
173 * Set up private data struct
175 ct
->ct_sock
= *sockp
;
176 ct
->ct_wait
.tv_usec
= 0;
177 ct
->ct_waitset
= FALSE
;
178 ct
->ct_addr
= *raddr
;
181 * Initialize call message
183 (void) gettimeofday(&now
, (struct timezone
*)0);
184 call_msg
.rm_xid
= getpid() ^ now
.tv_sec
^ now
.tv_usec
;
185 call_msg
.rm_direction
= CALL
;
186 call_msg
.rm_call
.cb_rpcvers
= RPC_MSG_VERSION
;
187 call_msg
.rm_call
.cb_prog
= prog
;
188 call_msg
.rm_call
.cb_vers
= vers
;
191 * pre-serialize the staic part of the call msg and stash it away
193 xdrmem_create(&(ct
->ct_xdrs
), ct
->ct_mcall
, MCALL_MSG_SIZE
,
195 if (! xdr_callhdr(&(ct
->ct_xdrs
), &call_msg
)) {
196 if (ct
->ct_closeit
) {
197 (void) close(*sockp
);
201 ct
->ct_mpos
= XDR_GETPOS(&(ct
->ct_xdrs
));
202 XDR_DESTROY(&(ct
->ct_xdrs
));
205 * Create a client handle which uses xdrrec for serialization
206 * and authnone for authentication.
208 xdrrec_create(&(ct
->ct_xdrs
), sendsz
, recvsz
,
209 (caddr_t
)ct
, readtcp
, writetcp
);
210 h
->cl_ops
= clnttcp_ops();
211 h
->cl_private
= (caddr_t
) ct
;
212 h
->cl_auth
= authnone_create();
217 * Something goofed, free stuff and barf
219 mem_free((caddr_t
)ct
, sizeof (struct ct_data
));
220 mem_free((caddr_t
)h
, sizeof (CLIENT
));
221 return ((CLIENT
*)NULL
);
224 static enum clnt_stat
225 clnttcp_call(h
, proc
, xdr_args
, args_ptr
, xdr_results
, results_ptr
, timeout
)
230 xdrproc_t xdr_results
;
232 struct timeval timeout
;
234 register struct ct_data
*ct
= (struct ct_data
*) h
->cl_private
;
235 register XDR
*xdrs
= &(ct
->ct_xdrs
);
236 struct rpc_msg reply_msg
;
238 uint32_t *msg_x_id
= (uint32_t *)(ct
->ct_mcall
); /* yuk */
239 register bool_t shipnow
;
242 if (!ct
->ct_waitset
) {
243 ct
->ct_wait
= timeout
;
247 (xdr_results
== (xdrproc_t
)0 && timeout
.tv_sec
== 0 &&
248 timeout
.tv_usec
== 0) ? FALSE
: TRUE
;
251 xdrs
->x_op
= XDR_ENCODE
;
252 ct
->ct_error
.re_status
= RPC_SUCCESS
;
253 x_id
= ntohl(--(*msg_x_id
));
254 if ((! XDR_PUTBYTES(xdrs
, ct
->ct_mcall
, ct
->ct_mpos
)) ||
255 (! XDR_PUTINT32(xdrs
, (int32_t *)&proc
)) ||
256 (! AUTH_MARSHALL(h
->cl_auth
, xdrs
)) ||
257 (! (*xdr_args
)(xdrs
, args_ptr
))) {
258 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
259 ct
->ct_error
.re_status
= RPC_CANTENCODEARGS
;
260 (void) xdrrec_endofrecord(xdrs
, TRUE
);
261 return (ct
->ct_error
.re_status
);
263 if (! xdrrec_endofrecord(xdrs
, shipnow
))
264 return (ct
->ct_error
.re_status
= RPC_CANTSEND
);
266 return (RPC_SUCCESS
);
268 * Hack to provide rpc-based message passing
270 if (timeout
.tv_sec
== 0 && timeout
.tv_usec
== 0) {
271 return (ct
->ct_error
.re_status
= RPC_TIMEDOUT
);
276 * Keep receiving until we get a valid transaction id
278 xdrs
->x_op
= XDR_DECODE
;
280 reply_msg
.acpted_rply
.ar_verf
= _null_auth
;
281 reply_msg
.acpted_rply
.ar_results
.where
= NULL
;
282 reply_msg
.acpted_rply
.ar_results
.proc
= xdr_void
;
283 if (! xdrrec_skiprecord(xdrs
))
284 return (ct
->ct_error
.re_status
);
285 /* now decode and validate the response header */
286 if (! xdr_replymsg(xdrs
, &reply_msg
)) {
287 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
289 return (ct
->ct_error
.re_status
);
291 if (reply_msg
.rm_xid
== x_id
)
298 __seterr_reply(&reply_msg
, &(ct
->ct_error
));
299 if (ct
->ct_error
.re_status
== RPC_SUCCESS
) {
300 if (! AUTH_VALIDATE(h
->cl_auth
,
301 &reply_msg
.acpted_rply
.ar_verf
)) {
302 ct
->ct_error
.re_status
= RPC_AUTHERROR
;
303 ct
->ct_error
.re_why
= AUTH_INVALIDRESP
;
304 } else if (! (*xdr_results
)(xdrs
, results_ptr
)) {
305 if (ct
->ct_error
.re_status
== RPC_SUCCESS
)
306 ct
->ct_error
.re_status
= RPC_CANTDECODERES
;
308 /* free verifier ... */
309 if (reply_msg
.acpted_rply
.ar_verf
.oa_base
!= NULL
) {
310 xdrs
->x_op
= XDR_FREE
;
311 (void) xdr_opaque_auth(xdrs
,
312 &(reply_msg
.acpted_rply
.ar_verf
));
314 } /* end successful completion */
316 /* maybe our credentials need to be refreshed ... */
317 if (refreshes
-- && AUTH_REFRESH(h
->cl_auth
, &reply_msg
))
319 } /* end of unsuccessful completion */
320 return (ct
->ct_error
.re_status
);
324 clnttcp_geterr(h
, errp
)
326 struct rpc_err
*errp
;
328 register struct ct_data
*ct
=
329 (struct ct_data
*) h
->cl_private
;
331 *errp
= ct
->ct_error
;
335 clnttcp_freeres(cl
, xdr_res
, res_ptr
)
340 register struct ct_data
*ct
= (struct ct_data
*)cl
->cl_private
;
341 register XDR
*xdrs
= &(ct
->ct_xdrs
);
343 xdrs
->x_op
= XDR_FREE
;
344 return ((*xdr_res
)(xdrs
, res_ptr
));
353 clnttcp_control(cl
, request
, info
)
358 register struct ct_data
*ct
= (struct ct_data
*)cl
->cl_private
;
362 ct
->ct_wait
= *(struct timeval
*)info
;
363 ct
->ct_waitset
= TRUE
;
366 *(struct timeval
*)info
= ct
->ct_wait
;
368 case CLGET_SERVER_ADDR
:
369 *(struct sockaddr_in
*)info
= ct
->ct_addr
;
372 *(int *)info
= ct
->ct_sock
;
375 ct
->ct_closeit
= TRUE
;
377 case CLSET_FD_NCLOSE
:
378 ct
->ct_closeit
= FALSE
;
391 register struct ct_data
*ct
=
392 (struct ct_data
*) h
->cl_private
;
394 if (ct
->ct_closeit
) {
395 (void) close(ct
->ct_sock
);
397 XDR_DESTROY(&(ct
->ct_xdrs
));
398 mem_free((caddr_t
)ct
, sizeof (struct ct_data
));
399 mem_free((caddr_t
)h
, sizeof (CLIENT
));
403 * Interface between xdr serializer and tcp connection.
404 * Behaves like the system calls, read & write, but keeps some error state
405 * around for the rpc level.
408 readtcp(ct
, buf
, len
)
409 register struct ct_data
*ct
;
419 FD_SET(ct
->ct_sock
, &mask
);
422 switch (select(__rpc_dtbsize(),
423 &readfds
, NULL
, NULL
, &(ct
->ct_wait
))) {
425 ct
->ct_error
.re_status
= RPC_TIMEDOUT
;
431 ct
->ct_error
.re_status
= RPC_CANTRECV
;
432 ct
->ct_error
.re_errno
= errno
;
437 switch (len
= read(ct
->ct_sock
, buf
, len
)) {
441 ct
->ct_error
.re_errno
= ECONNRESET
;
442 ct
->ct_error
.re_status
= RPC_CANTRECV
;
443 len
= -1; /* it's really an error */
447 ct
->ct_error
.re_errno
= errno
;
448 ct
->ct_error
.re_status
= RPC_CANTRECV
;
455 writetcp(ct
, buf
, len
)
462 for (cnt
= len
; cnt
> 0; cnt
-= i
, buf
+= i
) {
463 if ((i
= write(ct
->ct_sock
, buf
, cnt
)) == -1) {
464 ct
->ct_error
.re_errno
= errno
;
465 ct
->ct_error
.re_status
= RPC_CANTSEND
;
472 static struct clnt_ops
*
475 static struct clnt_ops ops
;
477 if (ops
.cl_call
== NULL
) {
478 ops
.cl_call
= clnttcp_call
;
479 ops
.cl_abort
= clnttcp_abort
;
480 ops
.cl_geterr
= clnttcp_geterr
;
481 ops
.cl_freeres
= clnttcp_freeres
;
482 ops
.cl_destroy
= clnttcp_destroy
;
483 ops
.cl_control
= clnttcp_control
;