Skip to content

Commit 55a5d03

Browse files
committed
Fix issue espressif#5507 "Constructor WebServer::WebServer(IPAddress addr, int port) produces an unexpected result"
This change adds support for multi-homed servers to libraries/WiFi. It was assumed to be there already by libraries/WebServer, but was not. This led to unexpected results when the IP address-specific constructor of class WebServer was used (see issue 5507). This change was tested using three concurrent instances of WebServer, one bound to the WiFi station address, one bound to the WiFi soft AP address, and one bound to INADDR_ANY. See libraries/WebServer/examples/MultiHomedServers for the test method.
1 parent 4a2034f commit 55a5d03

File tree

5 files changed

+188
-3
lines changed

5 files changed

+188
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
secret.h
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
#include <WiFi.h>
2+
#include <WiFiClient.h>
3+
#include <WebServer.h>
4+
#include <ESPmDNS.h>
5+
6+
/*
7+
* MultiHomedServers
8+
*
9+
* MultiHomedServers tests support for multi-homed servers, i.e. a distinct web servers on each IP interface.
10+
* It only tests the case n=2 because on a basic ESP32 device, we only have two IP interfaces, namely
11+
* the WiFi station interfaces and the WiFi soft AP interface.
12+
*
13+
* For this to work, the WebServer and the WiFiServer classes must correctly handle the case where an
14+
* IP address is passed to their relevant constructor. It also requires WebServer to work with multiple,
15+
* simultaneous instances.
16+
*
17+
* Testing the WebServer and the WiFiServer constructors was the primary purpose of this script.
18+
* The part of WebServer used by this sketch does seem to work with multiple, simultaneous instances.
19+
* However there is much functionality in WebServer that is not tested here. It may all be well, but
20+
* that is not proven here.
21+
*
22+
* This sketch starts the mDNS server, as did HelloServer, and it resolves esp32.local on both interfaces,
23+
* but was not otherwise tested.
24+
*
25+
* This script also tests that a server not bound to a specific IP address still works.
26+
*
27+
* We create three, simultaneous web servers, one specific to each interface and one that listens on both:
28+
*
29+
* name IP Address Port
30+
* ---- ---------- ----
31+
* server0 INADDR_ANY 8080
32+
* server1 station address 8081
33+
* server2 soft AP address 8082
34+
*
35+
* The expected responses to a brower's requests are as follows:
36+
*
37+
* 1. when client connected to the same WLAN as the station:
38+
* Request URL Response
39+
* ----------- --------
40+
* http://stationaddress:8080 "hello from server0"
41+
* http://stationaddress:8081 "hello from server1"
42+
* http://stationaddress:8082 browser reports failure to connect
43+
*
44+
* 2. when client is connected to the soft AP:
45+
*
46+
* Request URL Response
47+
* ----------- --------
48+
* http://softAPaddress:8080 "hello from server0"
49+
* http://softAPaddress:8082 "hello from server2"
50+
* http://softAPaddress:8081 browser reports failure to connect
51+
*
52+
* 3. Repeat 1 and 2 above with esp32.local in place of stationaddress and softAPaddress, respectively.
53+
*
54+
* MultiHomedServers was originally based on HelloServer.
55+
*/
56+
57+
#include "secret.h"
58+
const char* ssid = MySSID;
59+
const char* password = MyPASSWORD;
60+
const char *apssid = "ESP32";
61+
62+
WebServer *server0, *server1, *server2;
63+
64+
const int led = 13;
65+
66+
void handleRoot(WebServer *server, const char *content) {
67+
digitalWrite(led, 1);
68+
server->send(200, "text/plain", content);
69+
digitalWrite(led, 0);
70+
}
71+
72+
void handleRoot0() {
73+
handleRoot(server0, "hello from server0");
74+
}
75+
76+
void handleRoot1() {
77+
handleRoot(server1, "hello from server1");
78+
}
79+
80+
void handleRoot2() {
81+
handleRoot(server2, "hello from server2");
82+
}
83+
84+
void handleNotFound(WebServer *server) {
85+
digitalWrite(led, 1);
86+
String message = "File Not Found\n\n";
87+
message += "URI: ";
88+
message += server->uri();
89+
message += "\nMethod: ";
90+
message += (server->method() == HTTP_GET) ? "GET" : "POST";
91+
message += "\nArguments: ";
92+
message += server->args();
93+
message += "\n";
94+
for (uint8_t i = 0; i < server->args(); i++) {
95+
message += " " + server->argName(i) + ": " + server->arg(i) + "\n";
96+
}
97+
server->send(404, "text/plain", message);
98+
digitalWrite(led, 0);
99+
}
100+
101+
void handleNotFound0() {
102+
handleNotFound(server0);
103+
}
104+
105+
void handleNotFound1() {
106+
handleNotFound(server1);
107+
}
108+
109+
void handleNotFound2() {
110+
handleNotFound(server2);
111+
}
112+
113+
void setup(void) {
114+
pinMode(led, OUTPUT);
115+
digitalWrite(led, 0);
116+
Serial.begin(115200);
117+
WiFi.mode(WIFI_STA);
118+
WiFi.begin(ssid, password);
119+
Serial.println("");
120+
121+
// Wait for connection
122+
while (WiFi.status() != WL_CONNECTED) {
123+
delay(500);
124+
Serial.print(".");
125+
}
126+
Serial.println("");
127+
Serial.print("Connected to ");
128+
Serial.println(ssid);
129+
Serial.print("IP address: ");
130+
Serial.println(WiFi.localIP());
131+
if (!WiFi.softAP(apssid)) {
132+
Serial.println("failed to start softAP");
133+
for (;;) {
134+
digitalWrite(led, 1);
135+
delay(100);
136+
digitalWrite(led, 0);
137+
delay(100);
138+
}
139+
}
140+
Serial.print("Soft AP: ");
141+
Serial.print(apssid);
142+
Serial.print(" IP address: ");
143+
Serial.println(WiFi.softAPIP());
144+
145+
if (MDNS.begin("esp32")) {
146+
Serial.println("MDNS responder started");
147+
}
148+
149+
server0 = new WebServer(8080);
150+
server1 = new WebServer(WiFi.localIP(), 8081);
151+
server2 = new WebServer(WiFi.softAPIP(), 8082);
152+
153+
server0->on("/", handleRoot0);
154+
server1->on("/", handleRoot1);
155+
server2->on("/", handleRoot2);
156+
157+
server0->onNotFound(handleNotFound0);
158+
server1->onNotFound(handleNotFound1);
159+
server2->onNotFound(handleNotFound2);
160+
161+
server0->begin();
162+
Serial.println("HTTP server0 started");
163+
server1->begin();
164+
Serial.println("HTTP server1 started");
165+
server2->begin();
166+
Serial.println("HTTP server2 started");
167+
}
168+
169+
void loop(void) {
170+
server0->handleClient();
171+
server1->handleClient();
172+
server2->handleClient();
173+
delay(2);//allow the cpu to switch to other tasks
174+
}

