tcp.c
Go to the documentation of this file.
1 /**
2  * @file tcp.c
3  * @brief TCP (Transmission Control Protocol)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2021 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.0.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL TCP_TRACE_LEVEL
33 
34 //Dependencies
35 #include <string.h>
36 #include "core/net.h"
37 #include "core/socket.h"
38 #include "core/socket_misc.h"
39 #include "core/tcp.h"
40 #include "core/tcp_misc.h"
41 #include "core/tcp_timer.h"
42 #include "mibs/mib2_module.h"
43 #include "mibs/tcp_mib_module.h"
44 #include "debug.h"
45 
46 //Check TCP/IP stack configuration
47 #if (TCP_SUPPORT == ENABLED)
48 
49 //Tick counter to handle periodic operations
51 
52 //Ephemeral ports are used for dynamic port assignment
53 static uint16_t tcpDynamicPort;
54 
55 
56 /**
57  * @brief TCP related initialization
58  * @return Error code
59  **/
60 
62 {
63  //Reset ephemeral port number
64  tcpDynamicPort = 0;
65 
66  //Successful initialization
67  return NO_ERROR;
68 }
69 
70 
71 /**
72  * @brief Get an ephemeral port number
73  * @return Ephemeral port
74  **/
75 
76 uint16_t tcpGetDynamicPort(void)
77 {
78  uint_t port;
79 
80  //Retrieve current port number
81  port = tcpDynamicPort;
82 
83  //Invalid port number?
84  if(port < SOCKET_EPHEMERAL_PORT_MIN || port > SOCKET_EPHEMERAL_PORT_MAX)
85  {
86  //Generate a random port number
89  }
90 
91  //Next dynamic port to use
93  {
94  //Increment port number
95  tcpDynamicPort = port + 1;
96  }
97  else
98  {
99  //Wrap around if necessary
100  tcpDynamicPort = SOCKET_EPHEMERAL_PORT_MIN;
101  }
102 
103  //Return an ephemeral port number
104  return port;
105 }
106 
107 
108 /**
109  * @brief Establish a TCP connection
110  * @param[in] socket Handle to an unconnected socket
111  * @param[in] remoteIpAddr IP address of the remote host
112  * @param[in] remotePort Remote port number that will be used to establish the connection
113  * @return Error code
114  **/
115 
116 error_t tcpConnect(Socket *socket, const IpAddr *remoteIpAddr, uint16_t remotePort)
117 {
118  error_t error;
119  uint_t event;
120 
121  //Check current TCP state
122  if(socket->state == TCP_STATE_CLOSED)
123  {
124  //Save port number and IP address of the remote host
125  socket->remoteIpAddr = *remoteIpAddr;
126  socket->remotePort = remotePort;
127 
128  //Select the source address and the relevant network interface
129  //to use when establishing the connection
130  error = ipSelectSourceAddr(&socket->interface,
131  &socket->remoteIpAddr, &socket->localIpAddr);
132  //Any error to report?
133  if(error)
134  return error;
135 
136  //Make sure the source address is valid
137  if(ipIsUnspecifiedAddr(&socket->localIpAddr))
138  return ERROR_NOT_CONFIGURED;
139 
140  //The user owns the socket
141  socket->ownedFlag = TRUE;
142 
143  //Number of chunks that comprise the TX and the RX buffers
144  socket->txBuffer.maxChunkCount = arraysize(socket->txBuffer.chunk);
145  socket->rxBuffer.maxChunkCount = arraysize(socket->rxBuffer.chunk);
146 
147  //Allocate transmit buffer
148  error = netBufferSetLength((NetBuffer *) &socket->txBuffer,
149  socket->txBufferSize);
150 
151  //Allocate receive buffer
152  if(!error)
153  {
154  error = netBufferSetLength((NetBuffer *) &socket->rxBuffer,
155  socket->rxBufferSize);
156  }
157 
158  //Failed to allocate memory?
159  if(error)
160  {
161  //Free any previously allocated memory
163  //Report an error to the caller
164  return error;
165  }
166 
167  //The SMSS is the size of the largest segment that the sender can
168  //transmit
170 
171  //The RMSS is the size of the largest segment the receiver is willing
172  //to accept
173  socket->rmss = MIN(socket->rxBufferSize, TCP_MAX_MSS);
174 
175  //Generate the initial sequence number
176  socket->iss = tcpGenerateInitialSeqNum(&socket->localIpAddr,
177  socket->localPort, &socket->remoteIpAddr, socket->remotePort);
178 
179  //Initialize TCP control block
180  socket->sndUna = socket->iss;
181  socket->sndNxt = socket->iss + 1;
182  socket->rcvUser = 0;
183  socket->rcvWnd = socket->rxBufferSize;
184 
185  //Default retransmission timeout
186  socket->rto = TCP_INITIAL_RTO;
187 
188 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
189  //Default congestion state
190  socket->congestState = TCP_CONGEST_STATE_IDLE;
191  //Initial congestion window
192  socket->cwnd = MIN(TCP_INITIAL_WINDOW * socket->smss, socket->txBufferSize);
193  //Slow start threshold should be set arbitrarily high
194  socket->ssthresh = UINT16_MAX;
195  //Recover is set to the initial send sequence number
196  socket->recover = socket->iss;
197 #endif
198 
199  //Send a SYN segment
200  error = tcpSendSegment(socket, TCP_FLAG_SYN, socket->iss, 0, 0, TRUE);
201  //Failed to send TCP segment?
202  if(error)
203  return error;
204 
205  //Switch to the SYN-SENT state
207 
208  //Number of times TCP connections have made a direct transition to
209  //the SYN-SENT state from the CLOSED state
210  MIB2_INC_COUNTER32(tcpGroup.tcpActiveOpens, 1);
211  TCP_MIB_INC_COUNTER32(tcpActiveOpens, 1);
212  }
213 
214  //Wait for the connection to be established
216  SOCKET_EVENT_CLOSED, socket->timeout);
217 
218  //Connection successfully established?
219  if(event == SOCKET_EVENT_CONNECTED)
220  return NO_ERROR;
221  //Failed to establish connection?
222  else if(event == SOCKET_EVENT_CLOSED)
224  //Timeout exception?
225  else
226  return ERROR_TIMEOUT;
227 }
228 
229 
230 /**
231  * @brief Place a socket in the listening state
232  *
233  * Place a socket in a state in which it is listening for an incoming connection
234  *
235  * @param[in] socket Socket to place in the listening state
236  * @param[in] backlog backlog The maximum length of the pending connection queue.
237  * If this parameter is zero, then the default backlog value is used instead
238  * @return Error code
239  **/
240 
242 {
243  //Socket already connected?
244  if(socket->state != TCP_STATE_CLOSED)
246 
247  //Set the size of the SYN queue
248  socket->synQueueSize = (backlog > 0) ? backlog : TCP_DEFAULT_SYN_QUEUE_SIZE;
249  //Limit the number of pending connections
250  socket->synQueueSize = MIN(socket->synQueueSize, TCP_MAX_SYN_QUEUE_SIZE);
251 
252  //Place the socket in the listening state
254 
255  //Successful processing
256  return NO_ERROR;
257 }
258 
259 
260 /**
261  * @brief Permit an incoming connection attempt on a TCP socket
262  * @param[in] socket Handle to a socket previously placed in a listening state
263  * @param[out] clientIpAddr IP address of the client
264  * @param[out] clientPort Port number used by the client
265  * @return Handle to the socket in which the actual connection is made
266  **/
267 
268 Socket *tcpAccept(Socket *socket, IpAddr *clientIpAddr, uint16_t *clientPort)
269 {
270  error_t error;
271  Socket *newSocket;
272  TcpSynQueueItem *queueItem;
273 
274  //Ensure the socket was previously placed in the listening state
276  return NULL;
277 
278  //Get exclusive access
280 
281  //Wait for an connection attempt
282  while(1)
283  {
284  //The SYN queue is empty?
285  if(socket->synQueue == NULL)
286  {
287  //Set the events the application is interested in
288  socket->eventMask = SOCKET_EVENT_RX_READY;
289  //Reset the event object
290  osResetEvent(&socket->event);
291 
292  //Release exclusive access
294  //Wait until a SYN message is received from a client
295  osWaitForEvent(&socket->event, socket->timeout);
296  //Get exclusive access
298  }
299 
300  //Check whether the queue is still empty
301  if(socket->synQueue == NULL)
302  {
303  //Timeout error
304  newSocket = NULL;
305  //Exit immediately
306  break;
307  }
308 
309  //Point to the first item in the SYN queue
310  queueItem = socket->synQueue;
311 
312  //The function optionally returns the IP address of the client
313  if(clientIpAddr != NULL)
314  {
315  *clientIpAddr = queueItem->srcAddr;
316  }
317 
318  //The function optionally returns the port number used by the client
319  if(clientPort != NULL)
320  {
321  *clientPort = queueItem->srcPort;
322  }
323 
324  //Create a new socket to handle the incoming connection request
326 
327  //Socket successfully created?
328  if(newSocket != NULL)
329  {
330  //The user owns the socket
331  newSocket->ownedFlag = TRUE;
332 
333  //Inherit parameters from the listening socket
334  newSocket->txBufferSize = socket->txBufferSize;
335  newSocket->rxBufferSize = socket->rxBufferSize;
336 
337 #if (TCP_KEEP_ALIVE_SUPPORT == ENABLED)
338  //Inherit keep-alive parameters from the listening socket
339  newSocket->keepAliveEnabled = socket->keepAliveEnabled;
340  newSocket->keepAliveIdle = socket->keepAliveIdle;
341  newSocket->keepAliveInterval = socket->keepAliveInterval;
342  newSocket->keepAliveMaxProbes = socket->keepAliveMaxProbes;
343 #endif
344  //Number of chunks that comprise the TX and the RX buffers
345  newSocket->txBuffer.maxChunkCount = arraysize(newSocket->txBuffer.chunk);
346  newSocket->rxBuffer.maxChunkCount = arraysize(newSocket->rxBuffer.chunk);
347 
348  //Allocate transmit buffer
349  error = netBufferSetLength((NetBuffer *) &newSocket->txBuffer,
350  newSocket->txBufferSize);
351 
352  //Check status code
353  if(!error)
354  {
355  //Allocate receive buffer
356  error = netBufferSetLength((NetBuffer *) &newSocket->rxBuffer,
357  newSocket->rxBufferSize);
358  }
359 
360  //Transmit and receive buffers successfully allocated?
361  if(!error)
362  {
363  //Bind the newly created socket to the appropriate interface
364  newSocket->interface = queueItem->interface;
365 
366  //Bind the socket to the specified address
367  newSocket->localIpAddr = queueItem->destAddr;
368  newSocket->localPort = socket->localPort;
369 
370  //Save the port number and the IP address of the remote host
371  newSocket->remoteIpAddr = queueItem->srcAddr;
372  newSocket->remotePort = queueItem->srcPort;
373 
374  //The SMSS is the size of the largest segment that the sender can
375  //transmit
376  newSocket->smss = queueItem->mss;
377 
378  //The RMSS is the size of the largest segment the receiver is
379  //willing to accept
380  newSocket->rmss = MIN(newSocket->rxBufferSize, TCP_MAX_MSS);
381 
382  //Generate the initial sequence number
383  newSocket->iss = tcpGenerateInitialSeqNum(&socket->localIpAddr,
384  socket->localPort, &socket->remoteIpAddr, socket->remotePort);
385 
386  //Initialize TCP control block
387  newSocket->irs = queueItem->isn;
388  newSocket->sndUna = newSocket->iss;
389  newSocket->sndNxt = newSocket->iss + 1;
390  newSocket->rcvNxt = newSocket->irs + 1;
391  newSocket->rcvUser = 0;
392  newSocket->rcvWnd = newSocket->rxBufferSize;
393 
394  //Default retransmission timeout
395  newSocket->rto = TCP_INITIAL_RTO;
396 
397 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
398  //Default congestion state
399  newSocket->congestState = TCP_CONGEST_STATE_IDLE;
400  //Initial congestion window
401  newSocket->cwnd = MIN(TCP_INITIAL_WINDOW * newSocket->smss, newSocket->txBufferSize);
402  //Slow start threshold should be set arbitrarily high
403  newSocket->ssthresh = UINT16_MAX;
404  //Recover is set to the initial send sequence number
405  newSocket->recover = newSocket->iss;
406 #endif
407  //The connection state should be changed to SYN-RECEIVED
409 
410  //Number of times TCP connections have made a direct transition to
411  //the SYN-RECEIVED state from the LISTEN state
412  MIB2_INC_COUNTER32(tcpGroup.tcpPassiveOpens, 1);
413  TCP_MIB_INC_COUNTER32(tcpPassiveOpens, 1);
414 
415  //Send a SYN ACK control segment
416  error = tcpSendSegment(newSocket, TCP_FLAG_SYN | TCP_FLAG_ACK,
417  newSocket->iss, newSocket->rcvNxt, 0, TRUE);
418 
419  //TCP segment successfully sent?
420  if(!error)
421  {
422  //Remove the item from the SYN queue
423  socket->synQueue = queueItem->next;
424  //Deallocate memory buffer
425  memPoolFree(queueItem);
426  //Update the state of events
428 
429  //We are done
430  break;
431  }
432  }
433 
434  //Dispose the socket
435  tcpAbort(newSocket);
436  }
437 
438  //Debug message
439  TRACE_WARNING("Cannot accept TCP connection!\r\n");
440 
441  //Remove the item from the SYN queue
442  socket->synQueue = queueItem->next;
443  //Deallocate memory buffer
444  memPoolFree(queueItem);
445 
446  //Wait for the next connection attempt
447  }
448 
449  //Release exclusive access
451 
452  //Return a handle to the newly created socket
453  return newSocket;
454 }
455 
456 
457 /**
458  * @brief Send data to a connected socket
459  * @param[in] socket Handle that identifies a connected socket
460  * @param[in] data Pointer to a buffer containing the data to be transmitted
461  * @param[in] length Number of bytes to be transmitted
462  * @param[out] written Actual number of bytes written (optional parameter)
463  * @param[in] flags Set of flags that influences the behavior of this function
464  * @return Error code
465  **/
466 
467 error_t tcpSend(Socket *socket, const uint8_t *data,
468  size_t length, size_t *written, uint_t flags)
469 {
470  uint_t n;
471  uint_t totalLength;
472  uint_t event;
473 
474  //Check whether the socket is in the listening state
475  if(socket->state == TCP_STATE_LISTEN)
476  return ERROR_NOT_CONNECTED;
477 
478  //Actual number of bytes written
479  totalLength = 0;
480 
481  //Send as much data as possible
482  do
483  {
484  //Wait until there is more room in the send buffer
486 
487  //A timeout exception occurred?
488  if(event != SOCKET_EVENT_TX_READY)
489  return ERROR_TIMEOUT;
490 
491  //Check current TCP state
492  switch(socket->state)
493  {
494  //ESTABLISHED or CLOSE-WAIT state?
497  //The send buffer is now available for writing
498  break;
499 
500  //LAST-ACK, FIN-WAIT-1, FIN-WAIT-2, CLOSING or TIME-WAIT state?
501  case TCP_STATE_LAST_ACK:
504  case TCP_STATE_CLOSING:
505  case TCP_STATE_TIME_WAIT:
506  //The connection is being closed
508 
509  //CLOSED state?
510  default:
511  //The connection was reset by remote side?
512  return (socket->resetFlag) ? ERROR_CONNECTION_RESET : ERROR_NOT_CONNECTED;
513  }
514 
515  //Determine the actual number of bytes in the send buffer
516  n = socket->sndUser + socket->sndNxt - socket->sndUna;
517  //Exit immediately if the transmission buffer is full (sanity check)
518  if(n >= socket->txBufferSize)
519  return ERROR_FAILURE;
520 
521  //Number of bytes available for writing
522  n = socket->txBufferSize - n;
523  //Calculate the number of bytes to copy at a time
524  n = MIN(n, length - totalLength);
525 
526  //Any data to copy?
527  if(n > 0)
528  {
529  //Copy user data to send buffer
530  tcpWriteTxBuffer(socket, socket->sndNxt + socket->sndUser, data, n);
531 
532  //Update the number of data buffered but not yet sent
533  socket->sndUser += n;
534  //Advance data pointer
535  data += n;
536  //Update byte counter
537  totalLength += n;
538 
539  //Total number of data that have been written
540  if(written != NULL)
541  *written = totalLength;
542 
543  //Update TX events
545 
546  //To avoid a deadlock, it is necessary to have a timeout to force
547  //transmission of data, overriding the SWS avoidance algorithm. In
548  //practice, this timeout should seldom occur (refer to RFC 1122,
549  //section 4.2.3.4)
550  if(socket->sndUser == n)
551  {
552  netStartTimer(&socket->overrideTimer, TCP_OVERRIDE_TIMEOUT);
553  }
554  }
555 
556  //The Nagle algorithm should be implemented to coalesce
557  //short segments (refer to RFC 1122 4.2.3.4)
559 
560  //Send as much data as possible
561  } while(totalLength < length);
562 
563  //The SOCKET_FLAG_WAIT_ACK flag causes the function to
564  //wait for acknowledgment from the remote side
565  if((flags & SOCKET_FLAG_WAIT_ACK) != 0)
566  {
567  //Wait for the data to be acknowledged
569 
570  //A timeout exception occurred?
571  if(event != SOCKET_EVENT_TX_ACKED)
572  return ERROR_TIMEOUT;
573 
574  //The connection was closed before an acknowledgment was received?
575  if(socket->state != TCP_STATE_ESTABLISHED && socket->state != TCP_STATE_CLOSE_WAIT)
576  return ERROR_NOT_CONNECTED;
577  }
578 
579  //Successful write operation
580  return NO_ERROR;
581 }
582 
583 
584 /**
585  * @brief Receive data from a connected socket
586  * @param[in] socket Handle that identifies a connected socket
587  * @param[out] data Buffer where to store the incoming data
588  * @param[in] size Maximum number of bytes that can be received
589  * @param[out] received Number of bytes that have been received
590  * @param[in] flags Set of flags that influences the behavior of this function
591  * @return Error code
592  **/
593 
595  size_t size, size_t *received, uint_t flags)
596 {
597  uint_t i;
598  uint_t n;
599  uint_t event;
600  uint32_t seqNum;
601  systime_t timeout;
602 
603  //Retrieve the break character code
604  char_t c = LSB(flags);
605  //No data has been read yet
606  *received = 0;
607 
608  //Check whether the socket is in the listening state
609  if(socket->state == TCP_STATE_LISTEN)
610  return ERROR_NOT_CONNECTED;
611 
612  //Read as much data as possible
613  while(*received < size)
614  {
615  //The SOCKET_FLAG_DONT_WAIT enables non-blocking operation
616  timeout = (flags & SOCKET_FLAG_DONT_WAIT) ? 0 : socket->timeout;
617  //Wait for data to be available for reading
618  event = tcpWaitForEvents(socket, SOCKET_EVENT_RX_READY, timeout);
619 
620  //A timeout exception occurred?
621  if(event != SOCKET_EVENT_RX_READY)
622  return ERROR_TIMEOUT;
623 
624  //Check current TCP state
625  switch(socket->state)
626  {
627  //ESTABLISHED, FIN-WAIT-1 or FIN-WAIT-2 state?
631  //Sequence number of the first byte to read
632  seqNum = socket->rcvNxt - socket->rcvUser;
633  //Data is available in the receive buffer
634  break;
635 
636  //CLOSE-WAIT, LAST-ACK, CLOSING or TIME-WAIT state?
638  case TCP_STATE_LAST_ACK:
639  case TCP_STATE_CLOSING:
640  case TCP_STATE_TIME_WAIT:
641  //The user must be satisfied with data already on hand
642  if(socket->rcvUser == 0)
643  {
644  if(*received > 0)
645  return NO_ERROR;
646  else
647  return ERROR_END_OF_STREAM;
648  }
649 
650  //Sequence number of the first byte to read
651  seqNum = (socket->rcvNxt - 1) - socket->rcvUser;
652  //Data is available in the receive buffer
653  break;
654 
655  //CLOSED state?
656  default:
657  //The connection was reset by remote side?
658  if(socket->resetFlag)
659  return ERROR_CONNECTION_RESET;
660  //The connection has not yet been established?
661  if(!socket->closedFlag)
662  return ERROR_NOT_CONNECTED;
663 
664  //The user must be satisfied with data already on hand
665  if(socket->rcvUser == 0)
666  {
667  if(*received > 0)
668  return NO_ERROR;
669  else
670  return ERROR_END_OF_STREAM;
671  }
672 
673  //Sequence number of the first byte to read
674  seqNum = (socket->rcvNxt - 1) - socket->rcvUser;
675  //Data is available in the receive buffer
676  break;
677  }
678 
679  //Sanity check
680  if(socket->rcvUser == 0)
681  return ERROR_FAILURE;
682 
683  //Calculate the number of bytes to read at a time
684  n = MIN(socket->rcvUser, size - *received);
685  //Copy data from circular buffer
687 
688  //Read data until a break character is encountered?
689  if((flags & SOCKET_FLAG_BREAK_CHAR) != 0)
690  {
691  //Search for the specified break character
692  for(i = 0; i < n && data[i] != c; i++);
693  //Adjust the number of data to read
694  n = MIN(n, i + 1);
695  }
696 
697  //Total number of data that have been read
698  *received += n;
699  //Remaining data still available in the receive buffer
700  socket->rcvUser -= n;
701 
702  //Update the receive window
704  //Update RX event state
706 
707  //The SOCKET_FLAG_BREAK_CHAR flag causes the function to stop reading
708  //data as soon as the specified break character is encountered
709  if((flags & SOCKET_FLAG_BREAK_CHAR) != 0)
710  {
711  //Check whether a break character has been found
712  if(data[n - 1] == c)
713  break;
714  }
715  //The SOCKET_FLAG_WAIT_ALL flag causes the function to return
716  //only when the requested number of bytes have been read
717  else if((flags & SOCKET_FLAG_WAIT_ALL) == 0)
718  {
719  break;
720  }
721 
722  //Advance data pointer
723  data += n;
724  }
725 
726  //Successful read operation
727  return NO_ERROR;
728 }
729 
730 
731 /**
732  * @brief Shutdown gracefully reception, transmission, or both
733  *
734  * Note that socketShutdown() does not close the socket, and resources attached
735  * to the socket will not be freed until socketClose() is invoked
736  *
737  * @param[in] socket Handle to a socket
738  * @param[in] how Flag that describes what types of operation will no longer be allowed
739  * @return Error code
740  **/
741 
743 {
744  error_t error;
745  uint_t event;
746 
747  //Disable transmission?
748  if(how == SOCKET_SD_SEND || how == SOCKET_SD_BOTH)
749  {
750  //Check current state
751  switch(socket->state)
752  {
753  //CLOSED or LISTEN state?
754  case TCP_STATE_CLOSED:
755  case TCP_STATE_LISTEN:
756  //The connection does not exist
757  return ERROR_NOT_CONNECTED;
758 
759  //SYN-RECEIVED or ESTABLISHED state?
762  //Flush the send buffer
763  error = tcpSend(socket, NULL, 0, NULL, SOCKET_FLAG_NO_DELAY);
764  //Any error to report?
765  if(error)
766  return error;
767 
768  //Make sure all the data has been sent out
770  //Timeout error?
771  if(event != SOCKET_EVENT_TX_DONE)
772  return ERROR_TIMEOUT;
773 
774  //Send a FIN segment
776  socket->sndNxt, socket->rcvNxt, 0, TRUE);
777  //Failed to send FIN segment?
778  if(error)
779  return error;
780 
781  //Sequence number expected to be received
782  socket->sndNxt++;
783  //Switch to the FIN-WAIT1 state
785 
786  //Wait for the FIN to be acknowledged
788  //Timeout interval elapsed?
789  if(event != SOCKET_EVENT_TX_SHUTDOWN)
790  return ERROR_TIMEOUT;
791 
792  //Continue processing
793  break;
794 
795  //CLOSE-WAIT state?
797  //Flush the send buffer
798  error = tcpSend(socket, NULL, 0, NULL, SOCKET_FLAG_NO_DELAY);
799  //Any error to report?
800  if(error)
801  return error;
802 
803  //Make sure all the data has been sent out
805  //Timeout error?
806  if(event != SOCKET_EVENT_TX_DONE)
807  return ERROR_TIMEOUT;
808 
809  //Send a FIN segment
811  socket->sndNxt, socket->rcvNxt, 0, TRUE);
812  //Failed to send FIN segment?
813  if(error)
814  return error;
815 
816  //Sequence number expected to be received
817  socket->sndNxt++;
818  //Switch to the LAST-ACK state
820 
821  //Wait for the FIN to be acknowledged
823  //Timeout interval elapsed?
824  if(event != SOCKET_EVENT_TX_SHUTDOWN)
825  return ERROR_TIMEOUT;
826 
827  //Continue processing
828  break;
829 
830  //FIN-WAIT-1, CLOSING or LAST-ACK state?
832  case TCP_STATE_CLOSING:
833  case TCP_STATE_LAST_ACK:
834  //Wait for the FIN to be acknowledged
836  //Timeout interval elapsed?
837  if(event != SOCKET_EVENT_TX_SHUTDOWN)
838  return ERROR_TIMEOUT;
839 
840  //Continue processing
841  break;
842 
843  //SYN-SENT, FIN-WAIT-2 or TIME-WAIT state?
844  default:
845  //Continue processing
846  break;
847  }
848  }
849 
850  //Disable reception?
851  if(how == SOCKET_SD_RECEIVE || how == SOCKET_SD_BOTH)
852  {
853  //Check current state
854  switch(socket->state)
855  {
856  //LISTEN state?
857  case TCP_STATE_LISTEN:
858  //The connection does not exist
859  return ERROR_NOT_CONNECTED;
860 
861  //SYN-SENT, SYN-RECEIVED, ESTABLISHED, FIN-WAIT-1 or FIN-WAIT-2 state?
862  case TCP_STATE_SYN_SENT:
867  //Wait for a FIN to be received
869  //Timeout interval elapsed?
870  if(event != SOCKET_EVENT_RX_SHUTDOWN)
871  return ERROR_TIMEOUT;
872  //A FIN segment has been received
873  break;
874 
875  //CLOSING, TIME-WAIT, CLOSE-WAIT, LAST-ACK or CLOSED state?
876  default:
877  //A FIN segment has already been received
878  break;
879  }
880  }
881 
882  //Successful operation
883  return NO_ERROR;
884 }
885 
886 
887 /**
888  * @brief Abort an existing TCP connection
889  * @param[in] socket Handle identifying the socket to close
890  * @return Error code
891  **/
892 
894 {
895  error_t error;
896 
897  //Check current state
898  switch(socket->state)
899  {
900  //SYN-RECEIVED, ESTABLISHED, FIN-WAIT-1
901  //FIN-WAIT-2 or CLOSE-WAIT state?
907  //Send a reset segment
908  error = tcpSendResetSegment(socket, socket->sndNxt);
909  //Enter CLOSED state
911  //Delete TCB
913  //Mark the socket as closed
914  socket->type = SOCKET_TYPE_UNUSED;
915  //Return status code
916  return error;
917 
918  //TIME-WAIT state?
919  case TCP_STATE_TIME_WAIT:
920 #if (TCP_2MSL_TIMER > 0)
921  //The user doe not own the socket anymore...
922  socket->ownedFlag = FALSE;
923  //TCB will be deleted and socket will be closed
924  //when the 2MSL timer will elapse
925  return NO_ERROR;
926 #else
927  //Enter CLOSED state
929  //Delete TCB
931  //Mark the socket as closed
932  socket->type = SOCKET_TYPE_UNUSED;
933  //No error to report
934  return NO_ERROR;
935 #endif
936 
937  //Any other state?
938  default:
939  //Enter CLOSED state
941  //Delete TCB
943  //Mark the socket as closed
944  socket->type = SOCKET_TYPE_UNUSED;
945  //No error to report
946  return NO_ERROR;
947  }
948 }
949 
950 
951 /**
952  * @brief Get the current state of the TCP FSM
953  * @param[in] socket Handle identifying the socket
954  * @return TCP FSM state
955  **/
956 
958 {
959  TcpState state;
960 
961  //Get exclusive access
963 
964  //Get TCP FSM current state
965  state = socket->state;
966 
967  //Release exclusive access
969 
970  //Return current state
971  return state;
972 }
973 
974 
975 /**
976  * @brief Kill the oldest socket in the TIME-WAIT state
977  * @return Handle identifying the oldest TCP connection in the TIME-WAIT state.
978  * NULL is returned if no socket is currently in the TIME-WAIT state
979  **/
980 
982 {
983  uint_t i;
984  systime_t time;
985  Socket *socket;
986  Socket *oldestSocket;
987 
988  //Get current time
989  time = osGetSystemTime();
990 
991  //Keep track of the oldest socket in the TIME-WAIT state
992  oldestSocket = NULL;
993 
994  //Loop through socket descriptors
995  for(i = 0; i < SOCKET_MAX_COUNT; i++)
996  {
997  //Point to the current socket descriptor
998  socket = &socketTable[i];
999 
1000  //TCP connection found?
1001  if(socket->type == SOCKET_TYPE_STREAM)
1002  {
1003  //Check current state
1004  if(socket->state == TCP_STATE_TIME_WAIT)
1005  {
1006  //Keep track of the oldest socket in the TIME-WAIT state
1007  if(oldestSocket == NULL)
1008  {
1009  //Save socket handle
1010  oldestSocket = socket;
1011  }
1012  if((time - socket->timeWaitTimer.startTime) >
1013  (time - oldestSocket->timeWaitTimer.startTime))
1014  {
1015  //Save socket handle
1016  oldestSocket = socket;
1017  }
1018  }
1019  }
1020  }
1021 
1022  //Any connection in the TIME-WAIT state?
1023  if(oldestSocket != NULL)
1024  {
1025  //Enter CLOSED state
1026  tcpChangeState(oldestSocket, TCP_STATE_CLOSED);
1027  //Delete TCB
1028  tcpDeleteControlBlock(oldestSocket);
1029  //Mark the socket as closed
1030  oldestSocket->type = SOCKET_TYPE_UNUSED;
1031  }
1032 
1033  //The oldest connection in the TIME-WAIT state can be reused
1034  //when the socket table runs out of space
1035  return oldestSocket;
1036 }
1037 
1038 #endif
@ TCP_CONGEST_STATE_IDLE
Definition: tcp.h:288
void tcpUpdateReceiveWindow(Socket *socket)
Update receive window so as to avoid Silly Window Syndrome.
Definition: tcp_misc.c:1584
uint8_t length
Definition: coap_common.h:191
MIB-II module.
void netStartTimer(NetTimer *timer, systime_t interval)
Start timer.
Definition: net_misc.c:742
@ TCP_STATE_TIME_WAIT
Definition: tcp.h:278
uint32_t netGetRand(void)
Generate a random 32-bit value.
Definition: net_misc.c:867
#define TCP_INITIAL_WINDOW
Definition: tcp.h:159
@ SOCKET_FLAG_WAIT_ALL
Definition: socket.h:121
void memPoolFree(void *p)
Release a memory block.
Definition: net_mem.c:166
uint8_t data[]
Definition: ethernet.h:210
#define netMutex
Definition: net_legacy.h:266
IP network address.
Definition: ip.h:79
@ TCP_FLAG_FIN
Definition: tcp.h:300
@ SOCKET_FLAG_WAIT_ACK
Definition: socket.h:125
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
error_t tcpReceive(Socket *socket, uint8_t *data, size_t size, size_t *received, uint_t flags)
Receive data from a connected socket.
Definition: tcp.c:594
@ TCP_STATE_FIN_WAIT_1
Definition: tcp.h:275
uint16_t mss
Definition: tcp.h:403
#define TCP_OVERRIDE_TIMEOUT
Definition: tcp.h:187
#define TRUE
Definition: os_port.h:50
IpAddr srcAddr
Definition: tcp.h:399
@ ERROR_ALREADY_CONNECTED
Definition: error.h:81
@ ERROR_CONNECTION_RESET
Definition: error.h:78
@ TCP_STATE_CLOSE_WAIT
Definition: tcp.h:273
IpAddr destAddr
Definition: tcp.h:401
error_t tcpSendResetSegment(Socket *socket, uint32_t seqNum)
Send a TCP reset segment.
Definition: tcp_misc.c:328
#define TCP_MAX_MSS
Definition: tcp.h:54
@ ERROR_NOT_CONFIGURED
Definition: error.h:216
uint16_t srcPort
Definition: tcp.h:400
struct _TcpSynQueueItem * next
Definition: tcp.h:397
@ ERROR_END_OF_STREAM
Definition: error.h:209
error_t tcpListen(Socket *socket, uint_t backlog)
Place a socket in the listening state.
Definition: tcp.c:241
@ SOCKET_TYPE_STREAM
Definition: socket.h:78
@ TCP_FLAG_ACK
Definition: tcp.h:304
#define SOCKET_EPHEMERAL_PORT_MIN
Definition: socket.h:53
void tcpDeleteControlBlock(Socket *socket)
Delete TCB structure.
Definition: tcp_misc.c:1321
@ SOCKET_SD_SEND
Definition: socket.h:143
void tcpWriteTxBuffer(Socket *socket, uint32_t seqNum, const uint8_t *data, size_t length)
Copy incoming data to the send buffer.
Definition: tcp_misc.c:2156
TcpState
TCP FSM states.
Definition: tcp.h:267
#define FALSE
Definition: os_port.h:46
Helper functions for TCP.
#define SOCKET_EPHEMERAL_PORT_MAX
Definition: socket.h:60
void tcpChangeState(Socket *socket, TcpState newState)
Update TCP FSM current state.
Definition: tcp_misc.c:1939
void osResetEvent(OsEvent *event)
Set the specified event object to the nonsignaled state.
error_t
Error codes.
Definition: error.h:43
uint32_t seqNum
Definition: tcp.h:339
Socket * tcpKillOldestConnection(void)
Kill the oldest socket in the TIME-WAIT state.
Definition: tcp.c:981
error_t tcpSend(Socket *socket, const uint8_t *data, size_t length, size_t *written, uint_t flags)
Send data to a connected socket.
Definition: tcp.c:467
int_t socket(int_t family, int_t type, int_t protocol)
Create a socket that is bound to a specific transport service provider.
Definition: bsd_socket.c:109
@ SOCKET_EVENT_TX_READY
Definition: socket.h:158
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
error_t ipSelectSourceAddr(NetInterface **interface, const IpAddr *destAddr, IpAddr *srcAddr)
IP source address selection.
Definition: ip.c:110
TcpState tcpGetState(Socket *socket)
Get the current state of the TCP FSM.
Definition: tcp.c:957
NetInterface * interface
Definition: tcp.h:398
#define TCP_MAX_SYN_QUEUE_SIZE
Definition: tcp.h:103
@ SOCKET_EVENT_RX_SHUTDOWN
Definition: socket.h:163
bool_t ipIsUnspecifiedAddr(const IpAddr *ipAddr)
Compare an IP address against the unspecified address.
Definition: ip.c:210
#define TCP_MIB_INC_COUNTER32(name, value)
void tcpUpdateEvents(Socket *socket)
Update TCP related events.
Definition: tcp_misc.c:1970
@ TCP_STATE_SYN_SENT
Definition: tcp.h:270
@ TCP_FLAG_SYN
Definition: tcp.h:301
uint32_t isn
Definition: tcp.h:402
#define LSB(x)
Definition: os_port.h:54
@ TCP_STATE_LAST_ACK
Definition: tcp.h:274
#define MIN(a, b)
Definition: os_port.h:62
@ SOCKET_EVENT_TX_DONE
Definition: socket.h:159
@ TCP_STATE_CLOSING
Definition: tcp.h:277
Socket socketTable[SOCKET_MAX_COUNT]
Definition: socket.c:50
@ ERROR_CONNECTION_CLOSING
Definition: error.h:77
systime_t tcpTickCounter
Definition: tcp.c:50
@ SOCKET_FLAG_BREAK_CHAR
Definition: socket.h:123
@ TCP_STATE_CLOSED
Definition: tcp.h:268
uint16_t port
Definition: dns_common.h:223
@ TCP_STATE_LISTEN
Definition: tcp.h:269
uint8_t flags
Definition: tcp.h:349
#define TRACE_WARNING(...)
Definition: debug.h:85
@ ERROR_TIMEOUT
Definition: error.h:94
char char_t
Definition: compiler_port.h:43
Socket * socketAllocate(uint_t type, uint_t protocol)
Allocate a socket.
Definition: socket_misc.c:53
uint16_t tcpGetDynamicPort(void)
Get an ephemeral port number.
Definition: tcp.c:76
@ SOCKET_EVENT_TX_ACKED
Definition: socket.h:160
uint32_t time
Helper functions for sockets.
void tcpReadRxBuffer(Socket *socket, uint32_t seqNum, uint8_t *data, size_t length)
Copy data from the receive buffer.
Definition: tcp_misc.c:2271
error_t tcpInit(void)
TCP related initialization.
Definition: tcp.c:61
@ SOCKET_FLAG_NO_DELAY
Definition: socket.h:126
@ SOCKET_EVENT_RX_READY
Definition: socket.h:162
@ ERROR_NOT_CONNECTED
Definition: error.h:79
uint8_t n
bool_t osWaitForEvent(OsEvent *event, systime_t timeout)
Wait until the specified event is in the signaled state.
TCP (Transmission Control Protocol)
TCP MIB module.
@ SOCKET_EVENT_TX_SHUTDOWN
Definition: socket.h:161
@ SOCKET_TYPE_UNUSED
Definition: socket.h:77
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
#define TCP_DEFAULT_SYN_QUEUE_SIZE
Definition: tcp.h:96
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
@ SOCKET_SD_RECEIVE
Definition: socket.h:142
error_t tcpAbort(Socket *socket)
Abort an existing TCP connection.
Definition: tcp.c:893
error_t tcpNagleAlgo(Socket *socket, uint_t flags)
Nagle algorithm implementation.
Definition: tcp_misc.c:1810
#define MIB2_INC_COUNTER32(name, value)
Definition: mib2_module.h:156
#define Socket
Definition: socket.h:36
error_t netBufferSetLength(NetBuffer *buffer, size_t length)
Adjust the length of a multi-part buffer.
Definition: net_mem.c:320
@ TCP_STATE_FIN_WAIT_2
Definition: tcp.h:276
Socket API.
@ TCP_STATE_SYN_RECEIVED
Definition: tcp.h:271
error_t tcpConnect(Socket *socket, const IpAddr *remoteIpAddr, uint16_t remotePort)
Establish a TCP connection.
Definition: tcp.c:116
SYN queue item.
Definition: tcp.h:396
error_t tcpShutdown(Socket *socket, uint_t how)
Shutdown gracefully reception, transmission, or both.
Definition: tcp.c:742
#define TCP_INITIAL_RTO
Definition: tcp.h:117
TCP timer management.
Socket * tcpAccept(Socket *socket, IpAddr *clientIpAddr, uint16_t *clientPort)
Permit an incoming connection attempt on a TCP socket.
Definition: tcp.c:268
@ SOCKET_EVENT_CONNECTED
Definition: socket.h:156
@ ERROR_CONNECTION_FAILED
Definition: error.h:75
unsigned int uint_t
Definition: compiler_port.h:45
@ SOCKET_FLAG_DONT_WAIT
Definition: socket.h:122
TCP/IP stack core.
@ SOCKET_EVENT_CLOSED
Definition: socket.h:157
#define SOCKET_MAX_COUNT
Definition: socket.h:46
#define TCP_DEFAULT_MSS
Definition: tcp.h:251
uint32_t tcpGenerateInitialSeqNum(const IpAddr *localIpAddr, uint16_t localPort, const IpAddr *remoteIpAddr, uint16_t remotePort)
Initial sequence number generation.
Definition: tcp_misc.c:639
@ SOCKET_SD_BOTH
Definition: socket.h:144
error_t tcpSendSegment(Socket *socket, uint8_t flags, uint32_t seqNum, uint32_t ackNum, size_t length, bool_t addToQueue)
Send a TCP segment.
Definition: tcp_misc.c:70
@ SOCKET_IP_PROTO_TCP
Definition: socket.h:93
uint32_t systime_t
Definition: compiler_port.h:46
@ TCP_STATE_ESTABLISHED
Definition: tcp.h:272
@ NO_ERROR
Success.
Definition: error.h:44
uint8_t c
Definition: ndp.h:512
Debugging facilities.
uint_t tcpWaitForEvents(Socket *socket, uint_t eventMask, systime_t timeout)
Wait for a particular TCP event.
Definition: tcp_misc.c:2118
#define arraysize(a)
Definition: os_port.h:70
systime_t osGetSystemTime(void)
Retrieve system time.