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.16 1998/05/19 06:58:51 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 <string.h> 56 #include <unistd.h> 57 #include <rpc/rpc.h> 58 #include <sys/socket.h> 59 #include <netdb.h> 60 #include <errno.h> 61 #include <rpc/pmap_clnt.h> 62 63 #define MCALL_MSG_SIZE 24 64 65 static int readtcp(); 66 static int writetcp(); 67 68 static enum clnt_stat clnttcp_call(); 69 static void clnttcp_abort(); 70 static void clnttcp_geterr(); 71 static bool_t clnttcp_freeres(); 72 static bool_t clnttcp_control(); 73 static void clnttcp_destroy(); 74 75 static struct clnt_ops tcp_ops = { 76 clnttcp_call, 77 clnttcp_abort, 78 clnttcp_geterr, 79 clnttcp_freeres, 80 clnttcp_destroy, 81 clnttcp_control 82 }; 83 84 struct ct_data { 85 int ct_sock; 86 bool_t ct_closeit; 87 struct timeval ct_wait; 88 bool_t ct_waitset; /* wait set by clnt_control? */ 89 struct sockaddr_in ct_addr; 90 struct rpc_err ct_error; 91 char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */ 92 u_int ct_mpos; /* pos after marshal */ 93 XDR ct_xdrs; 94 }; 95 96 /* 97 * Create a client handle for a tcp/ip connection. 98 * If *sockp<0, *sockp is set to a newly created TCP socket and it is 99 * connected to raddr. If *sockp non-negative then 100 * raddr is ignored. The rpc/tcp package does buffering 101 * similar to stdio, so the client must pick send and receive buffer sizes,]; 102 * 0 => use the default. 103 * If raddr->sin_port is 0, then a binder on the remote machine is 104 * consulted for the right port number. 105 * NB: *sockp is copied into a private area. 106 * NB: It is the clients responsibility to close *sockp. 107 * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this 108 * something more useful. 109 */ 110 CLIENT * 111 clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) 112 struct sockaddr_in *raddr; 113 u_long prog; 114 u_long vers; 115 register int *sockp; 116 u_int sendsz; 117 u_int recvsz; 118 { 119 CLIENT *h; 120 register struct ct_data *ct; 121 struct timeval now; 122 struct rpc_msg call_msg; 123 124 h = (CLIENT *)mem_alloc(sizeof(*h)); 125 if (h == NULL) { 126 (void)fprintf(stderr, "clnttcp_create: out of memory\n"); 127 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 128 rpc_createerr.cf_error.re_errno = errno; 129 goto fooy; 130 } 131 ct = (struct ct_data *)mem_alloc(sizeof(*ct)); 132 if (ct == NULL) { 133 (void)fprintf(stderr, "clnttcp_create: out of memory\n"); 134 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 135 rpc_createerr.cf_error.re_errno = errno; 136 goto fooy; 137 } 138 139 /* 140 * If no port number given ask the pmap for one 141 */ 142 if (raddr->sin_port == 0) { 143 u_short port; 144 if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) { 145 mem_free((caddr_t)ct, sizeof(struct ct_data)); 146 mem_free((caddr_t)h, sizeof(CLIENT)); 147 return ((CLIENT *)NULL); 148 } 149 raddr->sin_port = htons(port); 150 } 151 152 /* 153 * If no socket given, open one 154 */ 155 if (*sockp < 0) { 156 *sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 157 (void)bindresvport(*sockp, (struct sockaddr_in *)0); 158 if ((*sockp < 0) 159 || (connect(*sockp, (struct sockaddr *)raddr, 160 sizeof(*raddr)) < 0)) { 161 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 162 rpc_createerr.cf_error.re_errno = errno; 163 if (*sockp != -1) 164 (void)close(*sockp); 165 goto fooy; 166 } 167 ct->ct_closeit = TRUE; 168 } else { 169 ct->ct_closeit = FALSE; 170 } 171 172 /* 173 * Set up private data struct 174 */ 175 ct->ct_sock = *sockp; 176 ct->ct_wait.tv_usec = 0; 177 ct->ct_waitset = FALSE; 178 ct->ct_addr = *raddr; 179 180 /* 181 * Initialize call message 182 */ 183 (void)gettimeofday(&now, (struct timezone *)0); 184 call_msg.rm_xid = arc4random(); 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; 189 190 /* 191 * pre-serialize the staic part of the call msg and stash it away 192 */ 193 xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, 194 XDR_ENCODE); 195 if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { 196 if (ct->ct_closeit) { 197 (void)close(*sockp); 198 } 199 goto fooy; 200 } 201 ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); 202 XDR_DESTROY(&(ct->ct_xdrs)); 203 204 /* 205 * Create a client handle which uses xdrrec for serialization 206 * and authnone for authentication. 207 */ 208 xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, 209 (caddr_t)ct, readtcp, writetcp); 210 h->cl_ops = &tcp_ops; 211 h->cl_private = (caddr_t) ct; 212 h->cl_auth = authnone_create(); 213 return (h); 214 215 fooy: 216 /* 217 * Something goofed, free stuff and barf 218 */ 219 if (ct) 220 mem_free((caddr_t)ct, sizeof(struct ct_data)); 221 if (h) 222 mem_free((caddr_t)h, sizeof(CLIENT)); 223 return ((CLIENT *)NULL); 224 } 225 226 static enum clnt_stat 227 clnttcp_call(h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout) 228 register CLIENT *h; 229 u_long proc; 230 xdrproc_t xdr_args; 231 caddr_t args_ptr; 232 xdrproc_t xdr_results; 233 caddr_t results_ptr; 234 struct timeval timeout; 235 { 236 register struct ct_data *ct = (struct ct_data *) h->cl_private; 237 register XDR *xdrs = &(ct->ct_xdrs); 238 struct rpc_msg reply_msg; 239 u_long x_id; 240 u_int32_t *msg_x_id = (u_int32_t *)(ct->ct_mcall); /* yuk */ 241 register bool_t shipnow; 242 int refreshes = 2; 243 244 if (!ct->ct_waitset) { 245 ct->ct_wait = timeout; 246 } 247 248 shipnow = 249 (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0 250 && timeout.tv_usec == 0) ? FALSE : TRUE; 251 252 call_again: 253 xdrs->x_op = XDR_ENCODE; 254 ct->ct_error.re_status = RPC_SUCCESS; 255 x_id = ntohl(--(*msg_x_id)); 256 if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) || 257 (! XDR_PUTLONG(xdrs, (long *)&proc)) || 258 (! AUTH_MARSHALL(h->cl_auth, xdrs)) || 259 (! (*xdr_args)(xdrs, args_ptr))) { 260 if (ct->ct_error.re_status == RPC_SUCCESS) 261 ct->ct_error.re_status = RPC_CANTENCODEARGS; 262 (void)xdrrec_endofrecord(xdrs, TRUE); 263 return (ct->ct_error.re_status); 264 } 265 if (! xdrrec_endofrecord(xdrs, shipnow)) 266 return (ct->ct_error.re_status = RPC_CANTSEND); 267 if (! shipnow) 268 return (RPC_SUCCESS); 269 /* 270 * Hack to provide rpc-based message passing 271 */ 272 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 273 return(ct->ct_error.re_status = RPC_TIMEDOUT); 274 } 275 276 277 /* 278 * Keep receiving until we get a valid transaction id 279 */ 280 xdrs->x_op = XDR_DECODE; 281 while (TRUE) { 282 reply_msg.acpted_rply.ar_verf = _null_auth; 283 reply_msg.acpted_rply.ar_results.where = NULL; 284 reply_msg.acpted_rply.ar_results.proc = xdr_void; 285 if (! xdrrec_skiprecord(xdrs)) 286 return (ct->ct_error.re_status); 287 /* now decode and validate the response header */ 288 if (! xdr_replymsg(xdrs, &reply_msg)) { 289 if (ct->ct_error.re_status == RPC_SUCCESS) 290 continue; 291 return (ct->ct_error.re_status); 292 } 293 if (reply_msg.rm_xid == x_id) 294 break; 295 } 296 297 /* 298 * process header 299 */ 300 _seterr_reply(&reply_msg, &(ct->ct_error)); 301 if (ct->ct_error.re_status == RPC_SUCCESS) { 302 if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) { 303 ct->ct_error.re_status = RPC_AUTHERROR; 304 ct->ct_error.re_why = AUTH_INVALIDRESP; 305 } else if (! (*xdr_results)(xdrs, results_ptr)) { 306 if (ct->ct_error.re_status == RPC_SUCCESS) 307 ct->ct_error.re_status = RPC_CANTDECODERES; 308 } 309 /* free verifier ... */ 310 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 311 xdrs->x_op = XDR_FREE; 312 (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); 313 } 314 } /* end successful completion */ 315 else { 316 /* maybe our credentials need to be refreshed ... */ 317 if (refreshes-- && AUTH_REFRESH(h->cl_auth)) 318 goto call_again; 319 } /* end of unsuccessful completion */ 320 return (ct->ct_error.re_status); 321 } 322 323 static void 324 clnttcp_geterr(h, errp) 325 CLIENT *h; 326 struct rpc_err *errp; 327 { 328 register struct ct_data *ct = 329 (struct ct_data *) h->cl_private; 330 331 *errp = ct->ct_error; 332 } 333 334 static bool_t 335 clnttcp_freeres(cl, xdr_res, res_ptr) 336 CLIENT *cl; 337 xdrproc_t xdr_res; 338 caddr_t res_ptr; 339 { 340 register struct ct_data *ct = (struct ct_data *)cl->cl_private; 341 register XDR *xdrs = &(ct->ct_xdrs); 342 343 xdrs->x_op = XDR_FREE; 344 return ((*xdr_res)(xdrs, res_ptr)); 345 } 346 347 static void 348 clnttcp_abort() 349 { 350 } 351 352 static bool_t 353 clnttcp_control(cl, request, info) 354 CLIENT *cl; 355 int request; 356 char *info; 357 { 358 register struct ct_data *ct = (struct ct_data *)cl->cl_private; 359 360 switch (request) { 361 case CLSET_TIMEOUT: 362 ct->ct_wait = *(struct timeval *)info; 363 ct->ct_waitset = TRUE; 364 break; 365 case CLGET_TIMEOUT: 366 *(struct timeval *)info = ct->ct_wait; 367 break; 368 case CLGET_SERVER_ADDR: 369 *(struct sockaddr_in *)info = ct->ct_addr; 370 break; 371 default: 372 return (FALSE); 373 } 374 return (TRUE); 375 } 376 377 378 static void 379 clnttcp_destroy(h) 380 CLIENT *h; 381 { 382 register struct ct_data *ct = 383 (struct ct_data *) h->cl_private; 384 385 if (ct->ct_closeit) { 386 (void)close(ct->ct_sock); 387 } 388 XDR_DESTROY(&(ct->ct_xdrs)); 389 mem_free((caddr_t)ct, sizeof(struct ct_data)); 390 mem_free((caddr_t)h, sizeof(CLIENT)); 391 } 392 393 /* 394 * Interface between xdr serializer and tcp connection. 395 * Behaves like the system calls, read & write, but keeps some error state 396 * around for the rpc level. 397 */ 398 static int 399 readtcp(ct, buf, len) 400 register struct ct_data *ct; 401 caddr_t buf; 402 register int len; 403 { 404 fd_set *fds, readfds; 405 struct timeval start, after, duration, delta, tmp; 406 int r, save_errno; 407 408 if (len == 0) 409 return (0); 410 411 if (ct->ct_sock+1 > FD_SETSIZE) { 412 int bytes = howmany(ct->ct_sock+1, NFDBITS) * sizeof(fd_mask); 413 fds = (fd_set *)malloc(bytes); 414 if (fds == NULL) 415 return (-1); 416 memset(fds, 0, bytes); 417 } else { 418 fds = &readfds; 419 FD_ZERO(fds); 420 } 421 422 gettimeofday(&start, NULL); 423 delta = ct->ct_wait; 424 while (TRUE) { 425 /* XXX we know the other bits are still clear */ 426 FD_SET(ct->ct_sock, fds); 427 r = select(ct->ct_sock+1, fds, NULL, NULL, &delta); 428 save_errno = errno; 429 430 gettimeofday(&after, NULL); 431 timersub(&start, &after, &duration); 432 timersub(&ct->ct_wait, &duration, &tmp); 433 delta = tmp; 434 if (delta.tv_sec < 0 || !timerisset(&delta)) 435 r = 0; 436 437 switch (r) { 438 case 0: 439 ct->ct_error.re_status = RPC_TIMEDOUT; 440 if (fds != &readfds) 441 free(fds); 442 return (-1); 443 case -1: 444 if (errno == EINTR) 445 continue; 446 ct->ct_error.re_status = RPC_CANTRECV; 447 ct->ct_error.re_errno = save_errno; 448 if (fds != &readfds) 449 free(fds); 450 return (-1); 451 } 452 break; 453 } 454 if (fds != &readfds) 455 free(fds); 456 457 switch (len = read(ct->ct_sock, buf, len)) { 458 case 0: 459 /* premature eof */ 460 ct->ct_error.re_errno = ECONNRESET; 461 ct->ct_error.re_status = RPC_CANTRECV; 462 len = -1; /* it's really an error */ 463 break; 464 case -1: 465 ct->ct_error.re_errno = errno; 466 ct->ct_error.re_status = RPC_CANTRECV; 467 break; 468 } 469 return (len); 470 } 471 472 static int 473 writetcp(ct, buf, len) 474 struct ct_data *ct; 475 caddr_t buf; 476 int len; 477 { 478 register int i, cnt; 479 480 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 481 if ((i = write(ct->ct_sock, buf, cnt)) == -1) { 482 ct->ct_error.re_errno = errno; 483 ct->ct_error.re_status = RPC_CANTSEND; 484 return (-1); 485 } 486 } 487 return (len); 488 } 489