Webserver Problem after certain time / calls

Hi All,
by setting up a webserver our Arduino can be controlled externally using JSON formatting.
So far so good, its working most of the time but when testing the system for some time and sending messages forth and back, it stops working at some point.

My test setup is chrome web browser from which we can talk to our webserver. For example checking the general state is:
192.168.0.10/state
Setting power on is:
192.168.0.10/setPower/on
Where: "setPower" is the command and "on" is the parameter

By using Easy Auto Refresh Plugin for Chrome, I set the refresh to one second and after about 30minutes the system stops working. This is more or less linear, so when refresh is every 2 seconds, it takes about 60 mins.

What happens is that the reply is a 404 error. Just from our code this means that the command could not be matched to any of the known commands. But we do not send anything else.
If this happens, the arduino is still working fine an doing the rest of work but there is no chance to control it via Webserver.
What helps is to reset the arduino or to call
asm volatile ("jmp 0"); //Soft reset

Logging the print out from the console shows that at some point it suddenly starts to struggle. The print out looks like this for example :

Computing: state

Request answered
Handle command cmd and param:
state

Computing: state

Request answered
Handle command cmd and param:
state

Computing: state

Request answered
Hacmd and param:
state

Computing: Request answered

Hawered
cmd and param:
state

CompRequest answered

Hawered
wered
cmd and param:
state

#Request answered
Hawered
wered
wered
cmd and param:
staRequest answered
Hawered
wered
wered
wered

....,.

Now I have to figure out how to upload the code...

I am not allowed to upload a file so I am pasting my code here, please let me know if there is any better way to share it:

#include <Arduino.h>

#include <Ethernet.h>

#include <TimeLib.h>

#include <Adafruit_Sensor.h>

#include <DHT.h>

#include <EEPROM-Storage.h>

// Network

EthernetServer server(80);                           

IPAddress defaultIP({192, 168, 0, 10});             

#define STRING_BUFFER_SIZE 128      

byte mac[] = {0x13, 0x03, 0x0C, 0x0C, 0x0C, 0x0C};

// ++++++++++++++++++++ +++ ++++++++++++ Setup ++++++++++++++++++++ +++ ++++++++++++

void setup() {

  Serial.begin(9600);

  server.begin();

  delay(1000);

  Ethernet.begin(mac, defaultIP);

  delay(1000);

  Serial.print(F("server is at "));

  Serial.println(Ethernet.localIP());

  setTime(0);

}

// ++++++++++++++++++++ +++ ++++++++++++ Loop ++++++++++++++++++++ +++ ++++++++++++

void loop() {

  delay(500);

  handleTraffic();

}

// ++++++++++++++++++++ +++ ++++++++++++ Network ++++++++++++++++++++ +++ ++++++++++++

void handleCommand(EthernetClient client, char* cmd, char* param) {

  Serial.println("Handle command cmd and param: ");

  Serial.println(cmd);

  Serial.println(param);

  

  if (strcmp(cmd, "state") == 0) {

    Serial.println(F("### Computing: state"));

    sendStatusJSON(client, false);

  }

  else if (strcmp(cmd, "setPower") == 0) {

    Serial.println(F("### Computing: power"));

    if(strcmp(param, "on")==0){

        //setOn();  

        sendJSON (client, F("statePower"), F("\"On\""));

    }

    else if(strcmp(param, "off")==0){

        //setOff();

        sendJSON (client, F("statePower"), F("\"Off\""));

    }

    else if(strcmp(param, "standby")==0){

        //setStandBy();

        sendJSON (client, F("statePower"), F("\"standby\""));

    }

    

  }

  else if (strcmp(cmd, "resetIP") == 0) {

    //resetIP();

    sendJSON (client, F("cmd"), F("\"Trying to reset IP address\""));

  }

  else if (strcmp(cmd, "setIP") == 0) {

    Serial.println(F("### Computing: setIP"));

    sendJSON (client, F("cmd"), F("\"Trying to change IP address\""));

    //storedIP = parseIP(param);

    //Ethernet.setLocalIP(storedIP);

    Serial.print(F("server is at "));

    Serial.println(Ethernet.localIP());

  }

  else if (strcmp(cmd, "setIPProj") == 0) {

    Serial.println(F("### Computing: setIP Projector"));

    sendJSON (client, F("cmd"), F("\"Changing my record of IP address of Projector\""));

    //storedIP_Projector = parseIP(param);

  }

  else {

    send404(client);

  }

}

// ++++++++++++++++++++ +++ ++++++++++++ Send Answers ++++++++++++++++++++ +++ ++++++++++++

void send404(EthernetClient client) {

  client.println(F("HTTP/1.1 404 OK"));

  client.println(F("Content-Type: text/html"));

  client.println(F("Access-Control-Allow-Headers: *"));

  client.println(F("Access-Control-Allow-Origin: *"));

  client.println(F("Access-Control-Allow-Methods: *"));

  client.println(F("Connnection: close"));

  client.println();

  client.println(F("<!DOCTYPE HTML>"));

  client.println(F("<html><body>404</body></html>"));

}

