Skip to content

Commit 83a8076

Browse files
d-a-vdevyte
authored andcommitted
ClientContext (tcp) updates (#5089)
* +sync, get/set default nodelay, sync * default nodelay=1 * update flush() * fix return value * ClientContext: put things together * ClientContext: fix debugging messages * WiFiClient: move static members out of the class, add comments * remove circular dependency * parameter and return value for Client::flush&stop, flush timeout raised to 300ms * tcp flush: restart timer on ack receive * OTA protocol needs setNoDelay(true) * fix Ethernet with Client changes * 1 line unredable -> 5 lines readable code * doc * Update client-class.rst * Added details for getters
1 parent 88bd26b commit 83a8076

15 files changed

+287
-93
lines changed

Diff for: cores/esp8266/Client.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ class Client: public Stream {
3434
virtual int read() = 0;
3535
virtual int read(uint8_t *buf, size_t size) = 0;
3636
virtual int peek() = 0;
37-
virtual void flush() = 0;
38-
virtual void stop() = 0;
37+
virtual bool flush(unsigned int maxWaitMs = 0) = 0;
38+
virtual bool stop(unsigned int maxWaitMs = 0) = 0;
3939
virtual uint8_t connected() = 0;
4040
virtual operator bool() = 0;
4141
protected:

Diff for: doc/esp8266wifi/client-class.rst

+52-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,17 @@ Methods documented for `Client <https://www.arduino.cc/en/Reference/WiFiClientCo
1818

1919
Methods and properties described further down are specific to ESP8266. They are not covered in `Arduino WiFi library <https://www.arduino.cc/en/Reference/WiFi>`__ documentation. Before they are fully documented please refer to information below.
2020

21+
flush and stop
22+
~~~~~~~~~~~~~~
23+
24+
``flush(timeoutMs)`` and ``stop(timeoutMs)`` both have now an optional argument: ``timeout`` in millisecond, and both return a boolean.
25+
26+
Default input value 0 means that effective value is left at the discretion of the implementer.
27+
28+
``flush()`` returning ``true`` indicates that output data have effectively been sent, and ``false`` that a timeout has occurred.
29+
30+
``stop()`` returns ``false`` in case of an issue when closing the client (for instance a timed-out ``flush``). Depending on implementation, its parameter can be passed to ``flush()``.
31+
2132
setNoDelay
2233
~~~~~~~~~~
2334

@@ -35,6 +46,47 @@ This algorithm is intended to reduce TCP/IP traffic of small packets sent over t
3546
3647
client.setNoDelay(true);
3748
49+
getNoDelay
50+
~~~~~~~~~~
51+
52+
Returns whether NoDelay is enabled or not for the current connection.
53+
54+
setSync
55+
~~~~~~~
56+
57+
This is an experimental API that will set the client in synchronized mode.
58+
In this mode, every ``write()`` is flushed. It means that after a call to
59+
``write()``, data are ensured to be received where they went sent to (that is
60+
``flush`` semantic).
61+
62+
When set to ``true`` in ``WiFiClient`` implementation,
63+
64+
- It slows down transfers, and implicitely disable the Nagle algorithm.
65+
66+
- It also allows to avoid a temporary copy of data that otherwise consumes
67+
at most ``TCP_SND_BUF`` = (2 * ``MSS``) bytes per connection,
68+
69+
getSync
70+
~~~~~~~
71+
72+
Returns whether Sync is enabled or not for the current connection.
73+
74+
setDefaultNoDelay and setDefaultSync
75+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
76+
77+
These set the default value for both ``setSync`` and ``setNoDelay`` for
78+
every future instance of ``WiFiClient`` (including those coming from
79+
``WiFiServer.available()`` by default).
80+
81+
Default values are false for both ``NoDelay`` and ``Sync``.
82+
83+
This means that Nagle is enabled by default *for all new connections*.
84+
85+
getDefaultNoDelay and getDefaultSync
86+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
87+
88+
Return the values to be used as default for NoDelay and Sync for all future connections.
89+
3890
Other Function Calls
3991
~~~~~~~~~~~~~~~~~~~~
4092

@@ -54,7 +106,6 @@ Other Function Calls
54106
uint16_t remotePort ()
55107
IPAddress localIP ()
56108
uint16_t localPort ()
57-
bool getNoDelay ()
58109
59110
Documentation for the above functions is not yet prepared.
60111

Diff for: doc/esp8266wifi/server-class.rst

+4
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ This algorithm is intended to reduce TCP/IP traffic of small packets sent over t
3232
server.begin();
3333
server.setNoDelay(true);
3434
35+
By default, ``nodelay`` value will depends on global ``WiFiClient::getDefaultNoDelay()`` (currently false by default).
36+
37+
However, a call to ``wiFiServer.setNoDelay()`` will override ``NoDelay`` for all new ``WiFiClient`` provided by the calling instance (``wiFiServer``).
38+
3539
Other Function Calls
3640
~~~~~~~~~~~~~~~~~~~~
3741

Diff for: libraries/ArduinoOTA/ArduinoOTA.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,8 @@ void ArduinoOTAClass::_runUpdate() {
290290
}
291291
_state = OTA_IDLE;
292292
}
293+
// OTA sends little packets
294+
client.setNoDelay(true);
293295

294296
uint32_t written, total = 0;
295297
while (!Update.isFinished() && client.connected()) {

Diff for: libraries/ESP8266WiFi/src/WiFiClient.cpp

+62-9
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,34 @@ extern "C"
4343

4444
uint16_t WiFiClient::_localPort = 0;
4545

46+
static bool defaultNoDelay = false; // false == Nagle enabled by default
47+
static bool defaultSync = false;
48+
49+
bool getDefaultPrivateGlobalSyncValue ()
50+
{
51+
return defaultSync;
52+
}
53+
54+
void WiFiClient::setDefaultNoDelay (bool noDelay)
55+
{
56+
defaultNoDelay = noDelay;
57+
}
58+
59+
void WiFiClient::setDefaultSync (bool sync)
60+
{
61+
defaultSync = sync;
62+
}
63+
64+
bool WiFiClient::getDefaultNoDelay ()
65+
{
66+
return defaultNoDelay;
67+
}
68+
69+
bool WiFiClient::getDefaultSync ()
70+
{
71+
return defaultSync;
72+
}
73+
4674
template<>
4775
WiFiClient* SList<WiFiClient>::_s_first = 0;
4876

@@ -60,6 +88,9 @@ WiFiClient::WiFiClient(ClientContext* client)
6088
_timeout = 5000;
6189
_client->ref();
6290
WiFiClient::_add(this);
91+
92+
setSync(defaultSync);
93+
setNoDelay(defaultNoDelay);
6394
}
6495

6596
WiFiClient::~WiFiClient()
@@ -91,7 +122,6 @@ WiFiClient& WiFiClient::operator=(const WiFiClient& other)
91122
return *this;
92123
}
93124

