AlteriomPainlessMesh v2.1.1
Easy ESP32/ESP8266 mesh networking with Alteriom IoT extensions
Loading...
Searching...
No Matches
asynctcp.hpp
Go to the documentation of this file.
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
12using boost::asio::ip::tcp;
13
14#define ASYNC_WRITE_FLAG_COPY 0x01
15
16class AsyncClient;
17
18typedef std::function<void(void*, AsyncClient*)> AcConnectHandler;
19typedef std::function<void(void*, AsyncClient*, size_t len, uint32_t time)>
21typedef std::function<void(void*, AsyncClient*, int8_t error)> AcErrorHandler;
22typedef std::function<void(void*, AsyncClient*, void* data, size_t len)>
24// typedef std::function<void(void*, AsyncClient*, struct pbuf* pb)>
25// AcPacketHandler;
26typedef std::function<void(void*, AsyncClient*, uint32_t time)>
28
29typedef boost::asio::ip::address IPAddress;
30
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) {
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
152 bool writing = false;
153
154 bool disconnectCalled = false;
155
161 void* _sent_cb_arg = 0;
163 void* _error_cb_arg = 0;
165 void* _recv_cb_arg = 0;
169 void* _poll_cb_arg = 0;
170
171 void handleConnect(const boost::system::error_code& ec) {
172 if (!ec) {
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
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#ifdef _WIN32
237 setsockopt(mAcceptor.native_handle(), SOL_SOCKET,
238 SO_REUSEADDR | SO_REUSEPORT, reinterpret_cast<const char*>(&one), sizeof(one));
239#else
240 setsockopt(mAcceptor.native_handle(), SOL_SOCKET,
241 SO_REUSEADDR | SO_REUSEPORT, &one, sizeof(one));
242#endif
243 boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), _port);
244 mAcceptor.set_option(boost::asio::socket_base::reuse_address(true));
245 mAcceptor.set_option(boost::asio::ip::tcp::no_delay(true));
246 mAcceptor.set_option(boost::asio::socket_base::send_buffer_size(65536));
247 mAcceptor.set_option(boost::asio::socket_base::receive_buffer_size(65536));
248 mAcceptor.bind(endpoint);
249 mAcceptor.listen();
250 initAccept();
251 }
252
253 // Acceptor stop?
254 void end() { mAcceptor.close(); }
255
256 // Dummy function for compatibility with ESPAsycnTCP
257 void setNoDelay(bool value = true) {}
258
259 protected:
260 boost::asio::io_context& _io_service;
261 uint16_t _port = 0;
262 tcp::acceptor mAcceptor;
265
266 void initAccept() {
267#if BOOST_VERSION >= 107000
268 AsyncClient* client = new AsyncClient(_io_service);
269#else
270 AsyncClient* client = new AsyncClient(mAcceptor.get_io_service());
271#endif
272 mAcceptor.async_accept(
273 client->socket(), [this, client](const boost::system::error_code& e) {
274 if (!e && this->_connect_cb) {
275 this->_connect_cb(this->_connect_cb_arg, client);
276 this->initAccept();
277 client->initRead();
278 } else
279 std::cout << "Error: " << e.message() << std::endl;
280 });
281 }
282};
283
284#endif
std::function< void(void *, AsyncClient *)> AcConnectHandler
Definition asynctcp.hpp:18
boost::asio::ip::address IPAddress
Definition asynctcp.hpp:29
std::function< void(void *, AsyncClient *, size_t len, uint32_t time)> AcAckHandler
Definition asynctcp.hpp:20
std::function< void(void *, AsyncClient *, void *data, size_t len)> AcDataHandler
Definition asynctcp.hpp:23
std::function< void(void *, AsyncClient *, uint32_t time)> AcTimeoutHandler
Definition asynctcp.hpp:27
std::function< void(void *, AsyncClient *, int8_t error)> AcErrorHandler
Definition asynctcp.hpp:21
#define ASYNC_WRITE_FLAG_COPY
Definition asynctcp.hpp:14
#define TCP_MSS
Definition asynctcp.hpp:9
Definition asynctcp.hpp:31
bool freeable()
Definition asynctcp.hpp:113
size_t space()
Definition asynctcp.hpp:129
AcDataHandler _recv_cb
Definition asynctcp.hpp:164
bool connected()
Definition asynctcp.hpp:111
tcp::socket & socket()
Definition asynctcp.hpp:144
bool disconnectCalled
Definition asynctcp.hpp:154
AcConnectHandler _connect_cb
Definition asynctcp.hpp:156
char mWriteBuffer[TCP_MSS]
Definition asynctcp.hpp:151
void handleConnect(const boost::system::error_code &ec)
Definition asynctcp.hpp:171
void onAck(AcAckHandler cb, void *arg=0)
Definition asynctcp.hpp:86
AcErrorHandler _error_cb
Definition asynctcp.hpp:162
AcAckHandler _sent_cb
Definition asynctcp.hpp:160
void abort()
Definition asynctcp.hpp:74
~AsyncClient()
Definition asynctcp.hpp:127
boost::asio::io_context & _io_service
Definition asynctcp.hpp:147
void * _recv_cb_arg
Definition asynctcp.hpp:165
void onPoll(AcConnectHandler cb, void *arg=0)
Definition asynctcp.hpp:106
void initRead()
Definition asynctcp.hpp:44
void * _poll_cb_arg
Definition asynctcp.hpp:169
size_t write(const void *data, size_t len, size_t copy=ASYNC_WRITE_FLAG_COPY)
Definition asynctcp.hpp:50
void setNoDelay(bool value=true)
Definition asynctcp.hpp:69
void onConnect(AcConnectHandler cb, void *arg=0)
Definition asynctcp.hpp:76
void handleWrite(const boost::system::error_code &ec, size_t len)
Definition asynctcp.hpp:195
bool connect(IPAddress ipaddress, uint16_t port)
Definition asynctcp.hpp:36
void onData(AcDataHandler cb, void *arg=0)
Definition asynctcp.hpp:96
void * _error_cb_arg
Definition asynctcp.hpp:163
void * _discard_cb_arg
Definition asynctcp.hpp:159
AsyncClient(boost::asio::io_context &io_service)
Definition asynctcp.hpp:33
void onTimeout(AcTimeoutHandler cb, void *arg=0)
Definition asynctcp.hpp:101
AcConnectHandler _poll_cb
Definition asynctcp.hpp:168
void handleError(const boost::system::error_code &ec)
Definition asynctcp.hpp:210
void onDisconnect(AcConnectHandler cb, void *arg=0)
Definition asynctcp.hpp:81
void setRxTimeout(uint32_t timeout)
Definition asynctcp.hpp:70
tcp::socket mSocket
Definition asynctcp.hpp:148
void handleData(const boost::system::error_code &ec, size_t len)
Definition asynctcp.hpp:182
void send()
Definition asynctcp.hpp:68
AcConnectHandler _discard_cb
Definition asynctcp.hpp:158
void close(bool now=true)
Definition asynctcp.hpp:115
void onError(AcErrorHandler cb, void *arg=0)
Definition asynctcp.hpp:91
size_t ack(size_t len)
Definition asynctcp.hpp:137
char mInputBuffer[TCP_MSS]
Definition asynctcp.hpp:150
void * _timeout_cb_arg
Definition asynctcp.hpp:167
bool writing
Definition asynctcp.hpp:152
const char * errorToString(int8_t error)
Definition asynctcp.hpp:71
bool canSend()
Definition asynctcp.hpp:135
void * _connect_cb_arg
Definition asynctcp.hpp:157
void * _sent_cb_arg
Definition asynctcp.hpp:161
AcTimeoutHandler _timeout_cb
Definition asynctcp.hpp:166
Definition asynctcp.hpp:217
boost::asio::io_context & _io_service
Definition asynctcp.hpp:260
void * _connect_cb_arg
Definition asynctcp.hpp:264
~AsyncServer()
Definition asynctcp.hpp:225
void initAccept()
Definition asynctcp.hpp:266
void setNoDelay(bool value=true)
Definition asynctcp.hpp:257
void begin()
Definition asynctcp.hpp:233
uint16_t _port
Definition asynctcp.hpp:261
void onClient(AcConnectHandler cb, void *arg=0)
Definition asynctcp.hpp:227
void end()
Definition asynctcp.hpp:254
AcConnectHandler _connect_cb
Definition asynctcp.hpp:263
AsyncServer(boost::asio::io_context &io_service, uint16_t port)
Definition asynctcp.hpp:219
tcp::acceptor mAcceptor
Definition asynctcp.hpp:262