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-2024 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.4.4
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  //Initial congestion window
238  socket->cwnd = MIN(TCP_INITIAL_WINDOW * socket->smss, socket->txBufferSize);
239  //Slow start threshold should be set arbitrarily high
240  socket->ssthresh = UINT16_MAX;
241  //Recover is set to the initial send sequence number
242  socket->recover = socket->iss;
243 #endif
244 
245  //Send a SYN segment
246  error = tcpSendSegment(socket, TCP_FLAG_SYN, socket->iss, 0, 0, TRUE);
247  //Failed to send TCP segment?
248  if(error)
249  return error;
250 
251  //Switch to the SYN-SENT state
253 
254  //Number of times TCP connections have made a direct transition to
255  //the SYN-SENT state from the CLOSED state
256  MIB2_TCP_INC_COUNTER32(tcpActiveOpens, 1);
257  TCP_MIB_INC_COUNTER32(tcpActiveOpens, 1);
258  }
259 
260  //Wait for the connection to be established
262  SOCKET_EVENT_CLOSED, socket->timeout);
263 
264  //Return status code
265  if(event == SOCKET_EVENT_CONNECTED)
266  {
267  //Connection successfully established
268  return NO_ERROR;
269  }
270  else if(event == SOCKET_EVENT_CLOSED)
271  {
272  //Failed to establish connection
274  }
275  else
276  {
277  //Timeout exception
278  return ERROR_TIMEOUT;
279  }
280 }
281 
282 
283 /**
284  * @brief Place a socket in the listening state
285  *
286  * Place a socket in a state in which it is listening for an incoming connection
287  *
288  * @param[in] socket Socket to place in the listening state
289  * @param[in] backlog backlog The maximum length of the pending connection queue.
290  * If this parameter is zero, then the default backlog value is used instead
291  * @return Error code
292  **/
293 
295 {
296  //Socket already connected?
297  if(socket->state != TCP_STATE_CLOSED)
299 
300  //Set the size of the SYN queue
301  socket->synQueueSize = (backlog > 0) ? backlog : TCP_DEFAULT_SYN_QUEUE_SIZE;
302  //Limit the number of pending connections
303  socket->synQueueSize = MIN(socket->synQueueSize, TCP_MAX_SYN_QUEUE_SIZE);
304 
305  //Place the socket in the listening state
307 
308  //Successful processing
309  return NO_ERROR;
310 }
311 
312 
313 /**
314  * @brief Permit an incoming connection attempt on a TCP socket
315  * @param[in] socket Handle to a socket previously placed in a listening state
316  * @param[out] clientIpAddr IP address of the client
317  * @param[out] clientPort Port number used by the client
318  * @return Handle to the socket in which the actual connection is made
319  **/
320 
321 Socket *tcpAccept(Socket *socket, IpAddr *clientIpAddr, uint16_t *clientPort)
322 {
323  error_t error;
324  Socket *newSocket;
325  TcpSynQueueItem *queueItem;
326 
327  //Ensure the socket was previously placed in the listening state
329  return NULL;
330 
331  //Get exclusive access
333 
334  //Wait for an connection attempt
335  while(1)
336  {
337  //The SYN queue is empty?
338  if(socket->synQueue == NULL)
339  {
340  //Set the events the application is interested in
341  socket->eventMask = SOCKET_EVENT_RX_READY;
342  //Reset the event object
343  osResetEvent(&socket->event);
344 
345  //Release exclusive access
347  //Wait until a SYN message is received from a client
348  osWaitForEvent(&socket->event, socket->timeout);
349  //Get exclusive access
351  }
352 
353  //Check whether the queue is still empty
354  if(socket->synQueue == NULL)
355  {
356  //Timeout error
357  newSocket = NULL;
358  //Exit immediately
359  break;
360  }
361 
362  //Point to the first item in the SYN queue
363  queueItem = socket->synQueue;
364 
365  //The function optionally returns the IP address of the client
366  if(clientIpAddr != NULL)
367  {
368  *clientIpAddr = queueItem->srcAddr;
369  }
370 
371  //The function optionally returns the port number used by the client
372  if(clientPort != NULL)
373  {
374  *clientPort = queueItem->srcPort;
375  }
376 
377  //Create a new socket to handle the incoming connection request
379 
380  //Socket successfully created?
381  if(newSocket != NULL)
382  {
383  //The user owns the socket
384  newSocket->ownedFlag = TRUE;
385 
386  //Inherit parameters from the listening socket
387  newSocket->mss = socket->mss;
388  newSocket->txBufferSize = socket->txBufferSize;
389  newSocket->rxBufferSize = socket->rxBufferSize;
390 
391 #if (TCP_KEEP_ALIVE_SUPPORT == ENABLED)
392  //Inherit keep-alive parameters from the listening socket
393  newSocket->keepAliveEnabled = socket->keepAliveEnabled;
394  newSocket->keepAliveIdle = socket->keepAliveIdle;
395  newSocket->keepAliveInterval = socket->keepAliveInterval;
396  newSocket->keepAliveMaxProbes = socket->keepAliveMaxProbes;
397 #endif
398  //Number of chunks that comprise the TX and the RX buffers
399  newSocket->txBuffer.maxChunkCount = arraysize(newSocket->txBuffer.chunk);
400  newSocket->rxBuffer.maxChunkCount = arraysize(newSocket->rxBuffer.chunk);
401 
402  //Allocate transmit buffer
403  error = netBufferSetLength((NetBuffer *) &newSocket->txBuffer,
404  newSocket->txBufferSize);
405 
406  //Check status code
407  if(!error)
408  {
409  //Allocate receive buffer
410  error = netBufferSetLength((NetBuffer *) &newSocket->rxBuffer,
411  newSocket->rxBufferSize);
412  }
413 
414  //Transmit and receive buffers successfully allocated?
415  if(!error)
416  {
417  //Bind the newly created socket to the appropriate interface
418  newSocket->interface = queueItem->interface;
419 
420  //Bind the socket to the specified address
421  newSocket->localIpAddr = queueItem->destAddr;
422  newSocket->localPort = socket->localPort;
423 
424  //Save the port number and the IP address of the remote host
425  newSocket->remoteIpAddr = queueItem->srcAddr;
426  newSocket->remotePort = queueItem->srcPort;
427 
428  //The SMSS is the size of the largest segment that the sender can
429  //transmit
430  newSocket->smss = queueItem->mss;
431 
432  //The RMSS is the size of the largest segment the receiver is
433  //willing to accept
434  newSocket->rmss = MIN(newSocket->mss, newSocket->rxBufferSize);
435 
436  //Generate the initial sequence number
437  newSocket->iss = tcpGenerateInitialSeqNum(&newSocket->localIpAddr,
438  newSocket->localPort, &newSocket->remoteIpAddr,
439  newSocket->remotePort);
440 
441  //Initialize TCP control block
442  newSocket->irs = queueItem->isn;
443  newSocket->sndUna = newSocket->iss;
444  newSocket->sndNxt = newSocket->iss + 1;
445  newSocket->rcvNxt = newSocket->irs + 1;
446  newSocket->rcvUser = 0;
447  newSocket->rcvWnd = newSocket->rxBufferSize;
448 
449  //Set initial retransmission timeout
450  newSocket->rto = newSocket->interface->initialRto;
451 
452 #if (TCP_CONGEST_CONTROL_SUPPORT == ENABLED)
453  //Default congestion state
454  newSocket->congestState = TCP_CONGEST_STATE_IDLE;
455 
456  //Initial congestion window
457  newSocket->cwnd = MIN(TCP_INITIAL_WINDOW * newSocket->smss,
458  newSocket->txBufferSize);
459 
460  //Slow start threshold should be set arbitrarily high
461  newSocket->ssthresh = UINT16_MAX;
462  //Recover is set to the initial send sequence number
463  newSocket->recover = newSocket->iss;
464 #endif
465 
466 #if (TCP_SACK_SUPPORT == ENABLED)
467  //The SACK Permitted option can be sent in a SYN segment to
468  //indicate that the SACK option can be used once the connection
469  //is established
470  newSocket->sackPermitted = queueItem->sackPermitted;
471 #endif
472  //The connection state should be changed to SYN-RECEIVED
474 
475  //Number of times TCP connections have made a direct transition to
476  //the SYN-RECEIVED state from the LISTEN state
477  MIB2_TCP_INC_COUNTER32(tcpPassiveOpens, 1);
478  TCP_MIB_INC_COUNTER32(tcpPassiveOpens, 1);
479 
480  //Send a SYN ACK control segment
481  error = tcpSendSegment(newSocket, TCP_FLAG_SYN | TCP_FLAG_ACK,
482  newSocket->iss, newSocket->rcvNxt, 0, TRUE);
483 
484  //TCP segment successfully sent?
485  if(!error)
486  {
487  //Remove the item from the SYN queue
488  socket->synQueue = queueItem->next;
489  //Deallocate memory buffer
490  memPoolFree(queueItem);
491  //Update the state of events
493 
494  //We are done
495  break;
496  }
497  }
498 
499  //Dispose the socket
500  tcpAbort(newSocket);
501  }
502 
503  //Debug message
504  TRACE_WARNING("Cannot accept TCP connection!\r\n");
505 
506  //Remove the item from the SYN queue
507  socket->synQueue = queueItem->next;
508  //Deallocate memory buffer
509  memPoolFree(queueItem);
510 
511  //Wait for the next connection attempt
512  }
513 
514  //Release exclusive access
516 
517  //Return a handle to the newly created socket
518  return newSocket;
519 }
520 
521 
522 /**
523  * @brief Send data to a connected socket
524  * @param[in] socket Handle that identifies a connected socket
525  * @param[in] data Pointer to a buffer containing the data to be transmitted
526  * @param[in] length Number of bytes to be transmitted
527  * @param[out] written Actual number of bytes written (optional parameter)
528  * @param[in] flags Set of flags that influences the behavior of this function
529  * @return Error code
530  **/
531 
532 error_t tcpSend(Socket *socket, const uint8_t *data, size_t length,
533  size_t *written, uint_t flags)
534 {
535  uint_t n;
537  uint_t event;
538 
539  //Check whether the socket is in the listening state
540  if(socket->state == TCP_STATE_LISTEN)
541  return ERROR_NOT_CONNECTED;
542 
543  //Actual number of bytes written
544  totalLength = 0;
545 
546  //Send as much data as possible
547  do
548  {
549  //Wait until there is more room in the send buffer
551 
552  //A timeout exception occurred?
553  if(event != SOCKET_EVENT_TX_READY)
554  return ERROR_TIMEOUT;
555 
556  //Check current TCP state
557  switch(socket->state)
558  {
559  //ESTABLISHED or CLOSE-WAIT state?
562  //The send buffer is now available for writing
563  break;
564 
565  //LAST-ACK, FIN-WAIT-1, FIN-WAIT-2, CLOSING or TIME-WAIT state?
566  case TCP_STATE_LAST_ACK:
569  case TCP_STATE_CLOSING:
570  case TCP_STATE_TIME_WAIT:
571  //The connection is being closed
573 
574  //CLOSED state?
575  default:
576  //The connection was reset by remote side?
577  return (socket->resetFlag) ? ERROR_CONNECTION_RESET : ERROR_NOT_CONNECTED;
578  }
579 
580  //Determine the actual number of bytes in the send buffer
581  n = socket->sndUser + socket->sndNxt - socket->sndUna;
582  //Exit immediately if the transmission buffer is full (sanity check)
583  if(n >= socket->txBufferSize)
584  return ERROR_FAILURE;
585 
586  //Number of bytes available for writing
587  n = socket->txBufferSize - n;
588  //Calculate the number of bytes to copy at a time
589  n = MIN(n, length - totalLength);
590 
591  //Any data to copy?
592  if(n > 0)
593  {
594  //Copy user data to send buffer
595  tcpWriteTxBuffer(socket, socket->sndNxt + socket->sndUser, data, n);
596 
597  //Update the number of data buffered but not yet sent
598  socket->sndUser += n;
599  //Advance data pointer
600  data += n;
601  //Update byte counter
602  totalLength += n;
603 
604  //Total number of data that have been written
605  if(written != NULL)
606  *written = totalLength;
607 
608  //Update TX events
610 
611  //To avoid a deadlock, it is necessary to have a timeout to force
612  //transmission of data, overriding the SWS avoidance algorithm. In
613  //practice, this timeout should seldom occur (refer to RFC 1122,
614  //section 4.2.3.4)
615  if(socket->sndUser == n)
616  {
617  netStartTimer(&socket->overrideTimer, TCP_OVERRIDE_TIMEOUT);
618  }
619  }
620 
621  //The Nagle algorithm should be implemented to coalesce short segments
622  //(refer to RFC 1122 4.2.3.4)
624 
625  //Send as much data as possible
626  } while(totalLength < length);
627 
628  //The SOCKET_FLAG_WAIT_ACK flag causes the function to wait for
629  //acknowledgment from the remote side
630  if((flags & SOCKET_FLAG_WAIT_ACK) != 0)
631  {
632  //Wait for the data to be acknowledged
634 
635  //A timeout exception occurred?
636  if(event != SOCKET_EVENT_TX_ACKED)
637  return ERROR_TIMEOUT;
638 
639  //The connection closed before an acknowledgment was received?
640  if(socket->state != TCP_STATE_ESTABLISHED && socket->state != TCP_STATE_CLOSE_WAIT)
641  return ERROR_NOT_CONNECTED;
642  }
643 
644  //Successful write operation
645  return NO_ERROR;
646 }
647 
648 
649 /**
650  * @brief Receive data from a connected socket
651  * @param[in] socket Handle that identifies a connected socket
652  * @param[out] data Buffer where to store the incoming data
653  * @param[in] size Maximum number of bytes that can be received
654  * @param[out] received Number of bytes that have been received
655  * @param[in] flags Set of flags that influences the behavior of this function
656  * @return Error code
657  **/
658 
659 error_t tcpReceive(Socket *socket, uint8_t *data, size_t size,
660  size_t *received, uint_t flags)
661 {
662  uint_t i;
663  uint_t n;
664  uint_t event;
665  uint32_t seqNum;
666  systime_t timeout;
667 
668  //Retrieve the break character code
669  char_t c = LSB(flags);
670  //No data has been read yet
671  *received = 0;
672 
673  //Check whether the socket is in the listening state
674  if(socket->state == TCP_STATE_LISTEN)
675  return ERROR_NOT_CONNECTED;
676 
677  //Read as much data as possible
678  while(*received < size)
679  {
680  //The SOCKET_FLAG_DONT_WAIT enables non-blocking operation
681  timeout = (flags & SOCKET_FLAG_DONT_WAIT) ? 0 : socket->timeout;
682  //Wait for data to be available for reading
683  event = tcpWaitForEvents(socket, SOCKET_EVENT_RX_READY, timeout);
684 
685  //A timeout exception occurred?
686  if(event != SOCKET_EVENT_RX_READY)
687  return ERROR_TIMEOUT;
688 
689  //Check current TCP state
690  switch(socket->state)
691  {
692  //ESTABLISHED, FIN-WAIT-1 or FIN-WAIT-2 state?
696  //Sequence number of the first byte to read
697  seqNum = socket->rcvNxt - socket->rcvUser;
698  //Data is available in the receive buffer
699  break;
700 
701  //CLOSE-WAIT, LAST-ACK, CLOSING or TIME-WAIT state?
703  case TCP_STATE_LAST_ACK:
704  case TCP_STATE_CLOSING:
705  case TCP_STATE_TIME_WAIT:
706  //The user must be satisfied with data already on hand
707  if(socket->rcvUser == 0)
708  {
709  if(*received > 0)
710  {
711  return NO_ERROR;
712  }
713  else
714  {
715  return ERROR_END_OF_STREAM;
716  }
717  }
718 
719  //Sequence number of the first byte to read
720  seqNum = (socket->rcvNxt - 1) - socket->rcvUser;
721  //Data is available in the receive buffer
722  break;
723 
724  //CLOSED state?
725  default:
726  //The connection was reset by remote side?
727  if(socket->resetFlag)
728  return ERROR_CONNECTION_RESET;
729 
730  //The connection has not yet been established?
731  if(!socket->closedFlag)
732  return ERROR_NOT_CONNECTED;
733 
734  //The user must be satisfied with data already on hand
735  if(socket->rcvUser == 0)
736  {
737  if(*received > 0)
738  {
739  return NO_ERROR;
740  }
741  else
742  {
743  return ERROR_END_OF_STREAM;
744  }
745  }
746 
747  //Sequence number of the first byte to read
748  seqNum = (socket->rcvNxt - 1) - socket->rcvUser;
749  //Data is available in the receive buffer
750  break;
751  }
752 
753  //Sanity check
754  if(socket->rcvUser == 0)
755  return ERROR_FAILURE;
756 
757  //Calculate the number of bytes to read at a time
758  n = MIN(socket->rcvUser, size - *received);
759  //Copy data from circular buffer
761 
762  //Read data until a break character is encountered?
763  if((flags & SOCKET_FLAG_BREAK_CHAR) != 0)
764  {
765  //Search for the specified break character
766  for(i = 0; i < n && data[i] != c; i++)
767  {
768  }
769 
770  //Adjust the number of data to read
771  n = MIN(n, i + 1);
772  }
773 
774  //Total number of data that have been read
775  *received += n;
776  //Remaining data still available in the receive buffer
777  socket->rcvUser -= n;
778 
779  //Update the receive window
781  //Update RX event state
783 
784  //The SOCKET_FLAG_BREAK_CHAR flag causes the function to stop reading
785  //data as soon as the specified break character is encountered
786  if((flags & SOCKET_FLAG_BREAK_CHAR) != 0)
787  {
788  //Check whether a break character has been found
789  if(data[n - 1] == c)
790  break;
791  }
792  //The SOCKET_FLAG_WAIT_ALL flag causes the function to return
793  //only when the requested number of bytes have been read
794  else if((flags & SOCKET_FLAG_WAIT_ALL) == 0)
795  {
796  break;
797  }
798 
799  //Advance data pointer
800  data += n;
801  }
802 
803  //Successful read operation
804  return NO_ERROR;
805 }
806 
807 
808 /**
809  * @brief Shutdown gracefully reception, transmission, or both
810  *
811  * Note that socketShutdown() does not close the socket, and resources attached
812  * to the socket will not be freed until socketClose() is invoked
813  *
814  * @param[in] socket Handle to a socket
815  * @param[in] how Flag that describes what types of operation will no longer
816  * be allowed
817  * @return Error code
818  **/
819 
821 {
822  error_t error;
823  uint_t event;
824 
825  //Initialize status code
826  error = NO_ERROR;
827 
828  //Check whether transmission should be disabled
829  if(how == SOCKET_SD_SEND || how == SOCKET_SD_BOTH)
830  {
831  //Shutdown TX path
832  while(!error)
833  {
834  //LISTEN state?
835  if(socket->state == TCP_STATE_LISTEN)
836  {
837  //The connection does not exist
838  error = ERROR_NOT_CONNECTED;
839  }
840  //SYN-RECEIVED, ESTABLISHED or CLOSE-WAIT state?
841  else if(socket->state == TCP_STATE_SYN_RECEIVED ||
842  socket->state == TCP_STATE_ESTABLISHED ||
843  socket->state == TCP_STATE_CLOSE_WAIT)
844  {
845  //Any data pending in the send buffer?
846  if(socket->sndUser > 0)
847  {
848  //Flush the send buffer
850 
851  //Make sure all the data has been sent out
853  socket->timeout);
854 
855  //Timeout error?
856  if(event != SOCKET_EVENT_TX_DONE)
857  {
858  error = ERROR_TIMEOUT;
859  }
860  }
861  else
862  {
863  //Send a FIN segment
865  socket->sndNxt, socket->rcvNxt, 0, TRUE);
866 
867  //Check status code
868  if(!error)
869  {
870  //Sequence number expected to be received
871  socket->sndNxt++;
872 
873  //Switch to the FIN-WAIT1 or LAST-ACK state
874  if(socket->state == TCP_STATE_SYN_RECEIVED ||
875  socket->state == TCP_STATE_ESTABLISHED)
876  {
878  }
879  else
880  {
882  }
883  }
884  }
885  }
886  //FIN-WAIT-1, CLOSING or LAST-ACK state?
887  else if(socket->state == TCP_STATE_FIN_WAIT_1 ||
888  socket->state == TCP_STATE_CLOSING ||
889  socket->state == TCP_STATE_LAST_ACK)
890  {
891  //Wait for the FIN to be acknowledged
893  socket->timeout);
894 
895  //Timeout interval elapsed?
896  if(event != SOCKET_EVENT_TX_SHUTDOWN)
897  {
898  error = ERROR_TIMEOUT;
899  }
900  }
901  //SYN-SENT, FIN-WAIT-2, TIME-WAIT or CLOSED state?
902  else
903  {
904  //The TX path is shutdown
905  break;
906  }
907  }
908  }
909 
910  //Check status code
911  if(!error)
912  {
913  //Check whether reception should be disabled
914  if(how == SOCKET_SD_RECEIVE || how == SOCKET_SD_BOTH)
915  {
916  //LISTEN state?
917  if(socket->state == TCP_STATE_LISTEN)
918  {
919  //The connection does not exist
920  error = ERROR_NOT_CONNECTED;
921  }
922  //SYN-SENT, SYN-RECEIVED, ESTABLISHED, FIN-WAIT-1 or FIN-WAIT-2 state?
923  else if(socket->state == TCP_STATE_SYN_SENT ||
924  socket->state == TCP_STATE_SYN_RECEIVED ||
925  socket->state == TCP_STATE_ESTABLISHED ||
926  socket->state == TCP_STATE_FIN_WAIT_1 ||
927  socket->state == TCP_STATE_FIN_WAIT_2)
928  {
929  //Wait for a FIN to be received
931  socket->timeout);
932 
933  //Timeout interval elapsed?
934  if(event != SOCKET_EVENT_RX_SHUTDOWN)
935  {
936  error = ERROR_TIMEOUT;
937  }
938  }
939  //CLOSING, TIME-WAIT, CLOSE-WAIT, LAST-ACK or CLOSED state?
940  else
941  {
942  //The RX path is shutdown
943  }
944  }
945  }
946 
947  //Return status code
948  return error;
949 }
950 
951 
952 /**
953  * @brief Abort an existing TCP connection
954  * @param[in] socket Handle identifying the socket to close
955  * @return Error code
956  **/
957 
959 {
960  error_t error;
961 
962  //Check current state
963  switch(socket->state)
964  {
965  //SYN-RECEIVED, ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2 or CLOSE-WAIT state?
971  //Send a reset segment
972  error = tcpSendResetSegment(socket, socket->sndNxt);
973  //Enter CLOSED state
975  //Delete TCB
977  //Mark the socket as closed
978  socket->type = SOCKET_TYPE_UNUSED;
979  //Return status code
980  return error;
981 
982  //TIME-WAIT state?
983  case TCP_STATE_TIME_WAIT:
984 #if (TCP_2MSL_TIMER > 0)
985  //The user doe not own the socket anymore...
986  socket->ownedFlag = FALSE;
987  //TCB will be deleted and socket will be closed
988  //when the 2MSL timer will elapse
989  return NO_ERROR;
990 #else
991  //Enter CLOSED state
993  //Delete TCB
995  //Mark the socket as closed
996  socket->type = SOCKET_TYPE_UNUSED;
997  //No error to report
998  return NO_ERROR;
999 #endif
1000 
1001  //Any other state?
1002  default:
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  }
1012 }
1013 
1014 
1015 /**
1016  * @brief Get the current state of the TCP FSM
1017  * @param[in] socket Handle identifying the socket
1018  * @return TCP FSM state
1019  **/
1020 
1022 {
1023  TcpState state;
1024 
1025  //Get exclusive access
1027 
1028  //Get TCP FSM current state
1029  state = socket->state;
1030 
1031  //Release exclusive access
1033 
1034  //Return current state
1035  return state;
1036 }
1037 
1038 
1039 /**
1040  * @brief Kill the oldest socket in the TIME-WAIT state
1041  * @return Handle identifying the oldest TCP connection in the TIME-WAIT state.
1042  * NULL is returned if no socket is currently in the TIME-WAIT state
1043  **/
1044 
1046 {
1047  uint_t i;
1048  systime_t time;
1049  Socket *socket;
1050  Socket *oldestSocket;
1051 
1052  //Get current time
1053  time = osGetSystemTime();
1054 
1055  //Keep track of the oldest socket in the TIME-WAIT state
1056  oldestSocket = NULL;
1057 
1058  //Loop through socket descriptors
1059  for(i = 0; i < SOCKET_MAX_COUNT; i++)
1060  {
1061  //Point to the current socket descriptor
1062  socket = &socketTable[i];
1063 
1064  //TCP connection found?
1065  if(socket->type == SOCKET_TYPE_STREAM)
1066  {
1067  //Check current state
1068  if(socket->state == TCP_STATE_TIME_WAIT)
1069  {
1070  //Keep track of the oldest socket in the TIME-WAIT state
1071  if(oldestSocket == NULL)
1072  {
1073  //Save socket handle
1074  oldestSocket = socket;
1075  }
1076  if((time - socket->timeWaitTimer.startTime) >
1077  (time - oldestSocket->timeWaitTimer.startTime))
1078  {
1079  //Save socket handle
1080  oldestSocket = socket;
1081  }
1082  }
1083  }
1084  }
1085 
1086  //Any connection in the TIME-WAIT state?
1087  if(oldestSocket != NULL)
1088  {
1089  //Enter CLOSED state
1090  tcpChangeState(oldestSocket, TCP_STATE_CLOSED);
1091  //Delete TCB
1092  tcpDeleteControlBlock(oldestSocket);
1093  //Mark the socket as closed
1094  oldestSocket->type = SOCKET_TYPE_UNUSED;
1095  }
1096 
1097  //The oldest connection in the TIME-WAIT state can be reused
1098  //when the socket table runs out of space
1099  return oldestSocket;
1100 }
1101 
1102 #endif
@ TCP_CONGEST_STATE_IDLE
Definition: tcp.h:288
void tcpUpdateReceiveWindow(Socket *socket)
Update receive window so as to avoid Silly Window Syndrome.
Definition: tcp_misc.c:1636
MIB-II module.
void netStartTimer(NetTimer *timer, systime_t interval)
Start timer.
Definition: net_misc.c:766
@ TCP_STATE_TIME_WAIT
Definition: tcp.h:278
#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:300
@ 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:659
@ TCP_STATE_FIN_WAIT_1
Definition: tcp.h:275
uint16_t mss
Definition: tcp.h:407
#define TCP_OVERRIDE_TIMEOUT
Definition: tcp.h:187
#define TRUE
Definition: os_port.h:50
IpAddr srcAddr
Definition: tcp.h:403
@ ERROR_ALREADY_CONNECTED
Definition: error.h:82
uint8_t data[]
Definition: ethernet.h:222
@ ERROR_CONNECTION_RESET
Definition: error.h:79
@ TCP_STATE_CLOSE_WAIT
Definition: tcp.h:273
IpAddr destAddr
Definition: tcp.h:405
error_t tcpSendResetSegment(Socket *socket, uint32_t seqNum)
Send a TCP reset segment.
Definition: tcp_misc.c:371
uint16_t totalLength
Definition: ipv4.h:322
uint16_t srcPort
Definition: tcp.h:404
struct _TcpSynQueueItem * next
Definition: tcp.h:401
@ ERROR_END_OF_STREAM
Definition: error.h:210
error_t tcpListen(Socket *socket, uint_t backlog)
Place a socket in the listening state.
Definition: tcp.c:294
@ SOCKET_TYPE_STREAM
Definition: socket.h:92
@ TCP_FLAG_ACK
Definition: tcp.h:304
#define SOCKET_EPHEMERAL_PORT_MIN
Definition: socket.h:67
void tcpDeleteControlBlock(Socket *socket)
Delete TCB structure.
Definition: tcp_misc.c:1371
@ 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:2238
TcpState
TCP FSM states.
Definition: tcp.h:267
#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:2021
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:948
error_t
Error codes.
Definition: error.h:43
uint32_t seqNum
Definition: tcp.h:341
Socket * tcpKillOldestConnection(void)
Kill the oldest socket in the TIME-WAIT state.
Definition: tcp.c:1045
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:532
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:1021
#define NetInterface
Definition: net.h:36
NetInterface * interface
Definition: tcp.h:402
#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:2052
@ TCP_STATE_SYN_SENT
Definition: tcp.h:270
@ TCP_FLAG_SYN
Definition: tcp.h:301
uint32_t isn
Definition: tcp.h:406
uint8_t length
Definition: tcp.h:368
#define LSB(x)
Definition: os_port.h:55
@ TCP_STATE_LAST_ACK
Definition: tcp.h:274
#define MIN(a, b)
Definition: os_port.h:63
@ SOCKET_EVENT_TX_DONE
Definition: socket.h:176
@ TCP_STATE_CLOSING
Definition: tcp.h:277
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:268
uint16_t port
Definition: dns_common.h:267
@ TCP_STATE_LISTEN
Definition: tcp.h:269
uint8_t flags
Definition: tcp.h:351
#define TRACE_WARNING(...)
Definition: debug.h:85
#define MAX(a, b)
Definition: os_port.h:67
@ ERROR_TIMEOUT
Definition: error.h:95
char char_t
Definition: compiler_port.h:48
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:2353
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
@ 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:958
error_t tcpNagleAlgo(Socket *socket, uint_t flags)
Nagle algorithm implementation.
Definition: tcp_misc.c:1900
#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:276
Socket API.
@ TCP_STATE_SYN_RECEIVED
Definition: tcp.h:271
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:400
#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:820
TCP timer management.
Socket * tcpAccept(Socket *socket, IpAddr *clientIpAddr, uint16_t *clientPort)
Permit an incoming connection attempt on a TCP socket.
Definition: tcp.c:321
#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:50
@ 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:251
uint32_t tcpGenerateInitialSeqNum(const IpAddr *localIpAddr, uint16_t localPort, const IpAddr *remoteIpAddr, uint16_t remotePort)
Initial sequence number generation.
Definition: tcp_misc.c:683
@ 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:409
@ TCP_STATE_ESTABLISHED
Definition: tcp.h:272
@ 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:2200
#define arraysize(a)
Definition: os_port.h:71
systime_t osGetSystemTime(void)
Retrieve system time.