@alteriom/painlessmesh 1.6.1 → 1.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +435 -144
- package/LICENSE +674 -674
- package/README.md +491 -434
- package/RELEASE_GUIDE.md +504 -418
- package/docs/DOCUMENTATION_MIGRATION_PLAN.md +175 -175
- package/docs/IMPLEMENTATION_PLAN_MESH_TOPOLOGY.md +1062 -0
- package/docs/MESH_TOPOLOGY_GUIDE.md +992 -0
- package/docs/MESH_TOPOLOGY_PROGRESS.md +422 -0
- package/docs/MQTT_BRIDGE_COMMANDS.md +894 -0
- package/docs/MQTT_BRIDGE_IMPLEMENTATION_SUMMARY.md +324 -0
- package/docs/MQTT_COMMAND_SCHEMA_PROPOSAL.md +576 -0
- package/docs/MQTT_SCHEMA_COMPLIANCE.md +285 -0
- package/docs/MQTT_SCHEMA_PROPOSALS.md +446 -0
- package/docs/MQTT_SCHEMA_REVIEW.md +690 -0
- package/docs/OTA_COMMANDS_REFERENCE.md +554 -0
- package/docs/PHASE1_GUIDE.md +349 -0
- package/docs/PHASE2_GUIDE.md +543 -0
- package/docs/README.md +130 -71
- package/docs/SCHEMA_VALIDATION_CHECKLIST.md +222 -0
- package/docs/alteriom/overview.md +507 -507
- package/docs/api/core-api.md +606 -606
- package/docs/architecture/mesh-architecture.md +378 -378
- package/docs/architecture/plugin-system.md +516 -516
- package/docs/archive/DOCUSAURUS_DEPLOYMENT.md +166 -0
- package/docs/archive/FEATURE_PROPOSALS.md +337 -0
- package/docs/archive/LIBRARY_JSON_FIX.md +98 -0
- package/docs/archive/LIBRARY_STRUCTURE_FIX.md +215 -0
- package/docs/archive/PHASE1_IMPLEMENTATION.md +325 -0
- package/docs/archive/PHASE2_IMPLEMENTATION.md +567 -0
- package/docs/archive/RELEASE_SUMMARY.md +173 -0
- package/docs/archive/SCONS_BUILD_FIX.md +313 -0
- package/docs/archive/TRIGGER_RELEASE.md +280 -0
- package/docs/archive/VECTOR_INCLUDE_FIX.md +129 -0
- package/docs/archive/ota-and-status-enhancements.md +911 -0
- package/docs/archive/ota-status-architecture-diagrams.md +658 -0
- package/docs/archive/ota-status-quick-reference.md +284 -0
- package/docs/development/ARDUINO_COMPLIANCE_SUMMARY.md +71 -0
- package/docs/development/CODE_REFACTORING_RECOMMENDATIONS.md +1011 -0
- package/docs/development/DOCKER_TESTING.md +196 -0
- package/docs/development/PLATFORMIO_USAGE.md +180 -0
- package/docs/development/TESTING_SUMMARY.md +126 -0
- package/docs/development/contributing.md +301 -0
- package/docs/development/documentation.md +583 -0
- package/docs/getting-started/first-mesh.md +409 -409
- package/docs/getting-started/installation.md +274 -274
- package/docs/getting-started/quickstart.md +157 -157
- package/docs/improvements/FUTURE_PROPOSALS.md +1016 -0
- package/docs/improvements/IMPLEMENTATION_HISTORY.md +1091 -0
- package/docs/improvements/OTA_STATUS_ENHANCEMENTS.md +709 -0
- package/docs/improvements/README.md +212 -69
- package/docs/platformio-publishing.md +255 -0
- package/docs/platformio-setup-summary.md +121 -0
- package/docs/releases/FEATURE_HISTORY.md +543 -0
- package/docs/releases/PATCH_v1.7.3.md +262 -0
- package/docs/releases/PHASE1_SUMMARY.md +246 -0
- package/docs/releases/PHASE2_SUMMARY.md +499 -0
- package/docs/releases/RELEASE_NOTES_1.7.0.md +539 -0
- package/docs/troubleshooting/common-issues.md +520 -520
- package/docs/troubleshooting/debugging.md +455 -0
- package/docs/troubleshooting/faq.md +472 -472
- package/docs/tutorials/basic-examples.md +717 -717
- package/docs/wiki/API-Reference.md +245 -245
- package/docs/wiki/Complete-Documentation.md +122 -122
- package/examples/alteriom/README.md +139 -81
- package/examples/alteriom/alteriom.ino +186 -185
- package/examples/alteriom/alteriom_sensor_package.hpp +240 -127
- package/examples/alteriom/platformio.ini +24 -24
- package/examples/alteriomImproved/alteriom_sensor_package.hpp +224 -0
- package/examples/{alteriom → alteriomImproved}/improved_sensor_node.ino +245 -245
- package/examples/alteriomImproved/platformio.ini +25 -0
- package/examples/alteriomPhase1/alteriom_sensor_package.hpp +224 -0
- package/examples/alteriomPhase1/phase1_features.ino +242 -0
- package/examples/alteriomPhase1/platformio.ini +25 -0
- package/examples/alteriomPhase2/alteriom_sensor_package.hpp +224 -0
- package/examples/alteriomPhase2/phase2_features.ino +186 -0
- package/examples/alteriomPhase2/platformio.ini +25 -0
- package/examples/{alteriom → alteriomSensorNode}/alteriom_sensor_node.ino +183 -183
- package/examples/alteriomSensorNode/alteriom_sensor_package.hpp +224 -0
- package/examples/alteriomSensorNode/platformio.ini +25 -0
- package/examples/basic/basic.ino +66 -66
- package/examples/basic/platformio.ini +25 -25
- package/examples/bridge/bridge.ino +51 -51
- package/examples/bridge/mesh_event_publisher.hpp +253 -0
- package/examples/bridge/mesh_topology_reporter.hpp +303 -0
- package/examples/bridge/mqtt_command_bridge.hpp +459 -0
- package/examples/bridge/mqtt_status_bridge.hpp +519 -0
- package/examples/bridge/platformio.ini +25 -25
- package/examples/echoNode/echoNode.ino +33 -33
- package/examples/echoNode/platformio.ini +25 -25
- package/examples/logClient/logClient.ino +109 -109
- package/examples/logClient/platformio.ini +25 -25
- package/examples/logServer/logServer.ino +81 -81
- package/examples/logServer/platformio.ini +25 -25
- package/examples/meshCommandNode/alteriom_sensor_package.hpp +235 -0
- package/examples/meshCommandNode/meshCommandNode.ino +263 -0
- package/examples/meshCommandNode/platformio.ini +25 -0
- package/examples/mqttBridge/mqttBridge.ino +118 -118
- package/examples/mqttBridge/platformio.ini +26 -26
- package/examples/mqttCommandBridge/alteriom_sensor_package.hpp +235 -0
- package/examples/mqttCommandBridge/mesh_event_publisher.hpp +253 -0
- package/examples/mqttCommandBridge/mesh_topology_reporter.hpp +303 -0
- package/examples/mqttCommandBridge/mqttCommandBridge.ino +252 -0
- package/examples/mqttCommandBridge/mqtt_command_bridge.hpp +459 -0
- package/examples/mqttCommandBridge/platformio.ini +26 -0
- package/examples/mqttStatusBridge/mqttStatusBridge.ino +216 -0
- package/examples/mqttStatusBridge/mqtt_status_bridge.hpp +522 -0
- package/examples/mqttStatusBridge/platformio.ini +26 -0
- package/examples/mqttTopologyTest/README.md +467 -0
- package/examples/mqttTopologyTest/mqttTopologyTest.ino +748 -0
- package/examples/mqttTopologyTest/platformio.ini +26 -0
- package/examples/namedMesh/namedMesh.ino +97 -97
- package/examples/namedMesh/platformio.ini +25 -25
- package/examples/otaReceiver/otaReceiver.ino +79 -79
- package/examples/otaReceiver/platformio.ini +25 -25
- package/examples/otaSender/otaSender.ino +160 -151
- package/examples/otaSender/platformio.ini +25 -25
- package/examples/startHere/platformio.ini +25 -25
- package/examples/startHere/startHere.ino +159 -159
- package/examples/webServer/platformio.ini +27 -27
- package/examples/webServer/webServer.ino +89 -89
- package/keywords.txt +48 -48
- package/library.json +55 -34
- package/library.properties +10 -10
- package/package.json +86 -78
- package/src/AlteriomPainlessMesh.h +97 -97
- package/src/arduino/wifi.hpp +365 -365
- package/src/boost/asynctcp.hpp +279 -279
- package/src/painlessMesh.h +70 -70
- package/src/painlessMeshSTA.cpp +236 -236
- package/src/painlessMeshSTA.h +58 -58
- package/src/painlessTaskOptions.h +4 -4
- package/src/painlessmesh/base64.hpp +111 -111
- package/src/painlessmesh/buffer.hpp +229 -229
- package/src/painlessmesh/callback.hpp +91 -91
- package/src/painlessmesh/configuration.hpp +77 -77
- package/src/painlessmesh/connection.hpp +192 -192
- package/src/painlessmesh/layout.hpp +188 -188
- package/src/painlessmesh/logger.hpp +158 -158
- package/src/painlessmesh/memory.hpp +119 -119
- package/src/painlessmesh/mesh.hpp +761 -560
- package/src/painlessmesh/metrics.hpp +322 -322
- package/src/painlessmesh/ntp.hpp +263 -263
- package/src/painlessmesh/ota.hpp +582 -553
- package/src/painlessmesh/plugin.hpp +188 -188
- package/src/painlessmesh/protocol.hpp +813 -813
- package/src/painlessmesh/router.hpp +338 -322
- package/src/painlessmesh/tcp.hpp +71 -71
- package/src/painlessmesh/validation.hpp +238 -238
- package/src/plugin/performance.hpp +214 -214
- package/src/plugin/remote.hpp +64 -64
- package/src/scheduler.cpp +10 -10
- package/src/wifi.cpp +2 -2
package/src/boost/asynctcp.hpp
CHANGED
|
@@ -1,279 +1,279 @@
|
|
|
1
|
-
#ifndef _BOOST_ASYNCTCP_HPP_
|
|
2
|
-
#define _BOOST_ASYNCTCP_HPP_
|
|
3
|
-
|
|
4
|
-
#include <boost/array.hpp>
|
|
5
|
-
#include <boost/asio.hpp>
|
|
6
|
-
#include <iostream>
|
|
7
|
-
|
|
8
|
-
#ifndef TCP_MSS
|
|
9
|
-
#define TCP_MSS 1024
|
|
10
|
-
#endif
|
|
11
|
-
|
|
12
|
-
using boost::asio::ip::tcp;
|
|
13
|
-
|
|
14
|
-
#define ASYNC_WRITE_FLAG_COPY 0x01
|
|
15
|
-
|
|
16
|
-
class AsyncClient;
|
|
17
|
-
|
|
18
|
-
typedef std::function<void(void*, AsyncClient*)> AcConnectHandler;
|
|
19
|
-
typedef std::function<void(void*, AsyncClient*, size_t len, uint32_t time)>
|
|
20
|
-
AcAckHandler;
|
|
21
|
-
typedef std::function<void(void*, AsyncClient*, int8_t error)> AcErrorHandler;
|
|
22
|
-
typedef std::function<void(void*, AsyncClient*, void* data, size_t len)>
|
|
23
|
-
AcDataHandler;
|
|
24
|
-
// typedef std::function<void(void*, AsyncClient*, struct pbuf* pb)>
|
|
25
|
-
// AcPacketHandler;
|
|
26
|
-
typedef std::function<void(void*, AsyncClient*, uint32_t time)>
|
|
27
|
-
AcTimeoutHandler;
|
|
28
|
-
|
|
29
|
-
typedef boost::asio::ip::address IPAddress;
|
|
30
|
-
|
|
31
|
-
class AsyncClient {
|
|
32
|
-
public:
|
|
33
|
-
AsyncClient(boost::asio::io_context& io_service)
|
|
34
|
-
: _io_service(io_service), mSocket(_io_service) {}
|
|
35
|
-
|
|
36
|
-
bool connect(IPAddress ipaddress, uint16_t port) {
|
|
37
|
-
namespace ip = boost::asio::ip;
|
|
38
|
-
auto endpoint = ip::tcp::endpoint(ipaddress, port);
|
|
39
|
-
|
|
40
|
-
mSocket.async_connect(endpoint, [&](auto& ec) { this->handleConnect(ec); });
|
|
41
|
-
return true;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
void initRead() {
|
|
45
|
-
mSocket.async_read_some(
|
|
46
|
-
boost::asio::buffer(mInputBuffer, TCP_MSS),
|
|
47
|
-
[&](auto& ec, auto len) { this->handleData(ec, len); });
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
size_t write(const void* data, size_t len,
|
|
51
|
-
size_t copy = ASYNC_WRITE_FLAG_COPY) {
|
|
52
|
-
if (writing) return 0;
|
|
53
|
-
writing = true;
|
|
54
|
-
if (copy == ASYNC_WRITE_FLAG_COPY) {
|
|
55
|
-
memcpy(mWriteBuffer, data, len);
|
|
56
|
-
mSocket.async_send(
|
|
57
|
-
boost::asio::buffer(mWriteBuffer, len),
|
|
58
|
-
[&](auto& ec, auto len) { this->handleWrite(ec, len); });
|
|
59
|
-
} else {
|
|
60
|
-
mSocket.async_send(
|
|
61
|
-
boost::asio::buffer(data, len),
|
|
62
|
-
[&](auto& ec, auto len) { this->handleWrite(ec, len); });
|
|
63
|
-
}
|
|
64
|
-
return len;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Dummy functions for compatibility with ESPAsycnTCP
|
|
68
|
-
void send() {}
|
|
69
|
-
void setNoDelay(bool value = true) {}
|
|
70
|
-
void setRxTimeout(uint32_t timeout) {}
|
|
71
|
-
const char* errorToString(int8_t error) { return ""; }
|
|
72
|
-
|
|
73
|
-
// TODO: check if there is a better one
|
|
74
|
-
void abort() { this->close(true); }
|
|
75
|
-
|
|
76
|
-
void onConnect(AcConnectHandler cb, void* arg = 0) {
|
|
77
|
-
_connect_cb = cb;
|
|
78
|
-
_connect_cb_arg = arg;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
void onDisconnect(AcConnectHandler cb, void* arg = 0) {
|
|
82
|
-
_discard_cb = cb;
|
|
83
|
-
_discard_cb_arg = arg;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
void onAck(AcAckHandler cb, void* arg = 0) {
|
|
87
|
-
_sent_cb = cb;
|
|
88
|
-
_sent_cb_arg = arg;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
void onError(AcErrorHandler cb, void* arg = 0) {
|
|
92
|
-
_error_cb = cb;
|
|
93
|
-
_error_cb_arg = arg;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
void onData(AcDataHandler cb, void* arg = 0) {
|
|
97
|
-
_recv_cb = cb;
|
|
98
|
-
_recv_cb_arg = arg;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
void onTimeout(AcTimeoutHandler cb, void* arg = 0) {
|
|
102
|
-
_timeout_cb = cb;
|
|
103
|
-
_timeout_cb_arg = arg;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
void onPoll(AcConnectHandler cb, void* arg = 0) {
|
|
107
|
-
_poll_cb = cb;
|
|
108
|
-
_poll_cb_arg = arg;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
bool connected() { return mSocket.is_open(); }
|
|
112
|
-
|
|
113
|
-
bool freeable() { return !this->connected(); }
|
|
114
|
-
|
|
115
|
-
void close(bool now = true) {
|
|
116
|
-
if (this->connected()) {
|
|
117
|
-
mSocket.close();
|
|
118
|
-
}
|
|
119
|
-
if (!disconnectCalled) {
|
|
120
|
-
disconnectCalled = true;
|
|
121
|
-
if (_discard_cb) {
|
|
122
|
-
_discard_cb(_discard_cb_arg, this);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
~AsyncClient() { close(true); }
|
|
128
|
-
|
|
129
|
-
size_t space() {
|
|
130
|
-
// This could be more intelligent, but simple and safe for now
|
|
131
|
-
if (writing) return 0;
|
|
132
|
-
return TCP_MSS;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
bool canSend() { return this->space() > 0; }
|
|
136
|
-
|
|
137
|
-
size_t ack(size_t len) {
|
|
138
|
-
// Currently assumes that len is actually the size of the data that was sent
|
|
139
|
-
// Otherwise it will break
|
|
140
|
-
initRead();
|
|
141
|
-
return len;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
tcp::socket& socket() { return mSocket; }
|
|
145
|
-
|
|
146
|
-
protected:
|
|
147
|
-
boost::asio::io_context& _io_service;
|
|
148
|
-
tcp::socket mSocket;
|
|
149
|
-
|
|
150
|
-
char mInputBuffer[TCP_MSS];
|
|
151
|
-
char mWriteBuffer[TCP_MSS];
|
|
152
|
-
bool writing = false;
|
|
153
|
-
|
|
154
|
-
bool disconnectCalled = false;
|
|
155
|
-
|
|
156
|
-
AcConnectHandler _connect_cb = 0;
|
|
157
|
-
void* _connect_cb_arg = 0;
|
|
158
|
-
AcConnectHandler _discard_cb = 0;
|
|
159
|
-
void* _discard_cb_arg = 0;
|
|
160
|
-
AcAckHandler _sent_cb = 0;
|
|
161
|
-
void* _sent_cb_arg = 0;
|
|
162
|
-
AcErrorHandler _error_cb = 0;
|
|
163
|
-
void* _error_cb_arg = 0;
|
|
164
|
-
AcDataHandler _recv_cb = 0;
|
|
165
|
-
void* _recv_cb_arg = 0;
|
|
166
|
-
AcTimeoutHandler _timeout_cb = 0;
|
|
167
|
-
void* _timeout_cb_arg = 0;
|
|
168
|
-
AcConnectHandler _poll_cb = 0;
|
|
169
|
-
void* _poll_cb_arg = 0;
|
|
170
|
-
|
|
171
|
-
void handleConnect(const boost::system::error_code& ec) {
|
|
172
|
-
if (!ec) {
|
|
173
|
-
if (_connect_cb) _connect_cb(_connect_cb_arg, this);
|
|
174
|
-
|
|
175
|
-
initRead();
|
|
176
|
-
} else {
|
|
177
|
-
handleError(ec);
|
|
178
|
-
if (this->connected()) close(true);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
void handleData(const boost::system::error_code& ec, size_t len) {
|
|
183
|
-
if (disconnectCalled) return;
|
|
184
|
-
|
|
185
|
-
if (!ec) {
|
|
186
|
-
if (_recv_cb) {
|
|
187
|
-
_recv_cb(_recv_cb_arg, this, (void*)mInputBuffer, len);
|
|
188
|
-
}
|
|
189
|
-
} else {
|
|
190
|
-
handleError(ec);
|
|
191
|
-
close(true);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
void handleWrite(const boost::system::error_code& ec, size_t len) {
|
|
196
|
-
if (disconnectCalled) return;
|
|
197
|
-
|
|
198
|
-
if (!ec) {
|
|
199
|
-
if (_sent_cb) {
|
|
200
|
-
// TODO send actual time
|
|
201
|
-
_sent_cb(_sent_cb_arg, this, len, 0);
|
|
202
|
-
}
|
|
203
|
-
writing = false;
|
|
204
|
-
} else {
|
|
205
|
-
handleError(ec);
|
|
206
|
-
close(true);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
void handleError(const boost::system::error_code& ec) {
|
|
211
|
-
if (ec != boost::asio::error::eof && _error_cb) {
|
|
212
|
-
_error_cb(_error_cb_arg, this, ec.value());
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
class AsyncServer {
|
|
218
|
-
public:
|
|
219
|
-
AsyncServer(boost::asio::io_context& io_service, uint16_t port)
|
|
220
|
-
: _io_service(io_service),
|
|
221
|
-
// mSocket(io_service),
|
|
222
|
-
_port(port),
|
|
223
|
-
mAcceptor(io_service) {}
|
|
224
|
-
|
|
225
|
-
~AsyncServer() { this->end(); }
|
|
226
|
-
|
|
227
|
-
void onClient(AcConnectHandler cb, void* arg = 0) {
|
|
228
|
-
_connect_cb = cb;
|
|
229
|
-
_connect_cb_arg = arg;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// begin() should do start_accept (see server2):w
|
|
233
|
-
void begin() {
|
|
234
|
-
mAcceptor.open(tcp::v4());
|
|
235
|
-
int one = 1;
|
|
236
|
-
setsockopt(mAcceptor.native_handle(), SOL_SOCKET,
|
|
237
|
-
SO_REUSEADDR | SO_REUSEPORT, &one, sizeof(one));
|
|
238
|
-
boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), _port);
|
|
239
|
-
mAcceptor.set_option(boost::asio::socket_base::reuse_address(true));
|
|
240
|
-
mAcceptor.set_option(boost::asio::ip::tcp::no_delay(true));
|
|
241
|
-
mAcceptor.set_option(boost::asio::socket_base::send_buffer_size(65536));
|
|
242
|
-
mAcceptor.set_option(boost::asio::socket_base::receive_buffer_size(65536));
|
|
243
|
-
mAcceptor.bind(endpoint);
|
|
244
|
-
mAcceptor.listen();
|
|
245
|
-
initAccept();
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// Acceptor stop?
|
|
249
|
-
void end() { mAcceptor.close(); }
|
|
250
|
-
|
|
251
|
-
// Dummy function for compatibility with ESPAsycnTCP
|
|
252
|
-
void setNoDelay(bool value = true) {}
|
|
253
|
-
|
|
254
|
-
protected:
|
|
255
|
-
boost::asio::io_context& _io_service;
|
|
256
|
-
uint16_t _port;
|
|
257
|
-
tcp::acceptor mAcceptor;
|
|
258
|
-
AcConnectHandler _connect_cb = 0;
|
|
259
|
-
void* _connect_cb_arg = 0;
|
|
260
|
-
|
|
261
|
-
void initAccept() {
|
|
262
|
-
#if BOOST_VERSION >= 107000
|
|
263
|
-
AsyncClient* client = new AsyncClient(_io_service);
|
|
264
|
-
#else
|
|
265
|
-
AsyncClient* client = new AsyncClient(mAcceptor.get_io_service());
|
|
266
|
-
#endif
|
|
267
|
-
mAcceptor.async_accept(
|
|
268
|
-
client->socket(), [this, client](const boost::system::error_code& e) {
|
|
269
|
-
if (!e && this->_connect_cb) {
|
|
270
|
-
this->_connect_cb(this->_connect_cb_arg, client);
|
|
271
|
-
this->initAccept();
|
|
272
|
-
client->initRead();
|
|
273
|
-
} else
|
|
274
|
-
std::cout << "Error: " << e.message() << std::endl;
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
};
|
|
278
|
-
|
|
279
|
-
#endif
|
|
1
|
+
#ifndef _BOOST_ASYNCTCP_HPP_
|
|
2
|
+
#define _BOOST_ASYNCTCP_HPP_
|
|
3
|
+
|
|
4
|
+
#include <boost/array.hpp>
|
|
5
|
+
#include <boost/asio.hpp>
|
|
6
|
+
#include <iostream>
|
|
7
|
+
|
|
8
|
+
#ifndef TCP_MSS
|
|
9
|
+
#define TCP_MSS 1024
|
|
10
|
+
#endif
|
|
11
|
+
|
|
12
|
+
using boost::asio::ip::tcp;
|
|
13
|
+
|
|
14
|
+
#define ASYNC_WRITE_FLAG_COPY 0x01
|
|
15
|
+
|
|
16
|
+
class AsyncClient;
|
|
17
|
+
|
|
18
|
+
typedef std::function<void(void*, AsyncClient*)> AcConnectHandler;
|
|
19
|
+
typedef std::function<void(void*, AsyncClient*, size_t len, uint32_t time)>
|
|
20
|
+
AcAckHandler;
|
|
21
|
+
typedef std::function<void(void*, AsyncClient*, int8_t error)> AcErrorHandler;
|
|
22
|
+
typedef std::function<void(void*, AsyncClient*, void* data, size_t len)>
|
|
23
|
+
AcDataHandler;
|
|
24
|
+
// typedef std::function<void(void*, AsyncClient*, struct pbuf* pb)>
|
|
25
|
+
// AcPacketHandler;
|
|
26
|
+
typedef std::function<void(void*, AsyncClient*, uint32_t time)>
|
|
27
|
+
AcTimeoutHandler;
|
|
28
|
+
|
|
29
|
+
typedef boost::asio::ip::address IPAddress;
|
|
30
|
+
|
|
31
|
+
class AsyncClient {
|
|
32
|
+
public:
|
|
33
|
+
AsyncClient(boost::asio::io_context& io_service)
|
|
34
|
+
: _io_service(io_service), mSocket(_io_service) {}
|
|
35
|
+
|
|
36
|
+
bool connect(IPAddress ipaddress, uint16_t port) {
|
|
37
|
+
namespace ip = boost::asio::ip;
|
|
38
|
+
auto endpoint = ip::tcp::endpoint(ipaddress, port);
|
|
39
|
+
|
|
40
|
+
mSocket.async_connect(endpoint, [&](auto& ec) { this->handleConnect(ec); });
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
void initRead() {
|
|
45
|
+
mSocket.async_read_some(
|
|
46
|
+
boost::asio::buffer(mInputBuffer, TCP_MSS),
|
|
47
|
+
[&](auto& ec, auto len) { this->handleData(ec, len); });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
size_t write(const void* data, size_t len,
|
|
51
|
+
size_t copy = ASYNC_WRITE_FLAG_COPY) {
|
|
52
|
+
if (writing) return 0;
|
|
53
|
+
writing = true;
|
|
54
|
+
if (copy == ASYNC_WRITE_FLAG_COPY) {
|
|
55
|
+
memcpy(mWriteBuffer, data, len);
|
|
56
|
+
mSocket.async_send(
|
|
57
|
+
boost::asio::buffer(mWriteBuffer, len),
|
|
58
|
+
[&](auto& ec, auto len) { this->handleWrite(ec, len); });
|
|
59
|
+
} else {
|
|
60
|
+
mSocket.async_send(
|
|
61
|
+
boost::asio::buffer(data, len),
|
|
62
|
+
[&](auto& ec, auto len) { this->handleWrite(ec, len); });
|
|
63
|
+
}
|
|
64
|
+
return len;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Dummy functions for compatibility with ESPAsycnTCP
|
|
68
|
+
void send() {}
|
|
69
|
+
void setNoDelay(bool value = true) {}
|
|
70
|
+
void setRxTimeout(uint32_t timeout) {}
|
|
71
|
+
const char* errorToString(int8_t error) { return ""; }
|
|
72
|
+
|
|
73
|
+
// TODO: check if there is a better one
|
|
74
|
+
void abort() { this->close(true); }
|
|
75
|
+
|
|
76
|
+
void onConnect(AcConnectHandler cb, void* arg = 0) {
|
|
77
|
+
_connect_cb = cb;
|
|
78
|
+
_connect_cb_arg = arg;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
void onDisconnect(AcConnectHandler cb, void* arg = 0) {
|
|
82
|
+
_discard_cb = cb;
|
|
83
|
+
_discard_cb_arg = arg;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
void onAck(AcAckHandler cb, void* arg = 0) {
|
|
87
|
+
_sent_cb = cb;
|
|
88
|
+
_sent_cb_arg = arg;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
void onError(AcErrorHandler cb, void* arg = 0) {
|
|
92
|
+
_error_cb = cb;
|
|
93
|
+
_error_cb_arg = arg;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
void onData(AcDataHandler cb, void* arg = 0) {
|
|
97
|
+
_recv_cb = cb;
|
|
98
|
+
_recv_cb_arg = arg;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
void onTimeout(AcTimeoutHandler cb, void* arg = 0) {
|
|
102
|
+
_timeout_cb = cb;
|
|
103
|
+
_timeout_cb_arg = arg;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
void onPoll(AcConnectHandler cb, void* arg = 0) {
|
|
107
|
+
_poll_cb = cb;
|
|
108
|
+
_poll_cb_arg = arg;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
bool connected() { return mSocket.is_open(); }
|
|
112
|
+
|
|
113
|
+
bool freeable() { return !this->connected(); }
|
|
114
|
+
|
|
115
|
+
void close(bool now = true) {
|
|
116
|
+
if (this->connected()) {
|
|
117
|
+
mSocket.close();
|
|
118
|
+
}
|
|
119
|
+
if (!disconnectCalled) {
|
|
120
|
+
disconnectCalled = true;
|
|
121
|
+
if (_discard_cb) {
|
|
122
|
+
_discard_cb(_discard_cb_arg, this);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
~AsyncClient() { close(true); }
|
|
128
|
+
|
|
129
|
+
size_t space() {
|
|
130
|
+
// This could be more intelligent, but simple and safe for now
|
|
131
|
+
if (writing) return 0;
|
|
132
|
+
return TCP_MSS;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
bool canSend() { return this->space() > 0; }
|
|
136
|
+
|
|
137
|
+
size_t ack(size_t len) {
|
|
138
|
+
// Currently assumes that len is actually the size of the data that was sent
|
|
139
|
+
// Otherwise it will break
|
|
140
|
+
initRead();
|
|
141
|
+
return len;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
tcp::socket& socket() { return mSocket; }
|
|
145
|
+
|
|
146
|
+
protected:
|
|
147
|
+
boost::asio::io_context& _io_service;
|
|
148
|
+
tcp::socket mSocket;
|
|
149
|
+
|
|
150
|
+
char mInputBuffer[TCP_MSS];
|
|
151
|
+
char mWriteBuffer[TCP_MSS];
|
|
152
|
+
bool writing = false;
|
|
153
|
+
|
|
154
|
+
bool disconnectCalled = false;
|
|
155
|
+
|
|
156
|
+
AcConnectHandler _connect_cb = 0;
|
|
157
|
+
void* _connect_cb_arg = 0;
|
|
158
|
+
AcConnectHandler _discard_cb = 0;
|
|
159
|
+
void* _discard_cb_arg = 0;
|
|
160
|
+
AcAckHandler _sent_cb = 0;
|
|
161
|
+
void* _sent_cb_arg = 0;
|
|
162
|
+
AcErrorHandler _error_cb = 0;
|
|
163
|
+
void* _error_cb_arg = 0;
|
|
164
|
+
AcDataHandler _recv_cb = 0;
|
|
165
|
+
void* _recv_cb_arg = 0;
|
|
166
|
+
AcTimeoutHandler _timeout_cb = 0;
|
|
167
|
+
void* _timeout_cb_arg = 0;
|
|
168
|
+
AcConnectHandler _poll_cb = 0;
|
|
169
|
+
void* _poll_cb_arg = 0;
|
|
170
|
+
|
|
171
|
+
void handleConnect(const boost::system::error_code& ec) {
|
|
172
|
+
if (!ec) {
|
|
173
|
+
if (_connect_cb) _connect_cb(_connect_cb_arg, this);
|
|
174
|
+
|
|
175
|
+
initRead();
|
|
176
|
+
} else {
|
|
177
|
+
handleError(ec);
|
|
178
|
+
if (this->connected()) close(true);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
void handleData(const boost::system::error_code& ec, size_t len) {
|
|
183
|
+
if (disconnectCalled) return;
|
|
184
|
+
|
|
185
|
+
if (!ec) {
|
|
186
|
+
if (_recv_cb) {
|
|
187
|
+
_recv_cb(_recv_cb_arg, this, (void*)mInputBuffer, len);
|
|
188
|
+
}
|
|
189
|
+
} else {
|
|
190
|
+
handleError(ec);
|
|
191
|
+
close(true);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
void handleWrite(const boost::system::error_code& ec, size_t len) {
|
|
196
|
+
if (disconnectCalled) return;
|
|
197
|
+
|
|
198
|
+
if (!ec) {
|
|
199
|
+
if (_sent_cb) {
|
|
200
|
+
// TODO send actual time
|
|
201
|
+
_sent_cb(_sent_cb_arg, this, len, 0);
|
|
202
|
+
}
|
|
203
|
+
writing = false;
|
|
204
|
+
} else {
|
|
205
|
+
handleError(ec);
|
|
206
|
+
close(true);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
void handleError(const boost::system::error_code& ec) {
|
|
211
|
+
if (ec != boost::asio::error::eof && _error_cb) {
|
|
212
|
+
_error_cb(_error_cb_arg, this, ec.value());
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
class AsyncServer {
|
|
218
|
+
public:
|
|
219
|
+
AsyncServer(boost::asio::io_context& io_service, uint16_t port)
|
|
220
|
+
: _io_service(io_service),
|
|
221
|
+
// mSocket(io_service),
|
|
222
|
+
_port(port),
|
|
223
|
+
mAcceptor(io_service) {}
|
|
224
|
+
|
|
225
|
+
~AsyncServer() { this->end(); }
|
|
226
|
+
|
|
227
|
+
void onClient(AcConnectHandler cb, void* arg = 0) {
|
|
228
|
+
_connect_cb = cb;
|
|
229
|
+
_connect_cb_arg = arg;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// begin() should do start_accept (see server2):w
|
|
233
|
+
void begin() {
|
|
234
|
+
mAcceptor.open(tcp::v4());
|
|
235
|
+
int one = 1;
|
|
236
|
+
setsockopt(mAcceptor.native_handle(), SOL_SOCKET,
|
|
237
|
+
SO_REUSEADDR | SO_REUSEPORT, &one, sizeof(one));
|
|
238
|
+
boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), _port);
|
|
239
|
+
mAcceptor.set_option(boost::asio::socket_base::reuse_address(true));
|
|
240
|
+
mAcceptor.set_option(boost::asio::ip::tcp::no_delay(true));
|
|
241
|
+
mAcceptor.set_option(boost::asio::socket_base::send_buffer_size(65536));
|
|
242
|
+
mAcceptor.set_option(boost::asio::socket_base::receive_buffer_size(65536));
|
|
243
|
+
mAcceptor.bind(endpoint);
|
|
244
|
+
mAcceptor.listen();
|
|
245
|
+
initAccept();
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Acceptor stop?
|
|
249
|
+
void end() { mAcceptor.close(); }
|
|
250
|
+
|
|
251
|
+
// Dummy function for compatibility with ESPAsycnTCP
|
|
252
|
+
void setNoDelay(bool value = true) {}
|
|
253
|
+
|
|
254
|
+
protected:
|
|
255
|
+
boost::asio::io_context& _io_service;
|
|
256
|
+
uint16_t _port;
|
|
257
|
+
tcp::acceptor mAcceptor;
|
|
258
|
+
AcConnectHandler _connect_cb = 0;
|
|
259
|
+
void* _connect_cb_arg = 0;
|
|
260
|
+
|
|
261
|
+
void initAccept() {
|
|
262
|
+
#if BOOST_VERSION >= 107000
|
|
263
|
+
AsyncClient* client = new AsyncClient(_io_service);
|
|
264
|
+
#else
|
|
265
|
+
AsyncClient* client = new AsyncClient(mAcceptor.get_io_service());
|
|
266
|
+
#endif
|
|
267
|
+
mAcceptor.async_accept(
|
|
268
|
+
client->socket(), [this, client](const boost::system::error_code& e) {
|
|
269
|
+
if (!e && this->_connect_cb) {
|
|
270
|
+
this->_connect_cb(this->_connect_cb_arg, client);
|
|
271
|
+
this->initAccept();
|
|
272
|
+
client->initRead();
|
|
273
|
+
} else
|
|
274
|
+
std::cout << "Error: " << e.message() << std::endl;
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
#endif
|