1 /* $OpenBSD: clnt_tcp.c,v 1.24 2009/06/02 14:18:19 schwarze 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 static 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 if (h->cl_auth == NULL) { 208 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 209 rpc_createerr.cf_error.re_errno = errno; 210 goto fooy; 211 } 212 return (h); 213 214 fooy: 215 /* 216 * Something goofed, free stuff and barf 217 */ 218 if (ct) 219 mem_free((caddr_t)ct, sizeof(struct ct_data)); 220 if (h) 221 mem_free((caddr_t)h, sizeof(CLIENT)); 222 return (NULL); 223 } 224 225 static enum clnt_stat 226 clnttcp_call(CLIENT *h, u_long proc, xdrproc_t xdr_args, caddr_t args_ptr, 227 xdrproc_t xdr_results, caddr_t results_ptr, struct timeval timeout) 228 { 229 struct ct_data *ct = (struct ct_data *) h->cl_private; 230 XDR *xdrs = &(ct->ct_xdrs); 231 struct rpc_msg reply_msg; 232 u_long x_id; 233 u_int32_t *msg_x_id = (u_int32_t *)(ct->ct_mcall); /* yuk */ 234 bool_t shipnow; 235 int refreshes = 2; 236 237 if (!ct->ct_waitset) { 238 ct->ct_wait = timeout; 239 } 240 241 shipnow = 242 (xdr_results == NULL && timeout.tv_sec == 0 243 && timeout.tv_usec == 0) ? FALSE : TRUE; 244 245 call_again: 246 xdrs->x_op = XDR_ENCODE; 247 ct->ct_error.re_status = RPC_SUCCESS; 248 x_id = ntohl(--(*msg_x_id)); 249 if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) || 250 (! XDR_PUTLONG(xdrs, (long *)&proc)) || 251 (! AUTH_MARSHALL(h->cl_auth, xdrs)) || 252 (! (*xdr_args)(xdrs, args_ptr))) { 253 if (ct->ct_error.re_status == RPC_SUCCESS) 254 ct->ct_error.re_status = RPC_CANTENCODEARGS; 255 (void)xdrrec_endofrecord(xdrs, TRUE); 256 return (ct->ct_error.re_status); 257 } 258 if (! xdrrec_endofrecord(xdrs, shipnow)) 259 return (ct->ct_error.re_status = RPC_CANTSEND); 260 if (! shipnow) 261 return (RPC_SUCCESS); 262 /* 263 * Hack to provide rpc-based message passing 264 */ 265 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 266 return(ct->ct_error.re_status = RPC_TIMEDOUT); 267 } 268 269 270 /* 271 * Keep receiving until we get a valid transaction id 272 */ 273 xdrs->x_op = XDR_DECODE; 274 while (TRUE) { 275 reply_msg.acpted_rply.ar_verf = _null_auth; 276 reply_msg.acpted_rply.ar_results.where = NULL; 277 reply_msg.acpted_rply.ar_results.proc = xdr_void; 278 if (! xdrrec_skiprecord(xdrs)) 279 return (ct->ct_error.re_status); 280 /* now decode and validate the response header */ 281 if (! xdr_replymsg(xdrs, &reply_msg)) { 282 if (ct->ct_error.re_status == RPC_SUCCESS) 283 continue; 284 return (ct->ct_error.re_status); 285 } 286 if (reply_msg.rm_xid == x_id) 287 break; 288 } 289 290 /* 291 * process header 292 */ 293 _seterr_reply(&reply_msg, &(ct->ct_error)); 294 if (ct->ct_error.re_status == RPC_SUCCESS) { 295 if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) { 296 ct->ct_error.re_status = RPC_AUTHERROR; 297 ct->ct_error.re_why = AUTH_INVALIDRESP; 298 } else if (! (*xdr_results)(xdrs, results_ptr)) { 299 if (ct->ct_error.re_status == RPC_SUCCESS) 300 ct->ct_error.re_status = RPC_CANTDECODERES; 301 } 302 /* free verifier ... */ 303 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 304 xdrs->x_op = XDR_FREE; 305 (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); 306 } 307 } /* end successful completion */ 308 else { 309 /* maybe our credentials need to be refreshed ... */ 310 if (refreshes-- && AUTH_REFRESH(h->cl_auth)) 311 goto call_again; 312 } /* end of unsuccessful completion */ 313 return (ct->ct_error.re_status); 314 } 315 316 static void 317 clnttcp_geterr(CLIENT *h, struct rpc_err *errp) 318 { 319 struct ct_data *ct = 320 (struct ct_data *) h->cl_private; 321 322 *errp = ct->ct_error; 323 } 324 325 static bool_t 326 clnttcp_freeres(CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr) 327 { 328 struct ct_data *ct = (struct ct_data *)cl->cl_private; 329 XDR *xdrs = &(ct->ct_xdrs); 330 331 xdrs->x_op = XDR_FREE; 332 return ((*xdr_res)(xdrs, res_ptr)); 333 } 334 335 /*ARGSUSED*/ 336 static void 337 clnttcp_abort(CLIENT *clnt) 338 { 339 } 340 341 static bool_t 342 clnttcp_control(CLIENT *cl, u_int request, void *info) 343 { 344 struct ct_data *ct = (struct ct_data *)cl->cl_private; 345 346 switch (request) { 347 case CLSET_TIMEOUT: 348 ct->ct_wait = *(struct timeval *)info; 349 ct->ct_waitset = TRUE; 350 break; 351 case CLGET_TIMEOUT: 352 *(struct timeval *)info = ct->ct_wait; 353 break; 354 case CLGET_SERVER_ADDR: 355 *(struct sockaddr_in *)info = ct->ct_addr; 356 break; 357 default: 358 return (FALSE); 359 } 360 return (TRUE); 361 } 362 363 364 static void 365 clnttcp_destroy(CLIENT *h) 366 { 367 struct ct_data *ct = 368 (struct ct_data *) h->cl_private; 369 370 if (ct->ct_closeit) { 371 (void)close(ct->ct_sock); 372 } 373 XDR_DESTROY(&(ct->ct_xdrs)); 374 mem_free((caddr_t)ct, sizeof(struct ct_data)); 375 mem_free((caddr_t)h, sizeof(CLIENT)); 376 } 377 378 /* 379 * Interface between xdr serializer and tcp connection. 380 * Behaves like the system calls, read & write, but keeps some error state 381 * around for the rpc level. 382 */ 383 static int 384 readtcp(struct ct_data *ct, caddr_t buf, int len) 385 { 386 struct pollfd pfd[1]; 387 struct timeval start, after, duration, tmp; 388 int delta, r, save_errno; 389 390 if (len == 0) 391 return (0); 392 393 pfd[0].fd = ct->ct_sock; 394 pfd[0].events = POLLIN; 395 delta = ct->ct_wait.tv_sec * 1000 + ct->ct_wait.tv_usec / 1000; 396 gettimeofday(&start, NULL); 397 for (;;) { 398 r = poll(pfd, 1, delta); 399 save_errno = errno; 400 401 gettimeofday(&after, NULL); 402 timersub(&start, &after, &duration); 403 timersub(&ct->ct_wait, &duration, &tmp); 404 delta = tmp.tv_sec * 1000 + tmp.tv_usec / 1000; 405 if (delta <= 0) 406 r = 0; 407 408 switch (r) { 409 case 0: 410 ct->ct_error.re_status = RPC_TIMEDOUT; 411 return (-1); 412 case 1: 413 if (pfd[0].revents & POLLNVAL) 414 errno = EBADF; 415 else if (pfd[0].revents & POLLERR) 416 errno = EIO; 417 else 418 break; 419 /* FALLTHROUGH */ 420 case -1: 421 if (errno == EINTR) 422 continue; 423 ct->ct_error.re_status = RPC_CANTRECV; 424 ct->ct_error.re_errno = save_errno; 425 return (-1); 426 } 427 break; 428 } 429 430 switch (len = read(ct->ct_sock, buf, len)) { 431 case 0: 432 /* premature eof */ 433 ct->ct_error.re_errno = ECONNRESET; 434 ct->ct_error.re_status = RPC_CANTRECV; 435 len = -1; /* it's really an error */ 436 break; 437 case -1: 438 ct->ct_error.re_errno = errno; 439 ct->ct_error.re_status = RPC_CANTRECV; 440 break; 441 } 442 return (len); 443 } 444 445 static int 446 writetcp(struct ct_data *ct, caddr_t buf, int len) 447 { 448 int i, cnt; 449 450 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 451 if ((i = write(ct->ct_sock, buf, cnt)) == -1) { 452 ct->ct_error.re_errno = errno; 453 ct->ct_error.re_status = RPC_CANTSEND; 454 return (-1); 455 } 456 } 457 return (len); 458 } 459