Skip to content

Remote TCP disconnect not detected #377

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
bbx10 opened this issue May 15, 2017 · 5 comments
Closed

Remote TCP disconnect not detected #377

bbx10 opened this issue May 15, 2017 · 5 comments

Comments

@bbx10
Copy link
Contributor

bbx10 commented May 15, 2017

The test program works on ESP8266 but fails on ESP32. The code below listens on TCP port 9 and discards all incoming data. On a Linux box, use netcat (nc 9) to connect to the ESP. Pressing ^C stops netcat and terminates the TCP socket. On ESP32, the sketch never detects the remote TCP disconnect. On ESP8266, remote TCP disconnects are detected correctly.

BTW, the ESP32 TCP Rx performance is much slower than the ESP8266 but perhaps the Rx window size needs tweaking or something. I will open another issue if this is a real problem.

/*
 * Simple network performance tests. Works on ESP8266 but TBD for ESP32.
 *
 * == Listens on port 9 and discards all incoming data. Performance
 * in bits/sec reported.
 *
 */

#ifdef ESP8266
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
ESP8266WiFiMulti wifiMulti;
#else
#include <WiFi.h>
#include <WiFiMulti.h>
WiFiMulti wifiMulti;
#endif

#define DISCARD_PORT  (9)
WiFiServer tcpDiscardServer(DISCARD_PORT);
WiFiClient tcpDiscardClient; // Service at most 1 client

typedef struct scoreboard_t {
  uint64_t byteCount;
  uint32_t startMillis;
} scoreboard_t;

scoreboard_t DiscardScore;

#ifndef min
#define min(x,y) (((x) < (y)) ? (x) : (y))
#endif
#ifndef max
#define max(x,y) (((x) > (y)) ? (x) : (y))
#endif

char discard[4*1460];

void setup() {
  Serial.begin(115200);
  delay(10);
  Serial.println();

  wifiMulti.addAP("ssid_from_AP_1", "your_password_for_AP_1");
  //wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2");
  //wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3");

  Serial.println("Connecting Wifi ");
  for (int loops = 10; loops > 0; loops--) {
    if (wifiMulti.run() == WL_CONNECTED) {
      Serial.println("");
      Serial.print("WiFi connected ");
      Serial.print("IP address: ");
      Serial.println(WiFi.localIP());
      break;
    }
    else {
      Serial.println(loops);
      delay(1000);
    }
  }
  if (wifiMulti.run() != WL_CONNECTED) {
    Serial.println("WiFi connect failed");
    delay(1000);
    ESP.restart();
  }

  tcpDiscardServer.begin();
#ifdef ESP8266
  tcpDiscardServer.setNoDelay(true);
#endif
  Serial.print("DISCARD daemon listening on port "); Serial.println(DISCARD_PORT);
}

void loop() {
  if (wifiMulti.run() == WL_CONNECTED) {
    WiFiClient newClient = tcpDiscardServer.available();
    if (newClient) {
      newClient.setNoDelay(true);
      if (!tcpDiscardClient || !tcpDiscardClient.connected()) {
        if (tcpDiscardClient) tcpDiscardClient.stop();
        tcpDiscardClient = newClient;
        Serial.print("New client: "); Serial.println(tcpDiscardClient.remoteIP());
        DiscardScore.byteCount = 0;
        DiscardScore.startMillis = millis();
      }
      else {
        // client connected so refuse new client
        newClient.stop();
      }
    }
    //check client for data
    if (tcpDiscardClient) {
      if (tcpDiscardClient.connected()) {
        int bytesAvail, bytesIn, bytesRead;
        while ((bytesAvail = tcpDiscardClient.available()) > 0) {
          bytesIn = min(sizeof(discard), bytesAvail);
          if (bytesIn < bytesAvail) Serial.println("Embiggen discard[]?");
          bytesRead = tcpDiscardClient.readBytes(discard, bytesIn);
          if (bytesRead != bytesIn) Serial.println("readBytes() not cromulent");
          DiscardScore.byteCount += bytesRead;
        }
      }
      else {
        uint32_t deltaMillis = millis() - DiscardScore.startMillis;
        Serial.println("Discard client disconnect");
        Serial.printf("Bytes %u, %u ms, %u bits/s\n",
            (uint32_t)DiscardScore.byteCount, deltaMillis,
            (uint32_t)((DiscardScore.byteCount * 8000ULL) / deltaMillis));
        tcpDiscardClient.stop();
      }
    }
  }
  else {
    Serial.println("WiFi not connected!");
    if (tcpDiscardClient) tcpDiscardClient.stop();
    delay(1000);
  }
}
@bbx10
Copy link
Contributor Author

bbx10 commented May 16, 2017

This patch works on ESP32 so the above program detects remote TCP disconnects. The errno value is ENOTCONN versus ECONNRESET which, I think, is used on BSD sockets API.

I can submit a PR if it looks OK.

diff --git a/libraries/WiFi/src/WiFiClient.cpp b/libraries/WiFi/src/WiFiClient.cpp
index 1090695..b1b6e72 100644
--- a/libraries/WiFi/src/WiFiClient.cpp
+++ b/libraries/WiFi/src/WiFiClient.cpp
@@ -279,8 +279,28 @@ void WiFiClient::flush() {
 
 uint8_t WiFiClient::connected()
 {
-    uint8_t dummy = 0;
-    read(&dummy, 0);
+    if (_connected) {
+        uint8_t dummy;
+        int res = recv(fd(), &dummy, 0, MSG_DONTWAIT);
+        if (res <= 0) {
+            switch (errno) {
+                case ENOTCONN:
+                case EPIPE:
+                case ECONNRESET:
+                case ECONNREFUSED:
+                case ECONNABORTED:
+                    _connected = false;
+                    break;
+                default:
+                    _connected = true;
+                    break;
+            }
+        }
+        else {
+            // Should never happen since requested 0 bytes
+            _connected = true;
+        }
+    }
     return _connected;
 }

@me-no-dev
Copy link
Member

Yeah... I even raised an issue a while back for this. I guess they fixed it at some point. How about you PR this and the other change that you proposed?

@MayurUsdad
Copy link

Hi @bbx10 ,
Sorry i did not understand your solution. i am facing the same Issue,
i am using client.readStringUntil('\r'); which is blocking Loop, so i used client.setTimeout(500); before that but still its blocking it.
Below is my Full Code:

WiFiClient client = server.available();
client.setTimeout(500);

if(client.available()){

// Read the first line of the request
String req = client.readStringUntil('\r');
client.flush();

// Match the request
if (req.indexOf("/gpio/0") != -1)
digitalWrite(Relay1, 0);

}

@stickbreaker
Copy link
Contributor

@bbx10 setTimeout() is in SECONDS.

Chuck

@hayderismael
Copy link

I have the same problem with all series of ESP when the client disconnect, the server freezes in the last situation. Even when the client re connected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants