]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c
commit 9f316c246baafa15c542a5aea81a94f26e3d6507
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / FreeRTOS_Sockets.c
1 /*
2  * FreeRTOS+TCP V2.2.1
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * http://aws.amazon.com/freertos
23  * http://www.FreeRTOS.org
24  */
25
26 /* Standard includes. */
27 #include <stdint.h>
28 #include <stdio.h>
29
30 /* FreeRTOS includes. */
31 #include "FreeRTOS.h"
32 #include "task.h"
33 #include "queue.h"
34 #include "semphr.h"
35
36 /* FreeRTOS+TCP includes. */
37 #include "FreeRTOS_UDP_IP.h"
38 #include "FreeRTOS_IP.h"
39 #include "FreeRTOS_Sockets.h"
40 #include "FreeRTOS_IP_Private.h"
41 #include "FreeRTOS_DNS.h"
42 #include "NetworkBufferManagement.h"
43
44 /* The ItemValue of the sockets xBoundSocketListItem member holds the socket's
45 port number. */
46 #define socketSET_SOCKET_PORT( pxSocket, usPort ) listSET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ), ( usPort ) )
47 #define socketGET_SOCKET_PORT( pxSocket ) listGET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ) )
48
49 /* Test if a socket it bound which means it is either included in
50 xBoundUDPSocketsList or xBoundTCPSocketsList */
51 #define socketSOCKET_IS_BOUND( pxSocket )         ( listLIST_ITEM_CONTAINER( & ( pxSocket )->xBoundSocketListItem ) != NULL )
52
53 /* If FreeRTOS_sendto() is called on a socket that is not bound to a port
54 number then, depending on the FreeRTOSIPConfig.h settings, it might be that a
55 port number is automatically generated for the socket.  Automatically generated
56 port numbers will be between socketAUTO_PORT_ALLOCATION_START_NUMBER and
57 0xffff.
58
59 Per https://tools.ietf.org/html/rfc6056, "the dynamic ports consist of the range
60 49152-65535. However, ephemeral port selection algorithms should use the whole
61 range 1024-65535" excluding those already in use (inbound or outbound). */
62 #if !defined( socketAUTO_PORT_ALLOCATION_START_NUMBER )
63         #define socketAUTO_PORT_ALLOCATION_START_NUMBER ( ( uint16_t ) 0x0400 )
64 #endif
65
66 #define socketAUTO_PORT_ALLOCATION_MAX_NUMBER   ( ( uint16_t ) 0xffff )
67
68 /* The number of octets that make up an IP address. */
69 #define socketMAX_IP_ADDRESS_OCTETS             4u
70
71 /* A block time of 0 simply means "don't block". */
72 #define socketDONT_BLOCK                                ( ( TickType_t ) 0 )
73
74 #if( ( ipconfigUSE_TCP == 1 ) && !defined( ipTCP_TIMER_PERIOD_MS ) )
75         #define ipTCP_TIMER_PERIOD_MS   ( 1000 )
76 #endif
77
78 /* The next private port number to use when binding a client socket is stored in
79 the usNextPortToUse[] array - which has either 1 or two indexes depending on
80 whether TCP is being supported. */
81 #if( ipconfigUSE_TCP == 1 )
82         #define socketPROTOCOL_COUNT            2
83 #else
84         #define socketPROTOCOL_COUNT            1
85 #endif
86
87 /* Indexes into the usNextPortToUse[] array for UDP and TCP sockets
88 respectively. */
89 #define socketNEXT_UDP_PORT_NUMBER_INDEX        0
90 #define socketNEXT_TCP_PORT_NUMBER_INDEX        1
91
92 /* Some helper macro's for defining the 20/80 % limits of uxLittleSpace / uxEnoughSpace. */
93 #define sock20_PERCENT                                          20
94 #define sock80_PERCENT                                          80
95 #define sock100_PERCENT                                         100
96
97
98 /*-----------------------------------------------------------*/
99
100 /*
101  * Allocate the next port number from the private allocation range.
102  * TCP and UDP each have their own series of port numbers
103  * ulProtocol is either ipPROTOCOL_UDP or ipPROTOCOL_TCP
104  */
105 static uint16_t prvGetPrivatePortNumber( BaseType_t xProtocol );
106
107 /*
108  * Return the list item from within pxList that has an item value of
109  * xWantedItemValue.  If there is no such list item return NULL.
110  */
111 static const ListItem_t * pxListFindListItemWithValue( const List_t *pxList, TickType_t xWantedItemValue );
112
113 /*
114  * Return pdTRUE only if pxSocket is valid and bound, as far as can be
115  * determined.
116  */
117 static BaseType_t prvValidSocket( FreeRTOS_Socket_t *pxSocket, BaseType_t xProtocol, BaseType_t xIsBound );
118
119 /*
120  * Before creating a socket, check the validity of the parameters used
121  * and find the size of the socket space, which is different for UDP and TCP
122  */
123 static BaseType_t prvDetermineSocketSize( BaseType_t xDomain, BaseType_t xType, BaseType_t xProtocol, size_t *pxSocketSize );
124
125 #if( ipconfigUSE_TCP == 1 )
126         /*
127          * Create a txStream or a rxStream, depending on the parameter 'xIsInputStream'
128          */
129         static StreamBuffer_t *prvTCPCreateStream (FreeRTOS_Socket_t *pxSocket, BaseType_t xIsInputStream );
130 #endif /* ipconfigUSE_TCP == 1 */
131
132 #if( ipconfigUSE_TCP == 1 )
133         /*
134          * Called from FreeRTOS_send(): some checks which will be done before
135          * sending a TCP packed.
136          */
137         static int32_t prvTCPSendCheck( FreeRTOS_Socket_t *pxSocket, size_t xDataLength );
138 #endif /* ipconfigUSE_TCP */
139
140 #if( ipconfigUSE_TCP == 1 )
141         /*
142          * When a child socket gets closed, make sure to update the child-count of the parent
143          */
144         static void prvTCPSetSocketCount( FreeRTOS_Socket_t *pxSocketToDelete );
145 #endif  /* ipconfigUSE_TCP == 1 */
146
147 #if( ipconfigUSE_TCP == 1 )
148         /*
149          * Called from FreeRTOS_connect(): make some checks and if allowed, send a
150          * message to the IP-task to start connecting to a remote socket
151          */
152         static BaseType_t prvTCPConnectStart( FreeRTOS_Socket_t *pxSocket, struct freertos_sockaddr *pxAddress );
153 #endif /* ipconfigUSE_TCP */
154
155 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
156
157         /* Executed by the IP-task, it will check all sockets belonging to a set */
158         static FreeRTOS_Socket_t *prvFindSelectedSocket( SocketSelect_t *pxSocketSet );
159
160 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
161 /*-----------------------------------------------------------*/
162
163 /* The list that contains mappings between sockets and port numbers.  Accesses
164 to this list must be protected by critical sections of one kind or another. */
165 List_t xBoundUDPSocketsList;
166
167 #if ipconfigUSE_TCP == 1
168         List_t xBoundTCPSocketsList;
169 #endif /* ipconfigUSE_TCP == 1 */
170
171 /*-----------------------------------------------------------*/
172
173 static BaseType_t prvValidSocket( FreeRTOS_Socket_t *pxSocket, BaseType_t xProtocol, BaseType_t xIsBound )
174 {
175 BaseType_t xReturn = pdTRUE;
176
177         if( ( pxSocket == NULL ) || ( pxSocket == FREERTOS_INVALID_SOCKET ) )
178         {
179                 xReturn = pdFALSE;
180         }
181         else if( ( xIsBound != pdFALSE ) && ( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE ) )
182         {
183                 /* The caller expects the socket to be bound, but it isn't. */
184                 xReturn = pdFALSE;
185         }
186         else if( pxSocket->ucProtocol != ( uint8_t ) xProtocol )
187         {
188                 /* Socket has a wrong type (UDP != TCP). */
189                 xReturn = pdFALSE;
190         }
191
192         return xReturn;
193 }
194 /*-----------------------------------------------------------*/
195
196 BaseType_t vNetworkSocketsInit( void )
197 {
198         vListInitialise( &xBoundUDPSocketsList );
199
200         #if( ipconfigUSE_TCP == 1 )
201         {
202                 vListInitialise( &xBoundTCPSocketsList );
203         }
204         #endif  /* ipconfigUSE_TCP == 1 */
205
206         return pdTRUE;
207 }
208 /*-----------------------------------------------------------*/
209
210 static BaseType_t prvDetermineSocketSize( BaseType_t xDomain, BaseType_t xType, BaseType_t xProtocol, size_t *pxSocketSize )
211 {
212 BaseType_t xReturn = pdPASS;
213 FreeRTOS_Socket_t *pxSocket;
214
215         /* Asserts must not appear before it has been determined that the network
216         task is ready - otherwise the asserts will fail. */
217         if( xIPIsNetworkTaskReady() == pdFALSE )
218         {
219                 xReturn = pdFAIL;
220         }
221         else
222         {
223                 /* Only Ethernet is currently supported. */
224                 configASSERT( xDomain == FREERTOS_AF_INET );
225
226                 /* Check if the UDP socket-list has been initialised. */
227                 configASSERT( listLIST_IS_INITIALISED( &xBoundUDPSocketsList ) );
228                 #if( ipconfigUSE_TCP == 1 )
229                 {
230                         /* Check if the TCP socket-list has been initialised. */
231                         configASSERT( listLIST_IS_INITIALISED( &xBoundTCPSocketsList ) );
232                 }
233                 #endif  /* ipconfigUSE_TCP == 1 */
234
235                 if( xProtocol == FREERTOS_IPPROTO_UDP )
236                 {
237                         if( xType != FREERTOS_SOCK_DGRAM )
238                         {
239                                 xReturn = pdFAIL;
240                                 configASSERT( xReturn );
241                         }
242                         /* In case a UDP socket is created, do not allocate space for TCP data. */
243                         *pxSocketSize = ( sizeof( *pxSocket ) - sizeof( pxSocket->u ) ) + sizeof( pxSocket->u.xUDP );
244                 }
245 #if( ipconfigUSE_TCP == 1 )
246                 else if( xProtocol == FREERTOS_IPPROTO_TCP )
247                 {
248                         if( xType != FREERTOS_SOCK_STREAM )
249                         {
250                                 xReturn = pdFAIL;
251                                 configASSERT( xReturn );
252                         }
253
254                         *pxSocketSize = ( sizeof( *pxSocket ) - sizeof( pxSocket->u ) ) + sizeof( pxSocket->u.xTCP );
255                 }
256 #endif  /* ipconfigUSE_TCP == 1 */
257                 else
258                 {
259                         xReturn = pdFAIL;
260                         configASSERT( xReturn );
261                 }
262         }
263         /* In case configASSERT() is not used */
264         ( void )xDomain;
265         return xReturn;
266 }
267 /*-----------------------------------------------------------*/
268
269 /* FreeRTOS_socket() allocates and initiates a socket */
270 Socket_t FreeRTOS_socket( BaseType_t xDomain, BaseType_t xType, BaseType_t xProtocol )
271 {
272 FreeRTOS_Socket_t *pxSocket;
273 size_t uxSocketSize;
274 EventGroupHandle_t xEventGroup;
275 Socket_t xReturn;
276
277         if( prvDetermineSocketSize( xDomain, xType, xProtocol, &uxSocketSize ) == pdFAIL )
278         {
279                 xReturn = FREERTOS_INVALID_SOCKET;
280         }
281         else
282         {
283                 /* Allocate the structure that will hold the socket information.  The
284                 size depends on the type of socket: UDP sockets need less space.  A
285                 define 'pvPortMallocSocket' will used to allocate the necessary space.
286                 By default it points to the FreeRTOS function 'pvPortMalloc()'. */
287                 pxSocket = ( FreeRTOS_Socket_t * ) pvPortMallocSocket( uxSocketSize );
288
289                 if( pxSocket == NULL )
290                 {
291                         pxSocket = ( FreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET;
292                         iptraceFAILED_TO_CREATE_SOCKET();
293                 }
294                 else if( ( xEventGroup = xEventGroupCreate() ) == NULL )
295                 {
296                         vPortFreeSocket( pxSocket );
297                         pxSocket = ( FreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET;
298                         iptraceFAILED_TO_CREATE_EVENT_GROUP();
299                 }
300                 else
301                 {
302                         /* Clear the entire space to avoid nulling individual entries */
303                         memset( pxSocket, '\0', uxSocketSize );
304
305                         pxSocket->xEventGroup = xEventGroup;
306
307                         /* Initialise the socket's members.  The semaphore will be created
308                         if the socket is bound to an address, for now the pointer to the
309                         semaphore is just set to NULL to show it has not been created. */
310                         if( xProtocol == FREERTOS_IPPROTO_UDP )
311                         {
312                                 vListInitialise( &( pxSocket->u.xUDP.xWaitingPacketsList ) );
313
314                                 #if( ipconfigUDP_MAX_RX_PACKETS > 0 )
315                                 {
316                                         pxSocket->u.xUDP.uxMaxPackets = ( UBaseType_t ) ipconfigUDP_MAX_RX_PACKETS;
317                                 }
318                                 #endif /* ipconfigUDP_MAX_RX_PACKETS > 0 */
319                         }
320
321                         vListInitialiseItem( &( pxSocket->xBoundSocketListItem ) );
322                         listSET_LIST_ITEM_OWNER( &( pxSocket->xBoundSocketListItem ), ( void * ) pxSocket );
323
324                         pxSocket->xReceiveBlockTime = ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME;
325                         pxSocket->xSendBlockTime        = ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME;
326                         pxSocket->ucSocketOptions   = ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT;
327                         pxSocket->ucProtocol            = ( uint8_t ) xProtocol; /* protocol: UDP or TCP */
328
329                         #if( ipconfigUSE_TCP == 1 )
330                         {
331                                 if( xProtocol == FREERTOS_IPPROTO_TCP )
332                                 {
333                                         /* StreamSize is expressed in number of bytes */
334                                         /* Round up buffer sizes to nearest multiple of MSS */
335                                         pxSocket->u.xTCP.usInitMSS      = pxSocket->u.xTCP.usCurMSS = ipconfigTCP_MSS;
336                                         pxSocket->u.xTCP.uxRxStreamSize = ( size_t ) ipconfigTCP_RX_BUFFER_LENGTH;
337                                         pxSocket->u.xTCP.uxTxStreamSize = ( size_t ) FreeRTOS_round_up( ipconfigTCP_TX_BUFFER_LENGTH, ipconfigTCP_MSS );
338                                         /* Use half of the buffer size of the TCP windows */
339                                         #if ( ipconfigUSE_TCP_WIN == 1 )
340                                         {
341                                                 pxSocket->u.xTCP.uxRxWinSize  = FreeRTOS_max_uint32( 1UL, ( uint32_t ) ( pxSocket->u.xTCP.uxRxStreamSize / 2 ) / ipconfigTCP_MSS );
342                                                 pxSocket->u.xTCP.uxTxWinSize  = FreeRTOS_max_uint32( 1UL, ( uint32_t ) ( pxSocket->u.xTCP.uxTxStreamSize / 2 ) / ipconfigTCP_MSS );
343                                         }
344                                         #else
345                                         {
346                                                 pxSocket->u.xTCP.uxRxWinSize  = 1u;
347                                                 pxSocket->u.xTCP.uxTxWinSize  = 1u;
348                                         }
349                                         #endif
350                                         /* The above values are just defaults, and can be overridden by
351                                         calling FreeRTOS_setsockopt().  No buffers will be allocated until a
352                                         socket is connected and data is exchanged. */
353                                 }
354                         }
355                         #endif  /* ipconfigUSE_TCP == 1 */
356                 }
357
358                 xReturn = ( Socket_t ) pxSocket;
359         }
360
361         /* Remove compiler warnings in the case the configASSERT() is not defined. */
362         ( void ) xDomain;
363
364         return xReturn;
365 }
366 /*-----------------------------------------------------------*/
367
368 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
369
370         SocketSet_t FreeRTOS_CreateSocketSet( void )
371         {
372         SocketSelect_t *pxSocketSet;
373
374                 pxSocketSet = ( SocketSelect_t * ) pvPortMalloc( sizeof( *pxSocketSet ) );
375
376                 if( pxSocketSet != NULL )
377                 {
378                         memset( pxSocketSet, '\0', sizeof( *pxSocketSet ) );
379                         pxSocketSet->xSelectGroup = xEventGroupCreate();
380
381                         if( pxSocketSet->xSelectGroup == NULL )
382                         {
383                                 vPortFree( ( void* ) pxSocketSet );
384                                 pxSocketSet = NULL;
385                         }
386                 }
387
388                 return ( SocketSet_t ) pxSocketSet;
389         }
390
391 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
392 /*-----------------------------------------------------------*/
393
394 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
395
396         void FreeRTOS_DeleteSocketSet( SocketSet_t xSocketSet )
397         {
398                 SocketSelect_t *pxSocketSet = ( SocketSelect_t*) xSocketSet;
399
400                 vEventGroupDelete( pxSocketSet->xSelectGroup );
401                 vPortFree( ( void* ) pxSocketSet );
402         }
403
404 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
405 /*-----------------------------------------------------------*/
406
407 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
408
409         /* Add a socket to a set */
410         void FreeRTOS_FD_SET( Socket_t xSocket, SocketSet_t xSocketSet, EventBits_t xSelectBits )
411         {
412         FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
413         SocketSelect_t *pxSocketSet = ( SocketSelect_t * ) xSocketSet;
414
415                 configASSERT( pxSocket != NULL );
416                 configASSERT( xSocketSet != NULL );
417
418                 /* Make sure we're not adding bits which are reserved for internal use,
419                 such as eSELECT_CALL_IP */
420                 pxSocket->xSelectBits |= ( xSelectBits & eSELECT_ALL );
421
422                 if( ( pxSocket->xSelectBits & eSELECT_ALL ) != 0 )
423                 {
424                         /* Adding a socket to a socket set. */
425                         pxSocket->pxSocketSet = ( SocketSelect_t * ) xSocketSet;
426
427                         /* Now have the IP-task call vSocketSelect() to see if the set contains
428                         any sockets which are 'ready' and set the proper bits.
429                         By setting 'bApiCalled = false', vSocketSelect() knows that it was
430                         not called from a user API */
431                         pxSocketSet->bApiCalled = pdFALSE;
432                         prvFindSelectedSocket( pxSocketSet );
433                 }
434         }
435
436 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
437 /*-----------------------------------------------------------*/
438
439 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
440         /* Clear select bits for a socket
441         If the mask becomes 0, remove the socket from the set */
442         void FreeRTOS_FD_CLR( Socket_t xSocket, SocketSet_t xSocketSet, EventBits_t xSelectBits )
443         {
444         FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
445
446                 configASSERT( pxSocket != NULL );
447                 configASSERT( xSocketSet != NULL );
448
449                 pxSocket->xSelectBits &= ~( xSelectBits & eSELECT_ALL );
450                 if( ( pxSocket->xSelectBits & eSELECT_ALL ) != 0 )
451                 {
452                         pxSocket->pxSocketSet = ( SocketSelect_t *)xSocketSet;
453                 }
454                 else
455                 {
456                         /* disconnect it from the socket set */
457                         pxSocket->pxSocketSet = ( SocketSelect_t *)NULL;
458                 }
459         }
460
461 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
462 /*-----------------------------------------------------------*/
463
464
465 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
466
467         /* Test if a socket belongs to a socket-set */
468         EventBits_t FreeRTOS_FD_ISSET( Socket_t xSocket, SocketSet_t xSocketSet )
469         {
470         EventBits_t xReturn;
471         FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
472
473                 configASSERT( pxSocket != NULL );
474                 configASSERT( xSocketSet != NULL );
475
476                 if( xSocketSet == ( SocketSet_t ) pxSocket->pxSocketSet )
477                 {
478                         /* Make sure we're not adding bits which are reserved for internal
479                         use. */
480                         xReturn = pxSocket->xSocketBits & eSELECT_ALL;
481                 }
482                 else
483                 {
484                         xReturn = 0;
485                 }
486
487                 return xReturn;
488         }
489
490 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
491 /*-----------------------------------------------------------*/
492
493 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
494
495         /* The select() statement: wait for an event to occur on any of the sockets
496         included in a socket set */
497         BaseType_t FreeRTOS_select( SocketSet_t xSocketSet, TickType_t xBlockTimeTicks )
498         {
499         TimeOut_t xTimeOut;
500         TickType_t xRemainingTime;
501         SocketSelect_t *pxSocketSet = ( SocketSelect_t*) xSocketSet;
502         BaseType_t xResult;
503
504                 configASSERT( xSocketSet != NULL );
505
506                 /* Only in the first round, check for non-blocking */
507                 xRemainingTime = xBlockTimeTicks;
508
509                 /* Fetch the current time */
510                 vTaskSetTimeOutState( &xTimeOut );
511
512                 for( ;; )
513                 {
514                         /* Find a socket which might have triggered the bit
515                         This function might return immediately or block for a limited time */
516                         xResult = ( BaseType_t ) xEventGroupWaitBits( pxSocketSet->xSelectGroup, eSELECT_ALL, pdFALSE, pdFALSE, xRemainingTime );
517
518                         #if( ipconfigSUPPORT_SIGNALS != 0 )
519                         {
520                                 if( ( xResult & eSELECT_INTR ) != 0u )
521                                 {
522                                         xEventGroupClearBits( pxSocketSet->xSelectGroup, eSELECT_INTR );
523                                         FreeRTOS_debug_printf( ( "FreeRTOS_select: interrupted\n" ) );
524                                         break;
525                                 }
526                         }
527                         #endif /* ipconfigSUPPORT_SIGNALS */
528
529                         /* Have the IP-task find the socket which had an event */
530                         pxSocketSet->bApiCalled = pdTRUE;
531                         prvFindSelectedSocket( pxSocketSet );
532
533                         xResult = ( BaseType_t ) xEventGroupGetBits( pxSocketSet->xSelectGroup );
534
535                         if( xResult != 0 )
536                         {
537                                 break;
538                         }
539
540                         /* Has the timeout been reached? */
541                         if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
542                         {
543                                 break;
544                         }
545                 }
546
547                 return xResult;
548         }
549
550 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
551 /*-----------------------------------------------------------*/
552
553 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
554
555         /* Send a message to the IP-task to have it check all sockets belonging to
556         'pxSocketSet' */
557         static FreeRTOS_Socket_t *prvFindSelectedSocket( SocketSelect_t *pxSocketSet )
558         {
559         IPStackEvent_t xSelectEvent;
560         FreeRTOS_Socket_t *xReturn;
561
562                 xSelectEvent.eEventType = eSocketSelectEvent;
563                 xSelectEvent.pvData = ( void * ) pxSocketSet;
564
565                 /* while the IP-task works on the request, the API will block on
566                 'eSELECT_CALL_IP'.  So clear it first. */
567                 xEventGroupClearBits( pxSocketSet->xSelectGroup, eSELECT_CALL_IP );
568
569                 /* Now send the socket select event */
570                 if( xSendEventStructToIPTask( &xSelectEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL )
571                 {
572                         /* Oops, we failed to wake-up the IP task. No use to wait for it. */
573                         FreeRTOS_debug_printf( ( "prvFindSelectedSocket: failed\n" ) );
574                         xReturn = NULL;
575                 }
576                 else
577                 {
578                         /* As soon as the IP-task is ready, it will set 'eSELECT_CALL_IP' to
579                         wakeup the calling API */
580                         xEventGroupWaitBits( pxSocketSet->xSelectGroup, eSELECT_CALL_IP, pdTRUE, pdFALSE, portMAX_DELAY );
581
582                         /* Return 'pxSocket' which is set by the IP-task */
583                         xReturn = pxSocketSet->pxSocket;
584                 }
585
586                 return xReturn;
587         }
588
589 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
590 /*-----------------------------------------------------------*/
591
592 /*
593  * FreeRTOS_recvfrom: receive data from a bound socket
594  * In this library, the function can only be used with connectionsless sockets
595  * (UDP)
596  */
597 int32_t FreeRTOS_recvfrom( Socket_t xSocket, void *pvBuffer, size_t xBufferLength, BaseType_t xFlags, struct freertos_sockaddr *pxSourceAddress, socklen_t *pxSourceAddressLength )
598 {
599 BaseType_t lPacketCount = 0;
600 NetworkBufferDescriptor_t *pxNetworkBuffer;
601 FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
602 TickType_t xRemainingTime = ( TickType_t ) 0; /* Obsolete assignment, but some compilers output a warning if its not done. */
603 BaseType_t xTimed = pdFALSE;
604 TimeOut_t xTimeOut;
605 int32_t lReturn;
606 EventBits_t xEventBits = ( EventBits_t ) 0;
607
608         if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_UDP, pdTRUE ) == pdFALSE )
609         {
610                 return -pdFREERTOS_ERRNO_EINVAL;
611         }
612
613         lPacketCount = ( BaseType_t ) listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) );
614
615         /* The function prototype is designed to maintain the expected Berkeley
616         sockets standard, but this implementation does not use all the parameters. */
617         ( void ) pxSourceAddressLength;
618
619         while( lPacketCount == 0 )
620         {
621                 if( xTimed == pdFALSE )
622                 {
623                         /* Check to see if the socket is non blocking on the first
624                         iteration.  */
625                         xRemainingTime = pxSocket->xReceiveBlockTime;
626
627                         if( xRemainingTime == ( TickType_t ) 0 )
628                         {
629                                 #if( ipconfigSUPPORT_SIGNALS != 0 )
630                                 {
631                                         /* Just check for the interrupt flag. */
632                                         xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_INTR,
633                                                 pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, socketDONT_BLOCK );
634                                 }
635                                 #endif /* ipconfigSUPPORT_SIGNALS */
636                                 break;
637                         }
638
639                         if( ( xFlags & FREERTOS_MSG_DONTWAIT ) != 0 )
640                         {
641                                 break;
642                         }
643
644                         /* To ensure this part only executes once. */
645                         xTimed = pdTRUE;
646
647                         /* Fetch the current time. */
648                         vTaskSetTimeOutState( &xTimeOut );
649                 }
650
651                 /* Wait for arrival of data.  While waiting, the IP-task may set the
652                 'eSOCKET_RECEIVE' bit in 'xEventGroup', if it receives data for this
653                 socket, thus unblocking this API call. */
654                 xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_RECEIVE | eSOCKET_INTR,
655                         pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );
656
657                 #if( ipconfigSUPPORT_SIGNALS != 0 )
658                 {
659                         if( ( xEventBits & eSOCKET_INTR ) != 0 )
660                         {
661                                 if( ( xEventBits & eSOCKET_RECEIVE ) != 0 )
662                                 {
663                                         /* Shouldn't have cleared the eSOCKET_RECEIVE flag. */
664                                         xEventGroupSetBits( pxSocket->xEventGroup, eSOCKET_RECEIVE );
665                                 }
666                                 break;
667                         }
668                 }
669                 #else
670                 {
671                         ( void ) xEventBits;
672                 }
673                 #endif /* ipconfigSUPPORT_SIGNALS */
674
675                 lPacketCount = ( BaseType_t ) listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) );
676
677                 if( lPacketCount != 0 )
678                 {
679                         break;
680                 }
681
682                 /* Has the timeout been reached ? */
683                 if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) )
684                 {
685                         break;
686                 }
687         } /* while( lPacketCount == 0 ) */
688
689         if( lPacketCount != 0 )
690         {
691                 taskENTER_CRITICAL();
692                 {
693                         /* The owner of the list item is the network buffer. */
694                         pxNetworkBuffer = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->u.xUDP.xWaitingPacketsList ) );
695
696                         if( ( xFlags & FREERTOS_MSG_PEEK ) == 0 )
697                         {
698                                 /* Remove the network buffer from the list of buffers waiting to
699                                 be processed by the socket. */
700                                 uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
701                         }
702                 }
703                 taskEXIT_CRITICAL();
704
705                 /* The returned value is the length of the payload data, which is
706                 calculated at the total packet size minus the headers.
707                 The validity of `xDataLength` prvProcessIPPacket has been confirmed
708                 in 'prvProcessIPPacket()'. */
709                 lReturn = ( int32_t ) ( pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t ) );
710
711                 if( pxSourceAddress != NULL )
712                 {
713                         pxSourceAddress->sin_port = pxNetworkBuffer->usPort;
714                         pxSourceAddress->sin_addr = pxNetworkBuffer->ulIPAddress;
715                 }
716
717                 if( ( xFlags & FREERTOS_ZERO_COPY ) == 0 )
718                 {
719                         /* The zero copy flag is not set.  Truncate the length if it won't
720                         fit in the provided buffer. */
721                         if( lReturn > ( int32_t ) xBufferLength )
722                         {
723                                 iptraceRECVFROM_DISCARDING_BYTES( ( xBufferLength - lReturn ) );
724                                 lReturn = ( int32_t )xBufferLength;
725                         }
726
727                         /* Copy the received data into the provided buffer, then release the
728                         network buffer. */
729                         memcpy( pvBuffer, ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] ), ( size_t )lReturn );
730
731                         if( ( xFlags & FREERTOS_MSG_PEEK ) == 0 )
732                         {
733                                 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
734                         }
735                 }
736                 else
737                 {
738                         /* The zero copy flag was set.  pvBuffer is not a buffer into which
739                         the received data can be copied, but a pointer that must be set to
740                         point to the buffer in which the received data has already been
741                         placed. */
742                         *( ( void** ) pvBuffer ) = ( void * ) ( &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] ) );
743                 }
744
745         }
746 #if( ipconfigSUPPORT_SIGNALS != 0 )
747         else if( ( xEventBits & eSOCKET_INTR ) != 0 )
748         {
749                 lReturn = -pdFREERTOS_ERRNO_EINTR;
750                 iptraceRECVFROM_INTERRUPTED();
751         }
752 #endif /* ipconfigSUPPORT_SIGNALS */
753         else
754         {
755                 lReturn = -pdFREERTOS_ERRNO_EWOULDBLOCK;
756                 iptraceRECVFROM_TIMEOUT();
757         }
758
759         return lReturn;
760 }
761 /*-----------------------------------------------------------*/
762
763 int32_t FreeRTOS_sendto( Socket_t xSocket, const void *pvBuffer, size_t xTotalDataLength, BaseType_t xFlags, const struct freertos_sockaddr *pxDestinationAddress, socklen_t xDestinationAddressLength )
764 {
765 NetworkBufferDescriptor_t *pxNetworkBuffer;
766 IPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
767 TimeOut_t xTimeOut;
768 TickType_t xTicksToWait;
769 int32_t lReturn = 0;
770 FreeRTOS_Socket_t *pxSocket;
771
772         pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
773
774         /* The function prototype is designed to maintain the expected Berkeley
775         sockets standard, but this implementation does not use all the
776         parameters. */
777         ( void ) xDestinationAddressLength;
778         configASSERT( pvBuffer );
779
780         if( xTotalDataLength <= ( size_t ) ipMAX_UDP_PAYLOAD_LENGTH )
781         {
782                 /* If the socket is not already bound to an address, bind it now.
783                 Passing NULL as the address parameter tells FreeRTOS_bind() to select
784                 the address to bind to. */
785                 if( ( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE ) ||
786                         ( FreeRTOS_bind( xSocket, NULL, 0u ) == 0 ) )
787                 {
788                         xTicksToWait = pxSocket->xSendBlockTime;
789
790                         #if( ipconfigUSE_CALLBACKS != 0 )
791                         {
792                                 if( xIsCallingFromIPTask() != pdFALSE )
793                                 {
794                                         /* If this send function is called from within a call-back
795                                         handler it may not block, otherwise chances would be big to
796                                         get a deadlock: the IP-task waiting for itself. */
797                                         xTicksToWait = ( TickType_t )0;
798                                 }
799                         }
800                         #endif /* ipconfigUSE_CALLBACKS */
801
802                         if( ( xFlags & FREERTOS_MSG_DONTWAIT ) != 0 )
803                         {
804                                 xTicksToWait = ( TickType_t ) 0;
805                         }
806
807                         if( ( xFlags & FREERTOS_ZERO_COPY ) == 0 )
808                         {
809                                 /* Zero copy is not set, so obtain a network buffer into
810                                 which the payload will be copied. */
811                                 vTaskSetTimeOutState( &xTimeOut );
812
813                                 /* Block until a buffer becomes available, or until a
814                                 timeout has been reached */
815                                 pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( xTotalDataLength + sizeof( UDPPacket_t ), xTicksToWait );
816
817                                 if( pxNetworkBuffer != NULL )
818                                 {
819                                         memcpy( ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] ), ( void * ) pvBuffer, xTotalDataLength );
820
821                                         if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
822                                         {
823                                                 /* The entire block time has been used up. */
824                                                 xTicksToWait = ( TickType_t ) 0;
825                                         }
826                                 }
827                         }
828                         else
829                         {
830                                 /* When zero copy is used, pvBuffer is a pointer to the
831                                 payload of a buffer that has already been obtained from the
832                                 stack.  Obtain the network buffer pointer from the buffer. */
833                                 pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( (void*)pvBuffer );
834                         }
835
836                         if( pxNetworkBuffer != NULL )
837                         {
838                                 /* xDataLength is the size of the total packet, including the Ethernet header. */
839                                 pxNetworkBuffer->xDataLength = xTotalDataLength + sizeof( UDPPacket_t );
840                                 pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;
841                                 pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_PORT( pxSocket );
842                                 pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr;
843
844                                 /* The socket options are passed to the IP layer in the
845                                 space that will eventually get used by the Ethernet header. */
846                                 pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = pxSocket->ucSocketOptions;
847
848                                 /* Tell the networking task that the packet needs sending. */
849                                 xStackTxEvent.pvData = pxNetworkBuffer;
850
851                                 /* Ask the IP-task to send this packet */
852                                 if( xSendEventStructToIPTask( &xStackTxEvent, xTicksToWait ) == pdPASS )
853                                 {
854                                         /* The packet was successfully sent to the IP task. */
855                                         lReturn = ( int32_t ) xTotalDataLength;
856                                         #if( ipconfigUSE_CALLBACKS == 1 )
857                                         {
858                                                 if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xUDP.pxHandleSent ) )
859                                                 {
860                                                         pxSocket->u.xUDP.pxHandleSent( ( Socket_t )pxSocket, xTotalDataLength );
861                                                 }
862                                         }
863                                         #endif /* ipconfigUSE_CALLBACKS */
864                                 }
865                                 else
866                                 {
867                                         /* If the buffer was allocated in this function, release
868                                         it. */
869                                         if( ( xFlags & FREERTOS_ZERO_COPY ) == 0 )
870                                         {
871                                                 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
872                                         }
873                                         iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
874                                 }
875                         }
876                         else
877                         {
878                                 /* If errno was available, errno would be set to
879                                 FREERTOS_ENOPKTS.  As it is, the function must return the
880                                 number of transmitted bytes, so the calling function knows
881                                 how     much data was actually sent. */
882                                 iptraceNO_BUFFER_FOR_SENDTO();
883                         }
884                 }
885                 else
886                 {
887                         iptraceSENDTO_SOCKET_NOT_BOUND();
888                 }
889         }
890         else
891         {
892                 /* The data is longer than the available buffer space. */
893                 iptraceSENDTO_DATA_TOO_LONG();
894         }
895
896         return lReturn;
897 } /* Tested */
898 /*-----------------------------------------------------------*/
899
900 /*
901  * FreeRTOS_bind() : binds a sockt to a local port number.  If port 0 is
902  * provided, a system provided port number will be assigned.  This function can
903  * be used for both UDP and TCP sockets.  The actual binding will be performed
904  * by the IP-task to avoid mutual access to the bound-socket-lists
905  * (xBoundUDPSocketsList or xBoundTCPSocketsList).
906  */
907 BaseType_t FreeRTOS_bind( Socket_t xSocket, struct freertos_sockaddr * pxAddress, socklen_t xAddressLength )
908 {
909 IPStackEvent_t xBindEvent;
910 FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
911 BaseType_t xReturn = 0;
912
913         ( void ) xAddressLength;
914
915         if( ( pxSocket == NULL ) || ( pxSocket == FREERTOS_INVALID_SOCKET ) )
916         {
917                 xReturn = -pdFREERTOS_ERRNO_EINVAL;
918         }
919         /* Once a socket is bound to a port, it can not be bound to a different
920         port number */
921         else if( socketSOCKET_IS_BOUND( pxSocket) != pdFALSE )
922         {
923                 /* The socket is already bound. */
924                 FreeRTOS_debug_printf( ( "vSocketBind: Socket already bound to %d\n", pxSocket->usLocalPort ) );
925                 xReturn = -pdFREERTOS_ERRNO_EINVAL;
926         }
927         else
928         {
929                 /* Prepare a messages to the IP-task in order to perform the binding.
930                 The desired port number will be passed in usLocalPort. */
931                 xBindEvent.eEventType = eSocketBindEvent;
932                 xBindEvent.pvData = ( void * ) xSocket;
933                 if( pxAddress != NULL )
934                 {
935                         pxSocket->usLocalPort = FreeRTOS_ntohs( pxAddress->sin_port );
936                 }
937                 else
938                 {
939                         /* Caller wants to bind to a random port number. */
940                         pxSocket->usLocalPort = 0u;
941                 }
942
943                 /* portMAX_DELAY is used as a the time-out parameter, as binding *must*
944                 succeed before the socket can be used.  _RB_ The use of an infinite
945                 block time needs be changed as it could result in the task hanging. */
946                 if( xSendEventStructToIPTask( &xBindEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL )
947                 {
948                         /* Failed to wake-up the IP-task, no use to wait for it */
949                         FreeRTOS_debug_printf( ( "FreeRTOS_bind: send event failed\n" ) );
950                         xReturn = -pdFREERTOS_ERRNO_ECANCELED;
951                 }
952                 else
953                 {
954                         /* The IP-task will set the 'eSOCKET_BOUND' bit when it has done its
955                         job. */
956                         xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_BOUND, pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, portMAX_DELAY );
957                         if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE )
958                         {
959                                 xReturn = -pdFREERTOS_ERRNO_EINVAL;
960                         }
961                 }
962         }
963
964         return xReturn;
965 }
966
967 /*
968  * vSocketBind(): internal version of bind() that should not be called directly.
969  * 'xInternal' is used for TCP sockets only: it allows to have several
970  * (connected) child sockets bound to the same server port.
971  */
972 BaseType_t vSocketBind( FreeRTOS_Socket_t *pxSocket, struct freertos_sockaddr * pxAddress, size_t uxAddressLength, BaseType_t xInternal )
973 {
974 BaseType_t xReturn = 0; /* In Berkeley sockets, 0 means pass for bind(). */
975 List_t *pxSocketList;
976 #if( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 )
977         struct freertos_sockaddr xAddress;
978 #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND */
979
980 #if( ipconfigUSE_TCP == 1 )
981         if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
982         {
983                 pxSocketList = &xBoundTCPSocketsList;
984         }
985         else
986 #endif  /* ipconfigUSE_TCP == 1 */
987         {
988                 pxSocketList = &xBoundUDPSocketsList;
989         }
990
991         /* The function prototype is designed to maintain the expected Berkeley
992         sockets standard, but this implementation does not use all the parameters. */
993         ( void ) uxAddressLength;
994
995         configASSERT( pxSocket );
996         configASSERT( pxSocket != FREERTOS_INVALID_SOCKET );
997
998         #if( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 )
999         {
1000                 /* pxAddress will be NULL if sendto() was called on a socket without the
1001                 socket being bound to an address. In this case, automatically allocate
1002                 an address and port to the socket. */
1003                 if( pxAddress == NULL )
1004                 {
1005                         pxAddress = &xAddress;
1006                         /* Put the port to zero to be assigned later. */
1007                         pxAddress->sin_port = 0u;
1008                 }
1009         }
1010         #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 */
1011
1012         /* Sockets must be bound before calling FreeRTOS_sendto() if
1013         ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is not set to 1. */
1014         configASSERT( pxAddress );
1015
1016         if( pxAddress != NULL )
1017         {
1018                 if( pxAddress->sin_port == 0u )
1019                 {
1020                         pxAddress->sin_port = prvGetPrivatePortNumber( ( BaseType_t )pxSocket->ucProtocol );
1021                         if( 0 == pxAddress->sin_port )
1022                         {
1023                                 return -pdFREERTOS_ERRNO_EADDRNOTAVAIL;
1024                         }
1025                 }
1026
1027                 /* If vSocketBind() is called from the API FreeRTOS_bind() it has been
1028                 confirmed that the socket was not yet bound to a port.  If it is called
1029                 from the IP-task, no such check is necessary. */
1030
1031                 /* Check to ensure the port is not already in use.  If the bind is
1032                 called internally, a port MAY be used by more than one socket. */
1033                 if( ( ( xInternal == pdFALSE ) || ( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) ) &&
1034                         ( pxListFindListItemWithValue( pxSocketList, ( TickType_t ) pxAddress->sin_port ) != NULL ) )
1035                 {
1036                         FreeRTOS_debug_printf( ( "vSocketBind: %sP port %d in use\n",
1037                                 pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP ? "TC" : "UD",
1038                                 FreeRTOS_ntohs( pxAddress->sin_port ) ) );
1039                         xReturn = -pdFREERTOS_ERRNO_EADDRINUSE;
1040                 }
1041                 else
1042                 {
1043                         /* Allocate the port number to the socket.
1044                         This macro will set 'xBoundSocketListItem->xItemValue' */
1045                         socketSET_SOCKET_PORT( pxSocket, pxAddress->sin_port );
1046
1047                         /* And also store it in a socket field 'usLocalPort' in host-byte-order,
1048                         mostly used for logging and debugging purposes */
1049                         pxSocket->usLocalPort = FreeRTOS_ntohs( pxAddress->sin_port );
1050
1051                         /* Add the socket to the list of bound ports. */
1052                         {
1053                                 /* If the network driver can iterate through 'xBoundUDPSocketsList',
1054                                 by calling xPortHasUDPSocket() then the IP-task must temporarily
1055                                 suspend the scheduler to keep the list in a consistent state. */
1056                                 #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
1057                                 {
1058                                         vTaskSuspendAll();
1059                                 }
1060                                 #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
1061
1062                                 /* Add the socket to 'xBoundUDPSocketsList' or 'xBoundTCPSocketsList' */
1063                                 vListInsertEnd( pxSocketList, &( pxSocket->xBoundSocketListItem ) );
1064
1065                                 #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
1066                                 {
1067                                         xTaskResumeAll();
1068                                 }
1069                                 #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
1070                         }
1071                 }
1072         }
1073         else
1074         {
1075                 xReturn = -pdFREERTOS_ERRNO_EADDRNOTAVAIL;
1076                 FreeRTOS_debug_printf( ( "vSocketBind: Socket no addr\n" ) );
1077         }
1078
1079         if( xReturn != 0 )
1080         {
1081                 iptraceBIND_FAILED( xSocket, ( FreeRTOS_ntohs( pxAddress->sin_port ) ) );
1082         }
1083
1084         return xReturn;
1085 } /* Tested */
1086 /*-----------------------------------------------------------*/
1087
1088 /*
1089  * Close a socket and free the allocated space
1090  * In case of a TCP socket: the connection will not be closed automatically
1091  * Subsequent messages for the closed socket will be responded to with a RST
1092  * The IP-task will actually close the socket, after receiving a 'eSocketCloseEvent' message
1093  */
1094 BaseType_t FreeRTOS_closesocket( Socket_t xSocket )
1095 {
1096 BaseType_t xResult;
1097 #if( ipconfigUSE_TCP == 1 ) && ( ipconfigUSE_CALLBACKS == 1 )
1098         FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * )xSocket;
1099 #endif
1100 IPStackEvent_t xCloseEvent;
1101 xCloseEvent.eEventType = eSocketCloseEvent;
1102 xCloseEvent.pvData = ( void * ) xSocket;
1103
1104         if( ( xSocket == NULL ) || ( xSocket == FREERTOS_INVALID_SOCKET ) )
1105         {
1106                 xResult = 0;
1107         }
1108         else
1109         {
1110                 #if( ( ipconfigUSE_TCP == 1 ) && ( ipconfigUSE_CALLBACKS == 1 ) )
1111                 {
1112                         if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
1113                         {
1114                                 /* Make sure that IP-task won't call the user callback's anymore */
1115                                 pxSocket->u.xTCP.pxHandleConnected = NULL;
1116                                 pxSocket->u.xTCP.pxHandleReceive = NULL;
1117                                 pxSocket->u.xTCP.pxHandleSent = NULL;
1118                         }
1119                 }
1120                 #endif  /* ( ( ipconfigUSE_TCP == 1 ) && ( ipconfigUSE_CALLBACKS == 1 ) ) */
1121
1122                 /* Let the IP task close the socket to keep it synchronised     with the
1123                 packet handling. */
1124
1125                 /* Note when changing the time-out value below, it must be checked who is calling
1126                 this function. If it is called by the IP-task, a deadlock could occur.
1127                 The IP-task would only call it in case of a user call-back */
1128                 if( xSendEventStructToIPTask( &xCloseEvent, ( TickType_t ) 0 ) == pdFAIL )
1129                 {
1130                         FreeRTOS_debug_printf( ( "FreeRTOS_closesocket: failed\n" ) );
1131                         xResult = -1;
1132                 }
1133                 else
1134                 {
1135                         xResult = 1;
1136                 }
1137         }
1138
1139         return xResult;
1140 }
1141
1142 /* This is the internal version of FreeRTOS_closesocket()
1143  * It will be called by the IPtask only to avoid problems with synchronicity
1144  */
1145 void *vSocketClose( FreeRTOS_Socket_t *pxSocket )
1146 {
1147 NetworkBufferDescriptor_t *pxNetworkBuffer;
1148
1149         #if( ipconfigUSE_TCP == 1 )
1150         {
1151                 /* For TCP: clean up a little more. */
1152                 if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
1153                 {
1154                         #if( ipconfigUSE_TCP_WIN == 1 )
1155                         {
1156                                 if( pxSocket->u.xTCP.pxAckMessage != NULL )
1157                                 {
1158                                         vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
1159                                 }
1160                                 /* Free the resources which were claimed by the tcpWin member */
1161                                 vTCPWindowDestroy( &pxSocket->u.xTCP.xTCPWindow );
1162                         }
1163                         #endif /* ipconfigUSE_TCP_WIN */
1164
1165                         /* Free the input and output streams */
1166                         if( pxSocket->u.xTCP.rxStream != NULL )
1167                         {
1168                                 vPortFreeLarge( pxSocket->u.xTCP.rxStream );
1169                         }
1170
1171                         if( pxSocket->u.xTCP.txStream != NULL )
1172                         {
1173                                 vPortFreeLarge( pxSocket->u.xTCP.txStream );
1174                         }
1175
1176                         /* In case this is a child socket, make sure the child-count of the
1177                         parent socket is decreased. */
1178                         prvTCPSetSocketCount( pxSocket );
1179                 }
1180         }
1181         #endif  /* ipconfigUSE_TCP == 1 */
1182
1183         /* Socket must be unbound first, to ensure no more packets are queued on
1184         it. */
1185         if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE )
1186         {
1187                 /* If the network driver can iterate through 'xBoundUDPSocketsList',
1188                 by calling xPortHasUDPSocket(), then the IP-task must temporarily
1189                 suspend the scheduler to keep the list in a consistent state. */
1190                 #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
1191                 {
1192                         vTaskSuspendAll();
1193                 }
1194                 #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
1195
1196                 uxListRemove( &( pxSocket->xBoundSocketListItem ) );
1197
1198                 #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
1199                 {
1200                         xTaskResumeAll();
1201                 }
1202                 #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
1203         }
1204
1205         /* Now the socket is not bound the list of waiting packets can be
1206         drained. */
1207         if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP )
1208         {
1209                 while( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) > 0U )
1210                 {
1211                         pxNetworkBuffer = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->u.xUDP.xWaitingPacketsList ) );
1212                         uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
1213                         vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
1214                 }
1215         }
1216
1217         if( pxSocket->xEventGroup )
1218         {
1219                 vEventGroupDelete( pxSocket->xEventGroup );
1220         }
1221
1222         #if( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_DEBUG_PRINTF != 0 )
1223         {
1224                 if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
1225                 {
1226                         FreeRTOS_debug_printf( ( "FreeRTOS_closesocket[%u to %lxip:%u]: buffers %lu socks %lu\n",
1227                                 pxSocket->usLocalPort,
1228                                 pxSocket->u.xTCP.ulRemoteIP,
1229                                 pxSocket->u.xTCP.usRemotePort,
1230                                 uxGetNumberOfFreeNetworkBuffers(),
1231                                 listCURRENT_LIST_LENGTH( &xBoundTCPSocketsList ) ) );
1232                 }
1233         }
1234         #endif /* ( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_DEBUG_PRINTF != 0 ) */
1235
1236         /* Anf finally, after all resources have been freed, free the socket space */
1237         vPortFreeSocket( pxSocket );
1238
1239         return 0;
1240 } /* Tested */
1241
1242 /*-----------------------------------------------------------*/
1243
1244 #if ipconfigUSE_TCP == 1
1245
1246         /*
1247          * When a child socket gets closed, make sure to update the child-count of the
1248          * parent.  When a listening parent socket is closed, make sure no child-sockets
1249          * keep a pointer to it.
1250          */
1251         static void prvTCPSetSocketCount( FreeRTOS_Socket_t *pxSocketToDelete )
1252         {
1253         const ListItem_t *pxIterator;
1254         const MiniListItem_t *pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xBoundTCPSocketsList );
1255         FreeRTOS_Socket_t *pxOtherSocket;
1256         uint16_t usLocalPort = pxSocketToDelete->usLocalPort;
1257
1258                 for( pxIterator  = ( const ListItem_t * ) listGET_NEXT( pxEnd );
1259                          pxIterator != ( const ListItem_t * ) pxEnd;
1260                          pxIterator  = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
1261                 {
1262                         pxOtherSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
1263                         if( ( pxOtherSocket->u.xTCP.ucTCPState == eTCP_LISTEN ) &&
1264                                 ( pxOtherSocket->usLocalPort == usLocalPort ) &&
1265                                 ( pxOtherSocket->u.xTCP.usChildCount ) )
1266                         {
1267                                 pxOtherSocket->u.xTCP.usChildCount--;
1268                                 FreeRTOS_debug_printf( ( "Lost: Socket %u now has %u / %u child%s\n",
1269                                         pxOtherSocket->usLocalPort,
1270                                         pxOtherSocket->u.xTCP.usChildCount,
1271                                         pxOtherSocket->u.xTCP.usBacklog,
1272                                         pxOtherSocket->u.xTCP.usChildCount == 1u ? "" : "ren" ) );
1273                                 break;
1274                         }
1275                 }
1276         }
1277
1278 #endif /* ipconfigUSE_TCP == 1 */
1279
1280 /*-----------------------------------------------------------*/
1281
1282 BaseType_t FreeRTOS_setsockopt( Socket_t xSocket, int32_t lLevel, int32_t lOptionName, const void *pvOptionValue, size_t xOptionLength )
1283 {
1284 /* The standard Berkeley function returns 0 for success. */
1285 BaseType_t xReturn = -pdFREERTOS_ERRNO_EINVAL;
1286 BaseType_t lOptionValue;
1287 FreeRTOS_Socket_t *pxSocket;
1288
1289         pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
1290
1291         /* The function prototype is designed to maintain the expected Berkeley
1292         sockets standard, but this implementation does not use all the parameters. */
1293         ( void ) lLevel;
1294         ( void ) xOptionLength;
1295
1296         configASSERT( xSocket );
1297
1298         switch( lOptionName )
1299         {
1300                 case FREERTOS_SO_RCVTIMEO       :
1301                         /* Receive time out. */
1302                         pxSocket->xReceiveBlockTime = *( ( TickType_t * ) pvOptionValue );
1303                         xReturn = 0;
1304                         break;
1305
1306                 case FREERTOS_SO_SNDTIMEO       :
1307                         pxSocket->xSendBlockTime = *( ( TickType_t * ) pvOptionValue );
1308                         if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP )
1309                         {
1310                                 /* The send time out is capped for the reason stated in the
1311                                 comments where ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS is defined
1312                                 in FreeRTOSIPConfig.h (assuming an official configuration file
1313                                 is being used. */
1314                                 if( pxSocket->xSendBlockTime > ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS )
1315                                 {
1316                                         pxSocket->xSendBlockTime = ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS;
1317                                 }
1318                         }
1319                         else
1320                         {
1321                                 /* For TCP socket, it isn't necessary to limit the blocking time
1322                                 because the FreeRTOS_send() function does not wait for a network
1323                                 buffer to become available. */
1324                         }
1325                         xReturn = 0;
1326                         break;
1327                 #if( ipconfigUDP_MAX_RX_PACKETS > 0 )
1328                         case FREERTOS_SO_UDP_MAX_RX_PACKETS:
1329                                 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_UDP )
1330                                 {
1331                                         break;  /* will return -pdFREERTOS_ERRNO_EINVAL */
1332                                 }
1333                                 pxSocket->u.xUDP.uxMaxPackets = *( ( UBaseType_t * ) pvOptionValue );
1334                                 xReturn = 0;
1335                                 break;
1336                 #endif /* ipconfigUDP_MAX_RX_PACKETS */
1337
1338                 case FREERTOS_SO_UDPCKSUM_OUT :
1339                         /* Turn calculating of the UDP checksum on/off for this socket. */
1340                         lOptionValue = ( BaseType_t ) pvOptionValue;
1341
1342                         if( lOptionValue == 0 )
1343                         {
1344                                 pxSocket->ucSocketOptions &= ( uint8_t ) ~FREERTOS_SO_UDPCKSUM_OUT;
1345                         }
1346                         else
1347                         {
1348                                 pxSocket->ucSocketOptions |= ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT;
1349                         }
1350                         xReturn = 0;
1351                         break;
1352
1353                 #if( ipconfigUSE_CALLBACKS == 1 )
1354                         #if( ipconfigUSE_TCP == 1 )
1355                                 case FREERTOS_SO_TCP_CONN_HANDLER:      /* Set a callback for (dis)connection events */
1356                                 case FREERTOS_SO_TCP_RECV_HANDLER:      /* Install a callback for receiving TCP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
1357                                 case FREERTOS_SO_TCP_SENT_HANDLER:      /* Install a callback for sending TCP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
1358                         #endif /* ipconfigUSE_TCP */
1359                                 case FREERTOS_SO_UDP_RECV_HANDLER:      /* Install a callback for receiving UDP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
1360                                 case FREERTOS_SO_UDP_SENT_HANDLER:      /* Install a callback for sending UDP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
1361                                         {
1362                                                 #if( ipconfigUSE_TCP == 1 )
1363                                                 {
1364                                                         UBaseType_t uxProtocol;
1365                                                         if( ( lOptionName == FREERTOS_SO_UDP_RECV_HANDLER ) ||
1366                                                                 ( lOptionName == FREERTOS_SO_UDP_SENT_HANDLER ) )
1367                                                         {
1368                                                                 uxProtocol = ( UBaseType_t ) FREERTOS_IPPROTO_UDP;
1369                                                         }
1370                                                         else
1371                                                         {
1372                                                                 uxProtocol = ( UBaseType_t ) FREERTOS_IPPROTO_TCP;
1373                                                         }
1374
1375                                                         if( pxSocket->ucProtocol != ( uint8_t ) uxProtocol )
1376                                                         {
1377                                                                 break;  /* will return -pdFREERTOS_ERRNO_EINVAL */
1378                                                         }
1379                                                 }
1380                                                 #else
1381                                                 {
1382                                                         /* No need to check if the socket has the right
1383                                                         protocol, because only UDP socket can be created. */
1384                                                 }
1385                                                 #endif /* ipconfigUSE_TCP */
1386
1387                                                 switch( lOptionName )
1388                                                 {
1389                                                 #if ipconfigUSE_TCP == 1
1390                                                         case FREERTOS_SO_TCP_CONN_HANDLER:
1391                                                                 pxSocket->u.xTCP.pxHandleConnected = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnTCPConnected;
1392                                                                 break;
1393                                                         case FREERTOS_SO_TCP_RECV_HANDLER:
1394                                                                 pxSocket->u.xTCP.pxHandleReceive = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnTCPReceive;
1395                                                                 break;
1396                                                         case FREERTOS_SO_TCP_SENT_HANDLER:
1397                                                                 pxSocket->u.xTCP.pxHandleSent = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnTCPSent;
1398                                                                 break;
1399                                                 #endif /* ipconfigUSE_TCP */
1400                                                 case FREERTOS_SO_UDP_RECV_HANDLER:
1401                                                         pxSocket->u.xUDP.pxHandleReceive = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnUDPReceive;
1402                                                         break;
1403                                                 case FREERTOS_SO_UDP_SENT_HANDLER:
1404                                                         pxSocket->u.xUDP.pxHandleSent = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnUDPSent;
1405                                                         break;
1406                                                 default:
1407                                                         break;
1408                                                 }
1409                                         }
1410
1411                                         xReturn = 0;
1412                                         break;
1413                 #endif /* ipconfigUSE_CALLBACKS */
1414
1415                 #if( ipconfigUSE_TCP != 0 )
1416                         #if( ipconfigSOCKET_HAS_USER_SEMAPHORE != 0 )
1417                                 /* Each socket has a semaphore on which the using task normally
1418                                 sleeps. */
1419                                 case FREERTOS_SO_SET_SEMAPHORE:
1420                                         {
1421                                                 pxSocket->pxUserSemaphore = *( ( SemaphoreHandle_t * ) pvOptionValue );
1422                                                 xReturn = 0;
1423                                         }
1424                                         break;
1425                         #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */
1426
1427                         #if( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK != 0 )
1428                                 case FREERTOS_SO_WAKEUP_CALLBACK:
1429                                 {
1430                                         /* Each socket can have a callback function that is executed
1431                                         when there is an event the socket's owner might want to
1432                                         process. */
1433                                         pxSocket->pxUserWakeCallback = ( SocketWakeupCallback_t ) pvOptionValue;
1434                                         xReturn = 0;
1435                                 }
1436                                 break;
1437                         #endif /* ipconfigSOCKET_HAS_USER_WAKE_CALLBACK */
1438
1439                         case FREERTOS_SO_SET_LOW_HIGH_WATER:
1440                                 {
1441                                 LowHighWater_t *pxLowHighWater = ( LowHighWater_t * ) pvOptionValue;
1442
1443                                         if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
1444                                         {
1445                                                 /* It is not allowed to access 'pxSocket->u.xTCP'. */
1446                                                 FreeRTOS_debug_printf( ( "FREERTOS_SO_SET_LOW_HIGH_WATER: wrong socket type\n" ) );
1447                                                 break;  /* will return -pdFREERTOS_ERRNO_EINVAL */
1448                                         }
1449                                         if( ( pxLowHighWater->uxLittleSpace >= pxLowHighWater->uxEnoughSpace ) ||
1450                                                 ( pxLowHighWater->uxEnoughSpace > pxSocket->u.xTCP.uxRxStreamSize ) )
1451                                         {
1452                                                 /* Impossible values. */
1453                                                 FreeRTOS_debug_printf( ( "FREERTOS_SO_SET_LOW_HIGH_WATER: bad values\n" ) );
1454                                                 break;  /* will return -pdFREERTOS_ERRNO_EINVAL */
1455                                         }
1456                                         /* Send a STOP when buffer space drops below 'uxLittleSpace' bytes. */
1457                                         pxSocket->u.xTCP.uxLittleSpace = pxLowHighWater->uxLittleSpace;
1458                                         /* Send a GO when buffer space grows above 'uxEnoughSpace' bytes. */
1459                                         pxSocket->u.xTCP.uxEnoughSpace = pxLowHighWater->uxEnoughSpace;
1460                                         xReturn = 0;
1461                                 }
1462                                 break;
1463
1464                         case FREERTOS_SO_SNDBUF:        /* Set the size of the send buffer, in units of MSS (TCP only) */
1465                         case FREERTOS_SO_RCVBUF:        /* Set the size of the receive buffer, in units of MSS (TCP only) */
1466                                 {
1467                                         uint32_t ulNewValue;
1468
1469                                         if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
1470                                         {
1471                                                 FreeRTOS_debug_printf( ( "Set SO_%sBUF: wrong socket type\n",
1472                                                         ( lOptionName == FREERTOS_SO_SNDBUF ) ? "SND" : "RCV" ) );
1473                                                 break;  /* will return -pdFREERTOS_ERRNO_EINVAL */
1474                                         }
1475
1476                                         if( ( ( lOptionName == FREERTOS_SO_SNDBUF ) && ( pxSocket->u.xTCP.txStream != NULL ) ) ||
1477                                                 ( ( lOptionName == FREERTOS_SO_RCVBUF ) && ( pxSocket->u.xTCP.rxStream != NULL ) ) )
1478                                         {
1479                                                 FreeRTOS_debug_printf( ( "Set SO_%sBUF: buffer already created\n",
1480                                                         ( lOptionName == FREERTOS_SO_SNDBUF ) ? "SND" : "RCV" ) );
1481                                                 break;  /* will return -pdFREERTOS_ERRNO_EINVAL */
1482                                         }
1483
1484                                         ulNewValue = *( ( uint32_t * ) pvOptionValue );
1485
1486                                         if( lOptionName == FREERTOS_SO_SNDBUF )
1487                                         {
1488                                                 /* Round up to nearest MSS size */
1489                                                 ulNewValue = FreeRTOS_round_up( ulNewValue, ( uint32_t ) pxSocket->u.xTCP.usInitMSS );
1490                                                 pxSocket->u.xTCP.uxTxStreamSize = ulNewValue;
1491                                         }
1492                                         else
1493                                         {
1494                                                 pxSocket->u.xTCP.uxRxStreamSize = ulNewValue;
1495                                         }
1496                                 }
1497                                 xReturn = 0;
1498                                 break;
1499
1500                         case FREERTOS_SO_WIN_PROPERTIES:        /* Set all buffer and window properties in one call, parameter is pointer to WinProperties_t */
1501                                 {
1502                                         WinProperties_t* pxProps;
1503
1504                                         if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
1505                                         {
1506                                                 FreeRTOS_debug_printf( ( "Set SO_WIN_PROP: wrong socket type\n" ) );
1507                                                 break;  /* will return -pdFREERTOS_ERRNO_EINVAL */
1508                                         }
1509
1510                                         if( ( pxSocket->u.xTCP.txStream != NULL ) || ( pxSocket->u.xTCP.rxStream != NULL ) )
1511                                         {
1512                                                 FreeRTOS_debug_printf( ( "Set SO_WIN_PROP: buffer already created\n" ) );
1513                                                 break;  /* will return -pdFREERTOS_ERRNO_EINVAL */
1514                                         }
1515
1516                                         pxProps = ( ( WinProperties_t * ) pvOptionValue );
1517
1518                                         if ( FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDBUF, &( pxProps->lTxBufSize ), sizeof( pxProps->lTxBufSize ) ) != 0 )
1519                                         {
1520                                                 break;  /* will return -pdFREERTOS_ERRNO_EINVAL */
1521                                         }
1522
1523                                         if ( FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVBUF, &( pxProps->lRxBufSize ), sizeof( pxProps->lRxBufSize ) ) != 0 )
1524                                         {
1525                                                 break;  /* will return -pdFREERTOS_ERRNO_EINVAL */
1526                                         }
1527
1528                                         #if( ipconfigUSE_TCP_WIN == 1 )
1529                                         {
1530                                                 pxSocket->u.xTCP.uxRxWinSize = ( uint32_t )pxProps->lRxWinSize; /* Fixed value: size of the TCP reception window */
1531                                                 pxSocket->u.xTCP.uxTxWinSize = ( uint32_t )pxProps->lTxWinSize; /* Fixed value: size of the TCP transmit window */
1532                                         }
1533                                         #else
1534                                         {
1535                                                 pxSocket->u.xTCP.uxRxWinSize = 1u;
1536                                                 pxSocket->u.xTCP.uxTxWinSize = 1u;
1537                                         }
1538                                         #endif
1539
1540                                         /* In case the socket has already initialised its tcpWin,
1541                                         adapt the window size parameters */
1542                                         if( pxSocket->u.xTCP.xTCPWindow.u.bits.bHasInit != pdFALSE_UNSIGNED )
1543                                         {
1544                                                 pxSocket->u.xTCP.xTCPWindow.xSize.ulRxWindowLength = pxSocket->u.xTCP.uxRxWinSize * pxSocket->u.xTCP.usInitMSS;
1545                                                 pxSocket->u.xTCP.xTCPWindow.xSize.ulTxWindowLength = pxSocket->u.xTCP.uxTxWinSize * pxSocket->u.xTCP.usInitMSS;
1546                                         }
1547                                 }
1548
1549                                 xReturn = 0;
1550                                 break;
1551
1552                         case FREERTOS_SO_REUSE_LISTEN_SOCKET:   /* If true, the server-socket will turn into a connected socket */
1553                                 {
1554                                         if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
1555                                         {
1556                                                 break;  /* will return -pdFREERTOS_ERRNO_EINVAL */
1557                                         }
1558                                         if( *( ( BaseType_t * ) pvOptionValue ) != 0 )
1559                                         {
1560                                                 pxSocket->u.xTCP.bits.bReuseSocket = pdTRUE_UNSIGNED;
1561                                         }
1562                                         else
1563                                         {
1564                                                 pxSocket->u.xTCP.bits.bReuseSocket = pdFALSE_UNSIGNED;
1565                                         }
1566                                 }
1567                                 xReturn = 0;
1568                                 break;
1569
1570                         case FREERTOS_SO_CLOSE_AFTER_SEND:              /* As soon as the last byte has been transmitted, finalise the connection */
1571                                 {
1572                                         if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
1573                                         {
1574                                                 break;  /* will return -pdFREERTOS_ERRNO_EINVAL */
1575                                         }
1576
1577                                         if( *( ( BaseType_t * ) pvOptionValue ) != 0 )
1578                                         {
1579                                                 pxSocket->u.xTCP.bits.bCloseAfterSend = pdTRUE_UNSIGNED;
1580                                         }
1581                                         else
1582                                         {
1583                                                 pxSocket->u.xTCP.bits.bCloseAfterSend = pdFALSE_UNSIGNED;
1584                                         }
1585                                 }
1586                                 xReturn = 0;
1587                                 break;
1588
1589                         case FREERTOS_SO_SET_FULL_SIZE:         /* Refuse to send packets smaller than MSS  */
1590                                 {
1591                                         if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
1592                                         {
1593                                                 break;  /* will return -pdFREERTOS_ERRNO_EINVAL */
1594                                         }
1595
1596                                         if( *( ( BaseType_t * ) pvOptionValue ) != 0 )
1597                                         {
1598                                                 pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize = pdTRUE_UNSIGNED;
1599                                         }
1600                                         else
1601                                         {
1602                                                 pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize = pdFALSE_UNSIGNED;
1603                                         }
1604
1605                                         if( ( pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize == pdFALSE_UNSIGNED ) &&
1606                                                 ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) &&
1607                                                 ( FreeRTOS_outstanding( pxSocket ) != 0 ) )
1608                                         {
1609                                                 pxSocket->u.xTCP.usTimeout = 1u; /* to set/clear bSendFullSize */
1610                                                 xSendEventToIPTask( eTCPTimerEvent );
1611                                         }
1612                                 }
1613                                 xReturn = 0;
1614                                 break;
1615
1616                         case FREERTOS_SO_STOP_RX:               /* Refuse to receive more packts */
1617                                 {
1618                                         if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
1619                                         {
1620                                                 break;  /* will return -pdFREERTOS_ERRNO_EINVAL */
1621                                         }
1622
1623                                         if( *( ( BaseType_t * ) pvOptionValue ) != 0 )
1624                                         {
1625                                                 pxSocket->u.xTCP.bits.bRxStopped = pdTRUE_UNSIGNED;
1626                                         }
1627                                         else
1628                                         {
1629                                                 pxSocket->u.xTCP.bits.bRxStopped = pdFALSE_UNSIGNED;
1630                                         }
1631
1632                                         pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
1633                                         pxSocket->u.xTCP.usTimeout = 1u; /* to set/clear bRxStopped */
1634                                         xSendEventToIPTask( eTCPTimerEvent );
1635                                 }
1636                                 xReturn = 0;
1637                                 break;
1638
1639                 #endif  /* ipconfigUSE_TCP == 1 */
1640
1641                 default :
1642                         /* No other options are handled. */
1643                         xReturn = -pdFREERTOS_ERRNO_ENOPROTOOPT;
1644                         break;
1645         }
1646
1647         return xReturn;
1648 } /* Tested */
1649
1650 /*-----------------------------------------------------------*/
1651
1652 /* Find an available port number per https://tools.ietf.org/html/rfc6056. */
1653 static uint16_t prvGetPrivatePortNumber( BaseType_t xProtocol )
1654 {
1655 const uint16_t usEphemeralPortCount =
1656         socketAUTO_PORT_ALLOCATION_MAX_NUMBER - socketAUTO_PORT_ALLOCATION_START_NUMBER + 1;
1657 uint16_t usIterations = usEphemeralPortCount;
1658 uint32_t ulRandomSeed = 0;
1659 uint16_t usResult = 0;
1660 const List_t *pxList;
1661
1662 #if ipconfigUSE_TCP == 1
1663         if( xProtocol == ( BaseType_t ) FREERTOS_IPPROTO_TCP )
1664         {
1665                 pxList = &xBoundTCPSocketsList;
1666         }
1667         else
1668 #endif
1669         {
1670                 pxList = &xBoundUDPSocketsList;
1671         }
1672
1673         /* Avoid compiler warnings if ipconfigUSE_TCP is not defined. */
1674         ( void ) xProtocol;
1675
1676         /* Find the next available port using the random seed as a starting
1677         point. */
1678         do
1679         {
1680                 /* Only proceed if the random number generator succeeded. */
1681                 if( xApplicationGetRandomNumber( &( ulRandomSeed ) ) == pdFALSE )
1682                 {
1683                         break;
1684                 }
1685
1686                 /* Map the random to a candidate port. */
1687                 usResult =
1688                         socketAUTO_PORT_ALLOCATION_START_NUMBER +
1689                         ( ( ( uint16_t )ulRandomSeed ) % usEphemeralPortCount );
1690
1691                 /* Check if there's already an open socket with the same protocol
1692                 and port. */
1693                 if( NULL == pxListFindListItemWithValue(
1694                         pxList,
1695                         ( TickType_t )FreeRTOS_htons( usResult ) ) )
1696                 {
1697                         usResult = FreeRTOS_htons( usResult );
1698                         break;
1699                 }
1700                 else
1701                 {
1702                         usResult = 0;
1703                 }
1704
1705                 usIterations--;
1706         }
1707         while( usIterations > 0 );
1708
1709         return usResult;
1710 }
1711 /*-----------------------------------------------------------*/
1712
1713 /* pxListFindListItemWithValue: find a list item in a bound socket list
1714 'xWantedItemValue' refers to a port number */
1715 static const ListItem_t * pxListFindListItemWithValue( const List_t *pxList, TickType_t xWantedItemValue )
1716 {
1717 const ListItem_t * pxResult = NULL;
1718
1719         if( ( xIPIsNetworkTaskReady() != pdFALSE ) && ( pxList != NULL ) )
1720         {
1721                 const ListItem_t *pxIterator;
1722                 const MiniListItem_t *pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( pxList );
1723                 for( pxIterator  = ( const ListItem_t * ) listGET_NEXT( pxEnd );
1724                          pxIterator != ( const ListItem_t * ) pxEnd;
1725                          pxIterator  = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
1726                 {
1727                         if( listGET_LIST_ITEM_VALUE( pxIterator ) == xWantedItemValue )
1728                         {
1729                                 pxResult = pxIterator;
1730                                 break;
1731                         }
1732                 }
1733         }
1734
1735         return pxResult;
1736 } /* Tested */
1737
1738 /*-----------------------------------------------------------*/
1739
1740 FreeRTOS_Socket_t *pxUDPSocketLookup( UBaseType_t uxLocalPort )
1741 {
1742 const ListItem_t *pxListItem;
1743 FreeRTOS_Socket_t *pxSocket = NULL;
1744
1745         /* Looking up a socket is quite simple, find a match with the local port.
1746
1747         See if there is a list item associated with the port number on the
1748         list of bound sockets. */
1749         pxListItem = pxListFindListItemWithValue( &xBoundUDPSocketsList, ( TickType_t ) uxLocalPort );
1750
1751         if( pxListItem != NULL )
1752         {
1753                 /* The owner of the list item is the socket itself. */
1754                 pxSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxListItem );
1755                 configASSERT( pxSocket != NULL );
1756         }
1757         return pxSocket;
1758 }
1759
1760 /*-----------------------------------------------------------*/
1761
1762 #if ipconfigINCLUDE_FULL_INET_ADDR == 1
1763
1764         uint32_t FreeRTOS_inet_addr( const char * pcIPAddress )
1765         {
1766         const uint32_t ulDecimalBase = 10u;
1767         uint8_t ucOctet[ socketMAX_IP_ADDRESS_OCTETS ];
1768         const char *pcPointerOnEntering;
1769         uint32_t ulReturn = 0UL, ulValue;
1770         UBaseType_t uxOctetNumber;
1771         BaseType_t xResult = pdPASS;
1772
1773                 for( uxOctetNumber = 0u; uxOctetNumber < socketMAX_IP_ADDRESS_OCTETS; uxOctetNumber++ )
1774                 {
1775                         ulValue = 0ul;
1776                         pcPointerOnEntering = pcIPAddress;
1777
1778                         while( ( *pcIPAddress >= '0' ) && ( *pcIPAddress <= '9' ) )
1779                         {
1780                                 /* Move previous read characters into the next decimal
1781                                 position. */
1782                                 ulValue *= ulDecimalBase;
1783
1784                                 /* Add the binary value of the ascii character. */
1785                                 ulValue += ( ( uint32_t ) ( *pcIPAddress ) - ( uint32_t ) '0' );
1786
1787                                 /* Move to next character in the string. */
1788                                 pcIPAddress++;
1789                         }
1790
1791                         /* Check characters were read. */
1792                         if( pcIPAddress == pcPointerOnEntering )
1793                         {
1794                                 xResult = pdFAIL;
1795                         }
1796
1797                         /* Check the value fits in an 8-bit number. */
1798                         if( ulValue > 0xffUL )
1799                         {
1800                                 xResult = pdFAIL;
1801                         }
1802                         else
1803                         {
1804                                 ucOctet[ uxOctetNumber ] = ( uint8_t ) ulValue;
1805
1806                                 /* Check the next character is as expected. */
1807                                 if( uxOctetNumber < ( socketMAX_IP_ADDRESS_OCTETS - 1u ) )
1808                                 {
1809                                         if( *pcIPAddress != '.' )
1810                                         {
1811                                                 xResult = pdFAIL;
1812                                         }
1813                                         else
1814                                         {
1815                                                 /* Move past the dot. */
1816                                                 pcIPAddress++;
1817                                         }
1818                                 }
1819                         }
1820
1821                         if( xResult == pdFAIL )
1822                         {
1823                                 /* No point going on. */
1824                                 break;
1825                         }
1826                 }
1827
1828                 if( *pcIPAddress != ( char ) 0 )
1829                 {
1830                         /* Expected the end of the string. */
1831                         xResult = pdFAIL;
1832                 }
1833
1834                 if( uxOctetNumber != socketMAX_IP_ADDRESS_OCTETS )
1835                 {
1836                         /* Didn't read enough octets. */
1837                         xResult = pdFAIL;
1838                 }
1839
1840                 if( xResult == pdPASS )
1841                 {
1842                         ulReturn = FreeRTOS_inet_addr_quick( ucOctet[ 0 ], ucOctet[ 1 ], ucOctet[ 2 ], ucOctet[ 3 ] );
1843                 }
1844
1845                 return ulReturn;
1846         }
1847
1848 #endif /* ipconfigINCLUDE_FULL_INET_ADDR */
1849
1850 /*-----------------------------------------------------------*/
1851
1852 /* Function to get the local address and IP port */
1853 size_t FreeRTOS_GetLocalAddress( Socket_t xSocket, struct freertos_sockaddr *pxAddress )
1854 {
1855 FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
1856
1857         /* IP address of local machine. */
1858         pxAddress->sin_addr = *ipLOCAL_IP_ADDRESS_POINTER;
1859
1860         /* Local port on this machine. */
1861         pxAddress->sin_port = FreeRTOS_htons( pxSocket->usLocalPort );
1862
1863         return sizeof( *pxAddress );
1864 }
1865
1866 /*-----------------------------------------------------------*/
1867
1868 void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket )
1869 {
1870 /* _HT_ must work this out, now vSocketWakeUpUser will be called for any important
1871  * event or transition */
1872         #if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
1873         {
1874                 if( pxSocket->pxUserSemaphore != NULL )
1875                 {
1876                         xSemaphoreGive( pxSocket->pxUserSemaphore );
1877                 }
1878         }
1879         #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */
1880
1881         #if( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK == 1 )
1882         {
1883                 if( pxSocket->pxUserWakeCallback != NULL )
1884                 {
1885                         pxSocket->pxUserWakeCallback( pxSocket );
1886                 }
1887         }
1888         #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */
1889
1890         #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
1891         {
1892                 if( pxSocket->pxSocketSet != NULL )
1893                 {
1894                         EventBits_t xSelectBits = ( pxSocket->xEventBits >> SOCKET_EVENT_BIT_COUNT ) & eSELECT_ALL;
1895                         if( xSelectBits != 0ul )
1896                         {
1897                                 pxSocket->xSocketBits |= xSelectBits;
1898                                 xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, xSelectBits );
1899                         }
1900                 }
1901
1902                 pxSocket->xEventBits &= eSOCKET_ALL;
1903         }
1904         #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
1905
1906         if( ( pxSocket->xEventGroup != NULL ) && ( pxSocket->xEventBits != 0u ) )
1907         {
1908                 xEventGroupSetBits( pxSocket->xEventGroup, pxSocket->xEventBits );
1909         }
1910
1911         pxSocket->xEventBits = 0ul;
1912 }
1913
1914 /*-----------------------------------------------------------*/
1915
1916 #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
1917
1918         /* This define makes it possible for network-card drivers to inspect
1919          * UDP message and see if there is any UDP socket bound to a given port
1920          * number.
1921          * This is probably only usefull in systems with a minimum of RAM and
1922          * when lots of anonymous broadcast messages come in
1923          */
1924         BaseType_t xPortHasUDPSocket( uint16_t usPortNr )
1925         {
1926         BaseType_t xFound = pdFALSE;
1927
1928                 vTaskSuspendAll();
1929                 {
1930                         if( ( pxListFindListItemWithValue( &xBoundUDPSocketsList, ( TickType_t ) usPortNr ) != NULL ) )
1931                         {
1932                                 xFound = pdTRUE;
1933                         }
1934                 }
1935                 xTaskResumeAll();
1936
1937                 return xFound;
1938         }
1939
1940 #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
1941
1942 /*-----------------------------------------------------------*/
1943
1944 #if( ipconfigUSE_TCP == 1 )
1945
1946         static BaseType_t bMayConnect( FreeRTOS_Socket_t *pxSocket );
1947         static BaseType_t bMayConnect( FreeRTOS_Socket_t *pxSocket )
1948         {
1949                 switch( pxSocket->u.xTCP.ucTCPState )
1950                 {
1951                         case eCLOSED:
1952                         case eCLOSE_WAIT:       return 0;
1953                         case eCONNECT_SYN:      return -pdFREERTOS_ERRNO_EINPROGRESS;
1954                         default:                        return -pdFREERTOS_ERRNO_EAGAIN;
1955                 }
1956         }
1957
1958 #endif /* ipconfigUSE_TCP */
1959 /*-----------------------------------------------------------*/
1960
1961 #if( ipconfigUSE_TCP == 1 )
1962
1963         static BaseType_t prvTCPConnectStart( FreeRTOS_Socket_t *pxSocket, struct freertos_sockaddr *pxAddress )
1964         {
1965         BaseType_t xResult = 0;
1966
1967                 if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdFALSE )
1968                 {
1969                         /* Not a valid socket or wrong type */
1970                         xResult = -pdFREERTOS_ERRNO_EBADF;
1971                 }
1972                 else if( FreeRTOS_issocketconnected( pxSocket ) > 0 )
1973                 {
1974                         /* The socket is already connected. */
1975                         xResult = -pdFREERTOS_ERRNO_EISCONN;
1976                 }
1977                 else if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE )
1978                 {
1979                         /* Bind the socket to the port that the client task will send from.
1980                         Non-standard, so the error returned is that returned by bind(). */
1981                         xResult = FreeRTOS_bind( ( Socket_t ) pxSocket, NULL, 0u );
1982                 }
1983
1984                 if( xResult == 0 )
1985                 {
1986                         /* Check if it makes any sense to wait for a connect event, this condition
1987                         might change while sleeping, so it must be checked within each loop */
1988                         xResult = bMayConnect( pxSocket ); /* -EINPROGRESS, -EAGAIN, or 0 for OK */
1989
1990                         /* Start the connect procedure, kernel will start working on it */
1991                         if( xResult == 0 )
1992                         {
1993                                 pxSocket->u.xTCP.bits.bConnPrepared = pdFALSE_UNSIGNED;
1994                                 pxSocket->u.xTCP.ucRepCount = 0u;
1995
1996                                 FreeRTOS_debug_printf( ( "FreeRTOS_connect: %u to %lxip:%u\n",
1997                                         pxSocket->usLocalPort, FreeRTOS_ntohl( pxAddress->sin_addr ), FreeRTOS_ntohs( pxAddress->sin_port ) ) );
1998
1999                                 /* Port on remote machine. */
2000                                 pxSocket->u.xTCP.usRemotePort = FreeRTOS_ntohs( pxAddress->sin_port );
2001
2002                                 /* IP address of remote machine. */
2003                                 pxSocket->u.xTCP.ulRemoteIP = FreeRTOS_ntohl( pxAddress->sin_addr );
2004
2005                                 /* (client) internal state: socket wants to send a connect. */
2006                                 vTCPStateChange( pxSocket, eCONNECT_SYN );
2007
2008                                 /* To start an active connect. */
2009                                 pxSocket->u.xTCP.usTimeout = 1u;
2010
2011                                 if( xSendEventToIPTask( eTCPTimerEvent ) != pdPASS )
2012                                 {
2013                                         xResult = -pdFREERTOS_ERRNO_ECANCELED;
2014                                 }
2015                         }
2016                 }
2017
2018                 return xResult;
2019         }
2020
2021 #endif /* ipconfigUSE_TCP */
2022 /*-----------------------------------------------------------*/
2023
2024 #if( ipconfigUSE_TCP == 1 )
2025
2026         /*
2027          * FreeRTOS_connect: socket wants to connect to a remote port
2028          */
2029         BaseType_t FreeRTOS_connect( Socket_t xClientSocket, struct freertos_sockaddr *pxAddress, socklen_t xAddressLength )
2030         {
2031         FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t* ) xClientSocket;
2032         TickType_t xRemainingTime;
2033         BaseType_t xTimed = pdFALSE;
2034         BaseType_t xResult;
2035         TimeOut_t xTimeOut;
2036
2037                 ( void ) xAddressLength;
2038
2039                 xResult = prvTCPConnectStart( pxSocket, pxAddress );
2040
2041                 if( xResult == 0 )
2042                 {
2043                         /* And wait for the result */
2044                         for( ;; )
2045                         {
2046                                 if( xTimed == pdFALSE )
2047                                 {
2048                                         /* Only in the first round, check for non-blocking */
2049                                         xRemainingTime = pxSocket->xReceiveBlockTime;
2050                                         if( xRemainingTime == ( TickType_t )0 )
2051                                         {
2052                                                 /* Not yet connected, correct state, non-blocking. */
2053                                                 xResult = -pdFREERTOS_ERRNO_EWOULDBLOCK;
2054                                                 break;
2055                                         }
2056
2057                                         /* Don't get here a second time. */
2058                                         xTimed = pdTRUE;
2059
2060                                         /* Fetch the current time */
2061                                         vTaskSetTimeOutState( &xTimeOut );
2062                                 }
2063
2064                                 /* Did it get connected while sleeping ? */
2065                                 xResult = FreeRTOS_issocketconnected( pxSocket );
2066
2067                                 /* Returns positive when connected, negative means an error */
2068                                 if( xResult < 0 )
2069                                 {
2070                                         /* Return the error */
2071                                         break;
2072                                 }
2073
2074                                 if( xResult > 0 )
2075                                 {
2076                                         /* Socket now connected, return a zero */
2077                                         xResult = 0;
2078                                         break;
2079                                 }
2080
2081                                 /* Is it allowed to sleep more? */
2082                                 if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) )
2083                                 {
2084                                         xResult = -pdFREERTOS_ERRNO_ETIMEDOUT;
2085                                         break;
2086                                 }
2087
2088                                 /* Go sleeping until we get any down-stream event */
2089                                 xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_CONNECT, pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );
2090                         }
2091                 }
2092
2093                 return xResult;
2094         }
2095 #endif /* ipconfigUSE_TCP */
2096 /*-----------------------------------------------------------*/
2097
2098 #if( ipconfigUSE_TCP == 1 )
2099
2100         /*
2101          * FreeRTOS_accept: can return a new connected socket
2102          * if the server socket is in listen mode and receives a connection request
2103          * The new socket will be bound already to the same port number as the listing
2104          * socket.
2105          */
2106         Socket_t FreeRTOS_accept( Socket_t xServerSocket, struct freertos_sockaddr *pxAddress, socklen_t *pxAddressLength )
2107         {
2108         FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xServerSocket;
2109         FreeRTOS_Socket_t *pxClientSocket = NULL;
2110         TickType_t xRemainingTime;
2111         BaseType_t xTimed = pdFALSE, xAsk = pdFALSE;
2112         TimeOut_t xTimeOut;
2113         IPStackEvent_t xAskEvent;
2114
2115                 if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
2116                 {
2117                         /* Not a valid socket or wrong type */
2118                         pxClientSocket = ( FreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET;
2119                 }
2120                 else if( ( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) &&
2121                                  ( pxSocket->u.xTCP.ucTCPState != eTCP_LISTEN ) )
2122                 {
2123                         /* Parent socket is not in listening mode */
2124                         pxClientSocket = ( FreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET;
2125                 }
2126                 else
2127                 {
2128                         /* Loop will stop with breaks. */
2129                         for( ; ; )
2130                         {
2131                                 /* Is there a new client? */
2132                                 vTaskSuspendAll();
2133                                 {
2134                                         if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
2135                                         {
2136                                                 pxClientSocket = pxSocket->u.xTCP.pxPeerSocket;
2137                                         }
2138                                         else
2139                                         {
2140                                                 pxClientSocket = pxSocket;
2141                                         }
2142                                         if( pxClientSocket != NULL )
2143                                         {
2144                                                 pxSocket->u.xTCP.pxPeerSocket = NULL;
2145
2146                                                 /* Is it still not taken ? */
2147                                                 if( pxClientSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED )
2148                                                 {
2149                                                         pxClientSocket->u.xTCP.bits.bPassAccept = pdFALSE_UNSIGNED;
2150                                                 }
2151                                                 else
2152                                                 {
2153                                                         pxClientSocket = NULL;
2154                                                 }
2155                                         }
2156                                 }
2157                                 xTaskResumeAll();
2158
2159                                 if( pxClientSocket != NULL )
2160                                 {
2161                                         if( pxAddress != NULL )
2162                                         {
2163                                                 /* IP address of remote machine. */
2164                                                 pxAddress->sin_addr = FreeRTOS_ntohl( pxClientSocket->u.xTCP.ulRemoteIP );
2165
2166                                                 /* Port on remote machine. */
2167                                                 pxAddress->sin_port = FreeRTOS_ntohs( pxClientSocket->u.xTCP.usRemotePort );
2168                                         }
2169                                         if( pxAddressLength != NULL )
2170                                         {
2171                                                 *pxAddressLength = sizeof( *pxAddress );
2172                                         }
2173
2174                                         if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
2175                                         {
2176                                                 xAsk = pdTRUE;
2177                                         }
2178                                 }
2179
2180                                 if( xAsk != pdFALSE )
2181                                 {
2182                                         /* Ask to set an event in 'xEventGroup' as soon as a new
2183                                         client gets connected for this listening socket. */
2184                                         xAskEvent.eEventType = eTCPAcceptEvent;
2185                                         xAskEvent.pvData = ( void * ) pxSocket;
2186                                         xSendEventStructToIPTask( &xAskEvent, portMAX_DELAY );
2187                                 }
2188
2189                                 if( pxClientSocket != NULL )
2190                                 {
2191                                         break;
2192                                 }
2193
2194                                 if( xTimed == pdFALSE )
2195                                 {
2196                                         /* Only in the first round, check for non-blocking */
2197                                         xRemainingTime = pxSocket->xReceiveBlockTime;
2198                                         if( xRemainingTime == ( TickType_t ) 0 )
2199                                         {
2200                                                 break;
2201                                         }
2202
2203                                         /* Don't get here a second time */
2204                                         xTimed = pdTRUE;
2205
2206                                         /* Fetch the current time */
2207                                         vTaskSetTimeOutState( &xTimeOut );
2208                                 }
2209
2210                                 /* Has the timeout been reached? */
2211                                 if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
2212                                 {
2213                                         break;
2214                                 }
2215
2216                                 /* Go sleeping until we get any down-stream event */
2217                                 xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_ACCEPT, pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );
2218                         }
2219                 }
2220
2221                 return ( Socket_t ) pxClientSocket;
2222         }
2223 #endif /* ipconfigUSE_TCP */
2224 /*-----------------------------------------------------------*/
2225
2226 #if( ipconfigUSE_TCP == 1 )
2227
2228         /*
2229          * Read incoming data from a TCP socket
2230          * Only after the last byte has been read, a close error might be returned
2231          */
2232         BaseType_t FreeRTOS_recv( Socket_t xSocket, void *pvBuffer, size_t xBufferLength, BaseType_t xFlags )
2233         {
2234         BaseType_t xByteCount;
2235         FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
2236         TickType_t xRemainingTime;
2237         BaseType_t xTimed = pdFALSE;
2238         TimeOut_t xTimeOut;
2239         EventBits_t xEventBits = ( EventBits_t ) 0;
2240
2241                 /* Check if the socket is valid, has type TCP and if it is bound to a
2242                 port. */
2243                 if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
2244                 {
2245                         xByteCount = -pdFREERTOS_ERRNO_EINVAL;
2246                 }
2247                 else
2248                 {
2249                         if( pxSocket->u.xTCP.rxStream != NULL )
2250                         {
2251                                 xByteCount = ( BaseType_t )uxStreamBufferGetSize ( pxSocket->u.xTCP.rxStream );
2252                         }
2253                         else
2254                         {
2255                                 xByteCount = 0;
2256                         }
2257
2258                         while( xByteCount == 0 )
2259                         {
2260                                 switch( pxSocket->u.xTCP.ucTCPState )
2261                                 {
2262                                 case eCLOSED:
2263                                 case eCLOSE_WAIT:       /* (server + client) waiting for a connection termination request from the local user. */
2264                                 case eCLOSING:          /* (server + client) waiting for a connection termination request acknowledgement from the remote TCP. */
2265                                         if( pxSocket->u.xTCP.bits.bMallocError != pdFALSE_UNSIGNED )
2266                                         {
2267                                                 /* The no-memory error has priority above the non-connected error.
2268                                                 Both are fatal and will elad to closing the socket. */
2269                                                 xByteCount = -pdFREERTOS_ERRNO_ENOMEM;
2270                                         }
2271                                         else
2272                                         {
2273                                                 xByteCount = -pdFREERTOS_ERRNO_ENOTCONN;
2274                                         }
2275                                         /* Call continue to break out of the switch and also the while
2276                                         loop. */
2277                                         continue;
2278                                 default:
2279                                         break;
2280                                 }
2281
2282                                 if( xTimed == pdFALSE )
2283                                 {
2284                                         /* Only in the first round, check for non-blocking. */
2285                                         xRemainingTime = pxSocket->xReceiveBlockTime;
2286
2287                                         if( xRemainingTime == ( TickType_t ) 0 )
2288                                         {
2289                                                 #if( ipconfigSUPPORT_SIGNALS != 0 )
2290                                                 {
2291                                                         /* Just check for the interrupt flag. */
2292                                                         xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_INTR,
2293                                                                 pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, socketDONT_BLOCK );
2294                                                 }
2295                                                 #endif /* ipconfigSUPPORT_SIGNALS */
2296                                                 break;
2297                                         }
2298
2299                                         if( ( xFlags & FREERTOS_MSG_DONTWAIT ) != 0 )
2300                                         {
2301                                                 break;
2302                                         }
2303
2304                                         /* Don't get here a second time. */
2305                                         xTimed = pdTRUE;
2306
2307                                         /* Fetch the current time. */
2308                                         vTaskSetTimeOutState( &xTimeOut );
2309                                 }
2310
2311                                 /* Has the timeout been reached? */
2312                                 if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
2313                                 {
2314                                         break;
2315                                 }
2316
2317                                 /* Block until there is a down-stream event. */
2318                                 xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup,
2319                                         eSOCKET_RECEIVE | eSOCKET_CLOSED | eSOCKET_INTR,
2320                                         pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );
2321                                 #if( ipconfigSUPPORT_SIGNALS != 0 )
2322                                 {
2323                                         if( ( xEventBits & eSOCKET_INTR ) != 0u )
2324                                         {
2325                                                 break;
2326                                         }
2327                                 }
2328                                 #else
2329                                 {
2330                                         ( void ) xEventBits;
2331                                 }
2332                                 #endif /* ipconfigSUPPORT_SIGNALS */
2333
2334                                 if( pxSocket->u.xTCP.rxStream != NULL )
2335                                 {
2336                                         xByteCount = ( BaseType_t ) uxStreamBufferGetSize ( pxSocket->u.xTCP.rxStream );
2337                                 }
2338                                 else
2339                                 {
2340                                         xByteCount = 0;
2341                                 }
2342                         }
2343
2344                 #if( ipconfigSUPPORT_SIGNALS != 0 )
2345                         if( ( xEventBits & eSOCKET_INTR ) != 0 )
2346                         {
2347                                 if( ( xEventBits & ( eSOCKET_RECEIVE | eSOCKET_CLOSED ) ) != 0 )
2348                                 {
2349                                         /* Shouldn't have cleared other flags. */
2350                                         xEventBits &= ~eSOCKET_INTR;
2351                                         xEventGroupSetBits( pxSocket->xEventGroup, xEventBits );
2352                                 }
2353                                 xByteCount = -pdFREERTOS_ERRNO_EINTR;
2354                         }
2355                         else
2356                 #endif /* ipconfigSUPPORT_SIGNALS */
2357                         if( xByteCount > 0 )
2358                         {
2359                                 if( ( xFlags & FREERTOS_ZERO_COPY ) == 0 )
2360                                 {
2361                                         xByteCount = ( BaseType_t ) uxStreamBufferGet( pxSocket->u.xTCP.rxStream, 0ul, ( uint8_t * ) pvBuffer, ( size_t ) xBufferLength, ( xFlags & FREERTOS_MSG_PEEK ) != 0 );
2362                                         if( pxSocket->u.xTCP.bits.bLowWater != pdFALSE_UNSIGNED )
2363                                         {
2364                                                 /* We had reached the low-water mark, now see if the flag
2365                                                 can be cleared */
2366                                                 size_t uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
2367
2368                                                 if( uxFrontSpace >= pxSocket->u.xTCP.uxEnoughSpace )
2369                                                 {
2370                                                         pxSocket->u.xTCP.bits.bLowWater = pdFALSE_UNSIGNED;
2371                                                         pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
2372                                                         pxSocket->u.xTCP.usTimeout = 1u; /* because bLowWater is cleared. */
2373                                                         xSendEventToIPTask( eTCPTimerEvent );
2374                                                 }
2375                                         }
2376                                 }
2377                                 else
2378                                 {
2379                                         /* Zero-copy reception of data: pvBuffer is a pointer to a pointer. */
2380                                         xByteCount = ( BaseType_t ) uxStreamBufferGetPtr( pxSocket->u.xTCP.rxStream, (uint8_t **)pvBuffer );
2381                                 }
2382                         }
2383                 } /* prvValidSocket() */
2384
2385                 return xByteCount;
2386         }
2387
2388 #endif /* ipconfigUSE_TCP */
2389 /*-----------------------------------------------------------*/
2390
2391 #if( ipconfigUSE_TCP == 1 )
2392
2393         static int32_t prvTCPSendCheck( FreeRTOS_Socket_t *pxSocket, size_t xDataLength )
2394         {
2395         int32_t xResult = 1;
2396
2397                 /* Is this a socket of type TCP and is it already bound to a port number ? */
2398                 if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
2399                 {
2400                         xResult = -pdFREERTOS_ERRNO_EINVAL;
2401                 }
2402                 else if( pxSocket->u.xTCP.bits.bMallocError != pdFALSE_UNSIGNED )
2403                 {
2404                         xResult = -pdFREERTOS_ERRNO_ENOMEM;
2405                 }
2406                 else if( pxSocket->u.xTCP.ucTCPState == eCLOSED ||
2407                  pxSocket->u.xTCP.ucTCPState == eCLOSE_WAIT ||
2408                  pxSocket->u.xTCP.ucTCPState == eCLOSING )
2409                 {
2410                         xResult = -pdFREERTOS_ERRNO_ENOTCONN;
2411                 }
2412                 else if( pxSocket->u.xTCP.bits.bFinSent != pdFALSE_UNSIGNED )
2413                 {
2414                         /* This TCP connection is closing already, the FIN flag has been sent.
2415                         Maybe it is still delivering or receiving data.
2416                         Return OK in order not to get closed/deleted too quickly */
2417                         xResult = 0;
2418                 }
2419                 else if( xDataLength == 0ul )
2420                 {
2421                         /* send() is being called to send zero bytes */
2422                         xResult = 0;
2423                 }
2424                 else if( pxSocket->u.xTCP.txStream == NULL )
2425                 {
2426                         /* Create the outgoing stream only when it is needed */
2427                         prvTCPCreateStream( pxSocket, pdFALSE );
2428
2429                         if( pxSocket->u.xTCP.txStream == NULL )
2430                         {
2431                                 xResult = -pdFREERTOS_ERRNO_ENOMEM;
2432                         }
2433                 }
2434
2435                 return xResult;
2436         }
2437
2438 #endif /* ipconfigUSE_TCP */
2439 /*-----------------------------------------------------------*/
2440
2441 #if( ipconfigUSE_TCP == 1 )
2442
2443         /* Get a direct pointer to the circular transmit buffer.
2444         '*pxLength' will contain the number of bytes that may be written. */
2445         uint8_t *FreeRTOS_get_tx_head( Socket_t xSocket, BaseType_t *pxLength )
2446         {
2447     uint8_t *pucReturn = NULL;
2448         FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
2449         StreamBuffer_t *pxBuffer = NULL;
2450
2451         *pxLength = 0;
2452
2453         /* Confirm that this is a TCP socket before dereferencing structure
2454         member pointers. */
2455         if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdTRUE )
2456         {
2457             pxBuffer = pxSocket->u.xTCP.txStream;
2458             if( pxBuffer != NULL )
2459             {
2460             BaseType_t xSpace = ( BaseType_t )uxStreamBufferGetSpace( pxBuffer );
2461             BaseType_t xRemain = ( BaseType_t )( pxBuffer->LENGTH - pxBuffer->uxHead );
2462
2463                 *pxLength = FreeRTOS_min_BaseType( xSpace, xRemain );
2464                 pucReturn = pxBuffer->ucArray + pxBuffer->uxHead;
2465             }
2466                 }
2467
2468                 return pucReturn;
2469         }
2470 #endif /* ipconfigUSE_TCP */
2471 /*-----------------------------------------------------------*/
2472
2473 #if( ipconfigUSE_TCP == 1 )
2474         /*
2475          * Send data using a TCP socket.  It is not necessary to have the socket
2476          * connected already.  Outgoing data will be stored and delivered as soon as
2477          * the socket gets connected.
2478          */
2479         BaseType_t FreeRTOS_send( Socket_t xSocket, const void *pvBuffer, size_t uxDataLength, BaseType_t xFlags )
2480         {
2481         BaseType_t xByteCount;
2482         BaseType_t xBytesLeft;
2483         FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
2484         TickType_t xRemainingTime;
2485         BaseType_t xTimed = pdFALSE;
2486         TimeOut_t xTimeOut;
2487         BaseType_t xCloseAfterSend;
2488
2489                 /* Prevent compiler warnings about unused parameters.  The parameter
2490                 may be used in future versions. */
2491                 ( void ) xFlags;
2492
2493                 xByteCount = ( BaseType_t ) prvTCPSendCheck( pxSocket, uxDataLength );
2494
2495                 if( xByteCount > 0 )
2496                 {
2497                         /* xBytesLeft is number of bytes to send, will count to zero. */
2498                         xBytesLeft = ( BaseType_t ) uxDataLength;
2499
2500                         /* xByteCount is number of bytes that can be sent now. */
2501                         xByteCount = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream );
2502
2503                         /* While there are still bytes to be sent. */
2504                         while( xBytesLeft > 0 )
2505                         {
2506                                 /* If txStream has space. */
2507                                 if( xByteCount > 0 )
2508                                 {
2509                                         /* Don't send more than necessary. */
2510                                         if( xByteCount > xBytesLeft )
2511                                         {
2512                                                 xByteCount = xBytesLeft;
2513                                         }
2514
2515                                         /* Is the close-after-send flag set and is this really the
2516                                         last transmission? */
2517                                         if( ( pxSocket->u.xTCP.bits.bCloseAfterSend != pdFALSE_UNSIGNED ) && ( xByteCount == xBytesLeft ) )
2518                                         {
2519                                                 xCloseAfterSend = pdTRUE;
2520                                         }
2521                                         else
2522                                         {
2523                                                 xCloseAfterSend = pdFALSE;
2524                                         }
2525
2526                                         /* The flag 'bCloseAfterSend' can be set before sending data
2527                                         using setsockopt()
2528
2529                                         When the last data packet is being sent out, a FIN flag will
2530                                         be included to let the peer know that no more data is to be
2531                                         expected.  The use of 'bCloseAfterSend' is not mandatory, it
2532                                         is just a faster way of transferring files (e.g. when using
2533                                         FTP). */
2534                                         if( xCloseAfterSend != pdFALSE )
2535                                         {
2536                                                 /* Now suspend the scheduler: sending the last data     and
2537                                                 setting bCloseRequested must be done together */
2538                                                 vTaskSuspendAll();
2539                                                 pxSocket->u.xTCP.bits.bCloseRequested = pdTRUE_UNSIGNED;
2540                                         }
2541
2542                                         xByteCount = ( BaseType_t ) uxStreamBufferAdd( pxSocket->u.xTCP.txStream, 0ul, ( const uint8_t * ) pvBuffer, ( size_t ) xByteCount );
2543
2544                                         if( xCloseAfterSend != pdFALSE )
2545                                         {
2546                                                 /* Now when the IP-task transmits the data, it will also
2547                                                 see     that bCloseRequested is true and include the FIN
2548                                                 flag to start closure of the connection. */
2549                                                 xTaskResumeAll();
2550                                         }
2551
2552                                         /* Send a message to the IP-task so it can work on this
2553                                         socket.  Data is sent, let the IP-task work on it. */
2554                                         pxSocket->u.xTCP.usTimeout = 1u;
2555
2556                                         if( xIsCallingFromIPTask() == pdFALSE )
2557                                         {
2558                                                 /* Only send a TCP timer event when not called from the
2559                                                 IP-task. */
2560                                                 xSendEventToIPTask( eTCPTimerEvent );
2561                                         }
2562
2563                                         xBytesLeft -= xByteCount;
2564
2565                                         if( xBytesLeft == 0 )
2566                                         {
2567                                                 break;
2568                                         }
2569
2570                                         /* As there are still bytes left to be sent, increase the
2571                                         data pointer. */
2572                                         pvBuffer = ( void * ) ( ( ( const uint8_t * ) pvBuffer) + xByteCount );
2573                                 }
2574
2575                                 /* Not all bytes have been sent. In case the socket is marked as
2576                                 blocking sleep for a while. */
2577                                 if( xTimed == pdFALSE )
2578                                 {
2579                                         /* Only in the first round, check for non-blocking. */
2580                                         xRemainingTime = pxSocket->xSendBlockTime;
2581
2582                                         #if( ipconfigUSE_CALLBACKS != 0 )
2583                                         {
2584                                                 if( xIsCallingFromIPTask() != pdFALSE )
2585                                                 {
2586                                                         /* If this send function is called from within a
2587                                                         call-back handler it may not block, otherwise
2588                                                         chances would be big to get a deadlock: the IP-task
2589                                                         waiting for     itself. */
2590                                                         xRemainingTime = ( TickType_t ) 0;
2591                                                 }
2592                                         }
2593                                         #endif /* ipconfigUSE_CALLBACKS */
2594
2595                                         if( xRemainingTime == ( TickType_t ) 0 )
2596                                         {
2597                                                 break;
2598                                         }
2599
2600                                         if( ( xFlags & FREERTOS_MSG_DONTWAIT ) != 0 )
2601                                         {
2602                                                 break;
2603                                         }
2604
2605                                         /* Don't get here a second time. */
2606                                         xTimed = pdTRUE;
2607
2608                                         /* Fetch the current time. */
2609                                         vTaskSetTimeOutState( &xTimeOut );
2610                                 }
2611                                 else
2612                                 {
2613                                         /* Has the timeout been reached? */
2614                                         if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
2615                                         {
2616                                                 break;
2617                                         }
2618                                 }
2619
2620                                 /* Go sleeping until down-stream events are received. */
2621                                 xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_SEND | eSOCKET_CLOSED,
2622                                         pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );
2623
2624                                 xByteCount = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream );
2625                         }
2626
2627                         /* How much was actually sent? */
2628                         xByteCount = ( ( BaseType_t ) uxDataLength ) - xBytesLeft;
2629
2630                         if( xByteCount == 0 )
2631                         {
2632                                 if( pxSocket->u.xTCP.ucTCPState > eESTABLISHED )
2633                                 {
2634                                         xByteCount = ( BaseType_t ) -pdFREERTOS_ERRNO_ENOTCONN;
2635                                 }
2636                                 else
2637                                 {
2638                                         if( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE )
2639                                         {
2640                                                 FreeRTOS_debug_printf( ( "FreeRTOS_send: %u -> %lxip:%d: no space\n",
2641                                                         pxSocket->usLocalPort,
2642                                                         pxSocket->u.xTCP.ulRemoteIP,
2643                                                         pxSocket->u.xTCP.usRemotePort ) );
2644                                         }
2645
2646                                         xByteCount = ( BaseType_t ) -pdFREERTOS_ERRNO_ENOSPC;
2647                                 }
2648                         }
2649                 }
2650
2651                 return xByteCount;
2652         }
2653
2654 #endif /* ipconfigUSE_TCP */
2655 /*-----------------------------------------------------------*/
2656
2657 #if( ipconfigUSE_TCP == 1 )
2658
2659         /*
2660          * Request to put a socket in listen mode
2661          */
2662         BaseType_t FreeRTOS_listen( Socket_t xSocket, BaseType_t xBacklog )
2663         {
2664         FreeRTOS_Socket_t *pxSocket;
2665         BaseType_t xResult = 0;
2666
2667                 pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
2668
2669                 /* listen() is allowed for a valid TCP socket in Closed state and already
2670                 bound. */
2671                 if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
2672                 {
2673                         xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP;
2674                 }
2675                 else if( ( pxSocket->u.xTCP.ucTCPState != eCLOSED ) && ( pxSocket->u.xTCP.ucTCPState != eCLOSE_WAIT ) )
2676                 {
2677                         /* Socket is in a wrong state. */
2678                         xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP;
2679                 }
2680                 else
2681                 {
2682                         /* Backlog is interpreted here as "the maximum number of child
2683                         sockets. */
2684                         pxSocket->u.xTCP.usBacklog = ( uint16_t )FreeRTOS_min_int32( ( int32_t ) 0xffff, ( int32_t ) xBacklog );
2685
2686                         /* This cleaning is necessary only if a listening socket is being
2687                         reused as it might have had a previous connection. */
2688                         if( pxSocket->u.xTCP.bits.bReuseSocket )
2689                         {
2690                                 if( pxSocket->u.xTCP.rxStream != NULL )
2691                                 {
2692                                         vStreamBufferClear( pxSocket->u.xTCP.rxStream );
2693                                 }
2694
2695                                 if( pxSocket->u.xTCP.txStream != NULL )
2696                                 {
2697                                         vStreamBufferClear( pxSocket->u.xTCP.txStream );
2698                                 }
2699
2700                                 memset( pxSocket->u.xTCP.xPacket.u.ucLastPacket, '\0', sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );
2701                                 memset( &pxSocket->u.xTCP.xTCPWindow, '\0', sizeof( pxSocket->u.xTCP.xTCPWindow ) );
2702                                 memset( &pxSocket->u.xTCP.bits, '\0', sizeof( pxSocket->u.xTCP.bits ) );
2703
2704                                 /* Now set the bReuseSocket flag again, because the bits have
2705                                 just been cleared. */
2706                                 pxSocket->u.xTCP.bits.bReuseSocket = pdTRUE_UNSIGNED;
2707                         }
2708
2709                         vTCPStateChange( pxSocket, eTCP_LISTEN );
2710                 }
2711
2712                 return xResult;
2713         }
2714
2715 #endif /* ipconfigUSE_TCP */
2716 /*-----------------------------------------------------------*/
2717
2718 #if( ipconfigUSE_TCP == 1 )
2719
2720         /* shutdown - shut down part of a full-duplex connection */
2721         BaseType_t FreeRTOS_shutdown( Socket_t xSocket, BaseType_t xHow )
2722         {
2723         FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
2724         BaseType_t xResult;
2725
2726                 if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
2727                 {
2728                         /*_RB_ Is this comment correct?  The socket is not of a type that
2729                         supports the listen() operation. */
2730                         xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP;
2731                 }
2732                 else if ( pxSocket->u.xTCP.ucTCPState != eESTABLISHED )
2733                 {
2734                         /*_RB_ Is this comment correct?  The socket is not of a type that
2735                         supports the listen() operation. */
2736                         xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP;
2737                 }
2738                 else
2739                 {
2740                         pxSocket->u.xTCP.bits.bUserShutdown = pdTRUE_UNSIGNED;
2741
2742                         /* Let the IP-task perform the shutdown of the connection. */
2743                         pxSocket->u.xTCP.usTimeout = 1u;
2744                         xSendEventToIPTask( eTCPTimerEvent );
2745                         xResult = 0;
2746                 }
2747                 (void) xHow;
2748
2749                 return xResult;
2750         }
2751
2752 #endif /* ipconfigUSE_TCP */
2753 /*-----------------------------------------------------------*/
2754
2755 #if( ipconfigUSE_TCP == 1 )
2756
2757         /*
2758          * A TCP timer has expired, now check all TCP sockets for:
2759          * - Active connect
2760          * - Send a delayed ACK
2761          * - Send new data
2762          * - Send a keep-alive packet
2763          * - Check for timeout (in non-connected states only)
2764          */
2765         TickType_t xTCPTimerCheck( BaseType_t xWillSleep )
2766         {
2767         FreeRTOS_Socket_t *pxSocket;
2768         TickType_t xShortest = pdMS_TO_TICKS( ( TickType_t ) ipTCP_TIMER_PERIOD_MS );
2769         TickType_t xNow = xTaskGetTickCount();
2770         static TickType_t xLastTime = 0u;
2771         TickType_t xDelta = xNow - xLastTime;
2772         ListItem_t* pxEnd = ( ListItem_t * ) listGET_END_MARKER( &xBoundTCPSocketsList );
2773         ListItem_t *pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList );
2774
2775                 xLastTime = xNow;
2776
2777                 if( xDelta == 0u )
2778                 {
2779                         xDelta = 1u;
2780                 }
2781
2782                 while( pxIterator != pxEnd )
2783                 {
2784                         pxSocket = ( FreeRTOS_Socket_t * )listGET_LIST_ITEM_OWNER( pxIterator );
2785                         pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator );
2786
2787                         /* Sockets with 'tmout == 0' do not need any regular attention. */
2788                         if( pxSocket->u.xTCP.usTimeout == 0u )
2789                         {
2790                                 continue;
2791                         }
2792
2793                         if( xDelta < ( TickType_t ) pxSocket->u.xTCP.usTimeout )
2794                         {
2795                                 pxSocket->u.xTCP.usTimeout = ( uint16_t ) ( ( ( TickType_t ) pxSocket->u.xTCP.usTimeout ) - xDelta );
2796                         }
2797                         else
2798                         {
2799                         int rc ;
2800                                 pxSocket->u.xTCP.usTimeout = 0u;
2801                                 rc = xTCPSocketCheck( pxSocket );
2802
2803                                 /* Within this function, the socket might want to send a delayed
2804                                 ack or send out data or whatever it needs to do. */
2805                                 if( rc < 0 )
2806                                 {
2807                                         /* Continue because the socket was deleted. */
2808                                         continue;
2809                                 }
2810                         }
2811
2812                         /* In xEventBits the driver may indicate that the socket has
2813                         important events for the user.  These are only done just before the
2814                         IP-task goes to sleep. */
2815                         if( pxSocket->xEventBits != 0u )
2816                         {
2817                                 if( xWillSleep != pdFALSE )
2818                                 {
2819                                         /* The IP-task is about to go to sleep, so messages can be
2820                                         sent to the socket owners. */
2821                                         vSocketWakeUpUser( pxSocket );
2822                                 }
2823                                 else
2824                                 {
2825                                         /* Or else make sure this will be called again to wake-up
2826                                         the sockets' owner. */
2827                                         xShortest = ( TickType_t ) 0;
2828                                 }
2829                         }
2830
2831                         if( ( pxSocket->u.xTCP.usTimeout != 0u ) && ( xShortest > ( TickType_t ) pxSocket->u.xTCP.usTimeout ) )
2832                         {
2833                                 xShortest = ( TickType_t ) pxSocket->u.xTCP.usTimeout;
2834                         }
2835                 }
2836
2837                 return xShortest;
2838         }
2839
2840 #endif /* ipconfigUSE_TCP */
2841 /*-----------------------------------------------------------*/
2842
2843 #if( ipconfigUSE_TCP == 1 )
2844
2845         /*
2846          * TCP: as multiple sockets may be bound to the same local port number
2847          * looking up a socket is a little more complex:
2848          * Both a local port, and a remote port and IP address are being used
2849          * For a socket in listening mode, the remote port and IP address are both 0
2850          */
2851         FreeRTOS_Socket_t *pxTCPSocketLookup( uint32_t ulLocalIP, UBaseType_t uxLocalPort, uint32_t ulRemoteIP, UBaseType_t uxRemotePort )
2852         {
2853         ListItem_t *pxIterator;
2854         FreeRTOS_Socket_t *pxResult = NULL, *pxListenSocket = NULL;
2855         MiniListItem_t *pxEnd = ( MiniListItem_t* )listGET_END_MARKER( &xBoundTCPSocketsList );
2856
2857                 /* Parameter not yet supported. */
2858                 ( void ) ulLocalIP;
2859
2860                 for( pxIterator  = ( ListItem_t * ) listGET_NEXT( pxEnd );
2861                          pxIterator != ( ListItem_t * ) pxEnd;
2862                          pxIterator  = ( ListItem_t * ) listGET_NEXT( pxIterator ) )
2863                 {
2864                         FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
2865
2866                         if( pxSocket->usLocalPort == ( uint16_t ) uxLocalPort )
2867                         {
2868                                 if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN )
2869                                 {
2870                                         /* If this is a socket listening to uxLocalPort, remember it
2871                                         in case there is no perfect match. */
2872                                         pxListenSocket = pxSocket;
2873                                 }
2874                                 else if( ( pxSocket->u.xTCP.usRemotePort == ( uint16_t ) uxRemotePort ) && ( pxSocket->u.xTCP.ulRemoteIP == ulRemoteIP ) )
2875                                 {
2876                                         /* For sockets not in listening mode, find a match with
2877                                         xLocalPort, ulRemoteIP AND xRemotePort. */
2878                                         pxResult = pxSocket;
2879                                         break;
2880                                 }
2881                         }
2882                 }
2883                 if( pxResult == NULL )
2884                 {
2885                         /* An exact match was not found, maybe a listening socket was
2886                         found. */
2887                         pxResult = pxListenSocket;
2888                 }
2889
2890                 return pxResult;
2891         }
2892
2893 #endif /* ipconfigUSE_TCP */
2894 /*-----------------------------------------------------------*/
2895
2896 #if( ipconfigUSE_TCP == 1 )
2897
2898     const struct xSTREAM_BUFFER *FreeRTOS_get_rx_buf( Socket_t xSocket )
2899     {
2900     FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * )xSocket;
2901     struct xSTREAM_BUFFER *pxReturn = NULL;
2902
2903         /* Confirm that this is a TCP socket before dereferencing structure
2904         member pointers. */
2905         if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdTRUE )
2906         {
2907             pxReturn = pxSocket->u.xTCP.rxStream;
2908         }
2909
2910         return pxReturn;
2911     }
2912
2913 #endif /* ipconfigUSE_TCP */
2914 /*-----------------------------------------------------------*/
2915
2916 #if( ipconfigUSE_TCP == 1 )
2917
2918         static StreamBuffer_t *prvTCPCreateStream ( FreeRTOS_Socket_t *pxSocket, BaseType_t xIsInputStream )
2919         {
2920         StreamBuffer_t *pxBuffer;
2921         size_t uxLength;
2922         size_t uxSize;
2923
2924                 /* Now that a stream is created, the maximum size is fixed before
2925                 creation, it could still be changed with setsockopt(). */
2926                 if( xIsInputStream != pdFALSE )
2927                 {
2928                         uxLength = pxSocket->u.xTCP.uxRxStreamSize;
2929
2930                         if( pxSocket->u.xTCP.uxLittleSpace == 0ul )
2931                         {
2932                                 pxSocket->u.xTCP.uxLittleSpace  = ( sock20_PERCENT * pxSocket->u.xTCP.uxRxStreamSize ) / sock100_PERCENT;
2933                         }
2934
2935                         if( pxSocket->u.xTCP.uxEnoughSpace == 0ul )
2936                         {
2937                                 pxSocket->u.xTCP.uxEnoughSpace = ( sock80_PERCENT * pxSocket->u.xTCP.uxRxStreamSize ) / sock100_PERCENT;
2938                         }
2939                 }
2940                 else
2941                 {
2942                         uxLength = pxSocket->u.xTCP.uxTxStreamSize;
2943                 }
2944
2945                 /* Add an extra 4 (or 8) bytes. */
2946                 uxLength += sizeof( size_t );
2947
2948                 /* And make the length a multiple of sizeof( size_t ). */
2949                 uxLength &= ~( sizeof( size_t ) - 1u );
2950
2951                 uxSize = sizeof( *pxBuffer ) - sizeof( pxBuffer->ucArray ) + uxLength;
2952
2953                 pxBuffer = ( StreamBuffer_t * )pvPortMallocLarge( uxSize );
2954
2955                 if( pxBuffer == NULL )
2956                 {
2957                         FreeRTOS_debug_printf( ( "prvTCPCreateStream: malloc failed\n" ) );
2958                         pxSocket->u.xTCP.bits.bMallocError = pdTRUE_UNSIGNED;
2959                         vTCPStateChange( pxSocket, eCLOSE_WAIT );
2960                 }
2961                 else
2962                 {
2963                         /* Clear the markers of the stream */
2964                         memset( pxBuffer, '\0', sizeof( *pxBuffer ) - sizeof( pxBuffer->ucArray ) );
2965                         pxBuffer->LENGTH = ( size_t ) uxLength ;
2966
2967                         if( xTCPWindowLoggingLevel != 0 )
2968                         {
2969                                 FreeRTOS_debug_printf( ( "prvTCPCreateStream: %cxStream created %lu bytes (total %lu)\n", xIsInputStream ? 'R' : 'T', uxLength, uxSize ) );
2970                         }
2971
2972                         if( xIsInputStream != 0 )
2973                         {
2974                                 pxSocket->u.xTCP.rxStream = pxBuffer;
2975                         }
2976                         else
2977                         {
2978                                 pxSocket->u.xTCP.txStream = pxBuffer;
2979                         }
2980                 }
2981
2982                 return pxBuffer;
2983         }
2984
2985 #endif /* ipconfigUSE_TCP */
2986 /*-----------------------------------------------------------*/
2987
2988 #if( ipconfigUSE_TCP == 1 )
2989
2990         /*
2991          * Add data to the RxStream.  When uxOffset > 0, data has come in out-of-order
2992          * and will be put in front of the head so it can not be popped by the user.
2993          */
2994         int32_t lTCPAddRxdata( FreeRTOS_Socket_t *pxSocket, size_t uxOffset, const uint8_t *pcData, uint32_t ulByteCount )
2995         {
2996         StreamBuffer_t *pxStream = pxSocket->u.xTCP.rxStream;
2997         int32_t xResult;
2998         #if( ipconfigUSE_CALLBACKS == 1 )
2999                 BaseType_t bHasHandler = ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleReceive );
3000                 const uint8_t *pucBuffer = NULL;
3001         #endif /* ipconfigUSE_CALLBACKS */
3002
3003                 /* int32_t uxStreamBufferAdd( pxBuffer, uxOffset, pucData, aCount )
3004                 if( pucData != NULL ) copy data the the buffer
3005                 if( pucData == NULL ) no copying, just advance rxHead
3006                 if( uxOffset != 0 ) Just store data which has come out-of-order
3007                 if( uxOffset == 0 ) Also advance rxHead */
3008                 if( pxStream == NULL )
3009                 {
3010                         pxStream = prvTCPCreateStream( pxSocket, pdTRUE );
3011                         if( pxStream == NULL )
3012                         {
3013                                 return -1;
3014                         }
3015                 }
3016
3017                 #if( ipconfigUSE_CALLBACKS == 1 )
3018                 {
3019                         if( ( bHasHandler != pdFALSE ) && ( uxStreamBufferGetSize( pxStream ) == 0u ) && ( uxOffset == 0ul ) && ( pcData != NULL ) )
3020                         {
3021                                 /* Data can be passed directly to the user */
3022                                 pucBuffer = pcData;
3023
3024                                 /* Zero-copy for call-back: no need to add the bytes to the
3025                                 stream, only the pointer will be advanced by uxStreamBufferAdd(). */
3026                                 pcData = NULL;
3027                         }
3028                 }
3029                 #endif /* ipconfigUSE_CALLBACKS */
3030
3031                 xResult = ( int32_t ) uxStreamBufferAdd( pxStream, uxOffset, pcData, ( size_t ) ulByteCount );
3032
3033                 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
3034                 {
3035                         if( xResult != ( int32_t ) ulByteCount )
3036                         {
3037                                 FreeRTOS_debug_printf( ( "lTCPAddRxdata: at %ld: %ld/%lu bytes (tail %lu head %lu space %lu front %lu)\n",
3038                                         uxOffset, xResult, ulByteCount,
3039                                         pxStream->uxTail,
3040                                         pxStream->uxHead,
3041                                         uxStreamBufferFrontSpace( pxStream ),
3042                                         pxStream->uxFront ) );
3043                         }
3044                 }
3045                 #endif /* ipconfigHAS_DEBUG_PRINTF */
3046
3047                 if( uxOffset == 0u )
3048                 {
3049                         /* Data is being added to rxStream at the head (offs = 0) */
3050                         #if( ipconfigUSE_CALLBACKS == 1 )
3051                                 if( bHasHandler != pdFALSE )
3052                                 {
3053                                         /* The socket owner has installed an OnReceive handler. Pass the
3054                                         Rx data, without copying from the rxStream, to the user. */
3055                                         for (;;)
3056                                         {
3057                                                 uint8_t *ucReadPtr = NULL;
3058                                                 uint32_t ulCount;
3059                                                 if( pucBuffer != NULL )
3060                                                 {
3061                                                         ucReadPtr = ( uint8_t * )pucBuffer;
3062                                                         ulCount = ulByteCount;
3063                                                         pucBuffer = NULL;
3064                                                 }
3065                                                 else
3066                                                 {
3067                                                         ulCount = ( uint32_t ) uxStreamBufferGetPtr( pxStream, &( ucReadPtr ) );
3068                                                 }
3069
3070                                                 if( ulCount == 0ul )
3071                                                 {
3072                                                         break;
3073                                                 }
3074
3075                                                 pxSocket->u.xTCP.pxHandleReceive( ( Socket_t )pxSocket, ( void* )ucReadPtr, ( size_t ) ulCount );
3076                                                 uxStreamBufferGet( pxStream, 0ul, NULL, ( size_t ) ulCount, pdFALSE );
3077                                         }
3078                                 } else
3079                         #endif /* ipconfigUSE_CALLBACKS */
3080                         {
3081                                 /* See if running out of space. */
3082                                 if( pxSocket->u.xTCP.bits.bLowWater == pdFALSE_UNSIGNED )
3083                                 {
3084                                         size_t uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
3085                                         if( uxFrontSpace <= pxSocket->u.xTCP.uxLittleSpace  )
3086                                         {
3087                                                 pxSocket->u.xTCP.bits.bLowWater = pdTRUE_UNSIGNED;
3088                                                 pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
3089
3090                                                 /* bLowWater was reached, send the changed window size. */
3091                                                 pxSocket->u.xTCP.usTimeout = 1u;
3092                                                 xSendEventToIPTask( eTCPTimerEvent );
3093                                         }
3094                                 }
3095
3096                                 /* New incoming data is available, wake up the user.   User's
3097                                 semaphores will be set just before the IP-task goes asleep. */
3098                                 pxSocket->xEventBits |= eSOCKET_RECEIVE;
3099
3100                                 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
3101                                 {
3102                                         if( ( pxSocket->xSelectBits & eSELECT_READ ) != 0 )
3103                                         {
3104                                                 pxSocket->xEventBits |= ( eSELECT_READ << SOCKET_EVENT_BIT_COUNT );
3105                                         }
3106                                 }
3107                                 #endif
3108                         }
3109                 }
3110
3111                 return xResult;
3112         }
3113
3114 #endif /* ipconfigUSE_TCP */
3115 /*-----------------------------------------------------------*/
3116
3117 #if( ipconfigUSE_TCP == 1 )
3118
3119         /* Function to get the remote address and IP port */
3120         BaseType_t FreeRTOS_GetRemoteAddress( Socket_t xSocket, struct freertos_sockaddr *pxAddress )
3121         {
3122         FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
3123         BaseType_t xResult;
3124
3125                 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
3126                 {
3127                         xResult = -pdFREERTOS_ERRNO_EINVAL;
3128                 }
3129                 else
3130                 {
3131                         /* BSD style sockets communicate IP and port addresses in network
3132                         byte order.
3133
3134                         IP address of remote machine. */
3135                         pxAddress->sin_addr = FreeRTOS_htonl ( pxSocket->u.xTCP.ulRemoteIP );
3136
3137                         /* Port on remote machine. */
3138                         pxAddress->sin_port = FreeRTOS_htons ( pxSocket->u.xTCP.usRemotePort );
3139
3140                         xResult = ( BaseType_t ) sizeof( ( *pxAddress ) );
3141                 }
3142
3143                 return xResult;
3144         }
3145
3146 #endif /* ipconfigUSE_TCP */
3147
3148 /*-----------------------------------------------------------*/
3149
3150 #if( ipconfigUSE_TCP == 1 )
3151
3152         /* Returns the number of bytes that may be added to txStream */
3153         BaseType_t FreeRTOS_maywrite( Socket_t xSocket )
3154         {
3155         FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
3156         BaseType_t xResult;
3157
3158                 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
3159                 {
3160                         xResult = -pdFREERTOS_ERRNO_EINVAL;
3161                 }
3162                 else if( pxSocket->u.xTCP.ucTCPState != eESTABLISHED )
3163                 {
3164                         if( ( pxSocket->u.xTCP.ucTCPState < eCONNECT_SYN ) || ( pxSocket->u.xTCP.ucTCPState > eESTABLISHED ) )
3165                         {
3166                                 xResult = -1;
3167                         }
3168                         else
3169                         {
3170                                 xResult = 0;
3171                         }
3172                 }
3173                 else if( pxSocket->u.xTCP.txStream == NULL )
3174                 {
3175                         xResult = ( BaseType_t ) pxSocket->u.xTCP.uxTxStreamSize;
3176                 }
3177                 else
3178                 {
3179                         xResult = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream );
3180                 }
3181
3182                 return xResult;
3183         }
3184
3185 #endif /* ipconfigUSE_TCP */
3186 /*-----------------------------------------------------------*/
3187
3188 #if( ipconfigUSE_TCP ==1 )
3189
3190         BaseType_t FreeRTOS_tx_space( Socket_t xSocket )
3191         {
3192         FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
3193         BaseType_t xReturn;
3194
3195                 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
3196                 {
3197                         xReturn = -pdFREERTOS_ERRNO_EINVAL;
3198                 }
3199                 else
3200                 {
3201                         if( pxSocket->u.xTCP.txStream != NULL )
3202                         {
3203                                 xReturn = ( BaseType_t ) uxStreamBufferGetSpace ( pxSocket->u.xTCP.txStream );
3204                         }
3205                         else
3206                         {
3207                                 xReturn = ( BaseType_t ) pxSocket->u.xTCP.uxTxStreamSize;
3208                         }
3209                 }
3210
3211                 return xReturn;
3212         }
3213
3214 #endif /* ipconfigUSE_TCP */
3215 /*-----------------------------------------------------------*/
3216
3217 #if( ipconfigUSE_TCP == 1 )
3218
3219         BaseType_t FreeRTOS_tx_size( Socket_t xSocket )
3220         {
3221         FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
3222         BaseType_t xReturn;
3223
3224                 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
3225                 {
3226                         xReturn = -pdFREERTOS_ERRNO_EINVAL;
3227                 }
3228                 else
3229                 {
3230                         if( pxSocket->u.xTCP.txStream != NULL )
3231                         {
3232                                 xReturn = ( BaseType_t ) uxStreamBufferGetSize ( pxSocket->u.xTCP.txStream );
3233                         }
3234                         else
3235                         {
3236                                 xReturn = 0;
3237                         }
3238                 }
3239
3240                 return xReturn;
3241         }
3242
3243 #endif /* ipconfigUSE_TCP */
3244 /*-----------------------------------------------------------*/
3245
3246 #if( ipconfigUSE_TCP == 1 )
3247
3248         /* Returns pdTRUE if TCP socket is connected. */
3249         BaseType_t FreeRTOS_issocketconnected( Socket_t xSocket )
3250         {
3251         FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
3252         BaseType_t xReturn = pdFALSE;
3253
3254                 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
3255                 {
3256                         xReturn = -pdFREERTOS_ERRNO_EINVAL;
3257                 }
3258                 else
3259                 {
3260                         if( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED )
3261                         {
3262                                 if( pxSocket->u.xTCP.ucTCPState < eCLOSE_WAIT )
3263                                 {
3264                                         xReturn = pdTRUE;
3265                                 }
3266                         }
3267                 }
3268
3269                 return xReturn;
3270         }
3271
3272 #endif /* ipconfigUSE_TCP */
3273 /*-----------------------------------------------------------*/
3274
3275 #if( ipconfigUSE_TCP == 1 )
3276
3277         /* returns the actual size of MSS being used */
3278         BaseType_t FreeRTOS_mss( Socket_t xSocket )
3279         {
3280         FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
3281         BaseType_t xReturn;
3282
3283                 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
3284                 {
3285                         xReturn = -pdFREERTOS_ERRNO_EINVAL;
3286                 }
3287                 else
3288                 {
3289                         /* usCurMSS is declared as uint16_t to save space.  FreeRTOS_mss()
3290                         will often be used in signed native-size expressions cast it to
3291                         BaseType_t. */
3292                         xReturn = ( BaseType_t ) ( pxSocket->u.xTCP.usCurMSS );
3293                 }
3294
3295                 return xReturn;
3296         }
3297
3298 #endif /* ipconfigUSE_TCP */
3299 /*-----------------------------------------------------------*/
3300
3301 #if( ipconfigUSE_TCP == 1 )
3302
3303         /* HT: for internal use only: return the connection status */
3304         BaseType_t FreeRTOS_connstatus( Socket_t xSocket )
3305         {
3306         FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
3307         BaseType_t xReturn;
3308
3309                 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
3310                 {
3311                         xReturn = -pdFREERTOS_ERRNO_EINVAL;
3312                 }
3313                 else
3314                 {
3315                         /* Cast it to BaseType_t */
3316                         xReturn = ( BaseType_t ) ( pxSocket->u.xTCP.ucTCPState );
3317                 }
3318
3319                 return xReturn;
3320         }
3321
3322 #endif /* ipconfigUSE_TCP */
3323 /*-----------------------------------------------------------*/
3324
3325 #if( ipconfigUSE_TCP == 1 )
3326
3327         /*
3328          * Returns the number of bytes which can be read.
3329          */
3330         BaseType_t FreeRTOS_rx_size( Socket_t xSocket )
3331         {
3332         FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
3333         BaseType_t xReturn;
3334
3335                 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
3336                 {
3337                         xReturn = -pdFREERTOS_ERRNO_EINVAL;
3338                 }
3339                 else if( pxSocket->u.xTCP.rxStream != NULL )
3340                 {
3341                         xReturn = ( BaseType_t ) uxStreamBufferGetSize( pxSocket->u.xTCP.rxStream );
3342                 }
3343                 else
3344                 {
3345                         xReturn = 0;
3346                 }
3347
3348                 return xReturn;
3349         }
3350
3351 #endif /* ipconfigUSE_TCP */
3352 /*-----------------------------------------------------------*/
3353
3354 #if( ipconfigUSE_TCP == 1 )
3355
3356         void FreeRTOS_netstat( void )
3357         {
3358         IPStackEvent_t xAskEvent;
3359
3360                 /* Ask the IP-task to call vTCPNetStat()
3361                  * to avoid accessing xBoundTCPSocketsList
3362                  */
3363                 xAskEvent.eEventType = eTCPNetStat;
3364                 xAskEvent.pvData = ( void * ) NULL;
3365                 xSendEventStructToIPTask( &xAskEvent, 1000u );
3366         }
3367
3368 #endif /* ipconfigUSE_TCP */
3369 /*-----------------------------------------------------------*/
3370
3371 #if( ( ipconfigHAS_PRINTF != 0 ) && ( ipconfigUSE_TCP == 1 ) )
3372
3373         void vTCPNetStat( void )
3374         {
3375         /* Show a simple listing of all created sockets and their connections */
3376         ListItem_t *pxIterator;
3377         BaseType_t count = 0;
3378
3379                 if( listLIST_IS_INITIALISED( &xBoundTCPSocketsList ) == pdFALSE )
3380                 {
3381                         FreeRTOS_printf( ( "PLUS-TCP not initialized\n" ) );
3382                 }
3383                 else
3384                 {
3385                         FreeRTOS_printf( ( "Prot Port IP-Remote    : Port  R/T Status      Alive  tmout Child\n" ) );
3386                         for( pxIterator  = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList );
3387                                  pxIterator != ( ListItem_t * ) listGET_END_MARKER( &xBoundTCPSocketsList );
3388                                  pxIterator  = ( ListItem_t * ) listGET_NEXT( pxIterator ) )
3389                         {
3390                                 FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
3391                                 #if( ipconfigTCP_KEEP_ALIVE == 1 )
3392                                         TickType_t age = xTaskGetTickCount() - pxSocket->u.xTCP.xLastAliveTime;
3393                                 #else
3394                                         TickType_t age = 0u;
3395                                 #endif
3396                                 #if( ipconfigUSE_CALLBACKS == 1 )
3397                                         void *pxHandleReceive = (void*)pxSocket->u.xTCP.pxHandleReceive;
3398                                 #else
3399                                         void *pxHandleReceive = (void*)NULL;
3400                                 #endif
3401                                 char ucChildText[16] = "";
3402                                 if (pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN)
3403                                 {
3404                                         const int32_t copied_len = snprintf( ucChildText, sizeof( ucChildText ), " %d/%d",
3405                                                 ( int ) pxSocket->u.xTCP.usChildCount,
3406                                                 ( int ) pxSocket->u.xTCP.usBacklog);
3407                                         /* These should never evaluate to false since the buffers are both shorter than 5-6 characters (<=65535) */
3408                                         configASSERT( copied_len >= 0 );
3409                                         configASSERT( copied_len < sizeof( ucChildText ) );
3410                                 }
3411                                 FreeRTOS_printf( ( "TCP %5d %-16lxip:%5d %d/%d %-13.13s %6lu %6u%s\n",
3412                                         pxSocket->usLocalPort,          /* Local port on this machine */
3413                                         pxSocket->u.xTCP.ulRemoteIP,    /* IP address of remote machine */
3414                                         pxSocket->u.xTCP.usRemotePort,  /* Port on remote machine */
3415                                         pxSocket->u.xTCP.rxStream != NULL,
3416                                         pxSocket->u.xTCP.txStream != NULL,
3417                                         FreeRTOS_GetTCPStateName( pxSocket->u.xTCP.ucTCPState ),
3418                                         (age > 999999 ? 999999 : age), /* Format 'age' for printing */
3419                                         pxSocket->u.xTCP.usTimeout,
3420                                         ucChildText ) );
3421                                         /* Remove compiler warnings if FreeRTOS_debug_printf() is not defined. */
3422                                         ( void ) pxHandleReceive;
3423                                 count++;
3424                         }
3425
3426                         for( pxIterator  = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundUDPSocketsList );
3427                                  pxIterator != ( ListItem_t * ) listGET_END_MARKER( &xBoundUDPSocketsList );
3428                                  pxIterator  = ( ListItem_t * ) listGET_NEXT( pxIterator ) )
3429                         {
3430                                 /* Local port on this machine */
3431                                 FreeRTOS_printf( ( "UDP Port %5u\n",
3432                                         FreeRTOS_ntohs( listGET_LIST_ITEM_VALUE( pxIterator ) ) ) );
3433                                 count++;
3434                         }
3435
3436                         FreeRTOS_printf( ( "FreeRTOS_netstat: %lu sockets %lu < %lu < %d buffers free\n",
3437                                 count,
3438                                 uxGetMinimumFreeNetworkBuffers( ),
3439                                 uxGetNumberOfFreeNetworkBuffers( ),
3440                                 ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) );
3441                 }
3442         }
3443
3444 #endif /* ( ( ipconfigHAS_PRINTF != 0 ) && ( ipconfigUSE_TCP == 1 ) ) */
3445 /*-----------------------------------------------------------*/
3446
3447 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
3448
3449         void vSocketSelect( SocketSelect_t *pxSocketSet )
3450         {
3451         BaseType_t xRound;
3452         EventBits_t xSocketBits, xBitsToClear;
3453         #if ipconfigUSE_TCP == 1
3454                 BaseType_t xLastRound = 1;
3455         #else
3456                 BaseType_t xLastRound = 0;
3457         #endif
3458
3459                 /* These flags will be switched on after checking the socket status. */
3460                 EventBits_t xGroupBits = 0;
3461                 pxSocketSet->pxSocket = NULL;
3462
3463                 for( xRound = 0; xRound <= xLastRound; xRound++ )
3464                 {
3465                         const ListItem_t *pxIterator;
3466                         const MiniListItem_t *pxEnd;
3467                         if( xRound == 0 )
3468                         {
3469                                 pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xBoundUDPSocketsList );
3470                         }
3471                 #if ipconfigUSE_TCP == 1
3472                         else
3473                         {
3474                                 pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xBoundTCPSocketsList );
3475                         }
3476                 #endif /* ipconfigUSE_TCP == 1 */
3477                         for( pxIterator = ( const ListItem_t * ) ( listGET_NEXT( pxEnd ) );
3478                                  pxIterator != ( const ListItem_t * ) pxEnd;
3479                                  pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) )
3480                         {
3481                                 FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator );
3482                                 if( pxSocket->pxSocketSet != pxSocketSet )
3483                                 {
3484                                         /* Socket does not belong to this select group. */
3485                                         continue;
3486                                 }
3487                                 xSocketBits = 0;
3488
3489                                 #if( ipconfigUSE_TCP == 1 )
3490                                         if( pxSocket->ucProtocol == FREERTOS_IPPROTO_TCP )
3491                                         {
3492                                                 /* Check if the socket has already been accepted by the
3493                                                 owner.  If not, it is useless to return it from a
3494                                                 select(). */
3495                                                 BaseType_t bAccepted = pdFALSE;
3496
3497                                                 if( pxSocket->u.xTCP.bits.bPassQueued == pdFALSE_UNSIGNED )
3498                                                 {
3499                                                         if( pxSocket->u.xTCP.bits.bPassAccept == pdFALSE_UNSIGNED )
3500                                                         {
3501                                                                 bAccepted = pdTRUE;
3502                                                         }
3503                                                 }
3504
3505                                                 /* Is the set owner interested in READ events? */
3506                                                 if( ( pxSocket->xSelectBits & eSELECT_READ ) != 0 )
3507                                                 {
3508                                                         if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN )
3509                                                         {
3510                                                                 if( ( pxSocket->u.xTCP.pxPeerSocket != NULL ) && ( pxSocket->u.xTCP.pxPeerSocket->u.xTCP.bits.bPassAccept != 0 ) )
3511                                                                 {
3512                                                                         xSocketBits |= eSELECT_READ;
3513                                                                 }
3514                                                         }
3515                                                         else if( ( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED ) && ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
3516                                                         {
3517                                                                 /* This socket has the re-use flag. After connecting it turns into
3518                                                                 aconnected socket. Set the READ event, so that accept() will be called. */
3519                                                                 xSocketBits |= eSELECT_READ;
3520                                                         }
3521                                                         else if( ( bAccepted != 0 ) && ( FreeRTOS_recvcount( pxSocket ) > 0 ) )
3522                                                         {
3523                                                                 xSocketBits |= eSELECT_READ;
3524                                                         }
3525                                                 }
3526                                                 /* Is the set owner interested in EXCEPTION events? */
3527                                                 if( ( pxSocket->xSelectBits & eSELECT_EXCEPT ) != 0 )
3528                                                 {
3529                                                         if( ( pxSocket->u.xTCP.ucTCPState == eCLOSE_WAIT ) || ( pxSocket->u.xTCP.ucTCPState == eCLOSED ) )
3530                                                         {
3531                                                                 xSocketBits |= eSELECT_EXCEPT;
3532                                                         }
3533                                                 }
3534
3535                                                 /* Is the set owner interested in WRITE events? */
3536                                                 if( ( pxSocket->xSelectBits & eSELECT_WRITE ) != 0 )
3537                                                 {
3538                                                         BaseType_t bMatch = pdFALSE;
3539
3540                                                         if( bAccepted != 0 )
3541                                                         {
3542                                                                 if( FreeRTOS_tx_space( pxSocket ) > 0 )
3543                                                                 {
3544                                                                         bMatch = pdTRUE;
3545                                                                 }
3546                                                         }
3547
3548                                                         if( bMatch == pdFALSE )
3549                                                         {
3550                                                                 if( ( pxSocket->u.xTCP.bits.bConnPrepared != pdFALSE_UNSIGNED ) &&
3551                                                                         ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) &&
3552                                                                         ( pxSocket->u.xTCP.bits.bConnPassed == pdFALSE_UNSIGNED ) )
3553                                                                 {
3554                                                                         pxSocket->u.xTCP.bits.bConnPassed = pdTRUE_UNSIGNED;
3555                                                                         bMatch = pdTRUE;
3556                                                                 }
3557                                                         }
3558
3559                                                         if( bMatch != pdFALSE )
3560                                                         {
3561                                                                 xSocketBits |= eSELECT_WRITE;
3562                                                         }
3563                                                 }
3564                                         }
3565                                         else
3566                                 #endif /* ipconfigUSE_TCP == 1 */
3567                                 {
3568                                         /* Select events for UDP are simpler. */
3569                                         if( ( ( pxSocket->xSelectBits & eSELECT_READ ) != 0 ) &&
3570                                                 ( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) > 0U ) )
3571                                         {
3572                                                 xSocketBits |= eSELECT_READ;
3573                                         }
3574                                         /* The WRITE and EXCEPT bits are not used for UDP */
3575                                 }       /* if( pxSocket->ucProtocol == FREERTOS_IPPROTO_TCP ) */
3576
3577                                 /* Each socket keeps its own event flags, which are looked-up
3578                                 by FreeRTOS_FD_ISSSET() */
3579                                 pxSocket->xSocketBits = xSocketBits;
3580
3581                                 /* The ORed value will be used to set the bits in the event
3582                                 group. */
3583                                 xGroupBits |= xSocketBits;
3584
3585                         }       /* for( pxIterator ... ) */
3586                 }       /* for( xRound = 0; xRound <= xLastRound; xRound++ ) */
3587
3588                 xBitsToClear = xEventGroupGetBits( pxSocketSet->xSelectGroup );
3589
3590                 /* Now set the necessary bits. */
3591                 xBitsToClear = ( xBitsToClear & ~xGroupBits ) & eSELECT_ALL;
3592
3593                 #if( ipconfigSUPPORT_SIGNALS != 0 )
3594                 {
3595                         /* Maybe the socketset was signalled, but don't
3596                         clear the 'eSELECT_INTR' bit here, as it will be used
3597                         and cleared in FreeRTOS_select(). */
3598                         xBitsToClear &= ( EventBits_t ) ~eSELECT_INTR;
3599                 }
3600                 #endif /* ipconfigSUPPORT_SIGNALS */
3601
3602                 if( xBitsToClear != 0 )
3603                 {
3604                         xEventGroupClearBits( pxSocketSet->xSelectGroup, xBitsToClear );
3605                 }
3606
3607                 /* Now include eSELECT_CALL_IP to wakeup the caller. */
3608                 xEventGroupSetBits( pxSocketSet->xSelectGroup, xGroupBits | eSELECT_CALL_IP );
3609         }
3610
3611 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
3612 /*-----------------------------------------------------------*/
3613
3614 #if( ipconfigSUPPORT_SIGNALS != 0 )
3615
3616         /* Send a signal to the task which reads from this socket. */
3617         BaseType_t FreeRTOS_SignalSocket( Socket_t xSocket )
3618         {
3619         FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
3620         BaseType_t xReturn;
3621
3622                 if( pxSocket == NULL )
3623                 {
3624                         xReturn = -pdFREERTOS_ERRNO_EINVAL;
3625                 }
3626                 else
3627         #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
3628                 if( ( pxSocket->pxSocketSet != NULL ) && ( pxSocket->pxSocketSet->xSelectGroup != NULL ) )
3629                 {
3630                         xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, eSELECT_INTR );
3631                         xReturn = 0;
3632                 }
3633                 else
3634         #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
3635                 if( pxSocket->xEventGroup != NULL )
3636                 {
3637                         xEventGroupSetBits( pxSocket->xEventGroup, eSOCKET_INTR );
3638                         xReturn = 0;
3639                 }
3640                 else
3641                 {
3642                         xReturn = -pdFREERTOS_ERRNO_EINVAL;
3643                 }
3644
3645                 return xReturn;
3646         }
3647
3648 #endif /* ipconfigSUPPORT_SIGNALS */
3649 /*-----------------------------------------------------------*/
3650
3651 #if( ipconfigSUPPORT_SIGNALS != 0 )
3652
3653         /* Send a signal to the task which reads from this socket (FromISR version). */
3654         BaseType_t FreeRTOS_SignalSocketFromISR( Socket_t xSocket, BaseType_t *pxHigherPriorityTaskWoken )
3655         {
3656         FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
3657         BaseType_t xReturn;
3658         IPStackEvent_t xEvent;
3659         extern QueueHandle_t xNetworkEventQueue;
3660
3661                 configASSERT( pxSocket != NULL );
3662                 configASSERT( pxSocket->ucProtocol == FREERTOS_IPPROTO_TCP );
3663                 configASSERT( pxSocket->xEventGroup );
3664
3665                 xEvent.eEventType = eSocketSignalEvent;
3666                 xEvent.pvData = ( void * )pxSocket;
3667
3668                 /* The IP-task will call FreeRTOS_SignalSocket for this socket. */
3669                 xReturn = xQueueSendToBackFromISR( xNetworkEventQueue, &xEvent, pxHigherPriorityTaskWoken );
3670
3671                 return xReturn;
3672         }
3673
3674 #endif /* ipconfigSUPPORT_SIGNALS */
3675 /*-----------------------------------------------------------*/