TCP Client Consuming Heap Memory

Ritu21
Posts: 123
Joined: Sat Aug 04, 2018 9:58 am

TCP Client Consuming Heap Memory

Postby Ritu21 » Mon May 20, 2019 10:20 am

Hi Team,

After lot of checking, I got to know that TCP client is consuming almost 320bytes everytime data is sent to server. So, my project is about sending RFID data to server. There are 7 task, each running with an average stack size of 8192 bytes. Major tasks are https_client() is token, tcp_client() is encryption and hash based,& tcp_server().

Problem started with rebooting of device after 400 - 500 rfid card swipes with an error of multi heap corrupt. I started examining free heap size through xPortGetFreeHeapSize() in both https_client(), tcp_client() tasks. I stopped tcp_client() task and ran Https_client(), here Free heap size was recovering after every card swipes but vice-versa, it was consuming around 320 bytes after card swipes. Below is my code of tcp_client() task. Kindly review and check where is it consuming the heap memory.

Code: Select all

void tcp_client(void *pvParam)
{
	ESP_LOGI(TCP_CLIENT_TAG,"tcp_client task started \n");
	struct sockaddr_in tcpServerAddr;
	tcpServerAddr.sin_family = AF_INET;
	tcpServerAddr.sin_port = htons(8050);
	//int clientSocket = 0;
	int readBytes = 0, serverConnect = 0;
	char read_serverCommand[200];
	char *ip_in_flash = NULL;
	static uint8_t tcpClient_queue_buff[RFID_Q_BUFF_SIZE];
	char time_buf[32];
	struct timeval timeout;
	timeout.tv_sec = 0;
	timeout.tv_usec = 200000;
	struct timeval readTimeout;
	readTimeout.tv_sec = 0;
	readTimeout.tv_usec = 500000;
	bool openGateIsTrue = false;
	time_t rawtime;
	struct tm * timeinfo;
	uint32_t freeheap1;
	bool boolRfidDataSendFailed = false;
	bool boolStatusDataSendFailed = false;
	char recvdResponseCode[20];
	char flag_data_recvd[7];
	double dateTime_recvd = 0;
	char hash_recvd[100];
	int match_result = 0;
	//static struct timeval tm1, tm2, tm3, tm4;
	//unsigned long long t;
	int no_delay = 1;
	char devid_encrypt_data[700];
	char scanData_encrypt_data[700];
	char status_data[512];
	
	xEventGroupWaitBits(wifi_event_group,WIFI_STA_CONNECTED_BIT,false,true,portMAX_DELAY);
	tcpClientPingHandle10Sec = xTimerCreate("TCPPingTimer",pdMS_TO_TICKS(10000),pdTRUE,(void*)1, vTimerCallbackTCP10SecExpired);
	if(tcpClientPingHandle10Sec == NULL){
		printf("Timer Not Created\n");
	}
	else{
		printf("TCP Timer started\n");
		xTimerStart(tcpClientPingHandle10Sec, 0); 
	}
	while(1)
	{		//xEventGroupWaitBits(wifi_event_group,WIFI_STA_CONNECTED_BIT,false,true,portMAX_DELAY);
		if(g_boolSmartAccessStatus_ReceivedFromServer)
		{
			err = nvs_get_str(ipPortHandler, "ip2", NULL, &g_byIP_size);
			if(err != ESP_OK) 
			{
				printf("No IP in flash\n");
				tcpServerAddr.sin_addr.s_addr = inet_addr(TCPServerIP);
				printf("TCPSERVERIP = %s\n", TCPServerIP);
			}
			else{
				ip_in_flash = malloc(g_byIP_size);
				err = nvs_get_str(ipPortHandler, "ip2", ip_in_flash, &g_byIP_size);
				if(err != ESP_OK)
				{
					if(err == ESP_ERR_NVS_NOT_FOUND) 
					printf("\nError in nvs_get_str to get string! (%04X)\n", err);
					tcpServerAddr.sin_addr.s_addr = inet_addr(TCPServerIP);
					//return;
				}
				else
				{
					//printf("IP received from TCP client is %s\n",ip_in_flash);
					tcpServerAddr.sin_addr.s_addr = inet_addr(ip_in_flash);
					//tcpServerAddr.sin_addr.s_addr = inet_addr(IP);
					printf("The IP address is %s\n",inet_ntoa(tcpServerAddr.sin_addr));
				}
				free(ip_in_flash);
			}			
			clientSocket = socket(AF_INET, SOCK_STREAM, 0);
			if(clientSocket < 0) 
			{
				ESP_LOGE(TCP_CLIENT_TAG, "... Failed to allocate socket, errno=%d \n", errno);
				vTaskDelay(1000 / portTICK_PERIOD_MS);
				//continue;
			}
			else
			{
				ESP_LOGI(TCP_CLIENT_TAG, "... allocated socket\n");
				if((serverConnect = connect(clientSocket, (struct sockaddr *)&tcpServerAddr, sizeof(tcpServerAddr)) != 0)) {
					ESP_LOGE(TCP_CLIENT_TAG, "... socket connect failed errno=%d \n", errno);
					close(clientSocket);
					g_boolTcpServerConnected = false;
					vTaskDelay(1000 / portTICK_PERIOD_MS);
				}
				else
				{
					ESP_LOGI(TCP_CLIENT_TAG, "... connected...\n");
					g_boolTcpServerConnected = true;
					if (setsockopt(clientSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&readTimeout, sizeof(timeout)) < 0)
					{
						ESP_LOGE(TCP_TAG, "... setsockopt recv failed\n");
						close(clientSocket);
						//vTaskDelay(1000 / portTICK_PERIOD_MS);
					}
					if (setsockopt(clientSocket, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout)) < 0)
					{
						ESP_LOGE(TCP_TAG, "... setsockopt send failed\n");
						close(clientSocket);
						//vTaskDelay(1000 / portTICK_PERIOD_MS);
					}
					
					if (setsockopt(clientSocket, IPPROTO_TCP, TCP_NODELAY, (void *)&no_delay, sizeof(no_delay)) < 0)
					{
						ESP_LOGE(TCP_TAG, "... setsockopt no delay failed \n");
						close(clientSocket);
						//vTaskDelay(1000 / portTICK_PERIOD_MS);
					}
					encryptedDevId_toSend_toTCPServer(devid_encrypt_data);
					if(write(clientSocket, devid_encrypt_data, strlen(devid_encrypt_data)) == -1)
					{
						ESP_LOGE(TCP_CLIENT_TAG, "... dev id Send failed errno=%d \n", errno);
						close(clientSocket);
					}
					else{
						printf("Dev id write successful\n");
						while(1)
						{	
							if(boolRfidDataSendFailed)
							{
								boolRfidDataSendFailed = false;
								if(write(clientSocket, scanData_encrypt_data, strlen(scanData_encrypt_data)) == -1)
								{
									ESP_LOGE(TCP_CLIENT_TAG, "... failed RFID Send failed errno=%d \n", errno);
									close(clientSocket);
									break;
								}
								else{
									printf("failed RFID write successful\n");
								}
							}
							else if(boolStatusDataSendFailed)
							{
								boolStatusDataSendFailed = false;
								//if(write(clientSocket, status_json_in_buff, strlen(status_json_in_buff)) == -1)
								if(write(clientSocket, status_data, strlen(status_data)) == -1)
								{
									ESP_LOGE(TCP_CLIENT_TAG, "...failed status Send failed errno=%d \n", errno);
									close(clientSocket);
									break;
								}
								else{
									printf("failed status write successful\n");
								}
							}
							else
							{
								if(xQueuePeek(rfid_queue_tcpClient, tcpClient_queue_buff, ( TickType_t ) 1 ))
								{
									if(xQueueReceive(rfid_queue_tcpClient, tcpClient_queue_buff, ( TickType_t ) 0 ) == 
                                                                         pdTRUE)
									{
										//gettimeofday(&tm1, NULL);
										//ESP_LOG_BUFFER_HEXDUMP(TCP_CLIENT_TAG, tcpClient_queue_buff, 
                                                                                 g_byRfid_byteCopy, ESP_LOG_INFO);
										heap_caps_check_integrity_all(true);
										freeheap1 = xPortGetFreeHeapSize();
										printf("xPortGetFreeHeapSize TCP = %d bytes\n", freeheap1);
										time ( &rawtime );
										timeinfo = localtime ( &rawtime );
										strftime(time_buf, sizeof(time_buf), "%d/%m/%Y %H:%M:%S", timeinfo);
										ESP_LOGI(TCP_CLIENT_TAG, "The current date/time in India is: %s",time_buf);
										
										encryptedScanData_toSend_toTCPServer((char 
                                                                                 *)tcpClient_queue_buff,time_buf, scanData_encrypt_data);
										if(write(clientSocket, scanData_encrypt_data, strlen(scanData_encrypt_data)) 
                                                                                == -1)
										{
											ESP_LOGE(TCP_CLIENT_TAG, "... Send failed errno=%d \n", errno);
											boolRfidDataSendFailed = true;
											close(clientSocket);
											break;
										}
										else{
											printf("RFID write successful\n");
										}
									}
									heap_caps_check_integrity_all(true);
									freeheap1 = xPortGetFreeHeapSize();
									printf("xPortGetFreeHeapSize TCP 1 = %d bytes\n", freeheap1);
								}
							}
							bzero(read_serverCommand, sizeof(read_serverCommand));
							readBytes = recv(clientSocket, read_serverCommand, sizeof(read_serverCommand)-1, 0);
							//gettimeofday(&tm4, NULL);
							//t = 1000 * (tm4.tv_sec - tm3.tv_sec) + (tm4.tv_usec - tm3.tv_usec) / 1000;
							//printf("Recvd data after %llu ms\n", t);
							//printf("Number of bytes received : %d\n", readBytes);
							//printf("Received: %s\n",(char*)read_serverCommand);
							if(readBytes > 0)
							{
								openGateIsTrue = parseData_recvdOn_TCPClient(read_serverCommand, 
                                                                 recvdResponseCode, flag_data_recvd, &dateTime_recvd, hash_recvd);
								//printf("DATE TIME RECVD = %f\n",dateTime_recvd);
								printf("Open Gate flag = %d\n", openGateIsTrue);
								match_result = match_data(flag_data_recvd, dateTime_recvd, hash_recvd, 
                                                                recvdResponseCode);
								if(match_result >= 0)
								{
									if(match_result == 1)
									{
										//gettimeofday(&tm2, NULL);
										//t = 1000 * (tm2.tv_sec - tm1.tv_sec) + (tm2.tv_usec - tm1.tv_usec) / 1000;
										//printf("Delay in Timer Start = %llu ms\n", t);
										gpio_set_level(SMART_ACCESS_RELAY_OUTPUT_PIN, 1);
										gpio_set_level(SMART_ACCESS_GRANTED_OUTPUT_PIN, 1);
										//printf("LED ON\n");
										
										if(g_boolTcpTimerIsOn == false){
											g_boolTcpTimerIsOn = true;
											tcpRelayTimerHandle3Sec = NULL;
											tcpRelayTimerHandle3Sec = 
                                                                                        xTimerCreate("TCPRelayTimer",pdMS_TO_TICKS(3000),pdFALSE,(void*)1, 
                                                                                        vTimerCallbackTCP3SecExpired);
											if(tcpRelayTimerHandle3Sec == NULL){
												printf("Timer Not Created\n");
											}
											else{
												printf("TCP Timer started\n");
												xTimerStart(tcpRelayTimerHandle3Sec, 0); 
											}
										}
										else{
											printf("Resetting TCP timer\n");
											if(xTimerReset(tcpRelayTimerHandle3Sec, 0)!=pdPASS) {
												printf("Timer not resetted\n");
											}
										}
									}
									else
										printf("DECRYPTION results to 0\n");
								}
								if(openGateIsTrue)
								{
									openGateIsTrue = false;
									openGateStatus_sendTo_TCPServer(recvdResponseCode, status_data);
									if(write(clientSocket, status_data, strlen(status_data)) == -1)
									{
										ESP_LOGE(TCP_CLIENT_TAG, "... Send failed errno=%d \n", errno);
										boolStatusDataSendFailed = true;
										close(clientSocket);
										break;
									}
									else{
										printf("write successful\n");
									}
								}
								heap_caps_check_integrity_all(true);
								freeheap1 = xPortGetFreeHeapSize();
								printf("xPortGetFreeHeapSize TCP 2 = %d bytes\n", freeheap1);
								
							}
							else if(readBytes == 0)
							{
								printf("Connection closed\n");
								close(clientSocket);
								break;
							}
							if(!g_boolStationDisconnected)
							{
								printf("Internet Disconnected\n");
								close(clientSocket);
								break;
							}
							if(clientSocket == 0)
							{
								printf("CLIENT SOCKET = 0\n");
								break;
							}
							if(g_boolNewIP_Received)
							{
								g_boolNewIP_Received = false;
								printf("New IP Received\n");
								break;
							}
						}
					}
				}
			}
		}
		else{
			vTaskDelay(1000 / portTICK_PERIOD_MS);
		}			
	}	
}
Waiting for your response.

