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;
}