Ethernet shield hangs after HTTP POST received

Hi, everybody!

I am facing a very weird problem here: I hope you can help me with it.

I have an arduino client that sends data through a HTTP Post request to my apache web server(with PHP

and MySQL) every time a button is pushed .
The apache server processes the data and sends a HTTP POST request (via cURL) to an arduino web server, which takes an action according to the message received from the apache server.
The whole system has been working fine for almost 2 months now.

I have a couple more arduinos for testing purpouses tha I am using along with an apache web server on a virtual machine (the same vm I used to develop that system that is still runnig).
Now, the problem is that, on the test system, my arduino web server hangs for a while after it receives the HTTP POST request from the apache web server: it just sits there for 30 to 60 seconds and then it can receive another POST request.
I really do not know why this is happening: it look like a connection problem to me, but I checked both MAC and IP addresses and they are ok; also when it hangs, I can still ping into it.
I really do not know how what to do.

Any idea?
Thank you.

here is the code I am using for the arduino web server:

#include <SPI.h>
#include <Ethernet.h>
#include <string.h>

 byte mac[] = { 0xDE, 0xAD, 0xC0, 0xA8, 0x01, 0x34 };  // TEST MAC Address: 0xDE, 0xAD + HEX(192.168.1.52)
 IPAddress ip(192,168,1,52); 
 EthernetServer server(80);
 EthernetClient client;

// Delay time
int WAIT = 300;

// Buffer to store HTTP POST Request
#define bufferMax 128
int bufferSize;
char buffer[bufferMax];

// *********************************************************************************

// *********************************************************************************
// SETUP
// Initilizing Arduino
// *********************************************************************************
void setup() {
  //Start serial port for debugging
  Serial.begin(9600);

  
  // Set pin D8,D7,D6 as OUTPUT
  pinMode(8, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(6, OUTPUT);

  
  // Start network connection
  setupCommunications();
      
}

//********************************************************
//** loop
//** This is the main function 
//********************************************************
void loop() {
    
  // if client connected
  client = server.available();
  
  // catch HTTP POST Request
  getPostRequest();

}

// ************************************************
// Functions definitions
// ************************************************

// ********************************************************
// ** setupCommunications
// ** This function is called in order to initialize
// ** the communication with the ethernet port.
// ********************************************************
void setupCommunications() {

  //
  // Attempt to establish ethernet connection.
  //
  Serial.println("********************************************");
  Serial.println("** Establishing network connection...     **");
  Ethernet.begin(mac, ip);
  
  // Pause to ensure successful connection.
  delay(WAIT);
  
  // start the server
  server.begin();
  
  //
  // Display the established IP address for debugging
  //
  Serial.println("** Connected.                             **");
  Serial.print("** Arduino IP address: ");
  Serial.print(Ethernet.localIP());
  Serial.print("      **");
  Serial.println();
  Serial.println("********************************************");
  
}


// ********************************************************
// ** getPostRequest
// ** This function catches the HTTP POST Request
// ** coming from the client.
// ********************************************************
void getPostRequest() {
  
  // if a client is connected....
  if (client) {
    Serial.println("** Client connected.                      **");
    boolean currentLineIsBlank = true;
    bufferSize = 0;
    
    while (client.connected()) {
      if(client.available()){
        char c = client.read();
        // if you received a newline character
        // and the line is blank, the HTTP POST Request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // Here is where the POST data is.  
          while(client.available()) {  
            char post = client.read();   
            if(bufferSize < bufferMax)    // if the character is NOT a 'RETURN'
                                          // and the number of characters received
                                          // is less than bufferMax, keep reading
            buffer[bufferSize++] = post;  // save the new character in buffer and increment bufferSize 
            }
           
          // Prints the received request to serial monitor
          Serial.println("** Received POST request:                 **");
          Serial.println(buffer);  // buffer contains the received HTTP POST Request
        
          // Parse HTTP POST Request                  
          ParseReceivedRequest();
          
          // Execute commands
          PerformRequestedCommands();
        
          // Send response to client
          sendResponse();
          
         } else if (c == '\n') {
            // you're starting a new line
            currentLineIsBlank = true;
           } else if (c != '\r') {
               // you've gotten a character on the current line
               currentLineIsBlank = false;
             }
          }
      }
  Serial.println("** Port closed. Waiting for next request. **");
  Serial.println("********************************************");
  Serial.println();
  
  }

}

// ********************************************************
// ** sendResponse
// ** This function sends response to the client.
// ********************************************************
void sendResponse() {

  Serial.println("********************************************");
          Serial.println("** Sending response                       **");
          Serial.println("********************************************");
          // send a standard http response header that causes a redirect to the Apache server
            client.println(F("HTTP/1.1 200 OK"));
            client.println(F("Content-Type: text/html"));
            client.println(F("Connection: close"));
            client.stop();
            delay(WAIT);
}

