1/* 2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights 7 * Reserved. This file contains Original Code and/or Modifications of 8 * Original Code as defined in and that are subject to the Apple Public 9 * Source License Version 1.1 (the "License"). You may not use this file 10 * except in compliance with the License. Please obtain a copy of the 11 * License at http://www.apple.com/publicsource and read it before using 12 * this file. 13 * 14 * The Original Code and all software distributed under the License are 15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the 19 * License for the specific language governing rights and limitations 20 * under the License. 21 * 22 * @APPLE_LICENSE_HEADER_END@ 23 */ 24/* 25 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 26 * unrestricted use provided that this legend is included on all tape 27 * media and as a part of the software program in whole or part. Users 28 * may copy or modify Sun RPC without charge, but are not authorized 29 * to license or distribute it to anyone else except as part of a product or 30 * program developed by the user. 31 * 32 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 33 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 34 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 35 * 36 * Sun RPC is provided with no support and without any obligation on the 37 * part of Sun Microsystems, Inc. to assist in its use, correction, 38 * modification or enhancement. 39 * 40 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 41 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 42 * OR ANY PART THEREOF. 43 * 44 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 45 * or profits or other special, indirect and consequential damages, even if 46 * Sun has been advised of the possibility of such damages. 47 * 48 * Sun Microsystems, Inc. 49 * 2550 Garcia Avenue 50 * Mountain View, California 94043 51 */ 52 53#if defined(LIBC_SCCS) && !defined(lint) 54/*static char *sccsid = "from: @(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";*/ 55/*static char *sccsid = "from: @(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC";*/ 56static char *rcsid = "$Id: svc_tcp.c,v 1.6 2004/06/11 16:28:07 majka Exp $"; 57#endif 58 59/* 60 * svc_tcp.c, Server side for TCP/IP based RPC. 61 * 62 * Copyright (C) 1984, Sun Microsystems, Inc. 63 * 64 * Actually implements two flavors of transporter - 65 * a tcp rendezvouser (a listner and connection establisher) 66 * and a record/tcp stream. 67 */ 68 69#include <stdio.h> 70#include <stdlib.h> 71#include <string.h> 72#include <unistd.h> 73#include <rpc/rpc.h> 74#include <sys/socket.h> 75#include <errno.h> 76 77#define max(a, b) (((a) > (b)) ? (a) : (b)) 78 79extern int bindresvport(); 80 81/* 82 * Ops vector for TCP/IP based rpc service handle 83 */ 84static bool_t svctcp_recv(); 85static enum xprt_stat svctcp_stat(); 86static bool_t svctcp_getargs(); 87static bool_t svctcp_reply(); 88static bool_t svctcp_freeargs(); 89static void svctcp_destroy(); 90 91static struct xp_ops svctcp_op = { 92 svctcp_recv, 93 svctcp_stat, 94 svctcp_getargs, 95 svctcp_reply, 96 svctcp_freeargs, 97 svctcp_destroy 98}; 99 100/* 101 * Ops vector for TCP/IP rendezvous handler 102 */ 103static bool_t rendezvous_abort(); 104static bool_t rendezvous_request(); 105static enum xprt_stat rendezvous_stat(); 106 107static struct xp_ops svctcp_rendezvous_op = { 108 rendezvous_request, 109 rendezvous_stat, 110 rendezvous_abort, 111 rendezvous_abort, 112 rendezvous_abort, 113 svctcp_destroy 114}; 115 116static int readtcp(), writetcp(); 117static SVCXPRT *makefd_xprt(); 118 119struct tcp_rendezvous { /* kept in xprt->xp_p1 */ 120 u_int sendsize; 121 u_int recvsize; 122}; 123 124struct tcp_conn { /* kept in xprt->xp_p1 */ 125 enum xprt_stat strm_stat; 126#ifdef __LP64__ 127 uint32_t x_id; 128#else 129 u_long x_id; 130#endif 131 XDR xdrs; 132 char verf_body[MAX_AUTH_BYTES]; 133}; 134 135/* 136 * Usage: 137 * xprt = svctcp_create(sock, send_buf_size, recv_buf_size); 138 * 139 * Creates, registers, and returns a (rpc) tcp based transporter. 140 * Once *xprt is initialized, it is registered as a transporter 141 * see (svc.h, xprt_register). This routine returns 142 * a NULL if a problem occurred. 143 * 144 * If sock<0 then a socket is created, else sock is used. 145 * If the socket, sock is not bound to a port then svctcp_create 146 * binds it to an arbitrary port. The routine then starts a tcp 147 * listener on the socket's associated port. In any (successful) case, 148 * xprt->xp_sock is the registered socket number and xprt->xp_port is the 149 * associated port number. 150 * 151 * Since tcp streams do buffered io similar to stdio, the caller can specify 152 * how big the send and receive buffers are via the second and third parms; 153 * 0 => use the system default. 154 */ 155SVCXPRT * 156svctcp_create(sock, sendsize, recvsize) 157 register int sock; 158 u_int sendsize; 159 u_int recvsize; 160{ 161 bool_t madesock = FALSE; 162 register SVCXPRT *xprt; 163 register struct tcp_rendezvous *r; 164 struct sockaddr_in addr; 165 unsigned int len = sizeof(struct sockaddr_in); 166 167 if (sock == RPC_ANYSOCK) { 168 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { 169 perror("svctcp_.c - udp socket creation problem"); 170 return ((SVCXPRT *)NULL); 171 } 172 madesock = TRUE; 173 } 174 bzero((char *)&addr, sizeof (addr)); 175 addr.sin_family = AF_INET; 176 if (bindresvport(sock, &addr)) { 177 addr.sin_port = 0; 178 (void)bind(sock, (struct sockaddr *)&addr, len); 179 } 180 if ((getsockname(sock, (struct sockaddr *)&addr, &len) != 0) || 181 (listen(sock, 2) != 0)) { 182 perror("svctcp_.c - cannot getsockname or listen"); 183 if (madesock) 184 (void)close(sock); 185 return ((SVCXPRT *)NULL); 186 } 187 r = (struct tcp_rendezvous *)mem_alloc(sizeof(*r)); 188 if (r == NULL) { 189 (void) fprintf(stderr, "svctcp_create: out of memory\n"); 190 return (NULL); 191 } 192 r->sendsize = sendsize; 193 r->recvsize = recvsize; 194 xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); 195 if (xprt == NULL) { 196 (void) fprintf(stderr, "svctcp_create: out of memory\n"); 197 return (NULL); 198 } 199 xprt->xp_p2 = NULL; 200 xprt->xp_p1 = (caddr_t)r; 201 xprt->xp_verf = _null_auth; 202 xprt->xp_ops = &svctcp_rendezvous_op; 203 xprt->xp_port = ntohs(addr.sin_port); 204 xprt->xp_sock = sock; 205 xprt_register(xprt); 206 return (xprt); 207} 208 209/* 210 * Like svtcp_create(), except the routine takes any *open* UNIX file 211 * descriptor as its first input. 212 */ 213SVCXPRT * 214svcfd_create(fd, sendsize, recvsize) 215 int fd; 216 u_int sendsize; 217 u_int recvsize; 218{ 219 220 return (makefd_xprt(fd, sendsize, recvsize)); 221} 222 223static SVCXPRT * 224makefd_xprt(fd, sendsize, recvsize) 225 int fd; 226 u_int sendsize; 227 u_int recvsize; 228{ 229 register SVCXPRT *xprt; 230 register struct tcp_conn *cd; 231 232 xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); 233 if (xprt == (SVCXPRT *)NULL) { 234 (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n"); 235 goto done; 236 } 237 cd = (struct tcp_conn *)mem_alloc(sizeof(struct tcp_conn)); 238 if (cd == (struct tcp_conn *)NULL) { 239 (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n"); 240 mem_free((char *) xprt, sizeof(SVCXPRT)); 241 xprt = (SVCXPRT *)NULL; 242 goto done; 243 } 244 cd->strm_stat = XPRT_IDLE; 245 xdrrec_create(&(cd->xdrs), sendsize, recvsize, 246 (caddr_t)xprt, readtcp, writetcp); 247 xprt->xp_p2 = NULL; 248 xprt->xp_p1 = (caddr_t)cd; 249 xprt->xp_verf.oa_base = cd->verf_body; 250 xprt->xp_addrlen = 0; 251 xprt->xp_ops = &svctcp_op; /* truely deals with calls */ 252 xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ 253 xprt->xp_sock = fd; 254 xprt_register(xprt); 255 done: 256 return (xprt); 257} 258 259static bool_t 260rendezvous_abort() 261{ 262 abort(); 263 return (FALSE); 264} 265 266static bool_t 267rendezvous_request(xprt) 268 register SVCXPRT *xprt; 269{ 270 int sock; 271 struct tcp_rendezvous *r; 272 struct sockaddr_in addr; 273 unsigned int len; 274 275 r = (struct tcp_rendezvous *)xprt->xp_p1; 276 again: 277 len = sizeof(struct sockaddr_in); 278 if ((sock = accept(xprt->xp_sock, (struct sockaddr *)&addr, &len)) < 0) { 279 if (errno == EINTR) 280 goto again; 281 return (FALSE); 282 } 283 /* 284 * make a new transporter (re-uses xprt) 285 */ 286 xprt = makefd_xprt(sock, r->sendsize, r->recvsize); 287 xprt->xp_raddr = addr; 288 xprt->xp_addrlen = len; 289 return (FALSE); /* there is never an rpc msg to be processed */ 290} 291 292static enum xprt_stat 293rendezvous_stat() 294{ 295 296 return (XPRT_IDLE); 297} 298 299static void 300svctcp_destroy(xprt) 301 register SVCXPRT *xprt; 302{ 303 register struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1; 304 305 xprt_unregister(xprt); 306 (void)close(xprt->xp_sock); 307 if (xprt->xp_port != 0) { 308 /* a rendezvouser socket */ 309 xprt->xp_port = 0; 310 } else { 311 /* an actual connection socket */ 312 XDR_DESTROY(&(cd->xdrs)); 313 } 314 mem_free((caddr_t)cd, sizeof(struct tcp_conn)); 315 mem_free((caddr_t)xprt, sizeof(SVCXPRT)); 316} 317 318/* 319 * All read operations timeout after 35 seconds. 320 * A timeout is fatal for the connection. 321 */ 322static struct timeval wait_per_try = { 35, 0 }; 323 324extern int svc_maxfd; 325 326/* 327 * reads data from the tcp conection. 328 * any error is fatal and the connection is closed. 329 * (And a read of zero bytes is a half closed stream => error.) 330 */ 331static int 332readtcp(xprt, buf, len) 333 register SVCXPRT *xprt; 334 caddr_t buf; 335 register int len; 336{ 337 register int sock = xprt->xp_sock; 338 fd_set readfds; 339 bool_t ready = FALSE; 340 341 do 342 { 343 FD_COPY(&svc_fdset, &readfds); 344 FD_SET(sock, &readfds); 345 if (select(max(svc_maxfd, sock) + 1, &readfds, NULL, NULL, &wait_per_try) <= 0) 346 { 347 if (errno == EINTR) continue; 348 goto fatal_err; 349 } 350 else if (FD_ISSET(sock, &readfds)) 351 { 352 ready = TRUE; 353 } 354 } while (!ready); 355 356 if ((len = read(sock, buf, len)) > 0) return len; 357 358fatal_err: 359 ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; 360 return -1; 361} 362 363/* 364 * writes data to the tcp connection. 365 * Any error is fatal and the connection is closed. 366 */ 367static int 368writetcp(xprt, buf, len) 369 register SVCXPRT *xprt; 370 caddr_t buf; 371 int len; 372{ 373 register int i, cnt; 374 375 for (cnt = len; cnt > 0; cnt -= i, buf += i) { 376 if ((i = write(xprt->xp_sock, buf, cnt)) < 0) { 377 ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = 378 XPRT_DIED; 379 return (-1); 380 } 381 } 382 return (len); 383} 384 385static enum xprt_stat 386svctcp_stat(xprt) 387 SVCXPRT *xprt; 388{ 389 register struct tcp_conn *cd = 390 (struct tcp_conn *)(xprt->xp_p1); 391 392 if (cd->strm_stat == XPRT_DIED) 393 return (XPRT_DIED); 394 if (! xdrrec_eof(&(cd->xdrs))) 395 return (XPRT_MOREREQS); 396 return (XPRT_IDLE); 397} 398 399static bool_t 400svctcp_recv(xprt, msg) 401 SVCXPRT *xprt; 402 register struct rpc_msg *msg; 403{ 404 register struct tcp_conn *cd = 405 (struct tcp_conn *)(xprt->xp_p1); 406 register XDR *xdrs = &(cd->xdrs); 407 408 xdrs->x_op = XDR_DECODE; 409 (void)xdrrec_skiprecord(xdrs); 410 if (xdr_callmsg(xdrs, msg)) { 411 cd->x_id = msg->rm_xid; 412 return (TRUE); 413 } 414 return (FALSE); 415} 416 417static bool_t 418svctcp_getargs(xprt, xdr_args, args_ptr) 419 SVCXPRT *xprt; 420 xdrproc_t xdr_args; 421 caddr_t args_ptr; 422{ 423 424 return ((*xdr_args)(&(((struct tcp_conn *)(xprt->xp_p1))->xdrs), args_ptr, 0)); 425} 426 427static bool_t 428svctcp_freeargs(xprt, xdr_args, args_ptr) 429 SVCXPRT *xprt; 430 xdrproc_t xdr_args; 431 caddr_t args_ptr; 432{ 433 register XDR *xdrs = 434 &(((struct tcp_conn *)(xprt->xp_p1))->xdrs); 435 436 xdrs->x_op = XDR_FREE; 437 return ((*xdr_args)(xdrs, args_ptr, 0)); 438} 439 440static bool_t 441svctcp_reply(xprt, msg) 442 SVCXPRT *xprt; 443 register struct rpc_msg *msg; 444{ 445 register struct tcp_conn *cd = 446 (struct tcp_conn *)(xprt->xp_p1); 447 register XDR *xdrs = &(cd->xdrs); 448 register bool_t stat; 449 450 xdrs->x_op = XDR_ENCODE; 451 msg->rm_xid = cd->x_id; 452 stat = xdr_replymsg(xdrs, msg); 453 (void)xdrrec_endofrecord(xdrs, TRUE); 454 return (stat); 455} 456