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