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