Diff for: libraries/WebServer/src/WebServer.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ WebServer::WebServer(IPAddress addr, int port)
5959
, _contentLength(0)
6060
, _chunked(false)
6161
{
62+
log_v("WebServer::Webserver(addr=%s, port=%d)", addr.toString().c_str(), port);
6263
}
6364

6465
WebServer::WebServer(int port)
@@ -81,6 +82,7 @@ WebServer::WebServer(int port)
8182
, _contentLength(0)
8283
, _chunked(false)
8384
{
85+
log_v("WebServer::Webserver(port=%d)", port);
8486
}
8587

8688
WebServer::~WebServer() {
@@ -289,7 +291,7 @@ void WebServer::handleClient() {
289291
return;
290292
}
291293

292-
log_v("New client");
294+
log_v("New client: client.localIP()=%s", client.localIP().toString().c_str());
293295

294296
_currentClient = client;
295297
_currentStatus = HC_WAIT_READ;

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ void WiFiServer::begin(uint16_t port, int enable){
8282
return;
8383
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
8484
server.sin_family = AF_INET;
85-
server.sin_addr.s_addr = INADDR_ANY;
85+
server.sin_addr.s_addr = _addr;
8686
server.sin_port = htons(_port);
8787
if(bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
8888
return;

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

+9-1
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,14 @@
2222
#include "Arduino.h"
2323
#include "Server.h"
2424
#include "WiFiClient.h"
25+
#include "arpa/inet.h"
26+
#include "IPAddress.h"
2527

2628
class WiFiServer : public Server {
2729
private:
2830
int sockfd;
2931
int _accepted_sockfd = -1;
32+
IPAddress _addr;
3033
uint16_t _port;
3134
uint8_t _max_clients;
3235
bool _listening;
@@ -35,7 +38,12 @@ class WiFiServer : public Server {
3538
public:
3639
void listenOnLocalhost(){}
3740

38-
WiFiServer(uint16_t port=80, uint8_t max_clients=4):sockfd(-1),_accepted_sockfd(-1),_port(port),_max_clients(max_clients),_listening(false),_noDelay(false){}
41+
WiFiServer(uint16_t port=80, uint8_t max_clients=4):sockfd(-1),_accepted_sockfd(-1),_addr(INADDR_ANY),_port(port),_max_clients(max_clients),_listening(false),_noDelay(false) {
42+
log_v("WiFiServer::WiFiServer(port=%d, ...)", port);
43+
}
44+
WiFiServer(const IPAddress& addr, uint16_t port=80, uint8_t max_clients=4):sockfd(-1),_accepted_sockfd(-1),_addr(addr),_port(port),_max_clients(max_clients),_listening(false),_noDelay(false) {
45+
log_v("WiFiServer::WiFiServer(addr=%s, port=%d, ...)", addr.toString().c_str(), port);
46+
}
3947
~WiFiServer(){ end();}
4048
WiFiClient available();
4149
WiFiClient accept(){return available();}

0 commit comments

Comments
 (0)