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