|
75 | 75 | /* MISRA Ref 8.9.1 [File scoped variables] */
|
76 | 76 | /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-89 */
|
77 | 77 | /* coverity[misra_c_2012_rule_8_9_violation] */
|
78 |
| - static FreeRTOS_Socket_t * xPreviousSocket = NULL; |
| 78 | + static FreeRTOS_Socket_t * xSocketToClose = NULL; |
| 79 | + |
| 80 | +/** @brief When a connection is coming in on a reusable socket, and the |
| 81 | + * SYN phase times out, the socket must be put back into eTCP_LISTEN |
| 82 | + * mode, so it can accept a new connection again. |
| 83 | + * This variable can be accessed by the IP task only. Thus, preventing any |
| 84 | + * race condition. |
| 85 | + */ |
| 86 | + /* MISRA Ref 8.9.1 [File scoped variables] */ |
| 87 | + /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-89 */ |
| 88 | + /* coverity[misra_c_2012_rule_8_9_violation] */ |
| 89 | + static FreeRTOS_Socket_t * xSocketToListen = NULL; |
79 | 90 |
|
80 | 91 | /*
|
81 | 92 | * For anti-hang protection and TCP keep-alive messages. Called in two places:
|
|
110 | 121 | /* coverity[single_use] */
|
111 | 122 | void vSocketCloseNextTime( FreeRTOS_Socket_t * pxSocket )
|
112 | 123 | {
|
113 |
| - if( ( xPreviousSocket != NULL ) && ( xPreviousSocket != pxSocket ) ) |
| 124 | + if( ( xSocketToClose != NULL ) && ( xSocketToClose != pxSocket ) ) |
114 | 125 | {
|
115 |
| - ( void ) vSocketClose( xPreviousSocket ); |
| 126 | + ( void ) vSocketClose( xSocketToClose ); |
116 | 127 | }
|
117 | 128 |
|
118 |
| - xPreviousSocket = pxSocket; |
| 129 | + xSocketToClose = pxSocket; |
| 130 | + } |
| 131 | + /*-----------------------------------------------------------*/ |
| 132 | + |
| 133 | +/** @brief Postpone a call to FreeRTOS_listen() to avoid recursive calls. |
| 134 | + * |
| 135 | + * @param[in] pxSocket: The socket to be checked. |
| 136 | + */ |
| 137 | + /* coverity[single_use] */ |
| 138 | + void vSocketListenNextTime( FreeRTOS_Socket_t * pxSocket ) |
| 139 | + { |
| 140 | + if( ( xSocketToListen != NULL ) && ( xSocketToListen != pxSocket ) ) |
| 141 | + { |
| 142 | + ( void ) FreeRTOS_listen( ( Socket_t ) xSocketToListen, xSocketToListen->u.xTCP.usBacklog ); |
| 143 | + } |
| 144 | + |
| 145 | + xSocketToListen = pxSocket; |
119 | 146 | }
|
120 | 147 | /*-----------------------------------------------------------*/
|
121 | 148 |
|
|
272 | 299 | void vTCPStateChange( FreeRTOS_Socket_t * pxSocket,
|
273 | 300 | enum eTCP_STATE eTCPState )
|
274 | 301 | {
|
275 |
| - FreeRTOS_Socket_t * xParent = NULL; |
| 302 | + FreeRTOS_Socket_t * xParent = pxSocket; |
276 | 303 | BaseType_t bBefore = tcpNOW_CONNECTED( ( BaseType_t ) pxSocket->u.xTCP.eTCPState ); /* Was it connected ? */
|
277 | 304 | BaseType_t bAfter = tcpNOW_CONNECTED( ( BaseType_t ) eTCPState ); /* Is it connected now ? */
|
278 | 305 |
|
279 |
| - #if ( ipconfigHAS_DEBUG_PRINTF != 0 ) |
280 |
| - BaseType_t xPreviousState = ( BaseType_t ) pxSocket->u.xTCP.eTCPState; |
281 |
| - #endif |
| 306 | + BaseType_t xPreviousState = ( BaseType_t ) pxSocket->u.xTCP.eTCPState; |
| 307 | + |
282 | 308 | #if ( ipconfigUSE_CALLBACKS == 1 )
|
283 | 309 | FreeRTOS_Socket_t * xConnected = NULL;
|
284 | 310 | #endif
|
285 | 311 |
|
| 312 | + if( ( ( xPreviousState == eCONNECT_SYN ) || |
| 313 | + ( xPreviousState == eSYN_FIRST ) || |
| 314 | + ( xPreviousState == eSYN_RECEIVED ) ) && |
| 315 | + ( eTCPState == eCLOSE_WAIT ) ) |
| 316 | + { |
| 317 | + /* A socket was in the connecting phase but something |
| 318 | + * went wrong and it should be closed. */ |
| 319 | + FreeRTOS_debug_printf( ( "Move from %s to %s\n", |
| 320 | + FreeRTOS_GetTCPStateName( xPreviousState ), |
| 321 | + FreeRTOS_GetTCPStateName( eTCPState ) ) ); |
| 322 | + |
| 323 | + /* Set the flag to show that it was connected before and that the |
| 324 | + * status has changed now. This will cause the control flow to go |
| 325 | + * in the below if condition.*/ |
| 326 | + bBefore = pdTRUE; |
| 327 | + } |
| 328 | + |
286 | 329 | /* Has the connected status changed? */
|
287 | 330 | if( bBefore != bAfter )
|
288 | 331 | {
|
| 332 | + /* if bPassQueued is true, this socket is an orphan until it gets connected. */ |
| 333 | + if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) |
| 334 | + { |
| 335 | + /* Find it's parent if the reuse bit is not set. */ |
| 336 | + if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) |
| 337 | + { |
| 338 | + xParent = pxSocket->u.xTCP.pxPeerSocket; |
| 339 | + configASSERT( xParent != NULL ); |
| 340 | + } |
| 341 | + } |
| 342 | + |
289 | 343 | /* Is the socket connected now ? */
|
290 | 344 | if( bAfter != pdFALSE )
|
291 | 345 | {
|
292 | 346 | /* if bPassQueued is true, this socket is an orphan until it gets connected. */
|
293 | 347 | if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED )
|
294 | 348 | {
|
295 |
| - /* Now that it is connected, find it's parent. */ |
296 |
| - if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED ) |
297 |
| - { |
298 |
| - xParent = pxSocket; |
299 |
| - } |
300 |
| - else |
301 |
| - { |
302 |
| - xParent = pxSocket->u.xTCP.pxPeerSocket; |
303 |
| - configASSERT( xParent != NULL ); |
304 |
| - } |
305 |
| - |
306 | 349 | if( xParent != NULL )
|
307 | 350 | {
|
| 351 | + /* The child socket has got connected. See if the parent |
| 352 | + * ( the listening socket ) should be signalled, or if a |
| 353 | + * call-back must be made, in which case 'xConnected' will |
| 354 | + * be set to the parent socket. */ |
| 355 | + |
308 | 356 | if( xParent->u.xTCP.pxPeerSocket == NULL )
|
309 | 357 | {
|
310 | 358 | xParent->u.xTCP.pxPeerSocket = pxSocket;
|
|
347 | 395 | }
|
348 | 396 | else
|
349 | 397 | {
|
| 398 | + /* An active connect() has succeeded. In this case there is no |
| 399 | + * ( listening ) parent socket. Signal the now connected socket. */ |
| 400 | + |
350 | 401 | pxSocket->xEventBits |= ( EventBits_t ) eSOCKET_CONNECT;
|
351 | 402 |
|
352 | 403 | #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
|
|
361 | 412 | }
|
362 | 413 | else /* bAfter == pdFALSE, connection is closed. */
|
363 | 414 | {
|
364 |
| - /* Notify/wake-up the socket-owner by setting a semaphore. */ |
365 |
| - pxSocket->xEventBits |= ( EventBits_t ) eSOCKET_CLOSED; |
| 415 | + /* Notify/wake-up the socket-owner by setting the event bits. */ |
| 416 | + xParent->xEventBits |= ( EventBits_t ) eSOCKET_CLOSED; |
366 | 417 |
|
367 | 418 | #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
|
368 | 419 | {
|
369 |
| - if( ( pxSocket->xSelectBits & ( EventBits_t ) eSELECT_EXCEPT ) != 0U ) |
| 420 | + if( ( xParent->xSelectBits & ( EventBits_t ) eSELECT_EXCEPT ) != 0U ) |
370 | 421 | {
|
371 |
| - pxSocket->xEventBits |= ( ( EventBits_t ) eSELECT_EXCEPT ) << SOCKET_EVENT_BIT_COUNT; |
| 422 | + xParent->xEventBits |= ( ( EventBits_t ) eSELECT_EXCEPT ) << SOCKET_EVENT_BIT_COUNT; |
372 | 423 | }
|
373 | 424 | }
|
374 | 425 | #endif
|
|
393 | 444 | pxSocket->u.xTCP.usTimeout = 0U;
|
394 | 445 | }
|
395 | 446 | }
|
396 |
| - else |
| 447 | + |
| 448 | + if( ( eTCPState == eCLOSED ) || |
| 449 | + ( eTCPState == eCLOSE_WAIT ) ) |
397 | 450 | {
|
398 |
| - if( ( eTCPState == eCLOSED ) || |
399 |
| - ( eTCPState == eCLOSE_WAIT ) ) |
| 451 | + /* Socket goes to status eCLOSED because of a RST. |
| 452 | + * When nobody owns the socket yet, delete it. */ |
| 453 | + if( ( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) || |
| 454 | + ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) ) |
400 | 455 | {
|
401 |
| - /* Socket goes to status eCLOSED because of a RST. |
402 |
| - * When nobody owns the socket yet, delete it. */ |
403 |
| - if( ( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) || |
404 |
| - ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) ) |
405 |
| - { |
406 |
| - FreeRTOS_debug_printf( ( "vTCPStateChange: Closing socket\n" ) ); |
| 456 | + FreeRTOS_debug_printf( ( "vTCPStateChange: Closing socket\n" ) ); |
407 | 457 |
|
408 |
| - if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) |
409 |
| - { |
410 |
| - configASSERT( xIsCallingFromIPTask() != pdFALSE ); |
411 |
| - vSocketCloseNextTime( pxSocket ); |
412 |
| - } |
| 458 | + if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) |
| 459 | + { |
| 460 | + configASSERT( xIsCallingFromIPTask() != pdFALSE ); |
| 461 | + vSocketCloseNextTime( pxSocket ); |
413 | 462 | }
|
414 | 463 | }
|
415 | 464 | }
|
416 | 465 |
|
417 | 466 | /* Fill in the new state. */
|
418 | 467 | pxSocket->u.xTCP.eTCPState = eTCPState;
|
419 | 468 |
|
| 469 | + if( ( eTCPState == eCLOSE_WAIT ) && ( pxSocket->u.xTCP.bits.bReuseSocket == pdTRUE_UNSIGNED ) ) |
| 470 | + { |
| 471 | + switch( xPreviousState ) |
| 472 | + { |
| 473 | + case eSYN_FIRST: /* 3 (server) Just created, must ACK the SYN request */ |
| 474 | + case eSYN_RECEIVED: /* 4 (server) waiting for a confirming connection request */ |
| 475 | + FreeRTOS_debug_printf( ( "Restoring a reuse socket port %u\n", pxSocket->usLocalPort ) ); |
| 476 | + |
| 477 | + /* Go back into listening mode. Set the TCP status to 'eCLOSED', |
| 478 | + * otherwise FreeRTOS_listen() will refuse the action. */ |
| 479 | + pxSocket->u.xTCP.eTCPState = eCLOSED; |
| 480 | + |
| 481 | + /* vSocketListenNextTime() makes sure that FreeRTOS_listen() will be called |
| 482 | + * before the IP-task handles any new message. */ |
| 483 | + vSocketListenNextTime( pxSocket ); |
| 484 | + break; |
| 485 | + |
| 486 | + default: |
| 487 | + /* Nothing to do. */ |
| 488 | + break; |
| 489 | + } |
| 490 | + } |
| 491 | + |
420 | 492 | /* Touch the alive timers because moving to another state. */
|
421 | 493 | prvTCPTouchSocket( pxSocket );
|
422 | 494 |
|
|
585 | 657 | ulLocalIP = FreeRTOS_htonl( pxIPHeader->ulDestinationIPAddress );
|
586 | 658 | ulRemoteIP = FreeRTOS_htonl( pxIPHeader->ulSourceIPAddress );
|
587 | 659 |
|
588 |
| - /* Find the destination socket, and if not found: return a socket listing to |
| 660 | + /* Find the destination socket, and if not found: return a socket listening to |
589 | 661 | * the destination PORT. */
|
590 | 662 | pxSocket = ( FreeRTOS_Socket_t * ) pxTCPSocketLookup( ulLocalIP, usLocalPort, ulRemoteIP, usRemotePort );
|
591 | 663 |
|
|
0 commit comments