From cb8316b1aaeedb320b23cb206162d299c167dbfb Mon Sep 17 00:00:00 2001 From: Damien Mascord Date: Thu, 20 Apr 2017 18:58:41 +1000 Subject: [PATCH] Add "Secure" client for default SSL connections (for use in PubSubClient etc) --- src/WiFiEsp.h | 2 + src/WiFiEspSecureClient.cpp | 289 ++++++++++++++++++++++++++++++++++++ src/WiFiEspSecureClient.h | 144 ++++++++++++++++++ 3 files changed, 435 insertions(+) create mode 100644 src/WiFiEspSecureClient.cpp create mode 100644 src/WiFiEspSecureClient.h diff --git a/src/WiFiEsp.h b/src/WiFiEsp.h index 7bf234e..8084ebf 100644 --- a/src/WiFiEsp.h +++ b/src/WiFiEsp.h @@ -26,6 +26,7 @@ along with The Arduino WiFiEsp library. If not, see #include "WiFiEspClient.h" +#include "WiFiEspSecureClient.h" #include "WiFiEspServer.h" #include "utility/EspDrv.h" #include "utility/RingBuffer.h" @@ -258,6 +259,7 @@ class WiFiEspClass friend class WiFiEspClient; + friend class WiFiEspSecureClient; friend class WiFiEspServer; friend class WiFiEspUDP; diff --git a/src/WiFiEspSecureClient.cpp b/src/WiFiEspSecureClient.cpp new file mode 100644 index 0000000..61808ad --- /dev/null +++ b/src/WiFiEspSecureClient.cpp @@ -0,0 +1,289 @@ +/*-------------------------------------------------------------------- +This file is part of the Arduino WiFiEsp library. + +The Arduino WiFiEsp library is free software: you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +The Arduino WiFiEsp 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with The Arduino WiFiEsp library. If not, see +. +--------------------------------------------------------------------*/ + +#include + +#include "WiFiEsp.h" +#include "WiFiEspSecureClient.h" +#include "WiFiEspServer.h" + +#include "utility/EspDrv.h" +#include "utility/debug.h" + + +WiFiEspSecureClient::WiFiEspSecureClient() : _sock(255) +{ +} + +WiFiEspSecureClient::WiFiEspSecureClient(uint8_t sock) : _sock(sock) +{ +} + + + +//////////////////////////////////////////////////////////////////////////////// +// Overrided Print methods +//////////////////////////////////////////////////////////////////////////////// + +// the standard print method will call write for each character in the buffer +// this is very slow on ESP +size_t WiFiEspSecureClient::print(const __FlashStringHelper *ifsh) +{ + printFSH(ifsh, false); +} + +// if we do override this, the standard println will call the print +// method twice +size_t WiFiEspSecureClient::println(const __FlashStringHelper *ifsh) +{ + printFSH(ifsh, true); +} + + +//////////////////////////////////////////////////////////////////////////////// +// Implementation of Client virtual methods +//////////////////////////////////////////////////////////////////////////////// + +int WiFiEspSecureClient::connectSSL(const char* host, uint16_t port) +{ + return connect(host, port, SSL_MODE); +} + +int WiFiEspSecureClient::connectSSL(IPAddress ip, uint16_t port) +{ + char s[16]; + sprintf_P(s, PSTR("%d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); + return connect(s, port, SSL_MODE); +} + +int WiFiEspSecureClient::connect(const char* host, uint16_t port) +{ + return connect(host, port, SSL_MODE); +} + +int WiFiEspSecureClient::connect(IPAddress ip, uint16_t port) +{ + char s[16]; + sprintf_P(s, PSTR("%d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); + + return connect(s, port, SSL_MODE); +} + +/* Private method */ +int WiFiEspSecureClient::connect(const char* host, uint16_t port, uint8_t protMode) +{ + LOGINFO1(F("Connecting to"), host); + + _sock = WiFiEspClass::getFreeSocket(); + + if (_sock != NO_SOCKET_AVAIL) + { + if (!EspDrv::startClient(host, port, _sock, protMode)) + return 0; + + WiFiEspClass::allocateSocket(_sock); + } + else + { + LOGERROR(F("No socket available")); + return 0; + } + return 1; +} + + + +size_t WiFiEspSecureClient::write(uint8_t b) +{ + return write(&b, 1); +} + +size_t WiFiEspSecureClient::write(const uint8_t *buf, size_t size) +{ + if (_sock >= MAX_SOCK_NUM or size==0) + { + setWriteError(); + return 0; + } + + bool r = EspDrv::sendData(_sock, buf, size); + if (!r) + { + setWriteError(); + LOGERROR1(F("Failed to write to socket"), _sock); + delay(4000); + stop(); + return 0; + } + + return size; +} + + + +int WiFiEspSecureClient::available() +{ + if (_sock != 255) + { + int bytes = EspDrv::availData(_sock); + if (bytes>0) + { + return bytes; + } + } + + return 0; +} + +int WiFiEspSecureClient::read() +{ + uint8_t b; + if (!available()) + return -1; + + bool connClose = false; + EspDrv::getData(_sock, &b, false, &connClose); + + if (connClose) + { + WiFiEspClass::releaseSocket(_sock); + _sock = 255; + } + + return b; +} + +int WiFiEspSecureClient::read(uint8_t* buf, size_t size) +{ + if (!available()) + return -1; + return EspDrv::getDataBuf(_sock, buf, size); +} + +int WiFiEspSecureClient::peek() +{ + uint8_t b; + if (!available()) + return -1; + + bool connClose = false; + EspDrv::getData(_sock, &b, true, &connClose); + + if (connClose) + { + WiFiEspClass::releaseSocket(_sock); + _sock = 255; + } + + return b; +} + + +void WiFiEspSecureClient::flush() +{ + while (available()) + read(); +} + +void WiFiEspSecureClient::stop() +{ + if (_sock == 255) + return; + + LOGINFO1(F("Disconnecting "), _sock); + + EspDrv::stopClient(_sock); + + WiFiEspClass::releaseSocket(_sock); + _sock = 255; +} + + +uint8_t WiFiEspSecureClient::connected() +{ + return (status() == ESTABLISHED); +} + + +WiFiEspSecureClient::operator bool() +{ + return _sock != 255; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Additional WiFi standard methods +//////////////////////////////////////////////////////////////////////////////// + + +uint8_t WiFiEspSecureClient::status() +{ + if (_sock == 255) + { + return CLOSED; + } + + if (EspDrv::availData(_sock)) + { + return ESTABLISHED; + } + + if (EspDrv::getClientState(_sock)) + { + return ESTABLISHED; + } + + WiFiEspClass::releaseSocket(_sock); + _sock = 255; + + return CLOSED; +} + +IPAddress WiFiEspSecureClient::remoteIP() +{ + IPAddress ret; + EspDrv::getRemoteIpAddress(ret); + return ret; +} + +//////////////////////////////////////////////////////////////////////////////// +// Private Methods +//////////////////////////////////////////////////////////////////////////////// + +size_t WiFiEspSecureClient::printFSH(const __FlashStringHelper *ifsh, bool appendCrLf) +{ + size_t size = strlen_P((char*)ifsh); + + if (_sock >= MAX_SOCK_NUM or size==0) + { + setWriteError(); + return 0; + } + + bool r = EspDrv::sendData(_sock, ifsh, size, appendCrLf); + if (!r) + { + setWriteError(); + LOGERROR1(F("Failed to write to socket"), _sock); + delay(4000); + stop(); + return 0; + } + + return size; +} diff --git a/src/WiFiEspSecureClient.h b/src/WiFiEspSecureClient.h new file mode 100644 index 0000000..957c5aa --- /dev/null +++ b/src/WiFiEspSecureClient.h @@ -0,0 +1,144 @@ +/*-------------------------------------------------------------------- +This file is part of the Arduino WiFiEsp library. + +The Arduino WiFiEsp library is free software: you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +The Arduino WiFiEsp 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with The Arduino WiFiEsp library. If not, see +. +--------------------------------------------------------------------*/ + +#ifndef WiFiEspSecureClient_h +#define WiFiEspSecureClient_h + + +#include "Arduino.h" +#include "Print.h" +#include "Client.h" +#include "IPAddress.h" + + + +class WiFiEspSecureClient : public Client +{ +public: + WiFiEspSecureClient(); + WiFiEspSecureClient(uint8_t sock); + + + + + // override Print.print method + + size_t print(const __FlashStringHelper *ifsh); + size_t println(const __FlashStringHelper *ifsh); + + + /* + * Connect to the specified IP address and port. The return value indicates success or failure. + * Returns true if the connection succeeds, false if not. + */ + virtual int connect(IPAddress ip, uint16_t port); + + /* + * Connect to the specified host and port. The return value indicates success or failure. + * Returns true if the connection succeeds, false if not. + */ + virtual int connect(const char *host, uint16_t port); + + /* + * Connect to the specified IP address and port using SSL. The return value indicates success or failure. + * Returns true if the connection succeeds, false if not. + */ + int connectSSL(IPAddress ip, uint16_t port); + + /* + * Connect to the specified host and port using SSL. The return value indicates success or failure. + * Returns true if the connection succeeds, false if not. + */ + int connectSSL(const char* host, uint16_t port); + + /* + * Write a character to the server the client is connected to. + * Returns the number of characters written. + */ + virtual size_t write(uint8_t); + + /* + * Write data to the server the client is connected to. + * Returns the number of characters written. + */ + virtual size_t write(const uint8_t *buf, size_t size); + + + virtual int available(); + + /* + * Read the next byte received from the server the client is connected to (after the last call to read()). + * Returns the next byte (or character), or -1 if none is available. + */ + virtual int read(); + + + virtual int read(uint8_t *buf, size_t size); + + /* + * Returns the next byte (character) of incoming serial data without removing it from the internal serial buffer. + */ + virtual int peek(); + + /* + * Discard any bytes that have been written to the client but not yet read. + */ + virtual void flush(); + + /* + * Disconnect from the server. + */ + virtual void stop(); + + /* + * Whether or not the client is connected. + * Note that a client is considered connected if the connection has been closed but there is still unread data. + * Returns true if the client is connected, false if not. + */ + virtual uint8_t connected(); + + + uint8_t status(); + + virtual operator bool(); + + + // needed to correctly handle overriding + // see http://stackoverflow.com/questions/888235/overriding-a-bases-overloaded-function-in-c + using Print::write; + using Print::print; + using Print::println; + + + /* + * Returns the remote IP address. + */ + IPAddress remoteIP(); + + friend class WiFiEspServer; + +private: + + uint8_t _sock; // connection id + int connect(const char* host, uint16_t port, uint8_t protMode); + + size_t printFSH(const __FlashStringHelper *ifsh, bool appendCrLf); + +}; + +#endif