// ************************************************
// ** ParseReceivedRequest
// ************************************************
void ParseReceivedRequest() {...}


// ************************************************
// ** PerformRequestedCommands
// ************************************************
void PerformRequestedCommands() {...}

Which Arduino are you using? All those string literals take up space in SRAM, and you seem to think you have unlimited amounts of it. You don't. You have 2048 bytes.

Now, the problem is that, on the test system, my arduino web server hangs for a while after it receives the HTTP POST request from the apache web server

Is the post request from Apache or actually from cURL?

@PaulS I am using an Arduino Nano Rev.3 as a web server on the test system but I used an Arduino UNO Rev3 on the 'original' system: I know they are 100% compatible and the code I used is exactly the same.

Which string literals are you referring to, by the way?

@zoomcat the POST request is from cURL: it's a server to server request. I checked cURL with a test html form and some php code that I wrote and I verified that it actually sends the message. =( If I wait for enough time between one request and the other, I have no problems at all, but if I post a request immediately after another, it just does not receive it (at least that's what seems to me)....

When the server code stalls, what is the last message on the serial monitor?

@SurferTim "Port closed. Waiting for next request."

I’ll go with PaulS. I think you may be out of SRAM. Shorten all those Serial.print() and println() strings to a minimum. Delete all the strings that are just asterisks. Use the F() function to save even more SRAM.

// delete these
  Serial.println("********************************************");

// change this
  Serial.println("** Connected.                             **");
// to this
  Serial.println(F("Connected"));

