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