1 /* 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. 8 * 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. 12 * 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. 16 * 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. 20 * 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. 24 * 25 * Sun Microsystems, Inc. 26 * 2550 Garcia Avenue 27 * Mountain View, California 94043 28 */ 29 30 #if defined(LIBC_SCCS) && !defined(lint) 31 static char *rcsid = "$OpenBSD: clnt_tcp.c,v 1.11 1996/12/10 07:46:37 deraadt Exp $"; 32 #endif /* LIBC_SCCS and not lint */ 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 <stdlib.h> 55 #include <unistd.h> 56 #include <rpc/rpc.h> 57 #include <sys/socket.h> 58 #include <netdb.h> 59 #include <errno.h> 60 #include <rpc/pmap_clnt.h> 61 62 #define MCALL_MSG_SIZE 24 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 static u_int32_t disrupt; 123 124 if (disrupt == 0) 125 disrupt = (u_int32_t)(long)raddr; 126 127 h = (CLIENT *)mem_alloc(sizeof(*h)); 128 if (h == NULL) { 129 (void)fprintf(stderr, "clnttcp_create: out of memory\n"); 130 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 131 rpc_createerr.cf_error.re_errno = errno; 132 goto fooy; 133 } 134 ct = (struct ct_data *)mem_alloc(sizeof(*ct)); 135 if (ct == NULL) { 136 (void)fprintf(stderr, "clnttcp_create: out of memory\n"); 137 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 138 rpc_createerr.cf_error.re_errno = errno; 139 goto fooy; 140 } 141 142 /* 143 * If no port number given ask the pmap for one 144 */ 145 if (raddr->sin_port == 0) { 146 u_short port; 147 if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) { 148 mem_free((caddr_t)ct, sizeof(struct ct_data)); 149 mem_free((caddr_t)h, sizeof(CLIENT)); 150 return ((CLIENT *)NULL); 151 } 152 raddr->sin_port = htons(port); 153 } 154 155 /* 156 * If no socket given, open one 157 */ 158 if (*sockp < 0) { 159 *sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 160 (void)bindresvport(*sockp, (struct sockaddr_in *)0); 161 if ((*sockp < 0) 162 || (connect(*sockp, (struct sockaddr *)raddr, 163 sizeof(*raddr)) < 0)) { 164 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 165 rpc_createerr.cf_error.re_errno = errno; 166 if (*sockp != -1) 167 (void)close(*sockp); 168 goto fooy; 169 } 170 ct->ct_closeit = TRUE; 171 } else { 172 ct->ct_closeit = FALSE; 173 } 174 175 /* 176 * Set up private data struct 177 */ 178 ct->ct_sock = *sockp; 179 ct->ct_wait.tv_usec = 0; 180 ct->ct_waitset = FALSE; 181 ct->ct_addr = *raddr; 182 183 /* 184 * Initialize call message 185 */ 186 (void)gettimeofday(&now, (struct timezone *)0); 187 call_msg.rm_xid = (++disrupt) ^ getpid() ^ now.tv_sec ^ now.tv_usec; 188 call_msg.rm_direction = CALL; 189 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 190 call_msg.rm_call.cb_prog = prog; 191 call_msg.rm_call.cb_vers = vers; 192 193 /* 194 * pre-serialize the staic part of the call msg and stash it away 195 */ 196 xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, 197 XDR_ENCODE); 198 if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { 199 if (ct->ct_closeit) { 200 (void)close(*sockp); 201 } 202 goto fooy; 203 } 204 ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); 205 XDR_DESTROY(&(ct->ct_xdrs)); 206 207 /* 208 * Create a client handle which uses xdrrec for serialization 209 * and authnone for authentication. 210 */ 211 xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, 212 (caddr_t)ct, readtcp, writetcp); 213 h->cl_ops = &tcp_ops; 214 h->cl_private = (caddr_t) ct; 215 h->cl_auth = authnone_create(); 216 return (h); 217 218 fooy: 219 /* 220 * Something goofed, free stuff and barf 221 */ 222 if (ct) 223 mem_free((caddr_t)ct, sizeof(struct ct_data)); 224 if (h) 225 mem_free((caddr_t)h, sizeof(CLIENT)); 226 return ((CLIENT *)NULL); 227 } 228 229 static enum clnt_stat 230 clnttcp_call(h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout) 231 register CLIENT *h; 232 u_long proc; 233 xdrproc_t xdr_args; 234 caddr_t args_ptr; 235 xdrproc_t xdr_results; 236 caddr_t results_ptr; 237 struct timeval timeout; 238 { 239 register struct ct_data *ct = (struct ct_data *) h->cl_private; 240 register XDR *xdrs = &(ct->ct_xdrs); 241 struct rpc_msg reply_msg; 242 u_long x_id; 243 u_int32_t *msg_x_id = (u_int32_t *)(ct->ct_mcall); /* yuk */ 244 register bool_t shipnow; 245 int refreshes = 2; 246 247 if (!ct->ct_waitset) { 248 ct->ct_wait = timeout; 249 } 250 251 shipnow = 252 (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0 253 && timeout.tv_usec == 0) ? FALSE : TRUE; 254 255 call_again: 256 xdrs->x_op = XDR_ENCODE; 257 ct->ct_error.re_status = RPC_SUCCESS; 258 x_id = ntohl(--(*msg_x_id)); 259 if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) || 260 (! XDR_PUTLONG(xdrs, (long *)&proc)) || 261 (! AUTH_MARSHALL(h->cl_auth, xdrs)) || 262 (! (*xdr_args)(xdrs, args_ptr))) { 263 if (ct->ct_error.re_status == RPC_SUCCESS) 264 ct->ct_error.re_status = RPC_CANTENCODEARGS; 265 (void)xdrrec_endofrecord(xdrs, TRUE); 266 return (ct->ct_error.re_status); 267 } 268 if (! xdrrec_endofrecord(xdrs, shipnow)) 269 return (ct->ct_error.re_status = RPC_CANTSEND); 270 if (! shipnow) 271 return (RPC_SUCCESS); 272 /* 273 * Hack to provide rpc-based message passing 274 */ 275 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 276 return(ct->ct_error.re_status = RPC_TIMEDOUT); 277 } 278 279 280 /* 281 * Keep receiving until we get a valid transaction id 282 */ 283 xdrs->x_op = XDR_DECODE; 284 while (TRUE) { 285 reply_msg.acpted_rply.ar_verf = _null_auth; 286 reply_msg.acpted_rply.ar_results.where = NULL; 287 reply_msg.acpted_rply.ar_results.proc = xdr_void; 288 if (! xdrrec_skiprecord(xdrs)) 289 return (ct->ct_error.re_status); 290 /* now decode and validate the response header */ 291 if (! xdr_replymsg(xdrs, &reply_msg)) { 292 if (ct->ct_error.re_status == RPC_SUCCESS) 293 continue; 294 return (ct->ct_error.re_status); 295 } 296 if (reply_msg.rm_xid == x_id) 297 break; 298 } 299 300 /* 301 * process header 302 */ 303 _seterr_reply(&reply_msg, &(ct->ct_error)); 304 if (ct->ct_error.re_status == RPC_SUCCESS) { 305 if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) { 306 ct->ct_error.re_status = RPC_AUTHERROR; 307 ct->ct_error.re_why = AUTH_INVALIDRESP; 308 } else if (! (*xdr_results)(xdrs, results_ptr)) { 309 if (ct->ct_error.re_status == RPC_SUCCESS) 310 ct->ct_error.re_status = RPC_CANTDECODERES; 311 } 312 /* free verifier ... */ 313 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 314 xdrs->x_op = XDR_FREE; 315 (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); 316 } 317 } /* end successful completion */ 318 else { 319 /* maybe our credentials need to be refreshed ... */ 320 if (refreshes-- && AUTH_REFRESH(h->cl_auth)) 321 goto call_again; 322 } /* end of unsuccessful completion */ 323 return (ct->ct_error.re_status); 324 } 325 326 static void 327 clnttcp_geterr(h, errp) 328 CLIENT *h; 329 struct rpc_err *errp; 330 { 331 register struct ct_data *ct = 332 (struct ct_data *) h->cl_private; 333 334 *errp = ct->ct_error; 335 } 336 337 static bool_t 338 clnttcp_freeres(cl, xdr_res, res_ptr) 339 CLIENT *cl; 340 xdrproc_t xdr_res; 341 caddr_t res_ptr; 342 { 343 register struct ct_data *ct = (struct ct_data *)cl->cl_private; 344 register XDR *xdrs = &(ct->ct_xdrs); 345 346 xdrs->x_op = XDR_FREE; 347 return ((*xdr_res)(xdrs, res_ptr)); 348 } 349 350 static void 351 clnttcp_abort() 352 { 353 } 354 355 static bool_t 356 clnttcp_control(cl, request, info) 357 CLIENT *cl; 358 int request; 359 char *info; 360 { 361 register struct ct_data *ct = (struct ct_data *)cl->cl_private; 362 363 switch (request) { 364 case CLSET_TIMEOUT: 365 ct->ct_wait = *(struct timeval *)info; 366 ct->ct_waitset = TRUE; 367 break; 368 case CLGET_TIMEOUT: 369 *(struct timeval *)info = ct->ct_wait; 370 break; 371 case CLGET_SERVER_ADDR: 372 *(struct sockaddr_in *)info = ct->ct_addr; 373 break; 374 default: 375 return (FALSE); 376 } 377 return (TRUE); 378 } 379 380 381 static void 382 clnttcp_destroy(h) 383 CLIENT *h; 384 { 385 register struct ct_data *ct = 386 (struct ct_data *) h->cl_private; 387 388 if (ct->ct_closeit) { 389 (void)close(ct->ct_sock); 390 } 391 XDR_DESTROY(&(ct->ct_xdrs)); 392 mem_free((caddr_t)ct, sizeof(struct ct_data)); 393 mem_free((caddr_t)h, sizeof(CLIENT)); 394 } 395 396 /* 397 * Interface between xdr serializer and tcp connection. 398 * Behaves like the system calls, read & write, but keeps some error state 399 * around for the rpc level. 400 */ 401 static int 402 readtcp(ct, buf, len) 403 register struct ct_data *ct; 404 caddr_t buf; 405 register int len; 406 { 407 fd_set *fds, readfds; 408 struct timeval start, after, duration, delta, tmp; 409 int r, save_errno; 410 411 if (len == 0) 412 return (0); 413 414 if (ct->ct_sock+1 > FD_SETSIZE) { 415 int bytes = howmany(ct->ct_sock+1, NFDBITS) * sizeof(fd_mask); 416 fds = (fd_set *)malloc(bytes); 417 if (fds == NULL) 418 return (-1); 419 memset(fds, 0, bytes); 420 } else { 421 fds = &readfds; 422 FD_ZERO(fds); 423 } 424 425 gettimeofday(&start, NULL); 426 delta = ct->ct_wait; 427 while (TRUE) { 428 /* XXX we know the other bits are still clear */ 429 FD_SET(ct->ct_sock, fds); 430 r = select(ct->ct_sock+1, fds, NULL, NULL, &delta); 431 save_errno = errno; 432 433 gettimeofday(&after, NULL); 434 timersub(&start, &after, &duration); 435 timersub(&delta, &duration, &tmp); 436 delta = tmp; 437 if (delta.tv_sec < 0 || !timerisset(&delta)) 438 r = 0; 439 440 switch (r) { 441 case 0: 442 ct->ct_error.re_status = RPC_TIMEDOUT; 443 if (fds != &readfds) 444 free(fds); 445 return (-1); 446 case -1: 447 if (errno == EINTR) 448 continue; 449 ct->ct_error.re_status = RPC_CANTRECV; 450 ct->ct_error.re_errno = save_errno; 451 if (fds != &readfds) 452 free(fds); 453 return (-1); 454 } 455 break; 456 } 457 if (fds != &readfds) 458 free(fds); 459 460 switch (len = read(ct->ct_sock, buf, len)) { 461 case 0: 462 /* premature eof */ 463 ct->ct_error.re_errno = ECONNRESET; 464 ct->ct_error.re_status = RPC_CANTRECV; 465 len = -1; /* it's really an error */ 466 break; 467 case -1: 468 ct->ct_error.re_errno = errno; 469 ct->ct_error.re_status = RPC_CANTRECV; 470 break; 471 } 472 return (len); 473 } 474 475 static int 476 writetcp(ct, buf, len) 477 struct ct_data *ct; 478 caddr_t buf; 479 int len; 480 { 481 register int i, cnt; 482 483 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 484 if ((i = write(ct->ct_sock, buf, cnt)) == -1) { 485 ct->ct_error.re_errno = errno; 486 ct->ct_error.re_status = RPC_CANTSEND; 487 return (-1); 488 } 489 } 490 return (len); 491 } 492