HttpClient::responseStatusCode() returns -3

I'm using ESP32 with ENC28J60 ethernet connector.
I'm trying to retrieve HTTP get from server, but after a few response, http.responseStatusCode() always returns -3, TIMEOUT.

Please let me know how to fix it. Any answer would be greatly appreciated.

#include <WiFi.h>
#include <HttpClient.h>
#include <EthernetENC.h>

String sChipID;
char cChipID[40];
byte mac[6];
bool isConnected = false;

// Number of milliseconds to wait without receiving any data before we give up
const int kNetworkTimeout = 30*1000;
// Number of milliseconds to wait if no data is available before trying again
const int kNetworkDelay = 100;

void setup() {
  // put your setup code here, to run once:
  uint8_t chipid[6] = "";
  int ethernetresult;
  Serial.begin(9600);
  WiFi.macAddress(chipid);
  sprintf(cChipID, "%02X%02X%02X%02X%02X%02X", chipid[5], chipid[4], chipid[3], chipid[2], chipid[1], chipid[0]);
  memcpy(mac, chipid, 6);

  Serial.println("Trying DHCP...");
  ethernetresult = Ethernet.begin(mac);// Use DHCP
  if( ethernetresult != 0 )
  {
    Serial.print("Local IP : ");
    Serial.println(Ethernet.localIP());
    Serial.print("Subnet Mask : ");
    Serial.println(Ethernet.subnetMask());
    Serial.print("Gateway IP : ");
    Serial.println(Ethernet.gatewayIP());
    Serial.print("DNS Server : ");
    Serial.println(Ethernet.dnsServerIP());
    isConnected = true;
  }
  else
  {
    Serial.println("DHCP not available.");
  }

}

void loop() {
  // put your main code here, to run repeatedly:
  EthernetClient eclient;
  HttpClient http(eclient);
  String response = "";
  String httpServer = "192.168.10.250";
  String httpURI = "/webjob/";
  String http_request = "broker_wakeup.jsp?sn=Q123A-DA305-0008";
  uint16_t httpPort = 8080;

  int err;
  int curmillis;
  bool ret = false;

  err = http.get(httpServer.c_str(), httpPort, (httpURI + http_request).c_str());

  if( err == 0 )
  {
    Serial.println("startedRequest ok");

    err = http.responseStatusCode();

    if (err >= 0)
    {
      Serial.print("Got status code: ");
      Serial.println(err);

      // Usually you'd check that the response code is 200 or a
      // similar "success" code (200-299) before carrying on,
      // but we'll print out whatever response we get

      err = http.skipResponseHeaders();
          
      if (err >= 0)
      {
        int bodyLen = http.contentLength();
        Serial.print("Response length: ");
        Serial.println(bodyLen);
      
        // Now we've got to the body, so we can print it out
        unsigned long timeoutStart = millis();
        char c;
        
        // Whilst we haven't timed out & haven't reached the end of the body
        while ( (http.connected() || http.available()) &&
               ((millis() - timeoutStart) < kNetworkTimeout) &&
               (bodyLen > 0) )
        {
          if (http.available())
          {
            c = http.read();
            response += c;
           
            bodyLen--;
            // We read something, reset the timeout counter
            timeoutStart = millis();
          }
          else
          {
            // We haven't got any data, so let's pause to allow some to
            // arrive
            delay(kNetworkDelay);
          }
        }

        if( bodyLen == 0 )
        {
          ret = true;
        }
      }
      else
      {
        Serial.print("Failed to skip response headers: ");
        Serial.println(err);
      }
    }
    else
    {    
      Serial.print("Getting response failed: ");
      Serial.println(err);
    }
  }
  else
  {
    Serial.print("Connect failed: ");
    Serial.println(err);
  }
  
  http.stop();

  if( err <= 0 )
  {
    
  }

  if( ret )
  {
    Serial.println(response);
  }

  delay(1000);
}

Output:

Trying DHCP...
16:44:13.495 -> Local IP : 192.168.10.64
16:44:13.541 -> Subnet Mask : 255.255.255.0
16:44:13.541 -> Gateway IP : 192.168.10.1
16:44:13.587 -> DNS Server : 203.248.252.2
16:44:14.011 -> startedRequest ok
16:44:17.029 -> Got status code: 200
16:44:17.075 -> Response length: 44
16:44:17.075 -> 
16:44:17.075 -> 
16:44:17.075 -> INTERVAL=1
16:44:17.075 -> TIME=2022-12-12 16:44:14
16:44:17.121 -> 
16:44:17.121 -> 
16:44:18.255 -> startedRequest ok
16:44:21.234 -> Got status code: 200
16:44:21.281 -> Response length: 44
16:44:21.281 -> 
16:44:21.281 -> 
16:44:21.281 -> INTERVAL=1
16:44:21.328 -> TIME=2022-12-12 16:44:18
16:44:21.328 -> 
16:44:21.328 -> 
16:44:22.460 -> startedRequest ok
16:44:25.461 -> Got status code: 200
16:44:25.461 -> Response length: 44
16:44:25.507 -> 
16:44:25.507 -> 
16:44:25.507 -> INTERVAL=1
16:44:25.507 -> TIME=2022-12-12 16:44:22
16:44:25.554 -> 
16:44:25.554 -> 
16:44:26.683 -> startedRequest ok
16:44:29.655 -> Got status code: 200
16:44:29.701 -> Response length: 44
16:44:29.701 -> 
16:44:29.701 -> 
16:44:29.701 -> INTERVAL=1
16:44:29.701 -> TIME=2022-12-12 16:44:26
16:44:29.748 -> 
16:44:29.748 -> 
16:44:30.868 -> startedRequest ok
16:45:00.886 -> Getting response failed: -3
16:45:02.066 -> startedRequest ok
16:45:32.077 -> Getting response failed: -3
16:45:33.250 -> startedRequest ok

