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 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 using Print::write;
106
107 protected:
108
109 bool begin_(int port = 0) {
110 if (port > 0) _port = port;
111 _status = wl_status_t::WL_DISCONNECTED;
112
113 // create server socket
114 if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
115 // error("socket failed");
116 _status = wl_status_t::WL_CONNECT_FAILED;
117 return false;
118 }
119
120 // Reuse address after restart
121 int iSetOption = 1;
122 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&iSetOption,
123 sizeof(iSetOption));
124
125 // Set SO_REUSEPORT for better port reuse
126 setsockopt(server_fd, SOL_SOCKET, SO_REUSEPORT, (char*)&iSetOption,
127 sizeof(iSetOption));
128
129 // config socket
130 server_addr.sin_family = AF_INET;
131 server_addr.sin_addr.s_addr = INADDR_ANY;
132 server_addr.sin_port = htons(_port);
133
134 // bind socket to port
135 while (::bind(server_fd, (struct sockaddr*)&server_addr,
136 sizeof(server_addr)) < 0) {
137 // error("bind failed");
138 //_status = wl_status_t::WL_CONNECT_FAILED;
139 Logger.error("bind failed");
140 // return false;
141 delay(1000);
142 }
143
144 // listen for connections
145 if (::listen(server_fd, 10) < 0) {
146 // error("listen failed");
147 _status = wl_status_t::WL_CONNECT_FAILED;
148 Logger.error("listen failed");
149 return false;
150 }
151
152 // Add to active servers list for signal handling
153 active_servers().push_back(this);
154 _status = wl_status_t::WL_CONNECTED;
155 return true;
156 }
157
158 void setBlocking(bool flag) { is_blocking = flag; }
159
160 EthernetClient available_() {
163 int client_fd;
164
165 if (_status == wl_status_t::WL_CONNECT_FAILED) {
166 begin(_port);
167 }
168
169 struct pollfd pfd;
170 pfd.fd = server_fd;
171 pfd.events = POLLIN;
172 int poll_rc = ::poll(&pfd, 1, 200);
173
174 // non blocking check if we have any request to accept
175 if (!is_blocking) {
176 if (poll_rc <= 0 || !(pfd.revents & POLLIN)) {
177 EthernetClient result(nullptr);
178 return result;
179 }
180 }
181
182 // accept client connection (blocking call)
183 if ((client_fd = ::accept(server_fd, (struct sockaddr*)&client_addr,
184 &client_addr_len)) < 0) {
185 EthernetClient result(nullptr);
186 Logger.error("accept failed");
187 return result;
188 }
189 std::shared_ptr<SocketImpl> sock_impl = std::make_shared<SocketImpl>(client_fd, (struct sockaddr_in*)&client_addr);
191 return result;
192 }
193};
194
195} // 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