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.0
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  *written = totalLength;
623 
624  //Update TX events
626 
627  //To avoid a deadlock, it is necessary to have a timeout to force
628  //transmission of data, overriding the SWS avoidance algorithm. In
629  //practice, this timeout should seldom occur (refer to RFC 1122,
630  //section 4.2.3.4)
631  if(socket->sndUser == n)
632  {
633  netStartTimer(&socket->overrideTimer, TCP_OVERRIDE_TIMEOUT);
634  }
635  }
636 
637  //The Nagle algorithm should be implemented to coalesce short segments
638  //(refer to RFC 1122 4.2.3.4)
640 
641  //Send as much data as possible
642  } while(totalLength < length);
643 
644  //The SOCKET_FLAG_WAIT_ACK flag causes the function to wait for
645  //acknowledgment from the remote side
646  if((flags & SOCKET_FLAG_WAIT_ACK) != 0)
647  {
648  //Wait for the data to be acknowledged
650 
651  //A timeout exception occurred?
652  if(event != SOCKET_EVENT_TX_ACKED)
653  return ERROR_TIMEOUT;
654 
655  //The connection closed before an acknowledgment was received?
656  if(socket->state != TCP_STATE_ESTABLISHED && socket->state != TCP_STATE_CLOSE_WAIT)
657  return ERROR_NOT_CONNECTED;
658  }
659 
660  //Successful write operation
661  return NO_ERROR;
662 }
663 
664 
665 /**
666  * @brief Receive data from a connected socket
667  * @param[in] socket Handle that identifies a connected socket
668  * @param[out] data Buffer where to store the incoming data
669  * @param[in] size Maximum number of bytes that can be received
670  * @param[out] received Number of bytes that have been received
671  * @param[in] flags Set of flags that influences the behavior of this function
672  * @return Error code
673  **/
674 
675 error_t tcpReceive(Socket *socket, uint8_t *data, size_t size,
676  size_t *received, uint_t flags)
677 {
678  uint_t i;
679  uint_t n;
680  uint_t event;
681  uint32_t seqNum;
682  systime_t timeout;
683 
684  //Retrieve the break character code
685  char_t c = LSB(flags);
686  //No data has been read yet
687  *received = 0;
688 
689  //Check whether the socket is in the listening state
690  if(socket->state == TCP_STATE_LISTEN)
691  return ERROR_NOT_CONNECTED;
692 
693  //Read as much data as possible
694  while(*received < size)
695  {
696  //The SOCKET_FLAG_DONT_WAIT enables non-blocking operation
697  timeout = (flags & SOCKET_FLAG_DONT_WAIT) ? 0 : socket->timeout;
698  //Wait for data to be available for reading
699  event = tcpWaitForEvents(socket, SOCKET_EVENT_RX_READY, timeout);
700 
701  //A timeout exception occurred?
702  if(event != SOCKET_EVENT_RX_READY)
703  return ERROR_TIMEOUT;
704 
705  //Check current TCP state
706  switch(socket->state)
707  {
708  //ESTABLISHED, FIN-WAIT-1 or FIN-WAIT-2 state?
712  //Sequence number of the first byte to read
713  seqNum = socket->rcvNxt - socket->rcvUser;
714  //Data is available in the receive buffer
715  break;
716 
717  //CLOSE-WAIT, LAST-ACK, CLOSING or TIME-WAIT state?
719  case TCP_STATE_LAST_ACK:
720  case TCP_STATE_CLOSING:
721  case TCP_STATE_TIME_WAIT:
722  //The user must be satisfied with data already on hand
723  if(socket->rcvUser == 0)
724  {
725  if(*received > 0)
726  {
727  return NO_ERROR;
728  }
729  else
730  {
731  return ERROR_END_OF_STREAM;
732  }
733  }
734 
735  //Sequence number of the first byte to read
736  seqNum = (socket->rcvNxt - 1) - socket->rcvUser;
737  //Data is available in the receive buffer
738  break;
739 
740  //CLOSED state?
741  default:
742  //The connection was reset by remote side?
743  if(socket->resetFlag)
744  return ERROR_CONNECTION_RESET;
745 
746  //The connection has not yet been established?
747  if(!socket->closedFlag)
748  return ERROR_NOT_CONNECTED;
749 
750  //The user must be satisfied with data already on hand
751  if(socket->rcvUser == 0)
752  {
753  if(*received > 0)
754  {
755  return NO_ERROR;
756  }
757  else
758  {
759  return ERROR_END_OF_STREAM;
760  }
761  }
762 
763  //Sequence number of the first byte to read
764  seqNum = (socket->rcvNxt - 1) - socket->rcvUser;
765  //Data is available in the receive buffer
766  break;
767  }
768 
769  //Sanity check
770  if(socket->rcvUser == 0)
771  return ERROR_FAILURE;
772 
773  //Calculate the number of bytes to read at a time
774  n = MIN(socket->rcvUser, size - *received);
775  //Copy data from circular buffer
777 
778  //Read data until a break character is encountered?
779  if((flags & SOCKET_FLAG_BREAK_CHAR) != 0)
780  {
781  //Search for the specified break character
782  for(i = 0; i < n && data[i] != c; i++)
783  {
784  }
785 
786  //Adjust the number of data to read
787  n = MIN(n, i + 1);
788  }
789 
790  //Total number of data that have been read
791  *received += n;
792  //Remaining data still available in the receive buffer
793  socket->rcvUser -= n;
794 
795  //Update the receive window
797  //Update RX event state
799 
800  //The SOCKET_FLAG_BREAK_CHAR flag causes the function to stop reading
801  //data as soon as the specified break character is encountered
802  if((flags & SOCKET_FLAG_BREAK_CHAR) != 0)
803  {
804  //Check whether a break character has been found
805  if(data[n - 1] == c)
806  break;
807  }
808  //The SOCKET_FLAG_WAIT_ALL flag causes the function to return
809  //only when the requested number of bytes have been read
810  else if((flags & SOCKET_FLAG_WAIT_ALL) == 0)
811  {
812  break;
813  }
814 
815  //Advance data pointer
816  data += n;
817  }
818 
819  //Successful read operation
820  return NO_ERROR;
821 }
822 
823 
824 /**
825  * @brief Shutdown gracefully reception, transmission, or both
826  *
827  * Note that socketShutdown() does not close the socket, and resources attached
828  * to the socket will not be freed until socketClose() is invoked
829  *
830  * @param[in] socket Handle to a socket
831  * @param[in] how Flag that describes what types of operation will no longer
832  * be allowed
833  * @return Error code
834  **/
835 
837 {
838  error_t error;
839  uint_t event;
840 
841  //Initialize status code
842  error = NO_ERROR;
843 
844  //Check whether transmission should be disabled
845  if(how == SOCKET_SD_SEND || how == SOCKET_SD_BOTH)
846  {
847  //Shutdown TX path
848  while(!error)
849  {
850  //LISTEN state?
851  if(socket->state == TCP_STATE_LISTEN)
852  {
853  //The connection does not exist
854  error = ERROR_NOT_CONNECTED;
855  }
856  //SYN-RECEIVED, ESTABLISHED or CLOSE-WAIT state?
857  else if(socket->state == TCP_STATE_SYN_RECEIVED ||
858  socket->state == TCP_STATE_ESTABLISHED ||
859  socket->state == TCP_STATE_CLOSE_WAIT)
860  {
861  //Any data pending in the send buffer?
862  if(socket->sndUser > 0)
863  {
864  //Flush the send buffer
866 
867  //Make sure all the data has been sent out
869  socket->timeout);
870 
871  //Timeout error?
872  if(event != SOCKET_EVENT_TX_DONE)
873  {
874  error = ERROR_TIMEOUT;
875  }
876  }
877  else
878  {
879  //Send a FIN segment
881  socket->sndNxt, socket->rcvNxt, 0, TRUE);
882 
883  //Check status code
884  if(!error)
885  {
886  //Sequence number expected to be received
887  socket->sndNxt++;
888 
889  //Switch to the FIN-WAIT1 or LAST-ACK state
890  if(socket->state == TCP_STATE_SYN_RECEIVED ||
891  socket->state == TCP_STATE_ESTABLISHED)
892  {
894  }
895  else
896  {
898  }
899  }
900  }
901  }
902  //FIN-WAIT-1, CLOSING or LAST-ACK state?
903  else if(socket->state == TCP_STATE_FIN_WAIT_1 ||
904  socket->state == TCP_STATE_CLOSING ||
905  socket->state == TCP_STATE_LAST_ACK)
906  {
907  //Wait for the FIN to be acknowledged
909  socket->timeout);
910 
911  //Timeout interval elapsed?
912  if(event != SOCKET_EVENT_TX_SHUTDOWN)
913  {
914  error = ERROR_TIMEOUT;
915  }
916  }
917  //SYN-SENT, FIN-WAIT-2, TIME-WAIT or CLOSED state?
918  else
919  {
920  //The TX path is shutdown
921  break;
922  }
923  }
924  }
925 
926  //Check status code
927  if(!error)
928  {
929  //Check whether reception should be disabled
930  if(how == SOCKET_SD_RECEIVE || how == SOCKET_SD_BOTH)
931  {
932  //LISTEN state?
933  if(socket->state == TCP_STATE_LISTEN)
934  {
935  //The connection does not exist
936  error = ERROR_NOT_CONNECTED;
937  }
938  //SYN-SENT, SYN-RECEIVED, ESTABLISHED, FIN-WAIT-1 or FIN-WAIT-2 state?
939  else if(socket->state == TCP_STATE_SYN_SENT ||
940  socket->state == TCP_STATE_SYN_RECEIVED ||
941  socket->state == TCP_STATE_ESTABLISHED ||
942  socket->state == TCP_STATE_FIN_WAIT_1 ||
943  socket->state == TCP_STATE_FIN_WAIT_2)
944  {
945  //Wait for a FIN to be received
947  socket->timeout);
948 
949  //Timeout interval elapsed?
950  if(event != SOCKET_EVENT_RX_SHUTDOWN)
951  {
952  error = ERROR_TIMEOUT;
953  }
954  }
955  //CLOSING, TIME-WAIT, CLOSE-WAIT, LAST-ACK or CLOSED state?
956  else
957  {
958  //The RX path is shutdown
959  }
960  }
961  }
962 
963  //Return status code
964  return error;
965 }
966 
967 
968 /**
969  * @brief Abort an existing TCP connection
970  * @param[in] socket Handle identifying the socket to close
971  * @return Error code
972  **/
973 
975 {
976  error_t error;
977 
978  //Check current state
979  switch(socket->state)
980  {
981  //SYN-RECEIVED, ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2 or CLOSE-WAIT state?
987  //Send a reset segment
988  error = tcpSendResetSegment(socket, socket->sndNxt);
989  //Enter CLOSED state
991  //Delete TCB
993  //Mark the socket as closed
994  socket->type = SOCKET_TYPE_UNUSED;
995  //Return status code
996  return error;
997 
998  //TIME-WAIT state?
999  case TCP_STATE_TIME_WAIT:
1000 #if (TCP_2MSL_TIMER > 0)
1001  //The user doe not own the socket anymore...
1002  socket->ownedFlag = FALSE;
1003  //TCB will be deleted and socket will be closed
1004  //when the 2MSL timer will elapse
1005  return NO_ERROR;
1006 #else
1007  //Enter CLOSED state
1009  //Delete TCB
1011  //Mark the socket as closed
1012  socket->type = SOCKET_TYPE_UNUSED;
1013  //No error to report
1014  return NO_ERROR;
1015 #endif
1016 
1017  //Any other state?
1018  default:
1019  //Enter CLOSED state
1021  //Delete TCB
1023  //Mark the socket as closed
1024  socket->type = SOCKET_TYPE_UNUSED;
1025  //No error to report
1026  return NO_ERROR;
1027  }
1028 }
1029 
1030 
1031 /**
1032  * @brief Get the current state of the TCP FSM
1033  * @param[in] socket Handle identifying the socket
1034  * @return TCP FSM state
1035  **/
1036 
1038 {
1039  TcpState state;
1040 
1041  //Get exclusive access
1043 
1044  //Get TCP FSM current state
1045  state = socket->state;
1046 
1047  //Release exclusive access
1049 
1050  //Return current state
1051  return state;
1052 }
1053 
1054 
1055 /**
1056  * @brief Kill the oldest socket in the TIME-WAIT state
1057  * @return Handle identifying the oldest TCP connection in the TIME-WAIT state.
1058  * NULL is returned if no socket is currently in the TIME-WAIT state
1059  **/
1060 
1062 {
1063  uint_t i;
1064  systime_t time;
1065  Socket *socket;
1066  Socket *oldestSocket;
1067 
1068  //Get current time
1069  time = osGetSystemTime();
1070 
1071  //Keep track of the oldest socket in the TIME-WAIT state
1072  oldestSocket = NULL;
1073 
1074  //Loop through socket descriptors
1075  for(i = 0; i < SOCKET_MAX_COUNT; i++)
1076  {
1077  //Point to the current socket descriptor
1078  socket = &socketTable[i];
1079 
1080  //TCP connection found?
1081  if(socket->type == SOCKET_TYPE_STREAM)
1082  {
1083  //Check current state
1084  if(socket->state == TCP_STATE_TIME_WAIT)
1085  {
1086  //Keep track of the oldest socket in the TIME-WAIT state
1087  if(oldestSocket == NULL)
1088  {
1089  //Save socket handle
1090  oldestSocket = socket;
1091  }
1092  if((time - socket->timeWaitTimer.startTime) >
1093  (time - oldestSocket->timeWaitTimer.startTime))
1094  {
1095  //Save socket handle
1096  oldestSocket = socket;
1097  }
1098  }
1099  }
1100  }
1101 
1102  //Any connection in the TIME-WAIT state?
1103  if(oldestSocket != NULL)
1104  {
1105  //Enter CLOSED state
1106  tcpChangeState(oldestSocket, TCP_STATE_CLOSED);
1107  //Delete TCB
1108  tcpDeleteControlBlock(oldestSocket);
1109  //Mark the socket as closed
1110  oldestSocket->type = SOCKET_TYPE_UNUSED;
1111  }
1112 
1113  //The oldest connection in the TIME-WAIT state can be reused
1114  //when the socket table runs out of space
1115  return oldestSocket;
1116 }
1117 
1118 #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:675
@ 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:222
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:1061
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:1037
#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:267
@ 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:974
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:836
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.