cancel
Showing results for 
Search instead for 
Did you mean: 

Azure RTOS NetX Duo application hung in "stuck" socket_state loop?

MHoop.1
Senior

I have been trying to debug my custom Azure RTOS NetXDuo application (which is based on the Nx_Tcp_Echo Server example code). My application gets stuck in a loop that it cannot return from after reading the socket_state of an established socket. The application runs correctly, but at some point (for some as-yet-unknown reason) the socket_state changes from NX_TCP_ESTABLISHED to either NX_NOT_CONNECTED, or NX_NOT_LISTEN_STATE. Based on the code of the example, the application interprets this as IDLE state, which is not correct. At this point a client can no longer connect to my server application.

Here's the code.

while(1)
	{
		ULONG socket_state;
 
		TX_MEMSET(data_buffer, '\0', sizeof(data_buffer));
 
		/* get the socket state */
		nx_tcp_socket_info_get(&TCPSocket, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &socket_state, NULL, NULL, NULL);
 
		/* if the connections is not established then accept new ones, otherwise start receiving data */
		if(socket_state != NX_TCP_ESTABLISHED)
		{
			ret = nx_tcp_server_socket_accept(&TCPSocket, NX_IP_PERIODIC_RATE);
		}
 
//		if(ret== NX_NOT_CONNECTED || ret == NX_NOT_LISTEN_STATE)
//		{
//			nx_tcp_socket_disconnect(&TCPSocket, NX_WAIT_FOREVER);
//			nx_tcp_server_socket_unaccept(&TCPSocket);
//			nx_tcp_server_socket_relisten(&NetXDuoEthIpInstance, DEFAULT_PORT, &TCPSocket);
//		}
//		else
 
		if(ret == NX_SUCCESS)
		{
//			  tx_trace_enable(&tracex_buffer,TRACEX_BUFFER_SIZE,30);
 
			/* receive the TCP packet send by the client */
			ret = nx_tcp_socket_receive(&TCPSocket, &data_packet, NX_WAIT_FOREVER);

I have tried adding the following code (commented out above) in an attempt to force a disconnect and begin re-listening. But this does not reset the socket and no attempts by the client to connect are successful.

//		if(ret== NX_NOT_CONNECTED || ret == NX_NOT_LISTEN_STATE)
//		{
//			nx_tcp_socket_disconnect(&TCPSocket, NX_WAIT_FOREVER);
//			nx_tcp_server_socket_unaccept(&TCPSocket);
//			nx_tcp_server_socket_relisten(&NetXDuoEthIpInstance, DEFAULT_PORT, &TCPSocket);
//		}
//		else

I would expect that I should not be able to confuse the socket_state with any communication attempt from the client. I would also expect the code above to resolve a "stuck" socket_state.

I am new to NetXDuo and would appreciate some sage advice on the best way to handle this "stuck" code.

For completeness, here's the entire app_netxduo.c code.

static VOID App_TCP_Thread_Entry(ULONG thread_input)
{
	uint8_t cmdLen = 64;
	UINT uret_tx;
	UINT uret_rx;
	UINT ret;
	UCHAR data_buffer[512];
 
	ULONG source_ip_address;
	NX_PACKET *data_packet;
 
	UINT source_port;
	ULONG bytes_read;
 
	/* create the TCP socket */
	ret = nx_tcp_socket_create(&NetXDuoEthIpInstance, &TCPSocket, "TCP Server Socket", NX_IP_NORMAL, NX_FRAGMENT_OKAY,
			NX_IP_TIME_TO_LIVE, WINDOW_SIZE, NX_NULL, NX_NULL);
	if (ret != NX_SUCCESS)
	{
		Error_Handler();
	}
 
	/*
	 * listen to new client connections.
	 * the TCP_listen_callback will release the 'Semaphore' when a new connection is available
	 */
	ret = nx_tcp_server_socket_listen(&NetXDuoEthIpInstance, DEFAULT_PORT, &TCPSocket, MAX_TCP_CLIENTS, tcp_listen_callback);
 
	if (ret != NX_SUCCESS)
	{
		Error_Handler();
	}
	else
	{
		printf("TCP Server listening on PORT %d ..\n", DEFAULT_PORT);
	}
 
//	thx_thread_info_get(NxAppThread, TX_NULL, TX_NULL, &run_count, TX_NULL, TX_NULL, TX_NULL, TX_NULL , TX_NULL);
 
	if(tx_semaphore_get(&DHCPSemaphore, TX_WAIT_FOREVER) != TX_SUCCESS)
	{
		Error_Handler();
	}
	else
	{
		/* accept the new client connection before starting data exchange */
		ret = nx_tcp_server_socket_accept(&TCPSocket, TX_WAIT_FOREVER);
 
		if (ret != NX_SUCCESS)
		{
			Error_Handler();
		}
	}
 
	//Test delayed TraceX
//	  tx_trace_enable(&tracex_buffer,TRACEX_BUFFER_SIZE,30);
 
	while(1)
	{
		ULONG socket_state;
 
		TX_MEMSET(data_buffer, '\0', sizeof(data_buffer));
 
		/* get the socket state */
		nx_tcp_socket_info_get(&TCPSocket, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &socket_state, NULL, NULL, NULL);
 
		/* if the connections is not established then accept new ones, otherwise start receiving data */
		if(socket_state != NX_TCP_ESTABLISHED)
		{
			ret = nx_tcp_server_socket_accept(&TCPSocket, NX_IP_PERIODIC_RATE);
		}
 
//		if(ret== NX_NOT_CONNECTED || ret == NX_NOT_LISTEN_STATE)
//		{
//			nx_tcp_socket_disconnect(&TCPSocket, NX_WAIT_FOREVER);
//			nx_tcp_server_socket_unaccept(&TCPSocket);
//			nx_tcp_server_socket_relisten(&NetXDuoEthIpInstance, DEFAULT_PORT, &TCPSocket);
//		}
//		else
 
		if(ret == NX_SUCCESS)
		{
//			  tx_trace_enable(&tracex_buffer,TRACEX_BUFFER_SIZE,30);
 
			/* receive the TCP packet send by the client */
			ret = nx_tcp_socket_receive(&TCPSocket, &data_packet, NX_WAIT_FOREVER);
 
			if (ret == NX_SUCCESS)
			{
//				HAL_GPIO_TogglePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin);
 
				/* get the client IP address and  port */
				nx_udp_source_extract(data_packet, &source_ip_address, &source_port);
 
				/* retrieve the data sent by the client */
				nx_packet_data_retrieve(data_packet, data_buffer, &bytes_read);
 
				int i;
				printf("Command: ");
				for(i=0; i<16; i++)printf("%d,", data_buffer[i] );
				printf("\n");
 
				//Use blocking HAL_UART_Transmit and Receive since there are no interrupts in the HAL routines
				uret_tx = HAL_UART_Transmit(&huart2, data_buffer, cmdLen, 2000);
				if(!uret_tx)
				{
					TX_MEMSET(data_buffer, '\0', sizeof(data_buffer));
					uret_rx = HAL_UART_Receive(&huart2, data_buffer, cmdLen, 2000 );
				}
 
				printf("Response: ");
				for(i=0; i<16; i++) printf("%d,", data_buffer[i] );
				printf("\n");
 
				if(uret_tx) printf("USART TX Error %d.\n", uret_tx);
				if(uret_rx)
				{
					printf("USART RX Error %d.\n", uret_rx);
 
					HAL_UART_MspDeInit(&huart2);
					HAL_UART_MspInit(&huart2);
					huart2.Instance = USART2;
					huart2.Init.BaudRate = 230400;
					huart2.Init.WordLength = UART_WORDLENGTH_8B;
					huart2.Init.StopBits = UART_STOPBITS_1;
					huart2.Init.Parity = UART_PARITY_NONE;
					huart2.Init.Mode = UART_MODE_TX_RX;
					huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
					huart2.Init.OverSampling = UART_OVERSAMPLING_16;
					huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
					huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1;
					huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
					if (HAL_RS485Ex_Init(&huart2, UART_DE_POLARITY_HIGH, 0, 0) != HAL_OK)
					{
						Error_Handler();
					}
					if (HAL_UARTEx_DisableFifoMode(&huart2) != HAL_OK)
					{
						Error_Handler();
					}
				}
 
				data_packet->nx_packet_append_ptr = data_packet->nx_packet_prepend_ptr;
				ret = nx_packet_data_append(data_packet,data_buffer,cmdLen,&NxAppPool,NX_WAIT_FOREVER);
				data_packet->nx_packet_length=cmdLen;
				ret =  nx_tcp_socket_send(&TCPSocket, data_packet, NX_WAIT_FOREVER);
				if (ret == NX_SUCCESS) HAL_GPIO_TogglePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin);
				else
				{
					printf("TCP Send Error %d.\n", ret);
					nx_tcp_socket_disconnect(&TCPSocket, NX_WAIT_FOREVER);
					nx_tcp_server_socket_unaccept(&TCPSocket);
					nx_tcp_server_socket_relisten(&NetXDuoEthIpInstance, DEFAULT_PORT, &TCPSocket);
				}
			}
			else
			{
				HAL_GPIO_TogglePin(LED_RED_GPIO_Port, LED_RED_Pin);
				nx_tcp_socket_disconnect(&TCPSocket, NX_WAIT_FOREVER);
				nx_tcp_server_socket_unaccept(&TCPSocket);
				nx_tcp_server_socket_relisten(&NetXDuoEthIpInstance, DEFAULT_PORT, &TCPSocket);
			}
		}
		else
		{
//			nx_tcp_socket_disconnect(&TCPSocket, NX_WAIT_FOREVER);
//			nx_tcp_server_socket_unaccept(&TCPSocket);
//			nx_tcp_server_socket_relisten(&NetXDuoEthIpInstance, DEFAULT_PORT, &TCPSocket);
 
			/*toggle the green led to indicate the idle state */
			HAL_GPIO_TogglePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin);
		}
	}
}

