home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume6 / rpc2 / part08 / rpc / rpclib / svc_tcp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-11-30  |  9.8 KB  |  411 lines

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