Skip to content

Commit 2e0fddd

Browse files
committed
Added test for connect timing
1 parent 5f1f368 commit 2e0fddd

3 files changed

Lines changed: 189 additions & 0 deletions

File tree

examples/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ add_subdirectory("spi")
66
add_subdirectory("serial2")
77
add_subdirectory("using-arduino-library")
88
add_subdirectory("pwm")
9+
add_subdirectory("network-connect-timing")
910

1011
# BME280 Sensor Examples
1112
arduino_library(SparkFunBME280 "https://github.com/sparkfun/SparkFun_BME280_Arduino_Library" )
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
arduino_sketch(network-connect-timing network-connect-timing.ino)
2+
3+
if(APPLE)
4+
target_compile_options(network-connect-timing PRIVATE -Wno-deprecated-declarations)
5+
endif()
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
/*
2+
Network connect timing test.
3+
4+
There are three test setups to exercise different situations:
5+
6+
Instant connect failure:
7+
For this test, there should be nothing listening on localhost port 8123
8+
9+
network-connect-timing should say "connect failed" with
10+
elapsed=0ms or nearly 0.
11+
12+
Connect success:
13+
Start a plain TCP listener locally, for example:
14+
nc -lk 127.0.0.1 8123
15+
16+
network-connect-timing should say "connect succeeded",
17+
display some send/response/connected/closed messages,
18+
and the elapsed time should be 1000 ms or so.
19+
20+
Connect timeout:
21+
For this test, you need to configure the host kernel to drop packets.
22+
It does not matter if the listener is running or not.
23+
24+
On MacOS you can drop packets as follows:
25+
Add this to /etc/pf.conf :
26+
anchor "connect-timeout-test"
27+
load anchor "connect-timeout-test" from "/etc/pf.anchors/connect-timeout-test"
28+
29+
Create a file /etc/pf.anchors/connect-timeout-test containing:
30+
block drop quick on lo0 proto tcp from any to 127.0.0.1 port 8123
31+
block drop quick on lo0 proto tcp from 127.0.0.1 to any port 8123
32+
33+
Then run this to enable the rules:
34+
sudo pfctl -f /etc/pf.conf
35+
sudo pfctl -e
36+
37+
For Linux you can drop packets by issuing:
38+
sudo nft add table inet connect_test
39+
sudo nft 'add chain inet connect_test output { type filter hook output priority 0; }'
40+
sudo nft 'add chain inet connect_test input { type filter hook input priority 0; }'
41+
sudo nft 'add rule inet connect_test output oifname "lo" tcp dport 8123 drop'
42+
sudo nft 'add rule inet connect_test input iifname "lo" tcp sport 8123 drop'
43+
44+
With those packet-dropping rules in place,
45+
network-connect-test should say "connect failed"
46+
and the elapsed time should be a little more than 2000 ms
47+
for the first test and 3000 ms for the second.
48+
*/
49+
50+
#include <Arduino.h>
51+
#include <WiFi.h>
52+
#include <WiFiClient.h>
53+
54+
namespace {
55+
56+
constexpr const char* ssid = "localhost-test";
57+
constexpr const char* password = "unused";
58+
constexpr const char* host = "127.0.0.1";
59+
constexpr uint16_t port = 8123;
60+
constexpr int32_t explicit_connect_timeout_ms = 2000;
61+
constexpr int32_t default_connect_timeout_ms = 3000;
62+
constexpr unsigned long read_timeout_ms = 1000;
63+
64+
WiFiClient explicit_timeout_client;
65+
WiFiClient default_timeout_client;
66+
67+
void print_test_elapsed(const char* label, unsigned long start_ms) {
68+
Serial.print(label);
69+
Serial.print(" elapsed=");
70+
Serial.print(millis() - start_ms);
71+
Serial.println("ms");
72+
}
73+
74+
void wait_for_wifi() {
75+
Serial.print("Attempting to connect to SSID: ");
76+
Serial.println(ssid);
77+
WiFi.begin(ssid, password);
78+
Serial.print("Connected to ");
79+
Serial.println(ssid);
80+
Serial.println();
81+
}
82+
83+
bool connect_with_explicit_timeout() {
84+
Serial.print("Connecting with explicit timeout to ");
85+
Serial.print(host);
86+
Serial.print(":");
87+
Serial.print(port);
88+
Serial.print(" timeout=");
89+
Serial.print(explicit_connect_timeout_ms);
90+
Serial.println("ms");
91+
92+
if (!explicit_timeout_client.connect(host, port, explicit_connect_timeout_ms)) {
93+
Serial.println("Explicit-timeout connect failed");
94+
return false;
95+
}
96+
97+
Serial.println("Explicit-timeout connect succeeded");
98+
return true;
99+
}
100+
101+
bool connect_with_default_timeout() {
102+
default_timeout_client.setConnectionTimeout(default_connect_timeout_ms);
103+
104+
Serial.print("Connecting with default connect(host, port) using timeout=");
105+
Serial.print(default_connect_timeout_ms);
106+
Serial.println("ms");
107+
108+
if (!default_timeout_client.connect(host, port)) {
109+
Serial.println("Default-timeout connect failed");
110+
return false;
111+
}
112+
113+
Serial.println("Default-timeout connect succeeded");
114+
return true;
115+
}
116+
117+
void send_plain_text(WiFiClient& client, const char* label) {
118+
Serial.print(label);
119+
client.println("hello from WiFiClient");
120+
}
121+
122+
void drain_input(WiFiClient& client, const char* label) {
123+
unsigned long deadline = millis() + read_timeout_ms;
124+
125+
Serial.print(label);
126+
Serial.println(" waiting for response bytes");
127+
128+
while (client.connected() && millis() < deadline) {
129+
while (client.available() > 0) {
130+
int ch = client.read();
131+
if (ch >= 0) {
132+
Serial.write(static_cast<char>(ch));
133+
deadline = millis() + read_timeout_ms;
134+
}
135+
}
136+
delay(10);
137+
}
138+
139+
Serial.println();
140+
Serial.print(label);
141+
Serial.print(" connected() -> ");
142+
Serial.println(client.connected() ? "true" : "false");
143+
}
144+
145+
void close_client(WiFiClient& client, const char* label) {
146+
client.stop();
147+
Serial.print(label);
148+
Serial.println(" closed");
149+
}
150+
151+
} // namespace
152+
153+
void setup() {
154+
Serial.begin(115200);
155+
delay(100);
156+
157+
wait_for_wifi();
158+
159+
unsigned long explicit_test_start_ms = millis();
160+
if (connect_with_explicit_timeout()) {
161+
send_plain_text(explicit_timeout_client, "explicit_timeout_client");
162+
drain_input(explicit_timeout_client, "explicit_timeout_client");
163+
close_client(explicit_timeout_client, "explicit_timeout_client");
164+
}
165+
print_test_elapsed("explicit-timeout test", explicit_test_start_ms);
166+
Serial.println();
167+
168+
unsigned long default_test_start_ms = millis();
169+
if (connect_with_default_timeout()) {
170+
send_plain_text(default_timeout_client, "default_timeout_client");
171+
drain_input(default_timeout_client, "default_timeout_client");
172+
close_client(default_timeout_client, "default_timeout_client");
173+
}
174+
print_test_elapsed("default-timeout test", default_test_start_ms);
175+
176+
Serial.println();
177+
Serial.println("network-connect-timing test complete");
178+
}
179+
180+
void loop() {
181+
exit(0);
182+
// delay(1000);
183+
}

0 commit comments

Comments
 (0)