Ejemplo n.º 1
0
void tcpIpStackRxTask(void *param)
{
   //Point to the structure describing the network interface
   NetInterface *interface = (NetInterface *) param;

   //Main loop
   while(1)
   {
      //Receive notifications when a Ethernet frame has been received,
      //or the link status has changed
      osEventWait(interface->nicRxEvent, INFINITE_DELAY);

      //Get exclusive access to the device
      osMutexAcquire(interface->nicDriverMutex);
      //Disable Ethernet controller interrupts
      interface->nicDriver->disableIrq(interface);

      //Handle incoming packets and link state changes
      interface->nicDriver->rxEventHandler(interface);

      //Re-enable Ethernet controller interrupts
      interface->nicDriver->enableIrq(interface);
      //Release exclusive access to the device
      osMutexRelease(interface->nicDriverMutex);
   }
}
Ejemplo n.º 2
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
      osEventReset(socket->event);
      //Leave critical section
      osMutexRelease(socketMutex);
      //Wait until an event is triggered
      osEventWait(socket->event, socket->timeout);
      //Enter critical section
      osMutexAcquire(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;
}
Ejemplo n.º 3
0
error_t dhcpv6RelayStop(Dhcpv6RelayCtx *context)
{
   uint_t i;

   //Debug message
   TRACE_INFO("Stopping DHCPv6 relay agent...\r\n");

   //Ensure the specified pointer is valid
   if(!context)
      return ERROR_INVALID_PARAMETER;
   //Check DHCPv6 relay agent state
   if(!context->running)
      return ERROR_WRONG_STATE;

   //Reset ACK event before sending the kill signal
   osEventReset(context->ackEvent);
   //Stop the DHCPv6 relay agent task
   context->stopRequest = TRUE;
   //Send a signal to the task in order to abort any blocking operation
   osEventSet(context->event);

   //Wait for the process to terminate...
   osEventWait(context->ackEvent, INFINITE_DELAY);

   //Leave the All_DHCP_Relay_Agents_and_Servers multicast group
   //for each client-facing interface
   dhcpv6RelayLeaveMulticastGroup(context);

   //Close the socket that carries traffic towards the DHCPv6 server
   socketClose(context->serverSocket);

   //Properly dispose the sockets that carry traffic towards the DHCPv6 clients
   for(i = 0; i < context->clientInterfaceCount; i++)
      socketClose(context->clientSocket[i]);

   //Close event objects
   osEventClose(context->event);
   osEventClose(context->ackEvent);

   //Successful processing
   return NO_ERROR;
}
Ejemplo n.º 4
0
int_t select(int_t nfds, fd_set *readfds, fd_set *writefds,
   fd_set *exceptfds, const timeval *timeout)
{
   int_t i;
   int_t j;
   int_t n;
   int_t s;
   time_t time;
   uint_t eventMask;
   uint_t eventFlags;
   OsEvent *event;
   fd_set *fds;

   //Create an event object to get notified of socket events
   event = osEventCreate(FALSE, FALSE);

   //Any error to report?
   if(event == OS_INVALID_HANDLE)
   {
      socketError(NULL, ERROR_OUT_OF_RESOURCES);
      return SOCKET_ERROR;
   }

   //Parse all the descriptor sets
   for(i = 0; i < 3; i ++)
   {
      //Select the suitable descriptor set
      switch(i)
      {
      case 0:
         //Set of sockets to be checked for readability
         fds = readfds;
         eventMask = SOCKET_EVENT_RX_READY;
         break;
      case 1:
         //Set of sockets to be checked for writability
         fds = writefds;
         eventMask = SOCKET_EVENT_TX_READY;
         break;
      default:
         //Set of sockets to be checked for errors
         fds = exceptfds;
         eventMask = SOCKET_EVENT_CLOSED;
         break;
      }

      //Each descriptor is optional and may be omitted
      if(fds != NULL)
      {
         //Parse the current set of sockets
         for(j = 0; j < fds->fd_count; j++)
         {
            //Get the descriptor associated with the current entry
            s = fds->fd_array[j];
            //Subscribe to the requested events
            socketRegisterEvents(&socketTable[s], event, eventMask);
         }
      }
   }

   //Retrieve timeout value
   if(timeout != NULL)
      time = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
   else
      time = INFINITE_DELAY;

   //Block the current task until an event occurs
   osEventWait(event, time);

   //Count the number of events in the signaled state
   n = 0;

   //Parse all the descriptor sets
   for(i = 0; i < 3; i ++)
   {
      //Select the suitable descriptor set
      switch(i)
      {
      case 0:
         //Set of sockets to be checked for readability
         fds = readfds;
         eventMask = SOCKET_EVENT_RX_READY;
         break;
      case 1:
         //Set of sockets to be checked for writability
         fds = writefds;
         eventMask = SOCKET_EVENT_TX_READY;
         break;
      default:
         //Set of sockets to be checked for errors
         fds = exceptfds;
         eventMask = SOCKET_EVENT_CLOSED;
         break;
      }

      //Each descriptor is optional and may be omitted
      if(fds != NULL)
      {
         //Parse the current set of sockets
         for(j = 0; j < fds->fd_count; )
         {
            //Get the descriptor associated with the current entry
            s = fds->fd_array[j];
            //Retrieve event flags for the current socket
            socketGetEvents(&socketTable[s], &eventFlags);
            //Unsubscribe previously registered events
            socketUnregisterEvents(&socketTable[s]);

            //Event flag is set?
            if(eventFlags & eventMask)
            {
               //Track the number of events in the signaled state
               n++;
               //Jump to the next socket descriptor
               j++;
            }
            else
            {
               //Remove descriptor from the current set
               selectFdClr(fds, s);
            }
         }
      }
   }

   //Close event
   osEventClose(event);
   //Return the number of events in the signaled state
   return n;
}
Ejemplo n.º 5
0
Socket *tcpAccept(Socket *socket, IpAddr *clientIpAddr, uint16_t *clientPort)
{
   error_t error;
   TcpSynQueueItem *queueItem;
   Socket *newSocket;

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

   //Enter critical section
   osMutexAcquire(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
         osEventReset(socket->event);
         //Leave critical section
         osMutexRelease(socketMutex);
         //Wait until a SYN message is received from a client
         osEventWait(socket->event, socket->timeout);
         //Enter critical section
         osMutexAcquire(socketMutex);
      }

      //Check whether the queue is still empty
      if(!socket->synQueue)
      {
         //Leave critical section
         osMutexRelease(socketMutex);
         //Timeout error
         return NULL;
      }

      //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
      osMutexRelease(socketMutex);

      //Create a new socket to handle the incoming connection request
      newSocket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_PROTOCOL_TCP);
      //Failed to open socket?
      if(!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
         continue;
      }

      //Enter critical section
      osMutexAcquire(socketMutex);

      //The user owns the socket
      newSocket->ownedFlag = TRUE;

      //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 = chunkedBufferSetLength((ChunkedBuffer *) &newSocket->txBuffer, newSocket->txBufferSize);
      //Allocate receive buffer
      if(!error)
         error = chunkedBufferSetLength((ChunkedBuffer *) &newSocket->rxBuffer, newSocket->rxBufferSize);

      //Failed to allocate memory?
      if(error)
      {
         //Debug message
         TRACE_WARNING("Cannot accept TCP connection!\r\n");

         //Properly close the socket
         tcpAbort(newSocket);
         //Remove the item from the SYN queue
         socket->synQueue = queueItem->next;
         //Deallocate memory buffer
         memPoolFree(queueItem);
         //Wait for the next connection attempt
         continue;
      }

      //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 = rand();
      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;
      //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;

      //Send a SYN ACK control segment
      error = tcpSendSegment(newSocket, TCP_FLAG_SYN | TCP_FLAG_ACK,
         newSocket->iss, newSocket->rcvNxt, 0, TRUE);
      //Failed to send TCP segment?
      if(error)
      {
         //Debug message
         TRACE_WARNING("Cannot accept TCP connection!\r\n");

         //Close previously created socket
         tcpAbort(newSocket);
         //Remove the item from the SYN queue
         socket->synQueue = queueItem->next;
         //Deallocate memory buffer
         memPoolFree(queueItem);
         //Wait for the next connection attempt
         continue;
      }

      //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);

      //Leave critical section
      osMutexRelease(socketMutex);
      //Return a handle to the newly created socket
      return newSocket;
   }
}
Ejemplo n.º 6
0
void icecastClientTask(void *param)
{
   error_t error;
   bool_t end;
   size_t n;
   size_t length;
   size_t received;
   IcecastClientContext *context;

   //Retrieve the Icecast client context
   context = (IcecastClientContext *) param;

   //Main loop
   while(1)
   {
      //Initiate a connection to the Icecast server
      error = icecastClientConnect(context);

      //Connection to server failed?
      if(error)
      {
         //Debug message
         TRACE_ERROR("Connection to Icecast server failed!\r\n");
         //Recovery delay
         osDelay(ICECAST_RECOVERY_DELAY);
         //Try to reconnect...
         continue;
      }

      //Debug message
      TRACE_INFO("Block size = %u\r\n", context->blockSize);

      //Check block size
      if(!context->blockSize)
      {
         socketClose(context->socket);
         continue;
      }

      //Initialize loop condition variable
      end = FALSE;

      //Read as much data as possible...
      while(!end)
      {
         //Process the stream block by block
         length = context->blockSize;

         //Read current block
         while(!end && length > 0)
         {
            //Wait for the buffer to be available for writing
            osEventWait(context->writeEvent, INFINITE_DELAY);

            //Enter critical section
            osMutexAcquire(context->mutex);
            //Compute the number of bytes to read at a time
            n = min(length, context->bufferSize - context->bufferLength);
            //Leave critical section
            osMutexRelease(context->mutex);

            //Check whether the specified data crosses buffer boundaries
            if((context->writeIndex + n) > context->bufferSize)
               n = context->bufferSize - context->writeIndex;

            //Receive data
            error = socketReceive(context->socket, context->streamBuffer +
               context->writeIndex, n, &received, SOCKET_FLAG_WAIT_ALL);

            //Make sure the expected number of bytes have been received
            if(error || received != n)
               end = TRUE;

            //Enter critical section
            osMutexAcquire(context->mutex);

            //Increment write index
            context->writeIndex += n;
            //Wrap around if necessary
            if(context->writeIndex >= context->bufferSize)
               context->writeIndex -= context->bufferSize;

            //Update buffer length
            context->bufferLength += n;
            //Check whether the buffer is available for writing
            if(context->bufferLength < context->bufferSize)
               osEventSet(context->writeEvent);
            //Check whether the buffer is available for reading
            if(context->bufferLength > 0)
               osEventSet(context->readEvent);

            //Leave critical section
            osMutexRelease(context->mutex);

            //Update the total number of bytes that have been received
            context->totalLength += n;
            //Number of remaining data to read
            length -= n;
         }

         //Debug message
         TRACE_DEBUG("Total bytes received = %u\r\n", context->totalLength);

         //Check whether the metadata block should be read
         if(!end)
         {
            //Process the metadata block
            error = icecastClientProcessMetadata(context);
            //Any error to report?
            if(error) end = TRUE;
         }
      }

      //Close connection
      socketClose(context->socket);
   }
}
Ejemplo n.º 7
0
error_t icecastClientReadStream(IcecastClientContext *context,
   uint8_t *data, size_t size, size_t *length, time_t timeout)
{
   bool_t status;

   //Ensure the parameters are valid
   if(!context || !data)
      return ERROR_INVALID_PARAMETER;

   //Wait for the buffer to be available for reading
   status = osEventWait(context->readEvent, timeout);
   //Timeout error?
   if(!status) return ERROR_TIMEOUT;

   //Enter critical section
   osMutexAcquire(context->mutex);
   //Compute the number of bytes to read at a time
   *length = min(size, context->bufferLength);
   //Leave critical section
   osMutexRelease(context->mutex);

   //Check whether the specified data crosses buffer boundaries
   if((context->readIndex + *length) <= context->bufferSize)
   {
      //Copy the data
      memcpy(data, context->streamBuffer + context->readIndex, *length);
   }
   else
   {
      //Copy the first part of the data
      memcpy(data, context->streamBuffer + context->readIndex,
         context->bufferSize - context->readIndex);
      //Wrap around to the beginning of the circular buffer
      memcpy(data + context->bufferSize - context->readIndex, context->streamBuffer,
         *length - context->bufferSize + context->readIndex);
   }

   //Enter critical section
   osMutexAcquire(context->mutex);

   //Increment read index
   context->readIndex += *length;
   //Wrap around if necessary
   if(context->readIndex >= context->bufferSize)
      context->readIndex -= context->bufferSize;

   //Update buffer length
   context->bufferLength -= *length;
   //Check whether the buffer is available for writing
   if(context->bufferLength < context->bufferSize)
      osEventSet(context->writeEvent);
   //Check whether the buffer is available for reading
   if(context->bufferLength > 0)
      osEventSet(context->readEvent);

   //Leave critical section
   osMutexRelease(context->mutex);

   //Successful read operation
   return NO_ERROR;
}