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