home *** CD-ROM | disk | FTP | other *** search
/ Total Network Tools 2002 / NextStepPublishing-TotalNetworkTools2002-Win95.iso / Archive / Web Server / Xitami Multithreaded Web Server.exe / LRWPLIB.C < prev    next >
Encoding:
C/C++ Source or Header  |  1999-11-05  |  16.8 KB  |  503 lines

  1. /************************************************************************
  2.                Copyright (c) 1997 by Total Control Software
  3.                          All Rights Reserved
  4. ------------------------------------------------------------------------
  5.  
  6. Module Name:    lrwplib.c
  7.  
  8. Description:    Small library of routines to assist with the creation
  9.                 of LRWP Peer applications.
  10.  
  11. Creation Date:  1/5/98 9:47:27PM
  12. Updated:        1999/08/18, by Xitami Team <xitami@imatix.com> for LRWP 2.0
  13. Updated:        1999/11/05, by Pascal Antonnaux <pascal@imatix.com>
  14.                             for posted size in context 
  15.  
  16. # License:      This is free software.  You may use this software for any
  17. #               purpose including modification/redistribution, so long as
  18. #               this header remains intact and that you do not claim any
  19. #               rights of ownership or authorship of this software.  This
  20. #               software has been tested, but no warranty is expressed or
  21. #               implied.
  22.  
  23. ************************************************************************/
  24.  
  25. #include "lrwplib.h"
  26.  
  27. #define LENGTH_LEN          9           /* Digits in length val to/from peer */
  28. #define LENGTH_FORMAT_ULONG "%09uld"    /* above for int; this for ulong     */
  29.  
  30. #define LRWP_STRING_DELIM      "\xFF"   /* Delimiter as string; to send      */
  31. #define LRWP_STRING_DELIM_CHAR '\xFF'   /* Delimiter as char; to search for  */
  32.  
  33. #define ALLOC_INCR  1024
  34.  
  35. static int
  36. read_full_TCP(
  37.     sock_t handle,                      /*  Socket handle                    */
  38.     void *buffer,                       /*  Buffer to receive data           */
  39.     size_t length                       /*  Full amount of data to read      */
  40.     );
  41.  
  42. /*  ---------------------------------------------------------------------[<]-
  43.     Function: lrwp_connect
  44.  
  45.     Connects to the LRWP agent running in Xitami on host and port.  Sends
  46.     the given appname to use as the URI alias that will trigger requests to
  47.     be sent to this peer.  If vhost is given, this peer will only be sent
  48.     requests origininating from that virtual host.  This function assumes
  49.     that the LRWP structure is uninitialized and clears it before use.
  50.  
  51.     Returns NULL on success and a pointer to an error message otherwise.
  52.     ---------------------------------------------------------------------[>]-*/
  53.  
  54. char* lrwp_connect(LRWP* lrwp,          /* pointer to UNCONNECTED LRWP object*/
  55.                    char* appname,       /* Name or alias of Peer app         */
  56.                    char* host,          /* hostname/IP address to connect to */
  57.                    char* port,          /* string containing port number     */
  58.                    char* vhost)         /* optional virtual hostname         */
  59. {
  60.     return lrwp2_connect(lrwp, appname, host, port, vhost, NULL);
  61. }
  62.  
  63.  
  64. /*  ---------------------------------------------------------------------[<]-
  65.     Function: lrwp2_connect
  66.  
  67.     Connects to the LRWP 2.0 agent running in Xitami on host and port.  Sends
  68.     the given appname to use as the URI alias that will trigger requests to
  69.     be sent to this peer.  If vhost is given, this peer will only be sent
  70.     requests origininating from that virtual host.  If the passphrase is
  71.     supplied a LRWP 2.0 connection will be attempted using that passphrase
  72.     to do the authentication, otherwise a LRWP 1.0 connection will be used. 
  73.     This function assumes that the LRWP structure is uninitialized and 
  74.     clears it before use.
  75.  
  76.     Returns NULL on success and a pointer to an error message otherwise.
  77.     ---------------------------------------------------------------------[>]-*/
  78.  
  79. char* lrwp2_connect(LRWP* lrwp,         /* pointer to UNCONNECTED LRWP object*/
  80.                     char* appname,      /* Name or alias of Peer app         */
  81.                     char* host,         /* hostname/IP address to connect to */
  82.                     char* port,         /* string containing port number     */
  83.                     char* vhost,        /* optional virtual hostname         */
  84.             char* passphrase)   /* optional authentication passphrase*/
  85. {
  86.     static char buf[1024];
  87.     char        sizebuf[LENGTH_LEN+1];
  88.     int         len;
  89.  
  90.     /* Initialize LRWP structure.  Assumes this is first use. */
  91.     lrwp->sock      = 0;
  92.     lrwp->cgi       = NULL;
  93.     lrwp->post_data = NULL;
  94.     lrwp->outbuf    = NULL;
  95.     lrwp->size      = 0;
  96.     lrwp->allocated = 0;
  97.     lrwp->post_size = 0;
  98.  
  99.     /* Attempt the connection */
  100.     ip_nonblock = FALSE;                /*  Use blocking socket i/o          */
  101.     lrwp->sock = connect_TCP(host, port);
  102.     if (lrwp->sock == INVALID_SOCKET) {
  103.         sprintf(buf, "ERROR: Unable to connect (%s)", sockmsg());
  104.         return buf;
  105.     }
  106.  
  107.     /* send the startup string.  We use a LRWP 2.0 startup string if we 
  108.      * have a passphrase, and thus expect to need to do authentication
  109.      *
  110.      * LRWP connection request contains:
  111.      *   LRWP 1.0: applicationname 0xFF virtualhostname 0xFF filterext [0xFF]
  112.      *   LRWP 2.0: 0xFF proto_major "." proto_minor 0xFF applicationname
  113.      *             0xFF virtualhostname 0xFF
  114.      */
  115.     if (passphrase)
  116.     sprintf(buf, LRWP_STRING_DELIM "2.0" LRWP_STRING_DELIM "%s"   /*LRWP2*/
  117.              LRWP_STRING_DELIM "%s"  LRWP_STRING_DELIM,
  118.              appname, vhost ? vhost : "");
  119.     else
  120.         sprintf(buf, "%s" LRWP_STRING_DELIM "%s" LRWP_STRING_DELIM "%s",  /*1*/
  121.              appname, vhost?vhost:"", "");
  122.  
  123.     if (write_TCP(lrwp->sock, buf, strlen(buf)) == SOCKET_ERROR) {
  124.         sprintf(buf, "ERROR: Unable to send startup string (%s)", sockmsg());
  125.     lrwp_close(lrwp);
  126.         return buf;
  127.     }
  128.  
  129.     /* wait for an acknowledgement... */
  130.     len = read_TCP(lrwp->sock, buf, sizeof(buf)-1);
  131.     if (len == SOCKET_ERROR) {
  132.         sprintf(buf, "ERROR: Unable to receive acknowledgement string (%s)", 
  133.              sockmsg());
  134.     lrwp_close(lrwp);
  135.         return buf;
  136.     }
  137.     buf[len] = '\0';
  138.  
  139.     /* At this point we will either be acknowledged, or we will be
  140.      * challenged.  If we are challenged, we respond using our
  141.      * passphrase.
  142.      */
  143. #define CHALLENGE_IND ("CHALLENGE" LRWP_STRING_DELIM)
  144. #define CHALLENGE_LEN 10
  145. #define REJECTED_IND  ("REJECTED"  LRWP_STRING_DELIM)
  146. #define REJECTED_LEN  9
  147.  
  148.     if (streq(buf, "OK") || streq(buf, "OK" LRWP_STRING_DELIM))
  149.         return NULL;                         /* Connected, no problems */
  150.     else if (strncmp(buf, CHALLENGE_IND, CHALLENGE_LEN) == 0) {
  151.     /* We've been challenged -- either the buffer, or our input
  152.      * should contain the challenge length and string.
  153.      */
  154.     int i, size, passphraselen;
  155.     byte *challengeResponse = NULL;
  156.  
  157.         if (len < CHALLENGE_LEN + LENGTH_LEN) {
  158.         /* Don't have (all of) the length of the challenge string */
  159.             int got = read_full_TCP(lrwp->sock, (buf + len), 
  160.                             (CHALLENGE_LEN + LENGTH_LEN - len));
  161.         if (got == SOCKET_ERROR) {
  162.         sprintf(buf, "ERROR: Unable to receive LRWP challenge len (%s)",
  163.                  sockmsg());
  164.             lrwp_close(lrwp);
  165.                 return buf;
  166.         }
  167.         else
  168.         len += got;
  169.     }
  170.  
  171.     ASSERT(len >= CHALLENGE_LEN + LENGTH_LEN);
  172.     memcpy(sizebuf, (buf + CHALLENGE_LEN), LENGTH_LEN);
  173.     sizebuf[CHALLENGE_LEN] = '\0';
  174.         size = atoi(sizebuf);
  175.  
  176.     /* Ensure we'll have room to receive the challenge.  The current
  177.      * LRWP spec means we should easily be able to fit it in our
  178.      * buffer.
  179.      */
  180.         if (size < 0 || CHALLENGE_LEN + LENGTH_LEN + size > sizeof(buf)) {
  181.         sprintf(buf, "ERROR: Cannot process challenge (len: %s)",
  182.                   sizebuf);
  183.         lrwp_close(lrwp);
  184.             return buf;
  185.     }
  186.  
  187.     /* Make sure we've got the LRWP challenge itself. */
  188.     if (len < CHALLENGE_LEN + LENGTH_LEN + size) {
  189.             int got = read_full_TCP(lrwp->sock, (buf + len), 
  190.                             (CHALLENGE_LEN + LENGTH_LEN + size - len));
  191.         if (got == SOCKET_ERROR) {
  192.         sprintf(buf, "ERROR: Unable to receive LRWP challenge len (%s)",
  193.                  sockmsg());
  194.             lrwp_close(lrwp);
  195.                 return buf;
  196.         }
  197.         else
  198.         len += got;
  199.     }
  200.  
  201.         ASSERT(len == CHALLENGE_LEN + LENGTH_LEN + size);
  202.     buf[len] = '\0';
  203.  
  204.     /* Process response, in place */
  205.         passphraselen = strlen(passphrase);
  206.  
  207.         for (i = 0, challengeResponse=(byte *)(buf+CHALLENGE_LEN+LENGTH_LEN);
  208.              i < size;
  209.          ++i, ++challengeResponse)
  210.  
  211.              *challengeResponse ^= (passphrase[i % passphraselen]);
  212.  
  213.         /* Now send back the LRWP challenge response, length and data */
  214.         if (write_TCP(lrwp->sock, (buf + CHALLENGE_LEN), (LENGTH_LEN + size)) 
  215.             == SOCKET_ERROR) {
  216.  
  217.             sprintf(buf, "ERROR: Unable to send LRWP challenge response (%s)", 
  218.                  sockmsg());
  219.         lrwp_close(lrwp);
  220.             return buf;
  221.         } 
  222.  
  223.     /* Finally, check to see if we're accepted now */
  224.         len = read_TCP(lrwp->sock, buf, sizeof(buf)-1);
  225.         if (len == SOCKET_ERROR) {
  226.             sprintf(buf, "ERROR: Unable to receive LRWP challenge ack (%s)", 
  227.                  sockmsg());
  228.         lrwp_close(lrwp);
  229.             return buf;
  230.         }
  231.     buf[len] = '\0';
  232.         if (streq(buf, "OK") || streq(buf, "OK" LRWP_STRING_DELIM)) {
  233.         return NULL;                   /* We're accepted, no trouble */
  234.         } else if (strncmp(buf, REJECTED_IND, REJECTED_LEN) == 0) {
  235.         /* XXX: Assume we got the whole rejection message in one read */
  236.  
  237.         /* Tidy up the reject message for the viewer */
  238.         buf[len-1] = '\0';
  239.         ASSERT(REJECTED_LEN >= 7);
  240.         memcpy(buf + (REJECTED_LEN - 7), "ERROR: ", 7);
  241.  
  242.         lrwp_close(lrwp);
  243.         return (buf + REJECTED_LEN - 7);
  244.     } else {
  245.         lrwp_close(lrwp);
  246.             return buf;                    /* Rejection message */
  247.     }
  248.     } else if (strncmp(buf, REJECTED_IND, REJECTED_LEN) == 0) {
  249.     /* XXX: Assume we got the whole rejection message in one read */
  250.  
  251.     /* Tidy up the reject message for the viewer */
  252.     buf[len-1] = '\0';
  253.     ASSERT(REJECTED_LEN >= 7);
  254.     memcpy(buf + (REJECTED_LEN - 7), "ERROR: ", 7);
  255.  
  256.     lrwp_close(lrwp);
  257.     return (buf + REJECTED_LEN - 7);
  258.     } else {
  259.     /* Something else -- treat it like an error. */
  260.     lrwp_close(lrwp);
  261.         return buf;
  262.     }
  263. }
  264.  
  265. /*  ---------------------------------------------------------------------[<]-
  266.     Function: lrwp_accept_request
  267.  
  268.     This funation waits for and recieves a request from the LRWP agent, and
  269.     populates the LRWP structure with the request data.
  270.  
  271.     Returns 0 on success and -1 otherwise.
  272.     ---------------------------------------------------------------------[>]-*/
  273.  
  274. int  lrwp_accept_request(LRWP* lrwp)    /* pointer to CONNECTED LRWP object  */
  275. {
  276.     char
  277.         sizebuf [LENGTH_LEN + 1];
  278.     int
  279.         len,
  280.         size;
  281.     DESCR
  282.         descr;
  283.     char
  284.         *temp;
  285.  
  286.     /* read the size of the CGI environment                                  */
  287.     len = read_full_TCP(lrwp->sock, sizebuf, LENGTH_LEN);
  288.     if (len == SOCKET_ERROR 
  289.     || len != LENGTH_LEN)
  290.         return (-1);
  291.  
  292.     sizebuf [len] = 0;
  293.     size          = atoi (sizebuf);
  294.  
  295.     /*  read the CGI environment data                                        */
  296.     temp = mem_alloc (size + 1);
  297.     if (temp == NULL)
  298.         return (-1);
  299.  
  300.     len = read_full_TCP (lrwp->sock, temp, size);
  301.     if (len == SOCKET_ERROR 
  302.     ||  len != size)
  303.       {
  304.         mem_free (temp);
  305.         return (-1);
  306.       }
  307.  
  308.     /*  and convert it to a Symbol Table                                     */
  309.     descr.size = size;
  310.     descr.data = temp;
  311.     lrwp-> cgi = descr2symb (&descr);
  312.     mem_free (temp);
  313.  
  314.     /*  now read the size of the post data                                   */
  315.     len = read_full_TCP (lrwp-> sock, sizebuf, LENGTH_LEN);
  316.     if (len == SOCKET_ERROR 
  317.     ||  len != LENGTH_LEN)
  318.       {
  319.         sym_delete_table (lrwp->cgi);
  320.         lrwp->cgi = NULL;
  321.         return (-1);
  322.       }
  323.     sizebuf [len] = 0;
  324.     size = atoi (sizebuf);
  325.  
  326.     /*  and finally, read the post data, if any                              */
  327.     if (size) 
  328.       {
  329.         lrwp-> post_data = mem_alloc (size + 1);
  330.         if (lrwp-> post_data)
  331.           {
  332.             len = read_full_TCP (lrwp->sock, lrwp-> post_data, size);
  333.             if (len == SOCKET_ERROR
  334.             ||  len != size)
  335.               {
  336.                 sym_delete_table (lrwp->cgi);
  337.                 mem_free (lrwp->post_data);
  338.                 lrwp-> cgi       = NULL; 
  339.                 lrwp-> post_data = NULL;
  340.                 return (-1);
  341.               }
  342.             else
  343.               {
  344.                 lrwp-> post_data [size] = '\0';
  345.                 lrwp-> post_size        = size;
  346.               }
  347.           }
  348.         else
  349.             lrwp-> post_data = mem_strdup ("");
  350.     }
  351.     else
  352.         lrwp-> post_data = mem_strdup ("");
  353.  
  354.     return 0;
  355. }
  356.  
  357. /*  ---------------------------------------------------------------------[<]-
  358.     Function: lrwp_send_string
  359.  
  360.     This function appends a string to the response buffer.
  361.     lrwp_finish_request() must be called to send the response back to Xitami.
  362.  
  363.     Returns 0 on success and -1 otherwise.
  364.     ---------------------------------------------------------------------[>]-*/
  365.  
  366. int  lrwp_send_string(LRWP* lrwp,       /* pointer to CONNECTED LRWP object  */
  367.                       char* st)         /* an ouput string                   */
  368. {
  369.     return lrwp_send_data(lrwp, st, strlen(st));
  370. }
  371.  
  372. /*  ---------------------------------------------------------------------[<]-
  373.     Function: lrwp_send_data
  374.  
  375.     Appends a buffer of (possibly binary) data of the specified size to
  376.     the response buffer.  lrwp_finish_request() must be called to send the
  377.     response back to Xitami.
  378.  
  379.     Returns 0 on success and -1 otherwise.
  380.     ---------------------------------------------------------------------[>]-*/
  381.  
  382. int  lrwp_send_data(LRWP* lrwp,         /* pointer to CONNECTED LRWP object  */
  383.                     void* data,         /* pointer to a data buffer          */
  384.                     size_t len)         /* size of the data buffer           */
  385. {
  386.     char*   newPtr;
  387.     size_t  newAlloc;
  388.  
  389.     /* reallocate if necessary */
  390.     if ((lrwp->size + len) > lrwp->allocated) {
  391.         newAlloc = max(lrwp->allocated + len, lrwp->allocated + ALLOC_INCR);
  392.         if (! lrwp->outbuf)
  393.             newPtr = mem_alloc(newAlloc);
  394.         else
  395.             newPtr = mem_realloc(lrwp->outbuf, newAlloc);
  396.         if (!newPtr)
  397.             return -1;
  398.         lrwp->outbuf = newPtr;
  399.         lrwp->allocated = newAlloc;
  400.     }
  401.     memcpy(lrwp->outbuf + lrwp->size, data, len);
  402.     lrwp->size += len;
  403.     return 0;
  404. }
  405.  
  406. /*  ---------------------------------------------------------------------[<]-
  407.     Function: lrwp_finish_request
  408.  
  409.     Completes the request by sending the response buffer back to Xitami
  410.     and prepares the lwrp structure to receive another request.
  411.  
  412.     Returns 0 on success and -1 otherwise.
  413.     ---------------------------------------------------------------------[>]-*/
  414.  
  415. int  lrwp_finish_request(LRWP* lrwp)    /* pointer to CONNECTED LRWP object  */
  416. {
  417.     char    sizebuf[LENGTH_LEN+1];
  418.  
  419.     sprintf(sizebuf, LENGTH_FORMAT_ULONG, lrwp->size);
  420.     if (write_TCP(lrwp->sock, sizebuf, LENGTH_LEN) == SOCKET_ERROR) {
  421.         lrwp_cleanup(lrwp);
  422.         return -1;
  423.     }
  424.  
  425.     if (write_TCP(lrwp->sock, lrwp->outbuf, lrwp->size) == SOCKET_ERROR) {
  426.         lrwp_cleanup(lrwp);
  427.         return -1;
  428.     }
  429.     lrwp_cleanup(lrwp);
  430.     return 0;
  431. }
  432.  
  433. /*  ---------------------------------------------------------------------[<]-
  434.     Function: lrwp_close
  435.  
  436.     Closes the connection to Xitami.
  437.  
  438.     Returns 0 on success and -1 otherwise.
  439.     ---------------------------------------------------------------------[>]-*/
  440.  
  441. int  lrwp_close(LRWP* lrwp)             /* pointer to CONNECTED LRWP object  */
  442. {
  443.     close_socket(lrwp->sock);
  444.     lrwp->sock = INVALID_SOCKET;
  445.     lrwp_cleanup(lrwp);
  446.     return 0;
  447. }
  448.  
  449. /*  ---------------------------------------------------------------------[<]-
  450.     Function: lrwp_cleanup
  451.  
  452.     Cleans up the LRWP structure.
  453.  
  454.     ---------------------------------------------------------------------[>]-*/
  455.  
  456. void lrwp_cleanup(LRWP* lrwp)
  457. {
  458.     if (lrwp->cgi)
  459.         sym_delete_table(lrwp->cgi);
  460.  
  461.     if (lrwp->post_data)
  462.         mem_free(lrwp->post_data);
  463.  
  464.     if (lrwp->outbuf)
  465.         mem_free(lrwp->outbuf);
  466.  
  467.     lrwp->cgi        = NULL;
  468.     lrwp->post_data  = NULL;
  469.     lrwp->outbuf     = NULL;
  470.     lrwp->size       = 0;
  471.     lrwp->allocated  = 0;
  472.     lrwp-> post_size = 0;
  473.  
  474. }
  475.  
  476.  
  477. /*  -------------------------------------------------------------------------
  478.     Function: read_full_TCP
  479.  
  480.     Helper function to read the full number of bytes specified from the socket.
  481.  
  482.     -------------------------------------------------------------------------*/
  483. static int
  484. read_full_TCP(
  485.     sock_t handle,                      /*  Socket handle                    */
  486.     void *buffer,                       /*  Buffer to receive data           */
  487.     size_t length                       /*  Full amount of data to read      */
  488.     )
  489. {
  490.     size_t  numRead = 0;
  491.     int     chunkLen;
  492.  
  493.     while (numRead < length) {
  494.         chunkLen = read_TCP(handle, ((char*)buffer)+numRead, length-numRead);
  495.         if (chunkLen == SOCKET_ERROR)
  496.             return SOCKET_ERROR;
  497.         numRead += chunkLen;
  498.     }
  499.     return numRead;
  500. }
  501.  
  502.  
  503.