Thanks,

MikeH

1 ACCEPTED SOLUTION

Accepted Solutions
MSG_ST
ST Employee

Hi,

Based on the Nx_TCP_Server application, the socket state follows this process :

At the beginning socket starts listening with NX_TCP_LISTEN_STATE.

Once the connection with client is established, socket state goes to NX_TCP_ESTABLISHED.

When client disconnect, server disconnected too and re-listen again, at this stage, socket goes back to NX_TCP_LISTEN_STATE.;

The NX_NOT_CONNECTED return is related to the TCP socket disconnection; at this stage, a TCP deferred cleanup routine is processing, and the AppTCPThread is considered as suspended with NX_NOT_CONNECTED status.

But this does not block the client to connect again to the server and send data.

However, the NX_NOT_LISTEN_STATE blocks the TCP client to reconnect to the Socket. And it's coming from the fact that the server socket is in a closing process and has no pending packets to proceed.

An update of the application is required to handle the NX_NOT_LISTEN_STATE and do not consider it as an idle state.

And this is done by adding the section below here (between lines 440 - 441) :

    else if (re == NX_NOT_LISTEN_STATE)
    {
      nx_tcp_socket_disconnect(&TCPSocket, NX_WAIT_FOREVER);
      nx_tcp_server_socket_unaccept(&TCPSocket);
      nx_tcp_server_socket_relisten(&NetXDuoEthIpInstance, DEFAULT_PORT, &TCPSocket);
    }

