1 /* $OpenBSD: clnt_tcp.c,v 1.23 2006/03/31 18:28:55 deraadt Exp $ */ 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 31 /* 32 * clnt_tcp.c, Implements a TCP/IP based, client side RPC. 33 * 34 * Copyright (C) 1984, Sun Microsystems, Inc. 35 * 36 * TCP based RPC supports 'batched calls'. 37 * A sequence of calls may be batched-up in a send buffer. The rpc call 38 * return immediately to the client even though the call was not necessarily 39 * sent. The batching occurs if the results' xdr routine is NULL (0) AND 40 * the rpc timeout value is zero (see clnt.h, rpc). 41 * 42 * Clients should NOT casually batch calls that in fact return results; that is, 43 * the server side should be aware that a call is batched and not produce any 44 * return message. Batched calls that produce many result messages can 45 * deadlock (netlock) the client and the server.... 46 * 47 * Now go hang yourself. 48 */ 49 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <unistd.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 static enum clnt_stat clnttcp_call(CLIENT *, u_long, xdrproc_t, caddr_t, 63 xdrproc_t, caddr_t, struct timeval); 64 static void clnttcp_abort(CLIENT *); 65 static void clnttcp_geterr(CLIENT *, struct rpc_err *); 66 static bool_t clnttcp_freeres(CLIENT *, xdrproc_t, caddr_t); 67 static bool_t clnttcp_control(CLIENT *, u_int, void *); 68 static void clnttcp_destroy(CLIENT *); 69 70 static struct clnt_ops tcp_ops = { 71 clnttcp_call, 72 clnttcp_abort, 73 clnttcp_geterr, 74 clnttcp_freeres, 75 clnttcp_destroy, 76 clnttcp_control 77 }; 78 79 struct ct_data { 80 int ct_sock; 81 bool_t ct_closeit; 82 struct timeval ct_wait; 83 bool_t ct_waitset; /* wait set by clnt_control? */ 84 struct sockaddr_in ct_addr; 85 struct rpc_err ct_error; 86 char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */ 87 u_int ct_mpos; /* pos after marshal */ 88 XDR ct_xdrs; 89 }; 90 91 static int readtcp(struct ct_data *, caddr_t, int); 92 static int writetcp(struct ct_data *, caddr_t, int); 93 94 /* 95 * Create a client handle for a tcp/ip connection. 96 * If *sockp<0, *sockp is set to a newly created TCP socket and it is 97 * connected to raddr. If *sockp non-negative then 98 * raddr is ignored. The rpc/tcp package does buffering 99 * similar to stdio, so the client must pick send and receive buffer sizes,]; 100 * 0 => use the default. 101 * If raddr->sin_port is 0, then a binder on the remote machine is 102 * consulted for the right port number. 103 * NB: *sockp is copied into a private area. 104 * NB: It is the clients responsibility to close *sockp. 105 * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this 106 * something more useful. 107 */ 108 CLIENT * 109 clnttcp_create(struct sockaddr_in *raddr, u_long prog, u_long vers, int *sockp, 110 u_int sendsz, u_int recvsz) 111 { 112 CLIENT *h; 113 struct ct_data *ct = NULL; 114 struct timeval now; 115 struct rpc_msg call_msg; 116 117 h = (CLIENT *)mem_alloc(sizeof(*h)); 118 if (h == NULL) { 119 (void)fprintf(stderr, "clnttcp_create: out of memory\n"); 120 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 121 rpc_createerr.cf_error.re_errno = errno; 122 goto fooy; 123 } 124 ct = (struct ct_data *)mem_alloc(sizeof(*ct)); 125 if (ct == 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 132 /* 133 * If no port number given ask the pmap for one 134 */ 135 if (raddr->sin_port == 0) { 136 u_short port; 137 if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) { 138 mem_free((caddr_t)ct, sizeof(struct ct_data)); 139 mem_free((caddr_t)h, sizeof(CLIENT)); 140 return (NULL); 141 } 142 raddr->sin_port = htons(port); 143 } 144 145 /* 146 * If no socket given, open one 147 */ 148 if (*sockp < 0) { 149 *sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 150 (void)bindresvport(*sockp, NULL); 151 if ((*sockp < 0) 152 || (connect(*sockp, (struct sockaddr *)raddr, 153 sizeof(*raddr)) < 0)) { 154 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 155 rpc_createerr.cf_error.re_errno = errno; 156 if (*sockp != -1) 157 (void)close(*sockp); 158 goto fooy; 159 } 160 ct->ct_closeit = TRUE; 161 } else { 162 ct->ct_closeit = FALSE; 163 } 164 165 /* 166 * Set up private data struct 167 */ 168 ct->ct_sock = *sockp; 169 ct->ct_wait.tv_usec = 0; 170 ct->ct_waitset = FALSE; 171 ct->ct_addr = *raddr; 172 173 /* 174 * Initialize call message 175 */ 176 (void)gettimeofday(&now, NULL); 177 call_msg.rm_xid = arc4random(); 178 call_msg.rm_direction = CALL; 179 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 180 call_msg.rm_call.cb_prog = prog; 181 call_msg.rm_call.cb_vers = vers; 182 183 /* 184 * pre-serialize the staic part of the call msg and stash it away 185 */ 186 xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, 187 XDR_ENCODE); 188 if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { 189 if (ct->ct_closeit) { 190 (void)close(*sockp); 191 } 192 goto fooy; 193 } 194 ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); 195 XDR_DESTROY(&(ct->ct_xdrs)); 196 197 /* 198 * Create a client handle which uses xdrrec for serialization 199 * and authnone for authentication. 200 */ 201 xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, 202 (caddr_t)ct, (int(*)(caddr_t, caddr_t, int))readtcp, 203 (int(*)(caddr_t, caddr_t, int))writetcp); 204 h->cl_ops = &tcp_ops; 205 h->cl_private = (caddr_t) ct; 206 h->cl_auth = authnone_create(); 207 return (h); 208 209 fooy: 210 /* 211 * Something goofed, free stuff and barf 212 */ 213 if (ct) 214 mem_free((caddr_t)ct, sizeof(struct ct_data)); 215 if (h) 216 mem_free((caddr_t)h, sizeof(CLIENT)); 217 return (NULL); 218 } 219 220 static enum clnt_stat 221 clnttcp_call(CLIENT *h, u_long proc, xdrproc_t xdr_args, caddr_t args_ptr, 222 xdrproc_t xdr_results, caddr_t results_ptr, struct timeval timeout) 223 { 224 struct ct_data *ct = (struct ct_data *) h->cl_private; 225 XDR *xdrs = &(ct->ct_xdrs); 226 struct rpc_msg reply_msg; 227 u_long x_id; 228 u_int32_t *msg_x_id = (u_int32_t *)(ct->ct_mcall); /* yuk */ 229 bool_t shipnow; 230 int refreshes = 2; 231 232 if (!ct->ct_waitset) { 233 ct->ct_wait = timeout; 234 } 235 236 shipnow = 237 (xdr_results == NULL && timeout.tv_sec == 0 238 && timeout.tv_usec == 0) ? FALSE : TRUE; 239 240 call_again: 241 xdrs->x_op = XDR_ENCODE; 242 ct->ct_error.re_status = RPC_SUCCESS; 243 x_id = ntohl(--(*msg_x_id)); 244 if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) || 245 (! XDR_PUTLONG(xdrs, (long *)&proc)) || 246 (! AUTH_MARSHALL(h->cl_auth, xdrs)) || 247 (! (*xdr_args)(xdrs, args_ptr))) { 248 if (ct->ct_error.re_status == RPC_SUCCESS) 249 ct->ct_error.re_status = RPC_CANTENCODEARGS; 250 (void)xdrrec_endofrecord(xdrs, TRUE); 251 return (ct->ct_error.re_status); 252 } 253 if (! xdrrec_endofrecord(xdrs, shipnow)) 254 return (ct->ct_error.re_status = RPC_CANTSEND); 255 if (! shipnow) 256 return (RPC_SUCCESS); 257 /* 258 * Hack to provide rpc-based message passing 259 */ 260 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 261 return(ct->ct_error.re_status = RPC_TIMEDOUT); 262 } 263 264 265 /* 266 * Keep receiving until we get a valid transaction id 267 */ 268 xdrs->x_op = XDR_DECODE; 269 while (TRUE) { 270 reply_msg.acpted_rply.ar_verf = _null_auth; 271 reply_msg.acpted_rply.ar_results.where = NULL; 272 reply_msg.acpted_rply.ar_results.proc = xdr_void; 273 if (! xdrrec_skiprecord(xdrs)) 274 return (ct->ct_error.re_status); 275 /* now decode and validate the response header */ 276 if (! xdr_replymsg(xdrs, &reply_msg)) { 277 if (ct->ct_error.re_status == RPC_SUCCESS) 278 continue; 279 return (ct->ct_error.re_status); 280 } 281 if (reply_msg.rm_xid == x_id) 282 break; 283 } 284 285 /* 286 * process header 287 */ 288 _seterr_reply(&reply_msg, &(ct->ct_error)); 289 if (ct->ct_error.re_status == RPC_SUCCESS) { 290 if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) { 291 ct->ct_error.re_status = RPC_AUTHERROR; 292 ct->ct_error.re_why = AUTH_INVALIDRESP; 293 } else if (! (*xdr_results)(xdrs, results_ptr)) { 294 if (ct->ct_error.re_status == RPC_SUCCESS) 295 ct->ct_error.re_status = RPC_CANTDECODERES; 296 } 297 /* free verifier ... */ 298 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 299 xdrs->x_op = XDR_FREE; 300 (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); 301 } 302 } /* end successful completion */ 303 else { 304 /* maybe our credentials need to be refreshed ... */ 305 if (refreshes-- && AUTH_REFRESH(h->cl_auth)) 306 goto call_again; 307 } /* end of unsuccessful completion */ 308 return (ct->ct_error.re_status); 309 } 310 311 static void 312 clnttcp_geterr(CLIENT *h, struct rpc_err *errp) 313 { 314 struct ct_data *ct = 315 (struct ct_data *) h->cl_private; 316 317 *errp = ct->ct_error; 318 } 319 320 static bool_t 321 clnttcp_freeres(CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr) 322 { 323 struct ct_data *ct = (struct ct_data *)cl->cl_private; 324 XDR *xdrs = &(ct->ct_xdrs); 325 326 xdrs->x_op = XDR_FREE; 327 return ((*xdr_res)(xdrs, res_ptr)); 328 } 329 330 /*ARGSUSED*/ 331 static void 332 clnttcp_abort(CLIENT *clnt) 333 { 334 } 335 336 static bool_t 337 clnttcp_control(CLIENT *cl, u_int request, void *info) 338 { 339 struct ct_data *ct = (struct ct_data *)cl->cl_private; 340 341 switch (request) { 342 case CLSET_TIMEOUT: 343 ct->ct_wait = *(struct timeval *)info; 344 ct->ct_waitset = TRUE; 345 break; 346 case CLGET_TIMEOUT: 347 *(struct timeval *)info = ct->ct_wait; 348 break; 349 case CLGET_SERVER_ADDR: 350 *(struct sockaddr_in *)info = ct->ct_addr; 351 break; 352 default: 353 return (FALSE); 354 } 355 return (TRUE); 356 } 357 358 359 static void 360 clnttcp_destroy(CLIENT *h) 361 { 362 struct ct_data *ct = 363 (struct ct_data *) h->cl_private; 364 365 if (ct->ct_closeit) { 366 (void)close(ct->ct_sock); 367 } 368 XDR_DESTROY(&(ct->ct_xdrs)); 369 mem_free((caddr_t)ct, sizeof(struct ct_data)); 370 mem_free((caddr_t)h, sizeof(CLIENT)); 371 } 372 373 /* 374 * Interface between xdr serializer and tcp connection. 375 * Behaves like the system calls, read & write, but keeps some error state 376 * around for the rpc level. 377 */ 378 static int 379 readtcp(struct ct_data *ct, caddr_t buf, int len) 380 { 381 struct pollfd pfd[1]; 382 struct timeval start, after, duration, tmp; 383 int delta, r, save_errno; 384 385 if (len == 0) 386 return (0); 387 388 pfd[0].fd = ct->ct_sock; 389 pfd[0].events = POLLIN; 390 delta = ct->ct_wait.tv_sec * 1000 + ct->ct_wait.tv_usec / 1000; 391 gettimeofday(&start, NULL); 392 for (;;) { 393 r = poll(pfd, 1, delta); 394 save_errno = errno; 395 396 gettimeofday(&after, NULL); 397 timersub(&start, &after, &duration); 398 timersub(&ct->ct_wait, &duration, &tmp); 399 delta = tmp.tv_sec * 1000 + tmp.tv_usec / 1000; 400 if (delta <= 0) 401 r = 0; 402 403 switch (r) { 404 case 0: 405 ct->ct_error.re_status = RPC_TIMEDOUT; 406 return (-1); 407 case 1: 408 if (pfd[0].revents & POLLNVAL) 409 errno = EBADF; 410 else if (pfd[0].revents & POLLERR) 411 errno = EIO; 412 else 413 break; 414 /* FALLTHROUGH */ 415 case -1: 416 if (errno == EINTR) 417 continue; 418 ct->ct_error.re_status = RPC_CANTRECV; 419 ct->ct_error.re_errno = save_errno; 420 return (-1); 421 } 422 break; 423 } 424 425 switch (len = read(ct->ct_sock, buf, len)) { 426 case 0: 427 /* premature eof */ 428 ct->ct_error.re_errno = ECONNRESET; 429 ct->ct_error.re_status = RPC_CANTRECV; 430 len = -1; /* it's really an error */ 431 break; 432 case -1: 433 ct->ct_error.re_errno = errno; 434 ct->ct_error.re_status = RPC_CANTRECV; 435 break; 436 } 437 return (len); 438 } 439 440 static int 441 writetcp(struct ct_data *ct, caddr_t buf, int len) 442 { 443 int i, cnt; 444 445 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 446 if ((i = write(ct->ct_sock, buf, cnt)) == -1) { 447 ct->ct_error.re_errno = errno; 448 ct->ct_error.re_status = RPC_CANTSEND; 449 return (-1); 450 } 451 } 452 return (len); 453 } 454