Thanks
Ritu

ESP_Sprite
Posts: 9766
Joined: Thu Nov 26, 2015 4:08 am

Re: TCP Client Consuming Heap Memory

Postby ESP_Sprite » Tue May 21, 2019 1:48 am

I normally don't mind looking through code for memory leaks, but honestly, that routine is one big ball of mud; I'd strongly recommend refactoring it into a bunch of standalone subroutines. Chances are that while doing that, you'll find your memory leak in the process; if not, it makes it way more likely that someone here on the forum is able (and willing) to find it.

ESP_Angus
Posts: 2344
Joined: Sun May 08, 2016 4:11 am

Re: TCP Client Consuming Heap Memory

Postby ESP_Angus » Tue May 21, 2019 5:02 am

Ritu21 wrote:
Mon May 20, 2019 10:20 am
Kindly review and check where is it consuming the heap memory.
Hi Ritu,

You can use the heap tracing feature in IDF to find allocations which are not freed:
https://docs.espressif.com/projects/esp ... ap-tracing

Note that closed TCP sockets in TIME_WAIT state will use some heap memory until they time out. If you find that heap usage stabilises over time (several minutes or longer), then this is the reason. For more information see the "False-Positive Memory Leaks" section on the linked documentation page.

BTW, I agree with Jeroen that you will find this code much easier to debug if you refactor it into multiple functions.

Who is online

Users browsing this forum: No registered users and 155 guests