1 /* $OpenBSD: clnt_tcp.c,v 1.26 2014/11/11 04:51:49 guenther Exp $ */ 2 3 /* 4 * Copyright (c) 2010, Oracle America, Inc. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above 13 * copyright notice, this list of conditions and the following 14 * disclaimer in the documentation and/or other materials 15 * provided with the distribution. 16 * * Neither the name of the "Oracle America, Inc." nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 27 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * clnt_tcp.c, Implements a TCP/IP based, client side RPC. 36 * 37 * TCP based RPC supports 'batched calls'. 38 * A sequence of calls may be batched-up in a send buffer. The rpc call 39 * return immediately to the client even though the call was not necessarily 40 * sent. The batching occurs if the results' xdr routine is NULL (0) AND 41 * the rpc timeout value is zero (see clnt.h, rpc). 42 * 43 * Clients should NOT casually batch calls that in fact return results; that is, 44 * the server side should be aware that a call is batched and not produce any 45 * return message. Batched calls that produce many result messages can 46 * deadlock (netlock) the client and the server.... 47 * 48 * Now go hang yourself. 49 */ 50 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <unistd.h> 55 #include <rpc/rpc.h> 56 #include <sys/socket.h> 57 #include <netdb.h> 58 #include <errno.h> 59 #include <rpc/pmap_clnt.h> 60 61 #define MCALL_MSG_SIZE 24 62 63 static enum clnt_stat clnttcp_call(CLIENT *, u_long, xdrproc_t, caddr_t, 64 xdrproc_t, caddr_t, struct timeval); 65 static void clnttcp_abort(CLIENT *); 66 static void clnttcp_geterr(CLIENT *, struct rpc_err *); 67 static bool_t clnttcp_freeres(CLIENT *, xdrproc_t, caddr_t); 68 static bool_t clnttcp_control(CLIENT *, u_int, void *); 69 static void clnttcp_destroy(CLIENT *); 70 71 static struct clnt_ops tcp_ops = { 72 clnttcp_call, 73 clnttcp_abort, 74 clnttcp_geterr, 75 clnttcp_freeres, 76 clnttcp_destroy, 77 clnttcp_control 78 }; 79 80 struct ct_data { 81 int ct_sock; 82 bool_t ct_closeit; 83 struct timeval ct_wait; 84 bool_t ct_waitset; /* wait set by clnt_control? */ 85 struct sockaddr_in ct_addr; 86 struct rpc_err ct_error; 87 char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */ 88 u_int ct_mpos; /* pos after marshal */ 89 XDR ct_xdrs; 90 }; 91 92 static int readtcp(struct ct_data *, caddr_t, int); 93 static int writetcp(struct ct_data *, caddr_t, int); 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 client's responsibility to close *sockp, unless 106 * clnttcp_create() was called with *sockp = -1 (so it created 107 * the socket), and CLNT_DESTROY() is used. 108 * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this 109 * something more useful. 110 */ 111 CLIENT * 112 clnttcp_create(struct sockaddr_in *raddr, u_long prog, u_long vers, int *sockp, 113 u_int sendsz, u_int recvsz) 114 { 115 CLIENT *h; 116 struct ct_data *ct = NULL; 117 struct timeval now; 118 struct rpc_msg call_msg; 119 120 h = (CLIENT *)mem_alloc(sizeof(*h)); 121 if (h == NULL) { 122 (void)fprintf(stderr, "clnttcp_create: out of memory\n"); 123 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 124 rpc_createerr.cf_error.re_errno = errno; 125 goto fooy; 126 } 127 ct = (struct ct_data *)mem_alloc(sizeof(*ct)); 128 if (ct == 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 135 /* 136 * If no port number given ask the pmap for one 137 */ 138 if (raddr->sin_port == 0) { 139 u_short port; 140 if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) { 141 mem_free((caddr_t)ct, sizeof(struct ct_data)); 142 mem_free((caddr_t)h, sizeof(CLIENT)); 143 return (NULL); 144 } 145 raddr->sin_port = htons(port); 146 } 147 148 /* 149 * If no socket given, open one 150 */ 151 if (*sockp < 0) { 152 *sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 153 (void)bindresvport(*sockp, NULL); 154 if ((*sockp < 0) 155 || (connect(*sockp, (struct sockaddr *)raddr, 156 sizeof(*raddr)) < 0)) { 157 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 158 rpc_createerr.cf_error.re_errno = errno; 159 if (*sockp != -1) 160 (void)close(*sockp); 161 goto fooy; 162 } 163 ct->ct_closeit = TRUE; 164 } else { 165 ct->ct_closeit = FALSE; 166 } 167 168 /* 169 * Set up private data struct 170 */ 171 ct->ct_sock = *sockp; 172 ct->ct_wait.tv_usec = 0; 173 ct->ct_waitset = FALSE; 174 ct->ct_addr = *raddr; 175 176 /* 177 * Initialize call message 178 */ 179 (void)gettimeofday(&now, NULL); 180 call_msg.rm_xid = arc4random(); 181 call_msg.rm_direction = CALL; 182 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 183 call_msg.rm_call.cb_prog = prog; 184 call_msg.rm_call.cb_vers = vers; 185 186 /* 187 * pre-serialize the static part of the call msg and stash it away 188 */ 189 xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, 190 XDR_ENCODE); 191 if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { 192 if (ct->ct_closeit) { 193 (void)close(*sockp); 194 } 195 goto fooy; 196 } 197 ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); 198 XDR_DESTROY(&(ct->ct_xdrs)); 199 200 /* 201 * Create a client handle which uses xdrrec for serialization 202 * and authnone for authentication. 203 */ 204 xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, 205 (caddr_t)ct, (int(*)(caddr_t, caddr_t, int))readtcp, 206 (int(*)(caddr_t, caddr_t, int))writetcp); 207 h->cl_ops = &tcp_ops; 208 h->cl_private = (caddr_t) ct; 209 h->cl_auth = authnone_create(); 210 if (h->cl_auth == NULL) { 211 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 212 rpc_createerr.cf_error.re_errno = errno; 213 goto fooy; 214 } 215 return (h); 216 217 fooy: 218 /* 219 * Something goofed, free stuff and barf 220 */ 221 if (ct) 222 mem_free((caddr_t)ct, sizeof(struct ct_data)); 223 if (h) 224 mem_free((caddr_t)h, sizeof(CLIENT)); 225 return (NULL); 226 } 227 228 static enum clnt_stat 229 clnttcp_call(CLIENT *h, u_long proc, xdrproc_t xdr_args, caddr_t args_ptr, 230 xdrproc_t xdr_results, caddr_t results_ptr, struct timeval timeout) 231 { 232 struct ct_data *ct = (struct ct_data *) h->cl_private; 233 XDR *xdrs = &(ct->ct_xdrs); 234 struct rpc_msg reply_msg; 235 u_long x_id; 236 u_int32_t *msg_x_id = (u_int32_t *)(ct->ct_mcall); /* yuk */ 237 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 == NULL && 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(CLIENT *h, struct rpc_err *errp) 321 { 322 struct ct_data *ct = 323 (struct ct_data *) h->cl_private; 324 325 *errp = ct->ct_error; 326 } 327 328 static bool_t 329 clnttcp_freeres(CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr) 330 { 331 struct ct_data *ct = (struct ct_data *)cl->cl_private; 332 XDR *xdrs = &(ct->ct_xdrs); 333 334 xdrs->x_op = XDR_FREE; 335 return ((*xdr_res)(xdrs, res_ptr)); 336 } 337 338 /*ARGSUSED*/ 339 static void 340 clnttcp_abort(CLIENT *clnt) 341 { 342 } 343 344 static bool_t 345 clnttcp_control(CLIENT *cl, u_int request, void *info) 346 { 347 struct ct_data *ct = (struct ct_data *)cl->cl_private; 348 349 switch (request) { 350 case CLSET_TIMEOUT: 351 ct->ct_wait = *(struct timeval *)info; 352 ct->ct_waitset = TRUE; 353 break; 354 case CLGET_TIMEOUT: 355 *(struct timeval *)info = ct->ct_wait; 356 break; 357 case CLGET_SERVER_ADDR: 358 *(struct sockaddr_in *)info = ct->ct_addr; 359 break; 360 default: 361 return (FALSE); 362 } 363 return (TRUE); 364 } 365 366 367 static void 368 clnttcp_destroy(CLIENT *h) 369 { 370 struct ct_data *ct = 371 (struct ct_data *) h->cl_private; 372 373 if (ct->ct_closeit && ct->ct_sock != -1) { 374 (void)close(ct->ct_sock); 375 } 376 XDR_DESTROY(&(ct->ct_xdrs)); 377 mem_free((caddr_t)ct, sizeof(struct ct_data)); 378 mem_free((caddr_t)h, sizeof(CLIENT)); 379 } 380 381 /* 382 * Interface between xdr serializer and tcp connection. 383 * Behaves like the system calls, read & write, but keeps some error state 384 * around for the rpc level. 385 */ 386 static int 387 readtcp(struct ct_data *ct, caddr_t buf, int len) 388 { 389 struct pollfd pfd[1]; 390 struct timeval start, after, duration, tmp; 391 int delta, r, save_errno; 392 393 if (len == 0) 394 return (0); 395 396 pfd[0].fd = ct->ct_sock; 397 pfd[0].events = POLLIN; 398 delta = ct->ct_wait.tv_sec * 1000 + ct->ct_wait.tv_usec / 1000; 399 gettimeofday(&start, NULL); 400 for (;;) { 401 r = poll(pfd, 1, delta); 402 save_errno = errno; 403 404 gettimeofday(&after, NULL); 405 timersub(&start, &after, &duration); 406 timersub(&ct->ct_wait, &duration, &tmp); 407 delta = tmp.tv_sec * 1000 + tmp.tv_usec / 1000; 408 if (delta <= 0) 409 r = 0; 410 411 switch (r) { 412 case 0: 413 ct->ct_error.re_status = RPC_TIMEDOUT; 414 return (-1); 415 case 1: 416 if (pfd[0].revents & POLLNVAL) 417 errno = EBADF; 418 else if (pfd[0].revents & POLLERR) 419 errno = EIO; 420 else 421 break; 422 /* FALLTHROUGH */ 423 case -1: 424 if (errno == EINTR) 425 continue; 426 ct->ct_error.re_status = RPC_CANTRECV; 427 ct->ct_error.re_errno = save_errno; 428 return (-1); 429 } 430 break; 431 } 432 433 switch (len = read(ct->ct_sock, buf, len)) { 434 case 0: 435 /* premature eof */ 436 ct->ct_error.re_errno = ECONNRESET; 437 ct->ct_error.re_status = RPC_CANTRECV; 438 len = -1; /* it's really an error */ 439 break; 440 case -1: 441 ct->ct_error.re_errno = errno; 442 ct->ct_error.re_status = RPC_CANTRECV; 443 break; 444 } 445 return (len); 446 } 447 448 static int 449 writetcp(struct ct_data *ct, caddr_t buf, int len) 450 { 451 int i, cnt; 452 453 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 454 if ((i = write(ct->ct_sock, buf, cnt)) == -1) { 455 ct->ct_error.re_errno = errno; 456 ct->ct_error.re_status = RPC_CANTSEND; 457 return (-1); 458 } 459 } 460 return (len); 461 } 462