home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume13 / rpc3.9 / part04 / svc_tcp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-02-27  |  10.0 KB  |  421 lines

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