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