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