@SurferTim I tried exactly what you suggested, but it did not work.... =(

Could this be a hardware problem?

I tried the web server example and it workf fine....

What else can I try?

I don't know which web server example you tried, but if it works, then it is not a hardware problem. It is an issue with your code.

POST transactions are often used when large amounts of data need to be transferred. How much data is being returned to the client, and are you capturing the data into memory?

@zoomcat the POST request that I am sending to the (arduino) web server (through cURL) is just as stupid as "A=1&B=2": nothing special at all! The web server then returns the same string not to the "client", but to an Apache web server, through a GET.

I was thinking.... could it be the "char buffer[]" variable that does not empty after the first POST? Being full already, it cannot receive the next POST request coming in: does it make any sense?

What I really, really do not understand is why is this code working on the other arduino?

This kind of things make me crazy....

Just for the record, I tried the following

memset(buffer, 0, sizeof(buffer));

to empty the buffer[] variable before receiving the new POST request, but nothing changed: same problem....

How would you receive a POST message? What code would you use? Maybe my solution is not good for this kind of problem.

What does your code look like now? Have you gotten all those strings out of SRAM?

Here is my updated code:

#include <SPI.h>
#include <Ethernet.h>
#include <string.h>


 byte mac[] = { 0xDE, 0xAD, 0xC0, 0xA8, 0x01, 0x34 };  // TEST MAC Address: 0xDE, 0xAD + HEX(192.168.1.52)
 IPAddress ip(192,168,1,52); 
 EthernetServer server(80);
 EthernetClient client;

// Delay time
int WAIT = 300;

#define bufferMax 128
int bufferSize;
char buffer[bufferMax];

// *********************************************************************************

// *********************************************************************************
// SETUP
// Initilizing Arduino
// *********************************************************************************
void setup() {
  //Start serial port for debugging
  Serial.begin(9600);
  
  // Set pin D8,D7,D6 as OUTPUT
  pinMode(8, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(6, OUTPUT);
  
  
  // Start network connection
  setupCommunications();
      
}



//********************************************************
//** loop
//** This is the main function 
//********************************************************
void loop() {
    
  // if client connected
  client = server.available();
  
  // catch HTTP POST Request
  getPostRequest();

}



// ************************************************
// Functions definitions
// ************************************************

// ********************************************************
// ** setupCommunications
// ** This function is called in order to initialize
// ** the communication with the ethernet port.
// ********************************************************
void setupCommunications() {

  Ethernet.begin(mac, ip);
  
  // Pause to ensure successful connection.
  delay(WAIT);
  
  // start the server
  server.begin();
  
  Serial.print(F(" Arduino IP address: "));
  Serial.print(Ethernet.localIP());
  Serial.println();
  
}


// ********************************************************
// ** getPostRequest
// ** This function catches the HTTP POST Request
// ** coming from the client.
// ********************************************************
void getPostRequest() {
  
  // if a client is connected....
  if (client) {
    boolean currentLineIsBlank = true;
    bufferSize = 0;
    
    while (client.connected()) {
      if(client.available()){
        char c = client.read();
        if (c == '\n' && currentLineIsBlank) {
          
          while(client.available()) {  
            char post = client.read();   
            if(bufferSize < bufferMax){    

              buffer[bufferSize++] = post;   
            }
          }
           
          Serial.println(F(" Received POST request:"));
          Serial.println(buffer); 
         
          // Send response to client
          sendResponse();
          
         } else if (c == '\n') {
            // you're starting a new line
            currentLineIsBlank = true;
           } else if (c != '\r') {
               // you've gotten a character on the current line
               currentLineIsBlank = false;
             }
          }
      }

  Serial.println(F("Port closed. Waiting for next request."));
 
  Serial.println();
 
  }

}



// ********************************************************
// ** sendResponse
// ** This function sends response to the client.
// ********************************************************
void sendResponse() {
            client.println(F("HTTP/1.1 200 OK"));
            client.println(F("Content-Type: text/html"));
            client.println(F("Connection: close"));

          client.stop();
          delay(WAIT);
}

Even now the problem is still there…
Also, the pin13 led is always on even if I did not set it: why is that?

I am lost.

Are you getting the POST data? It may come in additional packets after the initial request.

Technically, you must parse the POST request for the "Content-Length" variable, and read that many characters after the blank line.

Also, the pin13 led is always on even if I did not set it: why is that?

How does the Arduino communicate with the Ethernet shield? It uses SPI. Which pins does that involve? On the 328-based Arduinos, they are pins 11, 12, and 13. Which pin are you trying to use for your LED? Oops.

What does your serial output look like? Post it, or send me your Arduino so I can run your code.

@SurferTim I do get the 'first' POST data, then the arduino hangs on something for some 50 seconds and then it gets another POST request. When it hangs, I can still ping into it.....

I do parse the data I get from POST: if the arduino gets the POST request it parse it, but if it doesn't get the request it just sits there doing I don't know what.

First of all, I would like to say that the ethernet module that I am using is the ‘Itead Studio W5100 ethernet module’…can’t remember if I mentioned.
By the way, I did a new test.
With the ethernet module connected I tried to ping into it with:

ping - t 192.168.1.52         // this is the IP address of my ethernet module

the module responded correctly.
The weird thing is that it kept responding even when I pushed the reset button on my arduino!
Even if the ethernet module leds turned off for a second (and then back on) and the serial monitor showed:
‘Arduino IP address: 192.168.1.52’ (code: Ethernet.begin(mac, ip):wink: every time I pushed the reset button, the ping result in the ‘cmd window’ kept coming in correctly…
What does this mean?
How is it possibile to keep receiving ping results when the ethernet module is being reset?

Guys, please…do me a favor: try running my code and see if you get positive results.

First of all, you need to be running a web server on a pc (mine is running Apache with php and mysql).
On that server, you have to have two pages: form.php and processor.php.
The form.php is just a basic form used to submit commands to the processor pages.
This is the code to the form.php page (actually html page!):

<table border="0" align="center" id="table"> 
    <tr>
        <td>
            <form action="processor.php" method="post"> 
                <input type="hidden" name="stnz" value="1" />
                <input type="hidden" name="opz" value="1" />
                <input type="hidden" name="act" value="1" />
                <input type="submit" value="Accendi" id="button1" />
            </form>
        </td>
        <td>
            <form action="processor.php" method="post"> 
                <input type="hidden" name="stnz" value="1" />
                <input type="hidden" name="opz" value="1" />
                <input type="hidden" name="act" value="0" />
                <input type="submit" value="Spegni" id="button2" />
            </form>
        </td>
    </tr>
</table>

In the same directory you have to have the processor.php page:

<?php
	// Reading POST request
	if(isset($_POST['stnz']) && (isset($_POST['opz'])) && (isset($_POST['act']))) {
		$stnz = $_POST['stnz'];
		$opz = $_POST['opz'];
		$act = $_POST['act'];
	
	
	// Setting 'url' and 'file' for the chosen room	
	switch($stnz) {
		case 1:
			$url = 'http://192.168.1.52';	// arduino web server IP Address
			break;
		case 2:
			$url = 'http://192.168.1.53';	
			break;
		case 3:
			$url = 'http://192.168.1.55';	
			break;
		}	

	echo $stnz . "
";
	echo $opz . "
";
	echo $act . "
";
	echo $url . "
";
	
	curl_sender($url, $stnz, $opz, $act);

	}
?>

<?php 
function curl_sender($url, $id_stanza, $id_opzione, $action) {
			//create array of data to be posted
			$post_data['id_stanza'] = $id_stanza;
			$post_data['id_opzione'] = $id_opzione;
			$post_data['action'] = $action;
			
			//traverse array and prepare data for posting (key1=value1)
			foreach ( $post_data as $key => $value) {
			$post_items[] = $key . '=' . $value;
			}
			
			//create the final string to be posted using implode()
			$post_string = implode ('&', $post_items);
			
			//create cURL connection
			$curl_connection = curl_init($url);
			
			//set options
			curl_setopt($curl_connection, CURLOPT_CONNECTTIMEOUT, 30);
			//curl_setopt($curl_connection, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)");
			curl_setopt($curl_connection, CURLOPT_USERAGENT, "Arduino/1.0");
			curl_setopt($curl_connection, CURLOPT_RETURNTRANSFER, false);
			//curl_setopt($curl_connection, CURLOPT_SSL_VERIFYPEER, false);
			//curl_setopt($curl_connection, CURLOPT_FOLLOWLOCATION, 1);
			
			//set data to be posted
			curl_setopt($curl_connection, CURLOPT_POSTFIELDS, $post_string);
			
			//perform our request
			$result = curl_exec($curl_connection);
			
			//show information regarding the request
			//print_r(curl_getinfo($curl_connection));
			//echo curl_errno($curl_connection) . '-' . curl_error($curl_connection);
			
			//close the connection
			curl_close($curl_connection);
			}

?>

I set my arduino web server to be at 192.168.1.52.
The processor.php page receives commands from the form.php page and sends the to the arduino via cURL.

The Arduino (I am using a Nano Rev.3 with an Itead Studio W5100 ethernet module) must be configured as a web server and this is the code that I am using on it:

#include <SPI.h>
#include <Ethernet.h>
#include <string.h>



 byte mac[] = { 0xDE, 0xAD, 0xC0, 0xA8, 0x01, 0x34 };  // TEST MAC Address: 0xDE, 0xAD + HEX(192.168.1.52)

 IPAddress ip(192,168,1,52);  
 EthernetServer server(80);
 EthernetClient client;

// Delay time
int WAIT = 300;

// Buffer to store HTTP POST Request
#define bufferMax 128
int bufferSize;
char buffer[bufferMax];

// *********************************************************************************

// *********************************************************************************
// SETUP
// Initilizing Arduino
// *********************************************************************************
void setup() {
  //Start serial port for debugging
  Serial.begin(9600);
 
  // Start network connection
  setupCommunications();
      
}



//********************************************************
//** loop
//** This is the main function 
//********************************************************
void loop() {
    
  // if client connected
  client = server.available();
  
  // catch HTTP POST Request
  getPostRequest();

}



// ************************************************
// Functions definitions
// ************************************************

// ********************************************************
// ** setupCommunications
// ** This function is called in order to initialize
// ** the communication with the ethernet port.
// ********************************************************
void setupCommunications() {

  //
  // Attempt to establish ethernet connection.
  //

  Ethernet.begin(mac, ip);
  
  // Pause to ensure successful connection.
  delay(WAIT);
  
  // start the server
  server.begin();
  
  
  Serial.print(F(" Arduino IP address: "));
  Serial.print(Ethernet.localIP());

  Serial.println();

}


// ********************************************************
// ** getPostRequest
// ** This function catches the HTTP POST Request
// ** coming from the client.
// ********************************************************
void getPostRequest() {
  
  // if a client is connected....
  if (client) {
    boolean currentLineIsBlank = true;
    bufferSize = 0;
    
    while (client.connected()) {
      if(client.available()){
        char c = client.read();
        // if you received a newline character
        // and the line is blank, the HTTP POST Request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // Here is where the POST data is.  
          while(client.available()) {  
            char post = client.read();   
            if(bufferSize < bufferMax){    // if the character is NOT a 'RETURN'
                                          // and the number of characters received
                                          // is less than bufferMax, keep reading
              buffer[bufferSize++] = post;  // save the new character in buffer and increment bufferSize 
            }
          }
           
          // Prints the received request to serial monitor
          Serial.println(F(" Received POST request:"));
          Serial.println(buffer);  // buffer contains the received HTTP POST Request
        
          // Send response to client
          sendResponse();
          
         } else if (c == '\n') {
            // you're starting a new line
            currentLineIsBlank = true;
           } else if (c != '\r') {
               // you've gotten a character on the current line
               currentLineIsBlank = false;
             }
          }
      }

  Serial.println(F("Port closed. Waiting for next request."));
  
  Serial.println();

  }

}


// ********************************************************
// ** sendResponse
// ** This function sends response to the client.
// ********************************************************
void sendResponse() {

          // send a standard http response header that causes a redirect to the Apache server
            client.println(F("HTTP/1.1 200 OK"));
            client.println(F("Content-Type: text/html"));
            client.println(F("Connection: close"));

          client.stop();
          delay(WAIT);
}

Basically, when the arduino receives a POST request (via cURL) from the processor.php page, it shows it on the serial monitor.
REMEBER: my problem is I receive the first POST data correctly, then the arduino web server hangs for a while and then it ‘comes back to life’ and it is able to receive a new POST request. When it hangs, I can still ping into it.

Please, let me know if you have success running this code.
Thanks a lot.