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 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 /* 43 * svc_tcp.c, Server side for TCP/IP based RPC. 44 * 45 * Actually implements two flavors of transporter - 46 * a tcp rendezvouser (a listner and connection establisher) 47 * and a record/tcp stream. 48 */ 49 50 #include <rpc/rpc.h> 51 #include <sys/socket.h> 52 #include <sys/time.h> 53 #include <errno.h> 54 #include <syslog.h> 55 #include <malloc.h> 56 #include <stdio.h> 57 58 extern bool_t abort(); 59 extern int errno; 60 extern SVCXPRT *svc_xprt_alloc(); 61 extern void svc_xprt_free(); 62 extern int _socket(int, int, int); 63 extern int _bind(int, const struct sockaddr *, int); 64 extern int _getsockname(int, struct sockaddr *, int *); 65 extern int _listen(int, int); 66 extern int _accept(int, struct sockaddr *, int *); 67 extern int bindresvport(int, struct sockaddr_in *); 68 69 static struct xp_ops *svctcp_ops(); 70 static struct xp_ops *svctcp_rendezvous_ops(); 71 72 static int readtcp(), writetcp(); 73 static SVCXPRT *makefd_xprt(); 74 75 struct tcp_rendezvous { /* kept in xprt->xp_p1 */ 76 u_int sendsize; 77 u_int recvsize; 78 }; 79 80 struct tcp_conn { /* kept in xprt->xp_p1 */ 81 enum xprt_stat strm_stat; 82 uint32_t x_id; 83 XDR xdrs; 84 char verf_body[MAX_AUTH_BYTES]; 85 }; 86 87 /* 88 * Usage: 89 * xprt = svctcp_create(sock, send_buf_size, recv_buf_size); 90 * 91 * Creates, registers, and returns a (rpc) tcp based transporter. 92 * Once *xprt is initialized, it is registered as a transporter 93 * see (svc.h, xprt_register). This routine returns 94 * a NULL if a problem occurred. 95 * 96 * If sock<0 then a socket is created, else sock is used. 97 * If the socket, sock is not bound to a port then svctcp_create 98 * binds it to an arbitrary port. The routine then starts a tcp 99 * listener on the socket's associated port. In any (successful) case, 100 * xprt->xp_sock is the registered socket number and xprt->xp_port is the 101 * associated port number. 102 * 103 * Since tcp streams do buffered io similar to stdio, the caller can specify 104 * how big the send and receive buffers are via the second and third parms; 105 * 0 => use the system default. 106 */ 107 SVCXPRT * 108 svctcp_create(sock, sendsize, recvsize) 109 register int sock; 110 u_int sendsize; 111 u_int recvsize; 112 { 113 bool_t madesock = FALSE; 114 register SVCXPRT *xprt; 115 register struct tcp_rendezvous *r; 116 struct sockaddr_in addr; 117 int len = sizeof (struct sockaddr_in); 118 119 if (sock == RPC_ANYSOCK) { 120 if ((sock = _socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { 121 (void) syslog(LOG_ERR, "svctcp_create - tcp", 122 " socket creation problem: %m"); 123 return ((SVCXPRT *)NULL); 124 } 125 madesock = TRUE; 126 } 127 memset((char *)&addr, 0, sizeof (addr)); 128 addr.sin_family = AF_INET; 129 if (bindresvport(sock, &addr)) { 130 addr.sin_port = 0; 131 (void) _bind(sock, (struct sockaddr *)&addr, len); 132 } 133 if ((_getsockname(sock, (struct sockaddr *)&addr, &len) != 0) || 134 (_listen(sock, 2) != 0)) { 135 (void) syslog(LOG_ERR, "svctcp_create - cannot", 136 " getsockname or listen: %m"); 137 if (madesock) 138 (void) close(sock); 139 return ((SVCXPRT *)NULL); 140 } 141 r = (struct tcp_rendezvous *)mem_alloc(sizeof (*r)); 142 if (r == NULL) { 143 (void) syslog(LOG_ERR, "svctcp_create: out of memory"); 144 if (madesock) 145 (void) close(sock); 146 return (NULL); 147 } 148 r->sendsize = sendsize; 149 r->recvsize = recvsize; 150 xprt = svc_xprt_alloc(); 151 if (xprt == NULL) { 152 (void) syslog(LOG_ERR, "svctcp_create: out of memory"); 153 mem_free((char *) r, sizeof (*r)); 154 if (madesock) 155 (void) close(sock); 156 return (NULL); 157 } 158 xprt->xp_p2 = NULL; 159 xprt->xp_netid = NULL; 160 xprt->xp_p1 = (caddr_t)r; 161 xprt->xp_verf = _null_auth; 162 xprt->xp_ops = svctcp_rendezvous_ops(); 163 xprt->xp_port = ntohs(addr.sin_port); 164 xprt->xp_sock = sock; 165 xprt->xp_rtaddr.buf = xprt->xp_raddr; 166 xprt_register(xprt); 167 return (xprt); 168 } 169 170 /* 171 * Like svtcp_create(), except the routine takes any *open* UNIX file 172 * descriptor as its first input. 173 */ 174 SVCXPRT * 175 svcfd_create(fd, sendsize, recvsize) 176 int fd; 177 u_int sendsize; 178 u_int recvsize; 179 { 180 181 return (makefd_xprt(fd, sendsize, recvsize)); 182 } 183 184 static SVCXPRT * 185 makefd_xprt(fd, sendsize, recvsize) 186 int fd; 187 u_int sendsize; 188 u_int recvsize; 189 { 190 register SVCXPRT *xprt; 191 register struct tcp_conn *cd; 192 193 xprt = svc_xprt_alloc(); 194 if (xprt == (SVCXPRT *)NULL) { 195 (void) syslog(LOG_ERR, "svc_tcp: makefd_xprt: out of memory"); 196 goto done; 197 } 198 cd = (struct tcp_conn *)mem_alloc(sizeof (struct tcp_conn)); 199 if (cd == (struct tcp_conn *)NULL) { 200 (void) syslog(LOG_ERR, "svc_tcp: makefd_xprt: out of memory"); 201 svc_xprt_free(xprt); 202 xprt = (SVCXPRT *)NULL; 203 goto done; 204 } 205 cd->strm_stat = XPRT_IDLE; 206 xdrrec_create(&(cd->xdrs), sendsize, recvsize, 207 (caddr_t)xprt, readtcp, writetcp); 208 xprt->xp_p2 = NULL; 209 xprt->xp_netid = NULL; 210 xprt->xp_p1 = (caddr_t)cd; 211 xprt->xp_verf.oa_base = cd->verf_body; 212 xprt->xp_addrlen = 0; 213 xprt->xp_ops = svctcp_ops(); /* truely deals with calls */ 214 xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ 215 xprt->xp_sock = fd; 216 /* to handle svc_getcaller() properly */ 217 xprt->xp_rtaddr.buf = xprt->xp_raddr; 218 xprt_register(xprt); 219 done: 220 return (xprt); 221 } 222 223 static bool_t 224 rendezvous_request(xprt, rpc_msg) 225 register SVCXPRT *xprt; 226 struct rpc_msg *rpc_msg; 227 { 228 int sock; 229 struct tcp_rendezvous *r; 230 struct sockaddr_in addr; 231 int len; 232 233 r = (struct tcp_rendezvous *)xprt->xp_p1; 234 again: 235 len = sizeof (struct sockaddr_in); 236 if ((sock = _accept(xprt->xp_sock, (struct sockaddr *)&addr, 237 &len)) < 0) { 238 if (errno == EINTR) 239 goto again; 240 return (FALSE); 241 } 242 /* 243 * make a new transporter (re-uses xprt) 244 */ 245 xprt = makefd_xprt(sock, r->sendsize, r->recvsize); 246 247 memcpy((char *)&xprt->xp_raddr, (char *)&addr, len); 248 xprt->xp_addrlen = len; 249 return (FALSE); /* there is never an rpc msg to be processed */ 250 } 251 252 static enum xprt_stat 253 rendezvous_stat(xprt) 254 SVCXPRT *xprt; 255 { 256 257 return (XPRT_IDLE); 258 } 259 260 static void 261 svctcp_destroy(xprt) 262 register SVCXPRT *xprt; 263 { 264 register struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1; 265 266 xprt_unregister(xprt); 267 (void) close(xprt->xp_sock); 268 if (xprt->xp_port != 0) { 269 /* a rendezvouser socket */ 270 xprt->xp_port = 0; 271 } else { 272 /* an actual connection socket */ 273 XDR_DESTROY(&(cd->xdrs)); 274 } 275 mem_free((caddr_t)cd, sizeof (struct tcp_conn)); 276 svc_xprt_free(xprt); 277 } 278 279 /* 280 * All read operations timeout after 35 seconds. 281 * A timeout is fatal for the connection. 282 */ 283 static struct timeval wait_per_try = { 35, 0 }; 284 285 /* 286 * reads data from the tcp conection. 287 * any error is fatal and the connection is closed. 288 * (And a read of zero bytes is a half closed stream => error.) 289 */ 290 static int 291 readtcp(xprt, buf, len) 292 register SVCXPRT *xprt; 293 caddr_t buf; 294 register int len; 295 { 296 register int sock = xprt->xp_sock; 297 fd_set mask; 298 fd_set readfds; 299 300 FD_ZERO(&mask); 301 FD_SET(sock, &mask); 302 do { 303 readfds = mask; 304 if (select(__rpc_dtbsize(), &readfds, NULL, NULL, 305 &wait_per_try) <= 0) { 306 if (errno == EINTR) { 307 continue; 308 } 309 goto fatal_err; 310 } 311 } while (!FD_ISSET(sock, &readfds)); 312 if ((len = read(sock, buf, len)) > 0) { 313 return (len); 314 } 315 fatal_err: 316 ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; 317 return (-1); 318 } 319 320 /* 321 * writes data to the tcp connection. 322 * Any error is fatal and the connection is closed. 323 */ 324 static int 325 writetcp(xprt, buf, len) 326 register SVCXPRT *xprt; 327 caddr_t buf; 328 int len; 329 { 330 register int i, cnt; 331 332 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 333 if ((i = write(xprt->xp_sock, buf, cnt)) < 0) { 334 ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = 335 XPRT_DIED; 336 return (-1); 337 } 338 } 339 return (len); 340 } 341 342 static enum xprt_stat 343 svctcp_stat(xprt) 344 SVCXPRT *xprt; 345 { 346 register struct tcp_conn *cd = 347 (struct tcp_conn *)(xprt->xp_p1); 348 349 if (cd->strm_stat == XPRT_DIED) 350 return (XPRT_DIED); 351 if (! xdrrec_eof(&(cd->xdrs))) 352 return (XPRT_MOREREQS); 353 return (XPRT_IDLE); 354 } 355 356 static bool_t 357 svctcp_recv(xprt, msg) 358 SVCXPRT *xprt; 359 register struct rpc_msg *msg; 360 { 361 register struct tcp_conn *cd = 362 (struct tcp_conn *)(xprt->xp_p1); 363 register XDR *xdrs = &(cd->xdrs); 364 365 xdrs->x_op = XDR_DECODE; 366 (void) xdrrec_skiprecord(xdrs); 367 if (xdr_callmsg(xdrs, msg)) { 368 cd->x_id = msg->rm_xid; 369 return (TRUE); 370 } 371 return (FALSE); 372 } 373 374 static bool_t 375 svctcp_getargs(xprt, xdr_args, args_ptr) 376 SVCXPRT *xprt; 377 xdrproc_t xdr_args; 378 caddr_t args_ptr; 379 { 380 381 return ((*xdr_args)(&(((struct tcp_conn *)(xprt->xp_p1))->xdrs), 382 args_ptr)); 383 } 384 385 static bool_t 386 svctcp_freeargs(xprt, xdr_args, args_ptr) 387 SVCXPRT *xprt; 388 xdrproc_t xdr_args; 389 caddr_t args_ptr; 390 { 391 register XDR *xdrs = 392 &(((struct tcp_conn *)(xprt->xp_p1))->xdrs); 393 394 xdrs->x_op = XDR_FREE; 395 return ((*xdr_args)(xdrs, args_ptr)); 396 } 397 398 static bool_t 399 svctcp_reply(xprt, msg) 400 SVCXPRT *xprt; 401 register struct rpc_msg *msg; 402 { 403 register struct tcp_conn *cd = 404 (struct tcp_conn *)(xprt->xp_p1); 405 register XDR *xdrs = &(cd->xdrs); 406 register bool_t stat; 407 408 xdrs->x_op = XDR_ENCODE; 409 msg->rm_xid = cd->x_id; 410 stat = xdr_replymsg(xdrs, msg); 411 (void) xdrrec_endofrecord(xdrs, TRUE); 412 return (stat); 413 } 414 415 416 static struct xp_ops * 417 svctcp_ops() 418 { 419 static struct xp_ops ops; 420 421 if (ops.xp_recv == NULL) { 422 ops.xp_recv = svctcp_recv; 423 ops.xp_stat = svctcp_stat; 424 ops.xp_getargs = svctcp_getargs; 425 ops.xp_reply = svctcp_reply; 426 ops.xp_freeargs = svctcp_freeargs; 427 ops.xp_destroy = svctcp_destroy; 428 } 429 return (&ops); 430 } 431 432 433 static struct xp_ops * 434 svctcp_rendezvous_ops() 435 { 436 static struct xp_ops ops; 437 438 if (ops.xp_recv == NULL) { 439 ops.xp_recv = rendezvous_request; 440 ops.xp_stat = rendezvous_stat; 441 ops.xp_getargs = abort; 442 ops.xp_reply = abort; 443 ops.xp_freeargs = abort, 444 ops.xp_destroy = svctcp_destroy; 445 } 446 return (&ops); 447 } 448