ESP32 has a fully equipped WiFi stack in a board, why do not use it and has troubles with not quite stable ENC28J60 module, ?

Using ethernet is a customer requirement. :slight_smile:

Could the problem be on the server? If it runs out of some resource it might stop responding, causing a timeout.

I've tried the same address with WIFI in same ESP32. There was no problem.

I once read that the ENC28J60 module has a problem - it does not clear itself the sockets after the connection is closed. And there are only 8 sockets, if I am not mistaken... so the sockets end very quickly. Your case is like this

Wow! That's a great hint.

Your advise was essential!
I've coded a subclass of HttpClient, which sends "Keep-Alive" instead of "close" for connection header and now it works well.
Thank you very much.

// Class to simplify HTTP fetching on Arduino
// (c) Copyright MCQN Ltd. 2010-2012
// Released under Apache License, version 2.0

#ifndef HttpClientKA_h
#define HttpClientKA_h

#include <HttpClient.h>

#define HTTP_HEADER_KAOPTION     "Keep-Alive"

class HttpClientKA : public HttpClient
{
public:
    HttpClientKA(Client& aClient): HttpClient(aClient) {}
    
    /** Connect to the server and start to send a GET request with keep alive
      @param aServerName  Name of the server being connected to.  If NULL, the
                          "Host" header line won't be sent
      @param aServerPort  Port to connect to on the server
      @param aURLPath     Url to request
      @param aUserAgent   User-Agent string to send.  If NULL the default
                          user-agent kUserAgent will be sent
      @return 0 if successful, else error
    */
    int getKA(const char* aServerName, uint16_t aServerPort, const char* aURLPath, 
              const char* aUserAgent = NULL)
      { return startRequestKA(aServerName, aServerPort, aURLPath, HTTP_METHOD_GET, aUserAgent); }


protected:
  int startRequestKA(const char* aServerName, uint16_t aServerPort, const char* aURLPath, const char* aHttpMethod, const char* aUserAgent);
  int sendInitialHeadersKA(const char* aServerName, IPAddress aServerIP, uint16_t aPort, const char* aURLPath, const char* aHttpMethod, const char* aUserAgent);

};

#endif

#include "HttpClientKA.h"

int HttpClientKA::startRequestKA(const char* aServerName, uint16_t aServerPort, const char* aURLPath, const char* aHttpMethod, const char* aUserAgent)
{
    tHttpState initialState = iState;
    if ((eIdle != iState) && (eRequestStarted != iState))
    {
        return HTTP_ERROR_API;
    }

    if( !iClient->connected() )
    {
#ifdef PROXY_ENABLED
      if (iProxyPort)
      {
          if (!iClient->connect(iProxyAddress, iProxyPort) > 0)
          {
#ifdef LOGGING
              Serial.println("Proxy connection failed");
#endif
              return HTTP_ERROR_CONNECTION_FAILED;
          }
      }
      else
#endif
      {
          if (!iClient->connect(aServerName, aServerPort) > 0)
          {
#ifdef LOGGING
            Serial.println("Connection failed");
#endif
            return HTTP_ERROR_CONNECTION_FAILED;
        }
      }
    }

    // Now we're connected, send the first part of the request
    int ret = sendInitialHeadersKA(aServerName, IPAddress(0,0,0,0), aServerPort, aURLPath, aHttpMethod, aUserAgent);
    if ((initialState == eIdle) && (HTTP_SUCCESS == ret))
    {
        // This was a simple version of the API, so terminate the headers now
        finishHeaders();
    }
    // else we'll call it in endRequest or in the first call to print, etc.

    return ret;
}

int HttpClientKA::sendInitialHeadersKA(const char* aServerName, IPAddress aServerIP, uint16_t aPort, const char* aURLPath, const char* aHttpMethod, const char* aUserAgent)
{
#ifdef LOGGING
    Serial.println("Connected");
#endif
    // Send the HTTP command, i.e. "GET /somepath/ HTTP/1.0"
    iClient->print(aHttpMethod);
    iClient->print(" ");
#ifdef PROXY_ENABLED
    if (iProxyPort)
    {
      // We're going through a proxy, send a full URL
      iClient->print("http://");
      if (aServerName)
      {
        // We've got a server name, so use it
        iClient->print(aServerName);
      }
      else
      {
        // We'll have to use the IP address
        iClient->print(aServerIP);
      }
      if (aPort != kHttpPort)
      {
        iClient->print(":");
        iClient->print(aPort);
      }
    }
#endif
    iClient->print(aURLPath);
    iClient->println(" HTTP/1.1");
    // The host header, if required
    if (aServerName)
    {
        iClient->print("Host: ");
        iClient->print(aServerName);
        if (aPort != kHttpPort)
        {
          iClient->print(":");
          iClient->print(aPort);
        }
        iClient->println();
    }
    // And user-agent string
    if (aUserAgent)
    {
        sendHeader(HTTP_HEADER_USER_AGENT, aUserAgent);
    }
    else
    {
        sendHeader(HTTP_HEADER_USER_AGENT, kUserAgent);
    }
    // We don't support persistent connections, so tell the server to
    // close this connection after we're done
    sendHeader(HTTP_HEADER_CONNECTION, "Keep-Alive");
    sendHeader(HTTP_HEADER_KAOPTION, "timeout=30, max=0");

    isConnected = true;

    // Everything has gone well
    iState = eRequestStarted;
    return HTTP_SUCCESS;
}

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