Skip to content

Commit 6833d27

Browse files
committed
SignalHandler: cleanup network
1 parent dd1bd6a commit 6833d27

File tree

5 files changed

+158
-6
lines changed

5 files changed

+158
-6
lines changed

ArduinoCore-Linux/cores/arduino/Ethernet.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,25 @@ class EthernetImpl {
3636
inline EthernetImpl Ethernet;
3737

3838
class EthernetClient : public Client {
39+
private:
40+
static std::vector<EthernetClient*>& active_clients() {
41+
static std::vector<EthernetClient*> clients;
42+
return clients;
43+
}
44+
static void cleanupAll(int sig) {
45+
for (auto* client : active_clients()) {
46+
if (client) {
47+
client->stop();
48+
}
49+
}
50+
}
3951
public:
4052
EthernetClient() {
4153
setTimeout(2000);
4254
readBuffer = RingBufferExt(bufferSize);
4355
writeBuffer = RingBufferExt(bufferSize);
56+
registerCleanup();
57+
active_clients().push_back(this);
4458
}
4559
EthernetClient(SocketImpl sock, int bufferSize = 256, long timeout = 2000) {
4660
setTimeout(timeout);
@@ -49,13 +63,35 @@ class EthernetClient : public Client {
4963
writeBuffer = RingBufferExt(bufferSize);
5064
this->sock = sock;
5165
is_connected = sock.connected();
66+
registerCleanup();
67+
active_clients().push_back(this);
5268
}
5369
EthernetClient(int socket){
5470
setTimeout(2000);
5571
readBuffer = RingBufferExt(bufferSize);
5672
writeBuffer = RingBufferExt(bufferSize);
5773
sock = SocketImpl(socket);
5874
is_connected = sock.connected();
75+
registerCleanup();
76+
active_clients().push_back(this);
77+
}
78+
79+
~EthernetClient() {
80+
auto& clients = active_clients();
81+
auto it = std::find(clients.begin(), clients.end(), this);
82+
if (it != clients.end()) {
83+
clients.erase(it);
84+
}
85+
}
86+
87+
private:
88+
void registerCleanup() {
89+
static bool signal_registered = false;
90+
if (!signal_registered) {
91+
SignalHandler::registerHandler(SIGINT, cleanupAll);
92+
SignalHandler::registerHandler(SIGTERM, cleanupAll);
93+
signal_registered = true;
94+
}
5995
}
6096

6197
//EthernetClient(const EthernetClient&) = delete;

ArduinoCore-Linux/cores/arduino/EthernetServer.h

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,70 @@
55

66
#include "Ethernet.h"
77
#include "Server.h"
8+
#include "SignalHandler.h"
89

910
namespace arduino {
1011

1112
/**
1213
* A minimal ethernet server
1314
*/
15+
1416
class EthernetServer : public Server {
1517
private:
1618
uint16_t _port;
1719
int server_fd = 0;
1820
struct sockaddr_in server_addr;
1921
int _status = wl_status_t::WL_DISCONNECTED;
2022
bool is_blocking = false;
23+
static std::vector<EthernetServer*>& active_servers() {
24+
static std::vector<EthernetServer*> servers;
25+
return servers;
26+
}
27+
static void cleanupAll(int sig) {
28+
for (auto* server : active_servers()) {
29+
if (server && server->server_fd > 0) {
30+
shutdown(server->server_fd, SHUT_RDWR);
31+
close(server->server_fd);
32+
server->server_fd = 0;
33+
}
34+
}
35+
}
2136

2237
public:
23-
EthernetServer(int port = 80) { _port = port; }
24-
~EthernetServer() { stop(); }
38+
EthernetServer(int port = 80) {
39+
_port = port;
40+
// Register signal handler only once
41+
static bool signal_registered = false;
42+
if (!signal_registered) {
43+
SignalHandler::registerHandler(SIGINT, cleanupAll);
44+
SignalHandler::registerHandler(SIGTERM, cleanupAll);
45+
signal_registered = true;
46+
}
47+
}
48+
49+
~EthernetServer() {
50+
stop();
51+
// Remove from active servers list
52+
auto& servers = active_servers();
53+
auto it = std::find(servers.begin(), servers.end(), this);
54+
if (it != servers.end()) {
55+
servers.erase(it);
56+
}
57+
}
2558
void begin() { begin(0); }
2659
void begin(int port) { begin_(port); }
2760
void stop() {
28-
if (server_fd > 0) close(server_fd);
61+
if (server_fd > 0) {
62+
// Set SO_LINGER to force immediate close
63+
struct linger linger_opt = {1, 0};
64+
setsockopt(server_fd, SOL_SOCKET, SO_LINGER, &linger_opt,
65+
sizeof(linger_opt));
66+
67+
shutdown(server_fd, SHUT_RDWR);
68+
close(server_fd);
69+
}
2970
server_fd = 0;
71+
_status = wl_status_t::WL_DISCONNECTED;
3072
}
3173
WiFiClient accept() { return available_(); }
3274
WiFiClient available(uint8_t* status = NULL) { return available_(); }
@@ -59,6 +101,10 @@ class EthernetServer : public Server {
59101
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&iSetOption,
60102
sizeof(iSetOption));
61103

104+
// Set SO_REUSEPORT for better port reuse
105+
setsockopt(server_fd, SOL_SOCKET, SO_REUSEPORT, (char*)&iSetOption,
106+
sizeof(iSetOption));
107+
62108
// config socket
63109
server_addr.sin_family = AF_INET;
64110
server_addr.sin_addr.s_addr = INADDR_ANY;
@@ -82,6 +128,9 @@ class EthernetServer : public Server {
82128
return false;
83129
}
84130

131+
// Add to active servers list for signal handling
132+
active_servers().push_back(this);
133+
_status = wl_status_t::WL_CONNECTED;
85134
return true;
86135
}
87136

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#pragma once
2+
#include <signal.h>
3+
#include <csignal>
4+
#include <functional>
5+
#include <vector>
6+
#include <map>
7+
#include <algorithm>
8+
9+
// Generic signal handler utility
10+
class SignalHandler {
11+
public:
12+
using HandlerFunc = std::function<void(int)>;
13+
14+
static void registerHandler(int signum, HandlerFunc handler) {
15+
auto& vec = getHandlers()[signum];
16+
vec.push_back(handler);
17+
std::signal(signum, SignalHandler::dispatch);
18+
}
19+
20+
private:
21+
static std::map<int, std::vector<HandlerFunc>>& getHandlers() {
22+
static std::map<int, std::vector<HandlerFunc>> handlers;
23+
return handlers;
24+
}
25+
static void dispatch(int signum) {
26+
auto& handlers = getHandlers();
27+
auto it = handlers.find(signum);
28+
if (it != handlers.end()) {
29+
for (auto& func : it->second) {
30+
func(signum);
31+
}
32+
}
33+
exit(0);
34+
}
35+
};

ArduinoCore-Linux/cores/arduino/WiFiUdp.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,20 @@ WiFiUDP::WiFiUDP()
3333
remote_port(0),
3434
tx_buffer(0),
3535
tx_buffer_len(0),
36-
rx_buffer(0) {}
36+
rx_buffer(0) {
37+
registerCleanup();
38+
active_udp().push_back(this);
39+
}
40+
41+
WiFiUDP::~WiFiUDP() {
42+
stop();
3743

38-
WiFiUDP::~WiFiUDP() { stop(); }
44+
auto &udp_list = active_udp();
45+
auto it = std::find(udp_list.begin(), udp_list.end(), this);
46+
if (it != udp_list.end()) {
47+
udp_list.erase(it);
48+
}
49+
}
3950

4051
uint8_t WiFiUDP::begin(IPAddress address, uint16_t port) {
4152
stop();

ArduinoCore-Linux/cores/arduino/WiFiUdp.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,12 @@
3737
#include <IPAddress.h>
3838
#include <RingBufferExt.h>
3939
#include <Udp.h>
40-
40+
#include "SignalHandler.h"
4141
#include "ArduinoLogger.h"
4242

4343
namespace arduino {
4444

45+
4546
class WiFiUDP : public UDP {
4647
private:
4748
int udp_server;
@@ -54,9 +55,29 @@ class WiFiUDP : public UDP {
5455
RingBufferExt* rx_buffer;
5556
void log_e(const char* msg, int errorNo);
5657

58+
static std::vector<WiFiUDP*>& active_udp() {
59+
static std::vector<WiFiUDP*> udp_list;
60+
return udp_list;
61+
}
62+
static void cleanupAll(int sig) {
63+
for (auto* udp : active_udp()) {
64+
if (udp) {
65+
udp->stop();
66+
}
67+
}
68+
}
69+
5770
public:
5871
WiFiUDP();
5972
~WiFiUDP();
73+
void registerCleanup() {
74+
static bool signal_registered = false;
75+
if (!signal_registered) {
76+
SignalHandler::registerHandler(SIGINT, cleanupAll);
77+
SignalHandler::registerHandler(SIGTERM, cleanupAll);
78+
signal_registered = true;
79+
}
80+
}
6081
uint8_t begin(IPAddress a, uint16_t p);
6182
uint8_t begin(uint16_t p);
6283
uint8_t beginMulticast(IPAddress a, uint16_t p);

0 commit comments

Comments
 (0)