コード例 #1
0
ファイル: server.c プロジェクト: JPatsy/IOT-DB410c-Course-2
    /**
     * Name:        runServer
     * Description: Runs the server. If a connection is accepted, then parent process continues listening
     *              and spawns child process to process the message and close the connection to client.
     *
     * @param sock  Socket File Descriptor for listening connection
     */
void runServer(int sock) {
    struct sockaddr_storage clientaddr;

    //continuous loop
    while (1) {

        socklen_t addr_size = sizeof(clientaddr);
        //accept the new connection
        int newsocket = accept(sock, (struct sockaddr*) &clientaddr, &addr_size);
        __android_log_print(ANDROID_LOG_INFO, TAG, "Accepting Socket");

        if (newsocket < 0) {
            __android_log_print(ANDROID_LOG_ERROR, TAG, "Socket accepting failed", 1);
            __android_log_print(ANDROID_LOG_INFO, TAG, strerror(errno));
            endServer(sock, NULL, newsocket);
            continue;
        }

        //split between parent process and child process. Parent=listening child=accepting
        if (!fork()) {
            close(sock);
            char buffer[HTTP_MAX_SIZE];
            __android_log_print(ANDROID_LOG_INFO, TAG, "Receiving");

            //grab info into httpReceive
            httpReceive(newsocket,buffer);
            __android_log_print(ANDROID_LOG_INFO,TAG,"%s %d", buffer, (int) strlen(buffer));

            //kick back message up to java
            const char * message = processMessage(buffer);
            __android_log_print(ANDROID_LOG_INFO,TAG,"%s %d", message, (int) strlen(message));
            __android_log_print(ANDROID_LOG_INFO, TAG, "Sending");

            //get the message and send it to client
            if (send(newsocket,message,strlen(message), 0) < 0){
                __android_log_print(ANDROID_LOG_ERROR,TAG,"Send Failed",1);
                endServer(-1, NULL, newsocket);
            }

            __android_log_print(ANDROID_LOG_INFO,TAG,"Sent Message %s", message);
            //close the new socket and exit the process
            close(newsocket);
            exit(0);
         }
        close(newsocket);
    }
}
コード例 #2
0
error_t httpReadStream(HttpConnection *connection, void *data, size_t size, size_t *received, uint_t flags)
{
   error_t error;
   size_t n;

   //No data has been read yet
   *received = 0;

   //Chunked encoding transfer is used?
   if(connection->request.chunkedEncoding)
   {
      //Point to the output buffer
      char_t *p = data;

      //Read as much data as possible
      while(*received < size)
      {
         //End of HTTP request body?
         if(connection->request.lastChunk)
            return ERROR_END_OF_STREAM;

         //Acquire a new chunk when the current chunk
         //has been completely consumed
         if(connection->request.byteCount == 0)
         {
            //The size of each chunk is sent right before the chunk itself
            error = httpReadChunkSize(connection);
            //Failed to decode the chunk-size field?
            if(error) return error;

            //Any chunk whose size is zero terminates the data transfer
            if(!connection->request.byteCount)
            {
               //The user must be satisfied with data already on hand
               return (*received > 0) ? NO_ERROR : ERROR_END_OF_STREAM;
            }
         }

         //Limit the number of bytes to read at a time
         n = MIN(size - *received, connection->request.byteCount);

         //Read data
         error = httpReceive(connection, p, n, &n, flags);
         //Any error to report?
         if(error) return error;

         //Total number of data that have been read
         *received += n;
         //Remaining data still available in the current chunk
         connection->request.byteCount -= n;

         //The HTTP_FLAG_BREAK_CHAR flag causes the function to stop reading
         //data as soon as the specified break character is encountered
         if(flags & HTTP_FLAG_BREAK_CRLF)
         {
            //Check whether a break character has been received
            if(p[n - 1] == LSB(flags)) break;
         }
         //The HTTP_FLAG_WAIT_ALL flag causes the function to return
         //only when the requested number of bytes have been read
         else if(!(flags & HTTP_FLAG_WAIT_ALL))
         {
            break;
         }

         //Advance data pointer
         p += n;
      }
   }
   //Default encoding?
   else
   {
      //Return immediately if the end of the request body has been reached
      if(!connection->request.byteCount)
         return ERROR_END_OF_STREAM;

      //Limit the number of bytes to read
      n = MIN(size, connection->request.byteCount);

      //Read data
      error = httpReceive(connection, data, n, received, flags);
      //Any error to report
      if(error) return error;

      //Decrement the count of remaining bytes to read
      connection->request.byteCount -= *received;
   }

   //Successful read operation
   return NO_ERROR;
}
コード例 #3
0
error_t httpReadHeader(HttpConnection *connection)
{
   error_t error;
   size_t length;
   char_t *token;
   char_t *p;
   char_t *s;

   //Set the maximum time the server will wait for an HTTP
   //request before closing the connection
   error = socketSetTimeout(connection->socket, HTTP_SERVER_IDLE_TIMEOUT);
   //Any error to report?
   if(error) return error;

   //Read the first line of the request
   error = httpReceive(connection, connection->buffer,
      HTTP_SERVER_BUFFER_SIZE - 1, &length, SOCKET_FLAG_BREAK_CRLF);
   //Unable to read any data?
   if(error) return error;

   //Revert to default timeout
   error = socketSetTimeout(connection->socket, HTTP_SERVER_TIMEOUT);
   //Any error to report?
   if(error) return error;

   //Properly terminate the string with a NULL character
   connection->buffer[length] = '\0';
   //Debug message
   TRACE_INFO("%s", connection->buffer);

   //The Request-Line begins with a method token
   token = strtok_r(connection->buffer, " \r\n", &p);
   //Unable to retrieve the method?
   if(!token) return ERROR_INVALID_REQUEST;

   //The Method token indicates the method to be performed on the
   //resource identified by the Request-URI
   error = strSafeCopy(connection->request.method, token, HTTP_SERVER_METHOD_MAX_LEN);
   //Any error to report?
   if(error) return ERROR_INVALID_REQUEST;

   //The Request-URI is following the method token
   token = strtok_r(NULL, " \r\n", &p);
   //Unable to retrieve the Request-URI?
   if(!token) return ERROR_INVALID_REQUEST;

   //Check whether a query string is present
   s = strchr(token, '?');

   //Query string found?
   if(s != NULL)
   {
      //Split the string
      *s = '\0';

      //Save the Request-URI
      error = httpDecodePercentEncodedString(token,
         connection->request.uri, HTTP_SERVER_URI_MAX_LEN);
      //Any error to report?
      if(error)
         return ERROR_INVALID_REQUEST;

      //Check the length of the query string
      if(strlen(s + 1) > HTTP_SERVER_QUERY_STRING_MAX_LEN)
         return ERROR_INVALID_REQUEST;

      //Save the query string
      strcpy(connection->request.queryString, s + 1);
   }
   else
   {
      //Save the Request-URI
      error = httpDecodePercentEncodedString(token,
         connection->request.uri, HTTP_SERVER_URI_MAX_LEN);
      //Any error to report?
      if(error)
         return ERROR_INVALID_REQUEST;

      //No query string
      connection->request.queryString[0] = '\0';
   }

   //Redirect to the default home page if necessary
   if(!strcasecmp(connection->request.uri, "/"))
      strcpy(connection->request.uri, connection->settings->defaultDocument);

   //Clean the resulting path
   pathCanonicalize(connection->request.uri);

   //The protocol version is following the Request-URI
   token = strtok_r(NULL, " \r\n", &p);

   //HTTP version 0.9?
   if(!token)
   {
      //Save version number
      connection->request.version = HTTP_VERSION_0_9;
      //Persistent connections are not supported
      connection->request.keepAlive = FALSE;
   }
   //HTTP version 1.0?
   else if(!strcasecmp(token, "HTTP/1.0"))
   {
      //Save version number
      connection->request.version = HTTP_VERSION_1_0;
      //By default connections are not persistent
      connection->request.keepAlive = FALSE;
   }
   //HTTP version 1.1?
   else if(!strcasecmp(token, "HTTP/1.1"))
   {
      //Save version number
      connection->request.version = HTTP_VERSION_1_1;
      //HTTP 1.1 makes persistent connections the default
      connection->request.keepAlive = TRUE;
   }
   //HTTP version not supported?
   else
   {
      return ERROR_INVALID_REQUEST;
   }

   //Default value for properties
   connection->request.chunkedEncoding = FALSE;
   connection->request.contentLength = 0;

   //HTTP 0.9 does not support Full-Request
   if(connection->request.version >= HTTP_VERSION_1_0)
   {
      //Local variables
      char_t firstChar;
      char_t *separator;
      char_t *name;
      char_t *value;

      //This variable is used to decode header fields that span multiple lines
      firstChar = '\0';

      //Parse the header fields of the HTTP request
      while(1)
      {
         //Decode multiple-line header field
         error = httpReadHeaderField(connection, connection->buffer,
            HTTP_SERVER_BUFFER_SIZE, &firstChar);
         //Any error to report?
         if(error) return error;

         //Debug message
         TRACE_DEBUG("%s", connection->buffer);

         //An empty line indicates the end of the header fields
         if(!strcmp(connection->buffer, "\r\n"))
            break;

         //Check whether a separator is present
         separator = strchr(connection->buffer, ':');

         //Separator found?
         if(separator != NULL)
         {
            //Split the line
            *separator = '\0';

            //Get field name and value
            name = strTrimWhitespace(connection->buffer);
            value = strTrimWhitespace(separator + 1);

            //Connection field found?
            if(!strcasecmp(name, "Connection"))
            {
               //Check whether persistent connections are supported or not
               if(!strcasecmp(value, "keep-alive"))
                  connection->request.keepAlive = TRUE;
               else if(!strcasecmp(value, "close"))
                  connection->request.keepAlive = FALSE;
            }
            //Transfer-Encoding field found?
            else if(!strcasecmp(name, "Transfer-Encoding"))
            {
               //Check whether chunked encoding is used
               if(!strcasecmp(value, "chunked"))
                  connection->request.chunkedEncoding = TRUE;
            }
            //Content-Type field found?
            else if(!strcasecmp(name, "Content-Type"))
            {
               //Parse Content-Type field
               httpParseContentTypeField(connection, value);
            }
            //Content-Length field found?
            else if(!strcasecmp(name, "Content-Length"))
            {
               //Get the length of the body data
               connection->request.contentLength = atoi(value);
            }
            //Authorization field found?
            else if(!strcasecmp(name, "Authorization"))
            {
               //Parse Authorization field
               httpParseAuthField(connection, value);
            }
         }
      }
   }

   //Prepare to read the HTTP request body
   if(connection->request.chunkedEncoding)
   {
      connection->request.byteCount = 0;
      connection->request.firstChunk = TRUE;
      connection->request.lastChunk = FALSE;
   }
   else
   {
      connection->request.byteCount = connection->request.contentLength;
   }

   //The request header has been successfully parsed
   return NO_ERROR;
}
コード例 #4
0
error_t httpReadChunkSize(HttpConnection *connection)
{
   error_t error;
   size_t n;
   char_t *end;
   char_t s[8];

   //First chunk to be received?
   if(connection->request.firstChunk)
   {
      //Clear the flag
      connection->request.firstChunk = FALSE;
   }
   else
   {
      //Read the CRLF that follows the previous chunk-data field
      error = httpReceive(connection, s, sizeof(s) - 1, &n, SOCKET_FLAG_BREAK_CRLF);
      //Any error to report?
      if(error) return error;

      //Properly terminate the string with a NULL character
      s[n] = '\0';

      //The chunk data must be terminated by CRLF
      if(strcmp(s, "\r\n"))
         return ERROR_WRONG_ENCODING;
   }

   //Read the chunk-size field
   error = httpReceive(connection, s, sizeof(s) - 1, &n, SOCKET_FLAG_BREAK_CRLF);
   //Any error to report?
   if(error) return error;

   //Properly terminate the string with a NULL character
   s[n] = '\0';
   //Remove extra whitespaces
   strRemoveTrailingSpace(s);

   //Retrieve the size of the chunk
   connection->request.byteCount = strtoul(s, &end, 16);

   //No valid conversion could be performed?
   if(end == s || *end != '\0')
      return ERROR_WRONG_ENCODING;

   //Any chunk whose size is zero terminates the data transfer
   if(!connection->request.byteCount)
   {
      //The end of the HTTP request body has been reached
      connection->request.lastChunk = TRUE;

      //Skip the trailer
      while(1)
      {
         //Read a complete line
         error = httpReceive(connection, s, sizeof(s) - 1, &n, SOCKET_FLAG_BREAK_CRLF);
         //Unable to read any data?
         if(error) return error;

         //Properly terminate the string with a NULL character
         s[n] = '\0';

         //The trailer is terminated by an empty line
         if(!strcmp(s, "\r\n"))
            break;
      }
   }

   //Successful processing
   return NO_ERROR;
}
コード例 #5
0
error_t httpReadHeaderField(HttpConnection *connection,
   char_t *buffer, size_t size, char_t *firstChar)
{
   error_t error;
   size_t n;
   size_t length;

   //This is the actual length of the header field
   length = 0;

   //The process of moving from a multiple-line representation of a header
   //field to its single line representation is called unfolding
   do
   {
      //Check the length of the header field
      if((length + 1) >= size)
      {
         //Report an error
         error = ERROR_INVALID_REQUEST;
         //Exit immediately
         break;
      }

      //NULL character found?
      if(*firstChar == '\0')
      {
         //Prepare to decode the first header field
         length = 0;
      }
      //LWSP character found?
      else if(*firstChar == ' ' || *firstChar == '\t')
      {
         //Unfolding is accomplished by regarding CRLF immediately
         //followed by a LWSP as equivalent to the LWSP character
         buffer[length] = *firstChar;
         //The current header field spans multiple lines
         length++;
      }
      //Any other character?
      else
      {
         //Restore the very first character of the header field
         buffer[0] = *firstChar;
         //Prepare to decode a new header field
         length = 1;
      }

      //Read data until a CLRF character is encountered
      error = httpReceive(connection, buffer + length,
         size - 1 - length, &n, SOCKET_FLAG_BREAK_CRLF);
      //Any error to report?
      if(error) break;

      //Update the length of the header field
      length += n;
      //Properly terminate the string with a NULL character
      buffer[length] = '\0';

      //An empty line indicates the end of the header fields
      if(!strcmp(buffer, "\r\n"))
         break;

      //Read the next character to detect if the CRLF is immediately
      //followed by a LWSP character
      error = httpReceive(connection, firstChar,
         sizeof(char_t), &n, SOCKET_FLAG_WAIT_ALL);
      //Any error to report?
      if(error) break;

      //LWSP character found?
      if(*firstChar == ' ' || *firstChar == '\t')
      {
         //CRLF immediately followed by LWSP as equivalent to the LWSP character
         if(length >= 2)
         {
            if(buffer[length - 2] == '\r' || buffer[length - 1] == '\n')
            {
               //Remove trailing CRLF sequence
               length -= 2;
               //Properly terminate the string with a NULL character
               buffer[length] = '\0';
            }
         }
      }

      //A header field may span multiple lines...
   } while(*firstChar == ' ' || *firstChar == '\t');

   //Return status code
   return error;
}