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 */