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 /* 43 * clnt_tcp.c, Implements a TCP/IP based, client side RPC. 44 * 45 * TCP based RPC supports 'batched calls'. 46 * A sequence of calls may be batched-up in a send buffer. The rpc call 47 * return immediately to the client even though the call was not necessarily 48 * sent. The batching occurs if the results' xdr routine is NULL (0) AND 49 * the rpc timeout value is zero (see clnt.h, rpc). 50 * 51 * Clients should NOT casually batch calls that in fact return results; that is, 52 * the server side should be aware that a call is batched and not produce any 53 * return message. Batched calls that produce many result messages can 54 * deadlock (netlock) the client and the server.... 55 * 56 * Now go hang yourself. 57 */ 58 59 #include <rpc/rpc.h> 60 #include <sys/socket.h> 61 #include <sys/time.h> 62 #include <netdb.h> 63 #include <errno.h> 64 #include <rpc/pmap_clnt.h> 65 #include <syslog.h> 66 #include <malloc.h> 67 #include <stdio.h> 68 69 #define MCALL_MSG_SIZE 24 70 71 extern int errno; 72 73 static int readtcp(void *, caddr_t, int); 74 static int writetcp(void *, caddr_t, int); 75 extern int _socket(int, int, int); 76 extern pid_t getpid(void); 77 extern int bindresvport(int, struct sockaddr_in *); 78 extern bool_t xdr_opaque_auth(XDR *, struct opaque_auth *); 79 static struct clnt_ops *clnttcp_ops(void); 80 81 struct ct_data { 82 int ct_sock; 83 bool_t ct_closeit; 84 struct timeval ct_wait; 85 bool_t ct_waitset; /* wait set by clnt_control? */ 86 struct sockaddr_in ct_addr; 87 struct rpc_err ct_error; 88 char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */ 89 uint_t ct_mpos; /* pos after marshal */ 90 XDR ct_xdrs; 91 }; 92 93 /* 94 * Create a client handle for a tcp/ip connection. 95 * If *sockp<0, *sockp is set to a newly created TCP socket and it is 96 * connected to raddr. If *sockp non-negative then 97 * raddr is ignored. The rpc/tcp package does buffering 98 * similar to stdio, so the client must pick send and receive buffer sizes 99 * 0 => use the default. 100 * If raddr->sin_port is 0, then a binder on the remote machine is 101 * consulted for the right port number. 102 * NB: *sockp is copied into a private area. 103 * NB: It is the clients responsibility to close *sockp. 104 * NB: The rpch->cl_auth is set null authentication. Caller may wish to 105 * set this something more useful. 106 */ 107 CLIENT * 108 clnttcp_create(struct sockaddr_in *raddr, rpcprog_t prog, rpcvers_t vers, 109 int *sockp, uint_t sendsz, uint_t recvsz) 110 { 111 CLIENT *h; 112 struct ct_data *ct; 113 struct timeval now; 114 struct rpc_msg call_msg; 115 116 h = (CLIENT *)mem_alloc(sizeof (*h)); 117 if (h == NULL) { 118 (void) syslog(LOG_ERR, "clnttcp_create: out of memory"); 119 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 120 rpc_createerr.cf_error.re_errno = errno; 121 goto fooy; 122 } 123 ct = (struct ct_data *)mem_alloc(sizeof (*ct)); 124 if (ct == NULL) { 125 (void) syslog(LOG_ERR, "clnttcp_create: out of memory"); 126 rpc_createerr.cf_stat = RPC_SYSTEMERROR; 127 rpc_createerr.cf_error.re_errno = errno; 128 goto fooy; 129 } 130 131 /* 132 * If no port number given ask the pmap for one 133 */ 134 if (raddr->sin_port == 0) { 135 ushort_t port; 136 if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) 137 == 0) { 138 mem_free((caddr_t)ct, sizeof (struct ct_data)); 139 mem_free((caddr_t)h, sizeof (CLIENT)); 140 return ((CLIENT *)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, (struct sockaddr_in *)0); 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 (void) close(*sockp); 157 goto fooy; 158 } 159 ct->ct_closeit = TRUE; 160 } else { 161 ct->ct_closeit = FALSE; 162 } 163 164 /* 165 * Set up private data struct 166 */ 167 ct->ct_sock = *sockp; 168 ct->ct_wait.tv_usec = 0; 169 ct->ct_waitset = FALSE; 170 ct->ct_addr = *raddr; 171 172 /* 173 * Initialize call message 174 */ 175 (void) gettimeofday(&now, (struct timezone *)0); 176 call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec; 177 call_msg.rm_direction = CALL; 178 call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 179 call_msg.rm_call.cb_prog = prog; 180 call_msg.rm_call.cb_vers = vers; 181 182 /* 183 * pre-serialize the staic part of the call msg and stash it away 184 */ 185 xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, 186 XDR_ENCODE); 187 if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { 188 if (ct->ct_closeit) { 189 (void) close(*sockp); 190 } 191 goto fooy; 192 } 193 ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); 194 XDR_DESTROY(&(ct->ct_xdrs)); 195 196 /* 197 * Create a client handle which uses xdrrec for serialization 198 * and authnone for authentication. 199 */ 200 xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, 201 (caddr_t)ct, readtcp, writetcp); 202 h->cl_ops = clnttcp_ops(); 203 h->cl_private = (caddr_t)ct; 204 h->cl_auth = authnone_create(); 205 return (h); 206 207 fooy: 208 /* 209 * Something goofed, free stuff and barf 210 */ 211 mem_free((caddr_t)ct, sizeof (struct ct_data)); 212 mem_free((caddr_t)h, sizeof (CLIENT)); 213 return (NULL); 214 } 215 216 static enum clnt_stat 217 clnttcp_call(CLIENT *h, rpcproc_t proc, xdrproc_t xdr_args, caddr_t args_ptr, 218 xdrproc_t xdr_results, caddr_t results_ptr, struct timeval timeout) 219 { 220 struct ct_data *ct; 221 XDR *xdrs; 222 struct rpc_msg reply_msg; 223 uint32_t x_id; 224 uint32_t *msg_x_id; 225 bool_t shipnow; 226 int refreshes; 227 228 ct = (struct ct_data *)h->cl_private; 229 xdrs = &(ct->ct_xdrs); 230 msg_x_id = (uint32_t *)(ct->ct_mcall); /* yuk */ 231 refreshes = 2; 232 233 if (!ct->ct_waitset) { 234 ct->ct_wait = timeout; 235 } 236 237 shipnow = 238 (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0 && 239 timeout.tv_usec == 0) ? FALSE : TRUE; 240 241 call_again: 242 xdrs->x_op = XDR_ENCODE; 243 ct->ct_error.re_status = RPC_SUCCESS; 244 x_id = ntohl(--(*msg_x_id)); 245 if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) || 246 (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || 247 (! AUTH_MARSHALL(h->cl_auth, xdrs)) || 248 (! (*xdr_args)(xdrs, args_ptr))) { 249 if (ct->ct_error.re_status == RPC_SUCCESS) 250 ct->ct_error.re_status = RPC_CANTENCODEARGS; 251 (void) xdrrec_endofrecord(xdrs, TRUE); 252 return (ct->ct_error.re_status); 253 } 254 if (! xdrrec_endofrecord(xdrs, shipnow)) 255 return (ct->ct_error.re_status = RPC_CANTSEND); 256 if (! shipnow) 257 return (RPC_SUCCESS); 258 /* 259 * Hack to provide rpc-based message passing 260 */ 261 if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 262 return (ct->ct_error.re_status = RPC_TIMEDOUT); 263 } 264 265 266 /* 267 * Keep receiving until we get a valid transaction id 268 */ 269 xdrs->x_op = XDR_DECODE; 270 while (TRUE) { 271 reply_msg.acpted_rply.ar_verf = _null_auth; 272 reply_msg.acpted_rply.ar_results.where = NULL; 273 reply_msg.acpted_rply.ar_results.proc = xdr_void; 274 if (! xdrrec_skiprecord(xdrs)) 275 return (ct->ct_error.re_status); 276 /* now decode and validate the response header */ 277 if (! xdr_replymsg(xdrs, &reply_msg)) { 278 if (ct->ct_error.re_status == RPC_SUCCESS) 279 continue; 280 return (ct->ct_error.re_status); 281 } 282 if (reply_msg.rm_xid == x_id) 283 break; 284 } 285 286 /* 287 * process header 288 */ 289 __seterr_reply(&reply_msg, &(ct->ct_error)); 290 if (ct->ct_error.re_status == RPC_SUCCESS) { 291 if (! AUTH_VALIDATE(h->cl_auth, 292 &reply_msg.acpted_rply.ar_verf)) { 293 ct->ct_error.re_status = RPC_AUTHERROR; 294 ct->ct_error.re_why = AUTH_INVALIDRESP; 295 } else if (! (*xdr_results)(xdrs, results_ptr)) { 296 if (ct->ct_error.re_status == RPC_SUCCESS) 297 ct->ct_error.re_status = RPC_CANTDECODERES; 298 } 299 /* free verifier ... */ 300 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 301 xdrs->x_op = XDR_FREE; 302 (void) xdr_opaque_auth(xdrs, 303 &(reply_msg.acpted_rply.ar_verf)); 304 } 305 } /* end successful completion */ 306 else { 307 /* maybe our credentials need to be refreshed ... */ 308 if (refreshes-- && AUTH_REFRESH(h->cl_auth, &reply_msg)) 309 goto call_again; 310 } /* end of unsuccessful completion */ 311 return (ct->ct_error.re_status); 312 } 313 314 static void 315 clnttcp_geterr(CLIENT *h, struct rpc_err *errp) 316 { 317 struct ct_data *ct; 318 319 ct = (struct ct_data *)h->cl_private; 320 *errp = ct->ct_error; 321 } 322 323 static bool_t 324 clnttcp_freeres(CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr) 325 { 326 struct ct_data *ct; 327 XDR *xdrs; 328 329 ct = (struct ct_data *)cl->cl_private; 330 xdrs = &(ct->ct_xdrs); 331 xdrs->x_op = XDR_FREE; 332 return ((*xdr_res)(xdrs, res_ptr)); 333 } 334 335 static void 336 clnttcp_abort(void) 337 { 338 } 339 340 static bool_t 341 clnttcp_control(CLIENT *cl, int request, char *info) 342 { 343 struct ct_data *ct; 344 345 ct = (struct ct_data *)cl->cl_private; 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 case CLGET_FD: 358 *(int *)info = ct->ct_sock; 359 break; 360 case CLSET_FD_CLOSE: 361 ct->ct_closeit = TRUE; 362 break; 363 case CLSET_FD_NCLOSE: 364 ct->ct_closeit = FALSE; 365 break; 366 default: 367 return (FALSE); 368 } 369 return (TRUE); 370 } 371 372 373 static void 374 clnttcp_destroy(CLIENT *h) 375 { 376 struct ct_data *ct; 377 378 ct = (struct ct_data *)h->cl_private; 379 if (ct->ct_closeit) { 380 (void) close(ct->ct_sock); 381 } 382 XDR_DESTROY(&(ct->ct_xdrs)); 383 mem_free((caddr_t)ct, sizeof (struct ct_data)); 384 mem_free((caddr_t)h, sizeof (CLIENT)); 385 } 386 387 /* 388 * Interface between xdr serializer and tcp connection. 389 * Behaves like the system calls, read & write, but keeps some error state 390 * around for the rpc level. 391 */ 392 static int 393 readtcp(void *data, caddr_t buf, int len) 394 { 395 fd_set mask; 396 fd_set readfds; 397 struct ct_data *ct; 398 399 if (len == 0) 400 return (0); 401 402 ct = data; 403 FD_ZERO(&mask); 404 FD_SET(ct->ct_sock, &mask); 405 while (TRUE) { 406 readfds = mask; 407 switch (select(__rpc_dtbsize(), 408 &readfds, NULL, NULL, &(ct->ct_wait))) { 409 case 0: 410 ct->ct_error.re_status = RPC_TIMEDOUT; 411 return (-1); 412 413 case -1: 414 if (errno == EINTR) 415 continue; 416 ct->ct_error.re_status = RPC_CANTRECV; 417 ct->ct_error.re_errno = errno; 418 return (-1); 419 } 420 break; 421 } 422 switch (len = read(ct->ct_sock, buf, len)) { 423 424 case 0: 425 /* premature eof */ 426 ct->ct_error.re_errno = ECONNRESET; 427 ct->ct_error.re_status = RPC_CANTRECV; 428 len = -1; /* it's really an error */ 429 break; 430 431 case -1: 432 ct->ct_error.re_errno = errno; 433 ct->ct_error.re_status = RPC_CANTRECV; 434 break; 435 } 436 return (len); 437 } 438 439 static int 440 writetcp(void *data, caddr_t buf, int len) 441 { 442 struct ct_data *ct; 443 int i, cnt; 444 445 ct = data; 446 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 447 if ((i = write(ct->ct_sock, buf, cnt)) == -1) { 448 ct->ct_error.re_errno = errno; 449 ct->ct_error.re_status = RPC_CANTSEND; 450 return (-1); 451 } 452 } 453 return (len); 454 } 455 456 static struct clnt_ops * 457 clnttcp_ops(void) 458 { 459 static struct clnt_ops ops; 460 461 if (ops.cl_call == NULL) { 462 ops.cl_call = clnttcp_call; 463 ops.cl_abort = clnttcp_abort; 464 ops.cl_geterr = clnttcp_geterr; 465 ops.cl_freeres = clnttcp_freeres; 466 ops.cl_destroy = clnttcp_destroy; 467 ops.cl_control = clnttcp_control; 468 } 469 return (&ops); 470 } 471