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-2025 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.5.2
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL TCP_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "core/socket.h"
37 #include "core/socket_misc.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 Set TCP initial retransmission timeout
72  * @param[in] interface Underlying network interface
73  * @param[in] initialRto TCP initial RTO value, in milliseconds
74  * @return Error code
75  **/
76 
78 {
79  //Check parameters
80  if(interface == NULL || initialRto == 0)
82 
83  //Get exclusive access
85 
86  //TCP imposes its minimum and maximum bounds over the value provided
87  initialRto = MIN(initialRto, TCP_MAX_RTO);
88  initialRto = MAX(initialRto, TCP_MIN_RTO);
89 
90  //Set TCP initial retransmission timeout
91  interface->initialRto = initialRto;
92 
93  //Release exclusive access
95 
96  //Successful processing
97  return NO_ERROR;
98 }
99 
100 
101 /**
102  * @brief Get an ephemeral port number
103  * @return Ephemeral port
104  **/
105 
106 uint16_t tcpGetDynamicPort(void)
107 {
108  uint_t port;
109 
110  //Retrieve current port number
111  port = tcpDynamicPort;
112 
113  //Invalid port number?
114  if(port < SOCKET_EPHEMERAL_PORT_MIN || port > SOCKET_EPHEMERAL_PORT_MAX)
115  {
116  //Generate a random port number
119  }
120 
121  //Next dynamic port to use
123  {
124  //Increment port number
125  tcpDynamicPort = port + 1;
126  }
127  else
128  {
129  //Wrap around if necessary
130  tcpDynamicPort = SOCKET_EPHEMERAL_PORT_MIN;
131  }
132 
133  //Return an ephemeral port number
134  return port;
135 }
136 
137 
138 /**
139  * @brief Establish a TCP connection
140  * @param[in] socket Handle to an unconnected socket
141  * @param[in] remoteIpAddr IP address of the remote host
142  * @param[in] remotePort Remote port number that will be used to establish the connection
143  * @return Error code
144  **/
145 
146 error_t tcpConnect(Socket *socket, const IpAddr *remoteIpAddr,
147  uint16_t remotePort)
148 {
149  error_t error;
150  uint_t event;
151 
152  //Check current TCP state
153  if(socket->state == TCP_STATE_CLOSED && !socket->resetFlag)
154  {
155  //Make sure the destination address is a valid unicast address
156  if(ipIsUnspecifiedAddr(remoteIpAddr) || ipIsMulticastAddr(remoteIpAddr) ||
157  ipIsBroadcastAddr(remoteIpAddr))
158  {
159  return ERROR_INVALID_ADDRESS;
160  }
161 
162  //Broadcast and multicast addresses must not be used as source address
163  if(ipIsMulticastAddr(&socket->localIpAddr) ||
164  ipIsBroadcastAddr(&socket->localIpAddr))
165  {
166  return ERROR_INVALID_ADDRESS;
167  }
168 
169  //Save port number and IP address of the remote host
170  socket->remoteIpAddr = *remoteIpAddr;
171  socket->remotePort = remotePort;
172 
173  //Unspecified source address?
174  if(ipIsUnspecifiedAddr(&socket->localIpAddr))
175  {
176  //Select the source address and the relevant network interface to use
177  //when establishing the connection
178  error = ipSelectSourceAddr(&socket->interface, &socket->remoteIpAddr,
179  &socket->localIpAddr);
180  //Any error to report?
181  if(error)
182  return error;
183  }
184 
185  //The user owns the socket
186  socket->ownedFlag = TRUE;
187 
188  //Number of chunks that comprise the TX and the RX buffers
189  socket->txBuffer.maxChunkCount = arraysize(socket->txBuffer.chunk);
190  socket->rxBuffer.maxChunkCount = arraysize(socket->rxBuffer.chunk);
191 
192  //Allocate transmit buffer
193  error = netBufferSetLength((NetBuffer *) &socket->txBuffer,
194  socket->txBufferSize);
195 
196  //Allocate receive buffer
197  if(!error)
198  {
199  error = netBufferSetLength((NetBuffer *) &socket->rxBuffer,
200  socket->rxBufferSize);
201  }
202 
203  //Failed to allocate memory?
204  if(error)
205  {
206  //Free any previously allocated memory
208  //Report an error to the caller
209  return error;
210  }
211 
212  //The SMSS is the size of the largest segment that the sender can
213  //transmit
214  socket->smss = MIN(socket->mss, TCP_DEFAULT_MSS);
215 
216  //The RMSS is the size of the largest segment the receiver is willing
217  //to accept
218  socket->rmss = MIN(socket->mss, socket->rxBufferSize);
219 
220  //Generate the initial sequence number
221  socket->iss = tcpGenerateInitialSeqNum(&socket->localIpAddr,
222  socket->localPort, &socket->remoteIpAddr, socket->remotePort);
223 
224  //Initialize TCP control block
225  socket->sndUna = socket->iss;
226  socket->sndNxt = socket->iss + 1;
227  socket->rcvNxt = 0;
228  socket->rcvUser = 0;
229  socket->rcvWnd = socket->rxBufferSize;
230 
231  //Set initial retransmission timeout
232  socket->rto = socket->interface->initialRto;
233 
234 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
235  //Default congestion state
236  socket->congestState = TCP_CONGEST_STATE_IDLE;
237 
238  //Initial congestion window
239  socket->cwnd = MIN((uint32_t) socket->smss * TCP_INITIAL_WINDOW,
240  socket->txBufferSize);
241 
242  //Slow start threshold should be set arbitrarily high
243  socket->ssthresh = UINT32_MAX;
244  //Recover is set to the initial send sequence number
245  socket->recover = socket->iss;
246 #endif
247 
248  //Send a SYN segment
249  error = tcpSendSegment(socket, TCP_FLAG_SYN, socket->iss, 0, 0, TRUE);
250  //Failed to send TCP segment?
251  if(error)
252  return error;
253 
254  //Switch to the SYN-SENT state
256 
257  //Number of times TCP connections have made a direct transition to
258  //the SYN-SENT state from the CLOSED state
259  MIB2_TCP_INC_COUNTER32(tcpActiveOpens, 1);
260  TCP_MIB_INC_COUNTER32(tcpActiveOpens, 1);
261  }
262 
263  //Wait for the connection to be established
265  SOCKET_EVENT_CLOSED, socket->timeout);
266 
267  //Return status code
268  if(event == SOCKET_EVENT_CONNECTED)
269  {
270  //Connection successfully established
271  return NO_ERROR;
272  }
273  else if(event == SOCKET_EVENT_CLOSED)
274  {
275  //Failed to establish connection
277  }
278  else
279  {
280  //Timeout exception
281  return ERROR_TIMEOUT;
282  }
283 }
284 
285 
286 /**
287  * @brief Place a socket in the listening state
288  *
289  * Place a socket in a state in which it is listening for an incoming connection
290  *
291  * @param[in] socket Socket to place in the listening state
292  * @param[in] backlog backlog The maximum length of the pending connection queue.
293  * If this parameter is zero, then the default backlog value is used instead
294  * @return Error code
295  **/
296 
298 {
299  //Socket already connected?
300  if(socket->state != TCP_STATE_CLOSED)
302 
303  //Set the size of the SYN queue
304  socket->synQueueSize = (backlog > 0) ? backlog : TCP_DEFAULT_SYN_QUEUE_SIZE;
305  //Limit the number of pending connections
306  socket->synQueueSize = MIN(socket->synQueueSize, TCP_MAX_SYN_QUEUE_SIZE);
307 
308  //Place the socket in the listening state
310 
311  //Successful processing
312  return NO_ERROR;
313 }
314 
315 
316 /**
317  * @brief Permit an incoming connection attempt on a TCP socket
318  * @param[in] socket Handle to a socket previously placed in a listening state
319  * @param[out] clientIpAddr IP address of the client
320  * @param[out] clientPort Port number used by the client
321  * @return Handle to the socket in which the actual connection is made
322  **/
323 
324 Socket *tcpAccept(Socket *socket, IpAddr *clientIpAddr, uint16_t *clientPort)
325 {
326  error_t error;
327  Socket *newSocket;
328  TcpSynQueueItem *queueItem;
329 
330  //Ensure the socket was previously placed in the listening state
332  return NULL;
333 
334  //Get exclusive access
336 
337  //Wait for an connection attempt
338  while(1)
339  {
340  //The SYN queue is empty?
341  if(socket->synQueue == NULL)
342  {
343  //Set the events the application is interested in
344  socket->eventMask = SOCKET_EVENT_RX_READY;
345  //Reset the event object
346  osResetEvent(&socket->event);
347 
348  //Release exclusive access
350  //Wait until a SYN message is received from a client
351  osWaitForEvent(&socket->event, socket->timeout);
352  //Get exclusive access
354  }
355 
356  //Check whether the queue is still empty
357  if(socket->synQueue == NULL)
358  {
359  //Timeout error
360  newSocket = NULL;
361  //Exit immediately
362  break;
363  }
364 
365  //Point to the first item in the SYN queue
366  queueItem = socket->synQueue;
367 
368  //The function optionally returns the IP address of the client
369  if(clientIpAddr != NULL)
370  {
371  *clientIpAddr = queueItem->srcAddr;
372  }
373 
374  //The function optionally returns the port number used by the client
375  if(clientPort != NULL)
376  {
377  *clientPort = queueItem->srcPort;
378  }
379 
380  //Create a new socket to handle the incoming connection request
382 
383  //Socket successfully created?
384  if(newSocket != NULL)
385  {
386  //The user owns the socket
387  newSocket->ownedFlag = TRUE;
388 
389  //Inherit parameters from the listening socket
390  newSocket->mss = socket->mss;
391  newSocket->txBufferSize = socket->txBufferSize;
392  newSocket->rxBufferSize = socket->rxBufferSize;
393 
394 #if (TCP_WINDOW_SCALE_SUPPORT == ENABLED)
395  //Save the window scale factor to use for the receive window
396  newSocket->rcvWndShift = socket->rcvWndShift;
397 #endif
398 
399 #if (TCP_KEEP_ALIVE_SUPPORT == ENABLED)
400  //Inherit keep-alive parameters from the listening socket
401  newSocket->keepAliveEnabled = socket->keepAliveEnabled;
402  newSocket->keepAliveIdle = socket->keepAliveIdle;
403  newSocket->keepAliveInterval = socket->keepAliveInterval;
404  newSocket->keepAliveMaxProbes = socket->keepAliveMaxProbes;
405 #endif
406  //Number of chunks that comprise the TX and the RX buffers
407  newSocket->txBuffer.maxChunkCount = arraysize(newSocket->txBuffer.chunk);
408  newSocket->rxBuffer.maxChunkCount = arraysize(newSocket->rxBuffer.chunk);
409 
410  //Allocate transmit buffer
411  error = netBufferSetLength((NetBuffer *) &newSocket->txBuffer,
412  newSocket->txBufferSize);
413 
414  //Check status code
415  if(!error)
416  {
417  //Allocate receive buffer
418  error = netBufferSetLength((NetBuffer *) &newSocket->rxBuffer,
419  newSocket->rxBufferSize);
420  }
421 
422  //Transmit and receive buffers successfully allocated?
423  if(!error)
424  {
425  //Bind the newly created socket to the appropriate interface
426  newSocket->interface = queueItem->interface;
427 
428  //Bind the socket to the specified address
429  newSocket->localIpAddr = queueItem->destAddr;
430  newSocket->localPort = socket->localPort;
431 
432  //Save the port number and the IP address of the remote host
433  newSocket->remoteIpAddr = queueItem->srcAddr;
434  newSocket->remotePort = queueItem->srcPort;
435 
436  //The SMSS is the size of the largest segment that the sender can
437  //transmit
438  newSocket->smss = queueItem->mss;
439 
440  //The RMSS is the size of the largest segment the receiver is
441  //willing to accept
442  newSocket->rmss = MIN(newSocket->mss, newSocket->rxBufferSize);
443 
444  //Generate the initial sequence number
445  newSocket->iss = tcpGenerateInitialSeqNum(&newSocket->localIpAddr,
446  newSocket->localPort, &newSocket->remoteIpAddr,
447  newSocket->remotePort);
448 
449  //Initialize TCP control block
450  newSocket->irs = queueItem->isn;
451  newSocket->sndUna = newSocket->iss;
452  newSocket->sndNxt = newSocket->iss + 1;
453  newSocket->rcvNxt = newSocket->irs + 1;
454  newSocket->rcvUser = 0;
455  newSocket->rcvWnd = newSocket->rxBufferSize;
456 
457  //Set initial retransmission timeout
458  newSocket->rto = newSocket->interface->initialRto;
459 
460 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
461  //Default congestion state
462  newSocket->congestState = TCP_CONGEST_STATE_IDLE;
463 
464  //Initial congestion window
465  newSocket->cwnd = MIN((uint32_t) newSocket->smss * TCP_INITIAL_WINDOW,
466  newSocket->txBufferSize);
467 
468  //Slow start threshold should be set arbitrarily high
469  newSocket->ssthresh = UINT32_MAX;
470  //Recover is set to the initial send sequence number
471  newSocket->recover = newSocket->iss;
472 #endif
473 
474 #if (TCP_WINDOW_SCALE_SUPPORT == ENABLED)
475  //If a Window Scale option is received with a shift.cnt value larger
476  //than 14, the TCP should log the error but must use 14 instead of
477  //the specified value (refer to RFC 7323, section 2.3)
478  newSocket->wndScaleOptionReceived = queueItem->wndScaleOptionReceived;
479  newSocket->sndWndShift = MIN(queueItem->wndScaleFactor, 14);
480 #endif
481 
482 #if (TCP_SACK_SUPPORT == ENABLED)
483  //The SACK Permitted option can be sent in a SYN segment to
484  //indicate that the SACK option can be used once the connection
485  //is established
486  newSocket->sackPermitted = queueItem->sackPermitted;
487 #endif
488  //The connection state should be changed to SYN-RECEIVED
490 
491  //Number of times TCP connections have made a direct transition to
492  //the SYN-RECEIVED state from the LISTEN state
493  MIB2_TCP_INC_COUNTER32(tcpPassiveOpens, 1);
494  TCP_MIB_INC_COUNTER32(tcpPassiveOpens, 1);
495 
496  //Send a SYN/ACK control segment
497  error = tcpSendSegment(newSocket, TCP_FLAG_SYN | TCP_FLAG_ACK,
498  newSocket->iss, newSocket->rcvNxt, 0, TRUE);
499 
500  //TCP segment successfully sent?
501  if(!error)
502  {
503  //Remove the item from the SYN queue
504  socket->synQueue = queueItem->next;
505  //Deallocate memory buffer
506  memPoolFree(queueItem);
507  //Update the state of events
509 
510  //We are done
511  break;
512  }
513  }
514 
515  //Dispose the socket
516  tcpAbort(newSocket);
517  }
518 
519  //Debug message
520  TRACE_WARNING("Cannot accept TCP connection!\r\n");
521 
522  //Remove the item from the SYN queue
523  socket->synQueue = queueItem->next;
524  //Deallocate memory buffer
525  memPoolFree(queueItem);
526 
527  //Wait for the next connection attempt
528  }
529 
530  //Release exclusive access
532 
533  //Return a handle to the newly created socket
534  return newSocket;
535 }
536 
537 
538 /**
539  * @brief Send data to a connected socket
540  * @param[in] socket Handle that identifies a connected socket
541  * @param[in] data Pointer to a buffer containing the data to be transmitted
542  * @param[in] length Number of bytes to be transmitted
543  * @param[out] written Actual number of bytes written (optional parameter)
544  * @param[in] flags Set of flags that influences the behavior of this function
545  * @return Error code
546  **/
547 
548 error_t tcpSend(Socket *socket, const uint8_t *data, size_t length,
549  size_t *written, uint_t flags)
550 {
551  uint_t n;
553  uint_t event;
554 
555  //Check whether the socket is in the listening state
556  if(socket->state == TCP_STATE_LISTEN)
557  return ERROR_NOT_CONNECTED;
558 
559  //Actual number of bytes written
560  totalLength = 0;
561 
562  //Send as much data as possible
563  do
564  {
565  //Wait until there is more room in the send buffer
567 
568  //A timeout exception occurred?
569  if(event != SOCKET_EVENT_TX_READY)
570  return ERROR_TIMEOUT;
571 
572  //Check current TCP state
573  switch(socket->state)
574  {
575  //ESTABLISHED or CLOSE-WAIT state?
578  //The send buffer is now available for writing
579  break;
580 
581  //LAST-ACK, FIN-WAIT-1, FIN-WAIT-2, CLOSING or TIME-WAIT state?
582  case TCP_STATE_LAST_ACK:
585  case TCP_STATE_CLOSING:
586  case TCP_STATE_TIME_WAIT:
587  //The connection is being closed
589 
590  //CLOSED state?
591  default:
592  //The connection was reset by remote side?
593  return (socket->resetFlag) ? ERROR_CONNECTION_RESET : ERROR_NOT_CONNECTED;
594  }
595 
596  //Determine the actual number of bytes in the send buffer
597  n = socket->sndUser + socket->sndNxt - socket->sndUna;
598  //Exit immediately if the transmission buffer is full (sanity check)
599  if(n >= socket->txBufferSize)
600  return ERROR_FAILURE;
601 
602  //Number of bytes available for writing
603  n = socket->txBufferSize - n;
604  //Calculate the number of bytes to copy at a time
605  n = MIN(n, length - totalLength);
606 
607  //Any data to copy?
608  if(n > 0)
609  {
610  //Copy user data to send buffer
611  tcpWriteTxBuffer(socket, socket->sndNxt + socket->sndUser, data, n);
612 
613  //Update the number of data buffered but not yet sent
614  socket->sndUser += n;
615  //Advance data pointer
616  data += n;
617  //Update byte counter
618  totalLength += n;
619 
620  //Total number of data that have been written
621  if(written != NULL)
622  {
623  *written = totalLength;
624  }
625 
626  //Update TX events
628 
629  //To avoid a deadlock, it is necessary to have a timeout to force
630  //transmission of data, overriding the SWS avoidance algorithm. In
631  //practice, this timeout should seldom occur (refer to RFC 1122,
632  //section 4.2.3.4)
633  if(socket->sndUser == n)
634  {
635  netStartTimer(&socket->overrideTimer, TCP_OVERRIDE_TIMEOUT);
636  }
637  }
638 
639  //The Nagle algorithm should be implemented to coalesce short segments
640  //(refer to RFC 1122 4.2.3.4)
642 
643  //Send as much data as possible
644  } while(totalLength < length);
645 
646  //The SOCKET_FLAG_WAIT_ACK flag causes the function to wait for
647  //acknowledgment from the remote side
648  if((flags & SOCKET_FLAG_WAIT_ACK) != 0)
649  {
650  //Wait for the data to be acknowledged
652 
653  //A timeout exception occurred?
654  if(event != SOCKET_EVENT_TX_ACKED)
655  return ERROR_TIMEOUT;
656 
657  //The connection closed before an acknowledgment was received?
658  if(socket->state != TCP_STATE_ESTABLISHED && socket->state != TCP_STATE_CLOSE_WAIT)
659  return ERROR_NOT_CONNECTED;
660  }
661 
662  //Successful write operation
663  return NO_ERROR;
664 }
665 
666 
667 /**
668  * @brief Receive data from a connected socket
669  * @param[in] socket Handle that identifies a connected socket
670  * @param[out] data Buffer where to store the incoming data
671  * @param[in] size Maximum number of bytes that can be received
672  * @param[out] received Number of bytes that have been received
673  * @param[in] flags Set of flags that influences the behavior of this function
674  * @return Error code
675  **/
676 
677 error_t tcpReceive(Socket *socket, uint8_t *data, size_t size,
678  size_t *received, uint_t flags)
679 {
680  uint_t i;
681  uint_t n;
682  uint_t event;
683  uint32_t seqNum;
684  systime_t timeout;
685 
686  //Retrieve the break character code
687  char_t c = LSB(flags);
688  //No data has been read yet
689  *received = 0;
690 
691  //Check whether the socket is in the listening state
692  if(socket->state == TCP_STATE_LISTEN)
693  return ERROR_NOT_CONNECTED;
694 
695  //Read as much data as possible
696  while(*received < size)
697  {
698  //The SOCKET_FLAG_DONT_WAIT enables non-blocking operation
699  timeout = (flags & SOCKET_FLAG_DONT_WAIT) ? 0 : socket->timeout;
700  //Wait for data to be available for reading
701  event = tcpWaitForEvents(socket, SOCKET_EVENT_RX_READY, timeout);
702 
703  //A timeout exception occurred?
704  if(event != SOCKET_EVENT_RX_READY)
705  return ERROR_TIMEOUT;
706 
707  //Check current TCP state
708  switch(socket->state)
709  {
710  //ESTABLISHED, FIN-WAIT-1 or FIN-WAIT-2 state?
714  //Sequence number of the first byte to read
715  seqNum = socket->rcvNxt - socket->rcvUser;
716  //Data is available in the receive buffer
717  break;
718 
719  //CLOSE-WAIT, LAST-ACK, CLOSING or TIME-WAIT state?
721  case TCP_STATE_LAST_ACK:
722  case TCP_STATE_CLOSING:
723  case TCP_STATE_TIME_WAIT:
724  //The user must be satisfied with data already on hand
725  if(socket->rcvUser == 0)
726  {
727  if(*received > 0)
728  {
729  return NO_ERROR;
730  }
731  else
732  {
733  return ERROR_END_OF_STREAM;
734  }
735  }
736 
737  //Sequence number of the first byte to read
738  seqNum = (socket->rcvNxt - 1) - socket->rcvUser;
739  //Data is available in the receive buffer
740  break;
741 
742  //CLOSED state?
743  default:
744  //The connection was reset by remote side?
745  if(socket->resetFlag)
746  return ERROR_CONNECTION_RESET;
747 
748  //The connection has not yet been established?
749  if(!socket->closedFlag)
750  return ERROR_NOT_CONNECTED;
751 
752  //The user must be satisfied with data already on hand
753  if(socket->rcvUser == 0)
754  {
755  if(*received > 0)
756  {
757  return NO_ERROR;
758  }
759  else
760  {
761  return ERROR_END_OF_STREAM;
762  }
763  }
764 
765  //Sequence number of the first byte to read
766  seqNum = (socket->rcvNxt - 1) - socket->rcvUser;
767  //Data is available in the receive buffer
768  break;
769  }
770 
771  //Sanity check
772  if(socket->rcvUser == 0)
773  return ERROR_FAILURE;
774 
775  //Calculate the number of bytes to read at a time
776  n = MIN(socket->rcvUser, size - *received);
777  //Copy data from circular buffer
779 
780  //Read data until a break character is encountered?
781  if((flags & SOCKET_FLAG_BREAK_CHAR) != 0)
782  {
783  //Search for the specified break character
784  for(i = 0; i < n && data[i] != c; i++)
785  {
786  }
787 
788  //Adjust the number of data to read
789  n = MIN(n, i + 1);
790  }
791 
792  //Total number of data that have been read
793  *received += n;
794  //Remaining data still available in the receive buffer
795  socket->rcvUser -= n;
796 
797  //Update the receive window
799  //Update RX event state
801 
802  //The SOCKET_FLAG_BREAK_CHAR flag causes the function to stop reading
803  //data as soon as the specified break character is encountered
804  if((flags & SOCKET_FLAG_BREAK_CHAR) != 0)
805  {
806  //Check whether a break character has been found
807  if(data[n - 1] == c)
808  break;
809  }
810  //The SOCKET_FLAG_WAIT_ALL flag causes the function to return
811  //only when the requested number of bytes have been read
812  else if((flags & SOCKET_FLAG_WAIT_ALL) == 0)
813  {
814  break;
815  }
816 
817  //Advance data pointer
818  data += n;
819  }
820 
821  //Successful read operation
822  return NO_ERROR;
823 }
824 
825 
826 /**
827  * @brief Shutdown gracefully reception, transmission, or both
828  *
829  * Note that socketShutdown() does not close the socket, and resources attached
830  * to the socket will not be freed until socketClose() is invoked
831  *
832  * @param[in] socket Handle to a socket
833  * @param[in] how Flag that describes what types of operation will no longer
834  * be allowed
835  * @return Error code
836  **/
837 
839 {
840  error_t error;
841  uint_t event;
842 
843  //Initialize status code
844  error = NO_ERROR;
845 
846  //Check whether transmission should be disabled
847  if(how == SOCKET_SD_SEND || how == SOCKET_SD_BOTH)
848  {
849  //Shutdown TX path
850  while(!error)
851  {
852  //LISTEN state?
853  if(socket->state == TCP_STATE_LISTEN)
854  {
855  //The connection does not exist
856  error = ERROR_NOT_CONNECTED;
857  }
858  //SYN-RECEIVED, ESTABLISHED or CLOSE-WAIT state?
859  else if(socket->state == TCP_STATE_SYN_RECEIVED ||
860  socket->state == TCP_STATE_ESTABLISHED ||
861  socket->state == TCP_STATE_CLOSE_WAIT)
862  {
863  //Any data pending in the send buffer?
864  if(socket->sndUser > 0)
865  {
866  //Flush the send buffer
868 
869  //Make sure all the data has been sent out
871  socket->timeout);
872 
873  //Timeout error?
874  if(event != SOCKET_EVENT_TX_DONE)
875  {
876  error = ERROR_TIMEOUT;
877  }
878  }
879  else
880  {
881  //Send a FIN segment
883  socket->sndNxt, socket->rcvNxt, 0, TRUE);
884 
885  //Check status code
886  if(!error)
887  {
888  //Sequence number expected to be received
889  socket->sndNxt++;
890 
891  //Switch to the FIN-WAIT1 or LAST-ACK state
892  if(socket->state == TCP_STATE_SYN_RECEIVED ||
893  socket->state == TCP_STATE_ESTABLISHED)
894  {
896  }
897  else
898  {
900  }
901  }
902  }
903  }
904  //FIN-WAIT-1, CLOSING or LAST-ACK state?
905  else if(socket->state == TCP_STATE_FIN_WAIT_1 ||
906  socket->state == TCP_STATE_CLOSING ||
907  socket->state == TCP_STATE_LAST_ACK)
908  {
909  //Wait for the FIN to be acknowledged
911  socket->timeout);
912 
913  //Timeout interval elapsed?
914  if(event != SOCKET_EVENT_TX_SHUTDOWN)
915  {
916  error = ERROR_TIMEOUT;
917  }
918  }
919  //SYN-SENT, FIN-WAIT-2, TIME-WAIT or CLOSED state?
920  else
921  {
922  //The TX path is shutdown
923  break;
924  }
925  }
926  }
927 
928  //Check status code
929  if(!error)
930  {
931  //Check whether reception should be disabled
932  if(how == SOCKET_SD_RECEIVE || how == SOCKET_SD_BOTH)
933  {
934  //LISTEN state?
935  if(socket->state == TCP_STATE_LISTEN)
936  {
937  //The connection does not exist
938  error = ERROR_NOT_CONNECTED;
939  }
940  //SYN-SENT, SYN-RECEIVED, ESTABLISHED, FIN-WAIT-1 or FIN-WAIT-2 state?
941  else if(socket->state == TCP_STATE_SYN_SENT ||
942  socket->state == TCP_STATE_SYN_RECEIVED ||
943  socket->state == TCP_STATE_ESTABLISHED ||
944  socket->state == TCP_STATE_FIN_WAIT_1 ||
945  socket->state == TCP_STATE_FIN_WAIT_2)
946  {
947  //Wait for a FIN to be received
949  socket->timeout);
950 
951  //Timeout interval elapsed?
952  if(event != SOCKET_EVENT_RX_SHUTDOWN)
953  {
954  error = ERROR_TIMEOUT;
955  }
956  }
957  //CLOSING, TIME-WAIT, CLOSE-WAIT, LAST-ACK or CLOSED state?
958  else
959  {
960  //The RX path is shutdown
961  }
962  }
963  }
964 
965  //Return status code
966  return error;
967 }
968 
969 
970 /**
971  * @brief Abort an existing TCP connection
972  * @param[in] socket Handle identifying the socket to close
973  * @return Error code
974  **/
975 
977 {
978  error_t error;
979 
980  //Check current state
981  switch(socket->state)
982  {
983  //SYN-RECEIVED, ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2 or CLOSE-WAIT state?
989  //Send a reset segment
990  error = tcpSendResetSegment(socket, socket->sndNxt);
991  //Enter CLOSED state
993  //Delete TCB
995  //Mark the socket as closed
996  socket->type = SOCKET_TYPE_UNUSED;
997  //Return status code
998  return error;
999 
1000  //TIME-WAIT state?
1001  case TCP_STATE_TIME_WAIT:
1002 #if (TCP_2MSL_TIMER > 0)
1003  //The user doe not own the socket anymore...
1004  socket->ownedFlag = FALSE;
1005  //TCB will be deleted and socket will be closed
1006  //when the 2MSL timer will elapse
1007  return NO_ERROR;
1008 #else
1009  //Enter CLOSED state
1011  //Delete TCB
1013  //Mark the socket as closed
1014  socket->type = SOCKET_TYPE_UNUSED;
1015  //No error to report
1016  return NO_ERROR;
1017 #endif
1018 
1019  //Any other state?
1020  default:
1021  //Enter CLOSED state
1023  //Delete TCB
1025  //Mark the socket as closed
1026  socket->type = SOCKET_TYPE_UNUSED;
1027  //No error to report
1028  return NO_ERROR;
1029  }
1030 }
1031 
1032 
1033 /**
1034  * @brief Get the current state of the TCP FSM
1035  * @param[in] socket Handle identifying the socket
1036  * @return TCP FSM state
1037  **/
1038 
1040 {
1041  TcpState state;
1042 
1043  //Get exclusive access
1045 
1046  //Get TCP FSM current state
1047  state = socket->state;
1048 
1049  //Release exclusive access
1051 
1052  //Return current state
1053  return state;
1054 }
1055 
1056 
1057 /**
1058  * @brief Kill the oldest socket in the TIME-WAIT state
1059  * @return Handle identifying the oldest TCP connection in the TIME-WAIT state.
1060  * NULL is returned if no socket is currently in the TIME-WAIT state
1061  **/
1062 
1064 {
1065  uint_t i;
1066  systime_t time;
1067  Socket *socket;
1068  Socket *oldestSocket;
1069 
1070  //Get current time
1071  time = osGetSystemTime();
1072 
1073  //Keep track of the oldest socket in the TIME-WAIT state
1074  oldestSocket = NULL;
1075 
1076  //Loop through socket descriptors
1077  for(i = 0; i < SOCKET_MAX_COUNT; i++)
1078  {
1079  //Point to the current socket descriptor
1080  socket = &socketTable[i];
1081 
1082  //TCP connection found?
1083  if(socket->type == SOCKET_TYPE_STREAM)
1084  {
1085  //Check current state
1086  if(socket->state == TCP_STATE_TIME_WAIT)
1087  {
1088  //Keep track of the oldest socket in the TIME-WAIT state
1089  if(oldestSocket == NULL)
1090  {
1091  //Save socket handle
1092  oldestSocket = socket;
1093  }
1094  if((time - socket->timeWaitTimer.startTime) >
1095  (time - oldestSocket->timeWaitTimer.startTime))
1096  {
1097  //Save socket handle
1098  oldestSocket = socket;
1099  }
1100  }
1101  }
1102  }
1103 
1104  //Any connection in the TIME-WAIT state?
1105  if(oldestSocket != NULL)
1106  {
1107  //Enter CLOSED state
1108  tcpChangeState(oldestSocket, TCP_STATE_CLOSED);
1109  //Delete TCB
1110  tcpDeleteControlBlock(oldestSocket);
1111  //Mark the socket as closed
1112  oldestSocket->type = SOCKET_TYPE_UNUSED;
1113  }
1114 
1115  //The oldest connection in the TIME-WAIT state can be reused
1116  //when the socket table runs out of space
1117  return oldestSocket;
1118 }
1119 
1120 #endif
@ TCP_CONGEST_STATE_IDLE
Definition: tcp.h:295
void tcpUpdateReceiveWindow(Socket *socket)
Update receive window so as to avoid Silly Window Syndrome.
Definition: tcp_misc.c:1738
MIB-II module.
void netStartTimer(NetTimer *timer, systime_t interval)
Start timer.
Definition: net_misc.c:781
@ TCP_STATE_TIME_WAIT
Definition: tcp.h:285
#define TCP_INITIAL_WINDOW
Definition: tcp.h:159
@ SOCKET_FLAG_WAIT_ALL
Definition: socket.h:138
void memPoolFree(void *p)
Release a memory block.
Definition: net_mem.c:166
#define TCP_MAX_RTO
Definition: tcp.h:131
#define netMutex
Definition: net_legacy.h:195
IP network address.
Definition: ip.h:90
@ TCP_FLAG_FIN
Definition: tcp.h:307
@ SOCKET_FLAG_WAIT_ACK
Definition: socket.h:142
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:677
@ TCP_STATE_FIN_WAIT_1
Definition: tcp.h:282
uint16_t mss
Definition: tcp.h:414
#define TCP_OVERRIDE_TIMEOUT
Definition: tcp.h:187
#define TRUE
Definition: os_port.h:50
IpAddr srcAddr
Definition: tcp.h:410
@ ERROR_ALREADY_CONNECTED
Definition: error.h:82
uint8_t data[]
Definition: ethernet.h:224
bool_t wndScaleOptionReceived
Definition: tcp.h:417
@ ERROR_CONNECTION_RESET
Definition: error.h:79
@ TCP_STATE_CLOSE_WAIT
Definition: tcp.h:280
IpAddr destAddr
Definition: tcp.h:412
error_t tcpSendResetSegment(Socket *socket, uint32_t seqNum)
Send a TCP reset segment.
Definition: tcp_misc.c:421
uint16_t totalLength
Definition: ipv4.h:323
uint16_t srcPort
Definition: tcp.h:411
struct _TcpSynQueueItem * next
Definition: tcp.h:408
@ ERROR_END_OF_STREAM
Definition: error.h:211
error_t tcpListen(Socket *socket, uint_t backlog)
Place a socket in the listening state.
Definition: tcp.c:297
@ SOCKET_TYPE_STREAM
Definition: socket.h:92
@ TCP_FLAG_ACK
Definition: tcp.h:311
#define SOCKET_EPHEMERAL_PORT_MIN
Definition: socket.h:67
void tcpDeleteControlBlock(Socket *socket)
Delete TCB structure.
Definition: tcp_misc.c:1429
@ SOCKET_SD_SEND
Definition: socket.h:160
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:2361
TcpState
TCP FSM states.
Definition: tcp.h:274
#define FALSE
Definition: os_port.h:46
Helper functions for TCP.
#define SOCKET_EPHEMERAL_PORT_MAX
Definition: socket.h:74
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
void tcpChangeState(Socket *socket, TcpState newState)
Update TCP FSM current state.
Definition: tcp_misc.c:2144
void osResetEvent(OsEvent *event)
Set the specified event object to the nonsignaled state.
uint32_t netGenerateRandRange(uint32_t min, uint32_t max)
Generate a random value in the specified range.
Definition: net_misc.c:963
error_t
Error codes.
Definition: error.h:43
uint32_t seqNum
Definition: tcp.h:348
Socket * tcpKillOldestConnection(void)
Kill the oldest socket in the TIME-WAIT state.
Definition: tcp.c:1063
bool_t ipIsMulticastAddr(const IpAddr *ipAddr)
Determine whether an IP address is a multicast address.
Definition: ip.c:250
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:548
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:65
@ SOCKET_EVENT_TX_READY
Definition: socket.h:175
@ ERROR_INVALID_ADDRESS
Definition: error.h:103
@ 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:119
TcpState tcpGetState(Socket *socket)
Get the current state of the TCP FSM.
Definition: tcp.c:1039
#define NetInterface
Definition: net.h:36
NetInterface * interface
Definition: tcp.h:409
#define TCP_MAX_SYN_QUEUE_SIZE
Definition: tcp.h:103
@ SOCKET_EVENT_RX_SHUTDOWN
Definition: socket.h:180
bool_t ipIsUnspecifiedAddr(const IpAddr *ipAddr)
Compare an IP address against the unspecified address.
Definition: ip.c:167
#define TCP_MIB_INC_COUNTER32(name, value)
void tcpUpdateEvents(Socket *socket)
Update TCP related events.
Definition: tcp_misc.c:2175
@ TCP_STATE_SYN_SENT
Definition: tcp.h:277
@ TCP_FLAG_SYN
Definition: tcp.h:308
uint32_t isn
Definition: tcp.h:413
uint8_t length
Definition: tcp.h:375
#define LSB(x)
Definition: os_port.h:55
@ TCP_STATE_LAST_ACK
Definition: tcp.h:281
#define MIN(a, b)
Definition: os_port.h:63
@ SOCKET_EVENT_TX_DONE
Definition: socket.h:176
@ TCP_STATE_CLOSING
Definition: tcp.h:284
Socket socketTable[SOCKET_MAX_COUNT]
Definition: socket.c:49
bool_t ipIsBroadcastAddr(const IpAddr *ipAddr)
Determine whether an IP address is a broadcast address.
Definition: ip.c:288
@ ERROR_CONNECTION_CLOSING
Definition: error.h:78
systime_t tcpTickCounter
Definition: tcp.c:49
@ SOCKET_FLAG_BREAK_CHAR
Definition: socket.h:140
uint32_t systime_t
System time.
@ TCP_STATE_CLOSED
Definition: tcp.h:275
uint16_t port
Definition: dns_common.h:269
@ TCP_STATE_LISTEN
Definition: tcp.h:276
uint8_t flags
Definition: tcp.h:358
#define TRACE_WARNING(...)
Definition: debug.h:93
#define MAX(a, b)
Definition: os_port.h:67
@ ERROR_TIMEOUT
Definition: error.h:95
char char_t
Definition: compiler_port.h:55
Socket * socketAllocate(uint_t type, uint_t protocol)
Allocate a socket.
Definition: socket_misc.c:52
uint16_t tcpGetDynamicPort(void)
Get an ephemeral port number.
Definition: tcp.c:106
error_t tcpSetInitialRto(NetInterface *interface, systime_t initialRto)
Set TCP initial retransmission timeout.
Definition: tcp.c:77
@ SOCKET_EVENT_TX_ACKED
Definition: socket.h:177
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:2476
error_t tcpInit(void)
TCP related initialization.
Definition: tcp.c:60
@ SOCKET_FLAG_NO_DELAY
Definition: socket.h:143
@ SOCKET_EVENT_RX_READY
Definition: socket.h:179
@ ERROR_NOT_CONNECTED
Definition: error.h:80
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:178
uint8_t wndScaleFactor
Definition: tcp.h:416
@ SOCKET_TYPE_UNUSED
Definition: socket.h:91
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:159
error_t tcpAbort(Socket *socket)
Abort an existing TCP connection.
Definition: tcp.c:976
error_t tcpNagleAlgo(Socket *socket, uint_t flags)
Nagle algorithm implementation.
Definition: tcp_misc.c:2023
#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:322
@ TCP_STATE_FIN_WAIT_2
Definition: tcp.h:283
Socket API.
@ TCP_STATE_SYN_RECEIVED
Definition: tcp.h:278
error_t tcpConnect(Socket *socket, const IpAddr *remoteIpAddr, uint16_t remotePort)
Establish a TCP connection.
Definition: tcp.c:146
SYN queue item.
Definition: tcp.h:407
#define TCP_MIN_RTO
Definition: tcp.h:124
error_t tcpShutdown(Socket *socket, uint_t how)
Shutdown gracefully reception, transmission, or both.
Definition: tcp.c:838
TCP timer management.
Socket * tcpAccept(Socket *socket, IpAddr *clientIpAddr, uint16_t *clientPort)
Permit an incoming connection attempt on a TCP socket.
Definition: tcp.c:324
#define MIB2_TCP_INC_COUNTER32(name, value)
Definition: mib2_module.h:178
@ SOCKET_EVENT_CONNECTED
Definition: socket.h:173
@ ERROR_CONNECTION_FAILED
Definition: error.h:76
unsigned int uint_t
Definition: compiler_port.h:57
@ SOCKET_FLAG_DONT_WAIT
Definition: socket.h:139
TCP/IP stack core.
@ SOCKET_EVENT_CLOSED
Definition: socket.h:174
#define SOCKET_MAX_COUNT
Definition: socket.h:46
#define TCP_DEFAULT_MSS
Definition: tcp.h:258
uint32_t tcpGenerateInitialSeqNum(const IpAddr *localIpAddr, uint16_t localPort, const IpAddr *remoteIpAddr, uint16_t remotePort)
Initial sequence number generation.
Definition: tcp_misc.c:740
@ SOCKET_SD_BOTH
Definition: socket.h:161
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:68
@ SOCKET_IP_PROTO_TCP
Definition: socket.h:107
bool_t sackPermitted
Definition: tcp.h:420
@ TCP_STATE_ESTABLISHED
Definition: tcp.h:279
@ NO_ERROR
Success.
Definition: error.h:44
uint8_t c
Definition: ndp.h:514
Debugging facilities.
uint_t tcpWaitForEvents(Socket *socket, uint_t eventMask, systime_t timeout)
Wait for a particular TCP event.
Definition: tcp_misc.c:2323
#define arraysize(a)
Definition: os_port.h:71
systime_t osGetSystemTime(void)
Retrieve system time.