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