1 /* $OpenBSD: clnt_tcp.c,v 1.25 2010/09/01 14:43:34 millert 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 clients responsibility to close *sockp. 106 * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this 107 * something more useful. 108 */ 109 CLIENT * 110 clnttcp_create(struct sockaddr_in *raddr, u_long prog, u_long vers, int *sockp, 111 u_int sendsz, u_int recvsz) 112 { 113 CLIENT *h; 114 struct ct_data *ct = NULL; 115 struct timeval now; 116 struct rpc_msg call_msg; 117 118 h = (CLIENT *)mem_alloc(sizeof(*h)); 119 if (h == NULL) { 120 (void)fprintf(stderr, "clnttcp_create: out of memory\n"); 121 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 122 rpc_createerr.cf_error.re_errno = errno; 123 goto fooy; 124 } 125 ct = (struct ct_data *)mem_alloc(sizeof(*ct)); 126 if (ct == NULL) { 127 (void)fprintf(stderr, "clnttcp_create: out of memory\n"); 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 226 static enum clnt_stat 227 clnttcp_call(CLIENT *h, u_long proc, xdrproc_t xdr_args, caddr_t args_ptr, 228 xdrproc_t xdr_results, caddr_t results_ptr, struct timeval timeout) 229 { 230 struct ct_data *ct = (struct ct_data *) h->cl_private; 231 XDR *xdrs = &(ct->ct_xdrs); 232 struct rpc_msg reply_msg; 233 u_long x_id; 234 u_int32_t *msg_x_id = (u_int32_t *)(ct->ct_mcall); /* yuk */ 235 bool_t shipnow; 236 int refreshes = 2; 237 238 if (!ct->ct_waitset) { 239 ct->ct_wait = timeout; 240 } 241 242 shipnow = 243 (xdr_results == NULL && timeout.tv_sec == 0 244 && timeout.tv_usec == 0) ? FALSE : TRUE; 245 246 call_again: 247 xdrs->x_op = XDR_ENCODE; 248 ct->ct_error.re_status = RPC_SUCCESS; 249 x_id = ntohl(--(*msg_x_id)); 250 if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) || 251 (! XDR_PUTLONG(xdrs, (long *)&proc)) || 252 (! AUTH_MARSHALL(h->cl_auth, xdrs)) || 253 (! (*xdr_args)(xdrs, args_ptr))) { 254 if (ct->ct_error.re_status == RPC_SUCCESS) 255 ct->ct_error.re_status = RPC_CANTENCODEARGS; 256 (void)xdrrec_endofrecord(xdrs, TRUE); 257 return (ct->ct_error.re_status); 258 } 259 if (! xdrrec_endofrecord(xdrs, shipnow)) 260 return (ct->ct_error.re_status = RPC_CANTSEND); 261 if (! shipnow) 262 return (RPC_SUCCESS); 263 /* 264 * Hack to provide rpc-based message passing 265 */ 266 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 267 return(ct->ct_error.re_status = RPC_TIMEDOUT); 268 } 269 270 271 /* 272 * Keep receiving until we get a valid transaction id 273 */ 274 xdrs->x_op = XDR_DECODE; 275 while (TRUE) { 276 reply_msg.acpted_rply.ar_verf = _null_auth; 277 reply_msg.acpted_rply.ar_results.where = NULL; 278 reply_msg.acpted_rply.ar_results.proc = xdr_void; 279 if (! xdrrec_skiprecord(xdrs)) 280 return (ct->ct_error.re_status); 281 /* now decode and validate the response header */ 282 if (! xdr_replymsg(xdrs, &reply_msg)) { 283 if (ct->ct_error.re_status == RPC_SUCCESS) 284 continue; 285 return (ct->ct_error.re_status); 286 } 287 if (reply_msg.rm_xid == x_id) 288 break; 289 } 290 291 /* 292 * process header 293 */ 294 _seterr_reply(&reply_msg, &(ct->ct_error)); 295 if (ct->ct_error.re_status == RPC_SUCCESS) { 296 if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) { 297 ct->ct_error.re_status = RPC_AUTHERROR; 298 ct->ct_error.re_why = AUTH_INVALIDRESP; 299 } else if (! (*xdr_results)(xdrs, results_ptr)) { 300 if (ct->ct_error.re_status == RPC_SUCCESS) 301 ct->ct_error.re_status = RPC_CANTDECODERES; 302 } 303 /* free verifier ... */ 304 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 305 xdrs->x_op = XDR_FREE; 306 (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); 307 } 308 } /* end successful completion */ 309 else { 310 /* maybe our credentials need to be refreshed ... */ 311 if (refreshes-- && AUTH_REFRESH(h->cl_auth)) 312 goto call_again; 313 } /* end of unsuccessful completion */ 314 return (ct->ct_error.re_status); 315 } 316 317 static void 318 clnttcp_geterr(CLIENT *h, struct rpc_err *errp) 319 { 320 struct ct_data *ct = 321 (struct ct_data *) h->cl_private; 322 323 *errp = ct->ct_error; 324 } 325 326 static bool_t 327 clnttcp_freeres(CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr) 328 { 329 struct ct_data *ct = (struct ct_data *)cl->cl_private; 330 XDR *xdrs = &(ct->ct_xdrs); 331 332 xdrs->x_op = XDR_FREE; 333 return ((*xdr_res)(xdrs, res_ptr)); 334 } 335 336 /*ARGSUSED*/ 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) { 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