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