void sendJSON(EthernetClient client, String description, String value) {

  client.println(F("HTTP/1.1 200 OK"));

  client.println(F("Content-Type: application/json"));

  client.println(F("Access-Control-Allow-Headers: *"));

  client.println(F("Access-Control-Allow-Origin: *"));

  client.println(F("Access-Control-Allow-Methods: *"));

  client.println(F("Connnection: close"));

  client.println();

  client.println(F("{"));

  client.print(F("\t\"")); client.print(description); client.print(F("\": "));

  client.print(value);

  client.println();

  client.println(F("}"));

  client.println(F("\n"));

  return;

}

void sendStatusJSON(EthernetClient client, boolean expert) {

  client.println(F("HTTP/1.1 200 OK"));

  client.println(F("Content-Type: application/json"));

  client.println(F("Access-Control-Allow-Headers: *"));

  client.println(F("Access-Control-Allow-Origin: *"));

  client.println(F("Access-Control-Allow-Methods: *"));

  client.println(F("Connnection: close"));

  client.println();

  client.println(F("{"));

  client.print(F("\t\"state-.-.-.-.-.\": "));

  client.println(F(","));

  client.println();

  client.println(F("}"));

  client.println(F("\n"));

  return;

}

// ++++++++++++++++++++ +++ ++++++++++++ Webserver ++++++++++++++++++++ +++ ++++++++++++

char** parse(char* str) {

  char ** messages;

  messages = (char**)malloc(sizeof(char *));

  char *p;

  p = strtok(str, " ");

  unsigned int i = 0;

  while (p != NULL) {

    p = strtok(NULL, "/");

    char *sp;

    boolean last = false;

    sp = strchr(p, ' ');

    if (sp != NULL) {

      *sp++ = '\0';

      last = true;

    }

    messages[i] = p;

    i++;

    if (last) {

      break;

    }

    messages = (char**)realloc(messages, sizeof(char *) * i + 1);

  }

  messages[i] = '\0';

  return messages;

}

int countSegments(char* str) {

  int p = 0;

  int count = 0;

  while (str[p] != '\0') {

    if (str[p] == '/') {

      count++;

    }

    p++;

  }

  count--;

  return count;

}

void handleTraffic() {

  char buffer[STRING_BUFFER_SIZE];

  EthernetClient client = server.available();

  if (client) {

    boolean currentLineIsBlank = true;

    while (client.connected()) {

      if (client.available()) {

        char c;

        int bufindex = 0; // reset buffer

        buffer[0] = client.read();

        buffer[1] = client.read();

        bufindex = 2;

        while (buffer[bufindex - 2] != '\r' && buffer[bufindex - 1] != '\n') {

          c = client.read();

          if (bufindex < STRING_BUFFER_SIZE) {

            buffer[bufindex] = c;

          }

          bufindex++;

        }

        bufindex = 0;

        int nSegments = countSegments(buffer);

        char **pathsegments = parse(buffer);

        if (c == '\n' && currentLineIsBlank) {

          handleCommand(client, pathsegments[0], pathsegments[1]);

          break;

        }

        if (c == '\n') {

          currentLineIsBlank = true;

        } else if (c != '\r') {

          currentLineIsBlank = false;

        }

      }

    }

    delay(100);

    client.stop();

    Serial.println(F("Request answered"));

  }

}

And not a String in sight.
You use
messages = (char**)malloc(sizeof(char ));
and
messages = (char
*)realloc(messages, sizeof(char *) * i + 1);

But I cannot see anywhere you release the memory.

You may as well use String that does the allocation/reallocation for you.
See Taming Arduino Strings re passing String by reference (String &)
Although you will need to do some minor rewrites to your parser :frowning:

Also if this is ESP32 or ESP8266 you may just need to reboot every now and again to clean up the underlying Wifi library
see Out-Of-Memory on ESP32 and ESP8266 – Add Periodic Automatic Reboots for the code.

this is an unconvential Arduino webserver. Which tutorial/page are you following?

It will not be the root cause of your problems but I would like to add two remarks to

client.println(F("HTTP/1.1 200 OK"));

a) non of your HTTP headers contain the Content-Length which is mandatory in 1.1
if you don't have the content length available, send HTTP/1.0

b) I recommend to avoid the F-Macro in the context of (ethernet) client.print().

It will slow down your webserver. Use a temporary buffer or Juraj's StreamLib.h instead.
Here I did a comparision of several methods of client.print
[url]https://werner.rothschopf.net/microcontroller/202011_arduino_webserver_optimize_en.htm[/url]

In your HandleTraffic function you add characters one by one to buffer, but you never do not appear to null terminate buffer. This may well work for most of the time but if you ever fill buffer the next function (CountSegments) will carry on reading memory that is not part of buffer with the result you could end up with random characters being read.

You are also not checking whether malloc or realloc succeed or fail.

Thanks a lot!
After parsing the data I have added:
free(messages);

this works fine now also after 24/7 testing with requests every second.

Thanks! I have implemented your feedback!

Thanks, yes this was the root of the problem!

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.