8000 Added close_abort() function to WiFiClient by pfabri · Pull Request #2767 · esp8266/Arduino · GitHub
[go: up one dir, main page]

Skip to content

Added close_abort() function to WiFiClient #2767

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
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Added close_abort() function to WiFiClient
This branch adds a close_abort() method to the WiFiClient class.

How it works, what it does:
Calling `close_abort()` will close and abort the client connection it
is invoked on and, as a result, free its resources (i.e. memory).

**WARNING:** aborting connections without a good reason violates the
TCP protocol, because a closed connection would normally need to
spend some time in `TIME_WAIT` state before its resources are freed.

Usage example:
    WiFiClient client;		// set up a client

    { /* do things with your client */ }

    client.stop_abort()		// when you're done,abort the
				// connection if you must

Why it's useful:
1. Give programmers a way to shut down connections immediately if
   need be. The underlying `tcp.c` file has an abort function, but
   this has not been directly accessible via the `WiFiClient`
   class until now.

2. There are a number of reported issues for the repository
   addressing the heap corruption that can result from trying to
   retain too many connections in `TIME_WAIT` state (most notably:
   #230, #1070, #1923). Although the warning above holds, there may be
   circumstances where this isn't very important. For example an ESP8266
   running in AP mode hosting a page, which requests a new
   connection every second via an AJAX script to  monitor
   a sensor/button/etc. continusously.

Currently existing alternative approach:
When building a project, defining the
`-D MEMP_NUM_TCP_PCB_TIME_WAIT=5`compiler directive will limit the
maximum number of clients allowed to stay in TIME_WAIT state. `5` is
the default, lower it as necessary. See reference
[here](https://github.com/esp8266/Arduino/blob/master/tools/sdk/lwip/include/lwipopts.h#L263)

Thanks:
Thank you to @me-no-dev, @everslick and @Palatis for bringing the `
MEMP_NUM_TCP_PCB_TIME_WAIT` option to my attention.
  • Loading branch information
pfabri committed Dec 15, 2016
commit 9fac2903ebad14752bfaa2324f01e526240bc2f3
9 changes: 9 additions & 0 deletions libraries/ESP8266WiFi/src/WiFiClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,15 @@ void WiFiClient::stop()
_client = 0;
}

void WiFiClient::stop_abort() //Compare this to ::stop
{
if (!_client)
return;

_client->unref_abort();
_client = 0;
}

uint8_t WiFiClient::connected()
{
if (!_client)
Expand Down
1 change: 1 addition & 0 deletions libraries/ESP8266WiFi/src/WiFiClient.h
8000
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class WiFiClient : public Client, public SList<WiFiClient> {
}
virtual void flush();
virtual void stop();
virtual void stop_abort();
virtual uint8_t connected();
virtual operator bool();

Expand Down
36 changes: 36 additions & 0 deletions libraries/ESP8266WiFi/src/include/ClientContext.h
8D8C
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,27 @@ class ClientContext
}
return err;
}

err_t close_abort()
{
/* ERR_ABRT must be sent back on abortion as specified in the comments
* of tools/sdk/lwip/src/core/tcp.c at the footnote of tcp_abort() */
err_t err = ERR_ABRT;
if(_pcb) {
DEBUGV(":close\r\n");
tcp_arg(_pcb, NULL);
tcp_sent(_pcb, NULL);
tcp_recv(_pcb, NULL);
tcp_err(_pcb, NULL);
tcp_close(_pcb);
/* Without delay some clients fail to receive the response and
* report a 'cannot connect' error message */
delay(10);
tcp_abort(_pcb);
_pcb = 0;
}
return err;
}

~ClientContext()
{
Expand Down Expand Up @@ -123,6 +144,21 @@ class ClientContext
}
}
}

void unref_abort()
{
if(this != 0) {
DEBUGV(":ur_abrt %d\r\n", _refcnt);
if(--_refcnt == 0) {
flush();
close_abort();
if(_discard_cb)
_discard_cb(_discard_cb_arg, this);
DEBUGV(":del\r\n");
delete this;
}
}
}

void setNoDelay(bool nodelay)
{
Expand Down
0