Skip to content
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

Pico W, Wifi HTTP request delays. #1522

Closed
hreintke opened this issue Jun 11, 2023 · 11 comments
Closed

Pico W, Wifi HTTP request delays. #1522

hreintke opened this issue Jun 11, 2023 · 11 comments

Comments

@hreintke
Copy link
Contributor

Hi,

Running non FreeRTOS, basic webserver example I see some late responses (5 seconds delay, but not always) on HTTP requests.
This only happens when I use a webbroswer, using curl all works as expected (keep tcp connection open ?)

Would like to do some IP traffic analyses for that, using the Netdump library I made for esp8266.

I am not sure, but think there needs to be a patch/addition in lwip netif (phy_capture) for that.
Was not (yet?) be able to track that down in pico-w and/or esp8266.

Do you know where/how to add that ?
If not, was @d-a-v involved in the wifi/lwip implementation of pico-w ? I can ask him for some help too.

@earlephilhower
Copy link
Owner

@d-a-v was not involved here, sadly. I'm not sure he'd be able to help w/the PicoW side of things.

My guess would be that if you're using Chrome it's trying to send a bunch of connections in parallel, and since the processing is very much serial in nature on the Pico, things get stuck waiting. FWIW under Firefox I haven't noticed any issue like this on the AdvancedWebServer.

We are using the unpatched LWIP, straight from the Pico-SDK, but I think there are a couple things low-effort to try.

First, you can grab/dumb all received Ethernet level packets by hacking in to

extern "C" void __wrap_cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len, const uint8_t *buf) {
. You can get all Ethernet sent packets here:
uint16_t CYW43::sendFrame(const uint8_t* data, uint16_t datalen) {

It is also possible to enable very verbose LWIP debugging by editing https://github.com/earlephilhower/arduino-pico/blob/master/tools/libpico/lwipopts.h (and enabling Tools->Debug Port->Serial to get ::printf output to USB).

@earlephilhower
Copy link
Owner

Another possibility could be a bug in the webserver code, which just happens to have been noted a couple days ago in the upstream sources... esp8266/Arduino#8941

I have not looked at the code, yet, so can't really comment if it's a real issue or not, but if it is then it's one heck of a coincidence. 🍀

@hreintke
Copy link
Contributor Author

hreintke commented Jun 12, 2023

Checked into it.

You are using another webserver implementation (webserver vs esp8266webserver) so the issue cannot come from there.
But it is definitely possible the the issue is caused by the webserver/webclient code.

Did a quick try to use the esp8266webserver for the pico but got into trouble because esp8266 has a custom implementation of String and you are using the Arduino api one. Not sure if is possible to solve that with namespaces.

Edit : Found a similar construct in your webserver implementation. Will look into that.

Edit 2 : In WebserverTemplate.h change code to :

template <typename ServerType, int DefaultPort>
void WebServerTemplate<ServerType, DefaultPort>::handleClient() {
    if (_currentStatus == HC_NONE) {
        if (_currentClient) {
            delete _currentClient;
            _currentClient = nullptr;
        }

//        ClientType client = _server.available();
        _currentClient = new ClientType(_server.available());
        if (!_currentClient) {
            if (_nullDelay) {
                delay(1);
            }
            return;
        }

//        _currentClient = new ClientType(client);
        _currentStatus = HC_WAIT_READ;
        _statusChange = millis();
    }
    httpHandleClient();
}

That had no effect on the issue.

Edit 3 : I think it is related to the fact that the browser already opens a new TCP connection when the first one is finished, without immediately sending data over the connection. Just to be prepared for the next request.

@earlephilhower
Copy link
Owner

Edit 3 : I think it is related to the fact that the browser already opens a new TCP connection when the first one is finished, without immediately sending data over the connection. Just to be prepared for the next request.

That's a tough nut to crack here. The TCP connections are processed by LWIP in order of reception and we need to finish the lifecycle for the current one before starting processing on the next one. You'd need to use the AsyncWebServer to handle something like that.

(The ESP8266 WebServer evolved to fit its niche so well that it's nigh on unusable elsewhere. In addition to the String there are Stream changes as well. Bringing those in requires bringing in lots of other 8266-specific oddities, as far as I could tell when I tried it before going to the ESP32 one. It's really well tuned for low memory usage, but not really portable anymore.)

@hreintke
Copy link
Contributor Author

it before going to the ESP32 one

Tried the same on esp32, that suffers the same issue.

Running it on esp8266, it runs OK As far my testing goes.

Do you want to close this as a "known limitation" ?

@earlephilhower
Copy link
Owner

I think that's the best we can do for now. I wonder if me-no-dev's async web server can work here...

@hreintke
Copy link
Contributor Author

I have seen this https://github.com/khoih-prog/AsyncWebServer_RP2040W but did not do any tests with it.

@supersjellie
Copy link

I see my issue is linked and read your story. Maybe a longshot but sharing my experiences. When using chrome on my ESP devices chrome asks for the page and the favicon.ico. It the latter request was first (since the default webserver does requests one by one) delays of a few seconds occurred (you have to wait for a timeout on the icon). Usually the first time, than a lot of requests ok, and than chrome "rechecked" the icon. And that's why it's ok with curl or in my case openHAB calls, they don't care about the favicon.

I solved this issue by adding an empty icon in the arduino code.

(somewhere in the setup method)
server.on("/favicon.ico", handleIcon);

//send no favicon (else blocks webserver for 3-5 seconds)
void handleIcon() {
  sendResponse(404,F("NA"));
}

Maybe it helps, you can give it a try.

@hreintke
Copy link
Contributor Author

hreintke commented Jun 14, 2023

@supersjellie No, it is not the favicon.ico request. I've seen that before and this different. See also the remark below.

@earlephilhower : Was wondering why esp8266 does not suffer from issue so took a dive into the code.
It is in the 'httpHandleClient()' part where there is always a wait when no data is (yet) available.

httpServer.cpp line 282

            } else { // !_currentClient->available()
                if (millis() - _statusChange <= HTTP_MAX_DATA_WAIT) {
                    keepCurrentClient = true;
                }

esp8266webserver-impl.h line 367

      } else {
        // !_currentClient.available(): waiting for more data
        unsigned long timeSinceChange = millis() - _statusChange;
        // Use faster connection drop timeout if any other client has data
        // or the buffer of pending clients is full
        if ((_server.hasClientData() || _server.hasMaxPendingClients())
          && timeSinceChange > HTTP_MAX_DATA_AVAILABLE_WAIT)
            DBGWS("webserver: closing since there's another connection to read from\n");
        else {
          if (timeSinceChange > HTTP_MAX_DATA_WAIT)
            DBGWS("webserver: closing after read timeout\n");
          else
            keepCurrentClient = true;
        }
        callYield = true;
      }

When I found the differences, I also found the issue/PR on which it was solved. esp8266/Arduino#8216

It is not a one to one port to pico, as it depends on other changes in their code
But I can give it a try if you want.

@earlephilhower
Copy link
Owner

That would be great if you could, since you seem to also have a good test case w/your web browser setup. I'm kind of surprised the same change wasn't already done to the ESP32 webserver (where this one was taken from)...

@hreintke
Copy link
Contributor Author

From @d-a-v in the issue

edit: esp32/arduino uses lwIP's socket API while here the raw API is used. Changes will not be the same there.

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

3 participants