diff --git a/lib/ESPAsyncTCP/LICENSE.txt b/lib/ESPAsyncTCP/LICENSE.txt deleted file mode 100644 index 65c5ca88a..000000000 --- a/lib/ESPAsyncTCP/LICENSE.txt +++ /dev/null @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/lib/ESPAsyncTCP/README.md b/lib/ESPAsyncTCP/README.md deleted file mode 100644 index f360005a0..000000000 --- a/lib/ESPAsyncTCP/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# ESPAsyncTCP -[![Build Status](https://travis-ci.org/me-no-dev/ESPAsyncTCP.svg?branch=master)](https://travis-ci.org/me-no-dev/ESPAsyncTCP) ![](https://github.com/me-no-dev/ESPAsyncTCP/workflows/ESP%20Async%20TCP%20CI/badge.svg) - -A fork of the [AsyncTCP](https://github.com/me-no-dev/AsyncTCP) library by [@me-no-dev](https://github.com/me-no-dev) for [ESPHome](https://esphome.io). - -### Async TCP Library for ESP8266 Arduino - -For ESP32 look [HERE](https://github.com/me-no-dev/AsyncTCP) - -[![Join the chat at https://gitter.im/me-no-dev/ESPAsyncWebServer](https://badges.gitter.im/me-no-dev/ESPAsyncWebServer.svg)](https://gitter.im/me-no-dev/ESPAsyncWebServer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - -This is a fully asynchronous TCP library, aimed at enabling trouble-free, multi-connection network environment for Espressif's ESP8266 MCUs. - -This library is the base for [ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer) - -## AsyncClient and AsyncServer -The base classes on which everything else is built. They expose all possible scenarios, but are really raw and require more skills to use. - -## AsyncPrinter -This class can be used to send data like any other ```Print``` interface (```Serial``` for example). -The object then can be used outside of the Async callbacks (the loop) and receive asynchronously data using ```onData```. The object can be checked if the underlying ```AsyncClient```is connected, or hook to the ```onDisconnect``` callback. - -## AsyncTCPbuffer -This class is really similar to the ```AsyncPrinter```, but it differs in the fact that it can buffer some of the incoming data. - -## SyncClient -It is exactly what it sounds like. This is a standard, blocking TCP Client, similar to the one included in ```ESP8266WiFi``` - -## Libraries and projects that use AsyncTCP -- [ESP Async Web Server](https://github.com/me-no-dev/ESPAsyncWebServer) -- [Async MQTT client](https://github.com/marvinroger/async-mqtt-client) -- [arduinoWebSockets](https://github.com/Links2004/arduinoWebSockets) -- [ESP8266 Smart Home](https://github.com/baruch/esp8266_smart_home) -- [KBox Firmware](https://github.com/sarfata/kbox-firmware) diff --git a/lib/ESPAsyncTCP/src/AsyncPrinter.cpp b/lib/ESPAsyncTCP/src/AsyncPrinter.cpp deleted file mode 100644 index 8a63f2051..000000000 --- a/lib/ESPAsyncTCP/src/AsyncPrinter.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* - 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 -*/ - -#include "AsyncPrinter.h" - -AsyncPrinter::AsyncPrinter() - : _client(NULL) - , _data_cb(NULL) - , _data_arg(NULL) - , _close_cb(NULL) - , _close_arg(NULL) - , _tx_buffer(NULL) - , _tx_buffer_size(TCP_MSS) - , next(NULL) -{} - -AsyncPrinter::AsyncPrinter(AsyncClient *client, size_t txBufLen) - : _client(client) - , _data_cb(NULL) - , _data_arg(NULL) - , _close_cb(NULL) - , _close_arg(NULL) - , _tx_buffer(NULL) - , _tx_buffer_size(txBufLen) - , next(NULL) -{ - _attachCallbacks(); - _tx_buffer = new (std::nothrow) cbuf(_tx_buffer_size); - if(_tx_buffer == NULL) { - panic(); //What should we do? - } -} - -AsyncPrinter::~AsyncPrinter(){ - _on_close(); -} - -void AsyncPrinter::onData(ApDataHandler cb, void *arg){ - _data_cb = cb; - _data_arg = arg; -} - -void AsyncPrinter::onClose(ApCloseHandler cb, void *arg){ - _close_cb = cb; - _close_arg = arg; -} - -int AsyncPrinter::connect(IPAddress ip, uint16_t port){ - if(_client != NULL && connected()) - return 0; - _client = new (std::nothrow) AsyncClient(); - if (_client == NULL) { - panic(); - } - - _client->onConnect([](void *obj, AsyncClient *c){ ((AsyncPrinter*)(obj))->_onConnect(c); }, this); - if(_client->connect(ip, port)){ - while(_client && _client->state() < 4) - delay(1); - return connected(); - } - return 0; -} - -int AsyncPrinter::connect(const char *host, uint16_t port){ - if(_client != NULL && connected()) - return 0; - _client = new (std::nothrow) AsyncClient(); - if (_client == NULL) { - panic(); - } - - _client->onConnect([](void *obj, AsyncClient *c){ ((AsyncPrinter*)(obj))->_onConnect(c); }, this); - if(_client->connect(host, port)){ - while(_client && _client->state() < 4) - delay(1); - return connected(); - } - return 0; -} - -void AsyncPrinter::_onConnect(AsyncClient *c){ - (void)c; - if(_tx_buffer != NULL){ - cbuf *b = _tx_buffer; - _tx_buffer = NULL; - delete b; - } - _tx_buffer = new (std::nothrow) cbuf(_tx_buffer_size); - if(_tx_buffer) { - panic(); - } - - _attachCallbacks(); -} - -AsyncPrinter::operator bool(){ return connected(); } - -AsyncPrinter & AsyncPrinter::operator=(const AsyncPrinter &other){ - if(_client != NULL){ - _client->close(true); - _client = NULL; - } - _tx_buffer_size = other._tx_buffer_size; - if(_tx_buffer != NULL){ - cbuf *b = _tx_buffer; - _tx_buffer = NULL; - delete b; - } - _tx_buffer = new (std::nothrow) cbuf(other._tx_buffer_size); - if(_tx_buffer == NULL) { - panic(); - } - - _client = other._client; - _attachCallbacks(); - return *this; -} - -size_t AsyncPrinter::write(uint8_t data){ - return write(&data, 1); -} - -size_t AsyncPrinter::write(const uint8_t *data, size_t len){ - if(_tx_buffer == NULL || !connected()) - return 0; - size_t toWrite = 0; - size_t toSend = len; - while(_tx_buffer->room() < toSend){ - toWrite = _tx_buffer->room(); - _tx_buffer->write((const char*)data, toWrite); - while(connected() && !_client->canSend()) - delay(0); - if(!connected()) - return 0; // or len - toSend; - _sendBuffer(); - toSend -= toWrite; - } - _tx_buffer->write((const char*)(data+(len - toSend)), toSend); - while(connected() && !_client->canSend()) delay(0); - if(!connected()) return 0; // or len - toSend; - _sendBuffer(); - return len; -} - -bool AsyncPrinter::connected(){ - return (_client != NULL && _client->connected()); -} - -void AsyncPrinter::close(){ - if(_client != NULL) - _client->close(true); -} - -size_t AsyncPrinter::_sendBuffer(){ - size_t available = _tx_buffer->available(); - if(!connected() || !_client->canSend() || available == 0) - return 0; - size_t sendable = _client->space(); - if(sendable < available) - available= sendable; - char *out = new (std::nothrow) char[available]; - if (out == NULL) { - panic(); // Connection should be aborted instead - } - - _tx_buffer->read(out, available); - size_t sent = _client->write(out, available); - delete out; - return sent; -} - -void AsyncPrinter::_onData(void *data, size_t len){ - if(_data_cb) - _data_cb(_data_arg, this, (uint8_t*)data, len); -} - -void AsyncPrinter::_on_close(){ - if(_client != NULL){ - _client = NULL; - } - if(_tx_buffer != NULL){ - cbuf *b = _tx_buffer; - _tx_buffer = NULL; - delete b; - } - if(_close_cb) - _close_cb(_close_arg, this); -} - -void AsyncPrinter::_attachCallbacks(){ - _client->onPoll([](void *obj, AsyncClient* c){ (void)c; ((AsyncPrinter*)(obj))->_sendBuffer(); }, this); - _client->onAck([](void *obj, AsyncClient* c, size_t len, uint32_t time){ (void)c; (void)len; (void)time; ((AsyncPrinter*)(obj))->_sendBuffer(); }, this); - _client->onDisconnect([](void *obj, AsyncClient* c){ ((AsyncPrinter*)(obj))->_on_close(); delete c; }, this); - _client->onData([](void *obj, AsyncClient* c, void *data, size_t len){ (void)c; ((AsyncPrinter*)(obj))->_onData(data, len); }, this); -} diff --git a/lib/ESPAsyncTCP/src/AsyncPrinter.h b/lib/ESPAsyncTCP/src/AsyncPrinter.h deleted file mode 100644 index c3ebe3a94..000000000 --- a/lib/ESPAsyncTCP/src/AsyncPrinter.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - 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 ASYNCPRINTER_H_ -#define ASYNCPRINTER_H_ - -#include "Arduino.h" -#include "ESPAsyncTCP.h" -#include "cbuf.h" - -class AsyncPrinter; - -typedef std::function ApDataHandler; -typedef std::function ApCloseHandler; - -class AsyncPrinter: public Print { - private: - AsyncClient *_client; - ApDataHandler _data_cb; - void *_data_arg; - ApCloseHandler _close_cb; - void *_close_arg; - cbuf *_tx_buffer; - size_t _tx_buffer_size; - - void _onConnect(AsyncClient *c); - public: - AsyncPrinter *next; - - AsyncPrinter(); - AsyncPrinter(AsyncClient *client, size_t txBufLen = TCP_MSS); - virtual ~AsyncPrinter(); - - int connect(IPAddress ip, uint16_t port); - int connect(const char *host, uint16_t port); - - void onData(ApDataHandler cb, void *arg); - void onClose(ApCloseHandler cb, void *arg); - - operator bool(); - AsyncPrinter & operator=(const AsyncPrinter &other); - - size_t write(uint8_t data); - size_t write(const uint8_t *data, size_t len); - - bool connected(); - void close(); - - size_t _sendBuffer(); - void _onData(void *data, size_t len); - void _on_close(); - void _attachCallbacks(); -}; - -#endif /* ASYNCPRINTER_H_ */ diff --git a/lib/ESPAsyncTCP/src/DebugPrintMacros.h b/lib/ESPAsyncTCP/src/DebugPrintMacros.h deleted file mode 100644 index 29accaf30..000000000 --- a/lib/ESPAsyncTCP/src/DebugPrintMacros.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef _DEBUG_PRINT_MACROS_H -#define _DEBUG_PRINT_MACROS_H -// Some customizable print macros to suite the debug needs de jour. - -// Debug macros -// #include -// https://stackoverflow.com/questions/8487986/file-macro-shows-full-path -// This value is resolved at compile time. -#define _FILENAME_ strrchr("/" __FILE__, '/') - -// #define DEBUG_ESP_ASYNC_TCP 1 -// #define DEBUG_ESP_TCP_SSL 1 -// #define DEBUG_ESP_PORT Serial - -#if defined(DEBUG_ESP_PORT) && !defined(DEBUG_TIME_STAMP_FMT) -#define DEBUG_TIME_STAMP_FMT "%06u.%03u " -struct _DEBUG_TIME_STAMP { - unsigned dec; - unsigned whole; -}; -inline struct _DEBUG_TIME_STAMP debugTimeStamp(void) { - struct _DEBUG_TIME_STAMP st; - unsigned now = millis() % 1000000000; - st.dec = now % 1000; - st.whole = now / 1000; - return st; -} -#endif - -#if defined(DEBUG_ESP_PORT) && !defined(DEBUG_GENERIC) - #define DEBUG_GENERIC( module, format, ... ) \ - do { \ - struct _DEBUG_TIME_STAMP st = debugTimeStamp(); \ - DEBUG_ESP_PORT.printf( DEBUG_TIME_STAMP_FMT module " " format, st.whole, st.dec, ##__VA_ARGS__ ); \ - } while(false) -#endif -#if defined(DEBUG_ESP_PORT) && !defined(DEBUG_GENERIC_P) - #define DEBUG_GENERIC_P( module, format, ... ) \ - do { \ - struct _DEBUG_TIME_STAMP st = debugTimeStamp(); \ - DEBUG_ESP_PORT.printf_P(PSTR( DEBUG_TIME_STAMP_FMT module " " format ), st.whole, st.dec, ##__VA_ARGS__ ); \ - } while(false) -#endif - -#if defined(DEBUG_GENERIC) && !defined(ASSERT_GENERIC) -#define ASSERT_GENERIC( a, module ) \ - do { \ - if ( !(a) ) { \ - DEBUG_GENERIC( module, "%s:%s:%u: ASSERT("#a") failed!\n", __FILE__, __func__, __LINE__); \ - DEBUG_ESP_PORT.flush(); \ - } \ - } while(false) -#endif -#if defined(DEBUG_GENERIC_P) && !defined(ASSERT_GENERIC_P) -#define ASSERT_GENERIC_P( a, module ) \ - do { \ - if ( !(a) ) { \ - DEBUG_GENERIC_P( module, "%s:%s:%u: ASSERT("#a") failed!\n", __FILE__, __func__, __LINE__); \ - DEBUG_ESP_PORT.flush(); \ - } \ - } while(false) -#endif - -#ifndef DEBUG_GENERIC -#define DEBUG_GENERIC(...) do { (void)0;} while(false) -#endif - -#ifndef DEBUG_GENERIC_P -#define DEBUG_GENERIC_P(...) do { (void)0;} while(false) -#endif - -#ifndef ASSERT_GENERIC -#define ASSERT_GENERIC(...) do { (void)0;} while(false) -#endif - -#ifndef ASSERT_GENERIC_P -#define ASSERT_GENERIC_P(...) do { (void)0;} while(false) -#endif - -#ifndef DEBUG_ESP_PRINTF -#define DEBUG_ESP_PRINTF( format, ...) DEBUG_GENERIC_P("[%s]", format, &_FILENAME_[1], ##__VA_ARGS__) -#endif - -#if defined(DEBUG_ESP_ASYNC_TCP) && !defined(ASYNC_TCP_DEBUG) -#define ASYNC_TCP_DEBUG( format, ...) DEBUG_GENERIC_P("[ASYNC_TCP]", format, ##__VA_ARGS__) -#endif - -#ifndef ASYNC_TCP_ASSERT -#define ASYNC_TCP_ASSERT( a ) ASSERT_GENERIC_P( (a), "[ASYNC_TCP]") -#endif - -#if defined(DEBUG_ESP_TCP_SSL) && !defined(TCP_SSL_DEBUG) -#define TCP_SSL_DEBUG( format, ...) DEBUG_GENERIC_P("[TCP_SSL]", format, ##__VA_ARGS__) -#endif - -#endif //_DEBUG_PRINT_MACROS_H diff --git a/lib/ESPAsyncTCP/src/ESPAsyncTCP.cpp b/lib/ESPAsyncTCP/src/ESPAsyncTCP.cpp deleted file mode 100644 index 0a51ed74e..000000000 --- a/lib/ESPAsyncTCP/src/ESPAsyncTCP.cpp +++ /dev/null @@ -1,1409 +0,0 @@ -/* - 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 -*/ -/* -Changes for July 2019 - -The operator "new ..." was changed to "new (std::nothrow) ...", which will -return NULL when the heap is out of memory. Without the change "soft WDT" -was the result, starting with Arduino ESP8266 Core 2.5.0. (Note, RE:"soft -WDT" - the error reporting may improve with core 2.6.) With proir core -versions the library appears to work fine. -ref: https://github.com/esp8266/Arduino/issues/6269#issue-464978944 - -To support newer lwIP versions and buffer models. All references to 1460 -were replaced with TCP_MSS. If TCP_MSS is not defined (exp. 1.4v lwIP) -1460 is assumed. - -The ESPAsyncTCP library should build for Arduino ESP8266 Core releases: -2.3.0, 2.4.1, 2.4.2, 2.5.1, 2.5.2. It may still build with core versions -2.4.0 and 2.5.0. I did not do any regression testing with these, since -they had too many issues and were quickly superseded. - -lwIP tcp_err() callback often resulted in crashes. The problem was a -tcp_err() would come in, while processing a send or receive in the -forground. The tcp_err() callback would be passed down to a client's -registered disconnect CB. A common problem with SyncClient and other -modules as well as some client code was: the freeing of ESPAsyncTCP -AsyncClient objects via disconnect CB handlers while the library was -waiting for an operstion to finished. Attempts to access bad pointers -followed. For SyncClient this commonly occured during a call to delay(). -On return to SyncClient _client was invalid. Also the problem described by -issue #94 also surfaced - -Use of tcp_abort() required some very special handling and was very -challenging to make work without changing client API. ERR_ABRT can only be -used once on a return to lwIP for a given connection and since the -AsyncClient structure was sometimes deleted before returning to lwIP, the -state tracking became tricky. While ugly, a global variable for this -seemed to work; however, I abanded it when I saw a possible -reentrancy/concurrency issue. After several approaches I settled the -problem by creating "class ACErrorTracker" to manage the issue. - - -Additional Async Client considerations: - -The client sketch must always test if the connection is still up at loop() -entry and after the return of any function call, that may have done a -delay() or yield() or any ESPAsyncTCP library family call. For example, -the connection could be lost during a call to _client->write(...). Client -sketches that delete _client as part of their onDisconnect() handler must -be very careful as _client will become invalid after calls to delay(), -yield(), etc. - - - */ -#include "Arduino.h" - -#include "ESPAsyncTCP.h" -extern "C"{ - #include "lwip/opt.h" - #include "lwip/tcp.h" - #include "lwip/inet.h" - #include "lwip/dns.h" - #include "lwip/init.h" -} -#include - -/* - Async Client Error Return Tracker -*/ -// Assumption: callbacks are never called with err == ERR_ABRT; however, -// they may return ERR_ABRT. - -ACErrorTracker::ACErrorTracker(AsyncClient *c): - _client(c) - , _close_error(ERR_OK) - , _errored(EE_OK) -#ifdef DEBUG_MORE - , _error_event_cb(NULL) - , _error_event_cb_arg(NULL) -#endif -{} - -#ifdef DEBUG_MORE -/** - * This is not necessary, but a start at gathering some statistics on - * errored out connections. Used from AsyncServer. - */ -void ACErrorTracker::onErrorEvent(AsNotifyHandler cb, void *arg) { - _error_event_cb = cb; - _error_event_cb_arg = arg; -} -#endif - -void ACErrorTracker::setCloseError(err_t e) { - if (e != ERR_OK) - ASYNC_TCP_DEBUG("setCloseError() to: %s(%ld)\n", _client->errorToString(e), e); - if(_errored == EE_OK) - _close_error = e; -} -/** - * Called mainly by callback routines, called when err is not ERR_OK. - * This prevents the possiblity of aborting an already errored out - * connection. - */ -void ACErrorTracker::setErrored(size_t errorEvent){ - if(EE_OK == _errored) - _errored = errorEvent; -#ifdef DEBUG_MORE - if (_error_event_cb) - _error_event_cb(_error_event_cb_arg, errorEvent); -#endif -} -/** - * Used by callback functions only. Used for proper ERR_ABRT return value - * reporting. ERR_ABRT is only reported/returned once; thereafter ERR_OK - * is always returned. - */ -err_t ACErrorTracker::getCallbackCloseError(void){ - if (EE_OK != _errored) - return ERR_OK; - if (ERR_ABRT == _close_error) - setErrored(EE_ABORTED); - return _close_error; -} - -/* - Async TCP Client -*/ -#if DEBUG_ESP_ASYNC_TCP -static size_t _connectionCount=0; -#endif - -#if ASYNC_TCP_SSL_ENABLED -AsyncClient::AsyncClient(tcp_pcb* pcb, SSL_CTX * ssl_ctx): -#else -AsyncClient::AsyncClient(tcp_pcb* pcb): -#endif - _connect_cb(0) - , _connect_cb_arg(0) - , _discard_cb(0) - , _discard_cb_arg(0) - , _sent_cb(0) - , _sent_cb_arg(0) - , _error_cb(0) - , _error_cb_arg(0) - , _recv_cb(0) - , _recv_cb_arg(0) - , _pb_cb(0) - , _pb_cb_arg(0) - , _timeout_cb(0) - , _timeout_cb_arg(0) - , _poll_cb(0) - , _poll_cb_arg(0) - , _pcb_busy(false) -#if ASYNC_TCP_SSL_ENABLED - , _pcb_secure(false) - , _handshake_done(true) -#endif - , _pcb_sent_at(0) - , _close_pcb(false) - , _ack_pcb(true) - , _tx_unacked_len(0) - , _tx_acked_len(0) - , _tx_unsent_len(0) - , _rx_ack_len(0) - , _rx_last_packet(0) - , _rx_since_timeout(0) - , _ack_timeout(ASYNC_MAX_ACK_TIME) - , _connect_port(0) - , _recv_pbuf_flags(0) - , _errorTracker(NULL) - , prev(NULL) - , next(NULL) -{ - _pcb = pcb; - if(_pcb){ - _rx_last_packet = millis(); - tcp_setprio(_pcb, TCP_PRIO_MIN); - tcp_arg(_pcb, this); - tcp_recv(_pcb, &_s_recv); - tcp_sent(_pcb, &_s_sent); - tcp_err(_pcb, &_s_error); - tcp_poll(_pcb, &_s_poll, 1); -#if ASYNC_TCP_SSL_ENABLED - if(ssl_ctx){ - if(tcp_ssl_new_server(_pcb, ssl_ctx) < 0){ - _close(); - return; - } - tcp_ssl_arg(_pcb, this); - tcp_ssl_data(_pcb, &_s_data); - tcp_ssl_handshake(_pcb, &_s_handshake); - tcp_ssl_err(_pcb, &_s_ssl_error); - - _pcb_secure = true; - _handshake_done = false; - } -#endif - } - - _errorTracker = std::make_shared(this); -#if DEBUG_ESP_ASYNC_TCP - _errorTracker->setConnectionId(++_connectionCount); -#endif -} - -AsyncClient::~AsyncClient(){ - if(_pcb) - _close(); - - _errorTracker->clearClient(); -} - -inline void clearTcpCallbacks(tcp_pcb* pcb){ - tcp_arg(pcb, NULL); - tcp_sent(pcb, NULL); - tcp_recv(pcb, NULL); - tcp_err(pcb, NULL); - tcp_poll(pcb, NULL, 0); -} - -#if ASYNC_TCP_SSL_ENABLED -bool AsyncClient::connect(IPAddress ip, uint16_t port, bool secure){ -#else -bool AsyncClient::connect(IPAddress ip, uint16_t port){ -#endif - if (_pcb) //already connected - return false; - ip_addr_t addr; - addr.addr = ip; -#if LWIP_VERSION_MAJOR == 1 - netif* interface = ip_route(&addr); - if (!interface){ //no route to host - return false; - } -#endif - tcp_pcb* pcb = tcp_new(); - if (!pcb){ //could not allocate pcb - return false; - } - - tcp_setprio(pcb, TCP_PRIO_MIN); -#if ASYNC_TCP_SSL_ENABLED - _pcb_secure = secure; - _handshake_done = !secure; -#endif - tcp_arg(pcb, this); - tcp_err(pcb, &_s_error); - size_t err = tcp_connect(pcb, &addr, port,(tcp_connected_fn)&_s_connected); - return (ERR_OK == err); -} - -#if ASYNC_TCP_SSL_ENABLED -bool AsyncClient::connect(const char* host, uint16_t port, bool secure){ -#else -bool AsyncClient::connect(const char* host, uint16_t port){ -#endif - ip_addr_t addr; - err_t err = dns_gethostbyname(host, &addr, (dns_found_callback)&_s_dns_found, this); - if(err == ERR_OK) { -#if ASYNC_TCP_SSL_ENABLED - return connect(IPAddress(addr.addr), port, secure); -#else - return connect(IPAddress(addr.addr), port); -#endif - } else if(err == ERR_INPROGRESS) { -#if ASYNC_TCP_SSL_ENABLED - _pcb_secure = secure; - _handshake_done = !secure; -#endif - _connect_port = port; - return true; - } - return false; -} - -AsyncClient& AsyncClient::operator=(const AsyncClient& other){ - if (_pcb) { - ASYNC_TCP_DEBUG("operator=[%u]: Abandoned _pcb(0x%" PRIXPTR ") forced close.\n", getConnectionId(), uintptr_t(_pcb)); - _close(); - } - _errorTracker = other._errorTracker; - - // I am confused when "other._pcb" falls out of scope the destructor will - // close it? TODO: Look to see where this is used and how it might work. - _pcb = other._pcb; - if (_pcb) { - _rx_last_packet = millis(); - tcp_setprio(_pcb, TCP_PRIO_MIN); - tcp_arg(_pcb, this); - tcp_recv(_pcb, &_s_recv); - tcp_sent(_pcb, &_s_sent); - tcp_err(_pcb, &_s_error); - tcp_poll(_pcb, &_s_poll, 1); -#if ASYNC_TCP_SSL_ENABLED - if(tcp_ssl_has(_pcb)){ - _pcb_secure = true; - _handshake_done = false; - tcp_ssl_arg(_pcb, this); - tcp_ssl_data(_pcb, &_s_data); - tcp_ssl_handshake(_pcb, &_s_handshake); - tcp_ssl_err(_pcb, &_s_ssl_error); - } else { - _pcb_secure = false; - _handshake_done = true; - } -#endif - } - return *this; -} - -bool AsyncClient::operator==(const AsyncClient &other) { - return (_pcb != NULL && other._pcb != NULL && (_pcb->remote_ip.addr == other._pcb->remote_ip.addr) && (_pcb->remote_port == other._pcb->remote_port)); -} - -void AsyncClient::abort(){ - // Notes: - // 1) _pcb is set to NULL, so we cannot call tcp_abort() more than once. - // 2) setCloseError(ERR_ABRT) is only done here! - // 3) Using this abort() function guarantees only one tcp_abort() call is - // made and only one CB returns with ERR_ABORT. - // 4) After abort() is called from _close(), no callbacks with an err - // parameter will be called. eg. _recv(), _error(), _connected(). - // _close() will reset there CB handlers before calling. - // 5) A callback to _error(), will set _pcb to NULL, thus avoiding the - // of a 2nd call to tcp_abort(). - // 6) Callbacks to _recv() or _connected() with err set, will result in _pcb - // set to NULL. Thus, preventing possible calls later to tcp_abort(). - if(_pcb) { - tcp_abort(_pcb); - _pcb = NULL; - setCloseError(ERR_ABRT); - } - return; -} - -void AsyncClient::close(bool now){ - if(_pcb) - tcp_recved(_pcb, _rx_ack_len); - if(now) - _close(); - else - _close_pcb = true; -} - -void AsyncClient::stop() { - close(false); -} - -bool AsyncClient::free(){ - if(!_pcb) - return true; - if(_pcb->state == 0 || _pcb->state > 4) - return true; - return false; -} - -size_t AsyncClient::write(const char* data) { - if(data == NULL) - return 0; - return write(data, strlen(data)); -} - -size_t AsyncClient::write(const char* data, size_t size, uint8_t apiflags) { - size_t will_send = add(data, size, apiflags); - - if(!will_send || !send()) - return 0; - return will_send; -} - -size_t AsyncClient::add(const char* data, size_t size, uint8_t apiflags) { - if(!_pcb || size == 0 || data == NULL) - return 0; - size_t room = space(); - if(!room) - return 0; -#if ASYNC_TCP_SSL_ENABLED - if(_pcb_secure){ - int sent = tcp_ssl_write(_pcb, (uint8_t*)data, size); - if(sent >= 0){ - _tx_unacked_len += sent; - return sent; - } - _close(); - return 0; - } -#endif - size_t will_send = (room < size) ? room : size; - err_t err = tcp_write(_pcb, data, will_send, apiflags); - if(err != ERR_OK) { - ASYNC_TCP_DEBUG("_add[%u]: tcp_write() returned err: %s(%ld)\n", getConnectionId(), errorToString(err), err); - return 0; - } - _tx_unsent_len += will_send; - return will_send; -} - -bool AsyncClient::send(){ -#if ASYNC_TCP_SSL_ENABLED - if(_pcb_secure) - return true; -#endif - err_t err = tcp_output(_pcb); - if(err == ERR_OK){ - _pcb_busy = true; - _pcb_sent_at = millis(); - _tx_unacked_len += _tx_unsent_len; - _tx_unsent_len = 0; - return true; - } - - ASYNC_TCP_DEBUG("send[%u]: tcp_output() returned err: %s(%ld)", getConnectionId(), errorToString(err), err); - _tx_unsent_len = 0; - return false; -} - -size_t AsyncClient::ack(size_t len){ - if(len > _rx_ack_len) - len = _rx_ack_len; - if(len) - tcp_recved(_pcb, len); - _rx_ack_len -= len; - return len; -} - -// Private Callbacks - -void AsyncClient::_connected(std::shared_ptr& errorTracker, void* pcb, err_t err){ - //(void)err; // LWIP v1.4 appears to always call with ERR_OK - // Documentation for 2.1.0 also says: - // "err - An unused error code, always ERR_OK currently ;-)" - // https://www.nongnu.org/lwip/2_1_x/tcp_8h.html#a939867106bd492caf2d85852fb7f6ae8 - // Based on that wording and emoji lets just handle it now. - // After all, the API does allow for an err != ERR_OK. - if(NULL == pcb || ERR_OK != err) { - ASYNC_TCP_DEBUG("_connected[%u]:%s err: %s(%ld)\n", errorTracker->getConnectionId(), ((NULL == pcb) ? " NULL == pcb!," : ""), errorToString(err), err); - errorTracker->setCloseError(err); - errorTracker->setErrored(EE_CONNECTED_CB); - _pcb = reinterpret_cast(pcb); - if (_pcb) - clearTcpCallbacks(_pcb); - _pcb = NULL; - _error(err); - return; - } - - _pcb = reinterpret_cast(pcb); - if(_pcb){ - _pcb_busy = false; - _rx_last_packet = millis(); - tcp_setprio(_pcb, TCP_PRIO_MIN); - tcp_recv(_pcb, &_s_recv); - tcp_sent(_pcb, &_s_sent); - tcp_poll(_pcb, &_s_poll, 1); -#if ASYNC_TCP_SSL_ENABLED - if(_pcb_secure){ - if(tcp_ssl_new_client(_pcb) < 0){ - _close(); - return; - } - tcp_ssl_arg(_pcb, this); - tcp_ssl_data(_pcb, &_s_data); - tcp_ssl_handshake(_pcb, &_s_handshake); - tcp_ssl_err(_pcb, &_s_ssl_error); - } - } - if(!_pcb_secure && _connect_cb) -#else - } - if(_connect_cb) -#endif - _connect_cb(_connect_cb_arg, this); - return; -} - -void AsyncClient::_close(){ - if(_pcb) { -#if ASYNC_TCP_SSL_ENABLED - if(_pcb_secure){ - tcp_ssl_free(_pcb); - } -#endif - clearTcpCallbacks(_pcb); - err_t err = tcp_close(_pcb); - if(ERR_OK == err) { - setCloseError(err); - } else { - ASYNC_TCP_DEBUG("_close[%u]: abort() called for AsyncClient 0x%" PRIXPTR "\n", getConnectionId(), uintptr_t(this)); - abort(); - } - _pcb = NULL; - if(_discard_cb) - _discard_cb(_discard_cb_arg, this); - } - return; -} - -void AsyncClient::_error(err_t err) { - ASYNC_TCP_DEBUG("_error[%u]:%s err: %s(%ld)\n", getConnectionId(), ((NULL == _pcb) ? " NULL == _pcb!," : ""), errorToString(err), err); - if(_pcb){ -#if ASYNC_TCP_SSL_ENABLED - if(_pcb_secure){ - tcp_ssl_free(_pcb); - } -#endif - // At this callback _pcb is possible already freed. Thus, no calls are - // made to set to NULL other callbacks. - _pcb = NULL; - } - if(_error_cb) - _error_cb(_error_cb_arg, this, err); - if(_discard_cb) - _discard_cb(_discard_cb_arg, this); -} - -#if ASYNC_TCP_SSL_ENABLED -void AsyncClient::_ssl_error(int8_t err){ - if(_error_cb) - _error_cb(_error_cb_arg, this, err+64); -} -#endif - -void AsyncClient::_sent(std::shared_ptr& errorTracker, tcp_pcb* pcb, uint16_t len) { - (void)pcb; -#if ASYNC_TCP_SSL_ENABLED - if (_pcb_secure && !_handshake_done) - return; -#endif - _rx_last_packet = millis(); - - // If add() is called, then send(), we have unacked len with data, and _pcb_busy true - // we have space so we call add with some more data, we call then canSend() - // That returns false, because _pcb_busy is true, so we dont call send(). - // Then this function gets called, but not only with the bytes queued before the send() call - // also the data added with add() is send, and acked, now we have more acked data than expected - // if we don't check for this unackled overflows when substracting acked length and - // pcb_busy never goes false, if we keep checking canSend(), we never call send even if we did - // _pcb_busy will remain true. - if (len > _tx_unacked_len) - { - _tx_unacked_len += _tx_unsent_len; - _tx_unsent_len = 0; - } - - _tx_unacked_len -= len; - _tx_acked_len += len; - ASYNC_TCP_DEBUG("_sent[%u]: %4u, unacked=%4u, acked=%4u, space=%4u\n", errorTracker->getConnectionId(), len, _tx_unacked_len, _tx_acked_len, space()); - if(_tx_unacked_len == 0){ - _pcb_busy = false; - errorTracker->setCloseError(ERR_OK); - if(_sent_cb) { - _sent_cb(_sent_cb_arg, this, _tx_acked_len, (millis() - _pcb_sent_at)); - if(!errorTracker->hasClient()) - return; - } - _tx_acked_len = 0; - } - return; -} - -void AsyncClient::_recv(std::shared_ptr& errorTracker, tcp_pcb* pcb, pbuf* pb, err_t err) { - // While lwIP v1.4 appears to always call with ERR_OK, 2.x lwIP may present - // a non-ERR_OK value. - // https://www.nongnu.org/lwip/2_1_x/tcp_8h.html#a780cfac08b02c66948ab94ea974202e8 - if(NULL == pcb || ERR_OK != err){ - ASYNC_TCP_DEBUG("_recv[%u]:%s err: %s(%ld)\n", errorTracker->getConnectionId(), ((NULL == pcb) ? " NULL == pcb!," : ""), errorToString(err), err); - ASYNC_TCP_ASSERT(ERR_ABRT != err); - errorTracker->setCloseError(err); - errorTracker->setErrored(EE_RECV_CB); - _pcb = pcb; - if(_pcb) - clearTcpCallbacks(_pcb); - _pcb = NULL; - // I think we are safe from being called from an interrupt context. - // Best Hint that calling _error() is safe: - // https://www.nongnu.org/lwip/2_1_x/group__lwip__nosys.html - // "Feed incoming packets to netif->input(pbuf, netif) function from - // mainloop, not from interrupt context. You can allocate a Packet buffers - // (PBUF) in interrupt context and put them into a queue which is processed - // from mainloop." - // And the description of "Mainloop Mode" option 2: - // https://www.nongnu.org/lwip/2_1_x/pitfalls.html - // "2) Run lwIP in a mainloop. ... lwIP is ONLY called from mainloop - // callstacks here. The ethernet IRQ has to put received telegrams into a - // queue which is polled in the mainloop. Ensure lwIP is NEVER called from - // an interrupt, ...!" - // Based on these comments I am thinking tcp_recv_fn() is called - // from somebody's mainloop(), which could only have been reached from a - // delay like function or the Arduino sketch loop() function has returned. - // What I don't want is for the client sketch to delete the AsyncClient - // object via _error() while it is in the middle of using it. However, - // the client sketch must always test that the connection is still up - // at loop() entry and after the return of any function call, that may - // have done a delay() or yield(). - _error(err); - return; - } - - if(pb == NULL){ - ASYNC_TCP_DEBUG("_recv[%u]: pb == NULL! Closing... %ld\n", errorTracker->getConnectionId(), err); - _close(); - return; - } - _rx_last_packet = millis(); - errorTracker->setCloseError(ERR_OK); -#if ASYNC_TCP_SSL_ENABLED - if(_pcb_secure){ - ASYNC_TCP_DEBUG("_recv[%u]: %d\n", getConnectionId(), pb->tot_len); - int read_bytes = tcp_ssl_read(pcb, pb); - if(read_bytes < 0){ - if (read_bytes != SSL_CLOSE_NOTIFY) { - ASYNC_TCP_DEBUG("_recv[%u] err: %d\n", getConnectionId(), read_bytes); - _close(); - } - } - return; - } -#endif - while(pb != NULL){ - // IF this callback function returns ERR_OK or ERR_ABRT - // then it is assummed we freed the pbufs. - // https://www.nongnu.org/lwip/2_1_x/group__tcp__raw.html#ga8afd0b316a87a5eeff4726dc95006ed0 - if(!errorTracker->hasClient()){ - while(pb != NULL){ - pbuf *b = pb; - pb = b->next; - b->next = NULL; - pbuf_free(b); - } - return; - } - //we should not ack before we assimilate the data - _ack_pcb = true; - pbuf *b = pb; - pb = b->next; - b->next = NULL; - ASYNC_TCP_DEBUG("_recv[%u]: %d%s\n", errorTracker->getConnectionId(), b->len, (b->flags&PBUF_FLAG_PUSH)?", PBUF_FLAG_PUSH":""); - if(_pb_cb){ - _pb_cb(_pb_cb_arg, this, b); - } else { - if(_recv_cb){ - _recv_pbuf_flags = b->flags; - _recv_cb(_recv_cb_arg, this, b->payload, b->len); - } - if(errorTracker->hasClient()){ - if(!_ack_pcb) - _rx_ack_len += b->len; - else - tcp_recved(pcb, b->len); - } - pbuf_free(b); - } - } - return; -} - -void AsyncClient::_poll(std::shared_ptr& errorTracker, tcp_pcb* pcb){ - (void)pcb; - errorTracker->setCloseError(ERR_OK); - - // Close requested - if(_close_pcb){ - _close_pcb = false; - _close(); - return; - } - uint32_t now = millis(); - - // ACK Timeout - if(_pcb_busy && _ack_timeout && (now - _pcb_sent_at) >= _ack_timeout){ - _pcb_busy = false; - if(_timeout_cb) - _timeout_cb(_timeout_cb_arg, this, (now - _pcb_sent_at)); - return; - } - // RX Timeout - if(_rx_since_timeout && (now - _rx_last_packet) >= (_rx_since_timeout * 1000)){ - _close(); - return; - } -#if ASYNC_TCP_SSL_ENABLED - // SSL Handshake Timeout - if(_pcb_secure && !_handshake_done && (now - _rx_last_packet) >= 2000){ - _close(); - return; - } -#endif - // Everything is fine - if(_poll_cb) - _poll_cb(_poll_cb_arg, this); - return; -} - -#if LWIP_VERSION_MAJOR == 1 -void AsyncClient::_dns_found(struct ip_addr *ipaddr){ -#else -void AsyncClient::_dns_found(const ip_addr *ipaddr){ -#endif - if(ipaddr){ -#if ASYNC_TCP_SSL_ENABLED - connect(IPAddress(ipaddr->addr), _connect_port, _pcb_secure); -#else - connect(IPAddress(ipaddr->addr), _connect_port); -#endif - } else { - if(_error_cb) - _error_cb(_error_cb_arg, this, -55); - if(_discard_cb) - _discard_cb(_discard_cb_arg, this); - } -} - -// lwIP Callbacks -#if LWIP_VERSION_MAJOR == 1 -void AsyncClient::_s_dns_found(const char *name, ip_addr_t *ipaddr, void *arg){ -#else -void AsyncClient::_s_dns_found(const char *name, const ip_addr *ipaddr, void *arg){ -#endif - (void)name; - reinterpret_cast(arg)->_dns_found(ipaddr); -} - -err_t AsyncClient::_s_poll(void *arg, struct tcp_pcb *tpcb) { - AsyncClient *c = reinterpret_cast(arg); - std::shared_ptrerrorTracker = c->getACErrorTracker(); - c->_poll(errorTracker, tpcb); - return errorTracker->getCallbackCloseError(); -} - -err_t AsyncClient::_s_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *pb, err_t err) { - AsyncClient *c = reinterpret_cast(arg); - auto errorTracker = c->getACErrorTracker(); - c->_recv(errorTracker, tpcb, pb, err); - return errorTracker->getCallbackCloseError(); -} - -void AsyncClient::_s_error(void *arg, err_t err) { - AsyncClient *c = reinterpret_cast(arg); - auto errorTracker = c->getACErrorTracker(); - errorTracker->setCloseError(err); - errorTracker->setErrored(EE_ERROR_CB); - c->_error(err); -} - -err_t AsyncClient::_s_sent(void *arg, struct tcp_pcb *tpcb, uint16_t len) { - AsyncClient *c = reinterpret_cast(arg); - auto errorTracker = c->getACErrorTracker(); - c->_sent(errorTracker, tpcb, len); - return errorTracker->getCallbackCloseError(); -} - -err_t AsyncClient::_s_connected(void* arg, void* tpcb, err_t err){ - AsyncClient *c = reinterpret_cast(arg); - auto errorTracker = c->getACErrorTracker(); - c->_connected(errorTracker, tpcb, err); - return errorTracker->getCallbackCloseError(); -} - -#if ASYNC_TCP_SSL_ENABLED -void AsyncClient::_s_data(void *arg, struct tcp_pcb *tcp, uint8_t * data, size_t len){ - AsyncClient *c = reinterpret_cast(arg); - if(c->_recv_cb) - c->_recv_cb(c->_recv_cb_arg, c, data, len); -} - -void AsyncClient::_s_handshake(void *arg, struct tcp_pcb *tcp, SSL *ssl){ - AsyncClient *c = reinterpret_cast(arg); - c->_handshake_done = true; - if(c->_connect_cb) - c->_connect_cb(c->_connect_cb_arg, c); -} - -void AsyncClient::_s_ssl_error(void *arg, struct tcp_pcb *tcp, int8_t err){ - reinterpret_cast(arg)->_ssl_error(err); -} -#endif - -// Operators - -AsyncClient & AsyncClient::operator+=(const AsyncClient &other) { - if(next == NULL){ - next = (AsyncClient*)(&other); - next->prev = this; - } else { - AsyncClient *c = next; - while(c->next != NULL) c = c->next; - c->next =(AsyncClient*)(&other); - c->next->prev = c; - } - return *this; -} - -void AsyncClient::setRxTimeout(uint32_t timeout){ - _rx_since_timeout = timeout; -} - -uint32_t AsyncClient::getRxTimeout(){ - return _rx_since_timeout; -} - -uint32_t AsyncClient::getAckTimeout(){ - return _ack_timeout; -} - -void AsyncClient::setAckTimeout(uint32_t timeout){ - _ack_timeout = timeout; -} - -void AsyncClient::setNoDelay(bool nodelay){ - if(!_pcb) - return; - if(nodelay) - tcp_nagle_disable(_pcb); - else - tcp_nagle_enable(_pcb); -} - -bool AsyncClient::getNoDelay(){ - if(!_pcb) - return false; - return tcp_nagle_disabled(_pcb); -} - -uint16_t AsyncClient::getMss(){ - if(_pcb) - return tcp_mss(_pcb); - return 0; -} - -uint32_t AsyncClient::getRemoteAddress() { - if(!_pcb) - return 0; - return _pcb->remote_ip.addr; -} - -uint16_t AsyncClient::getRemotePort() { - if(!_pcb) - return 0; - return _pcb->remote_port; -} - -uint32_t AsyncClient::getLocalAddress() { - if(!_pcb) - return 0; - return _pcb->local_ip.addr; -} - -uint16_t AsyncClient::getLocalPort() { - if(!_pcb) - return 0; - return _pcb->local_port; -} - -IPAddress AsyncClient::remoteIP() { - return IPAddress(getRemoteAddress()); -} - -uint16_t AsyncClient::remotePort() { - return getRemotePort(); -} - -IPAddress AsyncClient::localIP() { - return IPAddress(getLocalAddress()); -} - -uint16_t AsyncClient::localPort() { - return getLocalPort(); -} - -#if ASYNC_TCP_SSL_ENABLED -SSL * AsyncClient::getSSL(){ - if(_pcb && _pcb_secure){ - return tcp_ssl_get_ssl(_pcb); - } - return NULL; -} -#endif - -uint8_t AsyncClient::state() { - if(!_pcb) - return 0; - return _pcb->state; -} - -bool AsyncClient::connected(){ - if (!_pcb) - return false; -#if ASYNC_TCP_SSL_ENABLED - return _pcb->state == 4 && _handshake_done; -#else - return _pcb->state == 4; -#endif -} - -bool AsyncClient::connecting(){ - if (!_pcb) - return false; - return _pcb->state > 0 && _pcb->state < 4; -} - -bool AsyncClient::disconnecting(){ - if (!_pcb) - return false; - return _pcb->state > 4 && _pcb->state < 10; -} - -bool AsyncClient::disconnected(){ - if (!_pcb) - return true; - return _pcb->state == 0 || _pcb->state == 10; -} - -bool AsyncClient::freeable(){ - if (!_pcb) - return true; - return _pcb->state == 0 || _pcb->state > 4; -} - -bool AsyncClient::canSend(){ - return !_pcb_busy && (space() > 0); -} - - -// Callback Setters - -void AsyncClient::onConnect(AcConnectHandler cb, void* arg){ - _connect_cb = cb; - _connect_cb_arg = arg; -} - -void AsyncClient::onDisconnect(AcConnectHandler cb, void* arg){ - _discard_cb = cb; - _discard_cb_arg = arg; -} - -void AsyncClient::onAck(AcAckHandler cb, void* arg){ - _sent_cb = cb; - _sent_cb_arg = arg; -} - -void AsyncClient::onError(AcErrorHandler cb, void* arg){ - _error_cb = cb; - _error_cb_arg = arg; -} - -void AsyncClient::onData(AcDataHandler cb, void* arg){ - _recv_cb = cb; - _recv_cb_arg = arg; -} - -void AsyncClient::onPacket(AcPacketHandler cb, void* arg){ - _pb_cb = cb; - _pb_cb_arg = arg; -} - -void AsyncClient::onTimeout(AcTimeoutHandler cb, void* arg){ - _timeout_cb = cb; - _timeout_cb_arg = arg; -} - -void AsyncClient::onPoll(AcConnectHandler cb, void* arg){ - _poll_cb = cb; - _poll_cb_arg = arg; -} - - -size_t AsyncClient::space(){ -#if ASYNC_TCP_SSL_ENABLED - if((_pcb != NULL) && (_pcb->state == 4) && _handshake_done){ - uint16_t s = tcp_sndbuf(_pcb); - if(_pcb_secure){ -#ifdef AXTLS_2_0_0_SNDBUF - return tcp_ssl_sndbuf(_pcb); -#else - if(s >= 128) //safe approach - return s - 128; - return 0; -#endif - } - return s; - } -#else // ASYNC_TCP_SSL_ENABLED - if((_pcb != NULL) && (_pcb->state == 4)){ - return tcp_sndbuf(_pcb); - } -#endif // ASYNC_TCP_SSL_ENABLED - return 0; -} - -void AsyncClient::ackPacket(struct pbuf * pb){ - if(!pb){ - return; - } - tcp_recved(_pcb, pb->len); - pbuf_free(pb); -} - -const char * AsyncClient::errorToString(err_t error) { - switch (error) { - case ERR_OK: return "No error, everything OK"; - case ERR_MEM: return "Out of memory error"; - case ERR_BUF: return "Buffer error"; - case ERR_TIMEOUT: return "Timeout"; - case ERR_RTE: return "Routing problem"; - case ERR_INPROGRESS: return "Operation in progress"; - case ERR_VAL: return "Illegal value"; - case ERR_WOULDBLOCK: return "Operation would block"; - case ERR_ABRT: return "Connection aborted"; - case ERR_RST: return "Connection reset"; - case ERR_CLSD: return "Connection closed"; - case ERR_CONN: return "Not connected"; - case ERR_ARG: return "Illegal argument"; - case ERR_USE: return "Address in use"; -#if defined(LWIP_VERSION_MAJOR) && (LWIP_VERSION_MAJOR > 1) - case ERR_ALREADY: return "Already connectioning"; -#endif - case ERR_IF: return "Low-level netif error"; - case ERR_ISCONN: return "Connection already established"; - case -55: return "DNS failed"; - default: return "Unknown error"; - } -} - -const char * AsyncClient::stateToString(){ - switch(state()){ - case 0: return "Closed"; - case 1: return "Listen"; - case 2: return "SYN Sent"; - case 3: return "SYN Received"; - case 4: return "Established"; - case 5: return "FIN Wait 1"; - case 6: return "FIN Wait 2"; - case 7: return "Close Wait"; - case 8: return "Closing"; - case 9: return "Last ACK"; - case 10: return "Time Wait"; - default: return "UNKNOWN"; - } -} - -/* - Async TCP Server -*/ -struct pending_pcb { - tcp_pcb* pcb; - pbuf *pb; - struct pending_pcb * next; -}; - -AsyncServer::AsyncServer(IPAddress addr, uint16_t port) - : _port(port) - , _addr(addr) - , _noDelay(false) - , _pcb(0) - , _connect_cb(0) - , _connect_cb_arg(0) -#if ASYNC_TCP_SSL_ENABLED - , _pending(NULL) - , _ssl_ctx(NULL) - , _file_cb(0) - , _file_cb_arg(0) -#endif -{ -#ifdef DEBUG_MORE - for (size_t i=0; inext; - if(p->pb){ - pbuf_free(p->pb); - } - free(p); - } - } - } -#endif -} - -void AsyncServer::setNoDelay(bool nodelay){ - _noDelay = nodelay; -} - -bool AsyncServer::getNoDelay(){ - return _noDelay; -} - -uint8_t AsyncServer::status(){ - if (!_pcb) - return 0; - return _pcb->state; -} - -err_t AsyncServer::_accept(tcp_pcb* pcb, err_t err){ - //http://savannah.nongnu.org/bugs/?43739 - if(NULL == pcb || ERR_OK != err){ - // https://www.nongnu.org/lwip/2_1_x/tcp_8h.html#a00517abce6856d6c82f0efebdafb734d - // An error code if there has been an error accepting. Only return ERR_ABRT - // if you have called tcp_abort from within the callback function! - // eg. 2.1.0 could call with error on failure to allocate pcb. - ASYNC_TCP_DEBUG("_accept:%s err: %ld\n", ((NULL == pcb) ? " NULL == pcb!," : ""), err); - ASYNC_TCP_ASSERT(ERR_ABRT != err); -#ifdef DEBUG_MORE - incEventCount(EE_ACCEPT_CB); -#endif - return ERR_OK; - } - - if(_connect_cb){ -#if ASYNC_TCP_SSL_ENABLED - if (_noDelay || _ssl_ctx) -#else - if (_noDelay) -#endif - tcp_nagle_disable(pcb); - else - tcp_nagle_enable(pcb); - -#if ASYNC_TCP_SSL_ENABLED - if(_ssl_ctx){ - if(tcp_ssl_has_client() || _pending){ - struct pending_pcb * new_item = (struct pending_pcb*)malloc(sizeof(struct pending_pcb)); - if(!new_item){ - ASYNC_TCP_DEBUG("### malloc new pending failed!\n"); - if(tcp_close(pcb) != ERR_OK){ - tcp_abort(pcb); - return ERR_ABRT; - } - return ERR_OK; - } - ASYNC_TCP_DEBUG("### put to wait: %d\n", _clients_waiting); - new_item->pcb = pcb; - new_item->pb = NULL; - new_item->next = NULL; - tcp_setprio(_pcb, TCP_PRIO_MIN); - tcp_arg(pcb, this); - tcp_poll(pcb, &_s_poll, 1); - tcp_recv(pcb, &_s_recv); - - if(_pending == NULL){ - _pending = new_item; - } else { - struct pending_pcb * p = _pending; - while(p->next != NULL) - p = p->next; - p->next = new_item; - } - } else { - AsyncClient *c = new (std::nothrow) AsyncClient(pcb, _ssl_ctx); - if(c){ - ASYNC_TCP_DEBUG("_accept[%u]: SSL connected\n", c->getConnectionId()); - c->onConnect([this](void * arg, AsyncClient *c){ - _connect_cb(_connect_cb_arg, c); - }, this); - } else { - ASYNC_TCP_DEBUG("_accept[_ssl_ctx]: new AsyncClient() failed, connection aborted!\n"); - if(tcp_close(pcb) != ERR_OK){ - tcp_abort(pcb); - return ERR_ABRT; - } - } - } - return ERR_OK; - } else { - AsyncClient *c = new (std::nothrow) AsyncClient(pcb, NULL); -#else - AsyncClient *c = new (std::nothrow) AsyncClient(pcb); -#endif - - if(c){ - auto errorTracker = c->getACErrorTracker(); -#ifdef DEBUG_MORE - errorTracker->onErrorEvent( - [](void *obj, size_t ee){ ((AsyncServer*)(obj))->incEventCount(ee); }, - this); -#endif - ASYNC_TCP_DEBUG("_accept[%u]: connected\n", errorTracker->getConnectionId()); - _connect_cb(_connect_cb_arg, c); - return errorTracker->getCallbackCloseError(); - } else { - ASYNC_TCP_DEBUG("_accept: new AsyncClient() failed, connection aborted!\n"); - if(tcp_close(pcb) != ERR_OK){ - tcp_abort(pcb); - return ERR_ABRT; - } - } -#if ASYNC_TCP_SSL_ENABLED - } -#endif - } - if(tcp_close(pcb) != ERR_OK){ - tcp_abort(pcb); - return ERR_ABRT; - } - return ERR_OK; -} - -err_t AsyncServer::_s_accept(void *arg, tcp_pcb* pcb, err_t err){ - return reinterpret_cast(arg)->_accept(pcb, err); -} - -#if ASYNC_TCP_SSL_ENABLED -err_t AsyncServer::_poll(tcp_pcb* pcb){ - if(!tcp_ssl_has_client() && _pending){ - struct pending_pcb * p = _pending; - if(p->pcb == pcb){ - _pending = _pending->next; - } else { - while(p->next && p->next->pcb != pcb) p = p->next; - if(!p->next) return 0; - struct pending_pcb * b = p->next; - p->next = b->next; - p = b; - } - ASYNC_TCP_DEBUG("### remove from wait: %d\n", _clients_waiting); - AsyncClient *c = new (std::nothrow) AsyncClient(pcb, _ssl_ctx); - if(c){ - c->onConnect([this](void * arg, AsyncClient *c){ - _connect_cb(_connect_cb_arg, c); - }, this); - if(p->pb) - c->_recv(pcb, p->pb, 0); - } - // Should there be error handling for when "new AsynClient" fails?? - free(p); - } - return ERR_OK; -} - -err_t AsyncServer::_recv(struct tcp_pcb *pcb, struct pbuf *pb, err_t err){ - if(!_pending) - return ERR_OK; - - struct pending_pcb * p; - - if(!pb){ - ASYNC_TCP_DEBUG("### close from wait: %d\n", _clients_waiting); - p = _pending; - if(p->pcb == pcb){ - _pending = _pending->next; - } else { - while(p->next && p->next->pcb != pcb) p = p->next; - if(!p->next) return 0; - struct pending_pcb * b = p->next; - p->next = b->next; - p = b; - } - if(p->pb){ - pbuf_free(p->pb); - } - free(p); - size_t err = tcp_close(pcb); - if (err != ERR_OK) { - tcp_abort(pcb); - return ERR_ABRT; - } - } else { - ASYNC_TCP_DEBUG("### wait _recv: %u %d\n", pb->tot_len, _clients_waiting); - p = _pending; - while(p && p->pcb != pcb) - p = p->next; - if(p){ - if(p->pb){ - pbuf_chain(p->pb, pb); - } else { - p->pb = pb; - } - } - } - return ERR_OK; -} - -int AsyncServer::_cert(const char *filename, uint8_t **buf){ - if(_file_cb){ - return _file_cb(_file_cb_arg, filename, buf); - } - *buf = 0; - return 0; -} - -int AsyncServer::_s_cert(void *arg, const char *filename, uint8_t **buf){ - return reinterpret_cast(arg)->_cert(filename, buf); -} - -err_t AsyncServer::_s_poll(void *arg, struct tcp_pcb *pcb){ - return reinterpret_cast(arg)->_poll(pcb); -} - -err_t AsyncServer::_s_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *pb, err_t err){ - return reinterpret_cast(arg)->_recv(pcb, pb, err); -} -#endif diff --git a/lib/ESPAsyncTCP/src/ESPAsyncTCP.h b/lib/ESPAsyncTCP/src/ESPAsyncTCP.h deleted file mode 100644 index 2d1f768f0..000000000 --- a/lib/ESPAsyncTCP/src/ESPAsyncTCP.h +++ /dev/null @@ -1,327 +0,0 @@ -/* - 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 -#include "IPAddress.h" -#include -#include - -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 AcConnectHandler; -typedef std::function AcAckHandler; -typedef std::function AcErrorHandler; -typedef std::function AcDataHandler; -typedef std::function AcPacketHandler; -typedef std::function AcTimeoutHandler; -typedef std::function 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 _errorTracker; - - void _close(); - void _connected(std::shared_ptr& 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& closeAbort, tcp_pcb* pcb); - void _sent(std::shared_ptr& 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 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& 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 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_ */ diff --git a/lib/ESPAsyncTCP/src/ESPAsyncTCPbuffer.cpp b/lib/ESPAsyncTCP/src/ESPAsyncTCPbuffer.cpp deleted file mode 100644 index 9dc2985a6..000000000 --- a/lib/ESPAsyncTCP/src/ESPAsyncTCPbuffer.cpp +++ /dev/null @@ -1,557 +0,0 @@ -/** - * @file ESPAsyncTCPbuffer.cpp - * @date 22.01.2016 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the Asynv TCP for ESP. - * - * 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 - * - */ - - -#include -#include - -#include "ESPAsyncTCPbuffer.h" - - -AsyncTCPbuffer::AsyncTCPbuffer(AsyncClient * client) { - if (client == NULL) { - DEBUG_ASYNC_TCP("[A-TCP] client is null!!!\n"); - panic(); - } - - _client = client; - _TXbufferWrite = new (std::nothrow) cbuf(TCP_MSS); - _TXbufferRead = _TXbufferWrite; - _RXbuffer = new (std::nothrow) cbuf(100); - _RXmode = ATB_RX_MODE_FREE; - _rxSize = 0; - _rxTerminator = 0x00; - _rxReadBytesPtr = NULL; - _rxReadStringPtr = NULL; - _cbDisconnect = NULL; - - _cbRX = NULL; - _cbDone = NULL; - _attachCallbacks(); -} - -AsyncTCPbuffer::~AsyncTCPbuffer() { - if (_client) { - _client->close(); - } - - if (_RXbuffer) { - delete _RXbuffer; - _RXbuffer = NULL; - } - - if (_TXbufferWrite) { - // will be deleted in _TXbufferRead chain - _TXbufferWrite = NULL; - } - - if (_TXbufferRead) { - cbuf * next = _TXbufferRead->next; - delete _TXbufferRead; - while (next != NULL) { - _TXbufferRead = next; - next = _TXbufferRead->next; - delete _TXbufferRead; - } - _TXbufferRead = NULL; - } -} - -size_t AsyncTCPbuffer::write(String & data) { - return write(data.c_str(), data.length()); -} - -size_t AsyncTCPbuffer::write(uint8_t data) { - return write(&data, 1); -} - -size_t AsyncTCPbuffer::write(const char * data) { - return write((const uint8_t *)data, strlen(data)); -} - -size_t AsyncTCPbuffer::write(const char * data, size_t len) { - return write((const uint8_t *)data, len); -} - -/** - * write data in to buffer and try to send the data - * @param data - * @param len - * @return - */ -size_t AsyncTCPbuffer::write(const uint8_t * data, size_t len) { - if (_TXbufferWrite == NULL || _client == NULL || !_client->connected() || data == NULL || len == 0) { - return 0; - } - - size_t bytesLeft = len; - while (bytesLeft) { - size_t w = _TXbufferWrite->write((const char *)data, bytesLeft); - bytesLeft -= w; - data += w; - _sendBuffer(); - - // add new buffer since we have more data - if (_TXbufferWrite->full() && bytesLeft > 0) { - // to less ram!!! - if (ESP.getFreeHeap() < 4096) { - DEBUG_ASYNC_TCP("[A-TCP] run out of Heap can not send all Data!\n"); - return (len - bytesLeft); - } - - cbuf * next = new (std::nothrow) cbuf(TCP_MSS); - if (next == NULL) { - DEBUG_ASYNC_TCP("[A-TCP] run out of Heap!\n"); - panic(); - } else { - DEBUG_ASYNC_TCP("[A-TCP] new cbuf\n"); - } - - // add new buffer to chain (current cbuf) - _TXbufferWrite->next = next; - - // move ptr for next data - _TXbufferWrite = next; - } - } - - return len; -} - -/** - * wait until all data has send out - */ -void AsyncTCPbuffer::flush() { - while (!_TXbufferWrite->empty()) { - while (connected() && !_client->canSend()) { - delay(0); - } - if (!connected()) - return; - _sendBuffer(); - } -} - -void AsyncTCPbuffer::noCallback() { - _RXmode = ATB_RX_MODE_NONE; -} - -void AsyncTCPbuffer::readStringUntil(char terminator, String * str, AsyncTCPbufferDoneCb done) { - if (_client == NULL) { - return; - } - DEBUG_ASYNC_TCP("[A-TCP] readStringUntil terminator: %02X\n", terminator); - _RXmode = ATB_RX_MODE_NONE; - _cbDone = done; - _rxReadStringPtr = str; - _rxTerminator = terminator; - _rxSize = 0; - _RXmode = ATB_RX_MODE_TERMINATOR_STRING; -} - -/* - void AsyncTCPbuffer::readBytesUntil(char terminator, char *buffer, size_t length, AsyncTCPbufferDoneCb done) { - _RXmode = ATB_RX_MODE_NONE; - _cbDone = done; - _rxReadBytesPtr = (uint8_t *) buffer; - _rxTerminator = terminator; - _rxSize = length; - _RXmode = ATB_RX_MODE_TERMINATOR; - _handleRxBuffer(NULL, 0); - } - - void AsyncTCPbuffer::readBytesUntil(char terminator, uint8_t *buffer, size_t length, AsyncTCPbufferDoneCb done) { - readBytesUntil(terminator, (char *) buffer, length, done); - } - */ - -void AsyncTCPbuffer::readBytes(char * buffer, size_t length, AsyncTCPbufferDoneCb done) { - if (_client == NULL) { - return; - } - DEBUG_ASYNC_TCP("[A-TCP] readBytes length: %d\n", length); - _RXmode = ATB_RX_MODE_NONE; - _cbDone = done; - _rxReadBytesPtr = (uint8_t *)buffer; - _rxSize = length; - _RXmode = ATB_RX_MODE_READ_BYTES; -} - -void AsyncTCPbuffer::readBytes(uint8_t * buffer, size_t length, AsyncTCPbufferDoneCb done) { - readBytes((char *)buffer, length, done); -} - -void AsyncTCPbuffer::onData(AsyncTCPbufferDataCb cb) { - if (_client == NULL) { - return; - } - DEBUG_ASYNC_TCP("[A-TCP] onData\n"); - _RXmode = ATB_RX_MODE_NONE; - _cbDone = NULL; - _cbRX = cb; - _RXmode = ATB_RX_MODE_FREE; -} - -void AsyncTCPbuffer::onDisconnect(AsyncTCPbufferDisconnectCb cb) { - _cbDisconnect = cb; -} - -IPAddress AsyncTCPbuffer::remoteIP() { - if (!_client) { - return IPAddress(0U); - } - return _client->remoteIP(); -} - -uint16_t AsyncTCPbuffer::remotePort() { - if (!_client) { - return 0; - } - return _client->remotePort(); -} - -bool AsyncTCPbuffer::connected() { - if (!_client) { - return false; - } - return _client->connected(); -} - -void AsyncTCPbuffer::stop() { - if (!_client) { - return; - } - _client->stop(); - _client = NULL; - - if (_cbDone) { - switch (_RXmode) { - case ATB_RX_MODE_READ_BYTES: - case ATB_RX_MODE_TERMINATOR: - case ATB_RX_MODE_TERMINATOR_STRING: - _RXmode = ATB_RX_MODE_NONE; - _cbDone(false, NULL); - break; - default: - break; - } - } - _RXmode = ATB_RX_MODE_NONE; -} - -void AsyncTCPbuffer::close() { - stop(); -} - - -///-------------------------------- - -/** - * attachCallbacks to AsyncClient class - */ -void AsyncTCPbuffer::_attachCallbacks() { - if (!_client) { - return; - } - DEBUG_ASYNC_TCP("[A-TCP] attachCallbacks\n"); - - _client->onPoll( - [](void * obj, AsyncClient * c) { - (void)c; - AsyncTCPbuffer * b = ((AsyncTCPbuffer *)(obj)); - if ((b->_TXbufferRead != NULL) && !b->_TXbufferRead->empty()) { - b->_sendBuffer(); - } - // if(!b->_RXbuffer->empty()) { - // b->_handleRxBuffer(NULL, 0); - // } - }, - this); - - _client->onAck( - [](void * obj, AsyncClient * c, size_t len, uint32_t time) { - (void)c; - (void)len; - (void)time; - DEBUG_ASYNC_TCP("[A-TCP] onAck\n"); - ((AsyncTCPbuffer *)(obj))->_sendBuffer(); - }, - this); - - _client->onDisconnect( - [](void * obj, AsyncClient * c) { - DEBUG_ASYNC_TCP("[A-TCP] onDisconnect\n"); - AsyncTCPbuffer * b = ((AsyncTCPbuffer *)(obj)); - b->_client = NULL; - bool del = true; - if (b->_cbDisconnect) { - del = b->_cbDisconnect(b); - } - delete c; - if (del) { - delete b; - } - }, - this); - - _client->onData( - [](void * obj, AsyncClient * c, void * buf, size_t len) { - (void)c; - AsyncTCPbuffer * b = ((AsyncTCPbuffer *)(obj)); - b->_rxData((uint8_t *)buf, len); - }, - this); - - _client->onTimeout( - [](void * obj, AsyncClient * c, uint32_t time) { - (void)obj; - (void)time; - DEBUG_ASYNC_TCP("[A-TCP] onTimeout\n"); - c->close(); - }, - this); - - DEBUG_ASYNC_TCP("[A-TCP] attachCallbacks Done.\n"); -} - -/** - * send TX buffer if possible - */ -void AsyncTCPbuffer::_sendBuffer() { - //DEBUG_ASYNC_TCP("[A-TCP] _sendBuffer...\n"); - size_t available = _TXbufferRead->available(); - if (available == 0 || _client == NULL || !_client->connected() || !_client->canSend()) { - return; - } - - while (connected() && (_client->space() > 0) && (_TXbufferRead->available() > 0) && _client->canSend()) { - available = _TXbufferRead->available(); - - if (available > _client->space()) { - available = _client->space(); - } - - char * out = new (std::nothrow) char[available]; - if (out == NULL) { - DEBUG_ASYNC_TCP("[A-TCP] to less heap, try later.\n"); - return; - } - - // read data from buffer - _TXbufferRead->peek(out, available); - - // send data - size_t send = _client->write((const char *)out, available); - if (send != available) { - DEBUG_ASYNC_TCP("[A-TCP] write failed send: %d available: %d \n", send, available); - if (!connected()) { - DEBUG_ASYNC_TCP("[A-TCP] incomplete transfer, connection lost.\n"); - } - } - - // remove really send data from buffer - _TXbufferRead->remove(send); - - // if buffer is empty and there is a other buffer in chain delete the empty one - if (_TXbufferRead->available() == 0 && _TXbufferRead->next != NULL) { - cbuf * old = _TXbufferRead; - _TXbufferRead = _TXbufferRead->next; - delete old; - DEBUG_ASYNC_TCP("[A-TCP] delete cbuf\n"); - } - - delete out; - } -} - -/** - * called on incoming data - * @param buf - * @param len - */ -void AsyncTCPbuffer::_rxData(uint8_t * buf, size_t len) { - if (!_client || !_client->connected()) { - DEBUG_ASYNC_TCP("[A-TCP] not connected!\n"); - return; - } - if (!_RXbuffer) { - DEBUG_ASYNC_TCP("[A-TCP] _rxData no _RXbuffer!\n"); - return; - } - DEBUG_ASYNC_TCP("[A-TCP] _rxData len: %d RXmode: %d\n", len, _RXmode); - - size_t handled = 0; - - if (_RXmode != ATB_RX_MODE_NONE) { - handled = _handleRxBuffer((uint8_t *)buf, len); - buf += handled; - len -= handled; - - // handle as much as possible before using the buffer - if (_RXbuffer->empty()) { - while (_RXmode != ATB_RX_MODE_NONE && handled != 0 && len > 0) { - handled = _handleRxBuffer(buf, len); - buf += handled; - len -= handled; - } - } - } - - if (len > 0) { - if (_RXbuffer->room() < len) { - // to less space - DEBUG_ASYNC_TCP("[A-TCP] _rxData buffer full try resize\n"); - _RXbuffer->resizeAdd((len + _RXbuffer->room())); - - if (_RXbuffer->room() < len) { - DEBUG_ASYNC_TCP("[A-TCP] _rxData buffer to full can only handle %d!!!\n", _RXbuffer->room()); - } - } - - _RXbuffer->write((const char *)(buf), len); - } - - if (!_RXbuffer->empty() && _RXmode != ATB_RX_MODE_NONE) { - // handle as much as possible data in buffer - handled = _handleRxBuffer(NULL, 0); - while (_RXmode != ATB_RX_MODE_NONE && handled != 0) { - handled = _handleRxBuffer(NULL, 0); - } - } - - // clean up ram - if (_RXbuffer->empty() && _RXbuffer->room() != 100) { - _RXbuffer->resize(100); - } -} - -/** - * - */ -size_t AsyncTCPbuffer::_handleRxBuffer(uint8_t * buf, size_t len) { - if (!_client || !_client->connected() || _RXbuffer == NULL) { - return 0; - } - - DEBUG_ASYNC_TCP("[A-TCP] _handleRxBuffer len: %d RXmode: %d\n", len, _RXmode); - - size_t BufferAvailable = _RXbuffer->available(); - size_t r = 0; - - if (_RXmode == ATB_RX_MODE_NONE) { - return 0; - } else if (_RXmode == ATB_RX_MODE_FREE) { - if (_cbRX == NULL) { - return 0; - } - - if (BufferAvailable > 0) { - uint8_t * b = new (std::nothrow) uint8_t[BufferAvailable]; - if (b == NULL) { - panic(); - } - _RXbuffer->peek((char *)b, BufferAvailable); - r = _cbRX(b, BufferAvailable); - _RXbuffer->remove(r); - } - - if (r == BufferAvailable && buf && (len > 0)) { - return _cbRX(buf, len); - } else { - return 0; - } - - } else if (_RXmode == ATB_RX_MODE_READ_BYTES) { - if (_rxReadBytesPtr == NULL || _cbDone == NULL) { - return 0; - } - - size_t newReadCount = 0; - - if (BufferAvailable) { - r = _RXbuffer->read((char *)_rxReadBytesPtr, _rxSize); - _rxSize -= r; - _rxReadBytesPtr += r; - } - - if (_RXbuffer->empty() && (len > 0) && buf) { - r = len; - if (r > _rxSize) { - r = _rxSize; - } - memcpy(_rxReadBytesPtr, buf, r); - _rxReadBytesPtr += r; - _rxSize -= r; - newReadCount += r; - } - - if (_rxSize == 0) { - _RXmode = ATB_RX_MODE_NONE; - _cbDone(true, NULL); - } - - // add left over bytes to Buffer - return newReadCount; - - } else if (_RXmode == ATB_RX_MODE_TERMINATOR) { - // - } else if (_RXmode == ATB_RX_MODE_TERMINATOR_STRING) { - if (_rxReadStringPtr == NULL || _cbDone == NULL) { - return 0; - } - - // handle Buffer - if (BufferAvailable > 0) { - while (!_RXbuffer->empty()) { - char c = _RXbuffer->read(); - if (c == _rxTerminator || c == 0x00) { - _RXmode = ATB_RX_MODE_NONE; - _cbDone(true, _rxReadStringPtr); - return 0; - } else { - (*_rxReadStringPtr) += c; - } - } - } - - if (_RXbuffer->empty() && (len > 0) && buf) { - size_t newReadCount = 0; - while (newReadCount < len) { - char c = (char)*buf; - buf++; - newReadCount++; - if (c == _rxTerminator || c == 0x00) { - _RXmode = ATB_RX_MODE_NONE; - _cbDone(true, _rxReadStringPtr); - return newReadCount; - } else { - (*_rxReadStringPtr) += c; - } - } - return newReadCount; - } - } - - return 0; -} diff --git a/lib/ESPAsyncTCP/src/ESPAsyncTCPbuffer.h b/lib/ESPAsyncTCP/src/ESPAsyncTCPbuffer.h deleted file mode 100644 index 7a37de64b..000000000 --- a/lib/ESPAsyncTCP/src/ESPAsyncTCPbuffer.h +++ /dev/null @@ -1,107 +0,0 @@ -/** - * @file ESPAsyncTCPbuffer.h - * @date 22.01.2016 - * @author Markus Sattler - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the Asynv TCP for ESP. - * - * 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 ESPASYNCTCPBUFFER_H_ -#define ESPASYNCTCPBUFFER_H_ - -//#define DEBUG_ASYNC_TCP(...) while(((U0S >> USTXC) & 0x7F) != 0x00); os_printf( __VA_ARGS__ ); while(((U0S >> USTXC) & 0x7F) != 0x00) -//#define DEBUG_ASYNC_TCP ASYNC_TCP_DEBUG -#ifndef DEBUG_ASYNC_TCP -#define DEBUG_ASYNC_TCP(...) -#endif - -#include -#include - -#include "ESPAsyncTCP.h" - - - -typedef enum { ATB_RX_MODE_NONE, ATB_RX_MODE_FREE, ATB_RX_MODE_READ_BYTES, ATB_RX_MODE_TERMINATOR, ATB_RX_MODE_TERMINATOR_STRING } atbRxMode_t; - -class AsyncTCPbuffer : public Print { - public: - typedef std::function AsyncTCPbufferDataCb; - typedef std::function AsyncTCPbufferDoneCb; - typedef std::function AsyncTCPbufferDisconnectCb; - - AsyncTCPbuffer(AsyncClient * c); - virtual ~AsyncTCPbuffer(); - - size_t write(String & data); - size_t write(uint8_t data); - size_t write(const char * data); - size_t write(const char * data, size_t len); - size_t write(const uint8_t * data, size_t len); - - void flush(); - - void noCallback(); - - void readStringUntil(char terminator, String * str, AsyncTCPbufferDoneCb done); - - //void readBytesUntil(char terminator, char *buffer, size_t length, AsyncTCPbufferDoneCb done); - //void readBytesUntil(char terminator, uint8_t *buffer, size_t length, AsyncTCPbufferDoneCb done); - - void readBytes(char * buffer, size_t length, AsyncTCPbufferDoneCb done); - void readBytes(uint8_t * buffer, size_t length, AsyncTCPbufferDoneCb done); - - // void setTimeout(size_t timeout); - - void onData(AsyncTCPbufferDataCb cb); - void onDisconnect(AsyncTCPbufferDisconnectCb cb); - - IPAddress remoteIP(); - uint16_t remotePort(); - IPAddress localIP(); - uint16_t localPort(); - - bool connected(); - - void stop(); - void close(); - - protected: - AsyncClient * _client; - cbuf * _TXbufferRead; - cbuf * _TXbufferWrite; - cbuf * _RXbuffer; - atbRxMode_t _RXmode; - size_t _rxSize; - char _rxTerminator; - uint8_t * _rxReadBytesPtr; - String * _rxReadStringPtr; - - AsyncTCPbufferDataCb _cbRX; - AsyncTCPbufferDoneCb _cbDone; - AsyncTCPbufferDisconnectCb _cbDisconnect; - - void _attachCallbacks(); - void _sendBuffer(); - void _on_close(); - void _rxData(uint8_t * buf, size_t len); - size_t _handleRxBuffer(uint8_t * buf, size_t len); -}; - -#endif /* ESPASYNCTCPBUFFER_H_ */ diff --git a/lib/ESPAsyncTCP/src/SyncClient.cpp b/lib/ESPAsyncTCP/src/SyncClient.cpp deleted file mode 100644 index 8335358e3..000000000 --- a/lib/ESPAsyncTCP/src/SyncClient.cpp +++ /dev/null @@ -1,414 +0,0 @@ -/* - 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 -*/ -#include "Arduino.h" -#include "SyncClient.h" -#include "ESPAsyncTCP.h" -#include "cbuf.h" -#include - -#define DEBUG_ESP_SYNC_CLIENT -#if defined(DEBUG_ESP_SYNC_CLIENT) && !defined(SYNC_CLIENT_DEBUG) -#define SYNC_CLIENT_DEBUG( format, ...) DEBUG_GENERIC_P("[SYNC_CLIENT]", format, ##__VA_ARGS__) -#endif -#ifndef SYNC_CLIENT_DEBUG -#define SYNC_CLIENT_DEBUG(...) do { (void)0;} while(false) -#endif - -/* - Without LWIP_NETIF_TX_SINGLE_PBUF, all tcp_writes default to "no copy". - Referenced data must be preserved and free-ed from the specified tcp_sent() - callback. Alternative, tcp_writes need to use the TCP_WRITE_FLAG_COPY - attribute. -*/ -static_assert(LWIP_NETIF_TX_SINGLE_PBUF, "Required, tcp_write() must always copy."); - -SyncClient::SyncClient(size_t txBufLen) - : _client(NULL) - , _tx_buffer(NULL) - , _tx_buffer_size(txBufLen) - , _rx_buffer(NULL) - , _ref(NULL) -{ - ref(); -} - -SyncClient::SyncClient(AsyncClient *client, size_t txBufLen) - : _client(client) - , _tx_buffer(new (std::nothrow) cbuf(txBufLen)) - , _tx_buffer_size(txBufLen) - , _rx_buffer(NULL) - , _ref(NULL) -{ - if(ref() > 0 && _client != NULL) - _attachCallbacks(); -} - -SyncClient::~SyncClient(){ - if (0 == unref()) - _release(); -} - -void SyncClient::_release(){ - if(_client != NULL){ - _client->onData(NULL, NULL); - _client->onAck(NULL, NULL); - _client->onPoll(NULL, NULL); - _client->abort(); - _client = NULL; - } - if(_tx_buffer != NULL){ - cbuf *b = _tx_buffer; - _tx_buffer = NULL; - delete b; - } - while(_rx_buffer != NULL){ - cbuf *b = _rx_buffer; - _rx_buffer = _rx_buffer->next; - delete b; - } -} - -int SyncClient::ref(){ - if(_ref == NULL){ - _ref = new (std::nothrow) int; - if(_ref != NULL) - *_ref = 0; - else - return -1; - } - return (++*_ref); -} - -int SyncClient::unref(){ - int count = -1; - if (_ref != NULL) { - count = --*_ref; - if (0 == count) { - delete _ref; - _ref = NULL; - } - } - return count; -} - -#if ASYNC_TCP_SSL_ENABLED -int SyncClient::_connect(const IPAddress& ip, uint16_t port, bool secure){ -#else -int SyncClient::_connect(const IPAddress& ip, uint16_t port){ -#endif - if(connected()) - return 0; - if(_client != NULL) - delete _client; - - _client = new (std::nothrow) AsyncClient(); - if (_client == NULL) - return 0; - - _client->onConnect([](void *obj, AsyncClient *c){ ((SyncClient*)(obj))->_onConnect(c); }, this); - _attachCallbacks_Disconnect(); -#if ASYNC_TCP_SSL_ENABLED - if(_client->connect(ip, port, secure)){ -#else - if(_client->connect(ip, port)){ -#endif - while(_client != NULL && !_client->connected() && !_client->disconnecting()) - delay(1); - return connected(); - } - return 0; -} - -#if ASYNC_TCP_SSL_ENABLED -int SyncClient::connect(const char *host, uint16_t port, bool secure){ -#else -int SyncClient::connect(const char *host, uint16_t port){ -#endif - if(connected()) - return 0; - if(_client != NULL) - delete _client; - - _client = new (std::nothrow) AsyncClient(); - if (_client == NULL) - return 0; - - _client->onConnect([](void *obj, AsyncClient *c){ ((SyncClient*)(obj))->_onConnect(c); }, this); - _attachCallbacks_Disconnect(); -#if ASYNC_TCP_SSL_ENABLED - if(_client->connect(host, port, secure)){ -#else - if(_client->connect(host, port)){ -#endif - while(_client != NULL && !_client->connected() && !_client->disconnecting()) - delay(1); - return connected(); - } - return 0; -} -//#define SYNCCLIENT_NEW_OPERATOR_EQUAL -#ifdef SYNCCLIENT_NEW_OPERATOR_EQUAL -/* - New behavior for operator= - - Allow for the object to be placed on a queue and transfered to a new container - with buffers still in tact. Avoiding receive data drops. Transfers rx and tx - buffers. Supports return by value. - - Note, this is optional, the old behavior is the default. - -*/ -SyncClient & SyncClient::operator=(const SyncClient &other){ - int *rhsref = other._ref; - ++*rhsref; // Just in case the left and right side are the same object with different containers - if (0 == unref()) - _release(); - _ref = other._ref; - ref(); - --*rhsref; - // Why do I not test _tx_buffer for != NULL and free? - // I allow for the lh target container, to be a copy of an active - // connection. Thus we are just reusing the container. - // The above unref() handles releaseing the previous client of the container. - _tx_buffer_size = other._tx_buffer_size; - _tx_buffer = other._tx_buffer; - _client = other._client; - if (_client != NULL && _tx_buffer == NULL) - _tx_buffer = new (std::nothrow) cbuf(_tx_buffer_size); - - _rx_buffer = other._rx_buffer; - if(_client) - _attachCallbacks(); - return *this; -} -#else // ! SYNCCLIENT_NEW_OPERATOR_EQUAL -// This is the origianl logic with null checks -SyncClient & SyncClient::operator=(const SyncClient &other){ - if(_client != NULL){ - _client->abort(); - _client->free(); - _client = NULL; - } - _tx_buffer_size = other._tx_buffer_size; - if(_tx_buffer != NULL){ - cbuf *b = _tx_buffer; - _tx_buffer = NULL; - delete b; - } - while(_rx_buffer != NULL){ - cbuf *b = _rx_buffer; - _rx_buffer = b->next; - delete b; - } - if(other._client != NULL) - _tx_buffer = new (std::nothrow) cbuf(other._tx_buffer_size); - - _client = other._client; - if(_client) - _attachCallbacks(); - - return *this; -} -#endif - -void SyncClient::setTimeout(uint32_t seconds){ - if(_client != NULL) - _client->setRxTimeout(seconds); -} - -uint8_t SyncClient::status(){ - if(_client == NULL) - return 0; - return _client->state(); -} - -uint8_t SyncClient::connected(){ - return (_client != NULL && _client->connected()); -} - -bool SyncClient::stop(unsigned int maxWaitMs){ - (void)maxWaitMs; - if(_client != NULL) - _client->close(true); - return true; -} - -size_t SyncClient::_sendBuffer(){ - if(_client == NULL || _tx_buffer == NULL) - return 0; - size_t available = _tx_buffer->available(); - if(!connected() || !_client->canSend() || available == 0) - return 0; - size_t sendable = _client->space(); - if(sendable < available) - available= sendable; - char *out = new (std::nothrow) char[available]; - if(out == NULL) - return 0; - - _tx_buffer->read(out, available); - size_t sent = _client->write(out, available); - delete[] out; - return sent; -} - -void SyncClient::_onData(void *data, size_t len){ - _client->ackLater(); - cbuf *b = new (std::nothrow) cbuf(len+1); - if(b != NULL){ - b->write((const char *)data, len); - if(_rx_buffer == NULL) - _rx_buffer = b; - else { - cbuf *p = _rx_buffer; - while(p->next != NULL) - p = p->next; - p->next = b; - } - } else { - // We ran out of memory. This fail causes lost receive data. - // The connection should be closed in a manner that conveys something - // bad/abnormal has happened to the connection. Hence, we abort the - // connection to avoid possible data corruption. - // Note, callbacks maybe called. - _client->abort(); - } -} - -void SyncClient::_onDisconnect(){ - if(_client != NULL){ - _client = NULL; - } - if(_tx_buffer != NULL){ - cbuf *b = _tx_buffer; - _tx_buffer = NULL; - delete b; - } -} - -void SyncClient::_onConnect(AsyncClient *c){ - _client = c; - if(_tx_buffer != NULL){ - cbuf *b = _tx_buffer; - _tx_buffer = NULL; - delete b; - } - _tx_buffer = new (std::nothrow) cbuf(_tx_buffer_size); - _attachCallbacks_AfterConnected(); -} - -void SyncClient::_attachCallbacks(){ - _attachCallbacks_Disconnect(); - _attachCallbacks_AfterConnected(); -} - -void SyncClient::_attachCallbacks_AfterConnected(){ - _client->onAck([](void *obj, AsyncClient* c, size_t len, uint32_t time){ (void)c; (void)len; (void)time; ((SyncClient*)(obj))->_sendBuffer(); }, this); - _client->onData([](void *obj, AsyncClient* c, void *data, size_t len){ (void)c; ((SyncClient*)(obj))->_onData(data, len); }, this); - _client->onTimeout([](void *obj, AsyncClient* c, uint32_t time){ (void)obj; (void)time; c->close(); }, this); -} - -void SyncClient::_attachCallbacks_Disconnect(){ - _client->onDisconnect([](void *obj, AsyncClient* c){ ((SyncClient*)(obj))->_onDisconnect(); delete c; }, this); -} - -size_t SyncClient::write(uint8_t data){ - return write(&data, 1); -} - -size_t SyncClient::write(const uint8_t *data, size_t len){ - if(_tx_buffer == NULL || !connected()){ - return 0; - } - size_t toWrite = 0; - size_t toSend = len; - while(_tx_buffer->room() < toSend){ - toWrite = _tx_buffer->room(); - _tx_buffer->write((const char*)data, toWrite); - while(connected() && !_client->canSend()) - delay(0); - if(!connected()) - return 0; - _sendBuffer(); - toSend -= toWrite; - } - _tx_buffer->write((const char*)(data+(len - toSend)), toSend); - if(connected() && _client->canSend()) - _sendBuffer(); - return len; -} - -int SyncClient::available(){ - if(_rx_buffer == NULL) return 0; - size_t a = 0; - cbuf *b = _rx_buffer; - while(b != NULL){ - a += b->available(); - b = b->next; - } - return a; -} - -int SyncClient::peek(){ - if(_rx_buffer == NULL) return -1; - return _rx_buffer->peek(); -} - -int SyncClient::read(uint8_t *data, size_t len){ - if(_rx_buffer == NULL) return -1; - - size_t readSoFar = 0; - while(_rx_buffer != NULL && (len - readSoFar) >= _rx_buffer->available()){ - cbuf *b = _rx_buffer; - _rx_buffer = _rx_buffer->next; - size_t toRead = b->available(); - readSoFar += b->read((char*)(data+readSoFar), toRead); - if(connected()){ - _client->ack(b->size() - 1); - } - delete b; - } - if(_rx_buffer != NULL && readSoFar < len){ - readSoFar += _rx_buffer->read((char*)(data+readSoFar), (len - readSoFar)); - } - return readSoFar; -} - -int SyncClient::read(){ - uint8_t res = 0; - if(read(&res, 1) != 1) - return -1; - return res; -} - -bool SyncClient::flush(unsigned int maxWaitMs){ - (void)maxWaitMs; - if(_tx_buffer == NULL || !connected()) - return false; - if(_tx_buffer->available()){ - while(connected() && !_client->canSend()) - delay(0); - if(_client == NULL || _tx_buffer == NULL) - return false; - _sendBuffer(); - } - return true; -} diff --git a/lib/ESPAsyncTCP/src/SyncClient.h b/lib/ESPAsyncTCP/src/SyncClient.h deleted file mode 100644 index cb568de45..000000000 --- a/lib/ESPAsyncTCP/src/SyncClient.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - 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 SYNCCLIENT_H_ -#define SYNCCLIENT_H_ - -#include "Client.h" -// Needed for Arduino core releases prior to 2.5.0, because of changes -// made to accommodate Arduino core 2.5.0 -// CONST was 1st defined in Core 2.5.0 in IPAddress.h -#ifndef CONST -#define CONST -#endif -#include -class cbuf; -class AsyncClient; - -class SyncClient: public Client { - private: - AsyncClient *_client; - cbuf *_tx_buffer; - size_t _tx_buffer_size; - cbuf *_rx_buffer; - int *_ref; - - size_t _sendBuffer(); - void _onData(void *data, size_t len); - void _onConnect(AsyncClient *c); - void _onDisconnect(); - void _attachCallbacks(); - void _attachCallbacks_Disconnect(); - void _attachCallbacks_AfterConnected(); - void _release(); - - public: - SyncClient(size_t txBufLen = TCP_MSS); - SyncClient(AsyncClient *client, size_t txBufLen = TCP_MSS); - virtual ~SyncClient(); - - int ref(); - int unref(); - operator bool(){ return connected(); } - SyncClient & operator=(const SyncClient &other); - -#if ASYNC_TCP_SSL_ENABLED - int _connect(const IPAddress& ip, uint16_t port, bool secure); - int connect(CONST IPAddress& ip, uint16_t port, bool secure){ - return _connect(ip, port, secure); - } - int connect(IPAddress ip, uint16_t port, bool secure){ - return _connect(reinterpret_cast(ip), port, secure); - } - int connect(const char *host, uint16_t port, bool secure); - int connect(CONST IPAddress& ip, uint16_t port){ - return _connect(ip, port, false); - } - int connect(IPAddress ip, uint16_t port){ - return _connect(reinterpret_cast(ip), port, false); - } - int connect(const char *host, uint16_t port){ - return connect(host, port, false); - } -#else - int _connect(const IPAddress& ip, uint16_t port); - int connect(CONST IPAddress& ip, uint16_t port){ - return _connect(ip, port); - } - int connect(IPAddress ip, uint16_t port){ - return _connect(reinterpret_cast(ip), port); - } - int connect(const char *host, uint16_t port); -#endif - void setTimeout(uint32_t seconds); - - uint8_t status(); - uint8_t connected(); - - bool stop(unsigned int maxWaitMs); - bool flush(unsigned int maxWaitMs); - void stop() { (void)stop(0);} - void flush() { (void)flush(0);} - size_t write(uint8_t data); - size_t write(const uint8_t *data, size_t len); - - int available(); - int peek(); - int read(); - int read(uint8_t *data, size_t len); -}; - -#endif /* SYNCCLIENT_H_ */ diff --git a/lib/ESPAsyncTCP/src/async_config.h b/lib/ESPAsyncTCP/src/async_config.h deleted file mode 100644 index ca6912f0a..000000000 --- a/lib/ESPAsyncTCP/src/async_config.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef LIBRARIES_ESPASYNCTCP_SRC_ASYNC_CONFIG_H_ -#define LIBRARIES_ESPASYNCTCP_SRC_ASYNC_CONFIG_H_ - -#ifndef ASYNC_TCP_SSL_ENABLED -#define ASYNC_TCP_SSL_ENABLED 0 -#endif - -#ifndef TCP_MSS -// May have been definded as a -DTCP_MSS option on the compile line or not. -// Arduino core 2.3.0 or earlier does not do the -DTCP_MSS option. -// Later versions may set this option with info from board.txt. -// However, Core 2.4.0 and up board.txt does not define TCP_MSS for lwIP v1.4 -#define TCP_MSS (1460) -#endif - -// #define ASYNC_TCP_DEBUG(...) ets_printf(__VA_ARGS__) -// #define TCP_SSL_DEBUG(...) ets_printf(__VA_ARGS__) -// #define ASYNC_TCP_ASSERT( a ) do{ if(!(a)){ets_printf("ASSERT: %s %u \n", __FILE__, __LINE__);}}while(0) - -// Starting with Arduino Core 2.4.0 and up the define of DEBUG_ESP_PORT -// can be handled through the Arduino IDE Board options instead of here. -// #define DEBUG_ESP_PORT Serial - -// #define DEBUG_ESP_ASYNC_TCP 1 -// #define DEBUG_ESP_TCP_SSL 1 -#include - -#ifndef ASYNC_TCP_ASSERT -#define ASYNC_TCP_ASSERT(...) do { (void)0;} while(false) -#endif -#ifndef ASYNC_TCP_DEBUG -#define ASYNC_TCP_DEBUG(...) do { (void)0;} while(false) -#endif -#ifndef TCP_SSL_DEBUG -#define TCP_SSL_DEBUG(...) do { (void)0;} while(false) -#endif - -#endif /* LIBRARIES_ESPASYNCTCP_SRC_ASYNC_CONFIG_H_ */ diff --git a/lib/ESPAsyncTCP/src/tcp_axtls.c b/lib/ESPAsyncTCP/src/tcp_axtls.c deleted file mode 100644 index cdbdf417e..000000000 --- a/lib/ESPAsyncTCP/src/tcp_axtls.c +++ /dev/null @@ -1,588 +0,0 @@ -/* - 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 -*/ -/* - * Compatibility for AxTLS with LWIP raw tcp mode (http://lwip.wikia.com/wiki/Raw/TCP) - * Original Code and Inspiration: Slavey Karadzhov - */ -#include -#if ASYNC_TCP_SSL_ENABLED - -#include "lwip/opt.h" -#include "lwip/tcp.h" -#include "lwip/inet.h" -#include -#include -#include -#include -#include - -uint8_t * default_private_key = NULL; -uint16_t default_private_key_len = 0; - -uint8_t * default_certificate = NULL; -uint16_t default_certificate_len = 0; - -static uint8_t _tcp_ssl_has_client = 0; - -SSL_CTX * tcp_ssl_new_server_ctx(const char *cert, const char *private_key_file, const char *password){ - uint32_t options = SSL_CONNECT_IN_PARTS; - SSL_CTX *ssl_ctx; - - if(private_key_file){ - options |= SSL_NO_DEFAULT_KEY; - } - - if ((ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_SVR_SESS)) == NULL){ - TCP_SSL_DEBUG("tcp_ssl_new_server_ctx: failed to allocate context\n"); - return NULL; - } - - if (private_key_file){ - int obj_type = SSL_OBJ_RSA_KEY; - if (strstr(private_key_file, ".p8")) - obj_type = SSL_OBJ_PKCS8; - else if (strstr(private_key_file, ".p12")) - obj_type = SSL_OBJ_PKCS12; - - if (ssl_obj_load(ssl_ctx, obj_type, private_key_file, password)){ - TCP_SSL_DEBUG("tcp_ssl_new_server_ctx: load private key '%s' failed\n", private_key_file); - return NULL; - } - } - - if (cert){ - if (ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, cert, NULL)){ - TCP_SSL_DEBUG("tcp_ssl_new_server_ctx: load certificate '%s' failed\n", cert); - return NULL; - } - } - return ssl_ctx; -} - -struct tcp_ssl_pcb { - struct tcp_pcb *tcp; - int fd; - SSL_CTX* ssl_ctx; - SSL *ssl; - uint8_t type; - int handshake; - void * arg; - tcp_ssl_data_cb_t on_data; - tcp_ssl_handshake_cb_t on_handshake; - tcp_ssl_error_cb_t on_error; - int last_wr; - struct pbuf *tcp_pbuf; - int pbuf_offset; - struct tcp_ssl_pcb * next; -}; - -typedef struct tcp_ssl_pcb tcp_ssl_t; - -static tcp_ssl_t * tcp_ssl_array = NULL; -static int tcp_ssl_next_fd = 0; - -uint8_t tcp_ssl_has_client(){ - return _tcp_ssl_has_client; -} - -tcp_ssl_t * tcp_ssl_new(struct tcp_pcb *tcp) { - - if(tcp_ssl_next_fd < 0){ - tcp_ssl_next_fd = 0;//overflow - } - - tcp_ssl_t * new_item = (tcp_ssl_t*)malloc(sizeof(tcp_ssl_t)); - if(!new_item){ - TCP_SSL_DEBUG("tcp_ssl_new: failed to allocate tcp_ssl\n"); - return NULL; - } - - new_item->tcp = tcp; - new_item->handshake = SSL_NOT_OK; - new_item->arg = NULL; - new_item->on_data = NULL; - new_item->on_handshake = NULL; - new_item->on_error = NULL; - new_item->tcp_pbuf = NULL; - new_item->pbuf_offset = 0; - new_item->next = NULL; - new_item->ssl_ctx = NULL; - new_item->ssl = NULL; - new_item->type = TCP_SSL_TYPE_CLIENT; - new_item->fd = tcp_ssl_next_fd++; - - if(tcp_ssl_array == NULL){ - tcp_ssl_array = new_item; - } else { - tcp_ssl_t * item = tcp_ssl_array; - while(item->next != NULL) - item = item->next; - item->next = new_item; - } - - TCP_SSL_DEBUG("tcp_ssl_new: %d\n", new_item->fd); - return new_item; -} - -tcp_ssl_t* tcp_ssl_get(struct tcp_pcb *tcp) { - if(tcp == NULL) { - return NULL; - } - tcp_ssl_t * item = tcp_ssl_array; - while(item && item->tcp != tcp){ - item = item->next; - } - return item; -} - -int tcp_ssl_new_client(struct tcp_pcb *tcp){ - SSL_CTX* ssl_ctx; - tcp_ssl_t * tcp_ssl; - - if(tcp == NULL) { - return -1; - } - - if(tcp_ssl_get(tcp) != NULL){ - TCP_SSL_DEBUG("tcp_ssl_new_client: tcp_ssl already exists\n"); - return -1; - } - - ssl_ctx = ssl_ctx_new(SSL_CONNECT_IN_PARTS | SSL_SERVER_VERIFY_LATER, 1); - if(ssl_ctx == NULL){ - TCP_SSL_DEBUG("tcp_ssl_new_client: failed to allocate ssl context\n"); - return -1; - } - - tcp_ssl = tcp_ssl_new(tcp); - if(tcp_ssl == NULL){ - ssl_ctx_free(ssl_ctx); - return -1; - } - - tcp_ssl->ssl_ctx = ssl_ctx; - - tcp_ssl->ssl = ssl_client_new(ssl_ctx, tcp_ssl->fd, NULL, 0, NULL); - if(tcp_ssl->ssl == NULL){ - TCP_SSL_DEBUG("tcp_ssl_new_client: failed to allocate ssl\n"); - tcp_ssl_free(tcp); - return -1; - } - - return tcp_ssl->fd; -} - -int tcp_ssl_new_server(struct tcp_pcb *tcp, SSL_CTX* ssl_ctx){ - tcp_ssl_t * tcp_ssl; - - if(tcp == NULL) { - return -1; - } - - if(ssl_ctx == NULL){ - return -1; - } - - if(tcp_ssl_get(tcp) != NULL){ - TCP_SSL_DEBUG("tcp_ssl_new_server: tcp_ssl already exists\n"); - return -1; - } - - tcp_ssl = tcp_ssl_new(tcp); - if(tcp_ssl == NULL){ - return -1; - } - - tcp_ssl->type = TCP_SSL_TYPE_SERVER; - tcp_ssl->ssl_ctx = ssl_ctx; - - _tcp_ssl_has_client = 1; - tcp_ssl->ssl = ssl_server_new(ssl_ctx, tcp_ssl->fd); - if(tcp_ssl->ssl == NULL){ - TCP_SSL_DEBUG("tcp_ssl_new_server: failed to allocate ssl\n"); - tcp_ssl_free(tcp); - return -1; - } - - return tcp_ssl->fd; -} - -int tcp_ssl_free(struct tcp_pcb *tcp) { - - if(tcp == NULL) { - return -1; - } - - tcp_ssl_t * item = tcp_ssl_array; - - if(item->tcp == tcp){ - tcp_ssl_array = tcp_ssl_array->next; - if(item->tcp_pbuf != NULL){ - pbuf_free(item->tcp_pbuf); - } - TCP_SSL_DEBUG("tcp_ssl_free: %d\n", item->fd); - if(item->ssl) - ssl_free(item->ssl); - if(item->type == TCP_SSL_TYPE_CLIENT && item->ssl_ctx) - ssl_ctx_free(item->ssl_ctx); - if(item->type == TCP_SSL_TYPE_SERVER) - _tcp_ssl_has_client = 0; - free(item); - return 0; - } - - while(item->next && item->next->tcp != tcp) - item = item->next; - - if(item->next == NULL){ - return ERR_TCP_SSL_INVALID_CLIENTFD_DATA;//item not found - } - - tcp_ssl_t * i = item->next; - item->next = i->next; - if(i->tcp_pbuf != NULL){ - pbuf_free(i->tcp_pbuf); - } - TCP_SSL_DEBUG("tcp_ssl_free: %d\n", i->fd); - if(i->ssl) - ssl_free(i->ssl); - if(i->type == TCP_SSL_TYPE_CLIENT && i->ssl_ctx) - ssl_ctx_free(i->ssl_ctx); - if(i->type == TCP_SSL_TYPE_SERVER) - _tcp_ssl_has_client = 0; - free(i); - return 0; -} - -#ifdef AXTLS_2_0_0_SNDBUF -int tcp_ssl_sndbuf(struct tcp_pcb *tcp){ - int expected; - int available; - int result = -1; - - if(tcp == NULL) { - return result; - } - tcp_ssl_t * tcp_ssl = tcp_ssl_get(tcp); - if(!tcp_ssl){ - TCP_SSL_DEBUG("tcp_ssl_sndbuf: tcp_ssl is NULL\n"); - return result; - } - available = tcp_sndbuf(tcp); - if(!available){ - TCP_SSL_DEBUG("tcp_ssl_sndbuf: tcp_sndbuf is zero\n"); - return 0; - } - result = available; - while((expected = ssl_calculate_write_length(tcp_ssl->ssl, result)) > available){ - result -= (expected - available) + 4; - } - - if(expected > 0){ - //TCP_SSL_DEBUG("tcp_ssl_sndbuf: tcp_sndbuf is %d from %d\n", result, available); - return result; - } - - return 0; -} -#endif - -int tcp_ssl_write(struct tcp_pcb *tcp, uint8_t *data, size_t len) { - if(tcp == NULL) { - return -1; - } - tcp_ssl_t * tcp_ssl = tcp_ssl_get(tcp); - if(!tcp_ssl){ - TCP_SSL_DEBUG("tcp_ssl_write: tcp_ssl is NULL\n"); - return 0; - } - tcp_ssl->last_wr = 0; - -#ifdef AXTLS_2_0_0_SNDBUF - int expected_len = ssl_calculate_write_length(tcp_ssl->ssl, len); - int available_len = tcp_sndbuf(tcp); - if(expected_len < 0 || expected_len > available_len){ - TCP_SSL_DEBUG("tcp_ssl_write: data will not fit! %u < %d(%u)\r\n", available_len, expected_len, len); - return -1; - } -#endif - - int rc = ssl_write(tcp_ssl->ssl, data, len); - - //TCP_SSL_DEBUG("tcp_ssl_write: %u -> %d (%d)\r\n", len, tcp_ssl->last_wr, rc); - - if (rc < 0){ - if(rc != SSL_CLOSE_NOTIFY) { - TCP_SSL_DEBUG("tcp_ssl_write error: %d\r\n", rc); - } - return rc; - } - - return tcp_ssl->last_wr; -} - -/** - * Reads data from the SSL over TCP stream. Returns decrypted data. - * @param tcp_pcb *tcp - pointer to the raw tcp object - * @param pbuf *p - pointer to the buffer with the TCP packet data - * - * @return int - * 0 - when everything is fine but there are no symbols to process yet - * < 0 - when there is an error - * > 0 - the length of the clear text characters that were read - */ -int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p) { - if(tcp == NULL) { - return -1; - } - tcp_ssl_t* fd_data = NULL; - - int read_bytes = 0; - int total_bytes = 0; - uint8_t *read_buf; - - fd_data = tcp_ssl_get(tcp); - if(fd_data == NULL) { - TCP_SSL_DEBUG("tcp_ssl_read: tcp_ssl is NULL\n"); - return ERR_TCP_SSL_INVALID_CLIENTFD_DATA; - } - - if(p == NULL) { - TCP_SSL_DEBUG("tcp_ssl_read:p == NULL\n"); - return ERR_TCP_SSL_INVALID_DATA; - } - - //TCP_SSL_DEBUG("READY TO READ SOME DATA\n"); - - fd_data->tcp_pbuf = p; - fd_data->pbuf_offset = 0; - - do { - read_bytes = ssl_read(fd_data->ssl, &read_buf); - //TCP_SSL_DEBUG("tcp_ssl_ssl_read: %d\n", read_bytes); - if(read_bytes < SSL_OK) { - if(read_bytes != SSL_CLOSE_NOTIFY) { - TCP_SSL_DEBUG("tcp_ssl_read: read error: %d\n", read_bytes); - } - total_bytes = read_bytes; - break; - } else if(read_bytes > 0){ - if(fd_data->on_data){ - fd_data->on_data(fd_data->arg, tcp, read_buf, read_bytes); - } - total_bytes+= read_bytes; - } else { - if(fd_data->handshake != SSL_OK) { - fd_data->handshake = ssl_handshake_status(fd_data->ssl); - if(fd_data->handshake == SSL_OK){ - //TCP_SSL_DEBUG("tcp_ssl_read: handshake OK\n"); - if(fd_data->on_handshake) - fd_data->on_handshake(fd_data->arg, fd_data->tcp, fd_data->ssl); - } else if(fd_data->handshake != SSL_NOT_OK){ - TCP_SSL_DEBUG("tcp_ssl_read: handshake error: %d\n", fd_data->handshake); - if(fd_data->on_error) - fd_data->on_error(fd_data->arg, fd_data->tcp, fd_data->handshake); - return fd_data->handshake; - } - } - } - } while (p->tot_len - fd_data->pbuf_offset > 0); - - tcp_recved(tcp, p->tot_len); - fd_data->tcp_pbuf = NULL; - pbuf_free(p); - - return total_bytes; -} - -SSL * tcp_ssl_get_ssl(struct tcp_pcb *tcp){ - tcp_ssl_t * tcp_ssl = tcp_ssl_get(tcp); - if(tcp_ssl){ - return tcp_ssl->ssl; - } - return NULL; -} - -bool tcp_ssl_has(struct tcp_pcb *tcp){ - return tcp_ssl_get(tcp) != NULL; -} - -int tcp_ssl_is_server(struct tcp_pcb *tcp){ - tcp_ssl_t * tcp_ssl = tcp_ssl_get(tcp); - if(tcp_ssl){ - return tcp_ssl->type; - } - return -1; -} - -void tcp_ssl_arg(struct tcp_pcb *tcp, void * arg){ - tcp_ssl_t * item = tcp_ssl_get(tcp); - if(item) { - item->arg = arg; - } -} - -void tcp_ssl_data(struct tcp_pcb *tcp, tcp_ssl_data_cb_t arg){ - tcp_ssl_t * item = tcp_ssl_get(tcp); - if(item) { - item->on_data = arg; - } -} - -void tcp_ssl_handshake(struct tcp_pcb *tcp, tcp_ssl_handshake_cb_t arg){ - tcp_ssl_t * item = tcp_ssl_get(tcp); - if(item) { - item->on_handshake = arg; - } -} - -void tcp_ssl_err(struct tcp_pcb *tcp, tcp_ssl_error_cb_t arg){ - tcp_ssl_t * item = tcp_ssl_get(tcp); - if(item) { - item->on_error = arg; - } -} - -static tcp_ssl_file_cb_t _tcp_ssl_file_cb = NULL; -static void * _tcp_ssl_file_arg = NULL; - -void tcp_ssl_file(tcp_ssl_file_cb_t cb, void * arg){ - _tcp_ssl_file_cb = cb; - _tcp_ssl_file_arg = arg; -} - -int ax_get_file(const char *filename, uint8_t **buf) { - //TCP_SSL_DEBUG("ax_get_file: %s\n", filename); - if(_tcp_ssl_file_cb){ - return _tcp_ssl_file_cb(_tcp_ssl_file_arg, filename, buf); - } - *buf = 0; - return 0; -} - -tcp_ssl_t* tcp_ssl_get_by_fd(int fd) { - tcp_ssl_t * item = tcp_ssl_array; - while(item && item->fd != fd){ - item = item->next; - } - return item; -} -/* - * The LWIP tcp raw version of the SOCKET_WRITE(A, B, C) - */ -int ax_port_write(int fd, uint8_t *data, uint16_t len) { - tcp_ssl_t *fd_data = NULL; - int tcp_len = 0; - err_t err = ERR_OK; - - //TCP_SSL_DEBUG("ax_port_write: %d, %d\n", fd, len); - - fd_data = tcp_ssl_get_by_fd(fd); - if(fd_data == NULL) { - //TCP_SSL_DEBUG("ax_port_write: tcp_ssl[%d] is NULL\n", fd); - return ERR_MEM; - } - - if (data == NULL || len == 0) { - return 0; - } - - if (tcp_sndbuf(fd_data->tcp) < len) { - tcp_len = tcp_sndbuf(fd_data->tcp); - if(tcp_len == 0) { - TCP_SSL_DEBUG("ax_port_write: tcp_sndbuf is zero: %d\n", len); - return ERR_MEM; - } - } else { - tcp_len = len; - } - - if (tcp_len > 2 * fd_data->tcp->mss) { - tcp_len = 2 * fd_data->tcp->mss; - } - - err = tcp_write(fd_data->tcp, data, tcp_len, TCP_WRITE_FLAG_COPY); - if(err < ERR_OK) { - if (err == ERR_MEM) { - TCP_SSL_DEBUG("ax_port_write: No memory %d (%d)\n", tcp_len, len); - return err; - } - TCP_SSL_DEBUG("ax_port_write: tcp_write error: %d\n", err); - return err; - } else if (err == ERR_OK) { - //TCP_SSL_DEBUG("ax_port_write: tcp_output: %d / %d\n", tcp_len, len); - err = tcp_output(fd_data->tcp); - if(err != ERR_OK) { - TCP_SSL_DEBUG("ax_port_write: tcp_output err: %d\n", err); - return err; - } - } - - fd_data->last_wr += tcp_len; - - return tcp_len; -} - -/* - * The LWIP tcp raw version of the SOCKET_READ(A, B, C) - */ -int ax_port_read(int fd, uint8_t *data, int len) { - tcp_ssl_t *fd_data = NULL; - uint8_t *read_buf = NULL; - uint8_t *pread_buf = NULL; - u16_t recv_len = 0; - - //TCP_SSL_DEBUG("ax_port_read: %d, %d\n", fd, len); - - fd_data = tcp_ssl_get_by_fd(fd); - if (fd_data == NULL) { - TCP_SSL_DEBUG("ax_port_read: tcp_ssl[%d] is NULL\n", fd); - return ERR_TCP_SSL_INVALID_CLIENTFD_DATA; - } - - if(fd_data->tcp_pbuf == NULL || fd_data->tcp_pbuf->tot_len == 0) { - return 0; - } - - read_buf =(uint8_t*)calloc(fd_data->tcp_pbuf->len + 1, sizeof(uint8_t)); - pread_buf = read_buf; - if (pread_buf != NULL){ - recv_len = pbuf_copy_partial(fd_data->tcp_pbuf, read_buf, len, fd_data->pbuf_offset); - fd_data->pbuf_offset += recv_len; - } - - if (recv_len != 0) { - memcpy(data, read_buf, recv_len); - } - - if(len < recv_len) { - TCP_SSL_DEBUG("ax_port_read: got %d bytes more than expected\n", recv_len - len); - } - - free(pread_buf); - pread_buf = NULL; - - return recv_len; -} - -void ax_wdt_feed() {} - -#endif diff --git a/lib/ESPAsyncTCP/src/tcp_axtls.h b/lib/ESPAsyncTCP/src/tcp_axtls.h deleted file mode 100644 index 118e36f29..000000000 --- a/lib/ESPAsyncTCP/src/tcp_axtls.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - 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 -*/ -/* - * Compatibility for AxTLS with LWIP raw tcp mode (http://lwip.wikia.com/wiki/Raw/TCP) - * Original Code and Inspiration: Slavey Karadzhov - */ - -#ifndef LWIPR_COMPAT_H -#define LWIPR_COMPAT_H - -#include - -#if ASYNC_TCP_SSL_ENABLED - -#include "lwipopts.h" -/* - * All those functions will run only if LWIP tcp raw mode is used - */ -#if LWIP_RAW==1 - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include "include/ssl.h" - -#define ERR_TCP_SSL_INVALID_SSL -101 -#define ERR_TCP_SSL_INVALID_TCP -102 -#define ERR_TCP_SSL_INVALID_CLIENTFD -103 -#define ERR_TCP_SSL_INVALID_CLIENTFD_DATA -104 -#define ERR_TCP_SSL_INVALID_DATA -105 - -#define TCP_SSL_TYPE_CLIENT 0 -#define TCP_SSL_TYPE_SERVER 1 - -#define tcp_ssl_ssl_write(A, B, C) tcp_ssl_write(A, B, C) -#define tcp_ssl_ssl_read(A, B) tcp_ssl_read(A, B) - -typedef void (* tcp_ssl_data_cb_t)(void *arg, struct tcp_pcb *tcp, uint8_t * data, size_t len); -typedef void (* tcp_ssl_handshake_cb_t)(void *arg, struct tcp_pcb *tcp, SSL *ssl); -typedef void (* tcp_ssl_error_cb_t)(void *arg, struct tcp_pcb *tcp, int8_t error); -typedef int (* tcp_ssl_file_cb_t)(void *arg, const char *filename, uint8_t **buf); - -uint8_t tcp_ssl_has_client(); - -int tcp_ssl_new_client(struct tcp_pcb *tcp); - -SSL_CTX * tcp_ssl_new_server_ctx(const char *cert, const char *private_key_file, const char *password); -int tcp_ssl_new_server(struct tcp_pcb *tcp, SSL_CTX* ssl_ctx); -int tcp_ssl_is_server(struct tcp_pcb *tcp); - -int tcp_ssl_free(struct tcp_pcb *tcp); -int tcp_ssl_read(struct tcp_pcb *tcp, struct pbuf *p); - -#ifdef AXTLS_2_0_0_SNDBUF -int tcp_ssl_sndbuf(struct tcp_pcb *tcp); -#endif - -int tcp_ssl_write(struct tcp_pcb *tcp, uint8_t *data, size_t len); - -void tcp_ssl_file(tcp_ssl_file_cb_t cb, void * arg); - -void tcp_ssl_arg(struct tcp_pcb *tcp, void * arg); -void tcp_ssl_data(struct tcp_pcb *tcp, tcp_ssl_data_cb_t arg); -void tcp_ssl_handshake(struct tcp_pcb *tcp, tcp_ssl_handshake_cb_t arg); -void tcp_ssl_err(struct tcp_pcb *tcp, tcp_ssl_error_cb_t arg); - -SSL * tcp_ssl_get_ssl(struct tcp_pcb *tcp); -bool tcp_ssl_has(struct tcp_pcb *tcp); - -#ifdef __cplusplus -} -#endif - -#endif /* LWIP_RAW==1 */ - -#endif /* ASYNC_TCP_SSL_ENABLED */ - -#endif /* LWIPR_COMPAT_H */