int32_t SOCKETS_SetSockOpt()

in amazon-freertos/lib/secure_sockets/portable/freertos_plus_tcp/aws_secure_sockets.c [274:461]


int32_t SOCKETS_SetSockOpt( Socket_t xSocket,
                            int32_t lLevel,
                            int32_t lOptionName,
                            const void * pvOptionValue,
                            size_t xOptionLength )
{
    int32_t lStatus = SOCKETS_ERROR_NONE;
    TickType_t xTimeout;
    SSOCKETContextPtr_t pxContext = ( SSOCKETContextPtr_t ) xSocket; /*lint !e9087 cast used for portability. */
    char ** ppcAlpnIn = ( char ** ) pvOptionValue;
    size_t xLength = 0;
    uint32_t ulProtocol;

    if( ( xSocket != SOCKETS_INVALID_SOCKET ) && ( xSocket != NULL ) )
    {
        switch( lOptionName )
        {
            case SOCKETS_SO_SERVER_NAME_INDICATION:

                /* Do not set the SNI options if the socket is possibly already connected. */
                if( pxContext->xConnectAttempted == pdTRUE )
                {
                    lStatus = SOCKETS_EISCONN;
                }

                /* Non-NULL destination string indicates that SNI extension should
                 * be used during TLS negotiation. */
                else if( NULL == ( pxContext->pcDestination =
                                       ( char * ) pvPortMalloc( 1U + xOptionLength ) ) )
                {
                    lStatus = SOCKETS_ENOMEM;
                }
                else
                {
                    memcpy( pxContext->pcDestination, pvOptionValue, xOptionLength );
                    pxContext->pcDestination[ xOptionLength ] = '\0';
                }

                break;

            case SOCKETS_SO_TRUSTED_SERVER_CERTIFICATE:

                /* Do not set the trusted server certificate if the socket is possibly already connected. */
                if( pxContext->xConnectAttempted == pdTRUE )
                {
                    lStatus = SOCKETS_EISCONN;
                }

                /* Non-NULL server certificate field indicates that the default trust
                 * list should not be used. */
                else if( NULL == ( pxContext->pcServerCertificate =
                                       ( char * ) pvPortMalloc( xOptionLength ) ) )
                {
                    lStatus = SOCKETS_ENOMEM;
                }
                else
                {
                    memcpy( pxContext->pcServerCertificate, pvOptionValue, xOptionLength );
                    pxContext->ulServerCertificateLength = xOptionLength;
                }

                break;

            case SOCKETS_SO_REQUIRE_TLS:

                /* Do not set the TLS option if the socket is possibly already connected. */
                if( pxContext->xConnectAttempted == pdTRUE )
                {
                    lStatus = SOCKETS_EISCONN;
                }
                else
                {
                    pxContext->xRequireTLS = pdTRUE;
                }

                break;

            case SOCKETS_SO_ALPN_PROTOCOLS:

                /* Do not set the ALPN option if the socket is already connected. */
                if( pxContext->xConnectAttempted == pdTRUE )
                {
                    lStatus = SOCKETS_EISCONN;
                    break;
                }

                /* Allocate a sufficiently long array of pointers. */
                pxContext->ulAlpnProtocolsCount = 1 + xOptionLength;

                if( NULL == ( pxContext->ppcAlpnProtocols =
                                  ( char ** ) pvPortMalloc( pxContext->ulAlpnProtocolsCount * sizeof( char * ) ) ) )
                {
                    lStatus = SOCKETS_ENOMEM;
                }
                else
                {
                    /* Zero out the pointers. */
                    memset( pxContext->ppcAlpnProtocols,
                            0,
                            pxContext->ulAlpnProtocolsCount * sizeof( char * ) );
                }

                /* Copy each protocol string. */
                for( ulProtocol = 0;
                     ( ulProtocol < pxContext->ulAlpnProtocolsCount - 1 ) &&
                     ( pdFREERTOS_ERRNO_NONE == lStatus );
                     ulProtocol++ )
                {
                    xLength = strlen( ppcAlpnIn[ ulProtocol ] );

                    if( NULL == ( pxContext->ppcAlpnProtocols[ ulProtocol ] =
                                      ( char * ) pvPortMalloc( 1 + xLength ) ) )
                    {
                        lStatus = SOCKETS_ENOMEM;
                    }
                    else
                    {
                        memcpy( pxContext->ppcAlpnProtocols[ ulProtocol ],
                                ppcAlpnIn[ ulProtocol ],
                                xLength );
                        pxContext->ppcAlpnProtocols[ ulProtocol ][ xLength ] = '\0';
                    }
                }

                break;

            case SOCKETS_SO_NONBLOCK:
                xTimeout = 0;

                /* Non-blocking connect is not supported.  Socket may be set to nonblocking
                 * only after a connection is made. */
                if( pdTRUE == pxContext->xConnectAttempted )
                {
                    lStatus = FreeRTOS_setsockopt( pxContext->xSocket,
                                                   lLevel,
                                                   SOCKETS_SO_RCVTIMEO,
                                                   &xTimeout,
                                                   sizeof( xTimeout ) );

                    if( lStatus == SOCKETS_ERROR_NONE )
                    {
                        lStatus = FreeRTOS_setsockopt( pxContext->xSocket,
                                                       lLevel,
                                                       SOCKETS_SO_SNDTIMEO,
                                                       &xTimeout,
                                                       sizeof( xTimeout ) );
                    }
                }
                else
                {
                    lStatus = SOCKETS_EISCONN;
                }

                break;

            case SOCKETS_SO_RCVTIMEO:
            case SOCKETS_SO_SNDTIMEO:
                /* Comply with Berkeley standard - a 0 timeout is wait forever. */
                xTimeout = *( ( const TickType_t * ) pvOptionValue ); /*lint !e9087 pvOptionValue passed should be of TickType_t */

                if( xTimeout == 0U )
                {
                    xTimeout = portMAX_DELAY;
                }

                lStatus = FreeRTOS_setsockopt( pxContext->xSocket,
                                               lLevel,
                                               lOptionName,
                                               &xTimeout,
                                               xOptionLength );
                break;

            default:
                lStatus = FreeRTOS_setsockopt( pxContext->xSocket,
                                               lLevel,
                                               lOptionName,
                                               pvOptionValue,
                                               xOptionLength );
                break;
        }
    }
    else
    {
        lStatus = SOCKETS_EINVAL;
    }

    return lStatus;
}