1 /* @(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC */ 2 /* 3 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 4 * unrestricted use provided that this legend is included on all tape 5 * media and as a part of the software program in whole or part. Users 6 * may copy or modify Sun RPC without charge, but are not authorized 7 * to license or distribute it to anyone else except as part of a product or 8 * program developed by the user. 9 * 10 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 11 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 12 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 13 * 14 * Sun RPC is provided with no support and without any obligation on the 15 * part of Sun Microsystems, Inc. to assist in its use, correction, 16 * modification or enhancement. 17 * 18 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 19 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 20 * OR ANY PART THEREOF. 21 * 22 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 23 * or profits or other special, indirect and consequential damages, even if 24 * Sun has been advised of the possibility of such damages. 25 * 26 * Sun Microsystems, Inc. 27 * 2550 Garcia Avenue 28 * Mountain View, California 94043 29 */ 30 #if !defined(lint) && defined(SCCSIDS) 31 static char sccsid[] = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro"; 32 #endif 33 34 /* 35 * clnt_tcp.c, Implements a TCP/IP based, client side RPC. 36 * 37 * Copyright (C) 1984, Sun Microsystems, Inc. 38 * 39 * TCP based RPC supports 'batched calls'. 40 * A sequence of calls may be batched-up in a send buffer. The rpc call 41 * return immediately to the client even though the call was not necessarily 42 * sent. The batching occurs if the results' xdr routine is NULL (0) AND 43 * the rpc timeout value is zero (see clnt.h, rpc). 44 * 45 * Clients should NOT casually batch calls that in fact return results; that is, 46 * the server side should be aware that a call is batched and not produce any 47 * return message. Batched calls that produce many result messages can 48 * deadlock (netlock) the client and the server.... 49 * 50 * Now go hang yourself. 51 */ 52 53 #include <stdio.h> 54 #include <rpc/rpc.h> 55 #include <sys/socket.h> 56 #include <netdb.h> 57 #include <errno.h> 58 #include <rpc/pmap_clnt.h> 59 60 #define MCALL_MSG_SIZE 24 61 62 extern int errno; 63 64 static int readtcp(); 65 static int writetcp(); 66 67 static enum clnt_stat clnttcp_call(); 68 static void clnttcp_abort(); 69 static void clnttcp_geterr(); 70 static bool_t clnttcp_freeres(); 71 static bool_t clnttcp_control(); 72 static void clnttcp_destroy(); 73 74 static struct clnt_ops tcp_ops = { 75 clnttcp_call, 76 clnttcp_abort, 77 clnttcp_geterr, 78 clnttcp_freeres, 79 clnttcp_destroy, 80 clnttcp_control 81 }; 82 83 struct ct_data { 84 int ct_sock; 85 bool_t ct_closeit; 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 */ 92 XDR ct_xdrs; 93 }; 94 95 /* 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 set this 107 * something more useful. 108 */ 109 CLIENT * 110 clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) 111 struct sockaddr_in *raddr; 112 u_long prog; 113 u_long vers; 114 register int *sockp; 115 u_int sendsz; 116 u_int recvsz; 117 { 118 CLIENT *h; 119 register struct ct_data *ct; 120 struct timeval now; 121 struct rpc_msg call_msg; 122 123 h = (CLIENT *)mem_alloc(sizeof(*h)); 124 if (h == NULL) { 125 (void)fprintf(stderr, "clnttcp_create: out of memory\n"); 126 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 127 rpc_createerr.cf_error.re_errno = errno; 128 goto fooy; 129 } 130 ct = (struct ct_data *)mem_alloc(sizeof(*ct)); 131 if (ct == NULL) { 132 (void)fprintf(stderr, "clnttcp_create: out of memory\n"); 133 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 134 rpc_createerr.cf_error.re_errno = errno; 135 goto fooy; 136 } 137 138 /* 139 * If no port number given ask the pmap for one 140 */ 141 if (raddr->sin_port == 0) { 142 u_short port; 143 if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) { 144 mem_free((caddr_t)ct, sizeof(struct ct_data)); 145 mem_free((caddr_t)h, sizeof(CLIENT)); 146 return ((CLIENT *)NULL); 147 } 148 raddr->sin_port = htons(port); 149 } 150 151 /* 152 * If no socket given, open one 153 */ 154 if (*sockp < 0) { 155 *sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 156 (void)bindresvport(*sockp, (struct sockaddr_in *)0); 157 if ((*sockp < 0) 158 || (connect(*sockp, (struct sockaddr *)raddr, 159 sizeof(*raddr)) < 0)) { 160 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 161 rpc_createerr.cf_error.re_errno = errno; 162 (void)close(*sockp); 163 goto fooy; 164 } 165 ct->ct_closeit = TRUE; 166 } else { 167 ct->ct_closeit = FALSE; 168 } 169 170 /* 171 * Set up private data struct 172 */ 173 ct->ct_sock = *sockp; 174 ct->ct_wait.tv_usec = 0; 175 ct->ct_waitset = FALSE; 176 ct->ct_addr = *raddr; 177 178 /* 179 * Initialize call message 180 */ 181 (void)gettimeofday(&now, (struct timezone *)0); 182 call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec; 183 call_msg.rm_direction = CALL; 184 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 185 call_msg.rm_call.cb_prog = prog; 186 call_msg.rm_call.cb_vers = vers; 187 188 /* 189 * pre-serialize the staic part of the call msg and stash it away 190 */ 191 xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, 192 XDR_ENCODE); 193 if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { 194 if (ct->ct_closeit) { 195 (void)close(*sockp); 196 } 197 goto fooy; 198 } 199 ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); 200 XDR_DESTROY(&(ct->ct_xdrs)); 201 202 /* 203 * Create a client handle which uses xdrrec for serialization 204 * and authnone for authentication. 205 */ 206 xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, 207 (caddr_t)ct, readtcp, writetcp); 208 h->cl_ops = &tcp_ops; 209 h->cl_private = (caddr_t) ct; 210 h->cl_auth = authnone_create(); 211 return (h); 212 213 fooy: 214 /* 215 * Something goofed, free stuff and barf 216 */ 217 mem_free((caddr_t)ct, sizeof(struct ct_data)); 218 mem_free((caddr_t)h, sizeof(CLIENT)); 219 return ((CLIENT *)NULL); 220 } 221 222 static enum clnt_stat 223 clnttcp_call(h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout) 224 register CLIENT *h; 225 u_long proc; 226 xdrproc_t xdr_args; 227 caddr_t args_ptr; 228 xdrproc_t xdr_results; 229 caddr_t results_ptr; 230 struct timeval timeout; 231 { 232 register struct ct_data *ct = (struct ct_data *) h->cl_private; 233 register XDR *xdrs = &(ct->ct_xdrs); 234 struct rpc_msg reply_msg; 235 u_long x_id; 236 u_long *msg_x_id = (u_long *)(ct->ct_mcall); /* yuk */ 237 register bool_t shipnow; 238 int refreshes = 2; 239 240 if (!ct->ct_waitset) { 241 ct->ct_wait = timeout; 242 } 243 244 shipnow = 245 (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0 246 && timeout.tv_usec == 0) ? FALSE : TRUE; 247 248 call_again: 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 (void)xdrrec_endofrecord(xdrs, TRUE); 259 return (ct->ct_error.re_status); 260 } 261 if (! xdrrec_endofrecord(xdrs, shipnow)) 262 return (ct->ct_error.re_status = RPC_CANTSEND); 263 if (! shipnow) 264 return (RPC_SUCCESS); 265 /* 266 * Hack to provide rpc-based message passing 267 */ 268 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 269 return(ct->ct_error.re_status = RPC_TIMEDOUT); 270 } 271 272 273 /* 274 * Keep receiving until we get a valid transaction id 275 */ 276 xdrs->x_op = XDR_DECODE; 277 while (TRUE) { 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) 286 continue; 287 return (ct->ct_error.re_status); 288 } 289 if (reply_msg.rm_xid == x_id) 290 break; 291 } 292 293 /* 294 * process header 295 */ 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; 304 } 305 /* free verifier ... */ 306 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 307 xdrs->x_op = XDR_FREE; 308 (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); 309 } 310 } /* end successful completion */ 311 else { 312 /* maybe our credentials need to be refreshed ... */ 313 if (refreshes-- && AUTH_REFRESH(h->cl_auth)) 314 goto call_again; 315 } /* end of unsuccessful completion */ 316 return (ct->ct_error.re_status); 317 } 318 319 static void 320 clnttcp_geterr(h, errp) 321 CLIENT *h; 322 struct rpc_err *errp; 323 { 324 register struct ct_data *ct = 325 (struct ct_data *) h->cl_private; 326 327 *errp = ct->ct_error; 328 } 329 330 static bool_t 331 clnttcp_freeres(cl, xdr_res, res_ptr) 332 CLIENT *cl; 333 xdrproc_t xdr_res; 334 caddr_t res_ptr; 335 { 336 register struct ct_data *ct = (struct ct_data *)cl->cl_private; 337 register XDR *xdrs = &(ct->ct_xdrs); 338 339 xdrs->x_op = XDR_FREE; 340 return ((*xdr_res)(xdrs, res_ptr)); 341 } 342 343 static void 344 clnttcp_abort() 345 { 346 } 347 348 static bool_t 349 clnttcp_control(cl, request, info) 350 CLIENT *cl; 351 int request; 352 char *info; 353 { 354 register struct ct_data *ct = (struct ct_data *)cl->cl_private; 355 356 switch (request) { 357 case CLSET_TIMEOUT: 358 ct->ct_wait = *(struct timeval *)info; 359 ct->ct_waitset = TRUE; 360 break; 361 case CLGET_TIMEOUT: 362 *(struct timeval *)info = ct->ct_wait; 363 break; 364 case CLGET_SERVER_ADDR: 365 *(struct sockaddr_in *)info = ct->ct_addr; 366 break; 367 default: 368 return (FALSE); 369 } 370 return (TRUE); 371 } 372 373 374 static void 375 clnttcp_destroy(h) 376 CLIENT *h; 377 { 378 register struct ct_data *ct = 379 (struct ct_data *) h->cl_private; 380 381 if (ct->ct_closeit) { 382 (void)close(ct->ct_sock); 383 } 384 XDR_DESTROY(&(ct->ct_xdrs)); 385 mem_free((caddr_t)ct, sizeof(struct ct_data)); 386 mem_free((caddr_t)h, sizeof(CLIENT)); 387 } 388 389 /* 390 * Interface between xdr serializer and tcp connection. 391 * Behaves like the system calls, read & write, but keeps some error state 392 * around for the rpc level. 393 */ 394 static int 395 readtcp(ct, buf, len) 396 register struct ct_data *ct; 397 caddr_t buf; 398 register int len; 399 { 400 #ifdef FD_SETSIZE 401 fd_set mask; 402 fd_set readfds; 403 404 if (len == 0) 405 return (0); 406 FD_ZERO(&mask); 407 FD_SET(ct->ct_sock, &mask); 408 #else 409 register int mask = 1 << (ct->ct_sock); 410 int readfds; 411 412 if (len == 0) 413 return (0); 414 415 #endif /* def FD_SETSIZE */ 416 while (TRUE) { 417 readfds = mask; 418 switch (select(_rpc_dtablesize(), &readfds, (int*)NULL, (int*)NULL, 419 &(ct->ct_wait))) { 420 case 0: 421 ct->ct_error.re_status = RPC_TIMEDOUT; 422 return (-1); 423 424 case -1: 425 if (errno == EINTR) 426 continue; 427 ct->ct_error.re_status = RPC_CANTRECV; 428 ct->ct_error.re_errno = errno; 429 return (-1); 430 } 431 break; 432 } 433 switch (len = read(ct->ct_sock, buf, len)) { 434 435 case 0: 436 /* premature eof */ 437 ct->ct_error.re_errno = ECONNRESET; 438 ct->ct_error.re_status = RPC_CANTRECV; 439 len = -1; /* it's really an error */ 440 break; 441 442 case -1: 443 ct->ct_error.re_errno = errno; 444 ct->ct_error.re_status = RPC_CANTRECV; 445 break; 446 } 447 return (len); 448 } 449 450 static int 451 writetcp(ct, buf, len) 452 struct ct_data *ct; 453 caddr_t buf; 454 int len; 455 { 456 register int i, cnt; 457 458 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 459 if ((i = write(ct->ct_sock, buf, cnt)) == -1) { 460 ct->ct_error.re_errno = errno; 461 ct->ct_error.re_status = RPC_CANTSEND; 462 return (-1); 463 } 464 } 465 return (len); 466 } 467