BaseType_t FreeRTOS_setsockopt()

in FreeRTOS_Sockets.c [1747:2110]


BaseType_t FreeRTOS_setsockopt( Socket_t xSocket,
                                int32_t lLevel,
                                int32_t lOptionName,
                                const void * pvOptionValue,
                                size_t uxOptionLength )
{
/* The standard Berkeley function returns 0 for success. */
    BaseType_t xReturn = -pdFREERTOS_ERRNO_EINVAL;
    FreeRTOS_Socket_t * pxSocket;

    pxSocket = ( FreeRTOS_Socket_t * ) xSocket;

    /* The function prototype is designed to maintain the expected Berkeley
     * sockets standard, but this implementation does not use all the parameters. */
    ( void ) lLevel;
    ( void ) uxOptionLength;

    if( ( pxSocket == NULL ) || ( pxSocket == FREERTOS_INVALID_SOCKET ) )
    {
        xReturn = -pdFREERTOS_ERRNO_EINVAL;
        return xReturn;
    }

    switch( lOptionName )
    {
        case FREERTOS_SO_RCVTIMEO:
            /* Receive time out. */
            pxSocket->xReceiveBlockTime = *( ( const TickType_t * ) pvOptionValue );
            xReturn = 0;
            break;

        case FREERTOS_SO_SNDTIMEO:
            pxSocket->xSendBlockTime = *( ( const TickType_t * ) pvOptionValue );

            if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP )
            {
                /* The send time out is capped for the reason stated in the
                 * comments where ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS is defined
                 * in FreeRTOSIPConfig.h (assuming an official configuration file
                 * is being used. */
                if( pxSocket->xSendBlockTime > ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS )
                {
                    pxSocket->xSendBlockTime = ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS;
                }
            }
            else
            {
                /* For TCP socket, it isn't necessary to limit the blocking time
                 * because the FreeRTOS_send() function does not wait for a network
                 * buffer to become available. */
            }

            xReturn = 0;
            break;

            #if ( ipconfigUDP_MAX_RX_PACKETS > 0U )
                case FREERTOS_SO_UDP_MAX_RX_PACKETS:

                    if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_UDP )
                    {
                        break; /* will return -pdFREERTOS_ERRNO_EINVAL */
                    }

                    pxSocket->u.xUDP.uxMaxPackets = *( ( const UBaseType_t * ) pvOptionValue );
                    xReturn = 0;
                    break;
            #endif /* ipconfigUDP_MAX_RX_PACKETS */

        case FREERTOS_SO_UDPCKSUM_OUT:

            /* Turn calculating of the UDP checksum on/off for this socket. If pvOptionValue
             * is anything else than NULL, the checksum generation will be turned on. */

            if( pvOptionValue == NULL )
            {
                pxSocket->ucSocketOptions &= ~( ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT );
            }
            else
            {
                pxSocket->ucSocketOptions |= ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT;
            }

            xReturn = 0;
            break;

            #if ( ipconfigUSE_CALLBACKS == 1 )
                #if ( ipconfigUSE_TCP == 1 )
                    case FREERTOS_SO_TCP_CONN_HANDLER: /* Set a callback for (dis)connection events */
                    case FREERTOS_SO_TCP_RECV_HANDLER: /* Install a callback for receiving TCP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
                    case FREERTOS_SO_TCP_SENT_HANDLER: /* Install a callback for sending TCP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
                #endif /* ipconfigUSE_TCP */
                case FREERTOS_SO_UDP_RECV_HANDLER:     /* Install a callback for receiving UDP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
                case FREERTOS_SO_UDP_SENT_HANDLER:     /* Install a callback for sending UDP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */
                   {
                       #if ( ipconfigUSE_TCP == 1 )
                           {
                               UBaseType_t uxProtocol;

                               if( ( lOptionName == FREERTOS_SO_UDP_RECV_HANDLER ) ||
                                   ( lOptionName == FREERTOS_SO_UDP_SENT_HANDLER ) )
                               {
                                   uxProtocol = ( UBaseType_t ) FREERTOS_IPPROTO_UDP;
                               }
                               else
                               {
                                   uxProtocol = ( UBaseType_t ) FREERTOS_IPPROTO_TCP;
                               }

                               if( pxSocket->ucProtocol != ( uint8_t ) uxProtocol )
                               {
                                   break; /* will return -pdFREERTOS_ERRNO_EINVAL */
                               }
                           }
                       #else /* if ( ipconfigUSE_TCP == 1 ) */
                           {
                               /* No need to check if the socket has the right
                                * protocol, because only UDP socket can be created. */
                           }
                       #endif /* ipconfigUSE_TCP */

                       switch( lOptionName )
                       {
                           #if ipconfigUSE_TCP == 1
                               case FREERTOS_SO_TCP_CONN_HANDLER:
                                   pxSocket->u.xTCP.pxHandleConnected = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( F_TCP_UDP_Handler_t, pvOptionValue )->pxOnTCPConnected;
                                   break;

                               case FREERTOS_SO_TCP_RECV_HANDLER:
                                   pxSocket->u.xTCP.pxHandleReceive = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( F_TCP_UDP_Handler_t, pvOptionValue )->pxOnTCPReceive;
                                   break;

                               case FREERTOS_SO_TCP_SENT_HANDLER:
                                   pxSocket->u.xTCP.pxHandleSent = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( F_TCP_UDP_Handler_t, pvOptionValue )->pxOnTCPSent;
                                   break;
                           #endif /* ipconfigUSE_TCP */
                           case FREERTOS_SO_UDP_RECV_HANDLER:
                               pxSocket->u.xUDP.pxHandleReceive = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( F_TCP_UDP_Handler_t, pvOptionValue )->pxOnUDPReceive;
                               break;

                           case FREERTOS_SO_UDP_SENT_HANDLER:
                               pxSocket->u.xUDP.pxHandleSent = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( F_TCP_UDP_Handler_t, pvOptionValue )->pxOnUDPSent;
                               break;

                           default:
                               /* Should it throw an error here? */
                               break;
                       }
                   }

                    xReturn = 0;
                    break;
            #endif /* ipconfigUSE_CALLBACKS */

            #if ( ipconfigUSE_TCP != 0 )
                #if ( ipconfigSOCKET_HAS_USER_SEMAPHORE != 0 )

                    /* Each socket has a semaphore on which the using task normally
                     * sleeps. */
                    case FREERTOS_SO_SET_SEMAPHORE:
                       {
                           pxSocket->pxUserSemaphore = *( ipPOINTER_CAST( SemaphoreHandle_t *, pvOptionValue ) );
                       }
                        xReturn = 0;
                        break;
                #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */

                #if ( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK != 0 )
                    case FREERTOS_SO_WAKEUP_CALLBACK:

                        /* Each socket can have a callback function that is executed
                         * when there is an event the socket's owner might want to
                         * process. */
                        /* The type cast of the pointer expression "A" to type "B" removes const qualifier from the pointed to type. */
                        pxSocket->pxUserWakeCallback = ( SocketWakeupCallback_t ) pvOptionValue;
                        xReturn = 0;
                        break;
                #endif /* ipconfigSOCKET_HAS_USER_WAKE_CALLBACK */

                case FREERTOS_SO_SET_LOW_HIGH_WATER:
                   {
                       const LowHighWater_t * pxLowHighWater = ipPOINTER_CAST( const LowHighWater_t *, pvOptionValue );

                       if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
                       {
                           /* It is not allowed to access 'pxSocket->u.xTCP'. */
                           FreeRTOS_debug_printf( ( "FREERTOS_SO_SET_LOW_HIGH_WATER: wrong socket type\n" ) );
                           break; /* will return -pdFREERTOS_ERRNO_EINVAL */
                       }

                       if( ( pxLowHighWater->uxLittleSpace >= pxLowHighWater->uxEnoughSpace ) ||
                           ( pxLowHighWater->uxEnoughSpace > pxSocket->u.xTCP.uxRxStreamSize ) )
                       {
                           /* Impossible values. */
                           FreeRTOS_debug_printf( ( "FREERTOS_SO_SET_LOW_HIGH_WATER: bad values\n" ) );
                           break; /* will return -pdFREERTOS_ERRNO_EINVAL */
                       }

                       /* Send a STOP when buffer space drops below 'uxLittleSpace' bytes. */
                       pxSocket->u.xTCP.uxLittleSpace = pxLowHighWater->uxLittleSpace;
                       /* Send a GO when buffer space grows above 'uxEnoughSpace' bytes. */
                       pxSocket->u.xTCP.uxEnoughSpace = pxLowHighWater->uxEnoughSpace;
                       xReturn = 0;
                   }
                   break;

                case FREERTOS_SO_SNDBUF: /* Set the size of the send buffer, in units of MSS (TCP only) */
                case FREERTOS_SO_RCVBUF: /* Set the size of the receive buffer, in units of MSS (TCP only) */
                    xReturn = prvSockopt_so_buffer( pxSocket, lOptionName, pvOptionValue );
                    break;

                case FREERTOS_SO_WIN_PROPERTIES: /* Set all buffer and window properties in one call, parameter is pointer to WinProperties_t */
                   {
                       IPTCPSocket_t * pxTCP = &( pxSocket->u.xTCP );
                       const WinProperties_t * pxProps;

                       if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
                       {
                           FreeRTOS_debug_printf( ( "Set SO_WIN_PROP: wrong socket type\n" ) );
                           break; /* will return -pdFREERTOS_ERRNO_EINVAL */
                       }

                       if( ( pxTCP->txStream != NULL ) || ( pxTCP->rxStream != NULL ) )
                       {
                           FreeRTOS_debug_printf( ( "Set SO_WIN_PROP: buffer already created\n" ) );
                           break; /* will return -pdFREERTOS_ERRNO_EINVAL */
                       }

                       pxProps = ipPOINTER_CAST( const WinProperties_t *, pvOptionValue );

                       xReturn = prvSockopt_so_buffer( pxSocket, FREERTOS_SO_SNDBUF, &( pxProps->lTxBufSize ) );

                       if( xReturn != 0 )
                       {
                           break; /* will return an error. */
                       }

                       xReturn = prvSockopt_so_buffer( pxSocket, FREERTOS_SO_RCVBUF, &( pxProps->lRxBufSize ) );

                       if( xReturn != 0 )
                       {
                           break; /* will return an error. */
                       }

                       #if ( ipconfigUSE_TCP_WIN == 1 )
                           {
                               pxTCP->uxRxWinSize = ( uint32_t ) pxProps->lRxWinSize; /* Fixed value: size of the TCP reception window */
                               pxTCP->uxTxWinSize = ( uint32_t ) pxProps->lTxWinSize; /* Fixed value: size of the TCP transmit window */
                           }
                       #else
                           {
                               pxTCP->uxRxWinSize = 1U;
                               pxTCP->uxTxWinSize = 1U;
                           }
                       #endif

                       /* In case the socket has already initialised its tcpWin,
                        * adapt the window size parameters */
                       if( pxTCP->xTCPWindow.u.bits.bHasInit != pdFALSE_UNSIGNED )
                       {
                           pxTCP->xTCPWindow.xSize.ulRxWindowLength = ( uint32_t ) ( pxTCP->uxRxWinSize * pxTCP->usMSS );
                           pxTCP->xTCPWindow.xSize.ulTxWindowLength = ( uint32_t ) ( pxTCP->uxTxWinSize * pxTCP->usMSS );
                       }
                   }

                    xReturn = 0;
                    break;

                case FREERTOS_SO_REUSE_LISTEN_SOCKET: /* If true, the server-socket will turn into a connected socket */
                   {
                       if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
                       {
                           break; /* will return -pdFREERTOS_ERRNO_EINVAL */
                       }

                       if( *( ( const BaseType_t * ) pvOptionValue ) != 0 )
                       {
                           pxSocket->u.xTCP.bits.bReuseSocket = pdTRUE;
                       }
                       else
                       {
                           pxSocket->u.xTCP.bits.bReuseSocket = pdFALSE;
                       }
                   }
                    xReturn = 0;
                    break;

                case FREERTOS_SO_CLOSE_AFTER_SEND: /* As soon as the last byte has been transmitted, finalise the connection */
                   {
                       if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
                       {
                           break; /* will return -pdFREERTOS_ERRNO_EINVAL */
                       }

                       if( *( ( const BaseType_t * ) pvOptionValue ) != 0 )
                       {
                           pxSocket->u.xTCP.bits.bCloseAfterSend = pdTRUE;
                       }
                       else
                       {
                           pxSocket->u.xTCP.bits.bCloseAfterSend = pdFALSE;
                       }
                   }
                    xReturn = 0;
                    break;

                case FREERTOS_SO_SET_FULL_SIZE: /* Refuse to send packets smaller than MSS  */
                   {
                       if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
                       {
                           break; /* will return -pdFREERTOS_ERRNO_EINVAL */
                       }

                       if( *( ( const BaseType_t * ) pvOptionValue ) != 0 )
                       {
                           pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize = pdTRUE;
                       }
                       else
                       {
                           pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize = pdFALSE;
                       }

                       if( ( pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize == pdFALSE_UNSIGNED ) &&
                           ( pxSocket->u.xTCP.ucTCPState >= ( uint8_t ) eESTABLISHED ) &&
                           ( FreeRTOS_outstanding( pxSocket ) != 0 ) )
                       {
                           pxSocket->u.xTCP.usTimeout = 1U; /* to set/clear bSendFullSize */
                           ( void ) xSendEventToIPTask( eTCPTimerEvent );
                       }
                   }
                    xReturn = 0;
                    break;

                case FREERTOS_SO_STOP_RX: /* Refuse to receive more packets. */
                   {
                       if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
                       {
                           break; /* will return -pdFREERTOS_ERRNO_EINVAL */
                       }

                       if( *( ( const BaseType_t * ) pvOptionValue ) != 0 )
                       {
                           pxSocket->u.xTCP.bits.bRxStopped = pdTRUE;
                       }
                       else
                       {
                           pxSocket->u.xTCP.bits.bRxStopped = pdFALSE;
                       }

                       pxSocket->u.xTCP.bits.bWinChange = pdTRUE;
                       pxSocket->u.xTCP.usTimeout = 1U; /* to set/clear bRxStopped */
                       ( void ) xSendEventToIPTask( eTCPTimerEvent );
                   }
                    xReturn = 0;
                    break;
            #endif /* ipconfigUSE_TCP == 1 */

        default:
            /* No other options are handled. */
            xReturn = -pdFREERTOS_ERRNO_ENOPROTOOPT;
            break;
    }

    return xReturn;
} /* Tested */