Beispiel #1
0
error_t udpReceiveDatagram(Socket *socket, IpAddr *srcIpAddr, uint16_t *srcPort,
   IpAddr *destIpAddr, void *data, size_t size, size_t *received, uint_t flags)
{
   SocketQueueItem *queueItem;

   //The receive queue is empty?
   if(!socket->receiveQueue)
   {
      //Set the events the application is interested in
      socket->eventMask = SOCKET_EVENT_RX_READY;
      //Reset the event object
      osResetEvent(&socket->event);
      //Leave critical section
      osReleaseMutex(&socketMutex);
      //Wait until an event is triggered
      osWaitForEvent(&socket->event, socket->timeout);
      //Enter critical section
      osAcquireMutex(&socketMutex);
   }

   //Check whether the read operation timed out
   if(!socket->receiveQueue)
   {
      //No data can be read
      *received = 0;
      //Report a timeout error
      return ERROR_TIMEOUT;
   }

   //Point to the first item in the receive queue
   queueItem = socket->receiveQueue;
   //Copy data to user buffer
   *received = chunkedBufferRead(data, queueItem->buffer, queueItem->offset, size);

   //Save the source IP address
   if(srcIpAddr)
      *srcIpAddr = queueItem->srcIpAddr;
   //Save the source port number
   if(srcPort)
      *srcPort = queueItem->srcPort;
   //Save the destination IP address
   if(destIpAddr)
      *destIpAddr = queueItem->destIpAddr;

   //If the SOCKET_FLAG_PEEK flag is set, the data is copied
   //into the buffer but is not removed from the input queue
   if(!(flags & SOCKET_FLAG_PEEK))
   {
      //Remove the item from the receive queue
      socket->receiveQueue = queueItem->next;
      //Deallocate memory buffer
      chunkedBufferFree(queueItem->buffer);
   }

   //Update the state of events
   udpUpdateEvents(socket);

   //Successful read operation
   return NO_ERROR;
}
Beispiel #2
0
error_t rawSocketReceiveEthPacket(Socket *socket,
   void *data, size_t size, size_t *received, uint_t flags)
{
   SocketQueueItem *queueItem;

   //The SOCKET_FLAG_DONT_WAIT enables non-blocking operation
   if(!(flags & SOCKET_FLAG_DONT_WAIT))
   {
      //The receive queue is empty?
      if(!socket->receiveQueue)
      {
         //Set the events the application is interested in
         socket->eventMask = SOCKET_EVENT_RX_READY;
         //Reset the event object
         osResetEvent(&socket->event);
         //Leave critical section
         osReleaseMutex(&socketMutex);
         //Wait until an event is triggered
         osWaitForEvent(&socket->event, socket->timeout);
         //Enter critical section
         osAcquireMutex(&socketMutex);
      }
   }

   //Check whether the read operation timed out
   if(!socket->receiveQueue)
   {
      //No data can be read
      *received = 0;
      //Report a timeout error
      return ERROR_TIMEOUT;
   }

   //Point to the first item in the receive queue
   queueItem = socket->receiveQueue;
   //Copy data to user buffer
   *received = netBufferRead(data, queueItem->buffer, queueItem->offset, size);

   //If the SOCKET_FLAG_PEEK flag is set, the data is copied
   //into the buffer but is not removed from the input queue
   if(!(flags & SOCKET_FLAG_PEEK))
   {
      //Remove the item from the receive queue
      socket->receiveQueue = queueItem->next;
      //Deallocate memory buffer
      netBufferFree(queueItem->buffer);
   }

   //Update the state of events
   rawSocketUpdateEvents(socket);

   //Successful read operation
   return NO_ERROR;
}
Beispiel #3
0
error_t socketPoll(SocketEventDesc *eventDesc, uint_t size, OsEvent *extEvent, systime_t timeout)
{
   uint_t i;
   bool_t status;
   OsEvent *event;
   OsEvent eventObject;

   //Check parameters
   if(!eventDesc || !size)
      return ERROR_INVALID_PARAMETER;

   //Try to use the supplied event object to receive notifications
   if(!extEvent)
   {
      //Create an event object only if necessary
      if(!osCreateEvent(&eventObject))
      {
         //Report an error
         return ERROR_OUT_OF_RESOURCES;
      }

      //Reference to the newly created event
      event = &eventObject;
   }
   else
   {
      //Reference to the external event
      event = extEvent;
   }

   //Loop through descriptors
   for(i = 0; i < size; i++)
   {
      //Clear event flags
      eventDesc[i].eventFlags = 0;
      //Subscribe to the requested events
      socketRegisterEvents(eventDesc[i].socket, event, eventDesc[i].eventMask);
   }

   //Block the current task until an event occurs
   status = osWaitForEvent(event, timeout);

   //Any socket event is in the signaled state?
   if(status)
   {
      //Loop through descriptors
      for(i = 0; i < size; i++)
      {
         //Retrieve event flags for the current socket
         socketGetEvents(eventDesc[i].socket, &eventDesc[i].eventFlags);
         //Clear unnecessary flags
         eventDesc[i].eventFlags &= eventDesc[i].eventMask;
      }
   }

   //Unsubscribe previously registered events
   for(i = 0; i < size; i++)
      socketUnregisterEvents(eventDesc[i].socket);

   //Reset event object before exiting...
   osResetEvent(event);

   //Release previously allocated resources
   if(!extEvent)
      osDeleteEvent(&eventObject);

   //Return status code
   return status ? NO_ERROR : ERROR_TIMEOUT;
}
void httpConnectionTask(void *param)
{
   error_t error;
   uint_t counter;
   HttpConnection *connection;

   //Point to the structure representing the HTTP connection
   connection = (HttpConnection *) param;

   //Endless loop
   while(1)
   {
      //Wait for an incoming connection attempt
      osWaitForEvent(&connection->startEvent, INFINITE_DELAY);

      //Initialize status code
      error = NO_ERROR;

#if (HTTP_SERVER_TLS_SUPPORT == ENABLED)
      //Use SSL/TLS to secure the connection?
      if(connection->settings->useTls)
      {
         //Debug message
         TRACE_INFO("Initializing SSL/TLS session...\r\n");

         //Start of exception handling block
         do
         {
            //Allocate SSL/TLS context
            connection->tlsContext = tlsInit();
            //Initialization failed?
            if(connection->tlsContext == NULL)
            {
               //Report an error
               error = ERROR_OUT_OF_MEMORY;
               //Exit immediately
               break;
            }

            //Select server operation mode
            error = tlsSetConnectionEnd(connection->tlsContext, TLS_CONNECTION_END_SERVER);
            //Any error to report?
            if(error) break;

            //Bind TLS to the relevant socket
            error = tlsSetSocket(connection->tlsContext, connection->socket);
            //Any error to report?
            if(error) break;

            //Invoke user-defined callback, if any
            if(connection->settings->tlsInitCallback != NULL)
            {
               //Perform SSL/TLS related initialization
               error = connection->settings->tlsInitCallback(connection, connection->tlsContext);
               //Any error to report?
               if(error) break;
            }

            //Establish a secure session
            error = tlsConnect(connection->tlsContext);
            //Any error to report?
            if(error) break;

            //End of exception handling block
         } while(0);
      }
      else
      {
         //Do not use SSL/TLS
         connection->tlsContext = NULL;
      }
#endif

      //Check status code
      if(!error)
      {
         //Process incoming requests
         for(counter = 0; counter < HTTP_SERVER_MAX_REQUESTS; counter++)
         {
            //Debug message
            TRACE_INFO("Waiting for request...\r\n");

            //Clear request header
            memset(&connection->request, 0, sizeof(HttpRequest));
            //Clear response header
            memset(&connection->response, 0, sizeof(HttpResponse));

            //Read the HTTP request header and parse its contents
            error = httpReadHeader(connection);
            //Any error to report?
            if(error)
            {
               //Debug message
               TRACE_INFO("No HTTP request received or parsing error...\r\n");
               break;
            }

#if (HTTP_SERVER_BASIC_AUTH_SUPPORT == ENABLED || HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED)
            //No Authorization header found?
            if(!connection->request.auth.found)
            {
               //Invoke user-defined callback, if any
               if(connection->settings->authCallback != NULL)
               {
                  //Check whether the access to the specified URI is authorized
                  connection->status = connection->settings->authCallback(connection,
                     connection->request.auth.user, connection->request.uri);
               }
               else
               {
                  //Access to the specified URI is allowed
                  connection->status = HTTP_ACCESS_ALLOWED;
               }
            }

            //Check access status
            if(connection->status == HTTP_ACCESS_ALLOWED)
            {
               //Access to the specified URI is allowed
               error = NO_ERROR;
            }
            else if(connection->status == HTTP_ACCESS_BASIC_AUTH_REQUIRED)
            {
               //Basic access authentication is required
               connection->response.auth.mode = HTTP_AUTH_MODE_BASIC;
               //Report an error
               error = ERROR_AUTH_REQUIRED;
            }
            else if(connection->status == HTTP_ACCESS_DIGEST_AUTH_REQUIRED)
            {
               //Digest access authentication is required
               connection->response.auth.mode = HTTP_AUTH_MODE_DIGEST;
               //Report an error
               error = ERROR_AUTH_REQUIRED;
            }
            else
            {
               //Access to the specified URI is denied
               error = ERROR_NOT_FOUND;
            }
#endif

            //Debug message
            TRACE_INFO("Sending HTTP response to the client...\r\n");

            //Check status code
            if(!error)
            {
               //Default HTTP header fields
               connection->response.version = connection->request.version;
               connection->response.noCache = FALSE;

#if (HTTP_SERVER_PERSISTENT_CONN_SUPPORT == ENABLED)
               //Persistent connections are accepted
               connection->response.keepAlive = connection->request.keepAlive;
#else
               //Connections are not persistent by default
               connection->response.keepAlive = FALSE;
#endif

#if (HTTP_SERVER_SSI_SUPPORT == ENABLED)
               //Use server-side scripting to dynamically generate HTML code?
               if(httpCompExtension(connection->request.uri, ".stm") ||
                  httpCompExtension(connection->request.uri, ".shtm") ||
                  httpCompExtension(connection->request.uri, ".shtml"))
               {
                  //SSI processing (Server Side Includes)
                  error = ssiExecuteScript(connection, connection->request.uri, 0);
               }
               else
#endif
               {
                  //Send the contents of the requested page
                  error = httpSendResponse(connection, connection->request.uri);
               }

               //The requested resource is not available?
               if(error == ERROR_NOT_FOUND)
               {
                  //Default HTTP header fields
                  connection->response.version = connection->request.version;
                  connection->response.statusCode = 200;
                  connection->response.keepAlive = connection->request.keepAlive;
                  connection->response.noCache = FALSE;
                  connection->response.location = NULL;
                  connection->response.contentType = mimeGetType(connection->request.uri);
                  connection->response.chunkedEncoding = TRUE;

                  //Invoke user-defined callback, if any
                  if(connection->settings->uriNotFoundCallback != NULL)
                  {
                     error = connection->settings->uriNotFoundCallback(connection,
                        connection->request.uri);
                  }
               }
            }

            //Bad request?
            if(error == ERROR_INVALID_REQUEST)
            {
               //Send an error 400 and close the connection immediately
               httpSendErrorResponse(connection, 400,
                  "The request is badly formed");
            }
            //Authorization required?
            else if(error == ERROR_AUTH_REQUIRED)
            {
               //Send an error 401 and keep the connection alive
               error = httpSendErrorResponse(connection, 401,
                  "Authorization required");
            }
            //Page not found?
            else if(error == ERROR_NOT_FOUND)
            {
               //Send an error 404 and keep the connection alive
               error = httpSendErrorResponse(connection, 404,
                  "The requested page could not be found");
            }

            //Internal error?
            if(error)
            {
               //Close the connection immediately
               break;
            }

            //Check whether the connection is persistent or not
            if(!connection->request.keepAlive || !connection->response.keepAlive)
            {
               //Close the connection immediately
               break;
            }
         }
      }

#if (HTTP_SERVER_TLS_SUPPORT == ENABLED)
      //Valid SSL/TLS context?
      if(connection->tlsContext != NULL)
      {
         //Debug message
         TRACE_INFO("Closing SSL/TLS session...\r\n");

         //Gracefully close SSL/TLS session
         tlsShutdown(connection->tlsContext);
         //Release context
         tlsFree(connection->tlsContext);
      }
#endif

      //Debug message
      TRACE_INFO("Graceful shutdown...\r\n");
      //Graceful shutdown
      socketShutdown(connection->socket, SOCKET_SD_BOTH);

      //Debug message
      TRACE_INFO("Closing socket...\r\n");
      //Close socket
      socketClose(connection->socket);

      //Ready to serve the next connection request...
      connection->running = FALSE;
      //Release semaphore
      osReleaseSemaphore(&connection->serverContext->semaphore);
   }
}
Beispiel #5
0
Socket *tcpAccept(Socket *socket, IpAddr *clientIpAddr, uint16_t *clientPort)
{
   error_t error;
   Socket *newSocket;
   TcpSynQueueItem *queueItem;

   //Ensure the socket was previously placed in the listening state
   if(tcpGetState(socket) != TCP_STATE_LISTEN)
      return NULL;

   //Enter critical section
   osAcquireMutex(&socketMutex);

   //Wait for an connection attempt
   while(1)
   {
      //The SYN queue is empty?
      if(!socket->synQueue)
      {
         //Set the events the application is interested in
         socket->eventMask = SOCKET_EVENT_RX_READY;
         //Reset the event object
         osResetEvent(&socket->event);
         //Leave critical section
         osReleaseMutex(&socketMutex);
         //Wait until a SYN message is received from a client
         osWaitForEvent(&socket->event, socket->timeout);
         //Enter critical section
         osAcquireMutex(&socketMutex);
      }

      //Check whether the queue is still empty
      if(!socket->synQueue)
      {
         //Timeout error
         newSocket = NULL;
         //Exit immediately
         break;
      }

      //Point to the first item in the receive queue
      queueItem = socket->synQueue;

      //Return the client IP address and port number
      if(clientIpAddr)
         *clientIpAddr = queueItem->srcAddr;
      if(clientPort)
         *clientPort = queueItem->srcPort;

      //Leave critical section
      osReleaseMutex(&socketMutex);
      //Create a new socket to handle the incoming connection request
      newSocket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP);
      //Enter critical section
      osAcquireMutex(&socketMutex);

      //Socket successfully created?
      if(newSocket != NULL)
      {
         //The user owns the socket
         newSocket->ownedFlag = TRUE;

         //Inherit settings from the listening socket
         newSocket->txBufferSize = socket->txBufferSize;
         newSocket->rxBufferSize = socket->rxBufferSize;

         //Number of chunks that comprise the TX and the RX buffers
         newSocket->txBuffer.maxChunkCount = arraysize(newSocket->txBuffer.chunk);
         newSocket->rxBuffer.maxChunkCount = arraysize(newSocket->rxBuffer.chunk);

         //Allocate transmit buffer
         error = netBufferSetLength((NetBuffer *) &newSocket->txBuffer, newSocket->txBufferSize);

         //Check status code
         if(!error)
         {
            //Allocate receive buffer
            error = netBufferSetLength((NetBuffer *) &newSocket->rxBuffer, newSocket->rxBufferSize);
         }

         //Transmit and receive buffers successfully allocated?
         if(!error)
         {
            //Bind the newly created socket to the appropriate interface
            newSocket->interface = queueItem->interface;
            //Bind the socket to the specified address
            newSocket->localIpAddr = queueItem->destAddr;
            newSocket->localPort = socket->localPort;
            //Save the port number and the IP address of the remote host
            newSocket->remoteIpAddr = queueItem->srcAddr;
            newSocket->remotePort = queueItem->srcPort;
            //Save the maximum segment size
            newSocket->mss = queueItem->mss;

            //Initialize TCP control block
            newSocket->iss = netGetRand();
            newSocket->irs = queueItem->isn;
            newSocket->sndUna = newSocket->iss;
            newSocket->sndNxt = newSocket->iss + 1;
            newSocket->rcvNxt = newSocket->irs + 1;
            newSocket->rcvUser = 0;
            newSocket->rcvWnd = newSocket->rxBufferSize;

            //Default retransmission timeout
            newSocket->rto = TCP_INITIAL_RTO;

#if (TCP_CONGESTION_CONTROL_SUPPORT == ENABLED)
            //Initial congestion window
            newSocket->cwnd = MIN(TCP_INITIAL_WINDOW * newSocket->mss, newSocket->txBufferSize);
            //Slow start threshold should be set arbitrarily high
            newSocket->ssthresh = UINT16_MAX;
#endif

            //Send a SYN ACK control segment
            error = tcpSendSegment(newSocket, TCP_FLAG_SYN | TCP_FLAG_ACK,
               newSocket->iss, newSocket->rcvNxt, 0, TRUE);

            //TCP segment successfully sent?
            if(!error)
            {
               //Remove the item from the SYN queue
               socket->synQueue = queueItem->next;
               //Deallocate memory buffer
               memPoolFree(queueItem);
               //Update the state of events
               tcpUpdateEvents(socket);

               //The connection state should be changed to SYN-RECEIVED
               tcpChangeState(newSocket, TCP_STATE_SYN_RECEIVED);

               //We are done...
               break;
            }
         }

         //Dispose the socket
         tcpAbort(newSocket);
      }

      //Debug message
      TRACE_WARNING("Cannot accept TCP connection!\r\n");

      //Remove the item from the SYN queue
      socket->synQueue = queueItem->next;
      //Deallocate memory buffer
      memPoolFree(queueItem);

      //Wait for the next connection attempt
   }

   //Leave critical section
   osReleaseMutex(&socketMutex);

   //Return a handle to the newly created socket
   return newSocket;
}