2 static char sfs_ctcp_id[] = "@(#)sfs_ctcp.c 2.1 97/10/23";
4 /* @(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC */
6 * Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
8 * Standard Performance Evaluation Corporation (SPEC)
9 * 6585 Merchant Place, Suite 100
12 * This product contains benchmarks acquired from several sources who
13 * understand and agree with SPEC's goal of creating fair and objective
14 * benchmarks to measure computer performance.
16 * This copyright notice is placed here only to protect SPEC in the
17 * event the source is misused in any manner that is contrary to the
18 * spirit, the goals and the intent of SPEC.
20 * The source code is provided to the user or company under the license
21 * agreement for the SPEC Benchmark Suite for this product.
24 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
25 * unrestricted use provided that this legend is included on all tape
26 * media and as a part of the software program in whole or part. Users
27 * may copy or modify Sun RPC without charge, but are not authorized
28 * to license or distribute it to anyone else except as part of a product or
29 * program developed by the user.
31 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
32 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
33 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
35 * Sun RPC is provided with no support and without any obligation on the
36 * part of Sun Microsystems, Inc. to assist in its use, correction,
37 * modification or enhancement.
39 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
40 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
41 * OR ANY PART THEREOF.
43 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
44 * or profits or other special, indirect and consequential damages, even if
45 * Sun has been advised of the possibility of such damages.
47 * Sun Microsystems, Inc.
49 * Mountain View, California 94043
51 #if !defined(lint) && defined(SCCSIDS)
52 static char sccsid[] = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";
56 * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
58 * Copyright (C) 1984, Sun Microsystems, Inc.
60 * TCP based RPC supports 'batched calls'.
61 * A sequence of calls may be batched-up in a send buffer. The rpc call
62 * return immediately to the client even though the call was not necessarily
63 * sent. The batching occurs if the results' xdr routine is NULL (0) AND
64 * the rpc timeout value is zero (see clnt.h, rpc).
66 * Clients should NOT casually batch calls that in fact return results; that is,
67 * the server side should be aware that a call is batched and not produce any
68 * return message. Batched calls that produce many result messages can
69 * deadlock (netlock) the client and the server....
71 * Now go hang yourself.
80 #include "rpc/osdep.h"
83 #include "rpc/pmap_clnt.h"
85 #define MCALL_MSG_SIZE 24
90 struct timeval ct_wait;
91 struct sockaddr_in ct_addr;
92 struct sockaddr_in ct_oaddr;
93 struct rpc_err ct_error;
94 char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */
95 uint_t ct_mpos; /* pos after marshal */
104 static int readtcp(struct ct_data *, char *, int);
105 static int writetcp(struct ct_data *ct, char * buf, int len);
107 static enum clnt_stat sfs_ctcp_call(CLIENT *, uint32_t, xdrproc_t, void *,
108 xdrproc_t, void *, struct timeval);
109 static void sfs_ctcp_abort(CLIENT *);
110 static void sfs_ctcp_geterr(CLIENT *, struct rpc_err *);
111 static bool_t sfs_ctcp_freeres(CLIENT *, xdrproc_t, void *);
112 static bool_t sfs_ctcp_control(CLIENT *, uint_t, void *);
113 static void sfs_ctcp_destroy(CLIENT *);
114 static bool_t sfs_ctcp_getreply(CLIENT *, xdrproc_t, void *,
115 int, uint32_t *, uint32_t *, struct timeval *);
116 static int sfs_ctcp_poll(CLIENT *, uint32_t);
118 static struct clnt_ops tcp_ops = {
132 struct sockaddr_in *raddr,
141 #if defined(UNIXWARE) || defined(AIX)
147 if (ct->ct_first == 0)
152 (void) fprintf(stderr, "Re-establishing connection.\n");
156 * If no port number given ask the pmap for one
158 if (raddr->sin_port == 0) {
160 if ((port = pmap_getport(raddr, ct->ct_prog, ct->ct_vers,
161 IPPROTO_TCP)) == 0) {
164 raddr->sin_port = htons(port);
168 * If no socket given, open one
171 ct->ct_closeit = FALSE;
175 ct->ct_closeit = TRUE;
177 *sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
178 (void)bindresvport(*sockp, (struct sockaddr_in *)0);
180 || (connect(*sockp, (struct sockaddr *)raddr,
181 sizeof(struct sockaddr_in)) < 0)) {
186 * Need to try to size the socket buffers based on the number of
187 * outstanding requests desired. NFS reads and writes can do as
188 * much as 8K per request which can quickly run us out of space
189 * on the socket buffer queue. Use the maximum number of bio style
190 * requests * NFS_MAXDATA plus a pad as a starting point for desired
191 * socket buffer size and then back off by NFS_MAXDATA until the buffer
192 * sizes are successfully set. Note, the algorithm never sets the
193 * buffer size to less than the OS default.
196 for (i = 0; i < 2; i++) {
197 optlen = sizeof(min_buf_sz);
199 if (getsockopt(*sockp, SOL_SOCKET, type,
200 (void *)&min_buf_sz, &optlen) < 0) {
201 /* guess the default */
202 min_buf_sz = 18 * 1024;
205 if (getsockopt(*sockp, SOL_SOCKET, type,
206 (char *)&min_buf_sz, &optlen) < 0) {
207 /* guess the default */
208 min_buf_sz = 18 * 1024;
212 new_buf_sz = 512 * 1024;
213 if (new_buf_sz > min_buf_sz) {
215 error = setsockopt(*sockp, SOL_SOCKET,
216 type, (char *)&new_buf_sz,
218 new_buf_sz -= (8 * 1024);
219 } while (error != 0 && new_buf_sz > min_buf_sz);
226 setsockopt(*sockp, IPPROTO_TCP, TCP_NODELAY, (char *) &setopt,
228 #endif /* TCP_NODELAY */
234 * Create a client handle for a tcp/ip connection.
235 * If *sockp<0, *sockp is set to a newly created TCP socket and it is
236 * connected to raddr. If *sockp non-negative then
237 * raddr is ignored. The rpc/tcp package does buffering
238 * similar to stdio, so the client must pick send and receive buffer sizes,];
239 * 0 => use the default.
240 * If raddr->sin_port is 0, then a binder on the remote machine is
241 * consulted for the right port number.
242 * NB: *sockp is copied into a private area.
243 * NB: It is the clients responsibility to close *sockp.
244 * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this
245 * something more useful.
249 struct sockaddr_in *raddr,
259 struct rpc_msg call_msg;
261 h = (CLIENT *)mem_alloc(sizeof(CLIENT));
263 (void)fprintf(stderr, "clnttcp_create: out of memory\n");
264 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
265 rpc_createerr.cf_error.re_errno = errno;
268 ct = (struct ct_data *)mem_alloc(sizeof(struct ct_data));
270 (void)fprintf(stderr, "clnttcp_create: out of memory\n");
271 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
272 rpc_createerr.cf_error.re_errno = errno;
275 (void) memset(ct, '\0', sizeof (struct ct_data));
277 ct->ct_oaddr = *raddr;
281 if (sfs_ctcp_make_conn(ct, raddr, sockp) < 0) {
282 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
283 rpc_createerr.cf_error.re_errno = errno;
289 * Set up private data struct
291 ct->ct_sock = *sockp;
292 ct->ct_wait.tv_sec = 0;
293 ct->ct_wait.tv_usec = 0;
294 ct->ct_addr = *raddr;
297 * Initialize call message
299 (void)gettimeofday(&now, (struct timezone *)0);
300 call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
301 call_msg.rm_direction = CALL;
302 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
303 call_msg.rm_call.cb_prog = prog;
304 call_msg.rm_call.cb_vers = vers;
307 * pre-serialize the static part of the call msg and stash it away
309 xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE,
311 if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
312 if (ct->ct_closeit) {
317 ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
318 XDR_DESTROY(&(ct->ct_xdrs));
321 * Create a client handle which uses xdrrec for serialization
322 * and authnone for authentication.
324 xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
325 (void *)ct, readtcp, writetcp);
326 ct->ct_sendsz = sendsz;
327 ct->ct_recvsz = recvsz;
328 h->cl_ops = &tcp_ops;
329 h->cl_private = (void *) ct;
330 h->cl_auth = authnone_create();
335 * Something goofed, free stuff and barf
337 mem_free((void *)ct, sizeof(struct ct_data));
338 mem_free((void *)h, sizeof(CLIENT));
339 return ((CLIENT *)NULL);
342 static enum clnt_stat
345 struct rpc_msg *reply_msg)
347 struct ct_data *ct = (struct ct_data *) h->cl_private;
348 XDR *xdrs = &(ct->ct_xdrs);
352 reply_msg->acpted_rply.ar_verf = _null_auth;
353 reply_msg->acpted_rply.ar_results.where = NULL;
354 reply_msg->acpted_rply.ar_results.proc = xdr_void;
355 if (! xdrrec_skiprecord(xdrs)) {
356 return (ct->ct_error.re_status);
358 /* now decode and validate the response header */
359 if (! xdr_replymsg(xdrs, reply_msg)) {
360 if (ct->ct_error.re_status == RPC_SUCCESS)
363 return (ct->ct_error.re_status);
367 static enum clnt_stat
370 struct rpc_msg *reply_msg,
371 xdrproc_t xdr_results,
374 struct ct_data *ct = (struct ct_data *) h->cl_private;
375 XDR *xdrs = &(ct->ct_xdrs);
380 _seterr_reply(reply_msg, &(ct->ct_error));
381 if (ct->ct_error.re_status == RPC_SUCCESS) {
382 if (! AUTH_VALIDATE(h->cl_auth,
383 &reply_msg->acpted_rply.ar_verf)) {
384 ct->ct_error.re_status = RPC_AUTHERROR;
385 ct->ct_error.re_why = AUTH_INVALIDRESP;
386 } else if (! (*xdr_results)(xdrs, results_ptr)) {
387 if (ct->ct_error.re_status == RPC_SUCCESS)
388 ct->ct_error.re_status = RPC_CANTDECODERES;
390 /* free verifier ... */
391 if (reply_msg->acpted_rply.ar_verf.oa_base != NULL) {
392 xdrs->x_op = XDR_FREE;
393 (void)xdr_opaque_auth(xdrs,
394 &(reply_msg->acpted_rply.ar_verf));
396 } /* end successful completion */
397 return (ct->ct_error.re_status);
400 static enum clnt_stat
406 xdrproc_t xdr_results,
408 struct timeval timeout)
410 struct ct_data *ct = (struct ct_data *) h->cl_private;
411 XDR *xdrs = &(ct->ct_xdrs);
412 struct rpc_msg reply_msg;
414 uint32_t *msg_x_id = (uint32_t *)(ct->ct_mcall); /* yuk */
417 ct->ct_wait = timeout;
420 (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0
421 && timeout.tv_usec == 0) ? FALSE : TRUE;
423 xdrs->x_op = XDR_ENCODE;
424 ct->ct_error.re_status = RPC_SUCCESS;
425 x_id = ntohl(--(*msg_x_id));
426 if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) ||
427 (! XDR_PUTLONG(xdrs, (int32_t *)&proc)) ||
428 (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
429 (! (*xdr_args)(xdrs, args_ptr))) {
430 if (ct->ct_error.re_status == RPC_SUCCESS)
431 ct->ct_error.re_status = RPC_CANTENCODEARGS;
432 (void)xdrrec_endofrecord(xdrs, TRUE);
433 return (ct->ct_error.re_status);
435 if (! xdrrec_endofrecord(xdrs, TRUE))
436 return (ct->ct_error.re_status = RPC_CANTSEND);
438 * Hack to provide rpc-based message passing
440 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
441 if (! shipnow && results_ptr == NULL)
442 return (RPC_SUCCESS);
445 * Double hack, send back xid in results_prt if non-NULL
447 *(uint32_t *)results_ptr = x_id;
448 return(ct->ct_error.re_status = RPC_TIMEDOUT);
453 * Keep receiving until we get a valid transaction id
455 xdrs->x_op = XDR_DECODE;
460 if ((res = get_areply(h, &reply_msg)) != RPC_SUCCESS)
463 if (reply_msg.rm_xid == x_id)
470 return (proc_header(h, &reply_msg, xdr_results, results_ptr));
476 struct rpc_err *errp)
479 (struct ct_data *) h->cl_private;
481 *errp = ct->ct_error;
490 struct ct_data *ct = (struct ct_data *)cl->cl_private;
491 XDR *xdrs = &(ct->ct_xdrs);
493 xdrs->x_op = XDR_FREE;
494 return ((*xdr_res)(xdrs, res_ptr));
499 sfs_ctcp_abort(CLIENT *h)
509 struct ct_data *ct = (struct ct_data *)cl->cl_private;
512 case CLGET_SERVER_ADDR:
513 *(struct sockaddr_in *)info = ct->ct_addr;
527 (struct ct_data *) h->cl_private;
529 if (ct->ct_closeit) {
530 (void)close(ct->ct_sock);
532 XDR_DESTROY(&(ct->ct_xdrs));
533 mem_free((void *)ct, sizeof(struct ct_data));
534 mem_free((void *)h, sizeof(CLIENT));
538 * Interface between xdr serializer and tcp connection.
539 * Behaves like the system calls, read & write, but keeps some error state
540 * around for the rpc level.
543 readtcp(struct ct_data *ct,
552 FD_SET(ct->ct_sock, &mask);
554 int mask = 1 << (ct->ct_sock);
556 #endif /* def FD_SETSIZE */
564 switch (select(_rpc_dtablesize(), &readfds, NULL, NULL,
567 ct->ct_error.re_status = RPC_TIMEDOUT;
573 ct->ct_error.re_status = RPC_CANTRECV;
574 ct->ct_error.re_errno = errno;
579 switch (len = read(ct->ct_sock, buf, len)) {
583 ct->ct_error.re_errno = ECONNRESET;
584 ct->ct_error.re_status = RPC_CANTRECV;
585 len = -1; /* it's really an error */
589 ct->ct_error.re_errno = errno;
590 ct->ct_error.re_status = RPC_CANTRECV;
596 * We have lost our connection to the server. Try and
599 (void) close(ct->ct_sock);
600 ct->ct_addr = ct->ct_oaddr;
602 XDR_DESTROY(&(ct->ct_xdrs));
604 (void) sfs_ctcp_make_conn(ct, &ct->ct_addr, &ct->ct_sock);
606 * Create a client handle which uses xdrrec for
607 * serialization and authnone for authentication.
609 xdrrec_create(&(ct->ct_xdrs), ct->ct_sendsz, ct->ct_recvsz,
610 (void *)ct, readtcp, writetcp);
622 for (cnt = len; cnt > 0; cnt -= i, buf += i) {
623 if ((i = write(ct->ct_sock, buf, cnt)) == -1) {
625 * We have lost our connection to the server. Try and
628 (void) close(ct->ct_sock);
629 ct->ct_addr = ct->ct_oaddr;
631 XDR_DESTROY(&(ct->ct_xdrs));
633 (void) sfs_ctcp_make_conn(ct, &ct->ct_addr,
636 * Create a client handle which uses xdrrec for
637 * serialization and authnone for authentication.
639 xdrrec_create(&(ct->ct_xdrs), ct->ct_sendsz,
641 (void *)ct, readtcp, writetcp);
642 ct->ct_error.re_errno = errno;
643 ct->ct_error.re_status = RPC_CANTSEND;
654 xdrproc_t xdr_results,
661 struct ct_data *ct = (struct ct_data *) cl->cl_private;
662 XDR *xdrs = &(ct->ct_xdrs);
663 struct rpc_msg reply_msg;
668 * Receive just one returning transaction id
670 xdrs->x_op = XDR_DECODE;
671 ct->ct_error.re_status = RPC_SUCCESS;
672 ct->ct_wait.tv_sec = tv->tv_sec;
673 ct->ct_wait.tv_usec = tv->tv_usec;
675 if ((res = get_areply(cl, &reply_msg)) != RPC_SUCCESS)
678 *xid = reply_msg.rm_xid;
681 * Check to make sure xid matchs one that we are interested in
683 for (i = 0; i < cnt; i++) {
689 return (RPC_CANTDECODERES);
694 return (proc_header(cl, &reply_msg, xdr_results, results_ptr));
703 struct ct_data *ct = (struct ct_data *)cl->cl_private;
704 XDR *xdrs = &(ct->ct_xdrs);
711 FD_SET(ct->ct_sock, &mask);
713 int mask = 1 << (ct->ct_sock);
715 #endif /* def FD_SETSIZE */
717 if (xdrrec_eof(xdrs) == FALSE)
722 tv.tv_sec = usecs / 1000000;
723 tv.tv_usec = usecs % 1000000;
726 return (select(_rpc_dtablesize(), &readfds, NULL, NULL, &tv));