BaseType_t FreeRTOS_setsockopt()

in device_firmware/libraries/freertos_plus/standard/freertos_plus_tcp/source/FreeRTOS_Sockets.c [1279:1645]


BaseType_t FreeRTOS_setsockopt( Socket_t xSocket, int32_t lLevel, int32_t lOptionName, const void *pvOptionValue, size_t xOptionLength )
{
/* The standard Berkeley function returns 0 for success. */
BaseType_t xReturn = -pdFREERTOS_ERRNO_EINVAL;
BaseType_t lOptionValue;
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 ) xOptionLength;

	configASSERT( xSocket );

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

		case FREERTOS_SO_SNDTIMEO	:
			pxSocket->xSendBlockTime = *( ( 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 > 0 )
			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 = *( ( 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. */
			lOptionValue = ( BaseType_t ) pvOptionValue;

			if( lOptionValue == 0 )
			{
				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
						{
							/* 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 = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnTCPConnected;
								break;
							case FREERTOS_SO_TCP_RECV_HANDLER:
								pxSocket->u.xTCP.pxHandleReceive = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnTCPReceive;
								break;
							case FREERTOS_SO_TCP_SENT_HANDLER:
								pxSocket->u.xTCP.pxHandleSent = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnTCPSent;
								break;
						#endif /* ipconfigUSE_TCP */
						case FREERTOS_SO_UDP_RECV_HANDLER:
							pxSocket->u.xUDP.pxHandleReceive = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnUDPReceive;
							break;
						case FREERTOS_SO_UDP_SENT_HANDLER:
							pxSocket->u.xUDP.pxHandleSent = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnUDPSent;
							break;
						default:
							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 = *( ( 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. */
					pxSocket->pxUserWakeCallback = ( SocketWakeupCallback_t ) pvOptionValue;
					xReturn = 0;
				}
				break;
			#endif /* ipconfigSOCKET_HAS_USER_WAKE_CALLBACK */

			case FREERTOS_SO_SET_LOW_HIGH_WATER:
				{
				LowHighWater_t *pxLowHighWater = ( 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) */
				{
					uint32_t ulNewValue;

					if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP )
					{
						FreeRTOS_debug_printf( ( "Set SO_%sBUF: wrong socket type\n",
							( lOptionName == FREERTOS_SO_SNDBUF ) ? "SND" : "RCV" ) );
						break;	/* will return -pdFREERTOS_ERRNO_EINVAL */
					}

					if( ( ( lOptionName == FREERTOS_SO_SNDBUF ) && ( pxSocket->u.xTCP.txStream != NULL ) ) ||
						( ( lOptionName == FREERTOS_SO_RCVBUF ) && ( pxSocket->u.xTCP.rxStream != NULL ) ) )
					{
						FreeRTOS_debug_printf( ( "Set SO_%sBUF: buffer already created\n",
							( lOptionName == FREERTOS_SO_SNDBUF ) ? "SND" : "RCV" ) );
						break;	/* will return -pdFREERTOS_ERRNO_EINVAL */
					}

					ulNewValue = *( ( uint32_t * ) pvOptionValue );

					if( lOptionName == FREERTOS_SO_SNDBUF )
					{
						/* Round up to nearest MSS size */
						ulNewValue = FreeRTOS_round_up( ulNewValue, ( uint32_t ) pxSocket->u.xTCP.usInitMSS );
						pxSocket->u.xTCP.uxTxStreamSize = ulNewValue;
					}
					else
					{
						pxSocket->u.xTCP.uxRxStreamSize = ulNewValue;
					}
				}
				xReturn = 0;
				break;

			case FREERTOS_SO_WIN_PROPERTIES:	/* Set all buffer and window properties in one call, parameter is pointer to WinProperties_t */
				{
					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( ( pxSocket->u.xTCP.txStream != NULL ) || ( pxSocket->u.xTCP.rxStream != NULL ) )
					{
						FreeRTOS_debug_printf( ( "Set SO_WIN_PROP: buffer already created\n" ) );
						break;	/* will return -pdFREERTOS_ERRNO_EINVAL */
					}

					pxProps = ( ( WinProperties_t * ) pvOptionValue );

					if ( FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDBUF, &( pxProps->lTxBufSize ), sizeof( pxProps->lTxBufSize ) ) != 0 )
					{
						break;	/* will return -pdFREERTOS_ERRNO_EINVAL */
					}

					if ( FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVBUF, &( pxProps->lRxBufSize ), sizeof( pxProps->lRxBufSize ) ) != 0 )
					{
						break;	/* will return -pdFREERTOS_ERRNO_EINVAL */
					}

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

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

				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( *( ( BaseType_t * ) pvOptionValue ) != 0 )
					{
						pxSocket->u.xTCP.bits.bReuseSocket = pdTRUE_UNSIGNED;
					}
					else
					{
						pxSocket->u.xTCP.bits.bReuseSocket = pdFALSE_UNSIGNED;
					}
				}
				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( *( ( BaseType_t * ) pvOptionValue ) != 0 )
					{
						pxSocket->u.xTCP.bits.bCloseAfterSend = pdTRUE_UNSIGNED;
					}
					else
					{
						pxSocket->u.xTCP.bits.bCloseAfterSend = pdFALSE_UNSIGNED;
					}
				}
				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( *( ( BaseType_t * ) pvOptionValue ) != 0 )
					{
						pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize = pdTRUE_UNSIGNED;
					}
					else
					{
						pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize = pdFALSE_UNSIGNED;
					}

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

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

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

					pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED;
					pxSocket->u.xTCP.usTimeout = 1u; /* to set/clear bRxStopped */
					xSendEventToIPTask( eTCPTimerEvent );
				}
				xReturn = 0;
				break;

		#endif  /* ipconfigUSE_TCP == 1 */

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

	return xReturn;
} /* Tested */