1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
|
/*
Asynchronous TCP library for Espressif MCUs
Copyright (c) 2016 Hristo Gochkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ASYNCTCP_H_
#define ASYNCTCP_H_
#include <async_config.h>
#include "IPAddress.h"
#include <functional>
#include <memory>
extern "C" {
#include "lwip/init.h"
#include "lwip/err.h"
#include "lwip/pbuf.h"
};
class AsyncClient;
class AsyncServer;
class ACErrorTracker;
#define ASYNC_MAX_ACK_TIME 5000
#define ASYNC_WRITE_FLAG_COPY 0x01 //will allocate new buffer to hold the data while sending (else will hold reference to the data given)
#define ASYNC_WRITE_FLAG_MORE 0x02 //will not send PSH flag, meaning that there should be more data to be sent before the application should react.
struct tcp_pcb;
struct ip_addr;
#if ASYNC_TCP_SSL_ENABLED
struct SSL_;
typedef struct SSL_ SSL;
struct SSL_CTX_;
typedef struct SSL_CTX_ SSL_CTX;
#endif
typedef std::function<void(void*, AsyncClient*)> AcConnectHandler;
typedef std::function<void(void*, AsyncClient*, size_t len, uint32_t time)> AcAckHandler;
typedef std::function<void(void*, AsyncClient*, err_t error)> AcErrorHandler;
typedef std::function<void(void*, AsyncClient*, void *data, size_t len)> AcDataHandler;
typedef std::function<void(void*, AsyncClient*, struct pbuf *pb)> AcPacketHandler;
typedef std::function<void(void*, AsyncClient*, uint32_t time)> AcTimeoutHandler;
typedef std::function<void(void*, size_t event)> AsNotifyHandler;
enum error_events {
EE_OK = 0,
EE_ABORTED, // Callback or foreground aborted connections
EE_ERROR_CB, // Stack initiated aborts via error Callbacks.
EE_CONNECTED_CB,
EE_RECV_CB,
EE_ACCEPT_CB,
EE_MAX
};
// DEBUG_MORE is for gathering more information on which CBs close events are
// occuring and count.
// #define DEBUG_MORE 1
class ACErrorTracker {
private:
AsyncClient *_client;
err_t _close_error;
int _errored;
#if DEBUG_ESP_ASYNC_TCP
size_t _connectionId;
#endif
#ifdef DEBUG_MORE
AsNotifyHandler _error_event_cb;
void* _error_event_cb_arg;
#endif
protected:
friend class AsyncClient;
friend class AsyncServer;
#ifdef DEBUG_MORE
void onErrorEvent(AsNotifyHandler cb, void *arg);
#endif
#if DEBUG_ESP_ASYNC_TCP
void setConnectionId(size_t id) { _connectionId=id;}
size_t getConnectionId(void) { return _connectionId;}
#endif
void setCloseError(err_t e);
void setErrored(size_t errorEvent);
err_t getCallbackCloseError(void);
void clearClient(void){ if (_client) _client = NULL;}
public:
err_t getCloseError(void) const { return _close_error;}
bool hasClient(void) const { return (_client != NULL);}
ACErrorTracker(AsyncClient *c);
~ACErrorTracker() {}
};
class AsyncClient {
protected:
friend class AsyncTCPbuffer;
friend class AsyncServer;
tcp_pcb* _pcb;
AcConnectHandler _connect_cb;
void* _connect_cb_arg;
AcConnectHandler _discard_cb;
void* _discard_cb_arg;
AcAckHandler _sent_cb;
void* _sent_cb_arg;
AcErrorHandler _error_cb;
void* _error_cb_arg;
AcDataHandler _recv_cb;
void* _recv_cb_arg;
AcPacketHandler _pb_cb;
void* _pb_cb_arg;
AcTimeoutHandler _timeout_cb;
void* _timeout_cb_arg;
AcConnectHandler _poll_cb;
void* _poll_cb_arg;
bool _pcb_busy;
#if ASYNC_TCP_SSL_ENABLED
bool _pcb_secure;
bool _handshake_done;
#endif
uint32_t _pcb_sent_at;
bool _close_pcb;
bool _ack_pcb;
uint32_t _tx_unacked_len;
uint32_t _tx_acked_len;
uint32_t _tx_unsent_len;
uint32_t _rx_ack_len;
uint32_t _rx_last_packet;
uint32_t _rx_since_timeout;
uint32_t _ack_timeout;
uint16_t _connect_port;
u8_t _recv_pbuf_flags;
std::shared_ptr<ACErrorTracker> _errorTracker;
void _close();
void _connected(std::shared_ptr<ACErrorTracker>& closeAbort, void* pcb, err_t err);
void _error(err_t err);
#if ASYNC_TCP_SSL_ENABLED
void _ssl_error(int8_t err);
#endif
void _poll(std::shared_ptr<ACErrorTracker>& closeAbort, tcp_pcb* pcb);
void _sent(std::shared_ptr<ACErrorTracker>& closeAbort, tcp_pcb* pcb, uint16_t len);
#if LWIP_VERSION_MAJOR == 1
void _dns_found(struct ip_addr *ipaddr);
#else
void _dns_found(const ip_addr *ipaddr);
#endif
static err_t _s_poll(void *arg, struct tcp_pcb *tpcb);
static err_t _s_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *pb, err_t err);
static void _s_error(void *arg, err_t err);
static err_t _s_sent(void *arg, struct tcp_pcb *tpcb, uint16_t len);
static err_t _s_connected(void* arg, void* tpcb, err_t err);
#if LWIP_VERSION_MAJOR == 1
static void _s_dns_found(const char *name, struct ip_addr *ipaddr, void *arg);
#else
static void _s_dns_found(const char *name, const ip_addr *ipaddr, void *arg);
#endif
#if ASYNC_TCP_SSL_ENABLED
static void _s_data(void *arg, struct tcp_pcb *tcp, uint8_t * data, size_t len);
static void _s_handshake(void *arg, struct tcp_pcb *tcp, SSL *ssl);
static void _s_ssl_error(void *arg, struct tcp_pcb *tcp, int8_t err);
#endif
std::shared_ptr<ACErrorTracker> getACErrorTracker(void) const { return _errorTracker; };
void setCloseError(err_t e) const { _errorTracker->setCloseError(e);}
public:
AsyncClient* prev;
AsyncClient* next;
#if ASYNC_TCP_SSL_ENABLED
AsyncClient(tcp_pcb* pcb = 0, SSL_CTX * ssl_ctx = NULL);
#else
AsyncClient(tcp_pcb* pcb = 0);
#endif
~AsyncClient();
AsyncClient & operator=(const AsyncClient &other);
AsyncClient & operator+=(const AsyncClient &other);
bool operator==(const AsyncClient &other);
bool operator!=(const AsyncClient &other) {
return !(*this == other);
}
#if ASYNC_TCP_SSL_ENABLED
bool connect(IPAddress ip, uint16_t port, bool secure=false);
bool connect(const char* host, uint16_t port, bool secure=false);
#else
bool connect(IPAddress ip, uint16_t port);
bool connect(const char* host, uint16_t port);
#endif
void close(bool now = false);
void stop();
void abort();
bool free();
bool canSend();//ack is not pending
size_t space();
size_t add(const char* data, size_t size, uint8_t apiflags=0);//add for sending
bool send();//send all data added with the method above
size_t ack(size_t len); //ack data that you have not acked using the method below
void ackLater(){ _ack_pcb = false; } //will not ack the current packet. Call from onData
bool isRecvPush(){ return !!(_recv_pbuf_flags & PBUF_FLAG_PUSH); }
#if DEBUG_ESP_ASYNC_TCP
size_t getConnectionId(void) const { return _errorTracker->getConnectionId();}
#endif
#if ASYNC_TCP_SSL_ENABLED
SSL *getSSL();
#endif
size_t write(const char* data);
size_t write(const char* data, size_t size, uint8_t apiflags=0); //only when canSend() == true
uint8_t state();
bool connecting();
bool connected();
bool disconnecting();
bool disconnected();
bool freeable();//disconnected or disconnecting
uint16_t getMss();
uint32_t getRxTimeout();
void setRxTimeout(uint32_t timeout);//no RX data timeout for the connection in seconds
uint32_t getAckTimeout();
void setAckTimeout(uint32_t timeout);//no ACK timeout for the last sent packet in milliseconds
void setNoDelay(bool nodelay);
bool getNoDelay();
uint32_t getRemoteAddress();
uint16_t getRemotePort();
uint32_t getLocalAddress();
uint16_t getLocalPort();
IPAddress remoteIP();
uint16_t remotePort();
IPAddress localIP();
uint16_t localPort();
void onConnect(AcConnectHandler cb, void* arg = 0); //on successful connect
void onDisconnect(AcConnectHandler cb, void* arg = 0); //disconnected
void onAck(AcAckHandler cb, void* arg = 0); //ack received
void onError(AcErrorHandler cb, void* arg = 0); //unsuccessful connect or error
void onData(AcDataHandler cb, void* arg = 0); //data received (called if onPacket is not used)
void onPacket(AcPacketHandler cb, void* arg = 0); //data received
void onTimeout(AcTimeoutHandler cb, void* arg = 0); //ack timeout
void onPoll(AcConnectHandler cb, void* arg = 0); //every 125ms when connected
void ackPacket(struct pbuf * pb);
const char * errorToString(err_t error);
const char * stateToString();
void _recv(std::shared_ptr<ACErrorTracker>& closeAbort, tcp_pcb* pcb, pbuf* pb, err_t err);
err_t getCloseError(void) const { return _errorTracker->getCloseError();}
};
#if ASYNC_TCP_SSL_ENABLED
typedef std::function<int(void* arg, const char *filename, uint8_t **buf)> AcSSlFileHandler;
struct pending_pcb;
#endif
class AsyncServer {
protected:
uint16_t _port;
IPAddress _addr;
bool _noDelay;
tcp_pcb* _pcb;
AcConnectHandler _connect_cb;
void* _connect_cb_arg;
#if ASYNC_TCP_SSL_ENABLED
struct pending_pcb * _pending;
SSL_CTX * _ssl_ctx;
AcSSlFileHandler _file_cb;
void* _file_cb_arg;
#endif
#ifdef DEBUG_MORE
int _event_count[EE_MAX];
#endif
public:
AsyncServer(IPAddress addr, uint16_t port);
AsyncServer(uint16_t port);
~AsyncServer();
void onClient(AcConnectHandler cb, void* arg);
#if ASYNC_TCP_SSL_ENABLED
void onSslFileRequest(AcSSlFileHandler cb, void* arg);
void beginSecure(const char *cert, const char *private_key_file, const char *password);
#endif
void begin();
void end();
void setNoDelay(bool nodelay);
bool getNoDelay();
uint8_t status();
#ifdef DEBUG_MORE
int getEventCount(size_t ee) const { return _event_count[ee];}
#endif
protected:
err_t _accept(tcp_pcb* newpcb, err_t err);
static err_t _s_accept(void *arg, tcp_pcb* newpcb, err_t err);
#ifdef DEBUG_MORE
int incEventCount(size_t ee) { return ++_event_count[ee];}
#endif
#if ASYNC_TCP_SSL_ENABLED
int _cert(const char *filename, uint8_t **buf);
err_t _poll(tcp_pcb* pcb);
err_t _recv(tcp_pcb *pcb, struct pbuf *pb, err_t err);
static int _s_cert(void *arg, const char *filename, uint8_t **buf);
static err_t _s_poll(void *arg, struct tcp_pcb *tpcb);
static err_t _s_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *pb, err_t err);
#endif
};
#endif /* ASYNCTCP_H_ */
|