1 /*
2 * FreeRTOS+TCP V3.1.0
3 * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 *
5 * SPDX-License-Identifier: MIT
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy of
8 * this software and associated documentation files (the "Software"), to deal in
9 * the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 * the Software, and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * http://aws.amazon.com/freertos
25 * http://www.FreeRTOS.org
26 */
27
28 /**
29 * @file FreeRTOS_Sockets.c
30 * @brief Implements the Sockets API based on Berkeley sockets for the FreeRTOS+TCP network stack.
31 * Sockets are used by the application processes to interact with the IP-task which in turn
32 * interacts with the hardware.
33 */
34
35 /* Standard includes. */
36 #include <stdint.h>
37 #include <stdio.h>
38
39 /* FreeRTOS includes. */
40 #include "FreeRTOS.h"
41 #include "task.h"
42 #include "queue.h"
43 #include "semphr.h"
44
45 /* FreeRTOS+TCP includes. */
46 #include "FreeRTOS_UDP_IP.h"
47 #include "FreeRTOS_IP.h"
48 #include "FreeRTOS_Sockets.h"
49 #include "FreeRTOS_IP_Private.h"
50 #include "FreeRTOS_DNS.h"
51 #include "NetworkBufferManagement.h"
52
53 /* The ItemValue of the sockets xBoundSocketListItem member holds the socket's
54 * port number. */
55 /** @brief Set the port number for the socket in the xBoundSocketListItem. */
56 #define socketSET_SOCKET_PORT( pxSocket, usPort ) listSET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ), ( usPort ) )
57 /** @brief Get the port number for the socket in the xBoundSocketListItem. */
58 #define socketGET_SOCKET_PORT( pxSocket ) listGET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ) )
59
60 /** @brief Test if a socket it bound which means it is either included in
61 * xBoundUDPSocketsList or xBoundTCPSocketsList
62 */
63 #define socketSOCKET_IS_BOUND( pxSocket ) ( listLIST_ITEM_CONTAINER( &( pxSocket )->xBoundSocketListItem ) != NULL )
64
65 /** @brief If FreeRTOS_sendto() is called on a socket that is not bound to a port
66 * number then, depending on the FreeRTOSIPConfig.h settings, it might be
67 * that a port number is automatically generated for the socket.
68 * Automatically generated port numbers will be between
69 * socketAUTO_PORT_ALLOCATION_START_NUMBER and 0xffff.
70 *
71 * @note Per https://tools.ietf.org/html/rfc6056, "the dynamic ports consist of
72 * the range 49152-65535. However, ephemeral port selection algorithms should
73 * use the whole range 1024-65535" excluding those already in use (inbound
74 * or outbound).
75 */
76 #if !defined( socketAUTO_PORT_ALLOCATION_START_NUMBER )
77 #define socketAUTO_PORT_ALLOCATION_START_NUMBER ( ( uint16_t ) 0x0400 )
78 #endif
79
80 /** @brief Maximum value of port number which can be auto assigned. */
81 #define socketAUTO_PORT_ALLOCATION_MAX_NUMBER ( ( uint16_t ) 0xffff )
82
83 /** @brief The number of octets that make up an IP address. */
84 #define socketMAX_IP_ADDRESS_OCTETS 4U
85
86 /** @brief A block time of 0 simply means "don't block". */
87 #define socketDONT_BLOCK ( ( TickType_t ) 0 )
88
89 /** @brief TCP timer period in milliseconds. */
90 #if ( ( ipconfigUSE_TCP == 1 ) && !defined( ipTCP_TIMER_PERIOD_MS ) )
91 #define ipTCP_TIMER_PERIOD_MS ( 1000U )
92 #endif
93
94 /* Some helper macro's for defining the 20/80 % limits of uxLittleSpace / uxEnoughSpace. */
95 #define sock20_PERCENT 20U /**< 20% of the defined limit. */
96 #define sock80_PERCENT 80U /**< 80% of the defined limit. */
97 #define sock100_PERCENT 100U /**< 100% of the defined limit. */
98
99 /** @brief When ucASCIIToHex() can not convert a character,
100 * the value 255 will be returned.
101 */
102 #define socketINVALID_HEX_CHAR 0xffU
103
104 /*
105 * Allocate the next port number from the private allocation range.
106 * TCP and UDP each have their own series of port numbers
107 * ulProtocol is either ipPROTOCOL_UDP or ipPROTOCOL_TCP
108 */
109 static uint16_t prvGetPrivatePortNumber( BaseType_t xProtocol );
110
111 /*
112 * Return the list item from within pxList that has an item value of
113 * xWantedItemValue. If there is no such list item return NULL.
114 */
115 static const ListItem_t * pxListFindListItemWithValue( const List_t * pxList,
116 TickType_t xWantedItemValue );
117
118 /*
119 * Return pdTRUE only if pxSocket is valid and bound, as far as can be
120 * determined.
121 */
122 static BaseType_t prvValidSocket( const FreeRTOS_Socket_t * pxSocket,
123 BaseType_t xProtocol,
124 BaseType_t xIsBound );
125
126 #if ( ipconfigUSE_TCP == 1 )
127
128 /*
129 * Internal function prvSockopt_so_buffer(): sets FREERTOS_SO_SNDBUF or
130 * FREERTOS_SO_RCVBUF properties of a socket.
131 */
132 static BaseType_t prvSockopt_so_buffer( FreeRTOS_Socket_t * pxSocket,
133 int32_t lOptionName,
134 const void * pvOptionValue );
135 #endif /* ipconfigUSE_TCP == 1 */
136
137 /*
138 * Before creating a socket, check the validity of the parameters used
139 * and find the size of the socket space, which is different for UDP and TCP
140 */
141 static BaseType_t prvDetermineSocketSize( BaseType_t xDomain,
142 BaseType_t xType,
143 BaseType_t xProtocol,
144 size_t * pxSocketSize );
145
146 static uint8_t ucASCIIToHex( char cChar );
147
148 #if ( ipconfigUSE_TCP == 1 )
149
150 /*
151 * Create a txStream or a rxStream, depending on the parameter 'xIsInputStream'
152 */
153 static StreamBuffer_t * prvTCPCreateStream( FreeRTOS_Socket_t * pxSocket,
154 BaseType_t xIsInputStream );
155 #endif /* ipconfigUSE_TCP == 1 */
156
157 #if ( ipconfigUSE_TCP == 1 )
158
159 /*
160 * Called from FreeRTOS_send(): some checks which will be done before
161 * sending a TCP packed.
162 */
163 static int32_t prvTCPSendCheck( FreeRTOS_Socket_t * pxSocket,
164 size_t uxDataLength );
165 #endif /* ipconfigUSE_TCP */
166
167 #if ( ipconfigUSE_TCP == 1 )
168
169 /*
170 * When a child socket gets closed, make sure to update the child-count of the parent
171 */
172 static void prvTCPSetSocketCount( FreeRTOS_Socket_t const * pxSocketToDelete );
173 #endif /* ipconfigUSE_TCP == 1 */
174
175 #if ( ipconfigUSE_TCP == 1 )
176
177 /*
178 * Called from FreeRTOS_connect(): make some checks and if allowed, send a
179 * message to the IP-task to start connecting to a remote socket
180 */
181 static BaseType_t prvTCPConnectStart( FreeRTOS_Socket_t * pxSocket,
182 struct freertos_sockaddr const * pxAddress );
183 #endif /* ipconfigUSE_TCP */
184
185 #if ( ipconfigUSE_TCP == 1 )
186
187 /*
188 * Check if it makes any sense to wait for a connect event.
189 * It may return: -EINPROGRESS, -EAGAIN, or 0 for OK.
190 */
191 static BaseType_t bMayConnect( FreeRTOS_Socket_t const * pxSocket );
192 #endif /* ipconfigUSE_TCP */
193
194 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
195
196 /* Executed by the IP-task, it will check all sockets belonging to a set */
197 static void prvFindSelectedSocket( SocketSelect_t * pxSocketSet );
198
199 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
200 /*-----------------------------------------------------------*/
201
202 /** @brief The list that contains mappings between sockets and port numbers.
203 * Accesses to this list must be protected by critical sections of
204 * some kind.
205 */
206 List_t xBoundUDPSocketsList;
207
208 #if ipconfigUSE_TCP == 1
209
210 /** @brief The list that contains mappings between sockets and port numbers.
211 * Accesses to this list must be protected by critical sections of
212 * some kind.
213 */
214 List_t xBoundTCPSocketsList;
215
216 #endif /* ipconfigUSE_TCP == 1 */
217
218 /*-----------------------------------------------------------*/
219
220 /**
221 * @brief Check whether the socket is valid or not.
222 *
223 * @param[in] pxSocket: The socket being checked.
224 * @param[in] xProtocol: The protocol for which the socket was created.
225 * @param[in] xIsBound: pdTRUE when the socket should be bound, otherwise pdFALSE.
226 *
227 * @return If the socket is valid, then pdPASS is returned or else, pdFAIL
228 * is returned.
229 */
prvValidSocket(const FreeRTOS_Socket_t * pxSocket,BaseType_t xProtocol,BaseType_t xIsBound)230 static BaseType_t prvValidSocket( const FreeRTOS_Socket_t * pxSocket,
231 BaseType_t xProtocol,
232 BaseType_t xIsBound )
233 {
234 BaseType_t xReturn;
235
236 /* MISRA Ref 11.4.1 [Socket error and integer to pointer conversion] */
237 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */
238 /* coverity[misra_c_2012_rule_11_4_violation] */
239 if( ( pxSocket == NULL ) || ( pxSocket == FREERTOS_INVALID_SOCKET ) )
240 {
241 xReturn = pdFALSE;
242 }
243 else if( ( xIsBound != pdFALSE ) && !socketSOCKET_IS_BOUND( pxSocket ) )
244 {
245 /* The caller expects the socket to be bound, but it isn't. */
246 xReturn = pdFALSE;
247 }
248 else if( pxSocket->ucProtocol != ( uint8_t ) xProtocol )
249 {
250 /* Socket has a wrong type (UDP != TCP). */
251 xReturn = pdFALSE;
252 }
253 else
254 {
255 xReturn = pdTRUE;
256 }
257
258 return xReturn;
259 }
260 /*-----------------------------------------------------------*/
261
262 /**
263 * @brief Initialise the bound TCP/UDP socket lists.
264 */
vNetworkSocketsInit(void)265 void vNetworkSocketsInit( void )
266 {
267 vListInitialise( &xBoundUDPSocketsList );
268
269 #if ( ipconfigUSE_TCP == 1 )
270 {
271 vListInitialise( &xBoundTCPSocketsList );
272 }
273 #endif /* ipconfigUSE_TCP == 1 */
274 }
275 /*-----------------------------------------------------------*/
276
277 /**
278 * @brief Determine the socket size for the given protocol.
279 *
280 * @param[in] xDomain: The domain for which the size of socket is being determined.
281 * @param[in] xType: Is this a datagram socket or a stream socket.
282 * @param[in] xProtocol: The protocol being used.
283 * @param[out] pxSocketSize: Pointer to a variable in which the size shall be returned
284 * if all checks pass.
285 *
286 * @return pdPASS if socket size was determined and put in the parameter pxSocketSize
287 * correctly, else pdFAIL.
288 */
prvDetermineSocketSize(BaseType_t xDomain,BaseType_t xType,BaseType_t xProtocol,size_t * pxSocketSize)289 static BaseType_t prvDetermineSocketSize( BaseType_t xDomain,
290 BaseType_t xType,
291 BaseType_t xProtocol,
292 size_t * pxSocketSize )
293 {
294 BaseType_t xReturn = pdPASS;
295 FreeRTOS_Socket_t const * pxSocket = NULL;
296
297 /* Asserts must not appear before it has been determined that the network
298 * task is ready - otherwise the asserts will fail. */
299 if( xIPIsNetworkTaskReady() == pdFALSE )
300 {
301 xReturn = pdFAIL;
302 }
303 else
304 {
305 /* Only Ethernet is currently supported. */
306 configASSERT( xDomain == FREERTOS_AF_INET );
307
308 /* Check if the UDP socket-list has been initialised. */
309 configASSERT( listLIST_IS_INITIALISED( &xBoundUDPSocketsList ) );
310 #if ( ipconfigUSE_TCP == 1 )
311 {
312 /* Check if the TCP socket-list has been initialised. */
313 configASSERT( listLIST_IS_INITIALISED( &xBoundTCPSocketsList ) );
314 }
315 #endif /* ipconfigUSE_TCP == 1 */
316
317 if( xProtocol == FREERTOS_IPPROTO_UDP )
318 {
319 if( xType != FREERTOS_SOCK_DGRAM )
320 {
321 xReturn = pdFAIL;
322 configASSERT( xReturn == pdPASS ); /* LCOV_EXCL_BR_LINE Exclude this line from branch coverage as the not-taken condition will never happen. */
323 }
324
325 /* In case a UDP socket is created, do not allocate space for TCP data. */
326 *pxSocketSize = ( sizeof( *pxSocket ) - sizeof( pxSocket->u ) ) + sizeof( pxSocket->u.xUDP );
327 }
328
329 #if ( ipconfigUSE_TCP == 1 )
330 else if( xProtocol == FREERTOS_IPPROTO_TCP )
331 {
332 if( xType != FREERTOS_SOCK_STREAM )
333 {
334 xReturn = pdFAIL;
335 configASSERT( xReturn == pdPASS ); /* LCOV_EXCL_BR_LINE Exclude this line from branch coverage as the not-taken condition will never happen. */
336 }
337
338 *pxSocketSize = ( sizeof( *pxSocket ) - sizeof( pxSocket->u ) ) + sizeof( pxSocket->u.xTCP );
339 }
340 #endif /* ipconfigUSE_TCP == 1 */
341 else
342 {
343 xReturn = pdFAIL;
344 configASSERT( xReturn == pdPASS ); /* LCOV_EXCL_BR_LINE Exclude this line from branch coverage as the not-taken condition will never happen. */
345 }
346 }
347
348 /* In case configASSERT() is not used */
349 ( void ) xDomain;
350 ( void ) pxSocket; /* Was only used for sizeof. */
351 return xReturn;
352 }
353 /*-----------------------------------------------------------*/
354
355 /**
356 * @brief allocate and initialise a socket.
357 *
358 * @param[in] xDomain: The domain in which the socket should be created.
359 * @param[in] xType: The type of the socket.
360 * @param[in] xProtocol: The protocol of the socket.
361 *
362 * @return FREERTOS_INVALID_SOCKET if the allocation failed, or if there was
363 * a parameter error, otherwise a valid socket.
364 */
FreeRTOS_socket(BaseType_t xDomain,BaseType_t xType,BaseType_t xProtocol)365 Socket_t FreeRTOS_socket( BaseType_t xDomain,
366 BaseType_t xType,
367 BaseType_t xProtocol )
368 {
369 FreeRTOS_Socket_t * pxSocket;
370
371 /* Note that this value will be over-written by the call to prvDetermineSocketSize. */
372 size_t uxSocketSize = 1;
373 EventGroupHandle_t xEventGroup;
374 Socket_t xReturn;
375 BaseType_t xProtocolCpy = xProtocol;
376
377 /* The special protocol FREERTOS_SOCK_DEPENDENT_PROTO, which is equivalent
378 * to passing 0 as defined by POSIX, indicates to the socket layer that it
379 * should pick a sensible default protocol based off the given socket type.
380 * If we can't, prvDetermineSocketSize will catch it as an invalid
381 * type/protocol combo.
382 */
383 if( xProtocol == FREERTOS_SOCK_DEPENDENT_PROTO )
384 {
385 switch( xType )
386 {
387 case FREERTOS_SOCK_DGRAM:
388 xProtocolCpy = FREERTOS_IPPROTO_UDP;
389 break;
390
391 case FREERTOS_SOCK_STREAM:
392 xProtocolCpy = FREERTOS_IPPROTO_TCP;
393 break;
394
395 default:
396
397 /* incorrect xType. this will be caught by
398 * prvDetermineSocketSize.
399 */
400 break;
401 }
402 }
403
404 if( prvDetermineSocketSize( xDomain, xType, xProtocolCpy, &uxSocketSize ) == pdFAIL )
405 {
406 /* MISRA Ref 11.4.1 [Socket error and integer to pointer conversion] */
407 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */
408 /* coverity[misra_c_2012_rule_11_4_violation] */
409 xReturn = FREERTOS_INVALID_SOCKET;
410 }
411 else
412 {
413 /* Allocate the structure that will hold the socket information. The
414 * size depends on the type of socket: UDP sockets need less space. A
415 * define 'pvPortMallocSocket' will used to allocate the necessary space.
416 * By default it points to the FreeRTOS function 'pvPortMalloc()'. */
417 pxSocket = ( ( FreeRTOS_Socket_t * ) pvPortMallocSocket( uxSocketSize ) );
418
419 if( pxSocket == NULL )
420 {
421 /* MISRA Ref 11.4.1 [Socket error and integer to pointer conversion] */
422 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */
423 /* coverity[misra_c_2012_rule_11_4_violation] */
424 xReturn = FREERTOS_INVALID_SOCKET;
425 iptraceFAILED_TO_CREATE_SOCKET();
426 }
427 else
428 {
429 xEventGroup = xEventGroupCreate();
430
431 if( xEventGroup == NULL )
432 {
433 vPortFreeSocket( pxSocket );
434
435 /* MISRA Ref 11.4.1 [Socket error and integer to pointer conversion] */
436 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */
437 /* coverity[misra_c_2012_rule_11_4_violation] */
438 xReturn = FREERTOS_INVALID_SOCKET;
439 iptraceFAILED_TO_CREATE_EVENT_GROUP();
440 }
441 else
442 {
443 if( xProtocolCpy == FREERTOS_IPPROTO_UDP )
444 {
445 iptraceMEM_STATS_CREATE( tcpSOCKET_UDP, pxSocket, uxSocketSize + sizeof( StaticEventGroup_t ) );
446 }
447 else
448 {
449 /* Lint wants at least a comment, in case the macro is empty. */
450 iptraceMEM_STATS_CREATE( tcpSOCKET_TCP, pxSocket, uxSocketSize + sizeof( StaticEventGroup_t ) );
451 }
452
453 /* Clear the entire space to avoid nulling individual entries. */
454 ( void ) memset( pxSocket, 0, uxSocketSize );
455
456 pxSocket->xEventGroup = xEventGroup;
457
458 /* Initialise the socket's members. The semaphore will be created
459 * if the socket is bound to an address, for now the pointer to the
460 * semaphore is just set to NULL to show it has not been created. */
461 if( xProtocolCpy == FREERTOS_IPPROTO_UDP )
462 {
463 vListInitialise( &( pxSocket->u.xUDP.xWaitingPacketsList ) );
464
465 #if ( ipconfigUDP_MAX_RX_PACKETS > 0U )
466 {
467 pxSocket->u.xUDP.uxMaxPackets = ( UBaseType_t ) ipconfigUDP_MAX_RX_PACKETS;
468 }
469 #endif /* ipconfigUDP_MAX_RX_PACKETS > 0 */
470 }
471
472 vListInitialiseItem( &( pxSocket->xBoundSocketListItem ) );
473 listSET_LIST_ITEM_OWNER( &( pxSocket->xBoundSocketListItem ), ( void * ) pxSocket );
474
475 pxSocket->xReceiveBlockTime = ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME;
476 pxSocket->xSendBlockTime = ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME;
477 pxSocket->ucSocketOptions = ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT;
478 pxSocket->ucProtocol = ( uint8_t ) xProtocolCpy; /* protocol: UDP or TCP */
479
480 #if ( ipconfigUSE_TCP == 1 )
481 {
482 if( xProtocolCpy == FREERTOS_IPPROTO_TCP )
483 {
484 /* StreamSize is expressed in number of bytes */
485 /* Round up buffer sizes to nearest multiple of MSS */
486 pxSocket->u.xTCP.usMSS = ( uint16_t ) ipconfigTCP_MSS;
487 pxSocket->u.xTCP.uxRxStreamSize = ( size_t ) ipconfigTCP_RX_BUFFER_LENGTH;
488 pxSocket->u.xTCP.uxTxStreamSize = ( size_t ) FreeRTOS_round_up( ipconfigTCP_TX_BUFFER_LENGTH, ipconfigTCP_MSS );
489 /* Use half of the buffer size of the TCP windows */
490 #if ( ipconfigUSE_TCP_WIN == 1 )
491 {
492 pxSocket->u.xTCP.uxRxWinSize = FreeRTOS_max_uint32( 1U, ( uint32_t ) ( pxSocket->u.xTCP.uxRxStreamSize / 2U ) / ipconfigTCP_MSS );
493 pxSocket->u.xTCP.uxTxWinSize = FreeRTOS_max_uint32( 1U, ( uint32_t ) ( pxSocket->u.xTCP.uxTxStreamSize / 2U ) / ipconfigTCP_MSS );
494 }
495 #else
496 {
497 pxSocket->u.xTCP.uxRxWinSize = 1U;
498 pxSocket->u.xTCP.uxTxWinSize = 1U;
499 }
500 #endif
501
502 /* The above values are just defaults, and can be overridden by
503 * calling FreeRTOS_setsockopt(). No buffers will be allocated until a
504 * socket is connected and data is exchanged. */
505 }
506 }
507 #endif /* ipconfigUSE_TCP == 1 */
508 xReturn = pxSocket;
509 }
510 }
511 }
512
513 /* Remove compiler warnings in the case the configASSERT() is not defined. */
514 ( void ) xDomain;
515
516 return xReturn;
517 }
518 /*-----------------------------------------------------------*/
519
520 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
521
522 /**
523 * @brief Create a socket set.
524 *
525 * @return The new socket set which was created, or NULL when allocation has failed.
526 */
FreeRTOS_CreateSocketSet(void)527 SocketSet_t FreeRTOS_CreateSocketSet( void )
528 {
529 SocketSelect_t * pxSocketSet;
530
531 pxSocketSet = ( ( SocketSelect_t * ) pvPortMalloc( sizeof( *pxSocketSet ) ) );
532
533 if( pxSocketSet != NULL )
534 {
535 ( void ) memset( pxSocketSet, 0, sizeof( *pxSocketSet ) );
536 pxSocketSet->xSelectGroup = xEventGroupCreate();
537
538 if( pxSocketSet->xSelectGroup == NULL )
539 {
540 vPortFree( pxSocketSet );
541 pxSocketSet = NULL;
542 }
543 else
544 {
545 /* Lint wants at least a comment, in case the macro is empty. */
546 iptraceMEM_STATS_CREATE( tcpSOCKET_SET, pxSocketSet, sizeof( *pxSocketSet ) + sizeof( StaticEventGroup_t ) );
547 }
548 }
549
550 return ( SocketSet_t ) pxSocketSet;
551 }
552
553 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
554 /*-----------------------------------------------------------*/
555
556 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
557
558 /**
559 * @brief Delete a given socket set.
560 *
561 * @param[in] xSocketSet: The socket set being deleted.
562 */
FreeRTOS_DeleteSocketSet(SocketSet_t xSocketSet)563 void FreeRTOS_DeleteSocketSet( SocketSet_t xSocketSet )
564 {
565 IPStackEvent_t xCloseEvent;
566
567
568 xCloseEvent.eEventType = eSocketSetDeleteEvent;
569 xCloseEvent.pvData = ( void * ) xSocketSet;
570
571 if( xSendEventStructToIPTask( &xCloseEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL )
572 {
573 FreeRTOS_printf( ( "FreeRTOS_DeleteSocketSet: xSendEventStructToIPTask failed\n" ) );
574 }
575 }
576
577 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
578 /*-----------------------------------------------------------*/
579
580 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
581
582 /**
583 * @brief Add a socket to a set.
584 *
585 * @param[in] xSocket: The socket being added.
586 * @param[in] xSocketSet: The socket set being added to.
587 * @param[in] xBitsToSet: The event bits to set, a combination of the values defined
588 * in 'eSelectEvent_t', for read, write, exception, etc.
589 */
FreeRTOS_FD_SET(Socket_t xSocket,SocketSet_t xSocketSet,EventBits_t xBitsToSet)590 void FreeRTOS_FD_SET( Socket_t xSocket,
591 SocketSet_t xSocketSet,
592 EventBits_t xBitsToSet )
593 {
594 FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
595 SocketSelect_t * pxSocketSet = ( SocketSelect_t * ) xSocketSet;
596
597
598 configASSERT( pxSocket != NULL );
599 configASSERT( xSocketSet != NULL );
600
601 /* Make sure we're not adding bits which are reserved for internal use,
602 * such as eSELECT_CALL_IP */
603 pxSocket->xSelectBits |= xBitsToSet & ( ( EventBits_t ) eSELECT_ALL );
604
605 if( ( pxSocket->xSelectBits & ( ( EventBits_t ) eSELECT_ALL ) ) != ( EventBits_t ) 0U )
606 {
607 /* Adding a socket to a socket set. */
608 pxSocket->pxSocketSet = ( SocketSelect_t * ) xSocketSet;
609
610 /* Now have the IP-task call vSocketSelect() to see if the set contains
611 * any sockets which are 'ready' and set the proper bits. */
612 prvFindSelectedSocket( pxSocketSet );
613 }
614 }
615
616 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
617 /*-----------------------------------------------------------*/
618
619 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
620
621 /**
622 * @brief Clear select bits for a socket. If the mask becomes 0,
623 * remove the socket from the set.
624 *
625 * @param[in] xSocket: The socket whose select bits are being cleared.
626 * @param[in] xSocketSet: The socket set of the socket.
627 * @param[in] xBitsToClear: The bits to be cleared. Every '1' means that the
628 * corresponding bit will be cleared. See 'eSelectEvent_t' for
629 * the possible values.
630 */
FreeRTOS_FD_CLR(Socket_t xSocket,SocketSet_t xSocketSet,EventBits_t xBitsToClear)631 void FreeRTOS_FD_CLR( Socket_t xSocket,
632 SocketSet_t xSocketSet,
633 EventBits_t xBitsToClear )
634 {
635 FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
636
637 configASSERT( pxSocket != NULL );
638 configASSERT( xSocketSet != NULL );
639
640 pxSocket->xSelectBits &= ~( xBitsToClear & ( ( EventBits_t ) eSELECT_ALL ) );
641
642 if( ( pxSocket->xSelectBits & ( ( EventBits_t ) eSELECT_ALL ) ) != ( EventBits_t ) 0U )
643 {
644 pxSocket->pxSocketSet = ( SocketSelect_t * ) xSocketSet;
645 }
646 else
647 {
648 /* disconnect it from the socket set */
649 pxSocket->pxSocketSet = NULL;
650 }
651 }
652
653
654 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
655 /*-----------------------------------------------------------*/
656
657
658 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
659
660 /**
661 * @brief Test if a socket belongs to a socket-set and if so, which event bit(s)
662 * are set.
663 *
664 * @param[in] xSocket: The socket of interest.
665 * @param[in] xSocketSet: The socket set to which the socket belongs.
666 *
667 * @return If the socket belongs to the socket set: the event bits, otherwise zero.
668 */
FreeRTOS_FD_ISSET(const ConstSocket_t xSocket,const ConstSocketSet_t xSocketSet)669 EventBits_t FreeRTOS_FD_ISSET( const ConstSocket_t xSocket,
670 const ConstSocketSet_t xSocketSet )
671 {
672 EventBits_t xReturn;
673 const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
674
675 configASSERT( pxSocket != NULL );
676 configASSERT( xSocketSet != NULL );
677
678 if( xSocketSet == ( SocketSet_t ) pxSocket->pxSocketSet )
679 {
680 /* Make sure we're not adding bits which are reserved for internal
681 * use. */
682 xReturn = pxSocket->xSocketBits & ( ( EventBits_t ) eSELECT_ALL );
683 }
684 else
685 {
686 xReturn = 0;
687 }
688
689 return xReturn;
690 }
691
692
693 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
694 /*-----------------------------------------------------------*/
695
696 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
697
698 /**
699 * @brief The select() statement: wait for an event to occur on any of the sockets
700 * included in a socket set.
701 *
702 * @param[in] xSocketSet: The socket set including the sockets on which we are
703 * waiting for an event to occur.
704 * @param[in] xBlockTimeTicks: Maximum time ticks to wait for an event to occur.
705 * If the value is 'portMAX_DELAY' then the function will wait
706 * indefinitely for an event to occur.
707 *
708 * @return The socket which might have triggered the event bit.
709 */
FreeRTOS_select(SocketSet_t xSocketSet,TickType_t xBlockTimeTicks)710 BaseType_t FreeRTOS_select( SocketSet_t xSocketSet,
711 TickType_t xBlockTimeTicks )
712 {
713 TimeOut_t xTimeOut;
714 TickType_t xRemainingTime;
715 SocketSelect_t * pxSocketSet = ( SocketSelect_t * ) xSocketSet;
716 EventBits_t uxResult;
717
718 configASSERT( xSocketSet != NULL );
719
720 /* Only in the first round, check for non-blocking */
721 xRemainingTime = xBlockTimeTicks;
722
723 /* Fetch the current time */
724 vTaskSetTimeOutState( &xTimeOut );
725
726 for( ; ; )
727 {
728 /* Find a socket which might have triggered the bit
729 * This function might return immediately or block for a limited time */
730 uxResult = xEventGroupWaitBits( pxSocketSet->xSelectGroup, ( ( EventBits_t ) eSELECT_ALL ), pdFALSE, pdFALSE, xRemainingTime );
731
732 #if ( ipconfigSUPPORT_SIGNALS != 0 )
733 {
734 if( ( uxResult & ( ( EventBits_t ) eSELECT_INTR ) ) != 0U )
735 {
736 ( void ) xEventGroupClearBits( pxSocketSet->xSelectGroup, ( EventBits_t ) eSELECT_INTR );
737 FreeRTOS_debug_printf( ( "FreeRTOS_select: interrupted\n" ) );
738 break;
739 }
740 }
741 #endif /* ipconfigSUPPORT_SIGNALS */
742
743 /* Have the IP-task find the socket which had an event */
744 prvFindSelectedSocket( pxSocketSet );
745
746 uxResult = xEventGroupGetBits( pxSocketSet->xSelectGroup );
747
748 if( uxResult != 0U )
749 {
750 break;
751 }
752
753 /* Has the timeout been reached? */
754 if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
755 {
756 break;
757 }
758 }
759
760 return ( BaseType_t ) uxResult;
761 }
762
763
764 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
765 /*-----------------------------------------------------------*/
766
767 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
768
769 /**
770 * @brief Send a message to the IP-task to have it check all sockets belonging to
771 * 'pxSocketSet'
772 *
773 * @param[in] pxSocketSet: The socket set being asked to check.
774 */
prvFindSelectedSocket(SocketSelect_t * pxSocketSet)775 static void prvFindSelectedSocket( SocketSelect_t * pxSocketSet )
776 {
777 IPStackEvent_t xSelectEvent;
778
779 #if ( ipconfigSELECT_USES_NOTIFY != 0 )
780 SocketSelectMessage_t xSelectMessage;
781 #endif
782
783 xSelectEvent.eEventType = eSocketSelectEvent;
784 #if ( ipconfigSELECT_USES_NOTIFY != 0 )
785 {
786 xSelectMessage.pxSocketSet = pxSocketSet;
787 xSelectMessage.xTaskhandle = xTaskGetCurrentTaskHandle();
788 xSelectEvent.pvData = &( xSelectMessage );
789 }
790 #else
791 {
792 xSelectEvent.pvData = pxSocketSet;
793
794 /* while the IP-task works on the request, the API will block on
795 * 'eSELECT_CALL_IP'. So clear it first. */
796 ( void ) xEventGroupClearBits( pxSocketSet->xSelectGroup, ( BaseType_t ) eSELECT_CALL_IP );
797 }
798 #endif /* if ( ipconfigSELECT_USES_NOTIFY != 0 ) */
799
800 /* Now send the socket select event */
801 if( xSendEventStructToIPTask( &xSelectEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL )
802 {
803 /* Oops, we failed to wake-up the IP task. No use to wait for it. */
804 FreeRTOS_debug_printf( ( "prvFindSelectedSocket: failed\n" ) );
805 }
806 else
807 {
808 /* As soon as the IP-task is ready, it will set 'eSELECT_CALL_IP' to
809 * wakeup the calling API */
810 #if ( ipconfigSELECT_USES_NOTIFY != 0 )
811 {
812 ( void ) ulTaskNotifyTake( pdFALSE, portMAX_DELAY );
813 }
814 #else
815 {
816 ( void ) xEventGroupWaitBits( pxSocketSet->xSelectGroup, ( BaseType_t ) eSELECT_CALL_IP, pdTRUE, pdFALSE, portMAX_DELAY );
817 }
818 #endif
819 }
820 }
821
822
823 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
824 /*-----------------------------------------------------------*/
825
826 /**
827 * @brief Receive data from a bound socket. In this library, the function
828 * can only be used with connection-less sockets (UDP). For TCP sockets,
829 * please use FreeRTOS_recv().
830 *
831 * @param[in] xSocket: The socket to which the data is sent i.e. the
832 * listening socket.
833 * @param[out] pvBuffer: The buffer in which the data being received is to
834 * be stored.
835 * @param[in] uxBufferLength: The length of the buffer.
836 * @param[in] xFlags: The flags to indicate preferences while calling this function.
837 * @param[out] pxSourceAddress: The source address from which the data is being sent.
838 * @param[out] pxSourceAddressLength: This parameter is used only to adhere to Berkeley
839 * sockets standard. It is not used internally.
840 *
841 * @return The number of bytes received. Or else, an error code is returned. When it
842 * returns a negative value, the cause can be looked-up in
843 * 'FreeRTOS_errno_TCP.h'.
844 */
FreeRTOS_recvfrom(const ConstSocket_t xSocket,void * pvBuffer,size_t uxBufferLength,BaseType_t xFlags,struct freertos_sockaddr * pxSourceAddress,const socklen_t * pxSourceAddressLength)845 int32_t FreeRTOS_recvfrom( const ConstSocket_t xSocket,
846 void * pvBuffer,
847 size_t uxBufferLength,
848 BaseType_t xFlags,
849 struct freertos_sockaddr * pxSourceAddress,
850 const socklen_t * pxSourceAddressLength )
851 {
852 BaseType_t lPacketCount;
853 NetworkBufferDescriptor_t * pxNetworkBuffer;
854 const void * pvCopySource;
855 FreeRTOS_Socket_t const * pxSocket = xSocket;
856 TickType_t xRemainingTime = ( TickType_t ) 0; /* Obsolete assignment, but some compilers output a warning if its not done. */
857 BaseType_t xTimed = pdFALSE;
858 TimeOut_t xTimeOut;
859 int32_t lReturn;
860 EventBits_t xEventBits = ( EventBits_t ) 0;
861 size_t uxPayloadLength;
862
863 if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_UDP, pdTRUE ) == pdFALSE )
864 {
865 lReturn = -pdFREERTOS_ERRNO_EINVAL;
866 }
867 else
868 {
869 lPacketCount = ( BaseType_t ) listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) );
870
871 /* The function prototype is designed to maintain the expected Berkeley
872 * sockets standard, but this implementation does not use all the parameters. */
873 ( void ) pxSourceAddressLength;
874
875 while( lPacketCount == 0 )
876 {
877 if( xTimed == pdFALSE )
878 {
879 /* Check to see if the socket is non blocking on the first
880 * iteration. */
881 xRemainingTime = pxSocket->xReceiveBlockTime;
882
883 if( xRemainingTime == ( TickType_t ) 0 )
884 {
885 #if ( ipconfigSUPPORT_SIGNALS != 0 )
886 {
887 /* Just check for the interrupt flag. */
888 xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_INTR,
889 pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, socketDONT_BLOCK );
890 }
891 #endif /* ipconfigSUPPORT_SIGNALS */
892 break;
893 }
894
895 if( ( ( ( UBaseType_t ) xFlags ) & ( ( UBaseType_t ) FREERTOS_MSG_DONTWAIT ) ) != 0U )
896 {
897 break;
898 }
899
900 /* To ensure this part only executes once. */
901 xTimed = pdTRUE;
902
903 /* Fetch the current time. */
904 vTaskSetTimeOutState( &xTimeOut );
905 }
906
907 /* Wait for arrival of data. While waiting, the IP-task may set the
908 * 'eSOCKET_RECEIVE' bit in 'xEventGroup', if it receives data for this
909 * socket, thus unblocking this API call. */
910 xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, ( ( EventBits_t ) eSOCKET_RECEIVE ) | ( ( EventBits_t ) eSOCKET_INTR ),
911 pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );
912
913 #if ( ipconfigSUPPORT_SIGNALS != 0 )
914 {
915 if( ( xEventBits & ( EventBits_t ) eSOCKET_INTR ) != 0U )
916 {
917 if( ( xEventBits & ( EventBits_t ) eSOCKET_RECEIVE ) != 0U )
918 {
919 /* Shouldn't have cleared the eSOCKET_RECEIVE flag. */
920 ( void ) xEventGroupSetBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_RECEIVE );
921 }
922
923 break;
924 }
925 }
926 #else /* if ( ipconfigSUPPORT_SIGNALS != 0 ) */
927 {
928 ( void ) xEventBits;
929 }
930 #endif /* ipconfigSUPPORT_SIGNALS */
931
932 lPacketCount = ( BaseType_t ) listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) );
933
934 if( lPacketCount != 0 )
935 {
936 break;
937 }
938
939 /* Has the timeout been reached ? */
940 if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
941 {
942 break;
943 }
944 } /* while( lPacketCount == 0 ) */
945
946 if( lPacketCount != 0 )
947 {
948 taskENTER_CRITICAL();
949 {
950 /* The owner of the list item is the network buffer. */
951 pxNetworkBuffer = ( ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) );
952
953 if( ( ( UBaseType_t ) xFlags & ( UBaseType_t ) FREERTOS_MSG_PEEK ) == 0U )
954 {
955 /* Remove the network buffer from the list of buffers waiting to
956 * be processed by the socket. */
957 ( void ) uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
958 }
959 }
960 taskEXIT_CRITICAL();
961
962 /* The returned value is the length of the payload data, which is
963 * calculated at the total packet size minus the headers.
964 * The validity of `xDataLength` prvProcessIPPacket has been confirmed
965 * in 'prvProcessIPPacket()'. */
966 uxPayloadLength = pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t );
967 lReturn = ( int32_t ) uxPayloadLength;
968
969 if( pxSourceAddress != NULL )
970 {
971 pxSourceAddress->sin_port = pxNetworkBuffer->usPort;
972 pxSourceAddress->sin_addr = pxNetworkBuffer->ulIPAddress;
973 }
974
975 if( ( ( UBaseType_t ) xFlags & ( UBaseType_t ) FREERTOS_ZERO_COPY ) == 0U )
976 {
977 /* The zero copy flag is not set. Truncate the length if it won't
978 * fit in the provided buffer. */
979 if( lReturn > ( int32_t ) uxBufferLength )
980 {
981 iptraceRECVFROM_DISCARDING_BYTES( ( uxBufferLength - lReturn ) );
982 lReturn = ( int32_t ) uxBufferLength;
983 }
984
985 /* Copy the received data into the provided buffer, then release the
986 * network buffer. */
987 pvCopySource = ( const void * ) &pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ];
988 ( void ) memcpy( pvBuffer, pvCopySource, ( size_t ) lReturn );
989
990 if( ( ( UBaseType_t ) xFlags & ( UBaseType_t ) FREERTOS_MSG_PEEK ) == 0U )
991 {
992 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
993 }
994 }
995 else
996 {
997 /* The zero copy flag was set. pvBuffer is not a buffer into which
998 * the received data can be copied, but a pointer that must be set to
999 * point to the buffer in which the received data has already been
1000 * placed. */
1001 *( ( void ** ) pvBuffer ) = ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] );
1002 }
1003 }
1004
1005 #if ( ipconfigSUPPORT_SIGNALS != 0 )
1006 else if( ( xEventBits & ( EventBits_t ) eSOCKET_INTR ) != 0U )
1007 {
1008 lReturn = -pdFREERTOS_ERRNO_EINTR;
1009 iptraceRECVFROM_INTERRUPTED();
1010 }
1011 #endif /* ipconfigSUPPORT_SIGNALS */
1012 else
1013 {
1014 lReturn = -pdFREERTOS_ERRNO_EWOULDBLOCK;
1015 iptraceRECVFROM_TIMEOUT();
1016 }
1017 }
1018
1019 return lReturn;
1020 }
1021 /*-----------------------------------------------------------*/
1022
1023 /**
1024 * @brief Check if a socket is a valid UDP socket. In case it is not
1025 * yet bound, bind it to port 0 ( random port ).
1026 * @param[in] pxSocket: The socket that must be bound to a port number.
1027 * @return Returns pdTRUE if the socket was already bound, or if the
1028 * socket has been bound successfully.
1029 */
prvMakeSureSocketIsBound(FreeRTOS_Socket_t * pxSocket)1030 static BaseType_t prvMakeSureSocketIsBound( FreeRTOS_Socket_t * pxSocket )
1031 {
1032 /* Check if this is a valid UDP socket, does not have to be bound yet. */
1033 BaseType_t xReturn = prvValidSocket( pxSocket, FREERTOS_IPPROTO_UDP, pdFALSE );
1034
1035 if( ( xReturn == pdTRUE ) && ( !socketSOCKET_IS_BOUND( pxSocket ) ) )
1036 {
1037 /* The socket is valid but it is not yet bound. */
1038 if( FreeRTOS_bind( pxSocket, NULL, 0U ) != 0 )
1039 {
1040 /* The socket was not yet bound, and binding it has failed. */
1041 xReturn = pdFALSE;
1042 }
1043 }
1044
1045 return xReturn;
1046 }
1047 /*-----------------------------------------------------------*/
1048
1049 /**
1050 * @brief Send data to a socket. The socket must have already been created by a
1051 * successful call to FreeRTOS_socket(). It works for UDP-sockets only.
1052 *
1053 * @param[in] xSocket: The socket being sent to.
1054 * @param[in] pvBuffer: Pointer to the data being sent.
1055 * @param[in] uxTotalDataLength: Length (in bytes) of the data being sent.
1056 * @param[in] xFlags: Flags used to communicate preferences to the function.
1057 * Possibly FREERTOS_MSG_DONTWAIT and/or FREERTOS_ZERO_COPY.
1058 * @param[in] pxDestinationAddress: The address to which the data is to be sent.
1059 * @param[in] xDestinationAddressLength: This parameter is present to adhere to the
1060 * Berkeley sockets standard. Else, it is not used.
1061 *
1062 * @return When positive: the total number of bytes sent, when negative an error
1063 * has occurred: it can be looked-up in 'FreeRTOS_errno_TCP.h'.
1064 */
FreeRTOS_sendto(Socket_t xSocket,const void * pvBuffer,size_t uxTotalDataLength,BaseType_t xFlags,const struct freertos_sockaddr * pxDestinationAddress,socklen_t xDestinationAddressLength)1065 int32_t FreeRTOS_sendto( Socket_t xSocket,
1066 const void * pvBuffer,
1067 size_t uxTotalDataLength,
1068 BaseType_t xFlags,
1069 const struct freertos_sockaddr * pxDestinationAddress,
1070 socklen_t xDestinationAddressLength )
1071 {
1072 NetworkBufferDescriptor_t * pxNetworkBuffer;
1073 void * pvCopyDest;
1074 IPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
1075 TimeOut_t xTimeOut;
1076 TickType_t xTicksToWait;
1077 int32_t lReturn = 0;
1078 FreeRTOS_Socket_t * pxSocket;
1079 const size_t uxMaxPayloadLength = ipMAX_UDP_PAYLOAD_LENGTH;
1080 const size_t uxPayloadOffset = ipUDP_PAYLOAD_OFFSET_IPv4;
1081
1082
1083 pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
1084
1085 /* The function prototype is designed to maintain the expected Berkeley
1086 * sockets standard, but this implementation does not use all the
1087 * parameters. */
1088 ( void ) xDestinationAddressLength;
1089 configASSERT( pvBuffer != NULL );
1090
1091 if( uxTotalDataLength <= ( size_t ) uxMaxPayloadLength )
1092 {
1093 /* If the socket is not already bound to an address, bind it now.
1094 * Passing NULL as the address parameter tells FreeRTOS_bind() to select
1095 * the address to bind to. */
1096 if( prvMakeSureSocketIsBound( pxSocket ) == pdTRUE )
1097 {
1098 xTicksToWait = pxSocket->xSendBlockTime;
1099
1100 #if ( ipconfigUSE_CALLBACKS != 0 )
1101 {
1102 if( xIsCallingFromIPTask() != pdFALSE )
1103 {
1104 /* If this send function is called from within a call-back
1105 * handler it may not block, otherwise chances would be big to
1106 * get a deadlock: the IP-task waiting for itself. */
1107 xTicksToWait = ( TickType_t ) 0;
1108 }
1109 }
1110 #endif /* ipconfigUSE_CALLBACKS */
1111
1112 if( ( ( UBaseType_t ) xFlags & ( UBaseType_t ) FREERTOS_MSG_DONTWAIT ) != 0U )
1113 {
1114 xTicksToWait = ( TickType_t ) 0;
1115 }
1116
1117 if( ( ( UBaseType_t ) xFlags & ( UBaseType_t ) FREERTOS_ZERO_COPY ) == 0U )
1118 {
1119 /* Zero copy is not set, so obtain a network buffer into
1120 * which the payload will be copied. */
1121 vTaskSetTimeOutState( &xTimeOut );
1122
1123 /* Block until a buffer becomes available, or until a
1124 * timeout has been reached */
1125 pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( uxPayloadOffset + uxTotalDataLength, xTicksToWait );
1126
1127 if( pxNetworkBuffer != NULL )
1128 {
1129 pvCopyDest = ( void * ) &pxNetworkBuffer->pucEthernetBuffer[ uxPayloadOffset ];
1130 ( void ) memcpy( pvCopyDest, pvBuffer, uxTotalDataLength );
1131
1132 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE )
1133 {
1134 /* The entire block time has been used up. */
1135 xTicksToWait = ( TickType_t ) 0;
1136 }
1137 }
1138 }
1139 else
1140 {
1141 /* When zero copy is used, pvBuffer is a pointer to the
1142 * payload of a buffer that has already been obtained from the
1143 * stack. Obtain the network buffer pointer from the buffer. */
1144 pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pvBuffer );
1145 }
1146
1147 if( pxNetworkBuffer != NULL )
1148 {
1149 /* xDataLength is the size of the total packet, including the Ethernet header. */
1150 pxNetworkBuffer->xDataLength = uxTotalDataLength + sizeof( UDPPacket_t );
1151 pxNetworkBuffer->usPort = pxDestinationAddress->sin_port;
1152 pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_PORT( pxSocket );
1153 pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr;
1154
1155 /* The socket options are passed to the IP layer in the
1156 * space that will eventually get used by the Ethernet header. */
1157 pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = pxSocket->ucSocketOptions;
1158
1159 /* Tell the networking task that the packet needs sending. */
1160 xStackTxEvent.pvData = pxNetworkBuffer;
1161
1162 /* Ask the IP-task to send this packet */
1163 if( xSendEventStructToIPTask( &xStackTxEvent, xTicksToWait ) == pdPASS )
1164 {
1165 /* The packet was successfully sent to the IP task. */
1166 lReturn = ( int32_t ) uxTotalDataLength;
1167 #if ( ipconfigUSE_CALLBACKS == 1 )
1168 {
1169 if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xUDP.pxHandleSent ) )
1170 {
1171 pxSocket->u.xUDP.pxHandleSent( xSocket, uxTotalDataLength );
1172 }
1173 }
1174 #endif /* ipconfigUSE_CALLBACKS */
1175 }
1176 else
1177 {
1178 /* If the buffer was allocated in this function, release
1179 * it. */
1180 if( ( ( UBaseType_t ) xFlags & ( UBaseType_t ) FREERTOS_ZERO_COPY ) == 0U )
1181 {
1182 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
1183 }
1184
1185 iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
1186 }
1187 }
1188 else
1189 {
1190 /* If errno was available, errno would be set to
1191 * FREERTOS_ENOPKTS. As it is, the function must return the
1192 * number of transmitted bytes, so the calling function knows
1193 * how much data was actually sent. */
1194 iptraceNO_BUFFER_FOR_SENDTO();
1195 }
1196 }
1197 else
1198 {
1199 /* No comment. */
1200 iptraceSENDTO_SOCKET_NOT_BOUND();
1201 }
1202 }
1203 else
1204 {
1205 /* The data is longer than the available buffer space. */
1206 iptraceSENDTO_DATA_TOO_LONG();
1207 }
1208
1209 return lReturn;
1210 } /* Tested */
1211 /*-----------------------------------------------------------*/
1212
1213 /**
1214 * @brief binds a socket to a local port number. If port 0 is provided,
1215 * a system provided port number will be assigned. This function
1216 * can be used for both UDP and TCP sockets. The actual binding
1217 * will be performed by the IP-task to avoid mutual access to the
1218 * bound-socket-lists (xBoundUDPSocketsList or xBoundTCPSocketsList).
1219 *
1220 * @param[in] xSocket: The socket being bound.
1221 * @param[in] pxAddress: The address struct carrying the port number to which
1222 * this socket is to be bound.
1223 * @param[in] xAddressLength: This parameter is not used internally. The
1224 * function signature is used to adhere to standard
1225 * Berkeley sockets API.
1226 *
1227 * @return The return value is 0 if the bind is successful.
1228 * If some error occurred, then a negative value is returned.
1229 */
FreeRTOS_bind(Socket_t xSocket,struct freertos_sockaddr const * pxAddress,socklen_t xAddressLength)1230 BaseType_t FreeRTOS_bind( Socket_t xSocket,
1231 struct freertos_sockaddr const * pxAddress,
1232 socklen_t xAddressLength )
1233 {
1234 IPStackEvent_t xBindEvent;
1235 FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
1236 BaseType_t xReturn = 0;
1237
1238 ( void ) xAddressLength;
1239
1240 configASSERT( xIsCallingFromIPTask() == pdFALSE );
1241
1242 /* MISRA Ref 11.4.1 [Socket error and integer to pointer conversion] */
1243 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */
1244 /* coverity[misra_c_2012_rule_11_4_violation] */
1245 if( ( pxSocket == NULL ) || ( pxSocket == FREERTOS_INVALID_SOCKET ) )
1246 {
1247 xReturn = -pdFREERTOS_ERRNO_EINVAL;
1248 }
1249
1250 /* Once a socket is bound to a port, it can not be bound to a different
1251 * port number */
1252 else if( socketSOCKET_IS_BOUND( pxSocket ) )
1253 {
1254 /* The socket is already bound. */
1255 FreeRTOS_debug_printf( ( "vSocketBind: Socket already bound to %d\n", pxSocket->usLocalPort ) );
1256 xReturn = -pdFREERTOS_ERRNO_EINVAL;
1257 }
1258 else
1259 {
1260 /* Prepare a messages to the IP-task in order to perform the binding.
1261 * The desired port number will be passed in usLocalPort. */
1262 xBindEvent.eEventType = eSocketBindEvent;
1263 xBindEvent.pvData = xSocket;
1264
1265 if( pxAddress != NULL )
1266 {
1267 pxSocket->usLocalPort = FreeRTOS_ntohs( pxAddress->sin_port );
1268 }
1269 else
1270 {
1271 /* Caller wants to bind to a random port number. */
1272 pxSocket->usLocalPort = 0U;
1273 }
1274
1275 /* portMAX_DELAY is used as a the time-out parameter, as binding *must*
1276 * succeed before the socket can be used. _RB_ The use of an infinite
1277 * block time needs be changed as it could result in the task hanging. */
1278 if( xSendEventStructToIPTask( &xBindEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL )
1279 {
1280 /* Failed to wake-up the IP-task, no use to wait for it */
1281 FreeRTOS_debug_printf( ( "FreeRTOS_bind: send event failed\n" ) );
1282 xReturn = -pdFREERTOS_ERRNO_ECANCELED;
1283 }
1284 else
1285 {
1286 /* The IP-task will set the 'eSOCKET_BOUND' bit when it has done its
1287 * job. */
1288 ( void ) xEventGroupWaitBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_BOUND, pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, portMAX_DELAY );
1289
1290 if( !socketSOCKET_IS_BOUND( pxSocket ) )
1291 {
1292 xReturn = -pdFREERTOS_ERRNO_EINVAL;
1293 }
1294 }
1295 }
1296
1297 return xReturn;
1298 }
1299 /*-----------------------------------------------------------*/
1300
1301 /**
1302 * @brief Internal version of bind() that should not be called directly.
1303 * 'xInternal' is used for TCP sockets only: it allows to have several
1304 * (connected) child sockets bound to the same server port.
1305 *
1306 * @param[in] pxSocket: The socket is to be bound.
1307 * @param[in] pxBindAddress: The port to which this socket should be bound.
1308 * @param[in] uxAddressLength: The address length.
1309 * @param[in] xInternal: pdTRUE is calling internally, else pdFALSE.
1310 *
1311 * @return If the socket was bound to a port successfully, then a 0 is returned.
1312 * Or else, an error code is returned.
1313 */
vSocketBind(FreeRTOS_Socket_t * pxSocket,struct freertos_sockaddr * pxBindAddress,size_t uxAddressLength,BaseType_t xInternal)1314 BaseType_t vSocketBind( FreeRTOS_Socket_t * pxSocket,
1315 struct freertos_sockaddr * pxBindAddress,
1316 size_t uxAddressLength,
1317 BaseType_t xInternal )
1318 {
1319 BaseType_t xReturn = 0; /* In Berkeley sockets, 0 means pass for bind(). */
1320 List_t * pxSocketList;
1321 struct freertos_sockaddr * pxAddress = pxBindAddress;
1322
1323 #if ( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 )
1324 struct freertos_sockaddr xAddress;
1325 #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND */
1326
1327 configASSERT( pxSocket != NULL );
1328 configASSERT( pxSocket != FREERTOS_INVALID_SOCKET );
1329
1330 #if ( ipconfigUSE_TCP == 1 )
1331 if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
1332 {
1333 pxSocketList = &xBoundTCPSocketsList;
1334 }
1335 else
1336 #endif /* ipconfigUSE_TCP == 1 */
1337 {
1338 pxSocketList = &xBoundUDPSocketsList;
1339 }
1340
1341 /* The function prototype is designed to maintain the expected Berkeley
1342 * sockets standard, but this implementation does not use all the parameters. */
1343 ( void ) uxAddressLength;
1344
1345 #if ( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 )
1346 {
1347 /* pxAddress will be NULL if sendto() was called on a socket without the
1348 * socket being bound to an address. In this case, automatically allocate
1349 * an address to the socket. There is a small chance that the allocated
1350 * port will already be in use - if that is the case, then the check below
1351 * [pxListFindListItemWithValue()] will result in an error being returned. */
1352 if( pxAddress == NULL )
1353 {
1354 pxAddress = &xAddress;
1355 /* Put the port to zero to be assigned later. */
1356 pxAddress->sin_port = 0U;
1357 }
1358 }
1359 #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 */
1360
1361 /* Sockets must be bound before calling FreeRTOS_sendto() if
1362 * ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is not set to 1. */
1363 configASSERT( pxAddress != NULL );
1364
1365 #if ( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 )
1366 /* pxAddress is not NULL, no testing needed. */
1367 #else
1368 if( pxAddress != NULL )
1369 #endif
1370 {
1371 /* Add a do-while loop to facilitate use of 'break' statements. */
1372 do
1373 {
1374 if( pxAddress->sin_port == 0U )
1375 {
1376 pxAddress->sin_port = prvGetPrivatePortNumber( ( BaseType_t ) pxSocket->ucProtocol );
1377
1378 if( pxAddress->sin_port == ( uint16_t ) 0U )
1379 {
1380 xReturn = -pdFREERTOS_ERRNO_EADDRNOTAVAIL;
1381 break;
1382 }
1383 }
1384
1385 /* If vSocketBind() is called from the API FreeRTOS_bind() it has been
1386 * confirmed that the socket was not yet bound to a port. If it is called
1387 * from the IP-task, no such check is necessary. */
1388
1389 /* Check to ensure the port is not already in use. If the bind is
1390 * called internally, a port MAY be used by more than one socket. */
1391 if( ( ( xInternal == pdFALSE ) || ( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) ) &&
1392 ( pxListFindListItemWithValue( pxSocketList, ( TickType_t ) pxAddress->sin_port ) != NULL ) )
1393 {
1394 FreeRTOS_debug_printf( ( "vSocketBind: %sP port %d in use\n",
1395 ( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP ) ? "TC" : "UD",
1396 FreeRTOS_ntohs( pxAddress->sin_port ) ) );
1397 xReturn = -pdFREERTOS_ERRNO_EADDRINUSE;
1398 }
1399 else
1400 {
1401 /* Allocate the port number to the socket.
1402 * This macro will set 'xBoundSocketListItem->xItemValue' */
1403 socketSET_SOCKET_PORT( pxSocket, pxAddress->sin_port );
1404
1405 /* And also store it in a socket field 'usLocalPort' in host-byte-order,
1406 * mostly used for logging and debugging purposes */
1407 pxSocket->usLocalPort = FreeRTOS_ntohs( pxAddress->sin_port );
1408
1409 /* Add the socket to the list of bound ports. */
1410 {
1411 /* If the network driver can iterate through 'xBoundUDPSocketsList',
1412 * by calling xPortHasUDPSocket() then the IP-task must temporarily
1413 * suspend the scheduler to keep the list in a consistent state. */
1414 #if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
1415 {
1416 vTaskSuspendAll();
1417 }
1418 #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
1419
1420 /* Add the socket to 'xBoundUDPSocketsList' or 'xBoundTCPSocketsList' */
1421 vListInsertEnd( pxSocketList, &( pxSocket->xBoundSocketListItem ) );
1422
1423 #if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
1424 {
1425 ( void ) xTaskResumeAll();
1426 }
1427 #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
1428 }
1429 }
1430 } while( ipFALSE_BOOL );
1431 }
1432
1433 #if ( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 0 )
1434 else
1435 {
1436 xReturn = -pdFREERTOS_ERRNO_EADDRNOTAVAIL;
1437 FreeRTOS_debug_printf( ( "vSocketBind: Socket no addr\n" ) );
1438 }
1439 #endif
1440
1441 if( xReturn != 0 )
1442 {
1443 iptraceBIND_FAILED( xSocket, ( FreeRTOS_ntohs( pxAddress->sin_port ) ) );
1444 }
1445
1446 return xReturn;
1447 } /* Tested */
1448 /*-----------------------------------------------------------*/
1449
1450 /**
1451 * @brief Close a socket and free the allocated space. In case of a TCP socket:
1452 * the connection will not be closed automatically. Subsequent messages
1453 * for the closed socket will be responded to with a RST. The IP-task
1454 * will actually close the socket, after receiving a 'eSocketCloseEvent'
1455 * message.
1456 *
1457 * @param[in] xSocket: the socket being closed.
1458 *
1459 * @return There are three distinct values which can be returned:
1460 * 0: If the xSocket is NULL/invalid.
1461 * 1: If the socket was successfully closed (read the brief above).
1462 * -1: If the socket was valid but could not be closed because the message
1463 * could not be delivered to the IP-task. Try again later.
1464 */
FreeRTOS_closesocket(Socket_t xSocket)1465 BaseType_t FreeRTOS_closesocket( Socket_t xSocket )
1466 {
1467 BaseType_t xResult;
1468
1469 #if ( ipconfigUSE_CALLBACKS == 1 )
1470 FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
1471 #endif /* ipconfigUSE_CALLBACKS == 1 */
1472 IPStackEvent_t xCloseEvent;
1473 xCloseEvent.eEventType = eSocketCloseEvent;
1474 xCloseEvent.pvData = xSocket;
1475
1476 /* MISRA Ref 11.4.1 [Socket error and integer to pointer conversion] */
1477 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */
1478 /* coverity[misra_c_2012_rule_11_4_violation] */
1479 if( ( xSocket == NULL ) || ( xSocket == FREERTOS_INVALID_SOCKET ) )
1480 {
1481 xResult = 0;
1482 }
1483 else
1484 {
1485 #if ( ipconfigUSE_CALLBACKS == 1 )
1486 {
1487 #if ( ipconfigUSE_TCP == 1 )
1488 if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
1489 {
1490 /* Make sure that IP-task won't call the user callback's anymore */
1491 pxSocket->u.xTCP.pxHandleConnected = NULL;
1492 pxSocket->u.xTCP.pxHandleReceive = NULL;
1493 pxSocket->u.xTCP.pxHandleSent = NULL;
1494 }
1495 else
1496 #endif /* ipconfigUSE_TCP == 1 */
1497
1498 if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP )
1499 {
1500 /* Clear the two UDP handlers. */
1501 pxSocket->u.xUDP.pxHandleReceive = NULL;
1502 pxSocket->u.xUDP.pxHandleSent = NULL;
1503 }
1504 }
1505 #endif /* ipconfigUSE_CALLBACKS == 1 */
1506
1507 /* Let the IP task close the socket to keep it synchronised with the
1508 * packet handling. */
1509
1510 /* The timeout value below is only used if this function is called from
1511 * a user task. If this function is called by the IP-task, it may fail
1512 * to close the socket when the event queue is full.
1513 * This should only happen in case of a user call-back. */
1514 if( xSendEventStructToIPTask( &xCloseEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL )
1515 {
1516 FreeRTOS_debug_printf( ( "FreeRTOS_closesocket: failed\n" ) );
1517 xResult = -1;
1518 }
1519 else
1520 {
1521 xResult = 1;
1522 }
1523 }
1524
1525 return xResult;
1526 }
1527
1528 /**
1529 * @brief This is the internal version of FreeRTOS_closesocket(). It will
1530 * be called by the IPtask only to avoid problems with synchronicity.
1531 *
1532 * @param[in] pxSocket: The socket descriptor of the socket being closed.
1533 *
1534 * @return Returns NULL, always.
1535 */
1536 /* MISRA Ref 17.2.1 [Sockets and limited recursion] */
1537 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-172 */
1538 /* coverity[misra_c_2012_rule_17_2_violation] */
vSocketClose(FreeRTOS_Socket_t * pxSocket)1539 void * vSocketClose( FreeRTOS_Socket_t * pxSocket )
1540 {
1541 NetworkBufferDescriptor_t * pxNetworkBuffer;
1542
1543 #if ( ipconfigUSE_TCP == 1 )
1544 {
1545 /* For TCP: clean up a little more. */
1546 if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
1547 {
1548 #if ( ipconfigUSE_TCP_WIN == 1 )
1549 {
1550 if( pxSocket->u.xTCP.pxAckMessage != NULL )
1551 {
1552 vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage );
1553 }
1554
1555 /* Free the resources which were claimed by the tcpWin member */
1556 vTCPWindowDestroy( &pxSocket->u.xTCP.xTCPWindow );
1557 }
1558 #endif /* ipconfigUSE_TCP_WIN */
1559
1560 /* Free the input and output streams */
1561 if( pxSocket->u.xTCP.rxStream != NULL )
1562 {
1563 iptraceMEM_STATS_DELETE( pxSocket->u.xTCP.rxStream );
1564 vPortFreeLarge( pxSocket->u.xTCP.rxStream );
1565 }
1566
1567 if( pxSocket->u.xTCP.txStream != NULL )
1568 {
1569 iptraceMEM_STATS_DELETE( pxSocket->u.xTCP.txStream );
1570 vPortFreeLarge( pxSocket->u.xTCP.txStream );
1571 }
1572
1573 /* In case this is a child socket, make sure the child-count of the
1574 * parent socket is decreased. */
1575 prvTCPSetSocketCount( pxSocket );
1576 }
1577 }
1578 #endif /* ipconfigUSE_TCP == 1 */
1579
1580 /* Socket must be unbound first, to ensure no more packets are queued on
1581 * it. */
1582 if( socketSOCKET_IS_BOUND( pxSocket ) )
1583 {
1584 /* If the network driver can iterate through 'xBoundUDPSocketsList',
1585 * by calling xPortHasUDPSocket(), then the IP-task must temporarily
1586 * suspend the scheduler to keep the list in a consistent state. */
1587 #if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
1588 {
1589 vTaskSuspendAll();
1590 }
1591 #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
1592
1593 ( void ) uxListRemove( &( pxSocket->xBoundSocketListItem ) );
1594
1595 #if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
1596 {
1597 ( void ) xTaskResumeAll();
1598 }
1599 #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
1600 }
1601
1602 /* Now the socket is not bound the list of waiting packets can be
1603 * drained. */
1604 if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP )
1605 {
1606 while( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) > 0U )
1607 {
1608 pxNetworkBuffer = ( ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) );
1609 ( void ) uxListRemove( &( pxNetworkBuffer->xBufferListItem ) );
1610 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
1611 }
1612 }
1613
1614 if( pxSocket->xEventGroup != NULL )
1615 {
1616 vEventGroupDelete( pxSocket->xEventGroup );
1617 }
1618
1619 #if ( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_DEBUG_PRINTF != 0 )
1620 {
1621 if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
1622 {
1623 FreeRTOS_debug_printf( ( "FreeRTOS_closesocket[%u to %xip:%u]: buffers %u socks %u\n",
1624 pxSocket->usLocalPort,
1625 ( unsigned ) pxSocket->u.xTCP.ulRemoteIP,
1626 pxSocket->u.xTCP.usRemotePort,
1627 ( unsigned ) uxGetNumberOfFreeNetworkBuffers(),
1628 ( unsigned ) listCURRENT_LIST_LENGTH( &xBoundTCPSocketsList ) ) );
1629 }
1630 }
1631 #endif /* ( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_DEBUG_PRINTF != 0 ) */
1632
1633 /* And finally, after all resources have been freed, free the socket space */
1634 iptraceMEM_STATS_DELETE( pxSocket );
1635 vPortFreeSocket( pxSocket );
1636
1637 return NULL;
1638 } /* Tested */
1639
1640 /*-----------------------------------------------------------*/
1641
1642 #if ipconfigUSE_TCP == 1
1643
1644 /**
1645 * @brief When a child socket gets closed, make sure to update the child-count of the
1646 * parent. When a listening parent socket is closed, make sure to close also
1647 * all orphaned child-sockets.
1648 *
1649 * @param[in] pxSocketToDelete: The socket being closed.
1650 */
1651 /* MISRA Ref 17.2.1 [Sockets and limited recursion] */
1652 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-172 */
1653 /* coverity[misra_c_2012_rule_17_2_violation] */
1654 /* coverity[recursive_step] */
prvTCPSetSocketCount(FreeRTOS_Socket_t const * pxSocketToDelete)1655 static void prvTCPSetSocketCount( FreeRTOS_Socket_t const * pxSocketToDelete )
1656 {
1657 const ListItem_t * pxIterator;
1658
1659 /* MISRA Ref 11.3.1 [Misaligned access] */
1660 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
1661 /* coverity[misra_c_2012_rule_11_3_violation] */
1662 const ListItem_t * pxEnd = ( ( const ListItem_t * ) &( xBoundTCPSocketsList.xListEnd ) );
1663 FreeRTOS_Socket_t * pxOtherSocket;
1664 uint16_t usLocalPort = pxSocketToDelete->usLocalPort;
1665
1666 if( pxSocketToDelete->u.xTCP.eTCPState == eTCP_LISTEN )
1667 {
1668 pxIterator = listGET_NEXT( pxEnd );
1669
1670 while( pxIterator != pxEnd )
1671 {
1672 pxOtherSocket = ( ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) );
1673
1674 /* This needs to be done here, before calling vSocketClose. */
1675 pxIterator = listGET_NEXT( pxIterator );
1676
1677 if( ( pxOtherSocket->u.xTCP.eTCPState != eTCP_LISTEN ) &&
1678 ( pxOtherSocket->usLocalPort == usLocalPort ) &&
1679 ( ( pxOtherSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) ||
1680 ( pxOtherSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) ) )
1681 {
1682 /* MISRA Ref 17.2.1 [Sockets and limited recursion] */
1683 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-172 */
1684 /* coverity[misra_c_2012_rule_17_2_violation] */
1685 /* coverity[recursive_step] */
1686 ( void ) vSocketClose( pxOtherSocket );
1687 }
1688 }
1689 }
1690 else
1691 {
1692 for( pxIterator = listGET_NEXT( pxEnd );
1693 pxIterator != pxEnd;
1694 pxIterator = listGET_NEXT( pxIterator ) )
1695 {
1696 pxOtherSocket = ( ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) );
1697
1698 if( ( pxOtherSocket->u.xTCP.eTCPState == eTCP_LISTEN ) &&
1699 ( pxOtherSocket->usLocalPort == usLocalPort ) &&
1700 ( pxOtherSocket->u.xTCP.usChildCount != 0U ) )
1701 {
1702 pxOtherSocket->u.xTCP.usChildCount--;
1703 FreeRTOS_debug_printf( ( "Lost: Socket %u now has %u / %u child%s\n",
1704 pxOtherSocket->usLocalPort,
1705 pxOtherSocket->u.xTCP.usChildCount,
1706 pxOtherSocket->u.xTCP.usBacklog,
1707 ( pxOtherSocket->u.xTCP.usChildCount == 1U ) ? "" : "ren" ) );
1708 break;
1709 }
1710 }
1711 }
1712 }
1713
1714
1715 #endif /* ipconfigUSE_TCP == 1 */
1716
1717 /*-----------------------------------------------------------*/
1718
1719 #if ( ipconfigUSE_TCP == 1 )
1720
1721 /**
1722 * @brief Set the value of receive/send buffer after some preliminary checks.
1723 *
1724 * @param[in] pxSocket: The socket whose options are being set.
1725 * @param[in] lOptionName: The option name: either FREERTOS_SO_SNDBUF or
1726 * FREERTOS_SO_SNDBUF.
1727 * @param[in] pvOptionValue: The value of the option being set.
1728 *
1729 * @return If there is no error, then 0 is returned. Or a negative errno
1730 * value is returned.
1731 */
prvSockopt_so_buffer(FreeRTOS_Socket_t * pxSocket,int32_t lOptionName,const void * pvOptionValue)1732 static BaseType_t prvSockopt_so_buffer( FreeRTOS_Socket_t * pxSocket,
1733 int32_t lOptionName,
1734 const void * pvOptionValue )
1735 {
1736 uint32_t ulNewValue;
1737 BaseType_t xReturn;
1738
1739 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
1740 {
1741 FreeRTOS_debug_printf( ( "Set SO_%sBUF: wrong socket type\n",
1742 ( lOptionName == FREERTOS_SO_SNDBUF ) ? "SND" : "RCV" ) );
1743 xReturn = -pdFREERTOS_ERRNO_EINVAL;
1744 }
1745 else if( ( ( lOptionName == FREERTOS_SO_SNDBUF ) && ( pxSocket->u.xTCP.txStream != NULL ) ) ||
1746 ( ( lOptionName == FREERTOS_SO_RCVBUF ) && ( pxSocket->u.xTCP.rxStream != NULL ) ) )
1747 {
1748 FreeRTOS_debug_printf( ( "Set SO_%sBUF: buffer already created\n",
1749 ( lOptionName == FREERTOS_SO_SNDBUF ) ? "SND" : "RCV" ) );
1750 xReturn = -pdFREERTOS_ERRNO_EINVAL;
1751 }
1752 else
1753 {
1754 ulNewValue = *( ( const uint32_t * ) pvOptionValue );
1755
1756 if( lOptionName == FREERTOS_SO_SNDBUF )
1757 {
1758 /* Round up to nearest MSS size */
1759 ulNewValue = FreeRTOS_round_up( ulNewValue, ( uint32_t ) pxSocket->u.xTCP.usMSS );
1760 pxSocket->u.xTCP.uxTxStreamSize = ulNewValue;
1761 }
1762 else
1763 {
1764 pxSocket->u.xTCP.uxRxStreamSize = ulNewValue;
1765 }
1766
1767 xReturn = 0;
1768 }
1769
1770 return xReturn;
1771 }
1772 #endif /* ipconfigUSE_TCP == 1 */
1773 /*-----------------------------------------------------------*/
1774
1775 /* FreeRTOS_setsockopt calls itself, but in a very limited way,
1776 * only when FREERTOS_SO_WIN_PROPERTIES is being set. */
1777
1778 /**
1779 * @brief Set the socket options for the given socket.
1780 *
1781 * @param[in] xSocket: The socket for which the options are to be set.
1782 * @param[in] lLevel: Not used. Parameter is used to maintain the Berkeley sockets
1783 * standard.
1784 * @param[in] lOptionName: The name of the option to be set.
1785 * @param[in] pvOptionValue: The value of the option to be set.
1786 * @param[in] uxOptionLength: Not used. Parameter is used to maintain the Berkeley
1787 * sockets standard.
1788 *
1789 * @return If the option can be set with the given value, then 0 is returned. Else,
1790 * an error code is returned.
1791 */
FreeRTOS_setsockopt(Socket_t xSocket,int32_t lLevel,int32_t lOptionName,const void * pvOptionValue,size_t uxOptionLength)1792 BaseType_t FreeRTOS_setsockopt( Socket_t xSocket,
1793 int32_t lLevel,
1794 int32_t lOptionName,
1795 const void * pvOptionValue,
1796 size_t uxOptionLength )
1797 {
1798 /* The standard Berkeley function returns 0 for success. */
1799 BaseType_t xReturn = -pdFREERTOS_ERRNO_EINVAL;
1800 FreeRTOS_Socket_t * pxSocket;
1801
1802 pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
1803
1804 /* The function prototype is designed to maintain the expected Berkeley
1805 * sockets standard, but this implementation does not use all the parameters. */
1806 ( void ) lLevel;
1807 ( void ) uxOptionLength;
1808
1809 /* MISRA Ref 11.4.1 [Socket error and integer to pointer conversion] */
1810 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */
1811 /* coverity[misra_c_2012_rule_11_4_violation] */
1812 if( ( pxSocket != NULL ) && ( pxSocket != FREERTOS_INVALID_SOCKET ) )
1813 {
1814 switch( lOptionName )
1815 {
1816 case FREERTOS_SO_RCVTIMEO:
1817 /* Receive time out. */
1818 pxSocket->xReceiveBlockTime = *( ( const TickType_t * ) pvOptionValue );
1819 xReturn = 0;
1820 break;
1821
1822 case FREERTOS_SO_SNDTIMEO:
1823 pxSocket->xSendBlockTime = *( ( const TickType_t * ) pvOptionValue );
1824
1825 if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP )
1826 {
1827 /* The send time out is capped for the reason stated in the
1828 * comments where ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS is defined
1829 * in FreeRTOSIPConfig.h (assuming an official configuration file
1830 * is being used. */
1831 if( pxSocket->xSendBlockTime > ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS )
1832 {
1833 pxSocket->xSendBlockTime = ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS;
1834 }
1835 }
1836 else
1837 {
1838 /* For TCP socket, it isn't necessary to limit the blocking time
1839 * because the FreeRTOS_send() function does not wait for a network
1840 * buffer to become available. */
1841 }
1842
1843 xReturn = 0;
1844 break;
1845
1846 #if ( ipconfigUDP_MAX_RX_PACKETS > 0U )
1847 case FREERTOS_SO_UDP_MAX_RX_PACKETS:
1848
1849 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_UDP )
1850 {
1851 break; /* will return -pdFREERTOS_ERRNO_EINVAL */
1852 }
1853
1854 pxSocket->u.xUDP.uxMaxPackets = *( ( const UBaseType_t * ) pvOptionValue );
1855 xReturn = 0;
1856 break;
1857 #endif /* ipconfigUDP_MAX_RX_PACKETS */
1858
1859 case FREERTOS_SO_UDPCKSUM_OUT:
1860
1861 /* Turn calculating of the UDP checksum on/off for this socket. If pvOptionValue
1862 * is anything else than NULL, the checksum generation will be turned on. */
1863
1864 if( pvOptionValue == NULL )
1865 {
1866 pxSocket->ucSocketOptions &= ~( ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT );
1867 }
1868 else
1869 {
1870 pxSocket->ucSocketOptions |= ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT;
1871 }
1872
1873 xReturn = 0;
1874 break;
1875
1876 #if ( ipconfigUSE_CALLBACKS == 1 )
1877 #if ( ipconfigUSE_TCP == 1 )
1878 case FREERTOS_SO_TCP_CONN_HANDLER: /* Set a callback for (dis)connection events */
1879 case FREERTOS_SO_TCP_RECV_HANDLER: /* Install a callback for receiving TCP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
1880 case FREERTOS_SO_TCP_SENT_HANDLER: /* Install a callback for sending TCP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
1881 #endif /* ipconfigUSE_TCP */
1882 case FREERTOS_SO_UDP_RECV_HANDLER: /* Install a callback for receiving UDP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
1883 case FREERTOS_SO_UDP_SENT_HANDLER: /* Install a callback for sending UDP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
1884 {
1885 #if ( ipconfigUSE_TCP == 1 )
1886 {
1887 UBaseType_t uxProtocol;
1888
1889 if( ( lOptionName == FREERTOS_SO_UDP_RECV_HANDLER ) ||
1890 ( lOptionName == FREERTOS_SO_UDP_SENT_HANDLER ) )
1891 {
1892 uxProtocol = ( UBaseType_t ) FREERTOS_IPPROTO_UDP;
1893 }
1894 else
1895 {
1896 uxProtocol = ( UBaseType_t ) FREERTOS_IPPROTO_TCP;
1897 }
1898
1899 if( pxSocket->ucProtocol != ( uint8_t ) uxProtocol )
1900 {
1901 break; /* will return -pdFREERTOS_ERRNO_EINVAL */
1902 }
1903 }
1904 #else /* if ( ipconfigUSE_TCP == 1 ) */
1905 {
1906 /* No need to check if the socket has the right
1907 * protocol, because only UDP socket can be created. */
1908 }
1909 #endif /* ipconfigUSE_TCP */
1910
1911 switch( lOptionName )
1912 {
1913 #if ipconfigUSE_TCP == 1
1914 case FREERTOS_SO_TCP_CONN_HANDLER:
1915 pxSocket->u.xTCP.pxHandleConnected = ( ( const F_TCP_UDP_Handler_t * ) pvOptionValue )->pxOnTCPConnected;
1916 break;
1917
1918 case FREERTOS_SO_TCP_RECV_HANDLER:
1919 pxSocket->u.xTCP.pxHandleReceive = ( ( const F_TCP_UDP_Handler_t * ) pvOptionValue )->pxOnTCPReceive;
1920 break;
1921
1922 case FREERTOS_SO_TCP_SENT_HANDLER:
1923 pxSocket->u.xTCP.pxHandleSent = ( ( const F_TCP_UDP_Handler_t * ) pvOptionValue )->pxOnTCPSent;
1924 break;
1925 #endif /* ipconfigUSE_TCP */
1926 case FREERTOS_SO_UDP_RECV_HANDLER:
1927 pxSocket->u.xUDP.pxHandleReceive = ( ( const F_TCP_UDP_Handler_t * ) pvOptionValue )->pxOnUDPReceive;
1928 break;
1929
1930 case FREERTOS_SO_UDP_SENT_HANDLER:
1931 pxSocket->u.xUDP.pxHandleSent = ( ( const F_TCP_UDP_Handler_t * ) pvOptionValue )->pxOnUDPSent;
1932 break;
1933
1934 default: /* LCOV_EXCL_LINE The default case is required by MISRA but control flow will never ever reach
1935 * here since the switch statement enclosing this switch prevents that. */
1936 /* Should it throw an error here? */
1937 break; /* LCOV_EXCL_LINE. Since the default case will never reach, this break statement will not execute as well. */
1938 }
1939 }
1940
1941 xReturn = 0;
1942 break;
1943 #endif /* ipconfigUSE_CALLBACKS */
1944
1945 #if ( ipconfigSOCKET_HAS_USER_SEMAPHORE != 0 )
1946
1947 /* Each socket has a semaphore on which the using task normally
1948 * sleeps. */
1949 case FREERTOS_SO_SET_SEMAPHORE:
1950 {
1951 pxSocket->pxUserSemaphore = *( ( SemaphoreHandle_t * ) pvOptionValue );
1952 }
1953 xReturn = 0;
1954 break;
1955 #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */
1956
1957 #if ( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK != 0 )
1958 case FREERTOS_SO_WAKEUP_CALLBACK:
1959
1960 /* Each socket can have a callback function that is executed
1961 * when there is an event the socket's owner might want to
1962 * process. */
1963
1964 /* The type cast of the pointer expression "A" to
1965 * type "B" removes const qualifier from the pointed to type. */
1966
1967 /* MISRA Ref 11.8.1 [Function pointer and use of const pointer] */
1968 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-118 */
1969
1970 /* MISRA Ref 11.1.1 [ Conversion between pointer to
1971 * a function and another type ] */
1972 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-111 */
1973 /* coverity[misra_c_2012_rule_11_8_violation] */
1974 /* coverity[misra_c_2012_rule_11_1_violation] */
1975 pxSocket->pxUserWakeCallback = ( SocketWakeupCallback_t ) pvOptionValue;
1976 xReturn = 0;
1977 break;
1978 #endif /* ipconfigSOCKET_HAS_USER_WAKE_CALLBACK */
1979
1980 #if ( ipconfigUSE_TCP != 0 )
1981 case FREERTOS_SO_SET_LOW_HIGH_WATER:
1982 {
1983 const LowHighWater_t * pxLowHighWater = ( const LowHighWater_t * ) pvOptionValue;
1984
1985 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
1986 {
1987 /* It is not allowed to access 'pxSocket->u.xTCP'. */
1988 FreeRTOS_debug_printf( ( "FREERTOS_SO_SET_LOW_HIGH_WATER: wrong socket type\n" ) );
1989 break; /* will return -pdFREERTOS_ERRNO_EINVAL */
1990 }
1991
1992 if( ( pxLowHighWater->uxLittleSpace >= pxLowHighWater->uxEnoughSpace ) ||
1993 ( pxLowHighWater->uxEnoughSpace > pxSocket->u.xTCP.uxRxStreamSize ) )
1994 {
1995 /* Impossible values. */
1996 FreeRTOS_debug_printf( ( "FREERTOS_SO_SET_LOW_HIGH_WATER: bad values\n" ) );
1997 break; /* will return -pdFREERTOS_ERRNO_EINVAL */
1998 }
1999
2000 /* Send a STOP when buffer space drops below 'uxLittleSpace' bytes. */
2001 pxSocket->u.xTCP.uxLittleSpace = pxLowHighWater->uxLittleSpace;
2002 /* Send a GO when buffer space grows above 'uxEnoughSpace' bytes. */
2003 pxSocket->u.xTCP.uxEnoughSpace = pxLowHighWater->uxEnoughSpace;
2004 xReturn = 0;
2005 }
2006 break;
2007
2008 case FREERTOS_SO_SNDBUF: /* Set the size of the send buffer, in units of MSS (TCP only) */
2009 case FREERTOS_SO_RCVBUF: /* Set the size of the receive buffer, in units of MSS (TCP only) */
2010 xReturn = prvSockopt_so_buffer( pxSocket, lOptionName, pvOptionValue );
2011 break;
2012
2013 case FREERTOS_SO_WIN_PROPERTIES: /* Set all buffer and window properties in one call, parameter is pointer to WinProperties_t */
2014 {
2015 IPTCPSocket_t * pxTCP = &( pxSocket->u.xTCP );
2016 const WinProperties_t * pxProps;
2017
2018 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
2019 {
2020 FreeRTOS_debug_printf( ( "Set SO_WIN_PROP: wrong socket type\n" ) );
2021 break; /* will return -pdFREERTOS_ERRNO_EINVAL */
2022 }
2023
2024 pxProps = ( const WinProperties_t * ) pvOptionValue;
2025
2026 /* Validity of txStream will be checked by the function below. */
2027 xReturn = prvSockopt_so_buffer( pxSocket, FREERTOS_SO_SNDBUF, &( pxProps->lTxBufSize ) );
2028
2029 if( xReturn != 0 )
2030 {
2031 break; /* will return an error. */
2032 }
2033
2034 /* Validity of rxStream will be checked by the function below. */
2035 xReturn = prvSockopt_so_buffer( pxSocket, FREERTOS_SO_RCVBUF, &( pxProps->lRxBufSize ) );
2036
2037 if( xReturn != 0 )
2038 {
2039 break; /* will return an error. */
2040 }
2041
2042 #if ( ipconfigUSE_TCP_WIN == 1 )
2043 {
2044 pxTCP->uxRxWinSize = ( uint32_t ) pxProps->lRxWinSize; /* Fixed value: size of the TCP reception window */
2045 pxTCP->uxTxWinSize = ( uint32_t ) pxProps->lTxWinSize; /* Fixed value: size of the TCP transmit window */
2046 }
2047 #else
2048 {
2049 pxTCP->uxRxWinSize = 1U;
2050 pxTCP->uxTxWinSize = 1U;
2051 }
2052 #endif
2053
2054 /* In case the socket has already initialised its tcpWin,
2055 * adapt the window size parameters */
2056 if( pxTCP->xTCPWindow.u.bits.bHasInit != pdFALSE_UNSIGNED )
2057 {
2058 pxTCP->xTCPWindow.xSize.ulRxWindowLength = ( uint32_t ) ( pxTCP->uxRxWinSize * pxTCP->usMSS );
2059 pxTCP->xTCPWindow.xSize.ulTxWindowLength = ( uint32_t ) ( pxTCP->uxTxWinSize * pxTCP->usMSS );
2060 }
2061 }
2062
2063 xReturn = 0;
2064 break;
2065
2066 case FREERTOS_SO_REUSE_LISTEN_SOCKET: /* If true, the server-socket will turn into a connected socket */
2067 {
2068 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
2069 {
2070 break; /* will return -pdFREERTOS_ERRNO_EINVAL */
2071 }
2072
2073 if( *( ( const BaseType_t * ) pvOptionValue ) != 0 )
2074 {
2075 pxSocket->u.xTCP.bits.bReuseSocket = pdTRUE;
2076 }
2077 else
2078 {
2079 pxSocket->u.xTCP.bits.bReuseSocket = pdFALSE;
2080 }
2081 }
2082 xReturn = 0;
2083 break;
2084
2085 case FREERTOS_SO_CLOSE_AFTER_SEND: /* As soon as the last byte has been transmitted, finalise the connection */
2086 {
2087 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
2088 {
2089 break; /* will return -pdFREERTOS_ERRNO_EINVAL */
2090 }
2091
2092 if( *( ( const BaseType_t * ) pvOptionValue ) != 0 )
2093 {
2094 pxSocket->u.xTCP.bits.bCloseAfterSend = pdTRUE;
2095 }
2096 else
2097 {
2098 pxSocket->u.xTCP.bits.bCloseAfterSend = pdFALSE;
2099 }
2100 }
2101 xReturn = 0;
2102 break;
2103
2104 case FREERTOS_SO_SET_FULL_SIZE: /* Refuse to send packets smaller than MSS */
2105 {
2106 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
2107 {
2108 break; /* will return -pdFREERTOS_ERRNO_EINVAL */
2109 }
2110
2111 if( *( ( const BaseType_t * ) pvOptionValue ) != 0 )
2112 {
2113 pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize = pdTRUE;
2114 }
2115 else
2116 {
2117 pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize = pdFALSE;
2118 }
2119
2120 if( ( pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize == pdFALSE_UNSIGNED ) &&
2121 ( pxSocket->u.xTCP.eTCPState >= eESTABLISHED ) &&
2122 ( FreeRTOS_outstanding( pxSocket ) > 0 ) )
2123 {
2124 pxSocket->u.xTCP.usTimeout = 1U; /* to set/clear bSendFullSize */
2125 ( void ) xSendEventToIPTask( eTCPTimerEvent );
2126 }
2127 }
2128 xReturn = 0;
2129 break;
2130
2131 case FREERTOS_SO_STOP_RX: /* Refuse to receive more packets. */
2132 {
2133 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
2134 {
2135 break; /* will return -pdFREERTOS_ERRNO_EINVAL */
2136 }
2137
2138 if( *( ( const BaseType_t * ) pvOptionValue ) != 0 )
2139 {
2140 pxSocket->u.xTCP.bits.bRxStopped = pdTRUE;
2141 }
2142 else
2143 {
2144 pxSocket->u.xTCP.bits.bRxStopped = pdFALSE;
2145 }
2146
2147 pxSocket->u.xTCP.bits.bWinChange = pdTRUE;
2148 pxSocket->u.xTCP.usTimeout = 1U; /* to set/clear bRxStopped */
2149 ( void ) xSendEventToIPTask( eTCPTimerEvent );
2150 }
2151 xReturn = 0;
2152 break;
2153 #endif /* ipconfigUSE_TCP == 1 */
2154
2155 default:
2156 /* No other options are handled. */
2157 xReturn = -pdFREERTOS_ERRNO_ENOPROTOOPT;
2158 break;
2159 }
2160 }
2161 else
2162 {
2163 xReturn = -pdFREERTOS_ERRNO_EINVAL;
2164 }
2165
2166 return xReturn;
2167 } /* Tested */
2168
2169 /*-----------------------------------------------------------*/
2170
2171 /**
2172 * @brief Find an available port number per https://tools.ietf.org/html/rfc6056.
2173 *
2174 * @param[in] xProtocol: FREERTOS_IPPROTO_TCP/FREERTOS_IPPROTO_UDP.
2175 *
2176 * @return If an available protocol port is found then that port number is returned.
2177 * Or else, 0 is returned.
2178 */
prvGetPrivatePortNumber(BaseType_t xProtocol)2179 static uint16_t prvGetPrivatePortNumber( BaseType_t xProtocol )
2180 {
2181 const uint16_t usEphemeralPortCount =
2182 socketAUTO_PORT_ALLOCATION_MAX_NUMBER - ( socketAUTO_PORT_ALLOCATION_START_NUMBER - 1U );
2183 uint16_t usIterations = usEphemeralPortCount;
2184 uint32_t ulRandomSeed = 0;
2185 uint16_t usResult = 0;
2186 const List_t * pxList;
2187
2188 #if ipconfigUSE_TCP == 1
2189 if( xProtocol == ( BaseType_t ) FREERTOS_IPPROTO_TCP )
2190 {
2191 pxList = &xBoundTCPSocketsList;
2192 }
2193 else
2194 #endif
2195 {
2196 pxList = &xBoundUDPSocketsList;
2197 }
2198
2199 /* Avoid compiler warnings if ipconfigUSE_TCP is not defined. */
2200 ( void ) xProtocol;
2201
2202 /* Find the next available port using the random seed as a starting
2203 * point. */
2204 do
2205 {
2206 /* Only proceed if the random number generator succeeded. */
2207 if( xApplicationGetRandomNumber( &( ulRandomSeed ) ) == pdFALSE )
2208 {
2209 break;
2210 }
2211
2212 /* Map the random to a candidate port. */
2213 usResult =
2214 socketAUTO_PORT_ALLOCATION_START_NUMBER +
2215 ( ( ( uint16_t ) ulRandomSeed ) % usEphemeralPortCount );
2216
2217 /* Check if there's already an open socket with the same protocol
2218 * and port. */
2219 if( NULL == pxListFindListItemWithValue(
2220 pxList,
2221 ( TickType_t ) FreeRTOS_htons( usResult ) ) )
2222 {
2223 usResult = FreeRTOS_htons( usResult );
2224 break;
2225 }
2226 else
2227 {
2228 usResult = 0;
2229 }
2230
2231 usIterations--;
2232 }
2233 while( usIterations > 0U );
2234
2235 return usResult;
2236 }
2237 /*-----------------------------------------------------------*/
2238
2239 /**
2240 * @brief Find a list item associated with the wanted-item.
2241 *
2242 * @param[in] pxList: The list through which the search is to be conducted.
2243 * @param[in] xWantedItemValue: The wanted item whose association is to be found.
2244 *
2245 * @return The list item holding the value being searched for. If nothing is found,
2246 * then a NULL is returned.
2247 */
pxListFindListItemWithValue(const List_t * pxList,TickType_t xWantedItemValue)2248 static const ListItem_t * pxListFindListItemWithValue( const List_t * pxList,
2249 TickType_t xWantedItemValue )
2250 {
2251 const ListItem_t * pxResult = NULL;
2252
2253 if( ( xIPIsNetworkTaskReady() != pdFALSE ) && ( pxList != NULL ) )
2254 {
2255 const ListItem_t * pxIterator;
2256
2257 /* MISRA Ref 11.3.1 [Misaligned access] */
2258 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
2259 /* coverity[misra_c_2012_rule_11_3_violation] */
2260 const ListItem_t * pxEnd = ( ( const ListItem_t * ) &( pxList->xListEnd ) );
2261
2262 for( pxIterator = listGET_NEXT( pxEnd );
2263 pxIterator != pxEnd;
2264 pxIterator = listGET_NEXT( pxIterator ) )
2265 {
2266 if( listGET_LIST_ITEM_VALUE( pxIterator ) == xWantedItemValue )
2267 {
2268 pxResult = pxIterator;
2269 break;
2270 }
2271 }
2272 }
2273
2274 return pxResult;
2275 } /* Tested */
2276
2277 /*-----------------------------------------------------------*/
2278
2279 /**
2280 * @brief Find the UDP socket corresponding to the port number.
2281 *
2282 * @param[in] uxLocalPort: The port whose corresponding bound UDP socket
2283 * is to be found.
2284 *
2285 * @return The socket owning the port if found or else NULL.
2286 */
pxUDPSocketLookup(UBaseType_t uxLocalPort)2287 FreeRTOS_Socket_t * pxUDPSocketLookup( UBaseType_t uxLocalPort )
2288 {
2289 const ListItem_t * pxListItem;
2290 FreeRTOS_Socket_t * pxSocket = NULL;
2291
2292 /* Looking up a socket is quite simple, find a match with the local port.
2293 *
2294 * See if there is a list item associated with the port number on the
2295 * list of bound sockets. */
2296 pxListItem = pxListFindListItemWithValue( &xBoundUDPSocketsList, ( TickType_t ) uxLocalPort );
2297
2298 if( pxListItem != NULL )
2299 {
2300 /* The owner of the list item is the socket itself. */
2301 pxSocket = ( ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxListItem ) );
2302 configASSERT( pxSocket != NULL );
2303 }
2304
2305 return pxSocket;
2306 }
2307
2308 /*-----------------------------------------------------------*/
2309
2310 #define sockDIGIT_COUNT ( 3U ) /**< Each nibble is expressed in at most 3 digits such as "192". */
2311
2312 /**
2313 * @brief Convert the 32-bit representation of the IP-address to the dotted decimal
2314 * notation after some checks.
2315 * A safe alternative is FreeRTOS_inet_ntop4().
2316 *
2317 * @param[in] ulIPAddress: 32-bit representation of the IP-address.
2318 * @param[out] pcBuffer: The buffer where the dotted decimal representation will be
2319 * stored if all checks pass. The buffer must be at least 16
2320 * bytes long.
2321 *
2322 * @return The pointer returned will be same as pcBuffer and will have the address
2323 * stored in the location.
2324 */
FreeRTOS_inet_ntoa(uint32_t ulIPAddress,char * pcBuffer)2325 const char * FreeRTOS_inet_ntoa( uint32_t ulIPAddress,
2326 char * pcBuffer )
2327 {
2328 socklen_t uxNibble;
2329 socklen_t uxIndex = 0;
2330 const uint8_t * pucAddress = ( const uint8_t * ) &( ulIPAddress );
2331 const char * pcResult = pcBuffer;
2332
2333 for( uxNibble = 0; uxNibble < ipSIZE_OF_IPv4_ADDRESS; uxNibble++ )
2334 {
2335 uint8_t pucDigits[ sockDIGIT_COUNT ];
2336 uint8_t ucValue = pucAddress[ uxNibble ];
2337 socklen_t uxSource = ( socklen_t ) sockDIGIT_COUNT - ( socklen_t ) 1U;
2338
2339 for( ; ; )
2340 {
2341 pucDigits[ uxSource ] = ucValue % ( uint8_t ) 10U;
2342 ucValue /= ( uint8_t ) 10U;
2343
2344 if( uxSource == 1U )
2345 {
2346 break;
2347 }
2348
2349 uxSource--;
2350 }
2351
2352 pucDigits[ 0 ] = ucValue;
2353
2354 /* Skip leading zeros. */
2355 for( uxSource = 0; uxSource < ( ( socklen_t ) sockDIGIT_COUNT - ( socklen_t ) 1U ); uxSource++ )
2356 {
2357 if( pucDigits[ uxSource ] != 0U )
2358 {
2359 break;
2360 }
2361 }
2362
2363 for( ; uxSource < ( socklen_t ) sockDIGIT_COUNT; uxSource++ )
2364 {
2365 pcBuffer[ uxIndex ] = ( char ) ( pucDigits[ uxSource ] + ( char ) '0' );
2366 uxIndex++;
2367 }
2368
2369 if( uxNibble < ( ipSIZE_OF_IPv4_ADDRESS - 1U ) )
2370 {
2371 pcBuffer[ uxIndex ] = '.';
2372 }
2373 else
2374 {
2375 pcBuffer[ uxIndex ] = '\0';
2376 }
2377
2378 uxIndex++;
2379 }
2380
2381 return pcResult;
2382 }
2383 /*-----------------------------------------------------------*/
2384
2385 /**
2386 * @brief Convert the dotted decimal format of the IP-address to the 32-bit representation.
2387 *
2388 * @param[in] xAddressFamily: The Address family to which the IP-address belongs to. Only
2389 * FREERTOS_AF_INET (IPv4) is supported.
2390 * @param[in] pcSource: Pointer to the string holding the dotted decimal representation of
2391 * the IP-address.
2392 * @param[out] pvDestination: The pointer to the address struct/variable where the converted
2393 * IP-address will be stored. The buffer must be 4 bytes long
2394 * in case of a IPv4 address.
2395 *
2396 * @return If all checks pass, then pdPASS is returned or else pdFAIL is returned.
2397 */
FreeRTOS_inet_pton(BaseType_t xAddressFamily,const char * pcSource,void * pvDestination)2398 BaseType_t FreeRTOS_inet_pton( BaseType_t xAddressFamily,
2399 const char * pcSource,
2400 void * pvDestination )
2401 {
2402 BaseType_t xResult;
2403
2404 /* Printable string to struct sockaddr. */
2405 switch( xAddressFamily )
2406 {
2407 case FREERTOS_AF_INET:
2408 xResult = FreeRTOS_inet_pton4( pcSource, pvDestination );
2409 break;
2410
2411 default:
2412 xResult = -pdFREERTOS_ERRNO_EAFNOSUPPORT;
2413 break;
2414 }
2415
2416 return xResult;
2417 }
2418 /*-----------------------------------------------------------*/
2419
2420 /**
2421 * @brief Convert the 32-bit representation of the IP-address to the dotted
2422 * decimal format based on the Address Family. (Only FREERTOS_AF_INET
2423 * is allowed).
2424 *
2425 * @param[in] xAddressFamily: The address family of the IP-address.
2426 * @param[in] pvSource: Pointer to the 32-bit representation of IP-address.
2427 * @param[out] pcDestination: The pointer to the character array where the dotted
2428 * decimal address will be stored if every check does pass.
2429 * @param[in] uxSize: Size of the character array. This value makes sure that the code
2430 * doesn't write beyond it's bounds.
2431 *
2432 * @return If every check does pass, then the pointer to the pcDestination is returned
2433 * holding the dotted decimal format of IP-address. Else, a NULL is returned.
2434 */
FreeRTOS_inet_ntop(BaseType_t xAddressFamily,const void * pvSource,char * pcDestination,socklen_t uxSize)2435 const char * FreeRTOS_inet_ntop( BaseType_t xAddressFamily,
2436 const void * pvSource,
2437 char * pcDestination,
2438 socklen_t uxSize )
2439 {
2440 const char * pcResult;
2441
2442 /* Printable struct sockaddr to string. */
2443 switch( xAddressFamily )
2444 {
2445 case FREERTOS_AF_INET:
2446 pcResult = FreeRTOS_inet_ntop4( pvSource, pcDestination, uxSize );
2447 break;
2448
2449 default:
2450 /* errno should be set to pdFREERTOS_ERRNO_EAFNOSUPPORT. */
2451 pcResult = NULL;
2452 break;
2453 }
2454
2455 return pcResult;
2456 }
2457 /*-----------------------------------------------------------*/
2458
2459 /**
2460 * @brief Convert the 32-bit representation of the IP-address to the dotted decimal format.
2461 *
2462 * @param[in] pvSource: The pointer to the 32-bit representation of the IP-address.
2463 * @param[out] pcDestination: The pointer to a character array where the string of the
2464 * dotted decimal IP format.
2465 * @param[in] uxSize: Size of the character array. This value makes sure that the code
2466 * doesn't write beyond it's bounds.
2467 *
2468 * @return The pointer to the string holding the dotted decimal format of the IP-address. If
2469 * everything passes correctly, then the pointer being returned is the same as
2470 * pcDestination, else a NULL is returned.
2471 */
FreeRTOS_inet_ntop4(const void * pvSource,char * pcDestination,socklen_t uxSize)2472 const char * FreeRTOS_inet_ntop4( const void * pvSource,
2473 char * pcDestination,
2474 socklen_t uxSize )
2475 {
2476 uint32_t ulIPAddress;
2477 void * pvCopyDest;
2478 const char * pcReturn;
2479
2480 if( uxSize < 16U )
2481 {
2482 /* There must be space for "255.255.255.255". */
2483 pcReturn = NULL;
2484 }
2485 else
2486 {
2487 pvCopyDest = ( void * ) &ulIPAddress;
2488 ( void ) memcpy( pvCopyDest, pvSource, sizeof( ulIPAddress ) );
2489 ( void ) FreeRTOS_inet_ntoa( ulIPAddress, pcDestination );
2490 pcReturn = pcDestination;
2491 }
2492
2493 return pcReturn;
2494 }
2495 /*-----------------------------------------------------------*/
2496
2497 /**
2498 * @brief Convert an ASCII character to its corresponding hexadecimal value.
2499 * Accepted characters are 0-9, a-f, and A-F.
2500 *
2501 * @param[in] cChar: The character to be converted.
2502 *
2503 * @return The hexadecimal value, between 0 and 15.
2504 * When the character is not valid, socketINVALID_HEX_CHAR will be returned.
2505 */
ucASCIIToHex(char cChar)2506 static uint8_t ucASCIIToHex( char cChar )
2507 {
2508 char cValue = cChar;
2509 uint8_t ucNew;
2510
2511 if( ( cValue >= '0' ) && ( cValue <= '9' ) )
2512 {
2513 cValue -= ( char ) '0';
2514 /* The value will be between 0 and 9. */
2515 ucNew = ( uint8_t ) cValue;
2516 }
2517 else if( ( cValue >= 'a' ) && ( cValue <= 'f' ) )
2518 {
2519 cValue -= ( char ) 'a';
2520 ucNew = ( uint8_t ) cValue;
2521 /* The value will be between 10 and 15. */
2522 ucNew += ( uint8_t ) 10;
2523 }
2524 else if( ( cValue >= 'A' ) && ( cValue <= 'F' ) )
2525 {
2526 cValue -= ( char ) 'A';
2527 ucNew = ( uint8_t ) cValue;
2528 /* The value will be between 10 and 15. */
2529 ucNew += ( uint8_t ) 10;
2530 }
2531 else
2532 {
2533 /* The character does not represent a valid hex number, return 255. */
2534 ucNew = ( uint8_t ) socketINVALID_HEX_CHAR;
2535 }
2536
2537 return ucNew;
2538 }
2539 /*-----------------------------------------------------------*/
2540
2541 /**
2542 * @brief This function converts a 48-bit MAC address to a human readable string.
2543 *
2544 * @param[in] pucSource: A pointer to an array of 6 bytes.
2545 * @param[out] pcTarget: A buffer that is 18 bytes long, it will contain the resulting string.
2546 * @param[in] cTen: Either an 'A' or an 'a'. It determines whether the hex numbers will use
2547 * capital or small letters.
2548 * @param[in] cSeparator: The separator that should appear between the bytes, either ':' or '-'.
2549 */
FreeRTOS_EUI48_ntop(const uint8_t * pucSource,char * pcTarget,char cTen,char cSeparator)2550 void FreeRTOS_EUI48_ntop( const uint8_t * pucSource,
2551 char * pcTarget,
2552 char cTen,
2553 char cSeparator )
2554 {
2555 size_t uxIndex;
2556 size_t uxNibble;
2557 size_t uxTarget = 0U;
2558
2559 for( uxIndex = 0U; uxIndex < ipMAC_ADDRESS_LENGTH_BYTES; uxIndex++ )
2560 {
2561 uint8_t ucByte = pucSource[ uxIndex ];
2562
2563 for( uxNibble = 0; uxNibble < 2U; uxNibble++ )
2564 {
2565 uint8_t ucNibble;
2566 char cResult;
2567
2568 if( uxNibble == 0U )
2569 {
2570 ucNibble = ucByte >> 4;
2571 }
2572 else
2573 {
2574 ucNibble = ucByte & 0x0FU;
2575 }
2576
2577 if( ucNibble <= 0x09U )
2578 {
2579 cResult = '0';
2580 cResult = cResult + ucNibble;
2581 }
2582 else
2583 {
2584 cResult = cTen; /* Either 'a' or 'A' */
2585 cResult = cResult + ( ucNibble - 10U );
2586 }
2587
2588 pcTarget[ uxTarget ] = cResult;
2589 uxTarget++;
2590 }
2591
2592 if( uxIndex == ( ipMAC_ADDRESS_LENGTH_BYTES - 1U ) )
2593 {
2594 pcTarget[ uxTarget ] = ( char ) 0;
2595 uxTarget++;
2596 }
2597 else
2598 {
2599 pcTarget[ uxTarget ] = cSeparator;
2600 uxTarget++;
2601 }
2602 }
2603 }
2604 /*-----------------------------------------------------------*/
2605
2606 /**
2607 * @brief This function converts a human readable string, representing an 48-bit MAC address,
2608 * into a 6-byte address. Valid inputs are e.g. "62:48:5:83:A0:b2" and "0-12-34-fe-dc-ba".
2609 *
2610 * @param[in] pcSource: The null terminated string to be parsed.
2611 * @param[out] pucTarget: A buffer that is 6 bytes long, it will contain the MAC address.
2612 *
2613 * @return pdTRUE in case the string got parsed correctly, otherwise pdFALSE.
2614 */
FreeRTOS_EUI48_pton(const char * pcSource,uint8_t * pucTarget)2615 BaseType_t FreeRTOS_EUI48_pton( const char * pcSource,
2616 uint8_t * pucTarget )
2617 {
2618 BaseType_t xResult = pdFALSE;
2619 size_t uxByteNr = 0U;
2620 size_t uxSourceIndex;
2621 size_t uxNibbleCount = 0U;
2622 size_t uxLength = strlen( pcSource );
2623 uint32_t uxSum = 0U;
2624 uint8_t ucHex;
2625 char cChar;
2626
2627 /* Ignore the following line from branch coverage since the exits from this loop are
2628 * covered by break statements. The loop is kept as is to future proof the code against
2629 * any changes. LCOV_EXCL_BR_START */
2630 for( uxSourceIndex = 0U; uxSourceIndex <= uxLength; uxSourceIndex++ )
2631 /* LCOV_EXCL_BR_STOP */
2632 {
2633 cChar = pcSource[ uxSourceIndex ];
2634 ucHex = ucASCIIToHex( cChar );
2635
2636 if( ucHex != socketINVALID_HEX_CHAR )
2637 {
2638 /* A valid nibble was found. Shift it into the accumulator. */
2639 uxSum = uxSum << 4;
2640
2641 if( uxSum > 0xffU )
2642 {
2643 /* A hex value was too big. */
2644 break;
2645 }
2646
2647 uxSum |= ucHex;
2648 uxNibbleCount++;
2649 }
2650 else
2651 {
2652 if( uxNibbleCount != 2U )
2653 {
2654 /* Each number should have 2 nibbles. */
2655 break;
2656 }
2657
2658 pucTarget[ uxByteNr ] = ( uint8_t ) uxSum;
2659 uxSum = 0U;
2660 uxNibbleCount = 0U;
2661 uxByteNr++;
2662
2663 if( uxByteNr == ipMAC_ADDRESS_LENGTH_BYTES )
2664 {
2665 xResult = pdTRUE;
2666 break;
2667 }
2668
2669 if( ( cChar != ':' ) && ( cChar != '-' ) )
2670 {
2671 /* Invalid character. */
2672 break;
2673 }
2674 }
2675 }
2676
2677 return xResult;
2678 }
2679 /*-----------------------------------------------------------*/
2680
2681 /**
2682 * @brief This function converts the character string pcSource into a network address
2683 * structure, then copies the network address structure to pvDestination.
2684 * pvDestination is written in network byte order.
2685 *
2686 * @param[in] pcSource: The character string in holding the IP address.
2687 * @param[out] pvDestination: The returned network address in 32-bit network-endian format.
2688 *
2689 * @return pdPASS if the translation was successful or else pdFAIL.
2690 */
FreeRTOS_inet_pton4(const char * pcSource,void * pvDestination)2691 BaseType_t FreeRTOS_inet_pton4( const char * pcSource,
2692 void * pvDestination )
2693 {
2694 const uint32_t ulDecimalBase = 10U;
2695 uint8_t ucOctet[ socketMAX_IP_ADDRESS_OCTETS ];
2696 uint32_t ulReturn = 0U, ulValue;
2697 UBaseType_t uxOctetNumber;
2698 BaseType_t xResult = pdPASS;
2699 const char * pcIPAddress = pcSource;
2700 const void * pvCopySource;
2701
2702 ( void ) memset( pvDestination, 0, sizeof( ulReturn ) );
2703
2704 /* Translate "192.168.2.100" to a 32-bit number, network-endian. */
2705 for( uxOctetNumber = 0U; uxOctetNumber < socketMAX_IP_ADDRESS_OCTETS; uxOctetNumber++ )
2706 {
2707 ulValue = 0U;
2708
2709 if( pcIPAddress[ 0 ] == '0' )
2710 {
2711 /* Test for the sequence "0[0-9]", which would make it an octal representation. */
2712 if( ( pcIPAddress[ 1 ] >= '0' ) && ( pcIPAddress[ 1 ] <= '9' ) )
2713 {
2714 FreeRTOS_printf( ( "Octal representation of IP-addresses is not supported." ) );
2715 /* Don't support octal numbers. */
2716 xResult = pdFAIL;
2717 break;
2718 }
2719 }
2720
2721 while( ( *pcIPAddress >= '0' ) && ( *pcIPAddress <= '9' ) )
2722 {
2723 BaseType_t xChar;
2724
2725 /* Move previous read characters into the next decimal
2726 * position. */
2727 ulValue *= ulDecimalBase;
2728
2729 /* Add the binary value of the ascii character. */
2730 xChar = ( BaseType_t ) pcIPAddress[ 0 ];
2731 xChar = xChar - ( BaseType_t ) '0';
2732 ulValue += ( uint32_t ) xChar;
2733
2734 /* Move to next character in the string. */
2735 pcIPAddress++;
2736 }
2737
2738 /* Check characters were read. */
2739 if( pcIPAddress == pcSource )
2740 {
2741 xResult = pdFAIL;
2742 }
2743
2744 /* Check the value fits in an 8-bit number. */
2745 if( ulValue > 0xffU )
2746 {
2747 xResult = pdFAIL;
2748 }
2749 else
2750 {
2751 ucOctet[ uxOctetNumber ] = ( uint8_t ) ulValue;
2752
2753 /* Check the next character is as expected. */
2754 if( uxOctetNumber < ( socketMAX_IP_ADDRESS_OCTETS - 1U ) )
2755 {
2756 if( *pcIPAddress != '.' )
2757 {
2758 xResult = pdFAIL;
2759 }
2760 else
2761 {
2762 /* Move past the dot. */
2763 pcIPAddress++;
2764 }
2765 }
2766 }
2767
2768 if( xResult == pdFAIL )
2769 {
2770 /* No point going on. */
2771 break;
2772 }
2773 }
2774
2775 if( *pcIPAddress != ( char ) 0 )
2776 {
2777 /* Expected the end of the string. */
2778 xResult = pdFAIL;
2779 }
2780
2781 if( uxOctetNumber != socketMAX_IP_ADDRESS_OCTETS )
2782 {
2783 /* Didn't read enough octets. */
2784 xResult = pdFAIL;
2785 }
2786
2787 if( xResult == pdPASS )
2788 {
2789 /* lint: ucOctet has been set because xResult == pdPASS. */
2790 ulReturn = FreeRTOS_inet_addr_quick( ucOctet[ 0 ], ucOctet[ 1 ], ucOctet[ 2 ], ucOctet[ 3 ] );
2791 }
2792 else
2793 {
2794 ulReturn = 0U;
2795 }
2796
2797 if( xResult == pdPASS )
2798 {
2799 pvCopySource = ( const void * ) &ulReturn;
2800 ( void ) memcpy( pvDestination, pvCopySource, sizeof( ulReturn ) );
2801 }
2802
2803 return xResult;
2804 }
2805 /*-----------------------------------------------------------*/
2806
2807 /**
2808 * @brief Convert the IP address from "w.x.y.z" (dotted decimal) format to the 32-bit format.
2809 *
2810 * @param[in] pcIPAddress: The character string pointer holding the IP-address in the "W.X.Y.Z"
2811 * (dotted decimal) format.
2812 *
2813 * @return The 32-bit representation of IP(v4) address.
2814 */
FreeRTOS_inet_addr(const char * pcIPAddress)2815 uint32_t FreeRTOS_inet_addr( const char * pcIPAddress )
2816 {
2817 uint32_t ulReturn = 0U;
2818
2819 /* inet_pton AF_INET target is a 4-byte 'struct in_addr'. */
2820 if( pdFAIL == FreeRTOS_inet_pton4( pcIPAddress, &( ulReturn ) ) )
2821 {
2822 /* Return 0 if translation failed. */
2823 ulReturn = 0U;
2824 }
2825
2826 return ulReturn;
2827 }
2828 /*-----------------------------------------------------------*/
2829
2830
2831 /**
2832 * @brief Function to get the local address and IP port of the given socket.
2833 *
2834 * @param[in] xSocket: Socket whose port is to be added to the pxAddress.
2835 * @param[out] pxAddress: Structure in which the IP address and the port number
2836 * is returned.
2837 *
2838 * @return Size of the freertos_sockaddr structure.
2839 */
FreeRTOS_GetLocalAddress(ConstSocket_t xSocket,struct freertos_sockaddr * pxAddress)2840 size_t FreeRTOS_GetLocalAddress( ConstSocket_t xSocket,
2841 struct freertos_sockaddr * pxAddress )
2842 {
2843 const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
2844
2845 /* IP address of local machine. */
2846 pxAddress->sin_addr = *ipLOCAL_IP_ADDRESS_POINTER;
2847
2848 /* Local port on this machine. */
2849 pxAddress->sin_port = FreeRTOS_htons( pxSocket->usLocalPort );
2850
2851 return sizeof( *pxAddress );
2852 }
2853
2854 /*-----------------------------------------------------------*/
2855
2856 /**
2857 * @brief Wake up the user of the given socket through event-groups.
2858 *
2859 * @param[in] pxSocket: The socket whose user is to be woken up.
2860 */
vSocketWakeUpUser(FreeRTOS_Socket_t * pxSocket)2861 void vSocketWakeUpUser( FreeRTOS_Socket_t * pxSocket )
2862 {
2863 /* _HT_ must work this out, now vSocketWakeUpUser will be called for any important
2864 * event or transition */
2865 #if ( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
2866 {
2867 if( pxSocket->pxUserSemaphore != NULL )
2868 {
2869 ( void ) xSemaphoreGive( pxSocket->pxUserSemaphore );
2870 }
2871 }
2872 #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */
2873
2874 #if ( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK == 1 )
2875 {
2876 if( pxSocket->pxUserWakeCallback != NULL )
2877 {
2878 pxSocket->pxUserWakeCallback( pxSocket );
2879 }
2880 }
2881 #endif /* ipconfigSOCKET_HAS_USER_WAKE_CALLBACK */
2882
2883 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
2884 {
2885 if( pxSocket->pxSocketSet != NULL )
2886 {
2887 EventBits_t xSelectBits = ( pxSocket->xEventBits >> SOCKET_EVENT_BIT_COUNT ) & ( ( EventBits_t ) eSELECT_ALL );
2888
2889 if( xSelectBits != 0U )
2890 {
2891 pxSocket->xSocketBits |= xSelectBits;
2892 ( void ) xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, xSelectBits );
2893 }
2894 }
2895
2896 pxSocket->xEventBits &= ( EventBits_t ) eSOCKET_ALL;
2897 }
2898 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
2899
2900 if( ( pxSocket->xEventGroup != NULL ) && ( pxSocket->xEventBits != 0U ) )
2901 {
2902 ( void ) xEventGroupSetBits( pxSocket->xEventGroup, pxSocket->xEventBits );
2903 }
2904
2905 pxSocket->xEventBits = 0U;
2906 }
2907
2908 /*-----------------------------------------------------------*/
2909
2910 #if ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 )
2911
2912 /**
2913 * @brief This define makes it possible for network interfaces to inspect
2914 * UDP messages and see if there is any UDP socket bound to a given port
2915 * number. This is probably only useful in systems with a minimum of
2916 * RAM and when lots of anonymous broadcast messages come in.
2917 *
2918 * @param[in] usPortNr: the port number to look for.
2919 *
2920 * @return xFound if a socket with the port number is found.
2921 */
xPortHasUDPSocket(uint16_t usPortNr)2922 BaseType_t xPortHasUDPSocket( uint16_t usPortNr )
2923 {
2924 BaseType_t xFound = pdFALSE;
2925
2926 vTaskSuspendAll();
2927 {
2928 if( ( pxListFindListItemWithValue( &xBoundUDPSocketsList, ( TickType_t ) usPortNr ) != NULL ) )
2929 {
2930 xFound = pdTRUE;
2931 }
2932 }
2933 ( void ) xTaskResumeAll();
2934
2935 return xFound;
2936 }
2937
2938 #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
2939
2940 /*-----------------------------------------------------------*/
2941
2942 #if ( ipconfigUSE_TCP == 1 )
2943
2944 /**
2945 * @brief Check if it makes any sense to wait for a connect event.
2946 *
2947 * @param[in] pxSocket: The socket trying to connect.
2948 *
2949 * @return It may return: -EINPROGRESS, -EAGAIN, or 0 for OK.
2950 */
bMayConnect(FreeRTOS_Socket_t const * pxSocket)2951 static BaseType_t bMayConnect( FreeRTOS_Socket_t const * pxSocket )
2952 {
2953 BaseType_t xResult;
2954
2955 eIPTCPState_t eState = pxSocket->u.xTCP.eTCPState;
2956
2957 switch( eState )
2958 {
2959 case eCLOSED:
2960 case eCLOSE_WAIT:
2961 xResult = 0;
2962 break;
2963
2964 case eCONNECT_SYN:
2965 xResult = -pdFREERTOS_ERRNO_EINPROGRESS;
2966 break;
2967
2968 case eTCP_LISTEN:
2969 case eSYN_FIRST:
2970 case eSYN_RECEIVED:
2971 case eESTABLISHED:
2972 case eFIN_WAIT_1:
2973 case eFIN_WAIT_2:
2974 case eCLOSING:
2975 case eLAST_ACK:
2976 case eTIME_WAIT:
2977 default:
2978 xResult = -pdFREERTOS_ERRNO_EAGAIN;
2979 break;
2980 }
2981
2982 return xResult;
2983 }
2984
2985
2986 #endif /* ipconfigUSE_TCP */
2987 /*-----------------------------------------------------------*/
2988
2989 #if ( ipconfigUSE_TCP == 1 )
2990
2991 /**
2992 * @brief Called from #FreeRTOS_connect(): make some checks and if allowed,
2993 * send a message to the IP-task to start connecting to a remote socket.
2994 *
2995 * @param[in] pxSocket: The socket attempting to connect to a remote port.
2996 * @param[in] pxAddress: The address the socket is trying to connect to.
2997 *
2998 * @return 0 on successful checks or a negative error code.
2999 */
prvTCPConnectStart(FreeRTOS_Socket_t * pxSocket,struct freertos_sockaddr const * pxAddress)3000 static BaseType_t prvTCPConnectStart( FreeRTOS_Socket_t * pxSocket,
3001 struct freertos_sockaddr const * pxAddress )
3002 {
3003 BaseType_t xResult = 0;
3004
3005 if( pxAddress == NULL )
3006 {
3007 /* NULL address passed to the function. Invalid value. */
3008 xResult = -pdFREERTOS_ERRNO_EINVAL;
3009 }
3010 else if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdFALSE )
3011 {
3012 /* Not a valid socket or wrong type */
3013 xResult = -pdFREERTOS_ERRNO_EBADF;
3014 }
3015 else if( FreeRTOS_issocketconnected( pxSocket ) > 0 )
3016 {
3017 /* The socket is already connected. */
3018 xResult = -pdFREERTOS_ERRNO_EISCONN;
3019 }
3020 else if( !socketSOCKET_IS_BOUND( pxSocket ) )
3021 {
3022 /* Bind the socket to the port that the client task will send from.
3023 * Non-standard, so the error returned is that returned by bind(). */
3024 xResult = FreeRTOS_bind( pxSocket, NULL, 0U );
3025 }
3026 else
3027 {
3028 /* The socket is valid, not yet connected, and already bound to a port number. */
3029 }
3030
3031 if( xResult == 0 )
3032 {
3033 /* Check if it makes any sense to wait for a connect event, this condition
3034 * might change while sleeping, so it must be checked within each loop */
3035 xResult = bMayConnect( pxSocket ); /* -EINPROGRESS, -EAGAIN, or 0 for OK */
3036
3037 /* Start the connect procedure, kernel will start working on it */
3038 if( xResult == 0 )
3039 {
3040 pxSocket->u.xTCP.bits.bConnPrepared = pdFALSE;
3041 pxSocket->u.xTCP.ucRepCount = 0U;
3042
3043 FreeRTOS_debug_printf( ( "FreeRTOS_connect: %u to %xip:%u\n",
3044 pxSocket->usLocalPort, ( unsigned ) FreeRTOS_ntohl( pxAddress->sin_addr ), FreeRTOS_ntohs( pxAddress->sin_port ) ) );
3045
3046 /* Port on remote machine. */
3047 pxSocket->u.xTCP.usRemotePort = FreeRTOS_ntohs( pxAddress->sin_port );
3048
3049 /* IP address of remote machine. */
3050 pxSocket->u.xTCP.ulRemoteIP = FreeRTOS_ntohl( pxAddress->sin_addr );
3051
3052 /* (client) internal state: socket wants to send a connect. */
3053 vTCPStateChange( pxSocket, eCONNECT_SYN );
3054
3055 /* To start an active connect. */
3056 pxSocket->u.xTCP.usTimeout = 1U;
3057
3058 if( xSendEventToIPTask( eTCPTimerEvent ) != pdPASS )
3059 {
3060 xResult = -pdFREERTOS_ERRNO_ECANCELED;
3061 }
3062 }
3063 }
3064
3065 return xResult;
3066 }
3067
3068
3069 #endif /* ipconfigUSE_TCP */
3070 /*-----------------------------------------------------------*/
3071
3072 #if ( ipconfigUSE_TCP == 1 )
3073
3074 /**
3075 * @brief Connect to a remote port.
3076 *
3077 * @param[in] xClientSocket: The socket initiating the connection.
3078 * @param[in] pxAddress: The address of the remote socket.
3079 * @param[in] xAddressLength: This parameter is not used. It is kept in
3080 * the function signature to adhere to the Berkeley
3081 * sockets standard.
3082 *
3083 * @return 0 is returned on a successful connection, else a negative
3084 * error code is returned.
3085 */
FreeRTOS_connect(Socket_t xClientSocket,const struct freertos_sockaddr * pxAddress,socklen_t xAddressLength)3086 BaseType_t FreeRTOS_connect( Socket_t xClientSocket,
3087 const struct freertos_sockaddr * pxAddress,
3088 socklen_t xAddressLength )
3089 {
3090 FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xClientSocket;
3091 TickType_t xRemainingTime;
3092 BaseType_t xTimed = pdFALSE;
3093 BaseType_t xResult = -pdFREERTOS_ERRNO_EINVAL;
3094 TimeOut_t xTimeOut;
3095
3096 ( void ) xAddressLength;
3097
3098 xResult = prvTCPConnectStart( pxSocket, pxAddress );
3099
3100 if( xResult == 0 )
3101 {
3102 /* And wait for the result */
3103 for( ; ; )
3104 {
3105 EventBits_t uxEvents;
3106
3107 if( xTimed == pdFALSE )
3108 {
3109 /* Only in the first round, check for non-blocking */
3110 xRemainingTime = pxSocket->xReceiveBlockTime;
3111
3112 if( xRemainingTime == ( TickType_t ) 0 )
3113 {
3114 /* Not yet connected, correct state, non-blocking. */
3115 xResult = -pdFREERTOS_ERRNO_EWOULDBLOCK;
3116 break;
3117 }
3118
3119 /* Don't get here a second time. */
3120 xTimed = pdTRUE;
3121
3122 /* Fetch the current time */
3123 vTaskSetTimeOutState( &xTimeOut );
3124 }
3125
3126 /* Did it get connected while sleeping ? */
3127 xResult = FreeRTOS_issocketconnected( pxSocket );
3128
3129 if( xResult > 0 )
3130 {
3131 /* Socket now connected, return a zero */
3132 xResult = 0;
3133 break;
3134 }
3135
3136 /* Is it allowed to sleep more? */
3137 if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
3138 {
3139 xResult = -pdFREERTOS_ERRNO_ETIMEDOUT;
3140 break;
3141 }
3142
3143 /* Go sleeping until we get any down-stream event */
3144 uxEvents = xEventGroupWaitBits( pxSocket->xEventGroup,
3145 ( EventBits_t ) eSOCKET_CONNECT | ( EventBits_t ) eSOCKET_CLOSED,
3146 pdTRUE /*xClearOnExit*/,
3147 pdFALSE /*xWaitAllBits*/,
3148 xRemainingTime );
3149
3150 if( ( uxEvents & eSOCKET_CLOSED ) != 0U )
3151 {
3152 xResult = -pdFREERTOS_ERRNO_ENOTCONN;
3153 FreeRTOS_debug_printf( ( "FreeRTOS_connect() stopped due to an error\n" ) );
3154 break;
3155 }
3156 }
3157 }
3158
3159 return xResult;
3160 }
3161
3162 #endif /* ipconfigUSE_TCP */
3163 /*-----------------------------------------------------------*/
3164
3165 #if ( ipconfigUSE_TCP == 1 )
3166
3167 /**
3168 * @brief Accept a connection on an listening socket.
3169 *
3170 * @param[in] xServerSocket: The socket in listening mode.
3171 * @param[out] pxAddress: The address of the machine trying to connect to this node
3172 * is returned in this pointer.
3173 * @param[out] pxAddressLength: The length of the address of the remote machine.
3174 *
3175 * @return FreeRTOS_accept: can return a new connected socket if the server socket
3176 * is in listen mode and receives a connection request. The new socket will
3177 * be bound already to the same port number as the listening socket.
3178 */
FreeRTOS_accept(Socket_t xServerSocket,struct freertos_sockaddr * pxAddress,socklen_t * pxAddressLength)3179 Socket_t FreeRTOS_accept( Socket_t xServerSocket,
3180 struct freertos_sockaddr * pxAddress,
3181 socklen_t * pxAddressLength )
3182 {
3183 FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xServerSocket;
3184 FreeRTOS_Socket_t * pxClientSocket = NULL;
3185 TickType_t xRemainingTime;
3186 BaseType_t xTimed = pdFALSE, xAsk = pdFALSE;
3187 TimeOut_t xTimeOut;
3188 IPStackEvent_t xAskEvent;
3189
3190 if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
3191 {
3192 /* Not a valid socket or wrong type */
3193
3194 /* MISRA Ref 11.4.1 [Socket error and integer to pointer conversion] */
3195 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */
3196 /* coverity[misra_c_2012_rule_11_4_violation] */
3197 pxClientSocket = FREERTOS_INVALID_SOCKET;
3198 }
3199 else if( ( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) &&
3200 ( pxSocket->u.xTCP.eTCPState != eTCP_LISTEN ) )
3201 {
3202 /* Parent socket is not in listening mode */
3203
3204 /* MISRA Ref 11.4.1 [Socket error and integer to pointer conversion] */
3205 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */
3206 /* coverity[misra_c_2012_rule_11_4_violation] */
3207 pxClientSocket = FREERTOS_INVALID_SOCKET;
3208 }
3209 else
3210 {
3211 /* Loop will stop with breaks. */
3212 for( ; ; )
3213 {
3214 /* Is there a new client? */
3215 vTaskSuspendAll();
3216 {
3217 if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
3218 {
3219 pxClientSocket = pxSocket->u.xTCP.pxPeerSocket;
3220 }
3221 else
3222 {
3223 pxClientSocket = pxSocket;
3224 }
3225
3226 if( pxClientSocket != NULL )
3227 {
3228 pxSocket->u.xTCP.pxPeerSocket = NULL;
3229
3230 /* Is it still not taken ? */
3231 if( pxClientSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED )
3232 {
3233 pxClientSocket->u.xTCP.bits.bPassAccept = pdFALSE;
3234 }
3235 else
3236 {
3237 pxClientSocket = NULL;
3238 }
3239 }
3240 }
3241 ( void ) xTaskResumeAll();
3242
3243 if( pxClientSocket != NULL )
3244 {
3245 if( pxAddress != NULL )
3246 {
3247 /* IP address of remote machine. */
3248 pxAddress->sin_addr = FreeRTOS_ntohl( pxClientSocket->u.xTCP.ulRemoteIP );
3249
3250 /* Port on remote machine. */
3251 pxAddress->sin_port = FreeRTOS_ntohs( pxClientSocket->u.xTCP.usRemotePort );
3252 }
3253
3254 if( pxAddressLength != NULL )
3255 {
3256 *pxAddressLength = ( socklen_t ) sizeof( *pxAddress );
3257 }
3258
3259 if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED )
3260 {
3261 xAsk = pdTRUE;
3262 }
3263 }
3264
3265 if( xAsk != pdFALSE )
3266 {
3267 /* Ask to set an event in 'xEventGroup' as soon as a new
3268 * client gets connected for this listening socket. */
3269 xAskEvent.eEventType = eTCPAcceptEvent;
3270 xAskEvent.pvData = pxSocket;
3271 ( void ) xSendEventStructToIPTask( &xAskEvent, portMAX_DELAY );
3272 }
3273
3274 if( pxClientSocket != NULL )
3275 {
3276 break;
3277 }
3278
3279 if( xTimed == pdFALSE )
3280 {
3281 /* Only in the first round, check for non-blocking */
3282 xRemainingTime = pxSocket->xReceiveBlockTime;
3283
3284 if( xRemainingTime == ( TickType_t ) 0 )
3285 {
3286 break;
3287 }
3288
3289 /* Don't get here a second time */
3290 xTimed = pdTRUE;
3291
3292 /* Fetch the current time */
3293 vTaskSetTimeOutState( &xTimeOut );
3294 }
3295
3296 /* Has the timeout been reached? */
3297 if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
3298 {
3299 break;
3300 }
3301
3302 /* Put the calling task to 'sleep' until a down-stream event is received. */
3303 ( void ) xEventGroupWaitBits( pxSocket->xEventGroup,
3304 ( EventBits_t ) eSOCKET_ACCEPT,
3305 pdTRUE /*xClearOnExit*/,
3306 pdFALSE /*xWaitAllBits*/,
3307 xRemainingTime );
3308 }
3309 }
3310
3311 return pxClientSocket;
3312 }
3313
3314 #endif /* ipconfigUSE_TCP */
3315 /*-----------------------------------------------------------*/
3316
3317 #if ( ipconfigUSE_TCP == 1 )
3318
3319 /**
3320 * @brief Read incoming data from a TCP socket. Only after the last
3321 * byte has been read, a close error might be returned.
3322 *
3323 * @param[in] xSocket: The socket owning the connection.
3324 * @param[out] pvBuffer: The buffer to store the incoming data in.
3325 * @param[in] uxBufferLength: The length of the buffer so that the function
3326 * does not do out of bound access.
3327 * @param[in] xFlags: The flags for conveying preference. The values
3328 * FREERTOS_MSG_DONTWAIT, FREERTOS_ZERO_COPY and/or
3329 * FREERTOS_MSG_PEEK can be used.
3330 *
3331 * @return The number of bytes actually received and stored in the pvBuffer.
3332 */
FreeRTOS_recv(Socket_t xSocket,void * pvBuffer,size_t uxBufferLength,BaseType_t xFlags)3333 BaseType_t FreeRTOS_recv( Socket_t xSocket,
3334 void * pvBuffer,
3335 size_t uxBufferLength,
3336 BaseType_t xFlags )
3337 {
3338 BaseType_t xByteCount;
3339 FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
3340 TickType_t xRemainingTime;
3341 BaseType_t xTimed = pdFALSE;
3342 TimeOut_t xTimeOut;
3343 EventBits_t xEventBits = ( EventBits_t ) 0;
3344
3345 /* Check if the socket is valid, has type TCP and if it is bound to a
3346 * port. */
3347 if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
3348 {
3349 xByteCount = -pdFREERTOS_ERRNO_EINVAL;
3350 }
3351 else if( ( ( ( uint32_t ) xFlags & ( uint32_t ) FREERTOS_ZERO_COPY ) != 0U ) &&
3352 ( pvBuffer == NULL ) )
3353 {
3354 /* In zero-copy mode, pvBuffer is a pointer to a pointer ( not NULL ). */
3355 xByteCount = -pdFREERTOS_ERRNO_EINVAL;
3356 }
3357 else
3358 {
3359 if( pxSocket->u.xTCP.rxStream != NULL )
3360 {
3361 xByteCount = ( BaseType_t ) uxStreamBufferGetSize( pxSocket->u.xTCP.rxStream );
3362 }
3363 else
3364 {
3365 xByteCount = 0;
3366 }
3367
3368 while( xByteCount == 0 )
3369 {
3370 eIPTCPState_t eState = pxSocket->u.xTCP.eTCPState;
3371
3372 switch( eState )
3373 {
3374 case eCLOSED:
3375 case eCLOSE_WAIT: /* (server + client) waiting for a connection termination request from the local user. */
3376 case eCLOSING: /* (server + client) waiting for a connection termination request acknowledgement from the remote TCP. */
3377
3378 if( pxSocket->u.xTCP.bits.bMallocError != pdFALSE_UNSIGNED )
3379 {
3380 /* The no-memory error has priority above the non-connected error.
3381 * Both are fatal and will lead to closing the socket. */
3382 xByteCount = -pdFREERTOS_ERRNO_ENOMEM;
3383 }
3384 else
3385 {
3386 xByteCount = -pdFREERTOS_ERRNO_ENOTCONN;
3387 }
3388
3389 break;
3390
3391 case eTCP_LISTEN:
3392 case eCONNECT_SYN:
3393 case eSYN_FIRST:
3394 case eSYN_RECEIVED:
3395 case eESTABLISHED:
3396 case eFIN_WAIT_1:
3397 case eFIN_WAIT_2:
3398 case eLAST_ACK:
3399 case eTIME_WAIT:
3400 default:
3401 /* Nothing. */
3402 break;
3403 }
3404
3405 if( xByteCount < 0 )
3406 {
3407 break;
3408 }
3409
3410 if( xTimed == pdFALSE )
3411 {
3412 /* Only in the first round, check for non-blocking. */
3413 xRemainingTime = pxSocket->xReceiveBlockTime;
3414
3415 if( xRemainingTime == ( TickType_t ) 0 )
3416 {
3417 #if ( ipconfigSUPPORT_SIGNALS != 0 )
3418 {
3419 /* Just check for the interrupt flag. */
3420 xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_INTR,
3421 pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, socketDONT_BLOCK );
3422 }
3423 #endif /* ipconfigSUPPORT_SIGNALS */
3424 break;
3425 }
3426
3427 if( ( ( uint32_t ) xFlags & ( uint32_t ) FREERTOS_MSG_DONTWAIT ) != 0U )
3428 {
3429 break;
3430 }
3431
3432 /* Don't get here a second time. */
3433 xTimed = pdTRUE;
3434
3435 /* Fetch the current time. */
3436 vTaskSetTimeOutState( &xTimeOut );
3437 }
3438
3439 /* Has the timeout been reached? */
3440 if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
3441 {
3442 break;
3443 }
3444
3445 /* Block until there is a down-stream event. */
3446 xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup,
3447 ( EventBits_t ) eSOCKET_RECEIVE | ( EventBits_t ) eSOCKET_CLOSED | ( EventBits_t ) eSOCKET_INTR,
3448 pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );
3449 #if ( ipconfigSUPPORT_SIGNALS != 0 )
3450 {
3451 if( ( xEventBits & ( EventBits_t ) eSOCKET_INTR ) != 0U )
3452 {
3453 break;
3454 }
3455 }
3456 #else
3457 {
3458 ( void ) xEventBits;
3459 }
3460 #endif /* ipconfigSUPPORT_SIGNALS */
3461
3462 if( pxSocket->u.xTCP.rxStream != NULL )
3463 {
3464 xByteCount = ( BaseType_t ) uxStreamBufferGetSize( pxSocket->u.xTCP.rxStream );
3465 }
3466 else
3467 {
3468 xByteCount = 0;
3469 }
3470 }
3471
3472 #if ( ipconfigSUPPORT_SIGNALS != 0 )
3473 if( ( xEventBits & ( EventBits_t ) eSOCKET_INTR ) != 0U )
3474 {
3475 if( ( xEventBits & ( ( EventBits_t ) eSOCKET_RECEIVE | ( EventBits_t ) eSOCKET_CLOSED ) ) != 0U )
3476 {
3477 /* Shouldn't have cleared other flags. */
3478 xEventBits &= ~( ( EventBits_t ) eSOCKET_INTR );
3479 ( void ) xEventGroupSetBits( pxSocket->xEventGroup, xEventBits );
3480 }
3481
3482 xByteCount = -pdFREERTOS_ERRNO_EINTR;
3483 }
3484 else
3485 #endif /* ipconfigSUPPORT_SIGNALS */
3486
3487 if( xByteCount > 0 )
3488 {
3489 if( ( ( uint32_t ) xFlags & ( uint32_t ) FREERTOS_ZERO_COPY ) == 0U )
3490 {
3491 BaseType_t xIsPeek = ( ( ( uint32_t ) xFlags & ( uint32_t ) FREERTOS_MSG_PEEK ) != 0U ) ? 1L : 0L;
3492
3493 xByteCount = ( BaseType_t )
3494 uxStreamBufferGet( pxSocket->u.xTCP.rxStream,
3495 0U,
3496 ( uint8_t * ) pvBuffer,
3497 ( size_t ) uxBufferLength,
3498 xIsPeek );
3499
3500 if( pxSocket->u.xTCP.bits.bLowWater != pdFALSE_UNSIGNED )
3501 {
3502 /* We had reached the low-water mark, now see if the flag
3503 * can be cleared */
3504 size_t uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
3505
3506 if( uxFrontSpace >= pxSocket->u.xTCP.uxEnoughSpace )
3507 {
3508 pxSocket->u.xTCP.bits.bLowWater = pdFALSE;
3509 pxSocket->u.xTCP.bits.bWinChange = pdTRUE;
3510 pxSocket->u.xTCP.usTimeout = 1U; /* because bLowWater is cleared. */
3511 ( void ) xSendEventToIPTask( eTCPTimerEvent );
3512 }
3513 }
3514 }
3515 else
3516 {
3517 /* Zero-copy reception of data: pvBuffer is a pointer to a pointer. */
3518 xByteCount = ( BaseType_t ) uxStreamBufferGetPtr( pxSocket->u.xTCP.rxStream, ( uint8_t ** ) pvBuffer );
3519 }
3520 }
3521 else
3522 {
3523 /* Nothing. */
3524 }
3525 } /* prvValidSocket() */
3526
3527 return xByteCount;
3528 }
3529
3530
3531 #endif /* ipconfigUSE_TCP */
3532 /*-----------------------------------------------------------*/
3533
3534 #if ( ipconfigUSE_TCP == 1 )
3535
3536 /**
3537 * @brief Called from FreeRTOS_send(): some checks which will be done before
3538 * sending a TCP packed.
3539 *
3540 * @param[in] pxSocket: The socket owning the connection.
3541 * @param[in] uxDataLength: The length of the data to be sent.
3542 *
3543 * @return 0: representing OK, else a negative error code will be returned.
3544 */
prvTCPSendCheck(FreeRTOS_Socket_t * pxSocket,size_t uxDataLength)3545 static int32_t prvTCPSendCheck( FreeRTOS_Socket_t * pxSocket,
3546 size_t uxDataLength )
3547 {
3548 int32_t xResult = 1;
3549
3550 /* Is this a socket of type TCP and is it already bound to a port number ? */
3551 if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
3552 {
3553 xResult = -pdFREERTOS_ERRNO_EINVAL;
3554 }
3555 else if( pxSocket->u.xTCP.bits.bMallocError != pdFALSE_UNSIGNED )
3556 {
3557 xResult = -pdFREERTOS_ERRNO_ENOMEM;
3558 }
3559 else if( ( pxSocket->u.xTCP.eTCPState == eCLOSED ) ||
3560 ( pxSocket->u.xTCP.eTCPState == eCLOSE_WAIT ) ||
3561 ( pxSocket->u.xTCP.eTCPState == eCLOSING ) )
3562 {
3563 xResult = -pdFREERTOS_ERRNO_ENOTCONN;
3564 }
3565 else if( pxSocket->u.xTCP.bits.bFinSent != pdFALSE_UNSIGNED )
3566 {
3567 /* This TCP connection is closing already, the FIN flag has been sent.
3568 * Maybe it is still delivering or receiving data.
3569 * Return OK in order not to get closed/deleted too quickly */
3570 xResult = 0;
3571 }
3572 else if( uxDataLength == 0U )
3573 {
3574 /* send() is being called to send zero bytes */
3575 xResult = 0;
3576 }
3577 else if( pxSocket->u.xTCP.txStream == NULL )
3578 {
3579 /* Create the outgoing stream only when it is needed */
3580 ( void ) prvTCPCreateStream( pxSocket, pdFALSE );
3581
3582 if( pxSocket->u.xTCP.txStream == NULL )
3583 {
3584 xResult = -pdFREERTOS_ERRNO_ENOMEM;
3585 }
3586 }
3587 else
3588 {
3589 /* Nothing. */
3590 }
3591
3592 return xResult;
3593 }
3594
3595 #endif /* ipconfigUSE_TCP */
3596 /*-----------------------------------------------------------*/
3597
3598 #if ( ipconfigUSE_TCP == 1 )
3599
3600 /**
3601 * @brief Get a direct pointer to the circular transmit buffer.
3602 *
3603 * @param[in] xSocket: The socket owning the buffer.
3604 * @param[in] pxLength: This will contain the number of bytes that may be written.
3605 *
3606 * @return Head of the circular transmit buffer if all checks pass. Or else, NULL
3607 * is returned.
3608 */
FreeRTOS_get_tx_head(ConstSocket_t xSocket,BaseType_t * pxLength)3609 uint8_t * FreeRTOS_get_tx_head( ConstSocket_t xSocket,
3610 BaseType_t * pxLength )
3611 {
3612 uint8_t * pucReturn = NULL;
3613 const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
3614 StreamBuffer_t * pxBuffer = NULL;
3615
3616 *pxLength = 0;
3617
3618 /* Confirm that this is a TCP socket before dereferencing structure
3619 * member pointers. */
3620 if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdTRUE )
3621 {
3622 pxBuffer = pxSocket->u.xTCP.txStream;
3623
3624 if( pxBuffer != NULL )
3625 {
3626 size_t uxSpace = uxStreamBufferGetSpace( pxBuffer );
3627 size_t uxRemain = pxBuffer->LENGTH - pxBuffer->uxHead;
3628
3629 if( uxRemain <= uxSpace )
3630 {
3631 *pxLength = ( BaseType_t ) uxRemain;
3632 }
3633 else
3634 {
3635 *pxLength = ( BaseType_t ) uxSpace;
3636 }
3637
3638 pucReturn = &( pxBuffer->ucArray[ pxBuffer->uxHead ] );
3639 }
3640 }
3641
3642 return pucReturn;
3643 }
3644 #endif /* ipconfigUSE_TCP */
3645 /*-----------------------------------------------------------*/
3646
3647 #if ( ipconfigUSE_TCP == 1 )
3648
3649 /**
3650 * @brief Send data using a TCP socket. It is not necessary to have the socket
3651 * connected already. Outgoing data will be stored and delivered as soon as
3652 * the socket gets connected.
3653 *
3654 * @param[in] xSocket: The socket owning the connection.
3655 * @param[in] pvBuffer: The buffer containing the data. The value of this pointer
3656 * may be NULL in case zero-copy transmissions are used.
3657 * It is used in combination with 'FreeRTOS_get_tx_head()'.
3658 * @param[in] uxDataLength: The length of the data to be added.
3659 * @param[in] xFlags: This parameter is not used. (zero or FREERTOS_MSG_DONTWAIT).
3660 *
3661 * @return The number of bytes actually sent. Zero when nothing could be sent
3662 * or a negative error code in case an error occurred.
3663 */
FreeRTOS_send(Socket_t xSocket,const void * pvBuffer,size_t uxDataLength,BaseType_t xFlags)3664 BaseType_t FreeRTOS_send( Socket_t xSocket,
3665 const void * pvBuffer,
3666 size_t uxDataLength,
3667 BaseType_t xFlags )
3668 {
3669 BaseType_t xByteCount;
3670 BaseType_t xBytesLeft;
3671 FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
3672 TickType_t xRemainingTime;
3673 BaseType_t xTimed = pdFALSE;
3674 TimeOut_t xTimeOut;
3675 BaseType_t xCloseAfterSend;
3676 const uint8_t * pucSource = ( const uint8_t * ) pvBuffer;
3677
3678 /* Prevent compiler warnings about unused parameters. The parameter
3679 * may be used in future versions. */
3680 ( void ) xFlags;
3681
3682 xByteCount = ( BaseType_t ) prvTCPSendCheck( pxSocket, uxDataLength );
3683
3684 if( xByteCount > 0 )
3685 {
3686 /* xBytesLeft is number of bytes to send, will count to zero. */
3687 xBytesLeft = ( BaseType_t ) uxDataLength;
3688
3689 /* xByteCount is number of bytes that can be sent now. */
3690 xByteCount = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream );
3691
3692 /* Try sending till there is a timeout or all bytes have been sent. */
3693 while( ipTRUE_BOOL )
3694 {
3695 /* If txStream has space. */
3696 if( xByteCount > 0 )
3697 {
3698 /* Don't send more than necessary. */
3699 if( xByteCount > xBytesLeft )
3700 {
3701 xByteCount = xBytesLeft;
3702 }
3703
3704 /* Is the close-after-send flag set and is this really the
3705 * last transmission? */
3706 if( ( pxSocket->u.xTCP.bits.bCloseAfterSend != pdFALSE_UNSIGNED ) && ( xByteCount == xBytesLeft ) )
3707 {
3708 xCloseAfterSend = pdTRUE;
3709 }
3710 else
3711 {
3712 xCloseAfterSend = pdFALSE;
3713 }
3714
3715 /* The flag 'bCloseAfterSend' can be set before sending data
3716 * using setsockopt()
3717 *
3718 * When the last data packet is being sent out, a FIN flag will
3719 * be included to let the peer know that no more data is to be
3720 * expected. The use of 'bCloseAfterSend' is not mandatory, it
3721 * is just a faster way of transferring files (e.g. when using
3722 * FTP). */
3723 if( xCloseAfterSend != pdFALSE )
3724 {
3725 /* Now suspend the scheduler: sending the last data and
3726 * setting bCloseRequested must be done together */
3727 vTaskSuspendAll();
3728 pxSocket->u.xTCP.bits.bCloseRequested = pdTRUE;
3729 }
3730
3731 xByteCount = ( BaseType_t ) uxStreamBufferAdd( pxSocket->u.xTCP.txStream, 0U, pucSource, ( size_t ) xByteCount );
3732
3733 if( xCloseAfterSend != pdFALSE )
3734 {
3735 /* Now when the IP-task transmits the data, it will also
3736 * see that bCloseRequested is true and include the FIN
3737 * flag to start closure of the connection. */
3738 ( void ) xTaskResumeAll();
3739 }
3740
3741 /* Send a message to the IP-task so it can work on this
3742 * socket. Data is sent, let the IP-task work on it. */
3743 pxSocket->u.xTCP.usTimeout = 1U;
3744
3745 if( xIsCallingFromIPTask() == pdFALSE )
3746 {
3747 /* Only send a TCP timer event when not called from the
3748 * IP-task. */
3749 ( void ) xSendEventToIPTask( eTCPTimerEvent );
3750 }
3751
3752 xBytesLeft -= xByteCount;
3753
3754 if( ( xBytesLeft == 0 ) || ( pvBuffer == NULL ) )
3755 {
3756 /* pvBuffer can be NULL in case TCP zero-copy transmissions are used. */
3757 break;
3758 }
3759
3760 /* As there are still bytes left to be sent, increase the
3761 * data pointer. */
3762 pucSource = &( pucSource[ xByteCount ] );
3763 }
3764
3765 /* Not all bytes have been sent. In case the socket is marked as
3766 * blocking sleep for a while. */
3767 if( xTimed == pdFALSE )
3768 {
3769 /* Only in the first round, check for non-blocking. */
3770 xRemainingTime = pxSocket->xSendBlockTime;
3771
3772 #if ( ipconfigUSE_CALLBACKS != 0 )
3773 {
3774 if( xIsCallingFromIPTask() != pdFALSE )
3775 {
3776 /* If this send function is called from within a
3777 * call-back handler it may not block, otherwise
3778 * chances would be big to get a deadlock: the IP-task
3779 * waiting for itself. */
3780 xRemainingTime = ( TickType_t ) 0;
3781 }
3782 }
3783 #endif /* ipconfigUSE_CALLBACKS */
3784
3785 if( xRemainingTime == ( TickType_t ) 0 )
3786 {
3787 break;
3788 }
3789
3790 if( ( ( uint32_t ) xFlags & ( uint32_t ) FREERTOS_MSG_DONTWAIT ) != 0U )
3791 {
3792 break;
3793 }
3794
3795 /* Don't get here a second time. */
3796 xTimed = pdTRUE;
3797
3798 /* Fetch the current time. */
3799 vTaskSetTimeOutState( &xTimeOut );
3800 }
3801 else
3802 {
3803 /* Has the timeout been reached? */
3804 if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE )
3805 {
3806 break;
3807 }
3808 }
3809
3810 /* Go sleeping until down-stream events are received. */
3811 ( void ) xEventGroupWaitBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_SEND | ( EventBits_t ) eSOCKET_CLOSED,
3812 pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime );
3813
3814 xByteCount = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream );
3815 }
3816
3817 /* How much was actually sent? */
3818 xByteCount = ( ( BaseType_t ) uxDataLength ) - xBytesLeft;
3819
3820 if( xByteCount == 0 )
3821 {
3822 if( pxSocket->u.xTCP.eTCPState > eESTABLISHED )
3823 {
3824 xByteCount = ( BaseType_t ) -pdFREERTOS_ERRNO_ENOTCONN;
3825 }
3826 else
3827 {
3828 if( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) )
3829 {
3830 FreeRTOS_debug_printf( ( "FreeRTOS_send: %u -> %xip:%d: no space\n",
3831 pxSocket->usLocalPort,
3832 ( unsigned ) pxSocket->u.xTCP.ulRemoteIP,
3833 pxSocket->u.xTCP.usRemotePort ) );
3834 }
3835
3836 xByteCount = ( BaseType_t ) -pdFREERTOS_ERRNO_ENOSPC;
3837 }
3838 }
3839 }
3840
3841 return xByteCount;
3842 }
3843
3844
3845 #endif /* ipconfigUSE_TCP */
3846 /*-----------------------------------------------------------*/
3847
3848 #if ( ipconfigUSE_TCP == 1 )
3849
3850 /**
3851 * @brief Request to put a socket in listen mode.
3852 *
3853 * @param[in] xSocket: the socket to be put in listening mode.
3854 * @param[in] xBacklog: Maximum number of child sockets.
3855 *
3856 * @return 0 in case of success, or else a negative error code is
3857 * returned.
3858 */
FreeRTOS_listen(Socket_t xSocket,BaseType_t xBacklog)3859 BaseType_t FreeRTOS_listen( Socket_t xSocket,
3860 BaseType_t xBacklog )
3861 {
3862 FreeRTOS_Socket_t * pxSocket;
3863 BaseType_t xResult = 0;
3864
3865 pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
3866
3867 /* listen() is allowed for a valid TCP socket in Closed state and already
3868 * bound. */
3869 if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
3870 {
3871 xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP;
3872 }
3873 else if( ( pxSocket->u.xTCP.eTCPState != eCLOSED ) && ( pxSocket->u.xTCP.eTCPState != eCLOSE_WAIT ) )
3874 {
3875 /* Socket is in a wrong state. */
3876 xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP;
3877 }
3878 else
3879 {
3880 /* Backlog is interpreted here as "the maximum number of child
3881 * sockets. */
3882 pxSocket->u.xTCP.usBacklog = ( uint16_t ) FreeRTOS_min_int32( ( int32_t ) 0xffff, ( int32_t ) xBacklog );
3883
3884 /* This cleaning is necessary only if a listening socket is being
3885 * reused as it might have had a previous connection. */
3886 if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED )
3887 {
3888 if( pxSocket->u.xTCP.rxStream != NULL )
3889 {
3890 vStreamBufferClear( pxSocket->u.xTCP.rxStream );
3891 }
3892
3893 if( pxSocket->u.xTCP.txStream != NULL )
3894 {
3895 vStreamBufferClear( pxSocket->u.xTCP.txStream );
3896 }
3897
3898 ( void ) memset( pxSocket->u.xTCP.xPacket.u.ucLastPacket, 0, sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) );
3899 ( void ) memset( &pxSocket->u.xTCP.xTCPWindow, 0, sizeof( pxSocket->u.xTCP.xTCPWindow ) );
3900 ( void ) memset( &pxSocket->u.xTCP.bits, 0, sizeof( pxSocket->u.xTCP.bits ) );
3901
3902 /* Now set the bReuseSocket flag again, because the bits have
3903 * just been cleared. */
3904 pxSocket->u.xTCP.bits.bReuseSocket = pdTRUE;
3905 }
3906
3907 vTCPStateChange( pxSocket, eTCP_LISTEN );
3908 }
3909
3910 return xResult;
3911 }
3912
3913
3914 #endif /* ipconfigUSE_TCP */
3915 /*-----------------------------------------------------------*/
3916
3917 #if ( ipconfigUSE_TCP == 1 )
3918
3919 /**
3920 * @brief Shutdown - This function will shut down the connection in both
3921 * directions. However, it will first deliver all data queued for
3922 * transmission, and also it will first wait to receive any missing
3923 * packets from the peer.
3924 *
3925 * @param[in] xSocket: The socket owning the connection.
3926 * @param[in] xHow: Not used. Just present to stick to Berkeley standard.
3927 *
3928 * @return 0 on successful shutdown or else a negative error code.
3929 */
FreeRTOS_shutdown(Socket_t xSocket,BaseType_t xHow)3930 BaseType_t FreeRTOS_shutdown( Socket_t xSocket,
3931 BaseType_t xHow )
3932 {
3933 FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
3934 BaseType_t xResult;
3935
3936 if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE )
3937 {
3938 /*_RB_ Is this comment correct? The socket is not of a type that
3939 * supports the listen() operation. */
3940 xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP;
3941 }
3942 else if( pxSocket->u.xTCP.eTCPState != eESTABLISHED )
3943 {
3944 /* The socket is not connected. */
3945 xResult = -pdFREERTOS_ERRNO_ENOTCONN;
3946 }
3947 else
3948 {
3949 pxSocket->u.xTCP.bits.bUserShutdown = pdTRUE_UNSIGNED;
3950
3951 /* Let the IP-task perform the shutdown of the connection. */
3952 pxSocket->u.xTCP.usTimeout = 1U;
3953 ( void ) xSendEventToIPTask( eTCPTimerEvent );
3954 xResult = 0;
3955 }
3956
3957 ( void ) xHow;
3958
3959 return xResult;
3960 }
3961
3962
3963 #endif /* ipconfigUSE_TCP */
3964 /*-----------------------------------------------------------*/
3965
3966 #if ( ipconfigUSE_TCP == 1 )
3967
3968 /**
3969 * @brief A TCP timer has expired, now check all TCP sockets for:
3970 * - Active connect
3971 * - Send a delayed ACK
3972 * - Send new data
3973 * - Send a keep-alive packet
3974 * - Check for timeout (in non-connected states only)
3975 *
3976 * @param[in] xWillSleep: Whether the calling task is going to sleep.
3977 *
3978 * @return Minimum amount of time before the timer shall expire.
3979 */
xTCPTimerCheck(BaseType_t xWillSleep)3980 TickType_t xTCPTimerCheck( BaseType_t xWillSleep )
3981 {
3982 FreeRTOS_Socket_t * pxSocket;
3983 TickType_t xShortest = pdMS_TO_TICKS( ( TickType_t ) ipTCP_TIMER_PERIOD_MS );
3984 TickType_t xNow = xTaskGetTickCount();
3985 static TickType_t xLastTime = 0U;
3986 TickType_t xDelta = xNow - xLastTime;
3987
3988 /* MISRA Ref 11.3.1 [Misaligned access] */
3989 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
3990 /* coverity[misra_c_2012_rule_11_3_violation] */
3991 const ListItem_t * pxEnd = ( ( const ListItem_t * ) &( xBoundTCPSocketsList.xListEnd ) );
3992
3993 /* MISRA Ref 11.3.1 [Misaligned access] */
3994 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
3995 /* coverity[misra_c_2012_rule_11_3_violation] */
3996 const ListItem_t * pxIterator = ( const ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList );
3997
3998 xLastTime = xNow;
3999
4000 if( xDelta == 0U )
4001 {
4002 xDelta = 1U;
4003 }
4004
4005 while( pxIterator != pxEnd )
4006 {
4007 pxSocket = ( ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) );
4008 pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator );
4009
4010 /* Sockets with 'timeout == 0' do not need any regular attention. */
4011 if( pxSocket->u.xTCP.usTimeout == 0U )
4012 {
4013 continue;
4014 }
4015
4016 if( xDelta < ( TickType_t ) pxSocket->u.xTCP.usTimeout )
4017 {
4018 pxSocket->u.xTCP.usTimeout = ( uint16_t ) ( ( ( TickType_t ) pxSocket->u.xTCP.usTimeout ) - xDelta );
4019 }
4020 else
4021 {
4022 BaseType_t xRc;
4023
4024 pxSocket->u.xTCP.usTimeout = 0U;
4025 xRc = xTCPSocketCheck( pxSocket );
4026
4027 /* Within this function, the socket might want to send a delayed
4028 * ack or send out data or whatever it needs to do. */
4029 if( xRc < 0 )
4030 {
4031 /* Continue because the socket was deleted. */
4032 continue;
4033 }
4034 }
4035
4036 /* In xEventBits the driver may indicate that the socket has
4037 * important events for the user. These are only done just before the
4038 * IP-task goes to sleep. */
4039 if( pxSocket->xEventBits != 0U )
4040 {
4041 if( xWillSleep != pdFALSE )
4042 {
4043 /* The IP-task is about to go to sleep, so messages can be
4044 * sent to the socket owners. */
4045 vSocketWakeUpUser( pxSocket );
4046 }
4047 else
4048 {
4049 /* Or else make sure this will be called again to wake-up
4050 * the sockets' owner. */
4051 xShortest = ( TickType_t ) 0;
4052 }
4053 }
4054
4055 if( ( pxSocket->u.xTCP.usTimeout != 0U ) && ( xShortest > ( TickType_t ) pxSocket->u.xTCP.usTimeout ) )
4056 {
4057 xShortest = ( TickType_t ) pxSocket->u.xTCP.usTimeout;
4058 }
4059 }
4060
4061 return xShortest;
4062 }
4063
4064
4065 #endif /* ipconfigUSE_TCP */
4066 /*-----------------------------------------------------------*/
4067
4068 #if ( ipconfigUSE_TCP == 1 )
4069
4070 /**
4071 * @brief As multiple sockets may be bound to the same local port number
4072 * looking up a socket is a little more complex: Both a local port,
4073 * and a remote port and IP address are being used to find a match.
4074 * For a socket in listening mode, the remote port and IP address
4075 * are both 0.
4076 *
4077 * @param[in] ulLocalIP: Local IP address. Ignored for now.
4078 * @param[in] uxLocalPort: Local port number.
4079 * @param[in] ulRemoteIP: Remote (peer) IP address.
4080 * @param[in] uxRemotePort: Remote (peer) port.
4081 *
4082 * @return The socket which was found.
4083 */
pxTCPSocketLookup(uint32_t ulLocalIP,UBaseType_t uxLocalPort,uint32_t ulRemoteIP,UBaseType_t uxRemotePort)4084 FreeRTOS_Socket_t * pxTCPSocketLookup( uint32_t ulLocalIP,
4085 UBaseType_t uxLocalPort,
4086 uint32_t ulRemoteIP,
4087 UBaseType_t uxRemotePort )
4088 {
4089 const ListItem_t * pxIterator;
4090 FreeRTOS_Socket_t * pxResult = NULL, * pxListenSocket = NULL;
4091
4092 /* MISRA Ref 11.3.1 [Misaligned access] */
4093 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
4094 /* coverity[misra_c_2012_rule_11_3_violation] */
4095 const ListItem_t * pxEnd = ( ( const ListItem_t * ) &( xBoundTCPSocketsList.xListEnd ) );
4096
4097 /* Parameter not yet supported. */
4098 ( void ) ulLocalIP;
4099
4100 for( pxIterator = listGET_NEXT( pxEnd );
4101 pxIterator != pxEnd;
4102 pxIterator = listGET_NEXT( pxIterator ) )
4103 {
4104 FreeRTOS_Socket_t * pxSocket = ( ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) );
4105
4106 if( pxSocket->usLocalPort == ( uint16_t ) uxLocalPort )
4107 {
4108 if( pxSocket->u.xTCP.eTCPState == eTCP_LISTEN )
4109 {
4110 /* If this is a socket listening to uxLocalPort, remember it
4111 * in case there is no perfect match. */
4112 pxListenSocket = pxSocket;
4113 }
4114 else if( ( pxSocket->u.xTCP.usRemotePort == ( uint16_t ) uxRemotePort ) && ( pxSocket->u.xTCP.ulRemoteIP == ulRemoteIP ) )
4115 {
4116 /* For sockets not in listening mode, find a match with
4117 * xLocalPort, ulRemoteIP AND xRemotePort. */
4118 pxResult = pxSocket;
4119 break;
4120 }
4121 else
4122 {
4123 /* This 'pxSocket' doesn't match. */
4124 }
4125 }
4126 }
4127
4128 if( pxResult == NULL )
4129 {
4130 /* An exact match was not found, maybe a listening socket was
4131 * found. */
4132 pxResult = pxListenSocket;
4133 }
4134
4135 return pxResult;
4136 }
4137
4138 #endif /* ipconfigUSE_TCP */
4139 /*-----------------------------------------------------------*/
4140
4141 #if ( ipconfigUSE_TCP == 1 )
4142
4143 /**
4144 * @brief For the web server: borrow the circular Rx buffer for inspection.
4145 * HTML driver wants to see if a sequence of 13/10/13/10 is available.
4146 *
4147 * @param[in] xSocket: The socket whose Rx stream is to be returned.
4148 *
4149 * @return The Rx stream of the socket if all checks pass, else NULL.
4150 */
FreeRTOS_get_rx_buf(ConstSocket_t xSocket)4151 const struct xSTREAM_BUFFER * FreeRTOS_get_rx_buf( ConstSocket_t xSocket )
4152 {
4153 const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
4154 const struct xSTREAM_BUFFER * pxReturn = NULL;
4155
4156
4157 /* Confirm that this is a TCP socket before dereferencing structure
4158 * member pointers. */
4159 if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdTRUE )
4160 {
4161 pxReturn = pxSocket->u.xTCP.rxStream;
4162 }
4163
4164 return pxReturn;
4165 }
4166
4167 #endif /* ipconfigUSE_TCP */
4168 /*-----------------------------------------------------------*/
4169
4170 #if ( ipconfigUSE_TCP == 1 )
4171
4172 /**
4173 * @brief Create the stream buffer for the given socket.
4174 *
4175 * @param[in] pxSocket: the socket to create the stream for.
4176 * @param[in] xIsInputStream: Is this input stream? pdTRUE/pdFALSE?
4177 *
4178 * @return The stream buffer.
4179 */
prvTCPCreateStream(FreeRTOS_Socket_t * pxSocket,BaseType_t xIsInputStream)4180 static StreamBuffer_t * prvTCPCreateStream( FreeRTOS_Socket_t * pxSocket,
4181 BaseType_t xIsInputStream )
4182 {
4183 StreamBuffer_t * pxBuffer;
4184 size_t uxLength;
4185 size_t uxSize;
4186
4187 /* Now that a stream is created, the maximum size is fixed before
4188 * creation, it could still be changed with setsockopt(). */
4189 if( xIsInputStream != pdFALSE )
4190 {
4191 size_t uxLittlePerc = sock20_PERCENT;
4192 size_t uxEnoughPerc = sock80_PERCENT;
4193 size_t uxSegmentCount = pxSocket->u.xTCP.uxRxStreamSize / pxSocket->u.xTCP.usMSS;
4194 static const struct Percent
4195 {
4196 size_t uxPercLittle, uxPercEnough;
4197 }
4198 xPercTable[] =
4199 {
4200 { 0U, 100U }, /* 1 segment. */
4201 { 50U, 100U }, /* 2 segments. */
4202 { 34U, 100U }, /* 3 segments. */
4203 { 25U, 100U }, /* 4 segments. */
4204 };
4205
4206 if( ( uxSegmentCount > 0U ) &&
4207 ( uxSegmentCount <= ARRAY_USIZE( xPercTable ) ) )
4208 {
4209 uxLittlePerc = xPercTable[ uxSegmentCount - 1U ].uxPercLittle;
4210 uxEnoughPerc = xPercTable[ uxSegmentCount - 1U ].uxPercEnough;
4211 }
4212
4213 uxLength = pxSocket->u.xTCP.uxRxStreamSize;
4214
4215 if( pxSocket->u.xTCP.uxLittleSpace == 0U )
4216 {
4217 pxSocket->u.xTCP.uxLittleSpace = ( uxLittlePerc * pxSocket->u.xTCP.uxRxStreamSize ) / sock100_PERCENT;
4218 }
4219
4220 if( pxSocket->u.xTCP.uxEnoughSpace == 0U )
4221 {
4222 pxSocket->u.xTCP.uxEnoughSpace = ( uxEnoughPerc * pxSocket->u.xTCP.uxRxStreamSize ) / sock100_PERCENT;
4223 }
4224 }
4225 else
4226 {
4227 uxLength = pxSocket->u.xTCP.uxTxStreamSize;
4228 }
4229
4230 /* Add an extra 4 (or 8) bytes. */
4231 uxLength += sizeof( size_t );
4232
4233 /* And make the length a multiple of sizeof( size_t ). */
4234 uxLength &= ~( sizeof( size_t ) - 1U );
4235
4236 uxSize = ( sizeof( *pxBuffer ) + uxLength ) - sizeof( pxBuffer->ucArray );
4237
4238 pxBuffer = ( ( StreamBuffer_t * ) pvPortMallocLarge( uxSize ) );
4239
4240 if( pxBuffer == NULL )
4241 {
4242 FreeRTOS_debug_printf( ( "prvTCPCreateStream: malloc failed\n" ) );
4243 pxSocket->u.xTCP.bits.bMallocError = pdTRUE;
4244 vTCPStateChange( pxSocket, eCLOSE_WAIT );
4245 }
4246 else
4247 {
4248 /* Clear the markers of the stream */
4249 ( void ) memset( pxBuffer, 0, sizeof( *pxBuffer ) - sizeof( pxBuffer->ucArray ) );
4250 pxBuffer->LENGTH = ( size_t ) uxLength;
4251
4252 if( xTCPWindowLoggingLevel != 0 )
4253 {
4254 FreeRTOS_debug_printf( ( "prvTCPCreateStream: %cxStream created %u bytes (total %u)\n", ( xIsInputStream != 0 ) ? 'R' : 'T', ( unsigned ) uxLength, ( unsigned ) uxSize ) );
4255 }
4256
4257 if( xIsInputStream != 0 )
4258 {
4259 iptraceMEM_STATS_CREATE( tcpRX_STREAM_BUFFER, pxBuffer, uxSize );
4260 pxSocket->u.xTCP.rxStream = pxBuffer;
4261 }
4262 else
4263 {
4264 iptraceMEM_STATS_CREATE( tcpTX_STREAM_BUFFER, pxBuffer, uxSize );
4265 pxSocket->u.xTCP.txStream = pxBuffer;
4266 }
4267 }
4268
4269 return pxBuffer;
4270 }
4271
4272
4273 #endif /* ipconfigUSE_TCP */
4274 /*-----------------------------------------------------------*/
4275
4276 #if ( ipconfigUSE_TCP == 1 )
4277
4278 /**
4279 * @brief Add data to the RxStream. When uxOffset > 0, data has come in out-of-order
4280 * and will be put in front of the head so it can not be popped by the user.
4281 *
4282 * @param[in] pxSocket: The socket to whose RxStream data is to be added.
4283 * @param[in] uxOffset: Offset of the packet.
4284 * @param[in] pcData: The data to be added to the RxStream.
4285 * @param[in] ulByteCount: Number of bytes in the data.
4286 *
4287 * @return The number of bytes actually added to the RxStream. Or else, a negative
4288 * error code is returned.
4289 */
lTCPAddRxdata(FreeRTOS_Socket_t * pxSocket,size_t uxOffset,const uint8_t * pcData,uint32_t ulByteCount)4290 int32_t lTCPAddRxdata( FreeRTOS_Socket_t * pxSocket,
4291 size_t uxOffset,
4292 const uint8_t * pcData,
4293 uint32_t ulByteCount )
4294 {
4295 StreamBuffer_t * pxStream = pxSocket->u.xTCP.rxStream;
4296 int32_t xResult = 0;
4297
4298 #if ( ipconfigUSE_CALLBACKS == 1 )
4299 BaseType_t bHasHandler = ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleReceive ) ? pdTRUE : pdFALSE;
4300 const uint8_t * pucBuffer = NULL;
4301 #endif /* ipconfigUSE_CALLBACKS */
4302
4303 /* int32_t uxStreamBufferAdd( pxBuffer, uxOffset, pucData, aCount )
4304 * if( pucData != NULL ) copy data the the buffer
4305 * if( pucData == NULL ) no copying, just advance rxHead
4306 * if( uxOffset != 0 ) Just store data which has come out-of-order
4307 * if( uxOffset == 0 ) Also advance rxHead */
4308 if( pxStream == NULL )
4309 {
4310 pxStream = prvTCPCreateStream( pxSocket, pdTRUE );
4311
4312 if( pxStream == NULL )
4313 {
4314 xResult = -1;
4315 }
4316 }
4317
4318 if( xResult >= 0 )
4319 {
4320 #if ( ipconfigUSE_CALLBACKS == 1 )
4321 {
4322 if( ( bHasHandler != pdFALSE ) && ( uxStreamBufferGetSize( pxStream ) == 0U ) && ( uxOffset == 0U ) && ( pcData != NULL ) )
4323 {
4324 /* Data can be passed directly to the user */
4325 pucBuffer = pcData;
4326
4327 pcData = NULL;
4328 }
4329 }
4330 #endif /* ipconfigUSE_CALLBACKS */
4331
4332 xResult = ( int32_t ) uxStreamBufferAdd( pxStream, uxOffset, pcData, ( size_t ) ulByteCount );
4333
4334 #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
4335 {
4336 if( xResult != ( int32_t ) ulByteCount )
4337 {
4338 FreeRTOS_debug_printf( ( "lTCPAddRxdata: at %u: %d/%u bytes (tail %u head %u space %u front %u)\n",
4339 ( unsigned int ) uxOffset,
4340 ( int ) xResult,
4341 ( unsigned int ) ulByteCount,
4342 ( unsigned int ) pxStream->uxTail,
4343 ( unsigned int ) pxStream->uxHead,
4344 ( unsigned int ) uxStreamBufferFrontSpace( pxStream ),
4345 ( unsigned int ) pxStream->uxFront ) );
4346 }
4347 }
4348 #endif /* ipconfigHAS_DEBUG_PRINTF */
4349
4350 if( uxOffset == 0U )
4351 {
4352 /* Data is being added to rxStream at the head (offs = 0) */
4353 #if ( ipconfigUSE_CALLBACKS == 1 )
4354 if( bHasHandler != pdFALSE )
4355 {
4356 /* The socket owner has installed an OnReceive handler. Pass the
4357 * Rx data, without copying from the rxStream, to the user. */
4358 for( ; ; )
4359 {
4360 uint8_t * ucReadPtr = NULL;
4361 uint32_t ulCount;
4362
4363 if( pucBuffer != NULL )
4364 {
4365 ucReadPtr = ( uint8_t * ) pucBuffer;
4366 ulCount = ulByteCount;
4367 pucBuffer = NULL;
4368 }
4369 else
4370 {
4371 ulCount = ( uint32_t ) uxStreamBufferGetPtr( pxStream, &( ucReadPtr ) );
4372 }
4373
4374 if( ulCount == 0U )
4375 {
4376 break;
4377 }
4378
4379 ( void ) pxSocket->u.xTCP.pxHandleReceive( pxSocket, ucReadPtr, ( size_t ) ulCount );
4380 ( void ) uxStreamBufferGet( pxStream, 0U, NULL, ( size_t ) ulCount, pdFALSE );
4381 }
4382 }
4383 else
4384 #endif /* ipconfigUSE_CALLBACKS */
4385 {
4386 /* See if running out of space. */
4387 if( pxSocket->u.xTCP.bits.bLowWater == pdFALSE_UNSIGNED )
4388 {
4389 size_t uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream );
4390
4391 if( uxFrontSpace <= pxSocket->u.xTCP.uxLittleSpace )
4392 {
4393 pxSocket->u.xTCP.bits.bLowWater = pdTRUE;
4394 pxSocket->u.xTCP.bits.bWinChange = pdTRUE;
4395
4396 /* bLowWater was reached, send the changed window size. */
4397 pxSocket->u.xTCP.usTimeout = 1U;
4398 ( void ) xSendEventToIPTask( eTCPTimerEvent );
4399 }
4400 }
4401
4402 /* New incoming data is available, wake up the user. User's
4403 * semaphores will be set just before the IP-task goes asleep. */
4404 pxSocket->xEventBits |= ( EventBits_t ) eSOCKET_RECEIVE;
4405
4406 #if ipconfigSUPPORT_SELECT_FUNCTION == 1
4407 {
4408 if( ( pxSocket->xSelectBits & ( EventBits_t ) eSELECT_READ ) != 0U )
4409 {
4410 pxSocket->xEventBits |= ( ( ( EventBits_t ) eSELECT_READ ) << SOCKET_EVENT_BIT_COUNT );
4411 }
4412 }
4413 #endif
4414 }
4415 }
4416 }
4417
4418 return xResult;
4419 }
4420
4421
4422 #endif /* ipconfigUSE_TCP */
4423 /*-----------------------------------------------------------*/
4424
4425 #if ( ipconfigUSE_TCP == 1 )
4426
4427 /**
4428 * @brief Function to get the remote IP-address and port number.
4429 *
4430 * @param[in] xSocket: Socket owning the connection.
4431 * @param[out] pxAddress: The address pointer to which the address
4432 * is to be added.
4433 *
4434 * @return The size of the address being returned. Or else a negative
4435 * error code will be returned.
4436 */
FreeRTOS_GetRemoteAddress(ConstSocket_t xSocket,struct freertos_sockaddr * pxAddress)4437 BaseType_t FreeRTOS_GetRemoteAddress( ConstSocket_t xSocket,
4438 struct freertos_sockaddr * pxAddress )
4439 {
4440 const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
4441 BaseType_t xResult;
4442
4443 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
4444 {
4445 xResult = -pdFREERTOS_ERRNO_EINVAL;
4446 }
4447 else
4448 {
4449 /* BSD style sockets communicate IP and port addresses in network
4450 * byte order.
4451 * IP address of remote machine. */
4452 pxAddress->sin_addr = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP );
4453
4454 /* Port on remote machine. */
4455 pxAddress->sin_port = FreeRTOS_htons( pxSocket->u.xTCP.usRemotePort );
4456
4457 xResult = ( BaseType_t ) sizeof( *pxAddress );
4458 }
4459
4460 return xResult;
4461 }
4462
4463
4464 #endif /* ipconfigUSE_TCP */
4465
4466 /*-----------------------------------------------------------*/
4467
4468 #if ( ipconfigUSE_TCP == 1 )
4469
4470 /**
4471 * @brief Check the number of bytes that may be added to txStream.
4472 *
4473 * @param[in] xSocket: The socket to be checked.
4474 *
4475 * @return the number of bytes that may be added to txStream or
4476 * else a negative error code.
4477 */
FreeRTOS_maywrite(ConstSocket_t xSocket)4478 BaseType_t FreeRTOS_maywrite( ConstSocket_t xSocket )
4479 {
4480 const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
4481 BaseType_t xResult;
4482
4483 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
4484 {
4485 xResult = -pdFREERTOS_ERRNO_EINVAL;
4486 }
4487 else if( pxSocket->u.xTCP.eTCPState != eESTABLISHED )
4488 {
4489 if( ( pxSocket->u.xTCP.eTCPState < eCONNECT_SYN ) || ( pxSocket->u.xTCP.eTCPState > eESTABLISHED ) )
4490 {
4491 xResult = -1;
4492 }
4493 else
4494 {
4495 xResult = 0;
4496 }
4497 }
4498 else if( pxSocket->u.xTCP.txStream == NULL )
4499 {
4500 xResult = ( BaseType_t ) pxSocket->u.xTCP.uxTxStreamSize;
4501 }
4502 else
4503 {
4504 xResult = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream );
4505 }
4506
4507 return xResult;
4508 }
4509
4510
4511 #endif /* ipconfigUSE_TCP */
4512 /*-----------------------------------------------------------*/
4513
4514 #if ( ipconfigUSE_TCP == 1 )
4515
4516 /**
4517 * @brief Get the number of bytes that can be written in the Tx buffer
4518 * of the given socket.
4519 *
4520 * @param[in] xSocket: the socket to be checked.
4521 *
4522 * @return The bytes that can be written. Or else an error code.
4523 */
FreeRTOS_tx_space(ConstSocket_t xSocket)4524 BaseType_t FreeRTOS_tx_space( ConstSocket_t xSocket )
4525 {
4526 const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
4527 BaseType_t xReturn;
4528
4529 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
4530 {
4531 xReturn = -pdFREERTOS_ERRNO_EINVAL;
4532 }
4533 else
4534 {
4535 if( pxSocket->u.xTCP.txStream != NULL )
4536 {
4537 xReturn = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream );
4538 }
4539 else
4540 {
4541 xReturn = ( BaseType_t ) pxSocket->u.xTCP.uxTxStreamSize;
4542 }
4543 }
4544
4545 return xReturn;
4546 }
4547
4548
4549 #endif /* ipconfigUSE_TCP */
4550 /*-----------------------------------------------------------*/
4551
4552 #if ( ipconfigUSE_TCP == 1 )
4553
4554 /**
4555 * @brief Returns the number of bytes stored in the Tx buffer.
4556 *
4557 * @param[in] xSocket: The socket to be checked.
4558 *
4559 * @return The number of bytes stored in the Tx buffer of the socket.
4560 * Or an error code.
4561 */
FreeRTOS_tx_size(ConstSocket_t xSocket)4562 BaseType_t FreeRTOS_tx_size( ConstSocket_t xSocket )
4563 {
4564 const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
4565 BaseType_t xReturn;
4566
4567 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
4568 {
4569 xReturn = -pdFREERTOS_ERRNO_EINVAL;
4570 }
4571 else
4572 {
4573 if( pxSocket->u.xTCP.txStream != NULL )
4574 {
4575 xReturn = ( BaseType_t ) uxStreamBufferGetSize( pxSocket->u.xTCP.txStream );
4576 }
4577 else
4578 {
4579 xReturn = 0;
4580 }
4581 }
4582
4583 return xReturn;
4584 }
4585
4586
4587 #endif /* ipconfigUSE_TCP */
4588 /*-----------------------------------------------------------*/
4589
4590 #if ( ipconfigUSE_TCP == 1 )
4591
4592 /**
4593 * @brief Is the socket connected.
4594 *
4595 * @param[in] xSocket: The socket being checked.
4596 *
4597 * @return pdTRUE if TCP socket is connected.
4598 */
FreeRTOS_issocketconnected(ConstSocket_t xSocket)4599 BaseType_t FreeRTOS_issocketconnected( ConstSocket_t xSocket )
4600 {
4601 const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
4602 BaseType_t xReturn = pdFALSE;
4603
4604 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
4605 {
4606 xReturn = -pdFREERTOS_ERRNO_EINVAL;
4607 }
4608 else
4609 {
4610 if( pxSocket->u.xTCP.eTCPState >= eESTABLISHED )
4611 {
4612 if( pxSocket->u.xTCP.eTCPState < eCLOSE_WAIT )
4613 {
4614 xReturn = pdTRUE;
4615 }
4616 }
4617 }
4618
4619 return xReturn;
4620 }
4621
4622
4623 #endif /* ipconfigUSE_TCP */
4624 /*-----------------------------------------------------------*/
4625
4626 #if ( ipconfigUSE_TCP == 1 )
4627
4628 /**
4629 * @brief Get the actual value of Maximum Segment Size ( MSS ) being used.
4630 *
4631 * @param[in] xSocket: The socket whose MSS is to be returned.
4632 *
4633 * @return the actual size of MSS being used or an error code.
4634 */
FreeRTOS_mss(ConstSocket_t xSocket)4635 BaseType_t FreeRTOS_mss( ConstSocket_t xSocket )
4636 {
4637 const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
4638 BaseType_t xReturn;
4639
4640 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
4641 {
4642 xReturn = -pdFREERTOS_ERRNO_EINVAL;
4643 }
4644 else
4645 {
4646 /* usMSS is declared as uint16_t to save space. FreeRTOS_mss()
4647 * will often be used in signed native-size expressions cast it to
4648 * BaseType_t. */
4649 xReturn = ( BaseType_t ) ( pxSocket->u.xTCP.usMSS );
4650 }
4651
4652 return xReturn;
4653 }
4654
4655
4656 #endif /* ipconfigUSE_TCP */
4657 /*-----------------------------------------------------------*/
4658
4659 #if ( ipconfigUSE_TCP == 1 )
4660
4661 /**
4662 * @brief Get the connection status. The values correspond to the members
4663 * of the enum 'eIPTCPState_t'.
4664 *
4665 * @param[in] xSocket: Socket to get the connection status from.
4666 *
4667 * @return The connection status or an error code.
4668 *
4669 * @note For internal use only.
4670 */
FreeRTOS_connstatus(ConstSocket_t xSocket)4671 BaseType_t FreeRTOS_connstatus( ConstSocket_t xSocket )
4672 {
4673 const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
4674 BaseType_t xReturn;
4675
4676 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
4677 {
4678 xReturn = -pdFREERTOS_ERRNO_EINVAL;
4679 }
4680 else
4681 {
4682 /* Cast it to BaseType_t. */
4683 xReturn = ( BaseType_t ) ( pxSocket->u.xTCP.eTCPState );
4684 }
4685
4686 return xReturn;
4687 }
4688
4689
4690 #endif /* ipconfigUSE_TCP */
4691 /*-----------------------------------------------------------*/
4692
4693 #if ( ipconfigUSE_TCP == 1 )
4694
4695 /**
4696 * @brief Returns the number of bytes which can be read from the RX stream buffer.
4697 *
4698 * @param[in] xSocket: the socket to get the number of bytes from.
4699 *
4700 * @return Returns the number of bytes which can be read. Or an error
4701 * code is returned.
4702 */
FreeRTOS_rx_size(ConstSocket_t xSocket)4703 BaseType_t FreeRTOS_rx_size( ConstSocket_t xSocket )
4704 {
4705 const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
4706 BaseType_t xReturn;
4707
4708 if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
4709 {
4710 xReturn = -pdFREERTOS_ERRNO_EINVAL;
4711 }
4712 else if( pxSocket->u.xTCP.rxStream != NULL )
4713 {
4714 xReturn = ( BaseType_t ) uxStreamBufferGetSize( pxSocket->u.xTCP.rxStream );
4715 }
4716 else
4717 {
4718 xReturn = 0;
4719 }
4720
4721 return xReturn;
4722 }
4723
4724
4725 #endif /* ipconfigUSE_TCP */
4726 /*-----------------------------------------------------------*/
4727
4728 /**
4729 * @brief Check whether a given socket is valid or not. Validity is defined
4730 * as the socket not being NULL and not being Invalid.
4731 * @param[in] xSocket: The socket to be checked.
4732 * @return pdTRUE if the socket is valid, else pdFALSE.
4733 *
4734 */
xSocketValid(const ConstSocket_t xSocket)4735 BaseType_t xSocketValid( const ConstSocket_t xSocket )
4736 {
4737 BaseType_t xReturnValue = pdFALSE;
4738
4739 /* MISRA Ref 11.4.1 [Socket error and integer to pointer conversion] */
4740 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */
4741 /* coverity[misra_c_2012_rule_11_4_violation] */
4742 if( ( xSocket != FREERTOS_INVALID_SOCKET ) && ( xSocket != NULL ) )
4743 {
4744 xReturnValue = pdTRUE;
4745 }
4746
4747 return xReturnValue;
4748 }
4749 /*-----------------------------------------------------------*/
4750
4751 #if 0
4752
4753 /**
4754 * @brief Returns the number of packets that are stored in a UDP socket.
4755 *
4756 * @param[in] xSocket: the socket to get the number of bytes from.
4757 *
4758 * @return Returns the number of packets that are stored. Use FreeRTOS_recvfrom()
4759 * to retrieve those packets.
4760 */
4761 BaseType_t FreeRTOS_udp_rx_size( Socket_t xSocket )
4762 {
4763 BaseType_t xReturn = 0;
4764 const FreeRTOS_Socket_t * pxSocket = ( const FreeRTOS_Socket_t * ) xSocket;
4765
4766 if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP )
4767 {
4768 xReturn = ( BaseType_t ) listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) );
4769 }
4770 else
4771 {
4772 xReturn = -pdFREERTOS_ERRNO_EINVAL;
4773 }
4774
4775 return xReturn;
4776 }
4777 #endif /* 0 */
4778
4779 #if ( ipconfigUSE_TCP == 1 )
4780
4781 /**
4782 * @brief Get the net status. The IP-task will print a summary of all sockets and
4783 * their connections.
4784 */
FreeRTOS_netstat(void)4785 void FreeRTOS_netstat( void )
4786 {
4787 IPStackEvent_t xAskEvent;
4788
4789 /* Ask the IP-task to call vTCPNetStat()
4790 * to avoid accessing xBoundTCPSocketsList
4791 */
4792 xAskEvent.eEventType = eTCPNetStat;
4793 xAskEvent.pvData = ( void * ) NULL;
4794 ( void ) xSendEventStructToIPTask( &xAskEvent, pdMS_TO_TICKS( 1000U ) );
4795 }
4796
4797 #endif /* ipconfigUSE_TCP */
4798 /*-----------------------------------------------------------*/
4799
4800 #if ( ( ipconfigHAS_PRINTF != 0 ) && ( ipconfigUSE_TCP == 1 ) )
4801
4802 /**
4803 * @brief Print a summary of all sockets and their connections.
4804 */
vTCPNetStat(void)4805 void vTCPNetStat( void )
4806 {
4807 /* Show a simple listing of all created sockets and their connections */
4808 const ListItem_t * pxIterator;
4809 BaseType_t count = 0;
4810 size_t uxMinimum = uxGetMinimumFreeNetworkBuffers();
4811 size_t uxCurrent = uxGetNumberOfFreeNetworkBuffers();
4812
4813 if( !listLIST_IS_INITIALISED( &xBoundTCPSocketsList ) )
4814 {
4815 FreeRTOS_printf( ( "PLUS-TCP not initialized\n" ) );
4816 }
4817 else
4818 {
4819 const ListItem_t * pxEndTCP = listGET_END_MARKER( &xBoundTCPSocketsList );
4820 const ListItem_t * pxEndUDP = listGET_END_MARKER( &xBoundUDPSocketsList );
4821 FreeRTOS_printf( ( "Prot Port IP-Remote : Port R/T Status Alive tmout Child\n" ) );
4822
4823 for( pxIterator = listGET_HEAD_ENTRY( &xBoundTCPSocketsList );
4824 pxIterator != pxEndTCP;
4825 pxIterator = listGET_NEXT( pxIterator ) )
4826 {
4827 const FreeRTOS_Socket_t * pxSocket = ( ( const FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) );
4828 #if ( ipconfigTCP_KEEP_ALIVE == 1 )
4829 TickType_t age = xTaskGetTickCount() - pxSocket->u.xTCP.xLastAliveTime;
4830 #else
4831 TickType_t age = 0U;
4832 #endif
4833
4834 char ucChildText[ 16 ] = "";
4835
4836 if( pxSocket->u.xTCP.eTCPState == eTCP_LISTEN )
4837 {
4838 /* Using function "snprintf". */
4839 const int32_t copied_len = snprintf( ucChildText, sizeof( ucChildText ), " %d/%d",
4840 pxSocket->u.xTCP.usChildCount,
4841 pxSocket->u.xTCP.usBacklog );
4842 ( void ) copied_len;
4843 /* These should never evaluate to false since the buffers are both shorter than 5-6 characters (<=65535) */
4844 configASSERT( copied_len >= 0 ); /* LCOV_EXCL_BR_LINE the 'taken' branch will never execute. See the above comment. */
4845 configASSERT( copied_len < ( int32_t ) sizeof( ucChildText ) ); /* LCOV_EXCL_BR_LINE the 'taken' branch will never execute. See the above comment. */
4846 }
4847
4848 FreeRTOS_printf( ( "TCP %5u %-16xip:%5u %d/%d %-13.13s %6u %6u%s\n",
4849 pxSocket->usLocalPort, /* Local port on this machine */
4850 ( unsigned ) pxSocket->u.xTCP.ulRemoteIP, /* IP address of remote machine */
4851 pxSocket->u.xTCP.usRemotePort, /* Port on remote machine */
4852 ( pxSocket->u.xTCP.rxStream != NULL ) ? 1 : 0,
4853 ( pxSocket->u.xTCP.txStream != NULL ) ? 1 : 0,
4854 FreeRTOS_GetTCPStateName( pxSocket->u.xTCP.eTCPState ),
4855 ( unsigned ) ( ( age > 999999U ) ? 999999U : age ), /* Format 'age' for printing */
4856 pxSocket->u.xTCP.usTimeout,
4857 ucChildText ) );
4858 count++;
4859 }
4860
4861 for( pxIterator = listGET_HEAD_ENTRY( &xBoundUDPSocketsList );
4862 pxIterator != pxEndUDP;
4863 pxIterator = listGET_NEXT( pxIterator ) )
4864 {
4865 /* Local port on this machine */
4866 FreeRTOS_printf( ( "UDP Port %5u\n",
4867 FreeRTOS_ntohs( listGET_LIST_ITEM_VALUE( pxIterator ) ) ) );
4868 count++;
4869 }
4870
4871 FreeRTOS_printf( ( "FreeRTOS_netstat: %d sockets %u < %u < %u buffers free\n",
4872 ( int ) count,
4873 ( unsigned ) uxMinimum,
4874 ( unsigned ) uxCurrent,
4875 ( unsigned ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) );
4876 }
4877 }
4878
4879 #endif /* ( ( ipconfigHAS_PRINTF != 0 ) && ( ipconfigUSE_TCP == 1 ) ) */
4880 /*-----------------------------------------------------------*/
4881
4882 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
4883
4884 /**
4885 * @brief This internal non-blocking function will check all sockets that belong
4886 * to a select set. The events bits of each socket will be updated, and it
4887 * will check if an ongoing select() call must be interrupted because of an
4888 * event has occurred.
4889 *
4890 * @param[in] pxSocketSet: The socket-set which is to be waited on for change.
4891 */
vSocketSelect(const SocketSelect_t * pxSocketSet)4892 void vSocketSelect( const SocketSelect_t * pxSocketSet )
4893 {
4894 BaseType_t xRound;
4895 EventBits_t xSocketBits, xBitsToClear;
4896
4897 #if ipconfigUSE_TCP == 1
4898 BaseType_t xLastRound = 1;
4899 #else
4900 BaseType_t xLastRound = 0;
4901 #endif
4902
4903 /* These flags will be switched on after checking the socket status. */
4904 EventBits_t xGroupBits = 0;
4905
4906 for( xRound = 0; xRound <= xLastRound; xRound++ )
4907 {
4908 const ListItem_t * pxIterator;
4909 const ListItem_t * pxEnd;
4910
4911 if( xRound == 0 )
4912 {
4913 /* MISRA Ref 11.3.1 [Misaligned access] */
4914 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
4915 /* coverity[misra_c_2012_rule_11_3_violation] */
4916 pxEnd = ( ( const ListItem_t * ) &( xBoundUDPSocketsList.xListEnd ) );
4917 }
4918
4919 #if ipconfigUSE_TCP == 1
4920 else
4921 {
4922 /* MISRA Ref 11.3.1 [Misaligned access] */
4923 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
4924 /* coverity[misra_c_2012_rule_11_3_violation] */
4925 pxEnd = ( ( const ListItem_t * ) &( xBoundTCPSocketsList.xListEnd ) );
4926 }
4927 #endif /* ipconfigUSE_TCP == 1 */
4928
4929 for( pxIterator = listGET_NEXT( pxEnd );
4930 pxIterator != pxEnd;
4931 pxIterator = listGET_NEXT( pxIterator ) )
4932 {
4933 FreeRTOS_Socket_t * pxSocket = ( ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ) );
4934
4935 if( pxSocket->pxSocketSet != pxSocketSet )
4936 {
4937 /* Socket does not belong to this select group. */
4938 continue;
4939 }
4940
4941 xSocketBits = 0;
4942
4943 #if ( ipconfigUSE_TCP == 1 )
4944 if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP )
4945 {
4946 /* Check if the socket has already been accepted by the
4947 * owner. If not, it is useless to return it from a
4948 * select(). */
4949 BaseType_t bAccepted = pdFALSE;
4950
4951 if( pxSocket->u.xTCP.bits.bPassQueued == pdFALSE_UNSIGNED )
4952 {
4953 if( pxSocket->u.xTCP.bits.bPassAccept == pdFALSE_UNSIGNED )
4954 {
4955 bAccepted = pdTRUE;
4956 }
4957 }
4958
4959 /* Is the set owner interested in READ events? */
4960 if( ( pxSocket->xSelectBits & ( EventBits_t ) eSELECT_READ ) != ( EventBits_t ) 0U )
4961 {
4962 if( pxSocket->u.xTCP.eTCPState == eTCP_LISTEN )
4963 {
4964 if( ( pxSocket->u.xTCP.pxPeerSocket != NULL ) && ( pxSocket->u.xTCP.pxPeerSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
4965 {
4966 xSocketBits |= ( EventBits_t ) eSELECT_READ;
4967 }
4968 }
4969 else if( ( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED ) && ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) )
4970 {
4971 /* This socket has the re-use flag. After connecting it turns into
4972 * a connected socket. Set the READ event, so that accept() will be called. */
4973 xSocketBits |= ( EventBits_t ) eSELECT_READ;
4974 }
4975 else if( ( bAccepted != 0 ) && ( FreeRTOS_recvcount( pxSocket ) > 0 ) )
4976 {
4977 xSocketBits |= ( EventBits_t ) eSELECT_READ;
4978 }
4979 else
4980 {
4981 /* Nothing. */
4982 }
4983 }
4984
4985 /* Is the set owner interested in EXCEPTION events? */
4986 if( ( pxSocket->xSelectBits & ( EventBits_t ) eSELECT_EXCEPT ) != 0U )
4987 {
4988 if( ( pxSocket->u.xTCP.eTCPState == eCLOSE_WAIT ) || ( pxSocket->u.xTCP.eTCPState == eCLOSED ) )
4989 {
4990 xSocketBits |= ( EventBits_t ) eSELECT_EXCEPT;
4991 }
4992 }
4993
4994 /* Is the set owner interested in WRITE events? */
4995 if( ( pxSocket->xSelectBits & ( EventBits_t ) eSELECT_WRITE ) != 0U )
4996 {
4997 BaseType_t bMatch = pdFALSE;
4998
4999 if( bAccepted != 0 )
5000 {
5001 if( FreeRTOS_tx_space( pxSocket ) > 0 )
5002 {
5003 bMatch = pdTRUE;
5004 }
5005 }
5006
5007 if( bMatch == pdFALSE )
5008 {
5009 if( ( pxSocket->u.xTCP.bits.bConnPrepared != pdFALSE_UNSIGNED ) &&
5010 ( pxSocket->u.xTCP.eTCPState >= eESTABLISHED ) &&
5011 ( pxSocket->u.xTCP.bits.bConnPassed == pdFALSE_UNSIGNED ) )
5012 {
5013 pxSocket->u.xTCP.bits.bConnPassed = pdTRUE;
5014 bMatch = pdTRUE;
5015 }
5016 }
5017
5018 if( bMatch != pdFALSE )
5019 {
5020 xSocketBits |= ( EventBits_t ) eSELECT_WRITE;
5021 }
5022 }
5023 }
5024 else
5025 #endif /* ipconfigUSE_TCP == 1 */
5026 {
5027 /* Select events for UDP are simpler. */
5028 if( ( ( pxSocket->xSelectBits & ( EventBits_t ) eSELECT_READ ) != 0U ) &&
5029 ( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) > 0U ) )
5030 {
5031 xSocketBits |= ( EventBits_t ) eSELECT_READ;
5032 }
5033
5034 /* The WRITE and EXCEPT bits are not used for UDP */
5035 } /* if( pxSocket->ucProtocol == FREERTOS_IPPROTO_TCP ) */
5036
5037 /* Each socket keeps its own event flags, which are looked-up
5038 * by FreeRTOS_FD_ISSSET() */
5039 pxSocket->xSocketBits = xSocketBits;
5040
5041 /* The ORed value will be used to set the bits in the event
5042 * group. */
5043 xGroupBits |= xSocketBits;
5044 } /* for( pxIterator ... ) */
5045 } /* for( xRound = 0; xRound <= xLastRound; xRound++ ) */
5046
5047 xBitsToClear = xEventGroupGetBits( pxSocketSet->xSelectGroup );
5048
5049 /* Now set the necessary bits. */
5050 xBitsToClear = ( xBitsToClear & ~xGroupBits ) & ( ( EventBits_t ) eSELECT_ALL );
5051
5052 #if ( ipconfigSUPPORT_SIGNALS != 0 )
5053 {
5054 /* Maybe the socketset was signalled, but don't
5055 * clear the 'eSELECT_INTR' bit here, as it will be used
5056 * and cleared in FreeRTOS_select(). */
5057 xBitsToClear &= ~( ( EventBits_t ) eSELECT_INTR );
5058 }
5059 #endif /* ipconfigSUPPORT_SIGNALS */
5060
5061 if( xBitsToClear != 0U )
5062 {
5063 ( void ) xEventGroupClearBits( pxSocketSet->xSelectGroup, xBitsToClear );
5064 }
5065
5066 /* Now include eSELECT_CALL_IP to wakeup the caller. */
5067 ( void ) xEventGroupSetBits( pxSocketSet->xSelectGroup, xGroupBits | ( EventBits_t ) eSELECT_CALL_IP );
5068 }
5069
5070
5071 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
5072 /*-----------------------------------------------------------*/
5073
5074 #if ( ipconfigSUPPORT_SIGNALS != 0 )
5075
5076 /**
5077 * @brief Send a signal to the task which reads from this socket.
5078 * The socket will receive an event of the type 'eSOCKET_INTR'.
5079 * Any ongoing blocking API ( e.g. FreeRTOS_recv() ) will be terminated
5080 * and return the value -pdFREERTOS_ERRNO_EINTR ( -4 ).
5081 *
5082 * @param[in] xSocket: The socket that will be signalled.
5083 */
FreeRTOS_SignalSocket(Socket_t xSocket)5084 BaseType_t FreeRTOS_SignalSocket( Socket_t xSocket )
5085 {
5086 FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
5087 BaseType_t xReturn;
5088
5089 if( pxSocket == NULL )
5090 {
5091 xReturn = -pdFREERTOS_ERRNO_EINVAL;
5092 }
5093 else
5094 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
5095 if( ( pxSocket->pxSocketSet != NULL ) && ( pxSocket->pxSocketSet->xSelectGroup != NULL ) )
5096 {
5097 ( void ) xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, ( EventBits_t ) eSELECT_INTR );
5098 xReturn = 0;
5099 }
5100 else
5101 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
5102 if( pxSocket->xEventGroup != NULL )
5103 {
5104 ( void ) xEventGroupSetBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_INTR );
5105 xReturn = 0;
5106 }
5107 else
5108 {
5109 xReturn = -pdFREERTOS_ERRNO_EINVAL;
5110 }
5111
5112 return xReturn;
5113 }
5114
5115 #endif /* ipconfigSUPPORT_SIGNALS */
5116 /*-----------------------------------------------------------*/
5117
5118 #if ( ipconfigSUPPORT_SIGNALS != 0 )
5119
5120 /**
5121 * @brief The same as 'FreeRTOS_SignalSocket()', except that this function should
5122 * be called from an ISR context.
5123 *
5124 * @param[in] xSocket: The socket that will be signalled.
5125 * @param[in,out] pxHigherPriorityTaskWoken: will be set to non-zero in case a higher-
5126 * priority task has become runnable.
5127 */
FreeRTOS_SignalSocketFromISR(Socket_t xSocket,BaseType_t * pxHigherPriorityTaskWoken)5128 BaseType_t FreeRTOS_SignalSocketFromISR( Socket_t xSocket,
5129 BaseType_t * pxHigherPriorityTaskWoken )
5130 {
5131 FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) xSocket;
5132 BaseType_t xReturn;
5133 IPStackEvent_t xEvent;
5134
5135 configASSERT( pxSocket != NULL );
5136 configASSERT( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP );
5137 configASSERT( pxSocket->xEventGroup != NULL );
5138
5139 xEvent.eEventType = eSocketSignalEvent;
5140 xEvent.pvData = pxSocket;
5141
5142 /* The IP-task will call FreeRTOS_SignalSocket for this socket. */
5143 xReturn = xQueueSendToBackFromISR( xNetworkEventQueue, &xEvent, pxHigherPriorityTaskWoken );
5144
5145 return xReturn;
5146 }
5147
5148 #endif /* ipconfigSUPPORT_SIGNALS */
5149 /*-----------------------------------------------------------*/
5150
5151 #if 0
5152 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
5153 struct pollfd
5154 {
5155 Socket_t fd; /* file descriptor */
5156 EventBits_t events; /* requested events */
5157 EventBits_t revents; /* returned events */
5158 };
5159
5160 typedef BaseType_t nfds_t;
5161
5162 BaseType_t poll( struct pollfd * fds,
5163 nfds_t nfds,
5164 BaseType_t timeout );
5165 BaseType_t poll( struct pollfd * fds,
5166 nfds_t nfds,
5167 BaseType_t timeout )
5168 {
5169 BaseType_t index;
5170 SocketSelect_t * pxSocketSet = NULL;
5171 BaseType_t xReturn = 0;
5172
5173 /* See which socket-sets have been created and bound to the sockets involved. */
5174 for( index = 0; index < nfds; index++ )
5175 {
5176 FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) fds[ index ].fd;
5177
5178 if( pxSocket->pxSocketSet != NULL )
5179 {
5180 if( pxSocketSet == NULL )
5181 {
5182 /* Use this socket-set. */
5183 pxSocketSet = pxSocket->pxSocketSet;
5184 xReturn = 1;
5185 }
5186 else if( pxSocketSet == pxSocket->pxSocketSet )
5187 {
5188 /* Good: associated with the same socket-set. */
5189 }
5190 else
5191 {
5192 /* More than one socket-set is found: can not do a select on 2 sets. */
5193 xReturn = -1;
5194 break;
5195 }
5196 }
5197 }
5198
5199 if( xReturn == 0 )
5200 {
5201 /* Create a new socket-set, and attach all sockets to it. */
5202 pxSocketSet = FreeRTOS_CreateSocketSet();
5203
5204 if( pxSocketSet != NULL )
5205 {
5206 xReturn = 1;
5207 }
5208 else
5209 {
5210 xReturn = -2;
5211 }
5212
5213 /* Memory leak: when the last socket closes, there is no more reference to
5214 * this socket-set. It should be marked as an automatic or anonymous socket-set,
5215 * so when closing the last member, its memory will be freed. */
5216 }
5217
5218 if( xReturn > 0 )
5219 {
5220 /* Only one socket-set is found. Connect all sockets to this socket-set. */
5221 for( index = 0; index < nfds; index++ )
5222 {
5223 FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) fds[ index ].fd;
5224 EventBits_t xEventBits = fds[ index ].events;
5225
5226 FreeRTOS_FD_SET( pxSocket, pxSocketSet, xEventBits );
5227 FreeRTOS_FD_CLR( pxSocket, pxSocketSet, ( EventBits_t ) ~xEventBits );
5228 }
5229
5230 /* And sleep until an event happens or a time-out. */
5231 xReturn = FreeRTOS_select( pxSocketSet, timeout );
5232
5233 /* Now set the return events, copying from the socked field 'xSocketBits'. */
5234 for( index = 0; index < nfds; index++ )
5235 {
5236 FreeRTOS_Socket_t * pxSocket = ( FreeRTOS_Socket_t * ) fds[ index ].fd;
5237
5238 fds[ index ].revents = pxSocket->xSocketBits & ( ( EventBits_t ) eSELECT_ALL );
5239 }
5240 }
5241 else
5242 {
5243 /* -1: Sockets are connected to different socket sets. */
5244 /* -2: FreeRTOS_CreateSocketSet() failed. */
5245 }
5246
5247 return xReturn;
5248 }
5249
5250 #endif /* ipconfigSUPPORT_SELECT_FUNCTION */
5251 #endif /* 0 */
5252