Sming icon indicating copy to clipboard operation
Sming copied to clipboard

SmtpClient Memory Leak

Open frankdownunder opened this issue 5 years ago • 2 comments

I suspect there may be a memory leak in sending an email (or maybe the samples error handling could be improved) I modified the sample to send to a host that does not exist, ie mail.smtp2go.comXXX The same behaviour is probable for a server that is temporarily unavailable.

I tried to send 10 emails in a row. I would expect it to fail of course, but not to use memory on each call. Obviously the connect fails, and I really should avoid calling the function sendEmail(). - do I just test the return value of the connect function? If so can I suggest we change the sample code?

Program output: Connect called Free: 44752 send called Free: 43816 send called Free: 42880 send called Free: 41936 send called Free: 40992 open errno -10007 send called Free: 40064 open errno -10007 send called Free: 39552 open errno -10007 send called Free: 39024 open errno -10007 send called Free: 38512 open errno -10007

Here is the code I used:

#include <user_config.h>
#include "SmingCore/SmingCore.h"
#include "SmingCore/Network/SmtpClient.h"

// If you want, you can define WiFi settings globally in Eclipse Environment Variables
#ifndef WIFI_SSID
#define WIFI_SSID "PleaseEnterSSID" // Put you SSID and Password here
#define WIFI_PWD "PleaseEnterPass"
#endif

// Make sure to change those to your desired values
#define MAIL_FROM "[email protected]"
#define MAIL_TO "[email protected]"
#define SMTP_USERNAME
#define SMTP_PASSWORD
#define SMTP_HOST "attachix.comXXX"
#define SMTP_PORT 25
#define SMTP_USE_SSL false

SmtpClient client;
Timer counterTimer;

int onServerError(SmtpClient& client, int code, char* status)
{
	debugf("Status: %s", status);

	return 0; // return non-zero value to abort the connection
}

int ctr = 0;

int onMailSent(SmtpClient& client, int code, char* status)
{
	// get the sent mail message
	MailMessage* mail = client.getCurrentMessage();

	// TODO: The status line contains the unique ID that was given to this email
	debugf("Mail sent. Status: %s", status);

	// And if there are no more pending emails then you can disconnect from the server
	if(!client.countPending()) {
		debugf("No more mails to send. Quitting...");
		client.quit();
	}
	return 0;
}

void sendEmail()
{
	ctr++;
	if ( ctr >= 10 )
		return;

	debugf("Free: %d", system_get_free_heap_size());

	MailMessage* mail = new MailMessage();
	mail->from = MAIL_FROM;
	mail->to = MAIL_TO;
	mail->subject = "Greetings from Sming";
	mail->setBody("Hello.\r\n.\r\n"
				  "This is test email from Sming <https://github.com/SmingHub/Sming>"
				  "It contains attachment, Ümlauts, кирилица + etc");

	FileStream* file = new FileStream("image.png");
	mail->addAttachment(file);
	debugf("Attachment attached");


	client.onMessageSent(onMailSent);
	client.send(mail);
	debugf("send called");

}

void onConnected(IPAddress ip, IPAddress mask, IPAddress gateway)
{
#ifdef ENABLE_SSL
	client.addSslOptions(SSL_SERVER_VERIFY_LATER);
#endif

	client.onServerError(onServerError);

	String dsn = "smtp";
	if(SMTP_USE_SSL) {
		dsn += "s";
	}

	dsn += String("://") + SMTP_USERNAME + ":" + SMTP_PASSWORD + "@" + SMTP_HOST + ":" + SMTP_PORT;
	debugf("Connecting to SMTP server using: %s", dsn.c_str());

	client.connect(URL(dsn));
	debugf("Connect called");

	
	counterTimer.initializeMs(2000,	sendEmail).start();
}

void init()
{
	Serial.begin(SERIAL_BAUD_RATE);
	Serial.systemDebugOutput(true);
	Serial.println("Sming: SmtpClient example!");

	spiffs_mount();

	// Setup the WIFI connection
	WifiStation.enable(true);
	WifiStation.config(WIFI_SSID, WIFI_PWD); // Put you SSID and Password here

	WifiEvents.onStationGotIP(onConnected);
}

frankdownunder avatar Aug 06 '18 11:08 frankdownunder

Hm.. You can probably do something else. Put an email in the queue. Wait for the email to be sent using onMailSent callback. If that one is sent then send another one. Otherwise you are just stuffing the queues with emails that will never be sent.

slaff avatar Aug 06 '18 12:08 slaff

@slaff I did as you suggested, works well now. Would you like me to amend the sample to:

  1. Check the result of the connect
  2. Try to send a second email but only if the queue is empty OR I can just add some comments to the sample to suggest how production code might handle these issues.

frankdownunder avatar Aug 10 '18 23:08 frankdownunder