void socketClose(Socket *socket) { //Make sure the socket handle is valid if(!socket) return; //Enter critical section osAcquireMutex(&socketMutex); #if (TCP_SUPPORT == ENABLED) //Connection-oriented socket? if(socket->type == SOCKET_TYPE_STREAM) { //Abort the current TCP connection tcpAbort(socket); } #endif #if (UDP_SUPPORT == ENABLED || RAW_SOCKET_SUPPORT == ENABLED) //Connectionless socket or raw socket? if(socket->type == SOCKET_TYPE_DGRAM || socket->type == SOCKET_TYPE_RAW_IP || socket->type == SOCKET_TYPE_RAW_ETH) { //Point to the first item in the receive queue SocketQueueItem *queueItem = socket->receiveQueue; //Purge the receive queue while(queueItem) { //Keep track of the next item in the queue SocketQueueItem *nextQueueItem = queueItem->next; //Free previously allocated memory memPoolFree(queueItem); //Point to the next item queueItem = nextQueueItem; } //Mark the socket as closed socket->type = SOCKET_TYPE_UNUSED; } #endif //Leave critical section osReleaseMutex(&socketMutex); }
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; }