Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
tcp.c
00001 /** 00002 * @file tcp.c 00003 * @brief TCP (Transmission Control Protocol) 00004 * 00005 * @section License 00006 * 00007 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. 00008 * 00009 * This file is part of CycloneTCP Open. 00010 * 00011 * This program is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU General Public License 00013 * as published by the Free Software Foundation; either version 2 00014 * of the License, or (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program; if not, write to the Free Software Foundation, 00023 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00024 * 00025 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00026 * @version 1.7.6 00027 **/ 00028 00029 //Switch to the appropriate trace level 00030 #define TRACE_LEVEL TCP_TRACE_LEVEL 00031 00032 //Dependencies 00033 #include <string.h> 00034 #include "core/net.h" 00035 #include "core/socket.h" 00036 #include "core/tcp.h" 00037 #include "core/tcp_misc.h" 00038 #include "core/tcp_timer.h" 00039 #include "mibs/mib2_module.h" 00040 #include "debug.h" 00041 00042 //Check TCP/IP stack configuration 00043 #if (TCP_SUPPORT == ENABLED) 00044 00045 //Tick counter to handle periodic operations 00046 systime_t tcpTickCounter; 00047 00048 //Ephemeral ports are used for dynamic port assignment 00049 static uint16_t tcpDynamicPort; 00050 00051 00052 /** 00053 * @brief TCP related initialization 00054 * @return Error code 00055 **/ 00056 00057 error_t tcpInit(void) 00058 { 00059 //Reset ephemeral port number 00060 tcpDynamicPort = 0; 00061 00062 //Successful initialization 00063 return NO_ERROR; 00064 } 00065 00066 00067 /** 00068 * @brief Get an ephemeral port number 00069 * @return Ephemeral port 00070 **/ 00071 00072 uint16_t tcpGetDynamicPort(void) 00073 { 00074 uint_t port; 00075 00076 //Retrieve current port number 00077 port = tcpDynamicPort; 00078 00079 //Invalid port number? 00080 if(port < SOCKET_EPHEMERAL_PORT_MIN || port > SOCKET_EPHEMERAL_PORT_MAX) 00081 { 00082 //Generate a random port number 00083 port = SOCKET_EPHEMERAL_PORT_MIN + netGetRand() % 00084 (SOCKET_EPHEMERAL_PORT_MAX - SOCKET_EPHEMERAL_PORT_MIN + 1); 00085 } 00086 00087 //Next dynamic port to use 00088 if(port < SOCKET_EPHEMERAL_PORT_MAX) 00089 { 00090 //Increment port number 00091 tcpDynamicPort = port + 1; 00092 } 00093 else 00094 { 00095 //Wrap around if necessary 00096 tcpDynamicPort = SOCKET_EPHEMERAL_PORT_MIN; 00097 } 00098 00099 //Return an ephemeral port number 00100 return port; 00101 } 00102 00103 00104 /** 00105 * @brief Establish a TCP connection 00106 * @param[in] socket Handle to an unconnected socket 00107 * @param[in] remoteIpAddr IP address of the remote host 00108 * @param[in] remotePort Remote port number that will be used to establish the connection 00109 * @return Error code 00110 **/ 00111 00112 error_t tcpConnect(Socket *socket, const IpAddr *remoteIpAddr, uint16_t remotePort) 00113 { 00114 error_t error; 00115 uint_t event; 00116 00117 //Check current TCP state 00118 if(socket->state == TCP_STATE_CLOSED) 00119 { 00120 //Save port number and IP address of the remote host 00121 socket->remoteIpAddr = *remoteIpAddr; 00122 socket->remotePort = remotePort; 00123 00124 //Select the source address and the relevant network interface 00125 //to use when establishing the connection 00126 error = ipSelectSourceAddr(&socket->interface, 00127 &socket->remoteIpAddr, &socket->localIpAddr); 00128 //Any error to report? 00129 if(error) 00130 return error; 00131 00132 //Make sure the source address is valid 00133 if(ipIsUnspecifiedAddr(&socket->localIpAddr)) 00134 return ERROR_NOT_CONFIGURED; 00135 00136 //The user owns the socket 00137 socket->ownedFlag = TRUE; 00138 00139 //Number of chunks that comprise the TX and the RX buffers 00140 socket->txBuffer.maxChunkCount = arraysize(socket->txBuffer.chunk); 00141 socket->rxBuffer.maxChunkCount = arraysize(socket->rxBuffer.chunk); 00142 00143 //Allocate transmit buffer 00144 error = netBufferSetLength((NetBuffer *) &socket->txBuffer, 00145 socket->txBufferSize); 00146 00147 //Allocate receive buffer 00148 if(!error) 00149 { 00150 error = netBufferSetLength((NetBuffer *) &socket->rxBuffer, 00151 socket->rxBufferSize); 00152 } 00153 00154 //Failed to allocate memory? 00155 if(error) 00156 { 00157 //Free any previously allocated memory 00158 tcpDeleteControlBlock(socket); 00159 //Report an error to the caller 00160 return error; 00161 } 00162 00163 //The SMSS is the size of the largest segment that the sender can transmit 00164 socket->smss = MIN(TCP_DEFAULT_MSS, TCP_MAX_MSS); 00165 //The RMSS is the size of the largest segment the receiver is willing to accept 00166 socket->rmss = MIN(socket->rxBufferSize, TCP_MAX_MSS); 00167 00168 //An initial send sequence number is selected 00169 socket->iss = netGetRand(); 00170 00171 //Initialize TCP control block 00172 socket->sndUna = socket->iss; 00173 socket->sndNxt = socket->iss + 1; 00174 socket->rcvUser = 0; 00175 socket->rcvWnd = socket->rxBufferSize; 00176 00177 //Default retransmission timeout 00178 socket->rto = TCP_INITIAL_RTO; 00179 00180 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED) 00181 //Default congestion state 00182 socket->congestState = TCP_CONGEST_STATE_IDLE; 00183 //Initial congestion window 00184 socket->cwnd = MIN(TCP_INITIAL_WINDOW * socket->smss, socket->txBufferSize); 00185 //Slow start threshold should be set arbitrarily high 00186 socket->ssthresh = UINT16_MAX; 00187 //Recover is set to the initial send sequence number 00188 socket->recover = socket->iss; 00189 #endif 00190 00191 //Send a SYN segment 00192 error = tcpSendSegment(socket, TCP_FLAG_SYN, socket->iss, 0, 0, TRUE); 00193 //Failed to send TCP segment? 00194 if(error) 00195 return error; 00196 00197 //Switch to the SYN-SENT state 00198 tcpChangeState(socket, TCP_STATE_SYN_SENT); 00199 00200 //Number of times TCP connections have made a direct transition to 00201 //the SYN-SENT state from the CLOSED state 00202 MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpActiveOpens, 1); 00203 } 00204 00205 //Wait for the connection to be established 00206 event = tcpWaitForEvents(socket, SOCKET_EVENT_CONNECTED | 00207 SOCKET_EVENT_CLOSED, socket->timeout); 00208 00209 //Connection successfully established? 00210 if(event == SOCKET_EVENT_CONNECTED) 00211 return NO_ERROR; 00212 //Failed to establish connection? 00213 else if(event == SOCKET_EVENT_CLOSED) 00214 return ERROR_CONNECTION_FAILED; 00215 //Timeout exception? 00216 else 00217 return ERROR_TIMEOUT; 00218 } 00219 00220 00221 /** 00222 * @brief Place a socket in the listening state 00223 * 00224 * Place a socket in a state in which it is listening for an incoming connection 00225 * 00226 * @param[in] socket Socket to place in the listening state 00227 * @param[in] backlog backlog The maximum length of the pending connection queue. 00228 * If this parameter is zero, then the default backlog value is used instead 00229 * @return Error code 00230 **/ 00231 00232 error_t tcpListen(Socket *socket, uint_t backlog) 00233 { 00234 //Socket already connected? 00235 if(socket->state != TCP_STATE_CLOSED) 00236 return ERROR_ALREADY_CONNECTED; 00237 00238 //Set the size of the SYN queue 00239 socket->synQueueSize = (backlog > 0) ? backlog : TCP_DEFAULT_SYN_QUEUE_SIZE; 00240 //Limit the number of pending connections 00241 socket->synQueueSize = MIN(socket->synQueueSize, TCP_MAX_SYN_QUEUE_SIZE); 00242 00243 //Place the socket in the listening state 00244 tcpChangeState(socket, TCP_STATE_LISTEN); 00245 00246 //Successful processing 00247 return NO_ERROR; 00248 } 00249 00250 00251 /** 00252 * @brief Permit an incoming connection attempt on a TCP socket 00253 * @param[in] socket Handle to a socket previously placed in a listening state 00254 * @param[out] clientIpAddr IP address of the client 00255 * @param[out] clientPort Port number used by the client 00256 * @return Handle to the socket in which the actual connection is made 00257 **/ 00258 00259 Socket *tcpAccept(Socket *socket, IpAddr *clientIpAddr, uint16_t *clientPort) 00260 { 00261 error_t error; 00262 Socket *newSocket; 00263 TcpSynQueueItem *queueItem; 00264 00265 //Ensure the socket was previously placed in the listening state 00266 if(tcpGetState(socket) != TCP_STATE_LISTEN) 00267 return NULL; 00268 00269 //Get exclusive access 00270 osAcquireMutex(&netMutex); 00271 00272 //Wait for an connection attempt 00273 while(1) 00274 { 00275 //The SYN queue is empty? 00276 if(!socket->synQueue) 00277 { 00278 //Set the events the application is interested in 00279 socket->eventMask = SOCKET_EVENT_RX_READY; 00280 //Reset the event object 00281 osResetEvent(&socket->event); 00282 00283 //Release exclusive access 00284 osReleaseMutex(&netMutex); 00285 //Wait until a SYN message is received from a client 00286 osWaitForEvent(&socket->event, socket->timeout); 00287 //Get exclusive access 00288 osAcquireMutex(&netMutex); 00289 } 00290 00291 //Check whether the queue is still empty 00292 if(!socket->synQueue) 00293 { 00294 //Timeout error 00295 newSocket = NULL; 00296 //Exit immediately 00297 break; 00298 } 00299 00300 //Point to the first item in the receive queue 00301 queueItem = socket->synQueue; 00302 00303 //Return the client IP address and port number 00304 if(clientIpAddr) 00305 *clientIpAddr = queueItem->srcAddr; 00306 if(clientPort) 00307 *clientPort = queueItem->srcPort; 00308 00309 //Release exclusive access 00310 osReleaseMutex(&netMutex); 00311 //Create a new socket to handle the incoming connection request 00312 newSocket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP); 00313 //Get exclusive access 00314 osAcquireMutex(&netMutex); 00315 00316 //Socket successfully created? 00317 if(newSocket != NULL) 00318 { 00319 //The user owns the socket 00320 newSocket->ownedFlag = TRUE; 00321 00322 //Inherit settings from the listening socket 00323 newSocket->txBufferSize = socket->txBufferSize; 00324 newSocket->rxBufferSize = socket->rxBufferSize; 00325 00326 //Number of chunks that comprise the TX and the RX buffers 00327 newSocket->txBuffer.maxChunkCount = arraysize(newSocket->txBuffer.chunk); 00328 newSocket->rxBuffer.maxChunkCount = arraysize(newSocket->rxBuffer.chunk); 00329 00330 //Allocate transmit buffer 00331 error = netBufferSetLength((NetBuffer *) &newSocket->txBuffer, newSocket->txBufferSize); 00332 00333 //Check status code 00334 if(!error) 00335 { 00336 //Allocate receive buffer 00337 error = netBufferSetLength((NetBuffer *) &newSocket->rxBuffer, newSocket->rxBufferSize); 00338 } 00339 00340 //Transmit and receive buffers successfully allocated? 00341 if(!error) 00342 { 00343 //Bind the newly created socket to the appropriate interface 00344 newSocket->interface = queueItem->interface; 00345 00346 //Bind the socket to the specified address 00347 newSocket->localIpAddr = queueItem->destAddr; 00348 newSocket->localPort = socket->localPort; 00349 //Save the port number and the IP address of the remote host 00350 newSocket->remoteIpAddr = queueItem->srcAddr; 00351 newSocket->remotePort = queueItem->srcPort; 00352 00353 //The SMSS is the size of the largest segment that the sender 00354 //can transmit 00355 newSocket->smss = queueItem->mss; 00356 00357 //The RMSS is the size of the largest segment the receiver is 00358 //willing to accept 00359 newSocket->rmss = MIN(newSocket->rxBufferSize, TCP_MAX_MSS); 00360 00361 //Initialize TCP control block 00362 newSocket->iss = netGetRand(); 00363 newSocket->irs = queueItem->isn; 00364 newSocket->sndUna = newSocket->iss; 00365 newSocket->sndNxt = newSocket->iss + 1; 00366 newSocket->rcvNxt = newSocket->irs + 1; 00367 newSocket->rcvUser = 0; 00368 newSocket->rcvWnd = newSocket->rxBufferSize; 00369 00370 //Default retransmission timeout 00371 newSocket->rto = TCP_INITIAL_RTO; 00372 00373 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED) 00374 //Default congestion state 00375 socket->congestState = TCP_CONGEST_STATE_IDLE; 00376 //Initial congestion window 00377 newSocket->cwnd = MIN(TCP_INITIAL_WINDOW * newSocket->smss, newSocket->txBufferSize); 00378 //Slow start threshold should be set arbitrarily high 00379 newSocket->ssthresh = UINT16_MAX; 00380 //Recover is set to the initial send sequence number 00381 newSocket->recover = newSocket->iss; 00382 #endif 00383 //Send a SYN ACK control segment 00384 error = tcpSendSegment(newSocket, TCP_FLAG_SYN | TCP_FLAG_ACK, 00385 newSocket->iss, newSocket->rcvNxt, 0, TRUE); 00386 00387 //TCP segment successfully sent? 00388 if(!error) 00389 { 00390 //Remove the item from the SYN queue 00391 socket->synQueue = queueItem->next; 00392 //Deallocate memory buffer 00393 memPoolFree(queueItem); 00394 //Update the state of events 00395 tcpUpdateEvents(socket); 00396 00397 //The connection state should be changed to SYN-RECEIVED 00398 tcpChangeState(newSocket, TCP_STATE_SYN_RECEIVED); 00399 00400 //Number of times TCP connections have made a direct transition to 00401 //the SYN-RECEIVED state from the LISTEN state 00402 MIB2_INC_COUNTER32(mib2Base.tcpGroup.tcpPassiveOpens, 1); 00403 00404 //We are done... 00405 break; 00406 } 00407 } 00408 00409 //Dispose the socket 00410 tcpAbort(newSocket); 00411 } 00412 00413 //Debug message 00414 TRACE_WARNING("Cannot accept TCP connection!\r\n"); 00415 00416 //Remove the item from the SYN queue 00417 socket->synQueue = queueItem->next; 00418 //Deallocate memory buffer 00419 memPoolFree(queueItem); 00420 00421 //Wait for the next connection attempt 00422 } 00423 00424 //Release exclusive access 00425 osReleaseMutex(&netMutex); 00426 00427 //Return a handle to the newly created socket 00428 return newSocket; 00429 } 00430 00431 00432 /** 00433 * @brief Send data to a connected socket 00434 * @param[in] socket Handle that identifies a connected socket 00435 * @param[in] data Pointer to a buffer containing the data to be transmitted 00436 * @param[in] length Number of bytes to be transmitted 00437 * @param[out] written Actual number of bytes written (optional parameter) 00438 * @param[in] flags Set of flags that influences the behavior of this function 00439 * @return Error code 00440 **/ 00441 00442 error_t tcpSend(Socket *socket, const uint8_t *data, 00443 size_t length, size_t *written, uint_t flags) 00444 { 00445 uint_t n; 00446 uint_t totalLength; 00447 uint_t event; 00448 00449 //Check whether the socket is in the listening state 00450 if(socket->state == TCP_STATE_LISTEN) 00451 return ERROR_NOT_CONNECTED; 00452 00453 //Actual number of bytes written 00454 totalLength = 0; 00455 00456 //Send as much data as possible 00457 do 00458 { 00459 //Wait until there is more room in the send buffer 00460 event = tcpWaitForEvents(socket, SOCKET_EVENT_TX_READY, socket->timeout); 00461 00462 //A timeout exception occurred? 00463 if(event != SOCKET_EVENT_TX_READY) 00464 return ERROR_TIMEOUT; 00465 00466 //Check current TCP state 00467 switch(socket->state) 00468 { 00469 //ESTABLISHED or CLOSE-WAIT state? 00470 case TCP_STATE_ESTABLISHED: 00471 case TCP_STATE_CLOSE_WAIT: 00472 //The send buffer is now available for writing 00473 break; 00474 00475 //LAST-ACK, FIN-WAIT-1, FIN-WAIT-2, CLOSING or TIME-WAIT state? 00476 case TCP_STATE_LAST_ACK: 00477 case TCP_STATE_FIN_WAIT_1: 00478 case TCP_STATE_FIN_WAIT_2: 00479 case TCP_STATE_CLOSING: 00480 case TCP_STATE_TIME_WAIT: 00481 //The connection is being closed 00482 return ERROR_CONNECTION_CLOSING; 00483 00484 //CLOSED state? 00485 default: 00486 //The connection was reset by remote side? 00487 return (socket->resetFlag) ? ERROR_CONNECTION_RESET : ERROR_NOT_CONNECTED; 00488 } 00489 00490 //Determine the actual number of bytes in the send buffer 00491 n = socket->sndUser + socket->sndNxt - socket->sndUna; 00492 //Exit immediately if the transmission buffer is full (sanity check) 00493 if(n >= socket->txBufferSize) 00494 return ERROR_FAILURE; 00495 00496 //Number of bytes available for writing 00497 n = socket->txBufferSize - n; 00498 //Calculate the number of bytes to copy at a time 00499 n = MIN(n, length - totalLength); 00500 00501 //Any data to copy? 00502 if(n > 0) 00503 { 00504 //Copy user data to send buffer 00505 tcpWriteTxBuffer(socket, socket->sndNxt + socket->sndUser, data, n); 00506 00507 //Update the number of data buffered but not yet sent 00508 socket->sndUser += n; 00509 //Advance data pointer 00510 data += n; 00511 //Update byte counter 00512 totalLength += n; 00513 00514 //Total number of data that have been written 00515 if(written != NULL) 00516 *written = totalLength; 00517 00518 //Update TX events 00519 tcpUpdateEvents(socket); 00520 00521 //To avoid a deadlock, it is necessary to have a timeout to force 00522 //transmission of data, overriding the SWS avoidance algorithm. In 00523 //practice, this timeout should seldom occur (see RFC 1122 4.2.3.4) 00524 if(socket->sndUser == n) 00525 tcpTimerStart(&socket->overrideTimer, TCP_OVERRIDE_TIMEOUT); 00526 } 00527 00528 //The Nagle algorithm should be implemented to coalesce 00529 //short segments (refer to RFC 1122 4.2.3.4) 00530 tcpNagleAlgo(socket, flags); 00531 00532 //Send as much data as possible 00533 } while(totalLength < length); 00534 00535 //The SOCKET_FLAG_WAIT_ACK flag causes the function to 00536 //wait for acknowledgment from the remote side 00537 if(flags & SOCKET_FLAG_WAIT_ACK) 00538 { 00539 //Wait for the data to be acknowledged 00540 event = tcpWaitForEvents(socket, SOCKET_EVENT_TX_ACKED, socket->timeout); 00541 00542 //A timeout exception occurred? 00543 if(event != SOCKET_EVENT_TX_ACKED) 00544 return ERROR_TIMEOUT; 00545 00546 //The connection was closed before an acknowledgment was received? 00547 if(socket->state != TCP_STATE_ESTABLISHED && socket->state != TCP_STATE_CLOSE_WAIT) 00548 return ERROR_NOT_CONNECTED; 00549 } 00550 00551 //Successful write operation 00552 return NO_ERROR; 00553 } 00554 00555 00556 /** 00557 * @brief Receive data from a connected socket 00558 * @param[in] socket Handle that identifies a connected socket 00559 * @param[out] data Buffer where to store the incoming data 00560 * @param[in] size Maximum number of bytes that can be received 00561 * @param[out] received Number of bytes that have been received 00562 * @param[in] flags Set of flags that influences the behavior of this function 00563 * @return Error code 00564 **/ 00565 00566 error_t tcpReceive(Socket *socket, uint8_t *data, 00567 size_t size, size_t *received, uint_t flags) 00568 { 00569 uint_t i; 00570 uint_t n; 00571 uint_t event; 00572 uint32_t seqNum; 00573 systime_t timeout; 00574 00575 //Retrieve the break character code 00576 char_t c = LSB(flags); 00577 //No data has been read yet 00578 *received = 0; 00579 00580 //Check whether the socket is in the listening state 00581 if(socket->state == TCP_STATE_LISTEN) 00582 return ERROR_NOT_CONNECTED; 00583 00584 //Read as much data as possible 00585 while(*received < size) 00586 { 00587 //The SOCKET_FLAG_DONT_WAIT enables non-blocking operation 00588 timeout = (flags & SOCKET_FLAG_DONT_WAIT) ? 0 : socket->timeout; 00589 //Wait for data to be available for reading 00590 event = tcpWaitForEvents(socket, SOCKET_EVENT_RX_READY, timeout); 00591 00592 //A timeout exception occurred? 00593 if(event != SOCKET_EVENT_RX_READY) 00594 return ERROR_TIMEOUT; 00595 00596 //Check current TCP state 00597 switch(socket->state) 00598 { 00599 //ESTABLISHED, FIN-WAIT-1 or FIN-WAIT-2 state? 00600 case TCP_STATE_ESTABLISHED: 00601 case TCP_STATE_FIN_WAIT_1: 00602 case TCP_STATE_FIN_WAIT_2: 00603 //Sequence number of the first byte to read 00604 seqNum = socket->rcvNxt - socket->rcvUser; 00605 //Data is available in the receive buffer 00606 break; 00607 00608 //CLOSE-WAIT, LAST-ACK, CLOSING or TIME-WAIT state? 00609 case TCP_STATE_CLOSE_WAIT: 00610 case TCP_STATE_LAST_ACK: 00611 case TCP_STATE_CLOSING: 00612 case TCP_STATE_TIME_WAIT: 00613 //The user must be satisfied with data already on hand 00614 if(!socket->rcvUser) 00615 { 00616 if(*received > 0) 00617 return NO_ERROR; 00618 else 00619 return ERROR_END_OF_STREAM; 00620 } 00621 00622 //Sequence number of the first byte to read 00623 seqNum = (socket->rcvNxt - 1) - socket->rcvUser; 00624 //Data is available in the receive buffer 00625 break; 00626 00627 //CLOSED state? 00628 default: 00629 //The connection was reset by remote side? 00630 if(socket->resetFlag) 00631 return ERROR_CONNECTION_RESET; 00632 //The connection has not yet been established? 00633 if(!socket->closedFlag) 00634 return ERROR_NOT_CONNECTED; 00635 00636 //The user must be satisfied with data already on hand 00637 if(!socket->rcvUser) 00638 { 00639 if(*received > 0) 00640 return NO_ERROR; 00641 else 00642 return ERROR_END_OF_STREAM; 00643 } 00644 00645 //Sequence number of the first byte to read 00646 seqNum = (socket->rcvNxt - 1) - socket->rcvUser; 00647 //Data is available in the receive buffer 00648 break; 00649 } 00650 00651 //Sanity check 00652 if(!socket->rcvUser) 00653 return ERROR_FAILURE; 00654 00655 //Calculate the number of bytes to read at a time 00656 n = MIN(socket->rcvUser, size - *received); 00657 //Copy data from circular buffer 00658 tcpReadRxBuffer(socket, seqNum, data, n); 00659 00660 //Read data until a break character is encountered? 00661 if(flags & SOCKET_FLAG_BREAK_CHAR) 00662 { 00663 //Search for the specified break character 00664 for(i = 0; i < n && data[i] != c; i++); 00665 //Adjust the number of data to read 00666 n = MIN(n, i + 1); 00667 } 00668 00669 //Total number of data that have been read 00670 *received += n; 00671 //Remaining data still available in the receive buffer 00672 socket->rcvUser -= n; 00673 00674 //Update the receive window 00675 tcpUpdateReceiveWindow(socket); 00676 //Update RX event state 00677 tcpUpdateEvents(socket); 00678 00679 //The SOCKET_FLAG_BREAK_CHAR flag causes the function to stop reading 00680 //data as soon as the specified break character is encountered 00681 if(flags & SOCKET_FLAG_BREAK_CHAR) 00682 { 00683 //Check whether a break character has been found 00684 if(data[n - 1] == c) 00685 break; 00686 } 00687 //The SOCKET_FLAG_WAIT_ALL flag causes the function to return 00688 //only when the requested number of bytes have been read 00689 else if(!(flags & SOCKET_FLAG_WAIT_ALL)) 00690 { 00691 break; 00692 } 00693 00694 //Advance data pointer 00695 data += n; 00696 } 00697 00698 //Successful read operation 00699 return NO_ERROR; 00700 } 00701 00702 00703 /** 00704 * @brief Shutdown gracefully reception, transmission, or both 00705 * 00706 * Note that socketShutdown() does not close the socket, and resources attached 00707 * to the socket will not be freed until socketClose() is invoked 00708 * 00709 * @param[in] socket Handle to a socket 00710 * @param[in] how Flag that describes what types of operation will no longer be allowed 00711 * @return Error code 00712 **/ 00713 00714 error_t tcpShutdown(Socket *socket, uint_t how) 00715 { 00716 error_t error; 00717 uint_t event; 00718 00719 //Disable transmission? 00720 if(how == SOCKET_SD_SEND || how == SOCKET_SD_BOTH) 00721 { 00722 //Check current state 00723 switch(socket->state) 00724 { 00725 //CLOSED or LISTEN state? 00726 case TCP_STATE_CLOSED: 00727 case TCP_STATE_LISTEN: 00728 //Connection does not exist 00729 return ERROR_NOT_CONNECTED; 00730 00731 //SYN-RECEIVED or ESTABLISHED state? 00732 case TCP_STATE_SYN_RECEIVED: 00733 case TCP_STATE_ESTABLISHED: 00734 //Flush the send buffer 00735 error = tcpSend(socket, NULL, 0, NULL, SOCKET_FLAG_NO_DELAY); 00736 //Any error to report? 00737 if(error) 00738 return error; 00739 00740 //Make sure all the data has been sent out 00741 event = tcpWaitForEvents(socket, SOCKET_EVENT_TX_DONE, socket->timeout); 00742 //Timeout error? 00743 if(event != SOCKET_EVENT_TX_DONE) 00744 return ERROR_TIMEOUT; 00745 00746 //Send a FIN segment 00747 error = tcpSendSegment(socket, TCP_FLAG_FIN | TCP_FLAG_ACK, 00748 socket->sndNxt, socket->rcvNxt, 0, TRUE); 00749 //Failed to send FIN segment? 00750 if(error) 00751 return error; 00752 00753 //Sequence number expected to be received 00754 socket->sndNxt++; 00755 //Switch to the FIN-WAIT1 state 00756 tcpChangeState(socket, TCP_STATE_FIN_WAIT_1); 00757 00758 //Wait for the FIN to be acknowledged 00759 event = tcpWaitForEvents(socket, SOCKET_EVENT_TX_SHUTDOWN, socket->timeout); 00760 //Timeout interval elapsed? 00761 if(event != SOCKET_EVENT_TX_SHUTDOWN) 00762 return ERROR_TIMEOUT; 00763 00764 //Continue processing... 00765 break; 00766 00767 //CLOSE-WAIT state? 00768 case TCP_STATE_CLOSE_WAIT: 00769 //Flush the send buffer 00770 error = tcpSend(socket, NULL, 0, NULL, SOCKET_FLAG_NO_DELAY); 00771 //Any error to report? 00772 if(error) 00773 return error; 00774 00775 //Make sure all the data has been sent out 00776 event = tcpWaitForEvents(socket, SOCKET_EVENT_TX_DONE, socket->timeout); 00777 //Timeout error? 00778 if(event != SOCKET_EVENT_TX_DONE) 00779 return ERROR_TIMEOUT; 00780 00781 //Send a FIN segment 00782 error = tcpSendSegment(socket, TCP_FLAG_FIN | TCP_FLAG_ACK, 00783 socket->sndNxt, socket->rcvNxt, 0, TRUE); 00784 //Failed to send FIN segment? 00785 if(error) 00786 return error; 00787 00788 //Sequence number expected to be received 00789 socket->sndNxt++; 00790 //Switch to the LAST-ACK state 00791 tcpChangeState(socket, TCP_STATE_LAST_ACK); 00792 00793 //Wait for the FIN to be acknowledged 00794 event = tcpWaitForEvents(socket, SOCKET_EVENT_TX_SHUTDOWN, socket->timeout); 00795 //Timeout interval elapsed? 00796 if(event != SOCKET_EVENT_TX_SHUTDOWN) 00797 return ERROR_TIMEOUT; 00798 00799 //Continue processing... 00800 break; 00801 00802 //FIN-WAIT-1, CLOSING or LAST-ACK state? 00803 case TCP_STATE_FIN_WAIT_1: 00804 case TCP_STATE_CLOSING: 00805 case TCP_STATE_LAST_ACK: 00806 //Wait for the FIN to be acknowledged 00807 event = tcpWaitForEvents(socket, SOCKET_EVENT_TX_SHUTDOWN, socket->timeout); 00808 //Timeout interval elapsed? 00809 if(event != SOCKET_EVENT_TX_SHUTDOWN) 00810 return ERROR_TIMEOUT; 00811 00812 //Continue processing... 00813 break; 00814 00815 //SYN-SENT, FIN-WAIT-2 or TIME-WAIT state? 00816 default: 00817 //Continue processing... 00818 break; 00819 } 00820 } 00821 00822 //Disable reception? 00823 if(how == SOCKET_SD_RECEIVE || how == SOCKET_SD_BOTH) 00824 { 00825 //Check current state 00826 switch(socket->state) 00827 { 00828 //CLOSED or LISTEN state? 00829 case TCP_STATE_CLOSED: 00830 case TCP_STATE_LISTEN: 00831 //Connection does not exist 00832 return ERROR_NOT_CONNECTED; 00833 00834 //SYN-SENT, SYN-RECEIVED, ESTABLISHED, FIN-WAIT-1 or FIN-WAIT-2 state? 00835 case TCP_STATE_SYN_SENT: 00836 case TCP_STATE_SYN_RECEIVED: 00837 case TCP_STATE_ESTABLISHED: 00838 case TCP_STATE_FIN_WAIT_1: 00839 case TCP_STATE_FIN_WAIT_2: 00840 //Wait for a FIN to be received 00841 event = tcpWaitForEvents(socket, SOCKET_EVENT_RX_SHUTDOWN, socket->timeout); 00842 //Timeout interval elapsed? 00843 if(event != SOCKET_EVENT_RX_SHUTDOWN) 00844 return ERROR_TIMEOUT; 00845 //A FIN segment has been received 00846 break; 00847 00848 //CLOSING, TIME-WAIT, CLOSE-WAIT or LAST-ACK state? 00849 default: 00850 //A FIN segment has already been received 00851 break; 00852 } 00853 } 00854 00855 //Successful operation 00856 return NO_ERROR; 00857 } 00858 00859 00860 /** 00861 * @brief Abort an existing TCP connection 00862 * @param[in] socket Handle identifying the socket to close 00863 * @return Error code 00864 **/ 00865 00866 error_t tcpAbort(Socket *socket) 00867 { 00868 error_t error; 00869 00870 //Check current state 00871 switch(socket->state) 00872 { 00873 //SYN-RECEIVED, ESTABLISHED, FIN-WAIT-1 00874 //FIN-WAIT-2 or CLOSE-WAIT state? 00875 case TCP_STATE_SYN_RECEIVED: 00876 case TCP_STATE_ESTABLISHED: 00877 case TCP_STATE_FIN_WAIT_1: 00878 case TCP_STATE_FIN_WAIT_2: 00879 case TCP_STATE_CLOSE_WAIT: 00880 //Send a reset segment 00881 error = tcpSendSegment(socket, TCP_FLAG_RST, socket->sndNxt, 0, 0, FALSE); 00882 //Enter CLOSED state 00883 tcpChangeState(socket, TCP_STATE_CLOSED); 00884 //Delete TCB 00885 tcpDeleteControlBlock(socket); 00886 //Mark the socket as closed 00887 socket->type = SOCKET_TYPE_UNUSED; 00888 //Return status code 00889 return error; 00890 00891 //TIME-WAIT state? 00892 case TCP_STATE_TIME_WAIT: 00893 #if (TCP_2MSL_TIMER > 0) 00894 //The user doe not own the socket anymore... 00895 socket->ownedFlag = FALSE; 00896 //TCB will be deleted and socket will be closed 00897 //when the 2MSL timer will elapse 00898 return NO_ERROR; 00899 #else 00900 //Enter CLOSED state 00901 tcpChangeState(socket, TCP_STATE_CLOSED); 00902 //Delete TCB 00903 tcpDeleteControlBlock(socket); 00904 //Mark the socket as closed 00905 socket->type = SOCKET_TYPE_UNUSED; 00906 //No error to report 00907 return NO_ERROR; 00908 #endif 00909 00910 //Any other state? 00911 default: 00912 //Enter CLOSED state 00913 tcpChangeState(socket, TCP_STATE_CLOSED); 00914 //Delete TCB 00915 tcpDeleteControlBlock(socket); 00916 //Mark the socket as closed 00917 socket->type = SOCKET_TYPE_UNUSED; 00918 //No error to report 00919 return NO_ERROR; 00920 } 00921 } 00922 00923 00924 /** 00925 * @brief Get the current state of the TCP FSM 00926 * @param[in] socket Handle identifying the socket 00927 * @return TCP FSM state 00928 **/ 00929 00930 TcpState tcpGetState(Socket *socket) 00931 { 00932 TcpState state; 00933 00934 //Get exclusive access 00935 osAcquireMutex(&netMutex); 00936 00937 //Get TCP FSM current state 00938 state = socket->state; 00939 00940 //Release exclusive access 00941 osReleaseMutex(&netMutex); 00942 00943 //Return current state 00944 return state; 00945 } 00946 00947 00948 /** 00949 * @brief Kill the oldest socket in the TIME-WAIT state 00950 * @return Handle identifying the oldest TCP connection in the TIME-WAIT state. 00951 * NULL is returned if no socket is currently in the TIME-WAIT state 00952 **/ 00953 00954 Socket *tcpKillOldestConnection(void) 00955 { 00956 uint_t i; 00957 Socket *socket; 00958 Socket *oldestSocket; 00959 00960 //Keep track of the oldest socket in the TIME-WAIT state 00961 oldestSocket = NULL; 00962 00963 //Loop through socket descriptors 00964 for(i = 0; i < SOCKET_MAX_COUNT; i++) 00965 { 00966 //Point to the current socket descriptor 00967 socket = &socketTable[i]; 00968 00969 //TCP connection found? 00970 if(socket->type == SOCKET_TYPE_STREAM) 00971 { 00972 //Check current state 00973 if(socket->state == TCP_STATE_TIME_WAIT) 00974 { 00975 //Keep track of the oldest socket in the TIME-WAIT state 00976 if(oldestSocket == NULL) 00977 { 00978 //Save socket handle 00979 oldestSocket = socket; 00980 } 00981 else if(timeCompare(socket->timeWaitTimer.startTime, 00982 oldestSocket->timeWaitTimer.startTime) < 0) 00983 { 00984 //Save socket handle 00985 oldestSocket = socket; 00986 } 00987 } 00988 } 00989 } 00990 00991 //Any connection in the TIME-WAIT state? 00992 if(oldestSocket != NULL) 00993 { 00994 //Enter CLOSED state 00995 tcpChangeState(oldestSocket, TCP_STATE_CLOSED); 00996 //Delete TCB 00997 tcpDeleteControlBlock(oldestSocket); 00998 //Mark the socket as closed 00999 oldestSocket->type = SOCKET_TYPE_UNUSED; 01000 } 01001 01002 //The oldest connection in the TIME-WAIT state can be reused 01003 //when the socket table runs out of space 01004 return oldestSocket; 01005 } 01006 01007 #endif 01008
Generated on Tue Jul 12 2022 17:10:17 by
1.7.2