home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 3 / goldfish_volume_3.bin / files / comm / tcp / amitcp-sdk / src / rpclib / svc_tcp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-29  |  9.9 KB  |  410 lines

  1. /*
  2.  *      $Id: svc_tcp.c,v 4.2 1994/09/29 23:48:50 jraja Exp $
  3.  *
  4.  *      Server side for TCP/IP based RPC. 
  5.  *
  6.  *      Copyright © 1994 AmiTCP/IP Group,
  7.  *                       Network Solutions Development Inc.
  8.  *                       All rights reserved. 
  9.  */
  10.  
  11. /* @(#)svc_tcp.c    2.2 88/08/01 4.0 RPCSRC */
  12. #if !defined(lint) && defined(SCCSIDS)
  13. static char sccsid[] = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
  14. #endif
  15.  
  16. /*
  17.  * Copyright (C) 1984, Sun Microsystems, Inc.
  18.  *
  19.  * Actually implements two flavors of transporter -
  20.  * a tcp rendezvouser (a listner and connection establisher)
  21.  * and a record/tcp stream.
  22.  */
  23.  
  24. #include <sys/param.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <rpc/rpc.h>
  28. #include <sys/socket.h>
  29. #include <errno.h>
  30.  
  31. /*
  32.  * Ops vector for TCP/IP based rpc service handle
  33.  */
  34. static bool_t        svctcp_recv(SVCXPRT *xprt, struct rpc_msg *msg);
  35. static enum xprt_stat    svctcp_stat(SVCXPRT *xprt);
  36. static bool_t        svctcp_getargs(SVCXPRT *xprt, xdrproc_t xdr_args,
  37.                        void *args_ptr);
  38. static bool_t        svctcp_reply(SVCXPRT *xprt, struct rpc_msg *msg);
  39. static bool_t        svctcp_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args,
  40.                     void *args_ptr);
  41. static void        svctcp_destroy(SVCXPRT *xprt);
  42.  
  43. static struct xp_ops svctcp_op = {
  44.     svctcp_recv,
  45.     svctcp_stat,
  46.     svctcp_getargs,
  47.     svctcp_reply,
  48.     svctcp_freeargs,
  49.     svctcp_destroy
  50. };
  51.  
  52. /*
  53.  * Ops vector for TCP/IP rendezvous handler
  54.  */
  55. static bool_t        rendezvous_request(SVCXPRT *xprt, 
  56.                        struct rpc_msg *notused);
  57. static bool_t        rendezvous_illegal(SVCXPRT *xprt);
  58.  
  59. static enum xprt_stat    rendezvous_stat(SVCXPRT *xprt);
  60.  
  61. static struct xp_ops svctcp_rendezvous_op = {
  62.     rendezvous_request,
  63.     rendezvous_stat,
  64.     (int(*)(SVCXPRT *, xdrproc_t, void *))rendezvous_illegal,
  65.     (int(*)(SVCXPRT *, struct rpc_msg *))rendezvous_illegal,
  66.     (int(*)(SVCXPRT *, xdrproc_t, void *))rendezvous_illegal,
  67.     svctcp_destroy
  68. };
  69.  
  70. static int readtcp(SVCXPRT *xprt, caddr_t buf, int len), 
  71.   writetcp(SVCXPRT *xprt, caddr_t buf, int len);
  72. static SVCXPRT *makefd_xprt(int fd, u_int sendsize, u_int recvsize);
  73.  
  74. struct tcp_rendezvous { /* kept in xprt->xp_p1 */
  75.     u_int sendsize;
  76.     u_int recvsize;
  77. };
  78.  
  79. struct tcp_conn {  /* kept in xprt->xp_p1 */
  80.     enum xprt_stat strm_stat;
  81.     u_long x_id;
  82.     XDR xdrs;
  83.     char verf_body[MAX_AUTH_BYTES];
  84. };
  85.  
  86. /*
  87.  * Usage:
  88.  *    xprt = svctcp_create(sock, send_buf_size, recv_buf_size);
  89.  *
  90.  * Creates, registers, and returns a (rpc) tcp based transporter.
  91.  * Once *xprt is initialized, it is registered as a transporter
  92.  * see (svc.h, xprt_register).  This routine returns
  93.  * a NULL if a problem occurred.
  94.  *
  95.  * If sock<0 then a socket is created, else sock is used.
  96.  * If the socket, sock is not bound to a port then svctcp_create
  97.  * binds it to an arbitrary port.  The routine then starts a tcp
  98.  * listener on the socket's associated port.  In any (successful) case,
  99.  * xprt->xp_sock is the registered socket number and xprt->xp_port is the
  100.  * associated port number.
  101.  *
  102.  * Since tcp streams do buffered io similar to stdio, the caller can specify
  103.  * how big the send and receive buffers are via the second and third parms;
  104.  * 0 => use the system default.
  105.  */
  106. SVCXPRT *
  107. svctcp_create(sock, sendsize, recvsize)
  108.     register int sock;
  109.     u_int sendsize;
  110.     u_int recvsize;
  111. {
  112.     bool_t madesock = FALSE;
  113.     register SVCXPRT *xprt;
  114.     register struct tcp_rendezvous *r;
  115.     struct sockaddr_in addr;
  116. #ifdef AMITCP
  117.     long len = sizeof(struct sockaddr_in);
  118. #else
  119.     int len = sizeof(struct sockaddr_in);
  120. #endif
  121.     if (sock == RPC_ANYSOCK) {
  122.         if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
  123.             perror("svctcp_.c - udp socket creation problem");
  124.             return ((SVCXPRT *)NULL);
  125.         }
  126.         madesock = TRUE;
  127.     }
  128.     bzero((char *)&addr, sizeof (addr));
  129.     addr.sin_family = AF_INET;
  130.     if (bindresvport(sock, &addr)) {
  131.         addr.sin_port = 0;
  132.         (void)bind(sock, (struct sockaddr *)&addr, len);
  133.     }
  134.     if ((getsockname(sock, (struct sockaddr *)&addr, &len) != 0)  ||
  135.         (listen(sock, 2) != 0)) {
  136.         perror("svctcp_.c - cannot getsockname or listen");
  137.         if (madesock)
  138. #ifdef AMITCP
  139.                (void)CloseSocket(sock);
  140. #else
  141.                (void)close(sock);
  142. #endif
  143.         return ((SVCXPRT *)NULL);
  144.     }
  145.     r = (struct tcp_rendezvous *)mem_alloc(sizeof(*r));
  146.     if (r == NULL) {
  147.         (void) fprintf(stderr, "svctcp_create: out of memory\n");
  148.         return (NULL);
  149.     }
  150.     r->sendsize = sendsize;
  151.     r->recvsize = recvsize;
  152.     xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
  153.     if (xprt == NULL) {
  154.         (void) fprintf(stderr, "svctcp_create: out of memory\n");
  155.         return (NULL);
  156.     }
  157.     xprt->xp_p2 = NULL;
  158.     xprt->xp_p1 = (caddr_t)r;
  159.     xprt->xp_verf = _null_auth;
  160.     xprt->xp_ops = &svctcp_rendezvous_op;
  161.     xprt->xp_port = ntohs(addr.sin_port);
  162.     xprt->xp_sock = sock;
  163.     xprt_register(xprt);
  164.     return (xprt);
  165. }
  166.  
  167. #ifndef AMITCP
  168. /*
  169.  * Like svctcp_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. #endif
  182.  
  183. static SVCXPRT *
  184. makefd_xprt(int fd, u_int sendsize, u_int recvsize)
  185. {
  186.     register SVCXPRT *xprt;
  187.     register struct tcp_conn *cd;
  188.  
  189.     xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
  190.     if (xprt == (SVCXPRT *)NULL) {
  191.         (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n");
  192.         goto done;
  193.     }
  194.     cd = (struct tcp_conn *)mem_alloc(sizeof(struct tcp_conn));
  195.     if (cd == (struct tcp_conn *)NULL) {
  196.         (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n");
  197.         mem_free((char *) xprt, sizeof(SVCXPRT));
  198.         xprt = (SVCXPRT *)NULL;
  199.         goto done;
  200.     }
  201.     cd->strm_stat = XPRT_IDLE;
  202.     xdrrec_create(&(cd->xdrs), sendsize, recvsize,
  203.         xprt, readtcp, writetcp);
  204.     xprt->xp_p2 = NULL;
  205.     xprt->xp_p1 = (caddr_t)cd;
  206.     xprt->xp_verf.oa_base = cd->verf_body;
  207.     xprt->xp_addrlen = 0;
  208.     xprt->xp_ops = &svctcp_op;  /* truely deals with calls */
  209.     xprt->xp_port = 0;  /* this is a connection, not a rendezvouser */
  210.     xprt->xp_sock = fd;
  211.     xprt_register(xprt);
  212.     done:
  213.     return (xprt);
  214. }
  215.  
  216. static bool_t
  217. rendezvous_request(register SVCXPRT *xprt, struct rpc_msg *notused)
  218. {
  219.     int sock;
  220.     struct tcp_rendezvous *r;
  221.     struct sockaddr_in addr;
  222. #ifdef AMITCP
  223.     long len;
  224. #else
  225.     int len;
  226. #endif
  227.  
  228.     r = (struct tcp_rendezvous *)xprt->xp_p1;
  229.     again:
  230.     len = sizeof(struct sockaddr_in);
  231.     if ((sock = accept(xprt->xp_sock, (struct sockaddr *)&addr,
  232.         &len)) < 0) {
  233. #ifndef AMITCP /* EINTR is returned in case of a CTRL-C by default */
  234.         if (errno == EINTR)
  235.             goto again;
  236. #endif
  237.            return (FALSE);
  238.     }
  239.     /*
  240.      * make a new transporter (re-uses xprt)
  241.      */
  242.     xprt = makefd_xprt(sock, r->sendsize, r->recvsize);
  243.     xprt->xp_raddr = addr;
  244.     xprt->xp_addrlen = len;
  245.     return (FALSE); /* there is never an rpc msg to be processed */
  246. }
  247.  
  248. static enum xprt_stat
  249. rendezvous_stat(SVCXPRT *xprt)
  250. {
  251.     return (XPRT_IDLE);
  252. }
  253.  
  254. static bool_t
  255. rendezvous_illegal(SVCXPRT *xprt)
  256. {
  257.   fprintf(stderr, "svc_tcp.c: tcp xprt not connected yet!");
  258.   return FALSE;
  259. }
  260.  
  261. static void
  262. svctcp_destroy(register SVCXPRT *xprt)
  263. {
  264.     register struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1;
  265.  
  266.     xprt_unregister(xprt);
  267. #ifdef AMITCP
  268.     (void)CloseSocket(xprt->xp_sock);
  269. #else
  270.     (void)close(xprt->xp_sock);
  271. #endif
  272.     if (xprt->xp_port != 0) {
  273.         /* a rendezvouser socket */
  274.         xprt->xp_port = 0;
  275.     } else {
  276.         /* an actual connection socket */
  277.         XDR_DESTROY(&(cd->xdrs));
  278.     }
  279.     mem_free((caddr_t)cd, sizeof(struct tcp_conn));
  280.     mem_free((caddr_t)xprt, sizeof(SVCXPRT));
  281. }
  282.  
  283. /*
  284.  * All read operations timeout after 35 seconds.
  285.  * A timeout is fatal for the connection.
  286.  */
  287. static struct timeval wait_per_try = { 35, 0 };
  288.  
  289. /*
  290.  * reads data from the tcp conection.
  291.  * any error is fatal and the connection is closed.
  292.  * (And a read of zero bytes is a half closed stream => error.)
  293.  */
  294. static int
  295. readtcp(register SVCXPRT *xprt, caddr_t buf, register int len)
  296. {
  297.     register int sock = xprt->xp_sock;
  298. #ifdef FD_SETSIZE
  299.     fd_set mask;
  300.     fd_set readfds;
  301.  
  302.     FD_ZERO(&mask);
  303.     FD_SET(sock, &mask);
  304. #else
  305.     register int mask = 1 << sock;
  306.     int readfds;
  307. #endif /* def FD_SETSIZE */
  308.     do {
  309.         readfds = mask;
  310.         if (select(_rpc_dtablesize(), &readfds, NULL,
  311.                NULL, &wait_per_try) <= 0) {
  312. #ifndef AMITCP /* EINTR is returned in case of a CTRL-C by default */
  313.             if (errno == EINTR) {
  314.                 continue;
  315.             }
  316. #endif
  317.             goto fatal_err;
  318.         }
  319. #ifdef FD_SETSIZE
  320.     } while (!FD_ISSET(sock, &readfds));
  321. #else
  322.     } while (readfds != mask);
  323. #endif /* def FD_SETSIZE */
  324.     if ((len = recv(sock, buf, len, 0)) > 0) {
  325.         return (len);
  326.     }
  327. fatal_err:
  328.     ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
  329.     return (-1);
  330. }
  331.  
  332. /*
  333.  * writes data to the tcp connection.
  334.  * Any error is fatal and the connection is closed.
  335.  */
  336. static int
  337. writetcp(register SVCXPRT *xprt, caddr_t buf, int len)
  338. {
  339.     register int i, cnt;
  340.  
  341.     for (cnt = len; cnt > 0; cnt -= i, buf += i) {
  342.         if ((i = send(xprt->xp_sock, buf, cnt, 0)) < 0) {
  343.             ((struct tcp_conn *)(xprt->xp_p1))->strm_stat =
  344.                 XPRT_DIED;
  345.             return (-1);
  346.         }
  347.     }
  348.     return (len);
  349. }
  350.  
  351. static enum xprt_stat
  352. svctcp_stat(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(SVCXPRT *xprt, register struct rpc_msg *msg)
  366. {
  367.     register struct tcp_conn *cd =
  368.         (struct tcp_conn *)(xprt->xp_p1);
  369.     register XDR *xdrs = &(cd->xdrs);
  370.  
  371.     xdrs->x_op = XDR_DECODE;
  372.     (void)xdrrec_skiprecord(xdrs);
  373.     if (xdr_callmsg(xdrs, msg)) {
  374.         cd->x_id = msg->rm_xid;
  375.         return (TRUE);
  376.     }
  377.     return (FALSE);
  378. }
  379.  
  380. static bool_t
  381. svctcp_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
  382. {
  383.     return ((*xdr_args)(&(((struct tcp_conn *)(xprt->xp_p1))->xdrs), args_ptr));
  384. }
  385.  
  386. static bool_t
  387. svctcp_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *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(SVCXPRT *xprt, register struct rpc_msg *msg)
  398. {
  399.     register struct tcp_conn *cd =
  400.         (struct tcp_conn *)(xprt->xp_p1);
  401.     register XDR *xdrs = &(cd->xdrs);
  402.     register bool_t stat;
  403.  
  404.     xdrs->x_op = XDR_ENCODE;
  405.     msg->rm_xid = cd->x_id;
  406.     stat = xdr_replymsg(xdrs, msg);
  407.     (void)xdrrec_endofrecord(xdrs, TRUE);
  408.     return (stat);
  409. }
  410.