1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1990 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright (c) 1984, 1986, 1987, 1988, 1989, 1996 AT&T 29 * All Rights Reserved 30 */ 31 32 /* 33 * University Copyright- Copyright (c) 1982, 1986, 1988 34 * The Regents of the University of California 35 * All Rights Reserved 36 * 37 * University Acknowledgment- Portions of this document are derived from 38 * software developed by the University of California, Berkeley, and its 39 * contributors. 40 */ 41 42 #pragma ident "%Z%%M% %I% %E% SMI" 43 44 /* 45 * clnt_tcp.c, Implements a TCP/IP based, client side RPC. 46 * 47 * TCP based RPC supports 'batched calls'. 48 * A sequence of calls may be batched-up in a send buffer. The rpc call 49 * return immediately to the client even though the call was not necessarily 50 * sent. The batching occurs if the results' xdr routine is NULL (0) AND 51 * the rpc timeout value is zero (see clnt.h, rpc). 52 * 53 * Clients should NOT casually batch calls that in fact return results; that is, 54 * the server side should be aware that a call is batched and not produce any 55 * return message. Batched calls that produce many result messages can 56 * deadlock (netlock) the client and the server.... 57 * 58 * Now go hang yourself. 59 */ 60 61 #include <rpc/rpc.h> 62 #include <sys/socket.h> 63 #include <sys/time.h> 64 #include <netdb.h> 65 #include <errno.h> 66 #include <rpc/pmap_clnt.h> 67 #include <syslog.h> 68 #include <malloc.h> 69 #include <stdio.h> 70 71 #define MCALL_MSG_SIZE 24 72 73 extern int errno; 74 75 static int readtcp(); 76 static int writetcp(); 77 extern int _socket(int, int, int); 78 extern pid_t getpid(); 79 extern int bindresvport(int, struct sockaddr_in *); 80 extern bool_t xdr_opaque_auth(XDR *, struct opaque_auth *); 81 static struct clnt_ops *clnttcp_ops(); 82 83 struct ct_data { 84 int ct_sock; 85 bool_t ct_closeit; 86 struct timeval ct_wait; 87 bool_t ct_waitset; /* wait set by clnt_control? */ 88 struct sockaddr_in ct_addr; 89 struct rpc_err ct_error; 90 char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */ 91 u_int ct_mpos; /* pos after marshal */ 92 XDR ct_xdrs; 93 }; 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 107 * set this something more useful. 108 */ 109 CLIENT * 110 clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) 111 struct sockaddr_in *raddr; 112 rpcprog_t prog; 113 rpcvers_t vers; 114 register int *sockp; 115 u_int sendsz; 116 u_int recvsz; 117 { 118 CLIENT *h; 119 register struct ct_data *ct; 120 struct timeval now; 121 struct rpc_msg call_msg; 122 int i; 123 124 h = (CLIENT *)mem_alloc(sizeof (*h)); 125 if (h == NULL) { 126 (void) syslog(LOG_ERR, "clnttcp_create: out of memory"); 127 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 128 rpc_createerr.cf_error.re_errno = errno; 129 goto fooy; 130 } 131 ct = (struct ct_data *)mem_alloc(sizeof (*ct)); 132 if (ct == NULL) { 133 (void) syslog(LOG_ERR, "clnttcp_create: out of memory"); 134 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 135 rpc_createerr.cf_error.re_errno = errno; 136 goto fooy; 137 } 138 139 /* 140 * If no port number given ask the pmap for one 141 */ 142 if (raddr->sin_port == 0) { 143 u_short port; 144 if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) 145 == 0) { 146 mem_free((caddr_t)ct, sizeof (struct ct_data)); 147 mem_free((caddr_t)h, sizeof (CLIENT)); 148 return ((CLIENT *)NULL); 149 } 150 raddr->sin_port = htons(port); 151 } 152 153 /* 154 * If no socket given, open one 155 */ 156 if (*sockp < 0) { 157 *sockp = _socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 158 i = bindresvport(*sockp, (struct sockaddr_in *)0); 159 if ((*sockp < 0)|| 160 (connect(*sockp, (struct sockaddr *)raddr, 161 sizeof (*raddr)) < 0)) { 162 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 163 rpc_createerr.cf_error.re_errno = errno; 164 (void) close(*sockp); 165 goto fooy; 166 } 167 ct->ct_closeit = TRUE; 168 } else { 169 ct->ct_closeit = FALSE; 170 } 171 172 /* 173 * Set up private data struct 174 */ 175 ct->ct_sock = *sockp; 176 ct->ct_wait.tv_usec = 0; 177 ct->ct_waitset = FALSE; 178 ct->ct_addr = *raddr; 179 180 /* 181 * Initialize call message 182 */ 183 (void) gettimeofday(&now, (struct timezone *)0); 184 call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec; 185 call_msg.rm_direction = CALL; 186 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 187 call_msg.rm_call.cb_prog = prog; 188 call_msg.rm_call.cb_vers = vers; 189 190 /* 191 * pre-serialize the staic part of the call msg and stash it away 192 */ 193 xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, 194 XDR_ENCODE); 195 if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { 196 if (ct->ct_closeit) { 197 (void) close(*sockp); 198 } 199 goto fooy; 200 } 201 ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); 202 XDR_DESTROY(&(ct->ct_xdrs)); 203 204 /* 205 * Create a client handle which uses xdrrec for serialization 206 * and authnone for authentication. 207 */ 208 xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, 209 (caddr_t)ct, readtcp, writetcp); 210 h->cl_ops = clnttcp_ops(); 211 h->cl_private = (caddr_t) ct; 212 h->cl_auth = authnone_create(); 213 return (h); 214 215 fooy: 216 /* 217 * Something goofed, free stuff and barf 218 */ 219 mem_free((caddr_t)ct, sizeof (struct ct_data)); 220 mem_free((caddr_t)h, sizeof (CLIENT)); 221 return ((CLIENT *)NULL); 222 } 223 224 static enum clnt_stat 225 clnttcp_call(h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout) 226 register CLIENT *h; 227 rpcproc_t proc; 228 xdrproc_t xdr_args; 229 caddr_t args_ptr; 230 xdrproc_t xdr_results; 231 caddr_t results_ptr; 232 struct timeval timeout; 233 { 234 register struct ct_data *ct = (struct ct_data *) h->cl_private; 235 register XDR *xdrs = &(ct->ct_xdrs); 236 struct rpc_msg reply_msg; 237 uint32_t x_id; 238 uint32_t *msg_x_id = (uint32_t *)(ct->ct_mcall); /* yuk */ 239 register bool_t shipnow; 240 int refreshes = 2; 241 242 if (!ct->ct_waitset) { 243 ct->ct_wait = timeout; 244 } 245 246 shipnow = 247 (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0 && 248 timeout.tv_usec == 0) ? FALSE : TRUE; 249 250 call_again: 251 xdrs->x_op = XDR_ENCODE; 252 ct->ct_error.re_status = RPC_SUCCESS; 253 x_id = ntohl(--(*msg_x_id)); 254 if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) || 255 (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || 256 (! AUTH_MARSHALL(h->cl_auth, xdrs)) || 257 (! (*xdr_args)(xdrs, args_ptr))) { 258 if (ct->ct_error.re_status == RPC_SUCCESS) 259 ct->ct_error.re_status = RPC_CANTENCODEARGS; 260 (void) xdrrec_endofrecord(xdrs, TRUE); 261 return (ct->ct_error.re_status); 262 } 263 if (! xdrrec_endofrecord(xdrs, shipnow)) 264 return (ct->ct_error.re_status = RPC_CANTSEND); 265 if (! shipnow) 266 return (RPC_SUCCESS); 267 /* 268 * Hack to provide rpc-based message passing 269 */ 270 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 271 return (ct->ct_error.re_status = RPC_TIMEDOUT); 272 } 273 274 275 /* 276 * Keep receiving until we get a valid transaction id 277 */ 278 xdrs->x_op = XDR_DECODE; 279 while (TRUE) { 280 reply_msg.acpted_rply.ar_verf = _null_auth; 281 reply_msg.acpted_rply.ar_results.where = NULL; 282 reply_msg.acpted_rply.ar_results.proc = xdr_void; 283 if (! xdrrec_skiprecord(xdrs)) 284 return (ct->ct_error.re_status); 285 /* now decode and validate the response header */ 286 if (! xdr_replymsg(xdrs, &reply_msg)) { 287 if (ct->ct_error.re_status == RPC_SUCCESS) 288 continue; 289 return (ct->ct_error.re_status); 290 } 291 if (reply_msg.rm_xid == x_id) 292 break; 293 } 294 295 /* 296 * process header 297 */ 298 __seterr_reply(&reply_msg, &(ct->ct_error)); 299 if (ct->ct_error.re_status == RPC_SUCCESS) { 300 if (! AUTH_VALIDATE(h->cl_auth, 301 &reply_msg.acpted_rply.ar_verf)) { 302 ct->ct_error.re_status = RPC_AUTHERROR; 303 ct->ct_error.re_why = AUTH_INVALIDRESP; 304 } else if (! (*xdr_results)(xdrs, results_ptr)) { 305 if (ct->ct_error.re_status == RPC_SUCCESS) 306 ct->ct_error.re_status = RPC_CANTDECODERES; 307 } 308 /* free verifier ... */ 309 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 310 xdrs->x_op = XDR_FREE; 311 (void) xdr_opaque_auth(xdrs, 312 &(reply_msg.acpted_rply.ar_verf)); 313 } 314 } /* end successful completion */ 315 else { 316 /* maybe our credentials need to be refreshed ... */ 317 if (refreshes-- && AUTH_REFRESH(h->cl_auth, &reply_msg)) 318 goto call_again; 319 } /* end of unsuccessful completion */ 320 return (ct->ct_error.re_status); 321 } 322 323 static void 324 clnttcp_geterr(h, errp) 325 CLIENT *h; 326 struct rpc_err *errp; 327 { 328 register struct ct_data *ct = 329 (struct ct_data *) h->cl_private; 330 331 *errp = ct->ct_error; 332 } 333 334 static bool_t 335 clnttcp_freeres(cl, xdr_res, res_ptr) 336 CLIENT *cl; 337 xdrproc_t xdr_res; 338 caddr_t res_ptr; 339 { 340 register struct ct_data *ct = (struct ct_data *)cl->cl_private; 341 register XDR *xdrs = &(ct->ct_xdrs); 342 343 xdrs->x_op = XDR_FREE; 344 return ((*xdr_res)(xdrs, res_ptr)); 345 } 346 347 static void 348 clnttcp_abort() 349 { 350 } 351 352 static bool_t 353 clnttcp_control(cl, request, info) 354 CLIENT *cl; 355 int request; 356 char *info; 357 { 358 register struct ct_data *ct = (struct ct_data *)cl->cl_private; 359 360 switch (request) { 361 case CLSET_TIMEOUT: 362 ct->ct_wait = *(struct timeval *)info; 363 ct->ct_waitset = TRUE; 364 break; 365 case CLGET_TIMEOUT: 366 *(struct timeval *)info = ct->ct_wait; 367 break; 368 case CLGET_SERVER_ADDR: 369 *(struct sockaddr_in *)info = ct->ct_addr; 370 break; 371 case CLGET_FD: 372 *(int *)info = ct->ct_sock; 373 break; 374 case CLSET_FD_CLOSE: 375 ct->ct_closeit = TRUE; 376 break; 377 case CLSET_FD_NCLOSE: 378 ct->ct_closeit = FALSE; 379 break; 380 default: 381 return (FALSE); 382 } 383 return (TRUE); 384 } 385 386 387 static void 388 clnttcp_destroy(h) 389 CLIENT *h; 390 { 391 register struct ct_data *ct = 392 (struct ct_data *) h->cl_private; 393 394 if (ct->ct_closeit) { 395 (void) close(ct->ct_sock); 396 } 397 XDR_DESTROY(&(ct->ct_xdrs)); 398 mem_free((caddr_t)ct, sizeof (struct ct_data)); 399 mem_free((caddr_t)h, sizeof (CLIENT)); 400 } 401 402 /* 403 * Interface between xdr serializer and tcp connection. 404 * Behaves like the system calls, read & write, but keeps some error state 405 * around for the rpc level. 406 */ 407 static int 408 readtcp(ct, buf, len) 409 register struct ct_data *ct; 410 caddr_t buf; 411 register int len; 412 { 413 fd_set mask; 414 fd_set readfds; 415 416 if (len == 0) 417 return (0); 418 FD_ZERO(&mask); 419 FD_SET(ct->ct_sock, &mask); 420 while (TRUE) { 421 readfds = mask; 422 switch (select(__rpc_dtbsize(), 423 &readfds, NULL, NULL, &(ct->ct_wait))) { 424 case 0: 425 ct->ct_error.re_status = RPC_TIMEDOUT; 426 return (-1); 427 428 case -1: 429 if (errno == EINTR) 430 continue; 431 ct->ct_error.re_status = RPC_CANTRECV; 432 ct->ct_error.re_errno = errno; 433 return (-1); 434 } 435 break; 436 } 437 switch (len = read(ct->ct_sock, buf, len)) { 438 439 case 0: 440 /* premature eof */ 441 ct->ct_error.re_errno = ECONNRESET; 442 ct->ct_error.re_status = RPC_CANTRECV; 443 len = -1; /* it's really an error */ 444 break; 445 446 case -1: 447 ct->ct_error.re_errno = errno; 448 ct->ct_error.re_status = RPC_CANTRECV; 449 break; 450 } 451 return (len); 452 } 453 454 static int 455 writetcp(ct, buf, len) 456 struct ct_data *ct; 457 caddr_t buf; 458 int len; 459 { 460 register int i, cnt; 461 462 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 463 if ((i = write(ct->ct_sock, buf, cnt)) == -1) { 464 ct->ct_error.re_errno = errno; 465 ct->ct_error.re_status = RPC_CANTSEND; 466 return (-1); 467 } 468 } 469 return (len); 470 } 471 472 static struct clnt_ops * 473 clnttcp_ops() 474 { 475 static struct clnt_ops ops; 476 477 if (ops.cl_call == NULL) { 478 ops.cl_call = clnttcp_call; 479 ops.cl_abort = clnttcp_abort; 480 ops.cl_geterr = clnttcp_geterr; 481 ops.cl_freeres = clnttcp_freeres; 482 ops.cl_destroy = clnttcp_destroy; 483 ops.cl_control = clnttcp_control; 484 } 485 return (&ops); 486 } 487