Webserver+3d print
Embed:
(wiki syntax)
Show/hide line numbers
tcp.c
Go to the documentation of this file.
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
