1 /* $OpenBSD: clnt_tcp.c,v 1.29 2015/11/01 03:45:29 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 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 123 rpc_createerr.cf_error.re_errno = errno; 124 goto fooy; 125 } 126 ct = (struct ct_data *)mem_alloc(sizeof(*ct)); 127 if (ct == NULL) { 128 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 129 rpc_createerr.cf_error.re_errno = errno; 130 goto fooy; 131 } 132 133 /* 134 * If no port number given ask the pmap for one 135 */ 136 if (raddr->sin_port == 0) { 137 u_short port; 138 if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) { 139 mem_free((caddr_t)ct, sizeof(struct ct_data)); 140 mem_free((caddr_t)h, sizeof(CLIENT)); 141 return (NULL); 142 } 143 raddr->sin_port = htons(port); 144 } 145 146 /* 147 * If no socket given, open one 148 */ 149 if (*sockp < 0) { 150 *sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 151 (void)bindresvport(*sockp, NULL); 152 if ((*sockp < 0) 153 || (connect(*sockp, (struct sockaddr *)raddr, 154 sizeof(*raddr)) < 0)) { 155 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 156 rpc_createerr.cf_error.re_errno = errno; 157 if (*sockp != -1) 158 (void)close(*sockp); 159 goto fooy; 160 } 161 ct->ct_closeit = TRUE; 162 } else { 163 ct->ct_closeit = FALSE; 164 } 165 166 /* 167 * Set up private data struct 168 */ 169 ct->ct_sock = *sockp; 170 ct->ct_wait.tv_usec = 0; 171 ct->ct_waitset = FALSE; 172 ct->ct_addr = *raddr; 173 174 /* 175 * Initialize call message 176 */ 177 (void)gettimeofday(&now, NULL); 178 call_msg.rm_xid = arc4random(); 179 call_msg.rm_direction = CALL; 180 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 181 call_msg.rm_call.cb_prog = prog; 182 call_msg.rm_call.cb_vers = vers; 183 184 /* 185 * pre-serialize the static part of the call msg and stash it away 186 */ 187 xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, 188 XDR_ENCODE); 189 if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { 190 if (ct->ct_closeit) { 191 (void)close(*sockp); 192 } 193 goto fooy; 194 } 195 ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); 196 XDR_DESTROY(&(ct->ct_xdrs)); 197 198 /* 199 * Create a client handle which uses xdrrec for serialization 200 * and authnone for authentication. 201 */ 202 xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, 203 (caddr_t)ct, (int(*)(caddr_t, caddr_t, int))readtcp, 204 (int(*)(caddr_t, caddr_t, int))writetcp); 205 h->cl_ops = &tcp_ops; 206 h->cl_private = (caddr_t) ct; 207 h->cl_auth = authnone_create(); 208 if (h->cl_auth == NULL) { 209 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 210 rpc_createerr.cf_error.re_errno = errno; 211 goto fooy; 212 } 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 (NULL); 224 } 225 DEF_WEAK(clnttcp_create); 226 227 static enum clnt_stat 228 clnttcp_call(CLIENT *h, u_long proc, xdrproc_t xdr_args, caddr_t args_ptr, 229 xdrproc_t xdr_results, caddr_t results_ptr, struct timeval timeout) 230 { 231 struct ct_data *ct = (struct ct_data *) h->cl_private; 232 XDR *xdrs = &(ct->ct_xdrs); 233 struct rpc_msg reply_msg; 234 u_long x_id; 235 u_int32_t *msg_x_id = (u_int32_t *)(ct->ct_mcall); /* yuk */ 236 bool_t shipnow; 237 int refreshes = 2; 238 239 if (!ct->ct_waitset) { 240 ct->ct_wait = timeout; 241 } 242 243 shipnow = 244 (xdr_results == NULL && timeout.tv_sec == 0 245 && timeout.tv_usec == 0) ? FALSE : TRUE; 246 247 call_again: 248 xdrs->x_op = XDR_ENCODE; 249 ct->ct_error.re_status = RPC_SUCCESS; 250 x_id = ntohl(--(*msg_x_id)); 251 if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) || 252 (! XDR_PUTLONG(xdrs, (long *)&proc)) || 253 (! AUTH_MARSHALL(h->cl_auth, xdrs)) || 254 (! (*xdr_args)(xdrs, args_ptr))) { 255 if (ct->ct_error.re_status == RPC_SUCCESS) 256 ct->ct_error.re_status = RPC_CANTENCODEARGS; 257 (void)xdrrec_endofrecord(xdrs, TRUE); 258 return (ct->ct_error.re_status); 259 } 260 if (! xdrrec_endofrecord(xdrs, shipnow)) 261 return (ct->ct_error.re_status = RPC_CANTSEND); 262 if (! shipnow) 263 return (RPC_SUCCESS); 264 /* 265 * Hack to provide rpc-based message passing 266 */ 267 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 268 return(ct->ct_error.re_status = RPC_TIMEDOUT); 269 } 270 271 272 /* 273 * Keep receiving until we get a valid transaction id 274 */ 275 xdrs->x_op = XDR_DECODE; 276 while (TRUE) { 277 reply_msg.acpted_rply.ar_verf = _null_auth; 278 reply_msg.acpted_rply.ar_results.where = NULL; 279 reply_msg.acpted_rply.ar_results.proc = xdr_void; 280 if (! xdrrec_skiprecord(xdrs)) 281 return (ct->ct_error.re_status); 282 /* now decode and validate the response header */ 283 if (! xdr_replymsg(xdrs, &reply_msg)) { 284 if (ct->ct_error.re_status == RPC_SUCCESS) 285 continue; 286 return (ct->ct_error.re_status); 287 } 288 if (reply_msg.rm_xid == x_id) 289 break; 290 } 291 292 /* 293 * process header 294 */ 295 _seterr_reply(&reply_msg, &(ct->ct_error)); 296 if (ct->ct_error.re_status == RPC_SUCCESS) { 297 if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) { 298 ct->ct_error.re_status = RPC_AUTHERROR; 299 ct->ct_error.re_why = AUTH_INVALIDRESP; 300 } else if (! (*xdr_results)(xdrs, results_ptr)) { 301 if (ct->ct_error.re_status == RPC_SUCCESS) 302 ct->ct_error.re_status = RPC_CANTDECODERES; 303 } 304 /* free verifier ... */ 305 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 306 xdrs->x_op = XDR_FREE; 307 (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); 308 } 309 } /* end successful completion */ 310 else { 311 /* maybe our credentials need to be refreshed ... */ 312 if (refreshes-- && AUTH_REFRESH(h->cl_auth)) 313 goto call_again; 314 } /* end of unsuccessful completion */ 315 return (ct->ct_error.re_status); 316 } 317 318 static void 319 clnttcp_geterr(CLIENT *h, struct rpc_err *errp) 320 { 321 struct ct_data *ct = 322 (struct ct_data *) h->cl_private; 323 324 *errp = ct->ct_error; 325 } 326 327 static bool_t 328 clnttcp_freeres(CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr) 329 { 330 struct ct_data *ct = (struct ct_data *)cl->cl_private; 331 XDR *xdrs = &(ct->ct_xdrs); 332 333 xdrs->x_op = XDR_FREE; 334 return ((*xdr_res)(xdrs, res_ptr)); 335 } 336 337 static void 338 clnttcp_abort(CLIENT *clnt) 339 { 340 } 341 342 static bool_t 343 clnttcp_control(CLIENT *cl, u_int request, void *info) 344 { 345 struct ct_data *ct = (struct ct_data *)cl->cl_private; 346 347 switch (request) { 348 case CLSET_TIMEOUT: 349 ct->ct_wait = *(struct timeval *)info; 350 ct->ct_waitset = TRUE; 351 break; 352 case CLGET_TIMEOUT: 353 *(struct timeval *)info = ct->ct_wait; 354 break; 355 case CLGET_SERVER_ADDR: 356 *(struct sockaddr_in *)info = ct->ct_addr; 357 break; 358 default: 359 return (FALSE); 360 } 361 return (TRUE); 362 } 363 364 365 static void 366 clnttcp_destroy(CLIENT *h) 367 { 368 struct ct_data *ct = 369 (struct ct_data *) h->cl_private; 370 371 if (ct->ct_closeit && ct->ct_sock != -1) { 372 (void)close(ct->ct_sock); 373 } 374 XDR_DESTROY(&(ct->ct_xdrs)); 375 mem_free((caddr_t)ct, sizeof(struct ct_data)); 376 mem_free((caddr_t)h, sizeof(CLIENT)); 377 } 378 379 /* 380 * Interface between xdr serializer and tcp connection. 381 * Behaves like the system calls, read & write, but keeps some error state 382 * around for the rpc level. 383 */ 384 static int 385 readtcp(struct ct_data *ct, caddr_t buf, int len) 386 { 387 struct pollfd pfd[1]; 388 struct timeval start, after, duration, tmp; 389 int delta, r, save_errno; 390 391 if (len == 0) 392 return (0); 393 394 pfd[0].fd = ct->ct_sock; 395 pfd[0].events = POLLIN; 396 delta = ct->ct_wait.tv_sec * 1000 + ct->ct_wait.tv_usec / 1000; 397 gettimeofday(&start, NULL); 398 for (;;) { 399 r = poll(pfd, 1, delta); 400 save_errno = errno; 401 402 gettimeofday(&after, NULL); 403 timersub(&start, &after, &duration); 404 timersub(&ct->ct_wait, &duration, &tmp); 405 delta = tmp.tv_sec * 1000 + tmp.tv_usec / 1000; 406 if (delta <= 0) 407 r = 0; 408 409 switch (r) { 410 case 0: 411 ct->ct_error.re_status = RPC_TIMEDOUT; 412 return (-1); 413 case 1: 414 if (pfd[0].revents & POLLNVAL) 415 errno = EBADF; 416 else if (pfd[0].revents & POLLERR) 417 errno = EIO; 418 else 419 break; 420 /* FALLTHROUGH */ 421 case -1: 422 if (errno == EINTR) 423 continue; 424 ct->ct_error.re_status = RPC_CANTRECV; 425 ct->ct_error.re_errno = save_errno; 426 return (-1); 427 } 428 break; 429 } 430 431 switch (len = read(ct->ct_sock, buf, len)) { 432 case 0: 433 /* premature eof */ 434 ct->ct_error.re_errno = ECONNRESET; 435 ct->ct_error.re_status = RPC_CANTRECV; 436 len = -1; /* it's really an error */ 437 break; 438 case -1: 439 ct->ct_error.re_errno = errno; 440 ct->ct_error.re_status = RPC_CANTRECV; 441 break; 442 } 443 return (len); 444 } 445 446 static int 447 writetcp(struct ct_data *ct, caddr_t buf, int len) 448 { 449 int i, cnt; 450 451 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 452 if ((i = write(ct->ct_sock, buf, cnt)) == -1) { 453 ct->ct_error.re_errno = errno; 454 ct->ct_error.re_status = RPC_CANTSEND; 455 return (-1); 456 } 457 } 458 return (len); 459 } 460