Skip to content

Commit e752e96

Browse files
authored
lwip2 updates: no more git sub-sub-module deps, faster checksum, backlog limitation and other fixes (#6887)
* upstream lwIP is now downloaded by a makefile, not subsubmoduled * lwip2: upstream lwIP not sub-sub-modules anymore lwip2: Allow IPv4 and IPv6 DNS and SNTP server configured via DHCP to co-exist (patch against upstream) * lwip2: enable tcp-listen-with-backlog feature * lwip2 submodule update: - enable more efficient chksum algorithm thanks to Richard Allen - enable tcp listener with backlog * more comments, fix backlog management, fix API * move default value definition in .cpp because one must not believe it can be redefined before including WiFiServer.h * improved backlog handling, it is no more a breaking change
1 parent bc4f000 commit e752e96

14 files changed

+134
-34
lines changed

libraries/ESP8266WiFi/src/WiFiServer.cpp

+58-14
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,17 @@ extern "C" {
3535
#include "lwip/opt.h"
3636
#include "lwip/tcp.h"
3737
#include "lwip/inet.h"
38+
#include "lwip/init.h" // LWIP_VERSION_
3839
#include <include/ClientContext.h>
3940

41+
#ifndef MAX_PENDING_CLIENTS_PER_PORT
42+
#define MAX_PENDING_CLIENTS_PER_PORT 5
43+
#endif
44+
4045
WiFiServer::WiFiServer(const IPAddress& addr, uint16_t port)
4146
: _port(port)
4247
, _addr(addr)
43-
, _pcb(nullptr)
48+
, _listen_pcb(nullptr)
4449
, _unclaimed(nullptr)
4550
, _discarded(nullptr)
4651
{
@@ -49,7 +54,7 @@ WiFiServer::WiFiServer(const IPAddress& addr, uint16_t port)
4954
WiFiServer::WiFiServer(uint16_t port)
5055
: _port(port)
5156
, _addr(IP_ANY_TYPE)
52-
, _pcb(nullptr)
57+
, _listen_pcb(nullptr)
5358
, _unclaimed(nullptr)
5459
, _discarded(nullptr)
5560
{
@@ -60,30 +65,38 @@ void WiFiServer::begin() {
6065
}
6166

6267
void WiFiServer::begin(uint16_t port) {
68+
return begin(port, MAX_PENDING_CLIENTS_PER_PORT);
69+
}
70+
71+
void WiFiServer::begin(uint16_t port, uint8_t backlog) {
6372
close();
73+
if (!backlog)
74+
return;
6475
_port = port;
65-
err_t err;
6676
tcp_pcb* pcb = tcp_new();
6777
if (!pcb)
6878
return;
6979

7080
pcb->so_options |= SOF_REUSEADDR;
7181

7282
// (IPAddress _addr) operator-converted to (const ip_addr_t*)
73-
err = tcp_bind(pcb, _addr, _port);
74-
75-
if (err != ERR_OK) {
83+
if (tcp_bind(pcb, _addr, _port) != ERR_OK) {
7684
tcp_close(pcb);
7785
return;
7886
}
7987

88+
#if LWIP_VERSION_MAJOR == 1
8089
tcp_pcb* listen_pcb = tcp_listen(pcb);
90+
#else
91+
tcp_pcb* listen_pcb = tcp_listen_with_backlog(pcb, backlog);
92+
#endif
93+
8194
if (!listen_pcb) {
8295
tcp_close(pcb);
8396
return;
8497
}
85-
_pcb = listen_pcb;
86-
_port = _pcb->local_port;
98+
_listen_pcb = listen_pcb;
99+
_port = _listen_pcb->local_port;
87100
tcp_accept(listen_pcb, &WiFiServer::_s_accept);
88101
tcp_arg(listen_pcb, (void*) this);
89102
}
@@ -111,6 +124,10 @@ WiFiClient WiFiServer::available(byte* status) {
111124
(void) status;
112125
if (_unclaimed) {
113126
WiFiClient result(_unclaimed);
127+
#if LWIP_VERSION_MAJOR != 1
128+
_unclaimed->acceptPCB();
129+
tcp_backlog_accepted(_unclaimed->getPCB());
130+
#endif
114131
_unclaimed = _unclaimed->next();
115132
result.setNoDelay(getNoDelay());
116133
DEBUGV("WS:av\r\n");
@@ -122,21 +139,21 @@ WiFiClient WiFiServer::available(byte* status) {
122139
}
123140

124141
uint8_t WiFiServer::status() {
125-
if (!_pcb)
142+
if (!_listen_pcb)
126143
return CLOSED;
127-
return _pcb->state;
144+
return _listen_pcb->state;
128145
}
129146

130147
uint16_t WiFiServer::port() const {
131148
return _port;
132149
}
133150

134151
void WiFiServer::close() {
135-
if (!_pcb) {
152+
if (!_listen_pcb) {
136153
return;
137154
}
138-
tcp_close(_pcb);
139-
_pcb = nullptr;
155+
tcp_close(_listen_pcb);
156+
_listen_pcb = nullptr;
140157
}
141158

142159
void WiFiServer::stop() {
@@ -169,9 +186,36 @@ T* slist_append_tail(T* head, T* item) {
169186
long WiFiServer::_accept(tcp_pcb* apcb, long err) {
170187
(void) err;
171188
DEBUGV("WS:ac\r\n");
189+
190+
#if LWIP_VERSION_MAJOR == 1
191+
172192
ClientContext* client = new ClientContext(apcb, &WiFiServer::_s_discard, this);
193+
tcp_accepted(_listen_pcb);
194+
195+
#else
196+
197+
// backlog doc:
198+
// http://lwip.100.n7.nabble.com/Problem-re-opening-listening-pbc-tt32484.html#a32494
199+
// https://www.nongnu.org/lwip/2_1_x/group__tcp__raw.html#gaeff14f321d1eecd0431611f382fcd338
200+
201+
// lwip-v2: Tell ClientContext to not accept yet the connection (final 'false' below)
202+
ClientContext* client = new ClientContext(apcb, &WiFiServer::_s_discard, this, false);
203+
// increase lwIP's backlog
204+
tcp_backlog_delayed(apcb);
205+
206+
// Optimization Path:
207+
// when lwip-v1.4 is not allowed anymore,
208+
// - _accept() should not create ClientContext anymore
209+
// - apcb should be stored into some sort of linked list (->_unclaimed)
210+
// (the linked list would store tcp_pcb* instead of ClientContext*)
211+
// (TCP_PCB_EXTARGS might be used for that (lwIP's struct tcp_pcb))
212+
// - on available(), get the pcb back and create the ClientContext
213+
// (this is not done today for better source readability with lwip-1.4 around)
214+
215+
#endif
216+
173217
_unclaimed = slist_append_tail(_unclaimed, client);
174-
tcp_accepted(_pcb);
218+
175219
return ERR_OK;
176220
}
177221

libraries/ESP8266WiFi/src/WiFiServer.h

+33-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,37 @@ extern "C" {
3131
#include "Server.h"
3232
#include "IPAddress.h"
3333

34+
// lwIP-v2 backlog facility allows to keep memory safe by limiting the
35+
// maximum number of incoming *pending clients*. Default number of possibly
36+
// simultaneously pending clients is defined in WiFiServer.cpp
37+
// (MAX_PENDING_CLIENTS_PER_PORT=5). User can overide it at runtime from
38+
// sketch:
39+
// WiFiServer::begin(port, max-simultaneous-pending-clients);
40+
//
41+
// An "incoming pending" client is a new incoming TCP connection trying to
42+
// reach the TCP server. It is "pending" until lwIP acknowledges it and
43+
// "accepted / no more pending" when user calls WiFiServer::available().
44+
//
45+
// Before the backlog feature or with lwIP-v1.4, there was no pending
46+
// connections: They were immediately accepted and filling RAM.
47+
//
48+
// Several pending clients can appear during the time when one client is
49+
// served by a long not-async service like ESP8266WebServer. During that
50+
// time WiFiServer::available() cannot be called.
51+
//
52+
// Note: This *does not limit* the number of *simultaneously accepted
53+
// clients*. Such limit management is left to the user.
54+
//
55+
// Thus, when the maximum number of pending connections is reached, new
56+
// connections are delayed.
57+
// By "delayed", it is meant that WiFiServer(lwIP) will not answer to the
58+
// SYN packet until there is room for a new one: The TCP server on that port
59+
// will be mute. The TCP client will regularly try to connect until success
60+
// or a timeout occurs (72s on windows).
61+
//
62+
// When user calls WiFiServer::available(), the tcp server stops muting and
63+
// answers to newcomers (until the "backlog" pending list is full again).
64+
3465
class ClientContext;
3566
class WiFiClient;
3667

@@ -39,7 +70,7 @@ class WiFiServer : public Server {
3970
protected:
4071
uint16_t _port;
4172
IPAddress _addr;
42-
tcp_pcb* _pcb;
73+
tcp_pcb* _listen_pcb;
4374

4475
ClientContext* _unclaimed;
4576
ClientContext* _discarded;
@@ -53,6 +84,7 @@ class WiFiServer : public Server {
5384
bool hasClient();
5485
void begin();
5586
void begin(uint16_t port);
87+
void begin(uint16_t port, uint8_t backlog);
5688
void setNoDelay(bool nodelay);
5789
bool getNoDelay();
5890
virtual size_t write(uint8_t);

libraries/ESP8266WiFi/src/include/ClientContext.h

+18-7
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,27 @@ bool getDefaultPrivateGlobalSyncValue ();
3636
class ClientContext
3737
{
3838
public:
39-
ClientContext(tcp_pcb* pcb, discard_cb_t discard_cb, void* discard_cb_arg) :
39+
ClientContext(tcp_pcb* pcb, discard_cb_t discard_cb, void* discard_cb_arg, bool acceptNow = true) :
4040
_pcb(pcb), _rx_buf(0), _rx_buf_offset(0), _discard_cb(discard_cb), _discard_cb_arg(discard_cb_arg), _refcnt(0), _next(0),
4141
_sync(::getDefaultPrivateGlobalSyncValue())
4242
{
43-
tcp_setprio(pcb, TCP_PRIO_MIN);
44-
tcp_arg(pcb, this);
45-
tcp_recv(pcb, &_s_recv);
46-
tcp_sent(pcb, &_s_acked);
47-
tcp_err(pcb, &_s_error);
48-
tcp_poll(pcb, &_s_poll, 1);
43+
if (acceptNow)
44+
acceptPCB();
45+
}
46+
47+
tcp_pcb* getPCB ()
48+
{
49+
return _pcb;
50+
}
51+
52+
void acceptPCB()
53+
{
54+
tcp_setprio(_pcb, TCP_PRIO_MIN);
55+
tcp_arg(_pcb, this);
56+
tcp_recv(_pcb, &_s_recv);
57+
tcp_sent(_pcb, &_s_acked);
58+
tcp_err(_pcb, &_s_error);
59+
tcp_poll(_pcb, &_s_poll, 1);
4960

5061
// keep-alive not enabled by default
5162
//keepAlive();

tests/host/common/MockWiFiServer.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ WiFiClient WiFiServer::available (uint8_t* status)
5959
{
6060
(void)status;
6161
if (hasClient())
62-
return WiFiClient(new ClientContext(serverAccept(pcb2int(_pcb))));
62+
return WiFiClient(new ClientContext(serverAccept(pcb2int(_listen_pcb))));
6363
return WiFiClient();
6464
}
6565

tests/host/common/MockWiFiServerSocket.cpp

+12-5
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,13 @@ int serverAccept (int srvsock)
6060

6161
void WiFiServer::begin (uint16_t port)
6262
{
63+
return begin(port, !0);
64+
}
65+
66+
void WiFiServer::begin (uint16_t port, uint8_t backlog)
67+
{
68+
if (!backlog)
69+
return;
6370
_port = port;
6471
return begin();
6572
}
@@ -109,13 +116,13 @@ void WiFiServer::begin ()
109116

110117

111118
// store int into pointer
112-
_pcb = int2pcb(sock);
119+
_listen_pcb = int2pcb(sock);
113120
}
114121

115122
bool WiFiServer::hasClient ()
116123
{
117124
struct pollfd p;
118-
p.fd = pcb2int(_pcb);
125+
p.fd = pcb2int(_listen_pcb);
119126
p.events = POLLIN;
120127
return poll(&p, 1, 0) && p.revents == POLLIN;
121128
}
@@ -134,7 +141,7 @@ size_t WiFiServer::write (const uint8_t *buf, size_t size)
134141

135142
void WiFiServer::close ()
136143
{
137-
if (pcb2int(_pcb) >= 0)
138-
::close(pcb2int(_pcb));
139-
_pcb = int2pcb(-1);
144+
if (pcb2int(_listen_pcb) >= 0)
145+
::close(pcb2int(_listen_pcb));
146+
_listen_pcb = int2pcb(-1);
140147
}

tools/sdk/lib/liblwip2-1460-feat.a

7.1 KB
Binary file not shown.

tools/sdk/lib/liblwip2-1460.a

4.14 KB
Binary file not shown.

tools/sdk/lib/liblwip2-536-feat.a

7.1 KB
Binary file not shown.

tools/sdk/lib/liblwip2-536.a

4.14 KB
Binary file not shown.

tools/sdk/lib/liblwip6-1460-feat.a

8.69 KB
Binary file not shown.

tools/sdk/lib/liblwip6-536-feat.a

8.69 KB
Binary file not shown.
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// generated by makefiles/make-lwip2-hash
22
#ifndef LWIP_HASH_H
33
#define LWIP_HASH_H
4-
#define LWIP_HASH_STR "STABLE-2_1_2_RELEASE/glue:1.2-16-ge23a07e"
4+
#define LWIP_HASH_STR "STABLE-2_1_2_RELEASE/glue:1.2-29-gb543b1f"
55
#endif // LWIP_HASH_H

tools/sdk/lwip2/include/lwipopts.h

+10-4
Original file line numberDiff line numberDiff line change
@@ -1402,7 +1402,7 @@
14021402
* TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb.
14031403
*/
14041404
#if !defined TCP_LISTEN_BACKLOG || defined __DOXYGEN__
1405-
#define TCP_LISTEN_BACKLOG 0
1405+
#define TCP_LISTEN_BACKLOG LWIP_FEATURES // 0
14061406
#endif
14071407

14081408
/**
@@ -2278,6 +2278,12 @@
22782278
* @ingroup lwip_opts_infrastructure
22792279
* @{
22802280
*/
2281+
/**
2282+
* LWIP_CHKSUM_ALGORITHM==3: Checksum algorithm fastest for ESP8266
2283+
*/
2284+
#if !defined LWIP_CHKSUM_ALGORITHM || defined __DOXYGEN__
2285+
#define LWIP_CHKSUM_ALGORITHM 3 // 2
2286+
#endif
22812287
/**
22822288
* LWIP_CHECKSUM_CTRL_PER_NETIF==1: Checksum generation/check can be enabled/disabled
22832289
* per netif.
@@ -3573,7 +3579,7 @@ extern "C" {
35733579
#define SNTP_SUPPRESS_DELAY_CHECK 1
35743580
#define SNTP_UPDATE_DELAY_DEFAULT 3600000 // update delay defined by a default weak function
35753581
#define SNTP_UPDATE_DELAY sntp_update_delay_MS_rfc_not_less_than_15000()
3576-
extern uint32_t SNTP_UPDATE_DELAY;
3582+
uint32_t SNTP_UPDATE_DELAY;
35773583

35783584
#if LWIP_FEATURES
35793585
// esp8266/arduino/lwip-1.4 had 3 possible SNTP servers (constant was harcoded)
@@ -3591,7 +3597,7 @@ extern uint32_t SNTP_UPDATE_DELAY;
35913597
#define SNTP_STARTUP_DELAY 1 // enable startup delay
35923598
#define SNTP_STARTUP_DELAY_FUNC_DEFAULT 0 // to 0 by default via a default weak function
35933599
#define SNTP_STARTUP_DELAY_FUNC sntp_startup_delay_MS_rfc_not_less_than_60000()
3594-
extern uint32_t SNTP_STARTUP_DELAY_FUNC;
3600+
uint32_t SNTP_STARTUP_DELAY_FUNC;
35953601

35963602
/*
35973603
--------------------------------------------------
@@ -3611,7 +3617,7 @@ struct netif;
36113617
#error LWIP_ERR_T definition should come from lwip1.4 from espressif
36123618
#endif
36133619
//#define LWIP_ERR_T s8
3614-
LWIP_ERR_T lwip_unhandled_packet (struct pbuf* pbuf, struct netif* netif) __attribute__((weak));
3620+
LWIP_ERR_T lwip_unhandled_packet (struct pbuf* pbuf, struct netif* netif);
36153621

36163622
/*
36173623
--------------------------------------------------

0 commit comments

Comments
 (0)