With this update, TCP client will be able to connect to the server even after an NX_NOT_LISTEN_STATE of the server socket.

I hope my answer helps.

Regards

Mahdy

View solution in original post

1 REPLY 1
MSG_ST
ST Employee

Hi,

Based on the Nx_TCP_Server application, the socket state follows this process :

At the beginning socket starts listening with NX_TCP_LISTEN_STATE.

Once the connection with client is established, socket state goes to NX_TCP_ESTABLISHED.

When client disconnect, server disconnected too and re-listen again, at this stage, socket goes back to NX_TCP_LISTEN_STATE.;

The NX_NOT_CONNECTED return is related to the TCP socket disconnection; at this stage, a TCP deferred cleanup routine is processing, and the AppTCPThread is considered as suspended with NX_NOT_CONNECTED status.

But this does not block the client to connect again to the server and send data.

However, the NX_NOT_LISTEN_STATE blocks the TCP client to reconnect to the Socket. And it's coming from the fact that the server socket is in a closing process and has no pending packets to proceed.

An update of the application is required to handle the NX_NOT_LISTEN_STATE and do not consider it as an idle state.

And this is done by adding the section below here (between lines 440 - 441) :

    else if (re == NX_NOT_LISTEN_STATE)
    {
      nx_tcp_socket_disconnect(&TCPSocket, NX_WAIT_FOREVER);
      nx_tcp_server_socket_unaccept(&TCPSocket);
      nx_tcp_server_socket_relisten(&NetXDuoEthIpInstance, DEFAULT_PORT, &TCPSocket);
    }

With this update, TCP client will be able to connect to the server even after an NX_NOT_LISTEN_STATE of the server socket.

I hope my answer helps.

Regards

Mahdy