arduino-emulator
Loading...
Searching...
No Matches
EthernetServer.h
1
2/*
3 EthernetServer.h
4 Copyright (c) 2025 Phil Schatzmann. All right reserved.
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19*/
20#pragma once
21
22#include <poll.h>
23#include <unistd.h>
24
25#include "Ethernet.h"
26#include "api/Server.h"
27#include "SignalHandler.h"
28
29namespace arduino {
30
35class EthernetServer : public Server {
36 private:
37 uint16_t _port;
38 int server_fd = 0;
39 struct sockaddr_in server_addr;
40 int _status = wl_status_t::WL_DISCONNECTED;
41 bool is_blocking = false;
42 bool _noDelay = false;
43
44 static std::vector<EthernetServer*>& active_servers() {
45 static std::vector<EthernetServer*> servers;
46 return servers;
47 }
48 static void cleanupAll(int sig) {
49 for (auto* server : active_servers()) {
50 if (server && server->server_fd > 0) {
51 shutdown(server->server_fd, SHUT_RDWR);
52 close(server->server_fd);
53 server->server_fd = 0;
54 }
55 }
56 }
57
58 public:
59 EthernetServer(int port = 80) {
60 _port = port;
61 // Register signal handler only once
62 static bool signal_registered = false;
63 if (!signal_registered) {
64 SignalHandler::registerHandler(SIGINT, cleanupAll);
65 SignalHandler::registerHandler(SIGTERM, cleanupAll);
66 signal_registered = true;
67 }
68 }
69
71 stop();
72 // Remove from active servers list
73 auto& servers = active_servers();
74 auto it = std::find(servers.begin(), servers.end(), this);
75 if (it != servers.end()) {
76 servers.erase(it);
77 }
78 }
79 void begin() { begin(_port); }
80 void begin(int port) { begin_(port); }
81
82 void stop() {
83 if (server_fd > 0) {
84 // Set SO_LINGER to force immediate close
85 struct linger linger_opt = {1, 0};
87 sizeof(linger_opt));
88
89 shutdown(server_fd, SHUT_RDWR);
90 close(server_fd);
91 }
92 server_fd = 0;
93 _status = wl_status_t::WL_DISCONNECTED;
94 }
95 WiFiClient accept() { return available_(); }
96 WiFiClient available(uint8_t* status = NULL) { return available_(); }
97 virtual size_t write(uint8_t ch) { return write(&ch, 1); }
98 virtual size_t write(const uint8_t* buf, size_t size) {
99 int rc = ::write(server_fd, buf, size);
100 if (rc < 0) {
101 rc = 0;
102 }
103 return rc;
104 }
105 int status() { return _status; }
106
107 // The following are for compatibility with ESP32 WiFiServer
108 // get/setNoDelay maintain the state variable, but otherwise
109 // have no effect on the code.
110 void setNoDelay(bool nodelay) { _noDelay = nodelay; }
111 bool getNoDelay() { return _noDelay; }
112 bool hasClient() {
113 if (server_fd <= 0) return false;
114 struct pollfd pfd;
115 pfd.fd = server_fd;
116 pfd.events = POLLIN;
117 return ::poll(&pfd, 1, 0) > 0 && (pfd.revents & POLLIN);
118 }
119
120 using Print::write;
121
122 protected:
123
124 bool begin_(int port = 0) {
125 if (port > 0) _port = port;
126 _status = wl_status_t::WL_DISCONNECTED;
127
128 // create server socket
129 if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
130 // error("socket failed");
131 _status = wl_status_t::WL_CONNECT_FAILED;
132 return false;
133 }
134
135 // Reuse address after restart
136 int iSetOption = 1;
137 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&iSetOption,
138 sizeof(iSetOption));
139
140 // Set SO_REUSEPORT for better port reuse
141 setsockopt(server_fd, SOL_SOCKET, SO_REUSEPORT, (char*)&iSetOption,
142 sizeof(iSetOption));
143
144 // config socket
145 server_addr.sin_family = AF_INET;
146 server_addr.sin_addr.s_addr = INADDR_ANY;
147 server_addr.sin_port = htons(_port);
148
149 // bind socket to port
150 while (::bind(server_fd, (struct sockaddr*)&server_addr,
151 sizeof(server_addr)) < 0) {
152 // error("bind failed");
153 //_status = wl_status_t::WL_CONNECT_FAILED;
154 Logger.error("bind failed");
155 // return false;
156 delay(1000);
157 }
158
159 // listen for connections
160 if (::listen(server_fd, 10) < 0) {
161 // error("listen failed");
162 _status = wl_status_t::WL_CONNECT_FAILED;
163 Logger.error("listen failed");
164 return false;
165 }
166
167 _noDelay = false;
168
169 // Add to active servers list for signal handling
170 active_servers().push_back(this);
171 _status = wl_status_t::WL_CONNECTED;
172 return true;
173 }
174
175 void setBlocking(bool flag) { is_blocking = flag; }
176
177 EthernetClient available_() {
180 int client_fd;
181
182 if (_status == wl_status_t::WL_CONNECT_FAILED) {
183 begin(_port);
184 }
185
186 struct pollfd pfd;
187 pfd.fd = server_fd;
188 pfd.events = POLLIN;
189 int poll_rc = ::poll(&pfd, 1, 200);
190
191 // non blocking check if we have any request to accept
192 if (!is_blocking) {
193 if (poll_rc <= 0 || !(pfd.revents & POLLIN)) {
194 EthernetClient result(nullptr);
195 return result;
196 }
197 }
198
199 // accept client connection (blocking call)
200 if ((client_fd = ::accept(server_fd, (struct sockaddr*)&client_addr,
201 &client_addr_len)) < 0) {
202 EthernetClient result(nullptr);
203 Logger.error("accept failed");
204 return result;
205 }
206 std::shared_ptr<SocketImpl> sock_impl = std::make_shared<SocketImpl>(client_fd, (struct sockaddr_in*)&client_addr);
208 return result;
209 }
210};
211
212} // namespace arduino
Definition DMAPool.h:103
Definition Ethernet.h:128
Definition EthernetServer.h:35
Definition Server.h:26
We provide the WiFi class to simulate the Arduino WIFI. In in Linux we can expect that networking is ...
Definition CanMsg.cpp:31