home *** CD-ROM | disk | FTP | other *** search
/ Serving the Web / ServingTheWeb1995.disc1of1.iso / linux / slacksrce / d / libc / libc-4.6 / libc-4 / libc-linux / rpc / svc_tcp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-01  |  11.6 KB  |  485 lines

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