94-
95125
int WiFiClient::connect(const char* host, uint16_t port)
96126
{
97127
IPAddress remote_addr;
@@ -147,6 +177,9 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
147177
return 0;
148178
}
149179

180+
setSync(defaultSync);
181+
setNoDelay(defaultNoDelay);
182+
150183
return 1;
151184
}
152185

@@ -156,12 +189,26 @@ void WiFiClient::setNoDelay(bool nodelay) {
156189
_client->setNoDelay(nodelay);
157190
}
158191

159-
bool WiFiClient::getNoDelay() {
192+
bool WiFiClient::getNoDelay() const {
160193
if (!_client)
161194
return false;
162195
return _client->getNoDelay();
163196
}
164197

198+
void WiFiClient::setSync(bool sync)
199+
{
200+
if (!_client)
201+
return;
202+
_client->setSync(sync);
203+
}
204+
205+
bool WiFiClient::getSync() const
206+
{
207+
if (!_client)
208+
return false;
209+
return _client->getSync();
210+
}
211+
165212
size_t WiFiClient::availableForWrite ()
166213
{
167214
return _client? _client->availableForWrite(): 0;
@@ -264,19 +311,25 @@ size_t WiFiClient::peekBytes(uint8_t *buffer, size_t length) {
264311
return _client->peekBytes((char *)buffer, count);
265312
}
266313

267-
void WiFiClient::flush()
314+
bool WiFiClient::flush(unsigned int maxWaitMs)
268315
{
269-
if (_client)
270-
_client->wait_until_sent();
316+
if (!_client)
317+
return true;
318+
319+
if (maxWaitMs == 0)
320+
maxWaitMs = WIFICLIENT_MAX_FLUSH_WAIT_MS;
321+
return _client->wait_until_sent(maxWaitMs);
271322
}
272323

273-
void WiFiClient::stop()
324+
bool WiFiClient::stop(unsigned int maxWaitMs)
274325
{
275326
if (!_client)
276-
return;
327+
return true;
277328

278-
flush();
279-
_client->close();
329+
bool ret = flush(maxWaitMs); // virtual, may be ssl's
330+
if (_client->close() != ERR_OK)
331+
ret = false;
332+
return ret;
280333
}
281334

282335
uint8_t WiFiClient::connected()

Diff for: libraries/ESP8266WiFi/src/WiFiClient.h

+27-5
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,12 @@
2828
#include "IPAddress.h"
2929
#include "include/slist.h"
3030

31-
#define WIFICLIENT_MAX_PACKET_SIZE 1460
31+
#ifndef TCP_MSS
32+
#define TCP_MSS 1460 // lwip1.4
33+
#endif
34+
35+
#define WIFICLIENT_MAX_PACKET_SIZE TCP_MSS
36+
#define WIFICLIENT_MAX_FLUSH_WAIT_MS 300
3237

3338
#define TCP_DEFAULT_KEEPALIVE_IDLE_SEC 7200 // 2 hours
3439
#define TCP_DEFAULT_KEEPALIVE_INTERVAL_SEC 75 // 75 sec
@@ -67,17 +72,16 @@ class WiFiClient : public Client, public SList<WiFiClient> {
6772
size_t peekBytes(char *buffer, size_t length) {
6873
return peekBytes((uint8_t *) buffer, length);
6974
}
70-
virtual void flush();
71-
virtual void stop();
75+
virtual bool flush(unsigned int maxWaitMs = 0);
76+
virtual bool stop(unsigned int maxWaitMs = 0);
7277
virtual uint8_t connected();
7378
virtual operator bool();
7479

7580
IPAddress remoteIP();
7681
uint16_t remotePort();
7782
IPAddress localIP();
7883
uint16_t localPort();
79-
bool getNoDelay();
80-
void setNoDelay(bool nodelay);
84+
8185
static void setLocalPortStart(uint16_t port) { _localPort = port; }
8286

8387
size_t availableForWrite();
@@ -96,6 +100,24 @@ class WiFiClient : public Client, public SList<WiFiClient> {
96100
uint8_t getKeepAliveCount () const;
97101
void disableKeepAlive () { keepAlive(0, 0, 0); }
98102

103+
// default NoDelay=False (Nagle=True=!NoDelay)
104+
// Nagle is for shortly delaying outgoing data, to send less/bigger packets
105+
// Nagle should be disabled for telnet-like/interactive streams
106+
// Nagle is meaningless/ignored when Sync=true
107+
static void setDefaultNoDelay (bool noDelay);
108+
static bool getDefaultNoDelay ();
109+
bool getNoDelay() const;
110+
void setNoDelay(bool nodelay);
111+
112+
// default Sync=false
113+
// When sync is true, all writes are automatically flushed.
114+
// This is slower but also does not allocate
115+
// temporary memory for sending data
116+
static void setDefaultSync (bool sync);
117+
static bool getDefaultSync ();
118+
bool getSync() const;
119+
void setSync(bool sync);
120+
99121
protected:
100122

101123
static int8_t _s_connected(void* arg, void* tpcb, int8_t err);

Diff for: libraries/ESP8266WiFi/src/WiFiClientSecureAxTLS.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -271,12 +271,12 @@ uint8_t WiFiClientSecure::connected()
271271
return false;
272272
}
273273

274-
void WiFiClientSecure::stop()
274+
bool WiFiClientSecure::stop(unsigned int maxWaitMs)
275275
{
276276
if (_ssl) {
277277
_ssl->stop();
278278
}
279-
WiFiClient::stop();
279+
return WiFiClient::stop(maxWaitMs);
280280
}
281281

282282
static bool parseHexNibble(char pb, uint8_t* res)

Diff for: libraries/ESP8266WiFi/src/WiFiClientSecureAxTLS.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class WiFiClientSecure : public WiFiClient {
5151
int read() override;
5252
int peek() override;
5353
size_t peekBytes(uint8_t *buffer, size_t length) override;
54-
void stop() override;
54+
bool stop(unsigned int maxWaitMs = 0) override;
5555

5656
bool setCACert(const uint8_t* pk, size_t size);
5757
bool setCertificate(const uint8_t* pk, size_t size);

Diff for: libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp

+5-9
Original file line numberDiff line numberDiff line change
@@ -175,23 +175,19 @@ void WiFiClientSecure::setBufferSizes(int recv, int xmit) {
175175
_iobuf_out_size = xmit;
176176
}
177177

178-
void WiFiClientSecure::stop() {
179-
flush();
180-
if (_client) {
181-
_client->wait_until_sent();
182-
_client->abort();
183-
}
184-
WiFiClient::stop();
178+
bool WiFiClientSecure::stop(unsigned int maxWaitMs) {
179+
bool ret = WiFiClient::stop(maxWaitMs); // calls our virtual flush()
185180
// Only if we've already connected, clear the connection options
186181
if (_handshake_done) {
187182
_clearAuthenticationSettings();
188183
}
189184
_freeSSL();
185+
return ret;
190186
}
191187

192-
void WiFiClientSecure::flush() {
188+
bool WiFiClientSecure::flush(unsigned int maxWaitMs) {
193189
(void) _run_until(BR_SSL_SENDAPP);
194-
WiFiClient::flush();
190+
return WiFiClient::flush(maxWaitMs);
195191
}
196192

197193
int WiFiClientSecure::connect(IPAddress ip, uint16_t port) {

Diff for: libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ class WiFiClientSecure : public WiFiClient {
5555
int read() override;
5656
int peek() override;
5757
size_t peekBytes(uint8_t *buffer, size_t length) override;
58-
void stop() override;
59-
void flush() override;
58+
bool flush(unsigned int maxWaitMs = 0) override;
59+
bool stop(unsigned int maxWaitMs = 0) override;
6060

6161
// Don't validate the chain, just accept whatever is given. VERY INSECURE!
6262
void setInsecure() {

Diff for: libraries/ESP8266WiFi/src/WiFiServer.cpp

+8-3
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,16 @@ void WiFiServer::begin(uint16_t port) {
8888
}
8989

9090
void WiFiServer::setNoDelay(bool nodelay) {
91-
_noDelay = nodelay;
91+
_noDelay = nodelay? _ndTrue: _ndFalse;
9292
}
9393

9494
bool WiFiServer::getNoDelay() {
95-
return _noDelay;
95+
switch (_noDelay)
96+
{
97+
case _ndFalse: return false;
98+
case _ndTrue: return true;
99+
default: return WiFiClient::getDefaultNoDelay();
100+
}
96101
}
97102

98103
bool WiFiServer::hasClient() {
@@ -106,7 +111,7 @@ WiFiClient WiFiServer::available(byte* status) {
106111
if (_unclaimed) {
107112
WiFiClient result(_unclaimed);
108113
_unclaimed = _unclaimed->next();
109-
result.setNoDelay(_noDelay);
114+
result.setNoDelay(getNoDelay());
110115
DEBUGV("WS:av\r\n");
111116
return result;
112117
}

Diff for: libraries/ESP8266WiFi/src/WiFiServer.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class WiFiServer : public Server {
4343

4444
ClientContext* _unclaimed;
4545
ClientContext* _discarded;
46-
bool _noDelay = false;
46+
enum { _ndDefault, _ndFalse, _ndTrue } _noDelay = _ndDefault;
4747

4848
public:
4949
WiFiServer(IPAddress addr, uint16_t port);

0 commit comments

Comments
 (0)