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