int32_t SOCKETS_SetSockOpt()

in amazon-freertos/lib/secure_sockets/portable/lwip/aws_secure_sockets.c [575:782]


int32_t SOCKETS_SetSockOpt( Socket_t xSocket,
                            int32_t lLevel,
                            int32_t lOptionName,
                            const void * pvOptionValue,
                            size_t xOptionLength )
{
    ss_ctx_t * ctx;
    int        ret;
    char ** ppcAlpnIn = ( char ** ) pvOptionValue;
    size_t xLength = 0;
    uint32_t ulProtocol;

    if( SOCKETS_INVALID_SOCKET == xSocket )
    {
        return SOCKETS_EINVAL;
    }

    ctx            = ( ss_ctx_t * )xSocket;

    if( 0 > ctx->ip_socket )
    {
        return SOCKETS_SOCKET_ERROR;
    }

    switch( lOptionName )
    {
        case SOCKETS_SO_RCVTIMEO:
        case SOCKETS_SO_SNDTIMEO:
        {
            TickType_t      ticks;
            struct timeval  tv;

            ticks = *( ( const TickType_t * ) pvOptionValue );

            tv.tv_sec  = TICK_TO_S ( ticks );
            tv.tv_usec = TICK_TO_US( ticks % configTICK_RATE_HZ );

            ret = lwip_setsockopt( ctx->ip_socket,
                                   SOL_SOCKET,
                                   lOptionName == SOCKETS_SO_RCVTIMEO ? SO_RCVTIMEO : SO_SNDTIMEO,
                                   ( struct timeval * )&tv,
                                   sizeof( tv ) );

            if (0 != ret)
            {
                return SOCKETS_EINVAL;
            }

            break;
        }

        case SOCKETS_SO_NONBLOCK:
        {
            int opt;

            if( ( ctx->status & SS_STATUS_CONNECTED ) != SS_STATUS_CONNECTED )
            {
                return SOCKETS_ENOTCONN;
            }

            opt = 1;

            ret = lwip_ioctl( ctx->ip_socket, FIONBIO, &opt );

            if (0 != ret)
            {
                return SOCKETS_EINVAL;
            }

            break;
        }

        case SOCKETS_SO_REQUIRE_TLS:
        {
            if( ctx->status & SS_STATUS_CONNECTED )
            {
                return SOCKETS_EISCONN;
            }

            ctx->enforce_tls = true;
            break;
        }

        case SOCKETS_SO_TRUSTED_SERVER_CERTIFICATE:
        {
            if( ctx->status & SS_STATUS_CONNECTED )
            {
                return SOCKETS_EISCONN;
            }

            if( NULL == pvOptionValue || 0 == xOptionLength )
            {
                return SOCKETS_EINVAL;
            }

            if( ctx->server_cert )
            {
                vPortFree( ctx->server_cert );
            }

            ctx->server_cert = pvPortMalloc ( xOptionLength+1 );

            if( NULL == ctx->server_cert )
            {
                return SOCKETS_ENOMEM;
            }
            memset(ctx->server_cert, 0, xOptionLength+1);
            memcpy( ctx->server_cert, pvOptionValue, xOptionLength );
            ctx->server_cert_len = xOptionLength;

            break;
        }

        case SOCKETS_SO_SERVER_NAME_INDICATION:
        {
            if( ctx->status & SS_STATUS_CONNECTED )
            {
                return SOCKETS_EISCONN;
            }

            if( NULL == pvOptionValue || 0 == xOptionLength )
            {
                return SOCKETS_EINVAL;
            }

            if( ctx->destination )
            {
                vPortFree( ctx->destination );
            }

            ctx->destination = pvPortMalloc ( xOptionLength + 1 );

            if( NULL == ctx->destination )
            {
                return SOCKETS_ENOMEM;
            }

            memcpy( ctx->destination, pvOptionValue, xOptionLength );
            ctx->destination[ xOptionLength ] = '\0';

            break;
        }

        case SOCKETS_SO_WAKEUP_CALLBACK:
        {
            if( xOptionLength == sizeof( void * ) &&
                pvOptionValue != NULL )
            {
                prvRxSelectSet( ctx, pvOptionValue );
            }
            else
            {
                prvRxSelectClear( ctx );
            }

            break;
        }

        case SOCKETS_SO_ALPN_PROTOCOLS:
        {
            /* Do not set the ALPN option if the socket is already connected. */
            if( ctx->status & SS_STATUS_CONNECTED )
            {
                return SOCKETS_EISCONN;
            }


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

            if( NULL == ( ctx->ppcAlpnProtocols =
                              ( char ** ) pvPortMalloc( ctx->ulAlpnProtocolsCount * sizeof( char * ) ) ) )
            {
                return SOCKETS_ENOMEM;
            }
            else
            {
                ctx->ppcAlpnProtocols[
                    ctx->ulAlpnProtocolsCount - 1 ] = NULL;
            }

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

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

            break;
        }
        default:
            return SOCKETS_ENOPROTOOPT;
    }

    return SOCKETS_ERROR_NONE;
}