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