Compare commits

..

No commits in common. "74b0bf810cd3f344d576aabb8fa558f9e206095a" and "e108dd919ab273f55b3e63746dfa52c7466c255b" have entirely different histories.

37 changed files with 846 additions and 3069 deletions

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@ const Pin I2C_scl,
const Pin SPI_mosi, const Pin SPI_mosi,
const Pin SPI_miso, const Pin SPI_miso,
const Pin SPI_clk, const Pin SPI_clk,
const uint32_t spiSpeed const SPISettings spiSpeed
): ):
_I2C_sda(I2C_sda == DEFAULT_PIN ? GPIO_4_SDA : I2C_sda), _I2C_sda(I2C_sda == DEFAULT_PIN ? GPIO_4_SDA : I2C_sda),
_I2C_scl(I2C_scl == DEFAULT_PIN ? GPIO_5_SCL : I2C_scl), _I2C_scl(I2C_scl == DEFAULT_PIN ? GPIO_5_SCL : I2C_scl),
@ -75,7 +75,7 @@ uint16_t BoardConfig::getRTCFlashAddress() const
} }
uint32_t BoardConfig::getSPISpeed() const SPISettings BoardConfig::getSPISpeed() const
{ {
return _SPISpeed; return _SPISpeed;
} }

View File

@ -22,7 +22,7 @@ class BoardConfig
const Pin SPI_mosi = GPIO_13_MOSI, const Pin SPI_mosi = GPIO_13_MOSI,
const Pin SPI_miso = GPIO_12_MISO, const Pin SPI_miso = GPIO_12_MISO,
const Pin SPI_clk = GPIO_14_CLK, const Pin SPI_clk = GPIO_14_CLK,
const uint32_t spiSpeed = SPI_FULL_SPEED const SPISettings spiSpeed = SPI_FULL_SPEED
); );
Pin getI2C_sda() const; Pin getI2C_sda() const;
@ -37,7 +37,7 @@ class BoardConfig
uint16_t getI2C_IOExpanderAddress() const; uint16_t getI2C_IOExpanderAddress() const;
uint16_t getRTCFlashAddress() const; uint16_t getRTCFlashAddress() const;
uint32_t getSPISpeed() const; SPISettings getSPISpeed() const;
uint16_t getScreenWidth() const; uint16_t getScreenWidth() const;
uint16_t getScreenHeight() const; uint16_t getScreenHeight() const;
@ -58,7 +58,7 @@ class BoardConfig
const uint16_t _I2C_RTCFlashAddress; const uint16_t _I2C_RTCFlashAddress;
//3) SPI Speed //3) SPI Speed
const uint32_t _SPISpeed; const SPISettings _SPISpeed;
//4) Miscellaneous //4) Miscellaneous
const uint16_t _screenWidth; const uint16_t _screenWidth;

View File

@ -1,6 +1,6 @@
#include "SDCardManager.h" #include "SDCardManager.h"
SDCardManager::SDCardManager(const Pin csPin, uint32_t cfg) : _csPin(csPin), _spiCfg(cfg), _mounted(false) SDCardManager::SDCardManager(const Pin csPin, SPISettings cfg) : _csPin(csPin), _spiCfg(cfg), _mounted(false)
{ {
} }

View File

@ -10,7 +10,7 @@ class SDCardManager : public SDClass
{ {
friend class SAB; friend class SAB;
public: public:
SDCardManager(const Pin csPin, uint32_t cfg); SDCardManager(const Pin csPin, SPISettings cfg);
double getSize(const SizeUnit sizeUnit = GBYTE); double getSize(const SizeUnit sizeUnit = GBYTE);
boolean mountSD(); boolean mountSD();
void unMountSD(); void unMountSD();
@ -27,7 +27,7 @@ class SDCardManager : public SDClass
private: private:
const Pin _csPin; const Pin _csPin;
uint32_t _spiCfg; SPISettings _spiCfg;
boolean _mounted; boolean _mounted;
}; };

View File

@ -27,7 +27,11 @@ const int chipSelect = 4;
void setup() { void setup() {
// Open serial communications and wait for port to open: // Open serial communications and wait for port to open:
Serial.begin(115200); Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
Serial.print("Initializing SD card..."); Serial.print("Initializing SD card...");

View File

@ -27,7 +27,11 @@ const int chipSelect = 4;
void setup() { void setup() {
// Open serial communications and wait for port to open: // Open serial communications and wait for port to open:
Serial.begin(115200); Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
Serial.print("Initializing SD card..."); Serial.print("Initializing SD card...");

View File

@ -24,7 +24,11 @@ File myFile;
void setup() { void setup() {
// Open serial communications and wait for port to open: // Open serial communications and wait for port to open:
Serial.begin(115200); Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
Serial.print("Initializing SD card..."); Serial.print("Initializing SD card...");

View File

@ -25,7 +25,11 @@ File myFile;
void setup() { void setup() {
// Open serial communications and wait for port to open: // Open serial communications and wait for port to open:
Serial.begin(115200); Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
Serial.print("Initializing SD card..."); Serial.print("Initializing SD card...");

View File

@ -29,6 +29,9 @@ File root;
void setup() { void setup() {
// Open serial communications and wait for port to open: // Open serial communications and wait for port to open:
Serial.begin(115200); Serial.begin(115200);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
Serial.print("Initializing SD card..."); Serial.print("Initializing SD card...");
@ -68,12 +71,11 @@ void printDirectory(File dir, int numTabs) {
// files have sizes, directories do not // files have sizes, directories do not
Serial.print("\t\t"); Serial.print("\t\t");
Serial.print(entry.size(), DEC); Serial.print(entry.size(), DEC);
time_t cr = entry.getCreationTime(); Serial.print("\t\t");
time_t lw = entry.getLastWrite(); time_t ft = entry.getLastWrite();
struct tm * tmstruct = localtime(&cr); struct tm *tm = localtime(&ft);
Serial.printf("\tCREATION: %d-%02d-%02d %02d:%02d:%02d", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec); // US format. Feel free to convert to your own locale...
tmstruct = localtime(&lw); Serial.printf("%02d-%02d-%02d %02d:%02d:%02d\n", tm->tm_mon + 1, tm->tm_mday, tm->tm_year % 100, tm->tm_hour, tm->tm_min, tm->tm_sec);
Serial.printf("\tLAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec);
} }
entry.close(); entry.close();
} }

View File

@ -21,10 +21,12 @@ open KEYWORD2
close KEYWORD2 close KEYWORD2
seek KEYWORD2 seek KEYWORD2
position KEYWORD2 position KEYWORD2
size KEYWORD2 size KEYWORD2
rename KEYWORD2
####################################### #######################################
# Constants (LITERAL1) # Constants (LITERAL1)
####################################### #######################################
FILE_READ LITERAL1 FILE_READ LITERAL1
FILE_WRITE LITERAL1 FILE_WRITE LITERAL1
FILE_READWRITE LITERAL1

View File

@ -1,4 +1,4 @@
name=SD name=SD(esp8266)
version=2.0.0 version=2.0.0
author=Earle F. Philhower, III <earlephilhower@yahoo.com> author=Earle F. Philhower, III <earlephilhower@yahoo.com>
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com> maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>

View File

@ -28,12 +28,12 @@
#define FILE_READ sdfat::O_READ #define FILE_READ sdfat::O_READ
#undef FILE_WRITE #undef FILE_WRITE
#define FILE_WRITE (sdfat::O_READ | sdfat::O_WRITE | sdfat::O_CREAT | sdfat::O_APPEND) #define FILE_WRITE (sdfat::O_READ | sdfat::O_WRITE | sdfat::O_CREAT | sdfat::O_APPEND)
#undef FILE_READWRITE #undef FILE_READWRITE
#define FILE_READWRITE (sdfat::O_READ | sdfat::O_WRITE) #define FILE_READWRITE (sdfat::O_READ | sdfat::O_WRITE)
class SDClass { class SDClass {
public: public:
boolean begin(uint8_t csPin, uint32_t cfg = SPI_HALF_SPEED) { boolean begin(uint8_t csPin, SPISettings cfg = SPI_HALF_SPEED) {
SDFS.setConfig(SDFSConfig(csPin, cfg)); SDFS.setConfig(SDFSConfig(csPin, cfg));
return (boolean)SDFS.begin(); return (boolean)SDFS.begin();
} }
@ -69,18 +69,6 @@ public:
return (boolean)SDFS.exists(filepath.c_str()); return (boolean)SDFS.exists(filepath.c_str());
} }
boolean rename(const char* filepathfrom, const char* filepathto) {
return (boolean)SDFS.rename(filepathfrom, filepathto);
}
bool info64(FSInfo64& info) {
return (boolean)SDFS.info64(info);
}
boolean rename(const String &filepathfrom, const String &filepathto) {
return (boolean)rename(filepathfrom.c_str(), filepathto.c_str());
}
boolean mkdir(const char *filepath) { boolean mkdir(const char *filepath) {
return (boolean)SDFS.mkdir(filepath); return (boolean)SDFS.mkdir(filepath);
} }
@ -104,6 +92,14 @@ public:
boolean rmdir(const String &filepath) { boolean rmdir(const String &filepath) {
return rmdir(filepath.c_str()); return rmdir(filepath.c_str());
} }
bool rename(const char* pathFrom, const char* pathTo) {
return (boolean)SDFS.rename(pathFrom, pathTo);
}
bool info64(FSInfo64& info) {
return (boolean)SDFS.info64(info);
}
uint8_t type() { uint8_t type() {
sdfs::SDFSImpl* sd = static_cast<sdfs::SDFSImpl*>(SDFS.getImpl().get()); sdfs::SDFSImpl* sd = static_cast<sdfs::SDFSImpl*>(SDFS.getImpl().get());
@ -188,7 +184,7 @@ private:
}; };
// Expose FatStructs.h helpers for MS-DOS date/time for use with dateTimeCallback // Expose FatStructs.h helpers for MSDOS date/time for use with dateTimeCallback
static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) { static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) {
return (year - 1980) << 9 | month << 5 | day; return (year - 1980) << 9 | month << 5 | day;
} }

View File

@ -25,6 +25,7 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include "SDFS.h" #include "SDFS.h"
#include "SDFSFormatter.h"
#include <FS.h> #include <FS.h>
using namespace fs; using namespace fs;
@ -36,9 +37,6 @@ FS SDFS = FS(FSImplPtr(new sdfs::SDFSImpl()));
namespace sdfs { namespace sdfs {
// Required to be global because SDFAT doesn't allow a this pointer in it's own time call
time_t (*__sdfs_timeCallback)(void) = nullptr;
FileImplPtr SDFSImpl::open(const char* path, OpenMode openMode, AccessMode accessMode) FileImplPtr SDFSImpl::open(const char* path, OpenMode openMode, AccessMode accessMode)
{ {
if (!_mounted) { if (!_mounted) {
@ -64,13 +62,13 @@ FileImplPtr SDFSImpl::open(const char* path, OpenMode openMode, AccessMode acces
} }
free(pathStr); free(pathStr);
} }
sdfat::File32 fd = _fs.open(path, flags); sdfat::File fd = _fs.open(path, flags);
if (!fd) { if (!fd) {
DEBUGV("SDFSImpl::openFile: fd=%p path=`%s` openMode=%d accessMode=%d", DEBUGV("SDFSImpl::openFile: fd=%p path=`%s` openMode=%d accessMode=%d",
&fd, path, openMode, accessMode); &fd, path, openMode, accessMode);
return FileImplPtr(); return FileImplPtr();
} }
auto sharedFd = std::make_shared<sdfat::File32>(fd); auto sharedFd = std::make_shared<sdfat::File>(fd);
return std::make_shared<SDFSFileImpl>(this, sharedFd, path); return std::make_shared<SDFSFileImpl>(this, sharedFd, path);
} }
@ -90,7 +88,7 @@ DirImplPtr SDFSImpl::openDir(const char* path)
} }
// At this point we have a name of "/blah/blah/blah" or "blah" or "" // At this point we have a name of "/blah/blah/blah" or "blah" or ""
// If that references a directory, just open it and we're done. // If that references a directory, just open it and we're done.
sdfat::File32 dirFile; sdfat::File dirFile;
const char *filter = ""; const char *filter = "";
if (!pathStr[0]) { if (!pathStr[0]) {
// openDir("") === openDir("/") // openDir("") === openDir("/")
@ -135,7 +133,7 @@ DirImplPtr SDFSImpl::openDir(const char* path)
DEBUGV("SDFSImpl::openDir: path=`%s`\n", path); DEBUGV("SDFSImpl::openDir: path=`%s`\n", path);
return DirImplPtr(); return DirImplPtr();
} }
auto sharedDir = std::make_shared<sdfat::File32>(dirFile); auto sharedDir = std::make_shared<sdfat::File>(dirFile);
auto ret = std::make_shared<SDFSDirImpl>(filter, this, sharedDir, pathStr); auto ret = std::make_shared<SDFSDirImpl>(filter, this, sharedDir, pathStr);
free(pathStr); free(pathStr);
return ret; return ret;
@ -145,18 +143,12 @@ bool SDFSImpl::format() {
if (_mounted) { if (_mounted) {
return false; return false;
} }
sdfat::SdCardFactory cardFactory; SDFSFormatter formatter;
sdfat::SdCard* card = cardFactory.newCard(sdfat::SdSpiConfig(_cfg._csPin, DEDICATED_SPI, _cfg._spiSettings)); bool ret = formatter.format(&_fs, _cfg._csPin, _cfg._spiSettings);
if (!card || card->errorCode()) {
return false;
}
sdfat::FatFormatter fatFormatter;
uint8_t *sectorBuffer = new uint8_t[512];
bool ret = fatFormatter.format(card, sectorBuffer, nullptr);
delete[] sectorBuffer;
return ret; return ret;
} }
time_t (*SDFSImpl::timeCallback)(void) = nullptr;
}; // namespace sdfs }; // namespace sdfs

View File

@ -47,7 +47,7 @@ class SDFSConfig : public FSConfig
public: public:
static constexpr uint32_t FSId = 0x53444653; static constexpr uint32_t FSId = 0x53444653;
SDFSConfig(uint8_t csPin = 4, uint32_t spi = SD_SCK_MHZ(10)) : FSConfig(FSId, false), _csPin(csPin), _part(0), _spiSettings(spi) { } SDFSConfig(uint8_t csPin = 4, SPISettings spi = SD_SCK_MHZ(10)) : FSConfig(FSId, false), _csPin(csPin), _part(0), _spiSettings(spi) { }
SDFSConfig setAutoFormat(bool val = true) { SDFSConfig setAutoFormat(bool val = true) {
_autoFormat = val; _autoFormat = val;
@ -57,7 +57,7 @@ public:
_csPin = pin; _csPin = pin;
return *this; return *this;
} }
SDFSConfig setSPI(uint32_t spi) { SDFSConfig setSPI(SPISettings spi) {
_spiSettings = spi; _spiSettings = spi;
return *this; return *this;
} }
@ -67,9 +67,9 @@ public:
} }
// Inherit _type and _autoFormat // Inherit _type and _autoFormat
uint8_t _csPin; uint8_t _csPin;
uint8_t _part; uint8_t _part;
uint32_t _spiSettings; SPISettings _spiSettings;
}; };
class SDFSImpl : public FSImpl class SDFSImpl : public FSImpl
@ -97,11 +97,11 @@ public:
return false; return false;
} }
info.maxOpenFiles = 999; // TODO - not valid info.maxOpenFiles = 999; // TODO - not valid
info.blockSize = _fs.vol()->sectorsPerCluster() * _fs.vol()->bytesPerSector(); info.blockSize = _fs.vol()->blocksPerCluster() * 512;
info.pageSize = 0; // TODO ? info.pageSize = 0; // TODO ?
info.maxPathLength = 255; // TODO ? info.maxPathLength = 255; // TODO ?
info.totalBytes =_fs.vol()->clusterCount() * info.blockSize; info.totalBytes =_fs.vol()->volumeBlockCount() * 512LL;
info.usedBytes = info.totalBytes - (_fs.vol()->freeClusterCount() * _fs.vol()->sectorsPerCluster() * _fs.vol()->bytesPerSector()); info.usedBytes = info.totalBytes - (_fs.vol()->freeClusterCount() * _fs.vol()->blocksPerCluster() * 512LL);
return true; return true;
} }
@ -149,14 +149,14 @@ public:
bool begin() override { bool begin() override {
if (_mounted) { if (_mounted) {
return true; end();
} }
_mounted = _fs.begin(_cfg._csPin, _cfg._spiSettings); _mounted = _fs.begin(_cfg._csPin, _cfg._spiSettings);
if (!_mounted && _cfg._autoFormat) { if (!_mounted && _cfg._autoFormat) {
format(); format();
_mounted = _fs.begin(_cfg._csPin, _cfg._spiSettings); _mounted = _fs.begin(_cfg._csPin, _cfg._spiSettings);
} }
sdfat::FsDateTime::setCallback(dateTimeCB); sdfat::SdFile::dateTimeCallback(dateTimeCB);
return _mounted; return _mounted;
} }
@ -176,7 +176,7 @@ public:
return _fs.vol()->fatType(); return _fs.vol()->fatType();
} }
size_t blocksPerCluster() { size_t blocksPerCluster() {
return _fs.vol()->sectorsPerCluster(); return _fs.vol()->blocksPerCluster();
} }
size_t totalClusters() { size_t totalClusters() {
return _fs.vol()->clusterCount(); return _fs.vol()->clusterCount();
@ -185,7 +185,7 @@ public:
return (totalClusters() / blocksPerCluster()); return (totalClusters() / blocksPerCluster());
} }
size_t clusterSize() { size_t clusterSize() {
return blocksPerCluster() * _fs.vol()->bytesPerSector(); return blocksPerCluster() * 512; // 512b block size
} }
size_t size() { size_t size() {
return (clusterSize() * totalClusters()); return (clusterSize() * totalClusters());
@ -205,26 +205,24 @@ public:
return mktime(&tiempo); return mktime(&tiempo);
} }
virtual void setTimeCallback(time_t (*cb)(void)) override {
extern time_t (*__sdfs_timeCallback)(void);
__sdfs_timeCallback = cb;
}
// Because SdFat has a single, global setting for this we can only use a // Because SdFat has a single, global setting for this we can only use a
// static member of our class to return the time/date. // static member of our class to return the time/date. However, since
// this is static, we can't see the time callback variable. Punt for now,
// using time(NULL) as the best we can do.
static void dateTimeCB(uint16_t *dosYear, uint16_t *dosTime) { static void dateTimeCB(uint16_t *dosYear, uint16_t *dosTime) {
time_t now;
extern time_t (*__sdfs_timeCallback)(void); time_t now = (timeCallback == nullptr) ? time(nullptr) : (*timeCallback)();
if (__sdfs_timeCallback) { //time_t now = time(nullptr);
now = __sdfs_timeCallback();
} else {
now = time(nullptr);
}
struct tm *tiempo = localtime(&now); struct tm *tiempo = localtime(&now);
*dosYear = ((tiempo->tm_year - 80) << 9) | ((tiempo->tm_mon + 1) << 5) | tiempo->tm_mday; *dosYear = ((tiempo->tm_year - 80) << 9) | ((tiempo->tm_mon + 1) << 5) | tiempo->tm_mday;
*dosTime = (tiempo->tm_hour << 11) | (tiempo->tm_min << 5) | tiempo->tm_sec; *dosTime = (tiempo->tm_hour << 11) | (tiempo->tm_min << 5) | tiempo->tm_sec;
} }
virtual void setTimeCallback(time_t (*cb)(void))
{
timeCallback = cb;
}
protected: protected:
friend class SDFileImpl; friend class SDFileImpl;
friend class SDFSDirImpl; friend class SDFSDirImpl;
@ -234,7 +232,6 @@ protected:
return &_fs; return &_fs;
} }
static uint8_t _getFlags(OpenMode openMode, AccessMode accessMode) { static uint8_t _getFlags(OpenMode openMode, AccessMode accessMode) {
uint8_t mode = 0; uint8_t mode = 0;
if (openMode & OM_CREATE) { if (openMode & OM_CREATE) {
@ -258,13 +255,16 @@ protected:
sdfat::SdFat _fs; sdfat::SdFat _fs;
SDFSConfig _cfg; SDFSConfig _cfg;
bool _mounted; bool _mounted;
private:
static time_t (*timeCallback)(void);
}; };
class SDFSFileImpl : public FileImpl class SDFSFileImpl : public FileImpl
{ {
public: public:
SDFSFileImpl(SDFSImpl *fs, std::shared_ptr<sdfat::File32> fd, const char *name) SDFSFileImpl(SDFSImpl *fs, std::shared_ptr<sdfat::File> fd, const char *name)
: _fs(fs), _fd(fd), _opened(true) : _fs(fs), _fd(fd), _opened(true)
{ {
_name = std::shared_ptr<char>(new char[strlen(name) + 1], std::default_delete<char[]>()); _name = std::shared_ptr<char>(new char[strlen(name) + 1], std::default_delete<char[]>());
@ -277,17 +277,12 @@ public:
close(); close();
} }
int availableForWrite() override
{
return _opened ? _fd->availableSpaceForWrite() : 0;
}
size_t write(const uint8_t *buf, size_t size) override size_t write(const uint8_t *buf, size_t size) override
{ {
return _opened ? _fd->write(buf, size) : -1; return _opened ? _fd->write(buf, size) : -1;
} }
int read(uint8_t* buf, size_t size) override size_t read(uint8_t* buf, size_t size) override
{ {
return _opened ? _fd->read(buf, size) : -1; return _opened ? _fd->read(buf, size) : -1;
} }
@ -295,6 +290,7 @@ public:
void flush() override void flush() override
{ {
if (_opened) { if (_opened) {
_fd->flush();
_fd->sync(); _fd->sync();
} }
} }
@ -374,15 +370,15 @@ public:
bool isDirectory() const override bool isDirectory() const override
{ {
return _opened ? _fd->isDir() : false; return _opened ? _fd->isDirectory() : false;
} }
time_t getLastWrite() override { time_t getLastWrite() override {
time_t ftime = 0; time_t ftime = 0;
if (_opened && _fd) { if (_opened && _fd) {
sdfat::DirFat_t tmp; sdfat::dir_t tmp;
if (_fd.get()->dirEntry(&tmp)) { if (_fd.get()->dirEntry(&tmp)) {
ftime = SDFSImpl::FatToTimeT(*(uint16_t*)tmp.modifyDate, *(uint16_t*)tmp.modifyTime); ftime = SDFSImpl::FatToTimeT(tmp.lastWriteDate, tmp.lastWriteTime);
} }
} }
return ftime; return ftime;
@ -391,17 +387,19 @@ public:
time_t getCreationTime() override { time_t getCreationTime() override {
time_t ftime = 0; time_t ftime = 0;
if (_opened && _fd) { if (_opened && _fd) {
sdfat::DirFat_t tmp; sdfat::dir_t tmp;
if (_fd.get()->dirEntry(&tmp)) { if (_fd.get()->dirEntry(&tmp)) {
ftime = SDFSImpl::FatToTimeT(*(uint16_t*)tmp.createDate, *(uint16_t*)tmp.createTime); ftime = SDFSImpl::FatToTimeT(tmp.creationDate, tmp.creationTime);
} }
} }
return ftime; return ftime;
} }
protected: protected:
SDFSImpl* _fs; SDFSImpl* _fs;
std::shared_ptr<sdfat::File32> _fd; std::shared_ptr<sdfat::File> _fd;
std::shared_ptr<char> _name; std::shared_ptr<char> _name;
bool _opened; bool _opened;
}; };
@ -409,7 +407,7 @@ protected:
class SDFSDirImpl : public DirImpl class SDFSDirImpl : public DirImpl
{ {
public: public:
SDFSDirImpl(const String& pattern, SDFSImpl* fs, std::shared_ptr<sdfat::File32> dir, const char *dirPath = nullptr) SDFSDirImpl(const String& pattern, SDFSImpl* fs, std::shared_ptr<sdfat::File> dir, const char *dirPath = nullptr)
: _pattern(pattern), _fs(fs), _dir(dir), _valid(false), _dirPath(nullptr) : _pattern(pattern), _fs(fs), _dir(dir), _valid(false), _dirPath(nullptr)
{ {
if (dirPath) { if (dirPath) {
@ -484,17 +482,17 @@ public:
{ {
const int n = _pattern.length(); const int n = _pattern.length();
do { do {
sdfat::File32 file; sdfat::File file;
file.openNext(_dir.get(), sdfat::O_READ); file.openNext(_dir.get(), sdfat::O_READ);
if (file) { if (file) {
_valid = 1; _valid = 1;
_size = file.fileSize(); _size = file.fileSize();
_isFile = file.isFile(); _isFile = file.isFile();
_isDirectory = file.isDir(); _isDirectory = file.isDirectory();
sdfat::DirFat_t tmp; sdfat::dir_t tmp;
if (file.dirEntry(&tmp)) { if (file.dirEntry(&tmp)) {
_time = SDFSImpl::FatToTimeT(*(uint16_t*)tmp.modifyDate, *(uint16_t*)tmp.modifyTime); _time = SDFSImpl::FatToTimeT(tmp.lastWriteDate, tmp.lastWriteTime);
_creation = SDFSImpl::FatToTimeT(*(uint16_t*)tmp.createDate, *(uint16_t*)tmp.createTime); _creation = SDFSImpl::FatToTimeT(tmp.creationDate, tmp.creationTime);
} else { } else {
_time = 0; _time = 0;
_creation = 0; _creation = 0;
@ -518,7 +516,7 @@ public:
protected: protected:
String _pattern; String _pattern;
SDFSImpl* _fs; SDFSImpl* _fs;
std::shared_ptr<sdfat::File32> _dir; std::shared_ptr<sdfat::File> _dir;
bool _valid; bool _valid;
char _lfn[64]; char _lfn[64];
time_t _time; time_t _time;

View File

@ -0,0 +1,405 @@
/*
SDFSFormatter.cpp - Formatter for SdFat SD cards
Copyright (c) 2019 Earle F. Philhower, III. All rights reserved.
A C++ implementation of the SdFat/examples/SdFormatter sketch:
| Copyright (c) 2011-2018 Bill Greiman
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 _SDFSFORMATTER_H
#define _SDFSFORMATTER_H
#include "SDFS.h"
#include <FS.h>
#include <PolledTimeout.h>
namespace sdfs {
class SDFSFormatter {
private:
// Taken from main FS object
sdfat::Sd2Card *card;
sdfat::cache_t *cache;
uint32_t cardSizeBlocks;
uint32_t cardCapacityMB;
// MBR information
uint8_t partType;
uint32_t relSector;
uint32_t partSize;
// Fake disk geometry
uint8_t numberOfHeads;
uint8_t sectorsPerTrack;
// FAT parameters
uint16_t reservedSectors;
uint8_t sectorsPerCluster;
uint32_t fatStart;
uint32_t fatSize;
uint32_t dataStart;
uint8_t writeCache(uint32_t lbn) {
return card->writeBlock(lbn, cache->data);
}
void clearCache(uint8_t addSig) {
memset(cache, 0, sizeof(*cache));
if (addSig) {
cache->mbr.mbrSig0 = sdfat::BOOTSIG0;
cache->mbr.mbrSig1 = sdfat::BOOTSIG1;
}
}
bool clearFatDir(uint32_t bgn, uint32_t count) {
clearCache(false);
if (!card->writeStart(bgn, count)) {
DEBUGV("SDFS: Clear FAT/DIR writeStart failed");
return false;
}
esp8266::polledTimeout::periodicFastMs timeToYield(5); // Yield every 5ms of runtime
for (uint32_t i = 0; i < count; i++) {
if (timeToYield) {
delay(0); // WDT feed
}
if (!card->writeData(cache->data)) {
DEBUGV("SDFS: Clear FAT/DIR writeData failed");
return false;
}
}
if (!card->writeStop()) {
DEBUGV("SDFS: Clear FAT/DIR writeStop failed");
return false;
}
return true;
}
uint16_t lbnToCylinder(uint32_t lbn) {
return lbn / (numberOfHeads * sectorsPerTrack);
}
uint8_t lbnToHead(uint32_t lbn) {
return (lbn % (numberOfHeads * sectorsPerTrack)) / sectorsPerTrack;
}
uint8_t lbnToSector(uint32_t lbn) {
return (lbn % sectorsPerTrack) + 1;
}
bool writeMbr() {
clearCache(true);
sdfat::part_t* p = cache->mbr.part;
p->boot = 0;
uint16_t c = lbnToCylinder(relSector);
if (c > 1023) {
DEBUGV("SDFS: MBR CHS");
return false;
}
p->beginCylinderHigh = c >> 8;
p->beginCylinderLow = c & 0XFF;
p->beginHead = lbnToHead(relSector);
p->beginSector = lbnToSector(relSector);
p->type = partType;
uint32_t endLbn = relSector + partSize - 1;
c = lbnToCylinder(endLbn);
if (c <= 1023) {
p->endCylinderHigh = c >> 8;
p->endCylinderLow = c & 0XFF;
p->endHead = lbnToHead(endLbn);
p->endSector = lbnToSector(endLbn);
} else {
// Too big flag, c = 1023, h = 254, s = 63
p->endCylinderHigh = 3;
p->endCylinderLow = 255;
p->endHead = 254;
p->endSector = 63;
}
p->firstSector = relSector;
p->totalSectors = partSize;
if (!writeCache(0)) {
DEBUGV("SDFS: write MBR");
return false;
}
return true;
}
uint32_t volSerialNumber() {
return (cardSizeBlocks << 8) + micros();
}
bool makeFat16() {
uint16_t const BU16 = 128;
uint32_t nc;
for (dataStart = 2 * BU16;; dataStart += BU16) {
nc = (cardSizeBlocks - dataStart)/sectorsPerCluster;
fatSize = (nc + 2 + 255)/256;
uint32_t r = BU16 + 1 + 2 * fatSize + 32;
if (dataStart < r) {
continue;
}
relSector = dataStart - r + BU16;
break;
}
// check valid cluster count for FAT16 volume
if (nc < 4085 || nc >= 65525) {
DEBUGV("SDFS: Bad cluster count");
}
reservedSectors = 1;
fatStart = relSector + reservedSectors;
partSize = nc * sectorsPerCluster + 2 * fatSize + reservedSectors + 32;
if (partSize < 32680) {
partType = 0X01;
} else if (partSize < 65536) {
partType = 0X04;
} else {
partType = 0X06;
}
// write MBR
if (!writeMbr()) {
DEBUGV("SDFS: writembr failed");
return false;
}
clearCache(true);
sdfat::fat_boot_t* pb = &cache->fbs;
pb->jump[0] = 0XEB;
pb->jump[1] = 0X00;
pb->jump[2] = 0X90;
for (uint8_t i = 0; i < sizeof(pb->oemId); i++) {
pb->oemId[i] = ' ';
}
pb->bytesPerSector = 512;
pb->sectorsPerCluster = sectorsPerCluster;
pb->reservedSectorCount = reservedSectors;
pb->fatCount = 2;
pb->rootDirEntryCount = 512;
pb->mediaType = 0XF8;
pb->sectorsPerFat16 = fatSize;
pb->sectorsPerTrack = sectorsPerTrack;
pb->headCount = numberOfHeads;
pb->hidddenSectors = relSector;
pb->totalSectors32 = partSize;
pb->driveNumber = 0X80;
pb->bootSignature = sdfat::EXTENDED_BOOT_SIG;
pb->volumeSerialNumber = volSerialNumber();
memcpy_P(pb->volumeLabel, PSTR("NO NAME "), sizeof(pb->volumeLabel));
memcpy_P(pb->fileSystemType, PSTR("FAT16 "), sizeof(pb->fileSystemType));
// write partition boot sector
if (!writeCache(relSector)) {
DEBUGV("SDFS: FAT16 write PBS failed");
return false;
}
// clear FAT and root directory
if (!clearFatDir(fatStart, dataStart - fatStart)) {
DEBUGV("SDFS: FAT16 clear root failed\n");
return false;
}
clearCache(false);
cache->fat16[0] = 0XFFF8;
cache->fat16[1] = 0XFFFF;
// write first block of FAT and backup for reserved clusters
if (!writeCache(fatStart) || !writeCache(fatStart + fatSize)) {
DEBUGV("FAT16 reserve failed");
return false;
}
return true;
}
bool makeFat32() {
uint16_t const BU32 = 8192;
uint32_t nc;
relSector = BU32;
for (dataStart = 2 * BU32;; dataStart += BU32) {
nc = (cardSizeBlocks - dataStart)/sectorsPerCluster;
fatSize = (nc + 2 + 127)/128;
uint32_t r = relSector + 9 + 2 * fatSize;
if (dataStart >= r) {
break;
}
}
// error if too few clusters in FAT32 volume
if (nc < 65525) {
DEBUGV("SDFS: Bad cluster count");
return false;
}
reservedSectors = dataStart - relSector - 2 * fatSize;
fatStart = relSector + reservedSectors;
partSize = nc * sectorsPerCluster + dataStart - relSector;
// type depends on address of end sector
// max CHS has lbn = 16450560 = 1024*255*63
if ((relSector + partSize) <= 16450560) {
// FAT32
partType = 0X0B;
} else {
// FAT32 with INT 13
partType = 0X0C;
}
if (!writeMbr()) {
DEBUGV("SDFS: writembr failed");
return false;
}
clearCache(true);
sdfat::fat32_boot_t* pb = &cache->fbs32;
pb->jump[0] = 0XEB;
pb->jump[1] = 0X00;
pb->jump[2] = 0X90;
for (uint8_t i = 0; i < sizeof(pb->oemId); i++) {
pb->oemId[i] = ' ';
}
pb->bytesPerSector = 512;
pb->sectorsPerCluster = sectorsPerCluster;
pb->reservedSectorCount = reservedSectors;
pb->fatCount = 2;
pb->mediaType = 0XF8;
pb->sectorsPerTrack = sectorsPerTrack;
pb->headCount = numberOfHeads;
pb->hidddenSectors = relSector;
pb->totalSectors32 = partSize;
pb->sectorsPerFat32 = fatSize;
pb->fat32RootCluster = 2;
pb->fat32FSInfo = 1;
pb->fat32BackBootBlock = 6;
pb->driveNumber = 0X80;
pb->bootSignature = sdfat::EXTENDED_BOOT_SIG;
pb->volumeSerialNumber = volSerialNumber();
memcpy_P(pb->volumeLabel, PSTR("NO NAME "), sizeof(pb->volumeLabel));
memcpy_P(pb->fileSystemType, PSTR("FAT32 "), sizeof(pb->fileSystemType));
// write partition boot sector and backup
if (!writeCache(relSector) || !writeCache(relSector + 6)) {
DEBUGV("SDFS: FAT32 write PBS failed");
return false;
}
clearCache(true);
// write extra boot area and backup
if (!writeCache(relSector + 2) || !writeCache(relSector + 8)) {
DEBUGV("SDFS: FAT32 PBS ext failed");
return false;
}
sdfat::fat32_fsinfo_t* pf = &cache->fsinfo;
pf->leadSignature = sdfat::FSINFO_LEAD_SIG;
pf->structSignature = sdfat::FSINFO_STRUCT_SIG;
pf->freeCount = 0XFFFFFFFF;
pf->nextFree = 0XFFFFFFFF;
// write FSINFO sector and backup
if (!writeCache(relSector + 1) || !writeCache(relSector + 7)) {
DEBUGV("SDFS: FAT32 FSINFO failed");
return false;
}
clearFatDir(fatStart, 2 * fatSize + sectorsPerCluster);
clearCache(false);
cache->fat32[0] = 0x0FFFFFF8;
cache->fat32[1] = 0x0FFFFFFF;
cache->fat32[2] = 0x0FFFFFFF;
// write first block of FAT and backup for reserved clusters
if (!writeCache(fatStart) || !writeCache(fatStart + fatSize)) {
DEBUGV("SDFS: FAT32 reserve failed");
return false;
}
return true;
}
public:
bool format(sdfat::SdFat *_fs, int8_t _csPin, SPISettings _spiSettings) {
card = static_cast<sdfat::Sd2Card*>(_fs->card());
cache = _fs->cacheClear();
if (!card->begin(_csPin, _spiSettings)) {
return false;
}
cardSizeBlocks = card->cardSize();
if (cardSizeBlocks == 0) {
return false;
}
cardCapacityMB = (cardSizeBlocks + 2047)/2048;
if (cardCapacityMB <= 6) {
return false; // Card is too small
} else if (cardCapacityMB <= 16) {
sectorsPerCluster = 2;
} else if (cardCapacityMB <= 32) {
sectorsPerCluster = 4;
} else if (cardCapacityMB <= 64) {
sectorsPerCluster = 8;
} else if (cardCapacityMB <= 128) {
sectorsPerCluster = 16;
} else if (cardCapacityMB <= 1024) {
sectorsPerCluster = 32;
} else if (cardCapacityMB <= 32768) {
sectorsPerCluster = 64;
} else {
// SDXC cards
sectorsPerCluster = 128;
}
// set fake disk geometry
sectorsPerTrack = cardCapacityMB <= 256 ? 32 : 63;
if (cardCapacityMB <= 16) {
numberOfHeads = 2;
} else if (cardCapacityMB <= 32) {
numberOfHeads = 4;
} else if (cardCapacityMB <= 128) {
numberOfHeads = 8;
} else if (cardCapacityMB <= 504) {
numberOfHeads = 16;
} else if (cardCapacityMB <= 1008) {
numberOfHeads = 32;
} else if (cardCapacityMB <= 2016) {
numberOfHeads = 64;
} else if (cardCapacityMB <= 4032) {
numberOfHeads = 128;
} else {
numberOfHeads = 255;
}
// Erase all data on card (TRIM)
uint32_t const ERASE_SIZE = 262144L;
uint32_t firstBlock = 0;
uint32_t lastBlock;
do {
lastBlock = firstBlock + ERASE_SIZE - 1;
if (lastBlock >= cardSizeBlocks) {
lastBlock = cardSizeBlocks - 1;
}
if (!card->erase(firstBlock, lastBlock)) {
return false; // Erase fail
}
delay(0); // yield to the OS to avoid WDT
firstBlock += ERASE_SIZE;
} while (firstBlock < cardSizeBlocks);
if (!card->readBlock(0, cache->data)) {
return false;
}
if (card->type() != sdfat::SD_CARD_TYPE_SDHC) {
return makeFat16();
} else {
return makeFat32();
}
}
}; // class SDFSFormatter
}; // namespace sdfs
#endif // _SDFSFORMATTER_H

View File

@ -1,4 +1,4 @@
WebSocket Server and Client for Arduino [![Build Status](https://github.com/Links2004/arduinoWebSockets/workflows/CI/badge.svg?branch=master)](https://github.com/Links2004/arduinoWebSockets/actions?query=workflow%3ACI+branch%3Amaster) WebSocket Server and Client for Arduino [![Build Status](https://travis-ci.org/Links2004/arduinoWebSockets.svg?branch=master)](https://travis-ci.org/Links2004/arduinoWebSockets)
=========================================== ===========================================
a WebSocket Server and Client for Arduino based on RFC6455. a WebSocket Server and Client for Arduino based on RFC6455.
@ -34,9 +34,7 @@ a WebSocket Server and Client for Arduino based on RFC6455.
###### Note: ###### ###### Note: ######
version 2.0.0 and up is not compatible with AVR/ATmega, check ATmega branch. version 2.0 and up is not compatible with AVR/ATmega, check ATmega branch.
version 2.3.0 has API changes for the ESP8266 BareSSL (may brakes existing code)
Arduino for AVR not supports std namespace of c++. Arduino for AVR not supports std namespace of c++.
@ -59,34 +57,32 @@ The mode can be activated in the ```WebSockets.h``` (see WEBSOCKETS_NETWORK_TYPE
### High Level Client API ### ### High Level Client API ###
- `begin` : Initiate connection sequence to the websocket host. - `begin` : Initiate connection sequence to the websocket host.
```c++ ```
void begin(const char *host, uint16_t port, const char * url = "/", const char * protocol = "arduino"); void begin(const char *host, uint16_t port, const char * url = "/", const char * protocol = "arduino");
void begin(String host, uint16_t port, String url = "/", String protocol = "arduino"); void begin(String host, uint16_t port, String url = "/", String protocol = "arduino");
``` ```
- `onEvent`: Callback to handle for websocket events - `onEvent`: Callback to handle for websocket events
```c++ ```
void onEvent(WebSocketClientEvent cbEvent); void onEvent(WebSocketClientEvent cbEvent);
``` ```
- `WebSocketClientEvent`: Handler for websocket events - `WebSocketClientEvent`: Handler for websocket events
```c++ ```
void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length) void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length)
``` ```
Where `WStype_t type` is defined as: Where `WStype_t type` is defined as:
```c++ ```
typedef enum { typedef enum {
WStype_ERROR, WStype_ERROR,
WStype_DISCONNECTED, WStype_DISCONNECTED,
WStype_CONNECTED, WStype_CONNECTED,
WStype_TEXT, WStype_TEXT,
WStype_BIN, WStype_BIN,
WStype_FRAGMENT_TEXT_START, WStype_FRAGMENT_TEXT_START,
WStype_FRAGMENT_BIN_START, WStype_FRAGMENT_BIN_START,
WStype_FRAGMENT, WStype_FRAGMENT,
WStype_FRAGMENT_FIN, WStype_FRAGMENT_FIN,
WStype_PING,
WStype_PONG,
} WStype_t; } WStype_t;
``` ```

View File

@ -1,103 +0,0 @@
/*
* WebSocketClientSSLWithCA.ino
*
* Created on: 27.10.2019
*
* note SSL is only possible with the ESP8266
*
*/
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <WebSocketsClient.h>
ESP8266WiFiMulti WiFiMulti;
WebSocketsClient webSocket;
#define USE_SERIAL Serial1
// Can be obtained with:
// openssl s_client -showcerts -connect echo.websocket.org:443 </dev/null
const char ENDPOINT_CA_CERT[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0NlowSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWAa6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNvbTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAwVAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsFAAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlGPfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
-----END CERTIFICATE-----
)EOF";
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
switch(type) {
case WStype_DISCONNECTED:
USE_SERIAL.printf("[WSc] Disconnected!\n");
break;
case WStype_CONNECTED:
{
USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);
// send message to server when Connected
webSocket.sendTXT("Connected");
}
break;
case WStype_TEXT:
USE_SERIAL.printf("[WSc] get text: %s\n", payload);
// send message to server
// webSocket.sendTXT("message here");
break;
case WStype_BIN:
USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
hexdump(payload, length);
// send data to server
// webSocket.sendBIN(payload, length);
break;
}
}
void setup() {
USE_SERIAL.begin(115200);
USE_SERIAL.setDebugOutput(true);
USE_SERIAL.println();
USE_SERIAL.println();
USE_SERIAL.println();
for(uint8_t t = 4; t > 0; t--) {
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
USE_SERIAL.flush();
delay(1000);
}
WiFiMulti.addAP("SSID", "passpasspass");
while(WiFiMulti.run() != WL_CONNECTED) {
delay(100);
}
//When using BearSSL, client certificate and private key can be set:
//webSocket.setSSLClientCertKey(clientCert, clientPrivateKey);
//clientCert and clientPrivateKey can be of types (const char *, const char *) , or of types (BearSSL::X509List, BearSSL::PrivateKey)
webSocket.beginSslWithCA("echo.websocket.org", 443, "/", ENDPOINT_CA_CERT);
webSocket.onEvent(webSocketEvent);
}
void loop() {
webSocket.loop();
}

View File

@ -29,9 +29,6 @@ void socketIOEvent(socketIOmessageType_t type, uint8_t * payload, size_t length)
break; break;
case sIOtype_CONNECT: case sIOtype_CONNECT:
USE_SERIAL.printf("[IOc] Connected to url: %s\n", payload); USE_SERIAL.printf("[IOc] Connected to url: %s\n", payload);
// join default namespace (no auto join in Socket.IO V3)
socketIO.send(sIOtype_CONNECT, "/");
break; break;
case sIOtype_EVENT: case sIOtype_EVENT:
USE_SERIAL.printf("[IOc] get event: %s\n", payload); USE_SERIAL.printf("[IOc] get event: %s\n", payload);
@ -113,7 +110,7 @@ void loop() {
// add payload (parameters) for the event // add payload (parameters) for the event
JsonObject param1 = array.createNestedObject(); JsonObject param1 = array.createNestedObject();
param1["now"] = (uint32_t) now; param1["now"] = now;
// JSON to String (serializion) // JSON to String (serializion)
String output; String output;

View File

@ -1,165 +0,0 @@
/*
* WebSocketClientSocketIOack.ino
*
* Created on: 20.07.2019
*
*/
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ArduinoJson.h>
#include <WebSocketsClient.h>
#include <SocketIOclient.h>
#include <Hash.h>
ESP8266WiFiMulti WiFiMulti;
SocketIOclient socketIO;
#define USE_SERIAL Serial
void socketIOEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) {
switch(type) {
case sIOtype_DISCONNECT:
USE_SERIAL.printf("[IOc] Disconnected!\n");
break;
case sIOtype_CONNECT:
USE_SERIAL.printf("[IOc] Connected to url: %s\n", payload);
// join default namespace (no auto join in Socket.IO V3)
socketIO.send(sIOtype_CONNECT, "/");
break;
case sIOtype_EVENT:
{
char * sptr = NULL;
int id = strtol((char *)payload, &sptr, 10);
USE_SERIAL.printf("[IOc] get event: %s id: %d\n", payload, id);
if(id) {
payload = (uint8_t *)sptr;
}
DynamicJsonDocument doc(1024);
DeserializationError error = deserializeJson(doc, payload, length);
if(error) {
USE_SERIAL.print(F("deserializeJson() failed: "));
USE_SERIAL.println(error.c_str());
return;
}
String eventName = doc[0];
USE_SERIAL.printf("[IOc] event name: %s\n", eventName.c_str());
// Message Includes a ID for a ACK (callback)
if(id) {
// creat JSON message for Socket.IO (ack)
DynamicJsonDocument docOut(1024);
JsonArray array = docOut.to<JsonArray>();
// add payload (parameters) for the ack (callback function)
JsonObject param1 = array.createNestedObject();
param1["now"] = millis();
// JSON to String (serializion)
String output;
output += id;
serializeJson(docOut, output);
// Send event
socketIO.send(sIOtype_ACK, output);
}
}
break;
case sIOtype_ACK:
USE_SERIAL.printf("[IOc] get ack: %u\n", length);
hexdump(payload, length);
break;
case sIOtype_ERROR:
USE_SERIAL.printf("[IOc] get error: %u\n", length);
hexdump(payload, length);
break;
case sIOtype_BINARY_EVENT:
USE_SERIAL.printf("[IOc] get binary: %u\n", length);
hexdump(payload, length);
break;
case sIOtype_BINARY_ACK:
USE_SERIAL.printf("[IOc] get binary ack: %u\n", length);
hexdump(payload, length);
break;
}
}
void setup() {
//USE_SERIAL.begin(921600);
USE_SERIAL.begin(115200);
//Serial.setDebugOutput(true);
USE_SERIAL.setDebugOutput(true);
USE_SERIAL.println();
USE_SERIAL.println();
USE_SERIAL.println();
for(uint8_t t = 4; t > 0; t--) {
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
USE_SERIAL.flush();
delay(1000);
}
// disable AP
if(WiFi.getMode() & WIFI_AP) {
WiFi.softAPdisconnect(true);
}
WiFiMulti.addAP("SSID", "passpasspass");
//WiFi.disconnect();
while(WiFiMulti.run() != WL_CONNECTED) {
delay(100);
}
String ip = WiFi.localIP().toString();
USE_SERIAL.printf("[SETUP] WiFi Connected %s\n", ip.c_str());
// server address, port and URL
socketIO.begin("10.11.100.100", 8880);
// event handler
socketIO.onEvent(socketIOEvent);
}
unsigned long messageTimestamp = 0;
void loop() {
socketIO.loop();
uint64_t now = millis();
if(now - messageTimestamp > 2000) {
messageTimestamp = now;
// creat JSON message for Socket.IO (event)
DynamicJsonDocument doc(1024);
JsonArray array = doc.to<JsonArray>();
// add evnet name
// Hint: socket.on('event_name', ....
array.add("event_name");
// add payload (parameters) for the event
JsonObject param1 = array.createNestedObject();
param1["now"] = (uint32_t) now;
// JSON to String (serializion)
String output;
serializeJson(doc, output);
// Send event
socketIO.sendEVENT(output);
// Print JSON for debugging
USE_SERIAL.println(output);
}
}

View File

@ -1,103 +0,0 @@
/*
* WebSocketServerHooked.ino
*
* Created on: 22.05.2015
* Hooked on: 28.10.2020
*
*/
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <WebSockets4WebServer.h>
#include <Hash.h>
#include <ESP8266mDNS.h>
ESP8266WiFiMulti WiFiMulti;
ESP8266WebServer server(80);
WebSockets4WebServer webSocket;
#define USE_SERIAL Serial
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
switch(type) {
case WStype_DISCONNECTED:
USE_SERIAL.printf("[%u] Disconnected!\n", num);
break;
case WStype_CONNECTED:
{
IPAddress ip = webSocket.remoteIP(num);
USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
// send message to client
webSocket.sendTXT(num, "Connected");
}
break;
case WStype_TEXT:
USE_SERIAL.printf("[%u] get Text: %s\n", num, payload);
// send message to client
// webSocket.sendTXT(num, "message here");
// send data to all connected clients
// webSocket.broadcastTXT("message here");
break;
case WStype_BIN:
USE_SERIAL.printf("[%u] get binary length: %u\n", num, length);
hexdump(payload, length);
// send message to client
// webSocket.sendBIN(num, payload, length);
break;
}
}
void setup() {
// USE_SERIAL.begin(921600);
USE_SERIAL.begin(115200);
//Serial.setDebugOutput(true);
USE_SERIAL.setDebugOutput(true);
USE_SERIAL.println();
USE_SERIAL.println();
USE_SERIAL.println();
for(uint8_t t = 4; t > 0; t--) {
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
USE_SERIAL.flush();
delay(1000);
}
WiFiMulti.addAP("SSID", "passpasspass");
while(WiFiMulti.run() != WL_CONNECTED) {
delay(100);
}
server.on("/", []() {
server.send(200, "text/plain", "I am a regular webserver on port 80!\r\n");
server.send(200, "text/plain", "I am also a websocket server on '/ws' on the same port 80\r\n");
});
server.addHook(webSocket.hookForWebserver("/ws", webSocketEvent));
server.begin();
Serial.println("HTTP server started on port 80");
Serial.println("WebSocket server started on the same port");
Serial.printf("my network address is either 'arduinoWebsockets.local' (mDNS) or '%s'\n", WiFi.localIP().toString().c_str());
if (!MDNS.begin("arduinoWebsockets")) {
Serial.println("Error setting up MDNS responder!");
}
}
void loop() {
server.handleClient();
webSocket.loop();
MDNS.update();
}

View File

@ -1,20 +0,0 @@
#!/bin/sh
# linux script to compile&run arduinoWebSockets in a mock environment
if [ -z "$ESP8266ARDUINO" ]; then
echo "please set ESP8266ARDUINO env-var to where esp8266/arduino sits"
exit 1
fi
set -e
where=$(pwd)
cd $ESP8266ARDUINO/tests/host/
make -j FORCE32=0 \
ULIBDIRS=../../libraries/Hash/:~/dev/proj/arduino/libraries/arduinoWebSockets \
${where}/WebSocketServerHooked
valgrind ./bin/WebSocketServerHooked/WebSocketServerHooked -b "$@"

View File

@ -1,45 +0,0 @@
#!/usr/bin/env python3
# python websocket client to test with
# emulator: server is at ws://127.0.0.1:9080/ws
# esp8266: server is at ws:///ws
# (uncomment the right line below)
#uri = "ws://127.0.0.1:9080/ws"
uri = "ws://arduinoWebsockets.local/ws"
import websocket
try:
import thread
except ImportError:
import _thread as thread
import time
def on_message(ws, message):
print("message");
print(message)
def on_error(ws, error):
print("error")
print(error)
def on_close(ws):
print("### closed ###")
def on_open(ws):
print("opened")
def run(*args):
for i in range(3):
time.sleep(1)
ws.send("Hello %d" % i)
time.sleep(1)
ws.close()
print("thread terminating...")
thread.start_new_thread(run, ())
if __name__ == "__main__":
websocket.enableTrace(True)
ws = websocket.WebSocketApp(uri, on_message = on_message, on_error = on_error, on_close = on_close)
ws.on_open = on_open
ws.run_forever()

View File

@ -1,25 +1,25 @@
{ {
"name": "WebSockets",
"description": "WebSocket Server and Client for Arduino based on RFC6455",
"keywords": "wifi, http, web, server, client, websocket",
"authors": [ "authors": [
{ {
"maintainer": true,
"name": "Markus Sattler", "name": "Markus Sattler",
"url": "https://github.com/Links2004" "url": "https://github.com/Links2004",
"maintainer": true
} }
], ],
"description": "WebSocket Server and Client for Arduino based on RFC6455", "repository": {
"type": "git",
"url": "https://github.com/Links2004/arduinoWebSockets.git"
},
"version": "2.1.4",
"license": "LGPL-2.1",
"export": { "export": {
"exclude": [ "exclude": [
"tests" "tests"
] ]
}, },
"frameworks": "arduino", "frameworks": "arduino",
"keywords": "wifi, http, web, server, client, websocket", "platforms": "atmelavr, espressif8266, espressif32"
"license": "LGPL-2.1", }
"name": "WebSockets",
"platforms": "atmelavr, espressif8266, espressif32",
"repository": {
"type": "git",
"url": "https://github.com/Links2004/arduinoWebSockets.git"
},
"version": "2.3.5"
}

View File

@ -1,5 +1,5 @@
name=WebSockets name=WebSockets
version=2.3.5 version=2.1.4
author=Markus Sattler author=Markus Sattler
maintainer=Markus Sattler maintainer=Markus Sattler
sentence=WebSockets for Arduino (Server + Client) sentence=WebSockets for Arduino (Server + Client)

View File

@ -18,59 +18,11 @@ SocketIOclient::~SocketIOclient() {
void SocketIOclient::begin(const char * host, uint16_t port, const char * url, const char * protocol) { void SocketIOclient::begin(const char * host, uint16_t port, const char * url, const char * protocol) {
WebSocketsClient::beginSocketIO(host, port, url, protocol); WebSocketsClient::beginSocketIO(host, port, url, protocol);
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5); WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
initClient();
} }
void SocketIOclient::begin(String host, uint16_t port, String url, String protocol) { void SocketIOclient::begin(String host, uint16_t port, String url, String protocol) {
WebSocketsClient::beginSocketIO(host, port, url, protocol); WebSocketsClient::beginSocketIO(host, port, url, protocol);
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5); WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
initClient();
}
#if defined(HAS_SSL)
void SocketIOclient::beginSSL(const char * host, uint16_t port, const char * url, const char * protocol) {
WebSocketsClient::beginSocketIOSSL(host, port, url, protocol);
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
initClient();
}
void SocketIOclient::beginSSL(String host, uint16_t port, String url, String protocol) {
WebSocketsClient::beginSocketIOSSL(host, port, url, protocol);
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
initClient();
}
#if defined(SSL_BARESSL)
void SocketIOclient::beginSSLWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) {
WebSocketsClient::beginSocketIOSSLWithCA(host, port, url, CA_cert, protocol);
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
initClient();
}
void SocketIOclient::beginSSLWithCA(const char * host, uint16_t port, const char * url, BearSSL::X509List * CA_cert, const char * protocol) {
WebSocketsClient::beginSocketIOSSLWithCA(host, port, url, CA_cert, protocol);
WebSocketsClient::enableHeartbeat(60 * 1000, 90 * 1000, 5);
initClient();
}
void SocketIOclient::setSSLClientCertKey(const char * clientCert, const char * clientPrivateKey) {
WebSocketsClient::setSSLClientCertKey(clientCert, clientPrivateKey);
}
void SocketIOclient::setSSLClientCertKey(BearSSL::X509List * clientCert, BearSSL::PrivateKey * clientPrivateKey) {
WebSocketsClient::setSSLClientCertKey(clientCert, clientPrivateKey);
}
#endif
#endif
void SocketIOclient::configureEIOping(bool disableHeartbeat) {
_disableHeartbeat = disableHeartbeat;
}
void SocketIOclient::initClient(void) {
if(_client.cUrl.indexOf("EIO=4") != -1) {
DEBUG_WEBSOCKETS("[wsIOc] found EIO=4 disable EIO ping on client\n");
configureEIOping(true);
}
} }
/** /**
@ -88,24 +40,23 @@ bool SocketIOclient::isConnected(void) {
/** /**
* send text data to client * send text data to client
* @param num uint8_t client id * @param num uint8_t client id
* @param type socketIOmessageType_t
* @param payload uint8_t * * @param payload uint8_t *
* @param length size_t * @param length size_t
* @param headerToPayload bool (see sendFrame for more details) * @param headerToPayload bool (see sendFrame for more details)
* @return true if ok * @return true if ok
*/ */
bool SocketIOclient::send(socketIOmessageType_t type, uint8_t * payload, size_t length, bool headerToPayload) { bool SocketIOclient::sendEVENT(uint8_t * payload, size_t length, bool headerToPayload) {
bool ret = false; bool ret = false;
if(length == 0) { if(length == 0) {
length = strlen((const char *)payload); length = strlen((const char *)payload);
} }
if(clientIsConnected(&_client) && _client.status == WSC_CONNECTED) { if(clientIsConnected(&_client)) {
if(!headerToPayload) { if(!headerToPayload) {
// webSocket Header // webSocket Header
ret = WebSocketsClient::sendFrameHeader(&_client, WSop_text, length + 2, true); ret = WebSocketsClient::sendFrameHeader(&_client, WSop_text, length + 2, true);
// Engine.IO / Socket.IO Header // Engine.IO / Socket.IO Header
if(ret) { if(ret) {
uint8_t buf[3] = { eIOtype_MESSAGE, type, 0x00 }; uint8_t buf[3] = { eIOtype_MESSAGE, sIOtype_EVENT, 0x00 };
ret = WebSocketsClient::write(&_client, buf, 2); ret = WebSocketsClient::write(&_client, buf, 2);
} }
if(ret && payload && length > 0) { if(ret && payload && length > 0) {
@ -115,38 +66,12 @@ bool SocketIOclient::send(socketIOmessageType_t type, uint8_t * payload, size_t
} else { } else {
// TODO implement // TODO implement
} }
// return WebSocketsClient::sendFrame(&_client, WSop_text, payload, length, true, true, headerToPayload);
} }
return false; return false;
} }
bool SocketIOclient::send(socketIOmessageType_t type, const uint8_t * payload, size_t length) {
return send(type, (uint8_t *)payload, length);
}
bool SocketIOclient::send(socketIOmessageType_t type, char * payload, size_t length, bool headerToPayload) {
return send(type, (uint8_t *)payload, length, headerToPayload);
}
bool SocketIOclient::send(socketIOmessageType_t type, const char * payload, size_t length) {
return send(type, (uint8_t *)payload, length);
}
bool SocketIOclient::send(socketIOmessageType_t type, String & payload) {
return send(type, (uint8_t *)payload.c_str(), payload.length());
}
/**
* send text data to client
* @param num uint8_t client id
* @param payload uint8_t *
* @param length size_t
* @param headerToPayload bool (see sendFrame for more details)
* @return true if ok
*/
bool SocketIOclient::sendEVENT(uint8_t * payload, size_t length, bool headerToPayload) {
return send(sIOtype_EVENT, payload, length, headerToPayload);
}
bool SocketIOclient::sendEVENT(const uint8_t * payload, size_t length) { bool SocketIOclient::sendEVENT(const uint8_t * payload, size_t length) {
return sendEVENT((uint8_t *)payload, length); return sendEVENT((uint8_t *)payload, length);
} }
@ -166,8 +91,8 @@ bool SocketIOclient::sendEVENT(String & payload) {
void SocketIOclient::loop(void) { void SocketIOclient::loop(void) {
WebSocketsClient::loop(); WebSocketsClient::loop();
unsigned long t = millis(); unsigned long t = millis();
if(!_disableHeartbeat && (t - _lastHeartbeat) > EIO_HEARTBEAT_INTERVAL) { if((t - _lastConnectionFail) > EIO_HEARTBEAT_INTERVAL) {
_lastHeartbeat = t; _lastConnectionFail = t;
DEBUG_WEBSOCKETS("[wsIOc] send ping\n"); DEBUG_WEBSOCKETS("[wsIOc] send ping\n");
WebSocketsClient::sendTXT(eIOtype_PING); WebSocketsClient::sendTXT(eIOtype_PING);
} }
@ -183,7 +108,6 @@ void SocketIOclient::handleCbEvent(WStype_t type, uint8_t * payload, size_t leng
DEBUG_WEBSOCKETS("[wsIOc] Connected to url: %s\n", payload); DEBUG_WEBSOCKETS("[wsIOc] Connected to url: %s\n", payload);
// send message to server when Connected // send message to server when Connected
// Engine.io upgrade confirmation message (required) // Engine.io upgrade confirmation message (required)
WebSocketsClient::sendTXT("2probe");
WebSocketsClient::sendTXT(eIOtype_UPGRADE); WebSocketsClient::sendTXT(eIOtype_UPGRADE);
runIOCbEvent(sIOtype_CONNECT, payload, length); runIOCbEvent(sIOtype_CONNECT, payload, length);
} break; } break;
@ -214,8 +138,6 @@ void SocketIOclient::handleCbEvent(WStype_t type, uint8_t * payload, size_t leng
DEBUG_WEBSOCKETS("[wsIOc] get event (%d): %s\n", lData, data); DEBUG_WEBSOCKETS("[wsIOc] get event (%d): %s\n", lData, data);
break; break;
case sIOtype_CONNECT: case sIOtype_CONNECT:
DEBUG_WEBSOCKETS("[wsIOc] connected (%d): %s\n", lData, data);
return;
case sIOtype_DISCONNECT: case sIOtype_DISCONNECT:
case sIOtype_ACK: case sIOtype_ACK:
case sIOtype_ERROR: case sIOtype_ERROR:
@ -239,7 +161,7 @@ void SocketIOclient::handleCbEvent(WStype_t type, uint8_t * payload, size_t leng
break; break;
} }
} break; } break;
case WStype_ERROR:
case WStype_BIN: case WStype_BIN:
case WStype_FRAGMENT_TEXT_START: case WStype_FRAGMENT_TEXT_START:
case WStype_FRAGMENT_BIN_START: case WStype_FRAGMENT_BIN_START:

View File

@ -49,16 +49,6 @@ class SocketIOclient : protected WebSocketsClient {
void begin(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino"); void begin(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino");
void begin(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino"); void begin(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino");
#ifdef HAS_SSL
void beginSSL(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino");
void beginSSL(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino");
#ifndef SSL_AXTLS
void beginSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * CA_cert = NULL, const char * protocol = "arduino");
void beginSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", BearSSL::X509List * CA_cert = NULL, const char * protocol = "arduino");
void setSSLClientCertKey(const char * clientCert = NULL, const char * clientPrivateKey = NULL);
void setSSLClientCertKey(BearSSL::X509List * clientCert = NULL, BearSSL::PrivateKey * clientPrivateKey = NULL);
#endif
#endif
bool isConnected(void); bool isConnected(void);
void onEvent(SocketIOclientEvent cbEvent); void onEvent(SocketIOclientEvent cbEvent);
@ -69,18 +59,9 @@ class SocketIOclient : protected WebSocketsClient {
bool sendEVENT(const char * payload, size_t length = 0); bool sendEVENT(const char * payload, size_t length = 0);
bool sendEVENT(String & payload); bool sendEVENT(String & payload);
bool send(socketIOmessageType_t type, uint8_t * payload, size_t length = 0, bool headerToPayload = false);
bool send(socketIOmessageType_t type, const uint8_t * payload, size_t length = 0);
bool send(socketIOmessageType_t type, char * payload, size_t length = 0, bool headerToPayload = false);
bool send(socketIOmessageType_t type, const char * payload, size_t length = 0);
bool send(socketIOmessageType_t type, String & payload);
void loop(void); void loop(void);
void configureEIOping(bool disableHeartbeat = false);
protected: protected:
bool _disableHeartbeat = false;
uint64_t _lastHeartbeat = 0; uint64_t _lastHeartbeat = 0;
SocketIOclientEvent _cbEvent; SocketIOclientEvent _cbEvent;
virtual void runIOCbEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) { virtual void runIOCbEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) {
@ -89,8 +70,6 @@ class SocketIOclient : protected WebSocketsClient {
} }
} }
void initClient(void);
// Handeling events from websocket layer // Handeling events from websocket layer
virtual void runCbEvent(WStype_t type, uint8_t * payload, size_t length) { virtual void runCbEvent(WStype_t type, uint8_t * payload, size_t length) {
handleCbEvent(type, payload, length); handleCbEvent(type, payload, length);

View File

@ -39,14 +39,7 @@ extern "C" {
#ifdef ESP8266 #ifdef ESP8266
#include <Hash.h> #include <Hash.h>
#elif defined(ESP32) #elif defined(ESP32)
#include <esp_system.h>
#if ESP_IDF_VERSION_MAJOR >= 4
#include <esp32/sha.h>
#else
#include <hwcrypto/sha.h> #include <hwcrypto/sha.h>
#endif
#else #else
extern "C" { extern "C" {
@ -501,7 +494,7 @@ void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t
reasonCode = payload[0] << 8 | payload[1]; reasonCode = payload[0] << 8 | payload[1];
} }
#endif #endif
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] get ask for close. Code: %d\n", client->num, reasonCode); DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] get ask for close. Code: %d", client->num, reasonCode);
if(header->payloadLen > 2) { if(header->payloadLen > 2) {
DEBUG_WEBSOCKETS(" (%s)\n", (payload + 2)); DEBUG_WEBSOCKETS(" (%s)\n", (payload + 2));
} else { } else {
@ -510,7 +503,6 @@ void WebSockets::handleWebsocketPayloadCb(WSclient_t * client, bool ok, uint8_t
clientDisconnect(client, 1000); clientDisconnect(client, 1000);
} break; } break;
default: default:
DEBUG_WEBSOCKETS("[WS][%d][handleWebsocket] got unknown opcode: %d\n", client->num, header->opCode);
clientDisconnect(client, 1002); clientDisconnect(client, 1002);
break; break;
} }
@ -603,7 +595,7 @@ bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWait
#else #else
unsigned long t = millis(); unsigned long t = millis();
ssize_t len; size_t len;
DEBUG_WEBSOCKETS("[readCb] n: %zu t: %lu\n", n, t); DEBUG_WEBSOCKETS("[readCb] n: %zu t: %lu\n", n, t);
while(n > 0) { while(n > 0) {
if(client->tcp == NULL) { if(client->tcp == NULL) {
@ -631,12 +623,14 @@ bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWait
} }
if(!client->tcp->available()) { if(!client->tcp->available()) {
WEBSOCKETS_YIELD_MORE(); #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
delay(0);
#endif
continue; continue;
} }
len = client->tcp->read((uint8_t *)out, n); len = client->tcp->read((uint8_t *)out, n);
if(len > 0) { if(len) {
t = millis(); t = millis();
out += len; out += len;
n -= len; n -= len;
@ -644,14 +638,13 @@ bool WebSockets::readCb(WSclient_t * client, uint8_t * out, size_t n, WSreadWait
} else { } else {
//DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n); //DEBUG_WEBSOCKETS("Receive %d left %d!\n", len, n);
} }
if(n > 0) { #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
WEBSOCKETS_YIELD(); delay(0);
} #endif
} }
if(cb) { if(cb) {
cb(client, true); cb(client, true);
} }
WEBSOCKETS_YIELD();
#endif #endif
return true; return true;
} }
@ -696,13 +689,12 @@ size_t WebSockets::write(WSclient_t * client, uint8_t * out, size_t n) {
total += len; total += len;
//DEBUG_WEBSOCKETS("write %d left %d!\n", len, n); //DEBUG_WEBSOCKETS("write %d left %d!\n", len, n);
} else { } else {
DEBUG_WEBSOCKETS("WS write %d failed left %d!\n", len, n); //DEBUG_WEBSOCKETS("write %d failed left %d!\n", len, n);
}
if(n > 0) {
WEBSOCKETS_YIELD();
} }
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
delay(0);
#endif
} }
WEBSOCKETS_YIELD();
return total; return total;
} }

View File

@ -40,15 +40,9 @@
#include <functional> #include <functional>
#endif #endif
#include "WebSocketsVersion.h"
#ifndef NODEBUG_WEBSOCKETS #ifndef NODEBUG_WEBSOCKETS
#ifdef DEBUG_ESP_PORT #ifdef DEBUG_ESP_PORT
#define DEBUG_WEBSOCKETS(...) \ #define DEBUG_WEBSOCKETS(...) DEBUG_ESP_PORT.printf(__VA_ARGS__)
{ \
DEBUG_ESP_PORT.printf(__VA_ARGS__); \
DEBUG_ESP_PORT.flush(); \
}
#else #else
//#define DEBUG_WEBSOCKETS(...) os_printf( __VA_ARGS__ ) //#define DEBUG_WEBSOCKETS(...) os_printf( __VA_ARGS__ )
#endif #endif
@ -56,10 +50,8 @@
#ifndef DEBUG_WEBSOCKETS #ifndef DEBUG_WEBSOCKETS
#define DEBUG_WEBSOCKETS(...) #define DEBUG_WEBSOCKETS(...)
#ifndef NODEBUG_WEBSOCKETS
#define NODEBUG_WEBSOCKETS #define NODEBUG_WEBSOCKETS
#endif #endif
#endif
#if defined(ESP8266) || defined(ESP32) #if defined(ESP8266) || defined(ESP32)
@ -69,32 +61,22 @@
// moves all Header strings to Flash (~300 Byte) // moves all Header strings to Flash (~300 Byte)
//#define WEBSOCKETS_SAVE_RAM //#define WEBSOCKETS_SAVE_RAM
#if defined(ESP8266)
#define WEBSOCKETS_YIELD() delay(0)
#define WEBSOCKETS_YIELD_MORE() delay(1)
#elif defined(ESP32)
#define WEBSOCKETS_YIELD() yield()
#define WEBSOCKETS_YIELD_MORE() delay(1)
#endif
#elif defined(STM32_DEVICE) #elif defined(STM32_DEVICE)
#define WEBSOCKETS_MAX_DATA_SIZE (15 * 1024) #define WEBSOCKETS_MAX_DATA_SIZE (15 * 1024)
#define WEBSOCKETS_USE_BIG_MEM #define WEBSOCKETS_USE_BIG_MEM
#define GET_FREE_HEAP System.freeMemory() #define GET_FREE_HEAP System.freeMemory()
#define WEBSOCKETS_YIELD()
#define WEBSOCKETS_YIELD_MORE()
#else #else
//atmega328p has only 2KB ram! //atmega328p has only 2KB ram!
#define WEBSOCKETS_MAX_DATA_SIZE (1024) #define WEBSOCKETS_MAX_DATA_SIZE (1024)
// moves all Header strings to Flash // moves all Header strings to Flash
#define WEBSOCKETS_SAVE_RAM #define WEBSOCKETS_SAVE_RAM
#define WEBSOCKETS_YIELD()
#define WEBSOCKETS_YIELD_MORE()
#endif #endif
#define WEBSOCKETS_TCP_TIMEOUT (5000) #define WEBSOCKETS_TCP_TIMEOUT (2000)
#define NETWORK_ESP8266_ASYNC (0) #define NETWORK_ESP8266_ASYNC (0)
#define NETWORK_ESP8266 (1) #define NETWORK_ESP8266 (1)
@ -134,7 +116,6 @@
#elif defined(ESP32) #elif defined(ESP32)
#include <WiFi.h> #include <WiFi.h>
#include <WiFiClientSecure.h> #include <WiFiClientSecure.h>
#define SSL_AXTLS
#elif defined(ESP31B) #elif defined(ESP31B)
#include <ESP31BWiFi.h> #include <ESP31BWiFi.h>
#else #else
@ -154,11 +135,6 @@
#ifdef ESP8266 #ifdef ESP8266
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#if defined(wificlientbearssl_h) && !defined(USING_AXTLS) && !defined(wificlientsecure_h)
#define SSL_BARESSL
#else
#define SSL_AXTLS
#endif
#else #else
#include <ESP31BWiFi.h> #include <ESP31BWiFi.h>
#endif #endif
@ -188,7 +164,6 @@
#include <WiFi.h> #include <WiFi.h>
#include <WiFiClientSecure.h> #include <WiFiClientSecure.h>
#define SSL_AXTLS
#define WEBSOCKETS_NETWORK_CLASS WiFiClient #define WEBSOCKETS_NETWORK_CLASS WiFiClient
#define WEBSOCKETS_NETWORK_SSL_CLASS WiFiClientSecure #define WEBSOCKETS_NETWORK_SSL_CLASS WiFiClientSecure
#define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer #define WEBSOCKETS_NETWORK_SERVER_CLASS WiFiServer
@ -217,7 +192,6 @@
typedef enum { typedef enum {
WSC_NOT_CONNECTED, WSC_NOT_CONNECTED,
WSC_HEADER, WSC_HEADER,
WSC_BODY,
WSC_CONNECTED WSC_CONNECTED
} WSclientsStatus_t; } WSclientsStatus_t;
@ -261,44 +235,34 @@ typedef struct {
} WSMessageHeader_t; } WSMessageHeader_t;
typedef struct { typedef struct {
void init(uint8_t num, uint8_t num; ///< connection number
uint32_t pingInterval,
uint32_t pongTimeout,
uint8_t disconnectTimeoutCount) {
this->num = num;
this->pingInterval = pingInterval;
this->pongTimeout = pongTimeout;
this->disconnectTimeoutCount = disconnectTimeoutCount;
}
uint8_t num = 0; ///< connection number WSclientsStatus_t status;
WSclientsStatus_t status = WSC_NOT_CONNECTED; WEBSOCKETS_NETWORK_CLASS * tcp;
WEBSOCKETS_NETWORK_CLASS * tcp = nullptr; bool isSocketIO; ///< client for socket.io server
bool isSocketIO = false; ///< client for socket.io server
#if defined(HAS_SSL) #if defined(HAS_SSL)
bool isSSL = false; ///< run in ssl mode bool isSSL; ///< run in ssl mode
WEBSOCKETS_NETWORK_SSL_CLASS * ssl; WEBSOCKETS_NETWORK_SSL_CLASS * ssl;
#endif #endif
String cUrl; ///< http url String cUrl; ///< http url
uint16_t cCode = 0; ///< http code uint16_t cCode; ///< http code
bool cIsClient = false; ///< will be used for masking bool cIsClient = false; ///< will be used for masking
bool cIsUpgrade = false; ///< Connection == Upgrade bool cIsUpgrade; ///< Connection == Upgrade
bool cIsWebsocket = false; ///< Upgrade == websocket bool cIsWebsocket; ///< Upgrade == websocket
String cSessionId; ///< client Set-Cookie (session id) String cSessionId; ///< client Set-Cookie (session id)
String cKey; ///< client Sec-WebSocket-Key String cKey; ///< client Sec-WebSocket-Key
String cAccept; ///< client Sec-WebSocket-Accept String cAccept; ///< client Sec-WebSocket-Accept
String cProtocol; ///< client Sec-WebSocket-Protocol String cProtocol; ///< client Sec-WebSocket-Protocol
String cExtensions; ///< client Sec-WebSocket-Extensions String cExtensions; ///< client Sec-WebSocket-Extensions
uint16_t cVersion = 0; ///< client Sec-WebSocket-Version uint16_t cVersion; ///< client Sec-WebSocket-Version
uint8_t cWsRXsize = 0; ///< State of the RX uint8_t cWsRXsize; ///< State of the RX
uint8_t cWsHeader[WEBSOCKETS_MAX_HEADER_SIZE]; ///< RX WS Message buffer uint8_t cWsHeader[WEBSOCKETS_MAX_HEADER_SIZE]; ///< RX WS Message buffer
WSMessageHeader_t cWsHeaderDecode; WSMessageHeader_t cWsHeaderDecode;
@ -307,15 +271,15 @@ typedef struct {
String extraHeaders; String extraHeaders;
bool cHttpHeadersValid = false; ///< non-websocket http header validity indicator bool cHttpHeadersValid; ///< non-websocket http header validity indicator
size_t cMandatoryHeadersCount; ///< non-websocket mandatory http headers present count size_t cMandatoryHeadersCount; ///< non-websocket mandatory http headers present count
bool pongReceived = false; bool pongReceived;
uint32_t pingInterval = 0; // how often ping will be sent, 0 means "heartbeat is not active" uint32_t pingInterval; // how often ping will be sent, 0 means "heartbeat is not active"
uint32_t lastPing = 0; // millis when last pong has been received uint32_t lastPing; // millis when last pong has been received
uint32_t pongTimeout = 0; // interval in millis after which pong is considered to timeout uint32_t pongTimeout; // interval in millis after which pong is considered to timeout
uint8_t disconnectTimeoutCount = 0; // after how many subsequent pong timeouts discconnect will happen, 0 means "do not disconnect" uint8_t disconnectTimeoutCount; // after how many subsequent pong timeouts discconnect will happen, 0 means "do not disconnect"
uint8_t pongTimeoutCount = 0; // current pong timeout count uint8_t pongTimeoutCount; // current pong timeout count
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
String cHttpLine; ///< HTTP header lines String cHttpLine; ///< HTTP header lines

View File

@ -1,80 +0,0 @@
/**
* @file WebSocketsServer.cpp
* @date 28.10.2020
* @author Markus Sattler & esp8266/arduino community
*
* Copyright (c) 2020 Markus Sattler. All rights reserved.
* This file is part of the WebSockets for Arduino.
*
* 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 __WEBSOCKETS4WEBSERVER_H
#define __WEBSOCKETS4WEBSERVER_H
#include <WebSocketsServer.h>
#include <ESP8266WebServer.h>
#if WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK
class WebSockets4WebServer : public WebSocketsServerCore {
public:
WebSockets4WebServer(const String & origin = "", const String & protocol = "arduino")
: WebSocketsServerCore(origin, protocol) {
begin();
}
ESP8266WebServer::HookFunction hookForWebserver(const String & wsRootDir, WebSocketServerEvent event) {
onEvent(event);
return [&, wsRootDir](const String & method, const String & url, WiFiClient * tcpClient, ESP8266WebServer::ContentTypeFunction contentType) {
(void)contentType;
if(!(method == "GET" && url.indexOf(wsRootDir) == 0)) {
return ESP8266WebServer::CLIENT_REQUEST_CAN_CONTINUE;
}
// allocate a WiFiClient copy (like in WebSocketsServer::handleNewClients())
WEBSOCKETS_NETWORK_CLASS * newTcpClient = new WEBSOCKETS_NETWORK_CLASS(*tcpClient);
// Then initialize a new WSclient_t (like in WebSocketsServer::handleNewClient())
WSclient_t * client = handleNewClient(newTcpClient);
if(client) {
// give "GET <url>"
String headerLine;
headerLine.reserve(url.length() + 5);
headerLine = "GET ";
headerLine += url;
handleHeader(client, &headerLine);
}
// tell webserver to not close but forget about this client
return ESP8266WebServer::CLIENT_IS_GIVEN;
};
}
};
#else // WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK
#ifndef WEBSERVER_HAS_HOOK
#error Your current Framework / Arduino core version does not support Webserver Hook Functions
#else
#error Your Hardware Platform does not support Webserver Hook Functions
#endif
#endif // WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266 && WEBSERVER_HAS_HOOK
#endif // __WEBSOCKETS4WEBSERVER_H

View File

@ -30,9 +30,6 @@ WebSocketsClient::WebSocketsClient() {
_client.num = 0; _client.num = 0;
_client.cIsClient = true; _client.cIsClient = true;
_client.extraHeaders = WEBSOCKETS_STRING("Origin: file://"); _client.extraHeaders = WEBSOCKETS_STRING("Origin: file://");
_reconnectInterval = 500;
_port = 0;
_host = "";
} }
WebSocketsClient::~WebSocketsClient() { WebSocketsClient::~WebSocketsClient() {
@ -46,7 +43,7 @@ void WebSocketsClient::begin(const char * host, uint16_t port, const char * url,
_host = host; _host = host;
_port = port; _port = port;
#if defined(HAS_SSL) #if defined(HAS_SSL)
_fingerprint = SSL_FINGERPRINT_NULL; _fingerprint = "";
_CA_cert = NULL; _CA_cert = NULL;
#endif #endif
@ -85,9 +82,7 @@ void WebSocketsClient::begin(const char * host, uint16_t port, const char * url,
#endif #endif
_lastConnectionFail = 0; _lastConnectionFail = 0;
_lastHeaderSent = 0; _reconnectInterval = 500;
DEBUG_WEBSOCKETS("[WS-Client] Websocket Version: " WEBSOCKETS_VERSION "\n");
} }
void WebSocketsClient::begin(String host, uint16_t port, String url, String protocol) { void WebSocketsClient::begin(String host, uint16_t port, String url, String protocol) {
@ -99,7 +94,6 @@ void WebSocketsClient::begin(IPAddress host, uint16_t port, const char * url, co
} }
#if defined(HAS_SSL) #if defined(HAS_SSL)
#if defined(SSL_AXTLS)
void WebSocketsClient::beginSSL(const char * host, uint16_t port, const char * url, const char * fingerprint, const char * protocol) { void WebSocketsClient::beginSSL(const char * host, uint16_t port, const char * url, const char * fingerprint, const char * protocol) {
begin(host, port, url, protocol); begin(host, port, url, protocol);
_client.isSSL = true; _client.isSSL = true;
@ -114,39 +108,10 @@ void WebSocketsClient::beginSSL(String host, uint16_t port, String url, String f
void WebSocketsClient::beginSslWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) { void WebSocketsClient::beginSslWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) {
begin(host, port, url, protocol); begin(host, port, url, protocol);
_client.isSSL = true; _client.isSSL = true;
_fingerprint = SSL_FINGERPRINT_NULL; _fingerprint = "";
_CA_cert = CA_cert; _CA_cert = CA_cert;
} }
#else #endif
void WebSocketsClient::beginSSL(const char * host, uint16_t port, const char * url, const uint8_t * fingerprint, const char * protocol) {
begin(host, port, url, protocol);
_client.isSSL = true;
_fingerprint = fingerprint;
_CA_cert = NULL;
}
void WebSocketsClient::beginSslWithCA(const char * host, uint16_t port, const char * url, BearSSL::X509List * CA_cert, const char * protocol) {
begin(host, port, url, protocol);
_client.isSSL = true;
_fingerprint = SSL_FINGERPRINT_NULL;
_CA_cert = CA_cert;
}
void WebSocketsClient::beginSslWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) {
beginSslWithCA(host, port, url, new BearSSL::X509List(CA_cert), protocol);
}
void WebSocketsClient::setSSLClientCertKey(BearSSL::X509List * clientCert, BearSSL::PrivateKey * clientPrivateKey) {
_client_cert = clientCert;
_client_key = clientPrivateKey;
}
void WebSocketsClient::setSSLClientCertKey(const char * clientCert, const char * clientPrivateKey) {
setSSLClientCertKey(new BearSSL::X509List(clientCert), new BearSSL::PrivateKey(clientPrivateKey));
}
#endif // SSL_AXTLS
#endif // HAS_SSL
void WebSocketsClient::beginSocketIO(const char * host, uint16_t port, const char * url, const char * protocol) { void WebSocketsClient::beginSocketIO(const char * host, uint16_t port, const char * url, const char * protocol) {
begin(host, port, url, protocol); begin(host, port, url, protocol);
@ -162,35 +127,20 @@ void WebSocketsClient::beginSocketIOSSL(const char * host, uint16_t port, const
begin(host, port, url, protocol); begin(host, port, url, protocol);
_client.isSocketIO = true; _client.isSocketIO = true;
_client.isSSL = true; _client.isSSL = true;
_fingerprint = SSL_FINGERPRINT_NULL; _fingerprint = "";
} }
void WebSocketsClient::beginSocketIOSSL(String host, uint16_t port, String url, String protocol) { void WebSocketsClient::beginSocketIOSSL(String host, uint16_t port, String url, String protocol) {
beginSocketIOSSL(host.c_str(), port, url.c_str(), protocol.c_str()); beginSocketIOSSL(host.c_str(), port, url.c_str(), protocol.c_str());
} }
#if defined(SSL_BARESSL)
void WebSocketsClient::beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url, BearSSL::X509List * CA_cert, const char * protocol) {
begin(host, port, url, protocol);
_client.isSocketIO = true;
_client.isSSL = true;
_fingerprint = SSL_FINGERPRINT_NULL;
_CA_cert = CA_cert;
}
#endif
void WebSocketsClient::beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) { void WebSocketsClient::beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url, const char * CA_cert, const char * protocol) {
begin(host, port, url, protocol); begin(host, port, url, protocol);
_client.isSocketIO = true; _client.isSocketIO = true;
_client.isSSL = true; _client.isSSL = true;
_fingerprint = SSL_FINGERPRINT_NULL; _fingerprint = "";
#if defined(SSL_BARESSL) _CA_cert = CA_cert;
_CA_cert = new BearSSL::X509List(CA_cert);
#else
_CA_cert = CA_cert;
#endif
} }
#endif #endif
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
@ -198,10 +148,6 @@ void WebSocketsClient::beginSocketIOSSLWithCA(const char * host, uint16_t port,
* called in arduino loop * called in arduino loop
*/ */
void WebSocketsClient::loop(void) { void WebSocketsClient::loop(void) {
if(_port == 0) {
return;
}
WEBSOCKETS_YIELD();
if(!clientIsConnected(&_client)) { if(!clientIsConnected(&_client)) {
// do not flood the server // do not flood the server
if((millis() - _lastConnectionFail) < _reconnectInterval) { if((millis() - _lastConnectionFail) < _reconnectInterval) {
@ -222,25 +168,10 @@ void WebSocketsClient::loop(void) {
DEBUG_WEBSOCKETS("[WS-Client] setting CA certificate"); DEBUG_WEBSOCKETS("[WS-Client] setting CA certificate");
#if defined(ESP32) #if defined(ESP32)
_client.ssl->setCACert(_CA_cert); _client.ssl->setCACert(_CA_cert);
#elif defined(ESP8266) && defined(SSL_AXTLS) #elif defined(ESP8266)
_client.ssl->setCACert((const uint8_t *)_CA_cert, strlen(_CA_cert) + 1); _client.ssl->setCACert((const uint8_t *)_CA_cert, strlen(_CA_cert) + 1);
#elif defined(ESP8266) && defined(SSL_BARESSL)
_client.ssl->setTrustAnchors(_CA_cert);
#else #else
#error setCACert not implemented #error setCACert not implemented
#endif
#if defined(ESP32)
} else if(!SSL_FINGERPRINT_IS_SET) {
_client.ssl->setInsecure();
#elif defined(SSL_BARESSL)
} else if(SSL_FINGERPRINT_IS_SET) {
_client.ssl->setFingerprint(_fingerprint);
} else {
_client.ssl->setInsecure();
}
if(_client_cert && _client_key) {
_client.ssl->setClientRSACert(_client_cert, _client_key);
DEBUG_WEBSOCKETS("[WS-Client] setting client certificate and key");
#endif #endif
} }
} else { } else {
@ -259,7 +190,6 @@ void WebSocketsClient::loop(void) {
DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!"); DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!");
return; return;
} }
WEBSOCKETS_YIELD();
#if defined(ESP32) #if defined(ESP32)
if(_client.tcp->connect(_host.c_str(), _port, WEBSOCKETS_TCP_TIMEOUT)) { if(_client.tcp->connect(_host.c_str(), _port, WEBSOCKETS_TCP_TIMEOUT)) {
#else #else
@ -273,7 +203,7 @@ void WebSocketsClient::loop(void) {
} }
} else { } else {
handleClientData(); handleClientData();
WEBSOCKETS_YIELD();
if(_client.status == WSC_CONNECTED) { if(_client.status == WSC_CONNECTED) {
handleHBPing(); handleHBPing();
handleHBTimeout(&_client); handleHBTimeout(&_client);
@ -510,8 +440,7 @@ void WebSocketsClient::clientDisconnect(WSclient_t * client) {
client->cIsWebsocket = false; client->cIsWebsocket = false;
client->cSessionId = ""; client->cSessionId = "";
client->status = WSC_NOT_CONNECTED; client->status = WSC_NOT_CONNECTED;
_lastConnectionFail = millis();
DEBUG_WEBSOCKETS("[WS-Client] client disconnected.\n"); DEBUG_WEBSOCKETS("[WS-Client] client disconnected.\n");
if(event) { if(event) {
@ -554,13 +483,6 @@ bool WebSocketsClient::clientIsConnected(WSclient_t * client) {
* Handel incomming data from Client * Handel incomming data from Client
*/ */
void WebSocketsClient::handleClientData(void) { void WebSocketsClient::handleClientData(void) {
if((_client.status == WSC_HEADER || _client.status == WSC_BODY) && _lastHeaderSent + WEBSOCKETS_TCP_TIMEOUT < millis()) {
DEBUG_WEBSOCKETS("[WS-Client][handleClientData] header response timeout.. disconnecting!\n");
clientDisconnect(&_client);
WEBSOCKETS_YIELD();
return;
}
int len = _client.tcp->available(); int len = _client.tcp->available();
if(len > 0) { if(len > 0) {
switch(_client.status) { switch(_client.status) {
@ -568,12 +490,6 @@ void WebSocketsClient::handleClientData(void) {
String headerLine = _client.tcp->readStringUntil('\n'); String headerLine = _client.tcp->readStringUntil('\n');
handleHeader(&_client, &headerLine); handleHeader(&_client, &headerLine);
} break; } break;
case WSC_BODY: {
char buf[256] = { 0 };
_client.tcp->readBytes(&buf[0], std::min((size_t)len, sizeof(buf)));
String bodyLine = buf;
handleHeader(&_client, &bodyLine);
} break;
case WSC_CONNECTED: case WSC_CONNECTED:
WebSockets::handleWebsocket(&_client); WebSockets::handleWebsocket(&_client);
break; break;
@ -582,7 +498,9 @@ void WebSocketsClient::handleClientData(void) {
break; break;
} }
} }
WEBSOCKETS_YIELD(); #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
delay(0);
#endif
} }
#endif #endif
@ -649,7 +567,7 @@ void WebSocketsClient::sendHeader(WSclient_t * client) {
} }
// add extra headers; by default this includes "Origin: file://" // add extra headers; by default this includes "Origin: file://"
if(client->extraHeaders.length() > 0) { if(client->extraHeaders) {
handshake += client->extraHeaders + NEW_LINE; handshake += client->extraHeaders + NEW_LINE;
} }
@ -675,7 +593,6 @@ void WebSocketsClient::sendHeader(WSclient_t * client) {
#endif #endif
DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header... Done (%luus).\n", (micros() - start)); DEBUG_WEBSOCKETS("[WS-Client][sendHeader] sending header... Done (%luus).\n", (micros() - start));
_lastHeaderSent = millis();
} }
/** /**
@ -685,22 +602,6 @@ void WebSocketsClient::sendHeader(WSclient_t * client) {
void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) { void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
headerLine->trim(); // remove \r headerLine->trim(); // remove \r
// this code handels the http body for Socket.IO V3 requests
if(headerLine->length() > 0 && client->isSocketIO && client->status == WSC_BODY && client->cSessionId.length() == 0) {
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] socket.io json: %s\n", headerLine->c_str());
String sid_begin = WEBSOCKETS_STRING("\"sid\":\"");
if(headerLine->indexOf(sid_begin) > -1) {
int start = headerLine->indexOf(sid_begin) + sid_begin.length();
int end = headerLine->indexOf('"', start);
client->cSessionId = headerLine->substring(start, end);
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cSessionId: %s\n", client->cSessionId.c_str());
// Trigger websocket connection code path
*headerLine = "";
}
}
// headle HTTP header
if(headerLine->length() > 0) { if(headerLine->length() > 0) {
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] RX: %s\n", headerLine->c_str()); DEBUG_WEBSOCKETS("[WS-Client][handleHeader] RX: %s\n", headerLine->c_str());
@ -734,7 +635,7 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Version"))) { } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Sec-WebSocket-Version"))) {
client->cVersion = headerValue.toInt(); client->cVersion = headerValue.toInt();
} else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Set-Cookie"))) { } else if(headerName.equalsIgnoreCase(WEBSOCKETS_STRING("Set-Cookie"))) {
if(headerValue.indexOf(';') > -1) { if(headerValue.indexOf(WEBSOCKETS_STRING("HttpOnly")) > -1) {
client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1, headerValue.indexOf(";")); client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1, headerValue.indexOf(";"));
} else { } else {
client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1); client->cSessionId = headerValue.substring(headerValue.indexOf('=') + 1);
@ -765,14 +666,6 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cVersion: %d\n", client->cVersion); DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cVersion: %d\n", client->cVersion);
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cSessionId: %s\n", client->cSessionId.c_str()); DEBUG_WEBSOCKETS("[WS-Client][handleHeader] - cSessionId: %s\n", client->cSessionId.c_str());
if(client->isSocketIO && client->cSessionId.length() == 0 && clientIsConnected(client)) {
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] still missing cSessionId try socket.io V3\n");
client->status = WSC_BODY;
return;
} else {
client->status = WSC_HEADER;
}
bool ok = (client->cIsUpgrade && client->cIsWebsocket); bool ok = (client->cIsUpgrade && client->cIsWebsocket);
if(ok) { if(ok) {
@ -813,20 +706,15 @@ void WebSocketsClient::handleHeader(WSclient_t * client, String * headerLine) {
headerDone(client); headerDone(client);
runCbEvent(WStype_CONNECTED, (uint8_t *)client->cUrl.c_str(), client->cUrl.length()); runCbEvent(WStype_CONNECTED, (uint8_t *)client->cUrl.c_str(), client->cUrl.length());
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) } else if(clientIsConnected(client) && client->isSocketIO && client->cSessionId.length() > 0) {
} else if(client->isSocketIO) { if(_client.tcp->available()) {
if(client->cSessionId.length() > 0) { // read not needed data
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] found cSessionId\n"); DEBUG_WEBSOCKETS("[WS-Client][handleHeader] still data in buffer (%d), clean up.\n", _client.tcp->available());
if(clientIsConnected(client) && _client.tcp->available()) { while(_client.tcp->available() > 0) {
// read not needed data _client.tcp->read();
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] still data in buffer (%d), clean up.\n", _client.tcp->available());
while(_client.tcp->available() > 0) {
_client.tcp->read();
}
} }
sendHeader(client);
} }
#endif sendHeader(client);
} else { } else {
DEBUG_WEBSOCKETS("[WS-Client][handleHeader] no Websocket connection close.\n"); DEBUG_WEBSOCKETS("[WS-Client][handleHeader] no Websocket connection close.\n");
_lastConnectionFail = millis(); _lastConnectionFail = millis();
@ -867,18 +755,14 @@ void WebSocketsClient::connectedCb() {
#endif #endif
#if defined(HAS_SSL) #if defined(HAS_SSL)
#if defined(SSL_AXTLS) || defined(ESP32) if(_client.isSSL && _fingerprint.length()) {
if(_client.isSSL && SSL_FINGERPRINT_IS_SET) {
if(!_client.ssl->verify(_fingerprint.c_str(), _host.c_str())) { if(!_client.ssl->verify(_fingerprint.c_str(), _host.c_str())) {
DEBUG_WEBSOCKETS("[WS-Client] certificate mismatch\n"); DEBUG_WEBSOCKETS("[WS-Client] certificate mismatch\n");
WebSockets::clientDisconnect(&_client, 1000); WebSockets::clientDisconnect(&_client, 1000);
return; return;
} }
#else
if(_client.isSSL && SSL_FINGERPRINT_IS_SET) {
#endif
} else if(_client.isSSL && !_CA_cert) { } else if(_client.isSSL && !_CA_cert) {
#if defined(SSL_BARESSL) #if defined(wificlientbearssl_h) && !defined(USING_AXTLS) && !defined(wificlientsecure_h)
_client.ssl->setInsecure(); _client.ssl->setInsecure();
#endif #endif
} }
@ -948,9 +832,6 @@ void WebSocketsClient::handleHBPing() {
if(sendPing()) { if(sendPing()) {
_client.lastPing = millis(); _client.lastPing = millis();
_client.pongReceived = false; _client.pongReceived = false;
} else {
DEBUG_WEBSOCKETS("[WS-Client] sending HB ping failed\n");
WebSockets::clientDisconnect(&_client, 1000);
} }
} }
} }

View File

@ -43,15 +43,8 @@ class WebSocketsClient : protected WebSockets {
void begin(IPAddress host, uint16_t port, const char * url = "/", const char * protocol = "arduino"); void begin(IPAddress host, uint16_t port, const char * url = "/", const char * protocol = "arduino");
#if defined(HAS_SSL) #if defined(HAS_SSL)
#ifdef SSL_AXTLS void beginSSL(const char * host, uint16_t port, const char * url = "/", const char * = "", const char * protocol = "arduino");
void beginSSL(const char * host, uint16_t port, const char * url = "/", const char * fingerprint = "", const char * protocol = "arduino");
void beginSSL(String host, uint16_t port, String url = "/", String fingerprint = "", String protocol = "arduino"); void beginSSL(String host, uint16_t port, String url = "/", String fingerprint = "", String protocol = "arduino");
#else
void beginSSL(const char * host, uint16_t port, const char * url = "/", const uint8_t * fingerprint = NULL, const char * protocol = "arduino");
void beginSslWithCA(const char * host, uint16_t port, const char * url = "/", BearSSL::X509List * CA_cert = NULL, const char * protocol = "arduino");
void setSSLClientCertKey(BearSSL::X509List * clientCert = NULL, BearSSL::PrivateKey * clientPrivateKey = NULL);
void setSSLClientCertKey(const char * clientCert = NULL, const char * clientPrivateKey = NULL);
#endif
void beginSslWithCA(const char * host, uint16_t port, const char * url = "/", const char * CA_cert = NULL, const char * protocol = "arduino"); void beginSslWithCA(const char * host, uint16_t port, const char * url = "/", const char * CA_cert = NULL, const char * protocol = "arduino");
#endif #endif
@ -61,11 +54,7 @@ class WebSocketsClient : protected WebSockets {
#if defined(HAS_SSL) #if defined(HAS_SSL)
void beginSocketIOSSL(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino"); void beginSocketIOSSL(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * protocol = "arduino");
void beginSocketIOSSL(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino"); void beginSocketIOSSL(String host, uint16_t port, String url = "/socket.io/?EIO=3", String protocol = "arduino");
void beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * CA_cert = NULL, const char * protocol = "arduino"); void beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", const char * CA_cert = NULL, const char * protocol = "arduino");
#if defined(SSL_BARESSL)
void beginSocketIOSSLWithCA(const char * host, uint16_t port, const char * url = "/socket.io/?EIO=3", BearSSL::X509List * CA_cert = NULL, const char * protocol = "arduino");
#endif
#endif #endif
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
@ -102,27 +91,15 @@ class WebSocketsClient : protected WebSockets {
void enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount); void enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount);
void disableHeartbeat(); void disableHeartbeat();
bool isConnected(void);
protected: protected:
String _host; String _host;
uint16_t _port; uint16_t _port;
bool isConnected(void);
#if defined(HAS_SSL) #if defined(HAS_SSL)
#ifdef SSL_AXTLS
String _fingerprint; String _fingerprint;
const char * _CA_cert; const char * _CA_cert;
#define SSL_FINGERPRINT_IS_SET (_fingerprint.length())
#define SSL_FINGERPRINT_NULL ""
#else
const uint8_t * _fingerprint;
BearSSL::X509List * _CA_cert;
BearSSL::X509List * _client_cert;
BearSSL::PrivateKey * _client_key;
#define SSL_FINGERPRINT_IS_SET (_fingerprint != NULL)
#define SSL_FINGERPRINT_NULL NULL
#endif
#endif #endif
WSclient_t _client; WSclient_t _client;
@ -130,7 +107,6 @@ class WebSocketsClient : protected WebSockets {
unsigned long _lastConnectionFail; unsigned long _lastConnectionFail;
unsigned long _reconnectInterval; unsigned long _reconnectInterval;
unsigned long _lastHeaderSent;
void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin); void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin);

View File

@ -25,36 +25,31 @@
#include "WebSockets.h" #include "WebSockets.h"
#include "WebSocketsServer.h" #include "WebSocketsServer.h"
WebSocketsServerCore::WebSocketsServerCore(const String & origin, const String & protocol) { WebSocketsServer::WebSocketsServer(uint16_t port, String origin, String protocol) {
_origin = origin; _port = port;
_protocol = protocol; _origin = origin;
_runnning = false; _protocol = protocol;
_pingInterval = 0; _runnning = false;
_pongTimeout = 0;
_disconnectTimeoutCount = 0; _server = new WEBSOCKETS_NETWORK_SERVER_CLASS(port);
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
_server->onClient([](void * s, AsyncClient * c) {
((WebSocketsServer *)s)->newClient(new AsyncTCPbuffer(c));
},
this);
#endif
_cbEvent = NULL; _cbEvent = NULL;
_httpHeaderValidationFunc = NULL; _httpHeaderValidationFunc = NULL;
_mandatoryHttpHeaders = NULL; _mandatoryHttpHeaders = NULL;
_mandatoryHttpHeaderCount = 0; _mandatoryHttpHeaderCount = 0;
memset(&_clients[0], 0x00, (sizeof(WSclient_t) * WEBSOCKETS_SERVER_CLIENT_MAX));
} }
WebSocketsServer::WebSocketsServer(uint16_t port, const String & origin, const String & protocol) WebSocketsServer::~WebSocketsServer() {
: WebSocketsServerCore(origin, protocol) {
_port = port;
_server = new WEBSOCKETS_NETWORK_SERVER_CLASS(port);
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
_server->onClient([](void * s, AsyncClient * c) {
((WebSocketsServerCore *)s)->newClient(new AsyncTCPbuffer(c));
},
this);
#endif
}
WebSocketsServerCore::~WebSocketsServerCore() {
// disconnect all clients // disconnect all clients
close(); close();
@ -64,20 +59,38 @@ WebSocketsServerCore::~WebSocketsServerCore() {
_mandatoryHttpHeaderCount = 0; _mandatoryHttpHeaderCount = 0;
} }
WebSocketsServer::~WebSocketsServer() {
}
/** /**
* called to initialize the Websocket server * called to initialize the Websocket server
*/ */
void WebSocketsServerCore::begin(void) { void WebSocketsServer::begin(void) {
// adjust clients storage: WSclient_t * client;
// _clients[i]'s constructor are already called,
// all its members are initialized to their default value, // init client storage
// except the ones explicitly detailed in WSclient_t() constructor. for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
// Then we need to initialize some members to non-trivial values: client = &_clients[i];
for(int i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
_clients[i].init(i, _pingInterval, _pongTimeout, _disconnectTimeoutCount); client->num = i;
client->status = WSC_NOT_CONNECTED;
client->tcp = NULL;
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
client->isSSL = false;
client->ssl = NULL;
#endif
client->cUrl = "";
client->cCode = 0;
client->cKey = "";
client->cProtocol = "";
client->cVersion = 0;
client->cIsUpgrade = false;
client->cIsWebsocket = false;
client->base64Authorization = "";
client->cWsRXsize = 0;
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
client->cHttpLine = "";
#endif
} }
#ifdef ESP8266 #ifdef ESP8266
@ -91,26 +104,41 @@ void WebSocketsServerCore::begin(void) {
#endif #endif
_runnning = true; _runnning = true;
_server->begin();
DEBUG_WEBSOCKETS("[WS-Server] Websocket Version: " WEBSOCKETS_VERSION "\n"); DEBUG_WEBSOCKETS("[WS-Server] Server Started.\n");
} }
void WebSocketsServerCore::close(void) { void WebSocketsServer::close(void) {
_runnning = false; _runnning = false;
disconnect(); disconnect();
// restore _clients[] to their initial state #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
// before next call to ::begin() _server->close();
for(int i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { #elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
_clients[i] = WSclient_t(); _server->end();
#else
// TODO how to close server?
#endif
}
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
/**
* called in arduino loop
*/
void WebSocketsServer::loop(void) {
if(_runnning) {
handleNewClients();
handleClientData();
} }
} }
#endif
/** /**
* set callback function * set callback function
* @param cbEvent WebSocketServerEvent * @param cbEvent WebSocketServerEvent
*/ */
void WebSocketsServerCore::onEvent(WebSocketServerEvent cbEvent) { void WebSocketsServer::onEvent(WebSocketServerEvent cbEvent) {
_cbEvent = cbEvent; _cbEvent = cbEvent;
} }
@ -120,7 +148,7 @@ void WebSocketsServerCore::onEvent(WebSocketServerEvent cbEvent) {
* @param mandatoryHttpHeaders[] const char* ///< the array of named http headers considered to be mandatory / must be present in order for websocket upgrade to succeed * @param mandatoryHttpHeaders[] const char* ///< the array of named http headers considered to be mandatory / must be present in order for websocket upgrade to succeed
* @param mandatoryHttpHeaderCount size_t ///< the number of items in the mandatoryHttpHeaders array * @param mandatoryHttpHeaderCount size_t ///< the number of items in the mandatoryHttpHeaders array
*/ */
void WebSocketsServerCore::onValidateHttpHeader( void WebSocketsServer::onValidateHttpHeader(
WebSocketServerHttpHeaderValFunc validationFunc, WebSocketServerHttpHeaderValFunc validationFunc,
const char * mandatoryHttpHeaders[], const char * mandatoryHttpHeaders[],
size_t mandatoryHttpHeaderCount) { size_t mandatoryHttpHeaderCount) {
@ -145,7 +173,7 @@ void WebSocketsServerCore::onValidateHttpHeader(
* @param headerToPayload bool (see sendFrame for more details) * @param headerToPayload bool (see sendFrame for more details)
* @return true if ok * @return true if ok
*/ */
bool WebSocketsServerCore::sendTXT(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) { bool WebSocketsServer::sendTXT(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) {
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) { if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
return false; return false;
} }
@ -159,19 +187,19 @@ bool WebSocketsServerCore::sendTXT(uint8_t num, uint8_t * payload, size_t length
return false; return false;
} }
bool WebSocketsServerCore::sendTXT(uint8_t num, const uint8_t * payload, size_t length) { bool WebSocketsServer::sendTXT(uint8_t num, const uint8_t * payload, size_t length) {
return sendTXT(num, (uint8_t *)payload, length); return sendTXT(num, (uint8_t *)payload, length);
} }
bool WebSocketsServerCore::sendTXT(uint8_t num, char * payload, size_t length, bool headerToPayload) { bool WebSocketsServer::sendTXT(uint8_t num, char * payload, size_t length, bool headerToPayload) {
return sendTXT(num, (uint8_t *)payload, length, headerToPayload); return sendTXT(num, (uint8_t *)payload, length, headerToPayload);
} }
bool WebSocketsServerCore::sendTXT(uint8_t num, const char * payload, size_t length) { bool WebSocketsServer::sendTXT(uint8_t num, const char * payload, size_t length) {
return sendTXT(num, (uint8_t *)payload, length); return sendTXT(num, (uint8_t *)payload, length);
} }
bool WebSocketsServerCore::sendTXT(uint8_t num, String & payload) { bool WebSocketsServer::sendTXT(uint8_t num, String & payload) {
return sendTXT(num, (uint8_t *)payload.c_str(), payload.length()); return sendTXT(num, (uint8_t *)payload.c_str(), payload.length());
} }
@ -182,7 +210,7 @@ bool WebSocketsServerCore::sendTXT(uint8_t num, String & payload) {
* @param headerToPayload bool (see sendFrame for more details) * @param headerToPayload bool (see sendFrame for more details)
* @return true if ok * @return true if ok
*/ */
bool WebSocketsServerCore::broadcastTXT(uint8_t * payload, size_t length, bool headerToPayload) { bool WebSocketsServer::broadcastTXT(uint8_t * payload, size_t length, bool headerToPayload) {
WSclient_t * client; WSclient_t * client;
bool ret = true; bool ret = true;
if(length == 0) { if(length == 0) {
@ -196,24 +224,26 @@ bool WebSocketsServerCore::broadcastTXT(uint8_t * payload, size_t length, bool h
ret = false; ret = false;
} }
} }
WEBSOCKETS_YIELD(); #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
delay(0);
#endif
} }
return ret; return ret;
} }
bool WebSocketsServerCore::broadcastTXT(const uint8_t * payload, size_t length) { bool WebSocketsServer::broadcastTXT(const uint8_t * payload, size_t length) {
return broadcastTXT((uint8_t *)payload, length); return broadcastTXT((uint8_t *)payload, length);
} }
bool WebSocketsServerCore::broadcastTXT(char * payload, size_t length, bool headerToPayload) { bool WebSocketsServer::broadcastTXT(char * payload, size_t length, bool headerToPayload) {
return broadcastTXT((uint8_t *)payload, length, headerToPayload); return broadcastTXT((uint8_t *)payload, length, headerToPayload);
} }
bool WebSocketsServerCore::broadcastTXT(const char * payload, size_t length) { bool WebSocketsServer::broadcastTXT(const char * payload, size_t length) {
return broadcastTXT((uint8_t *)payload, length); return broadcastTXT((uint8_t *)payload, length);
} }
bool WebSocketsServerCore::broadcastTXT(String & payload) { bool WebSocketsServer::broadcastTXT(String & payload) {
return broadcastTXT((uint8_t *)payload.c_str(), payload.length()); return broadcastTXT((uint8_t *)payload.c_str(), payload.length());
} }
@ -225,7 +255,7 @@ bool WebSocketsServerCore::broadcastTXT(String & payload) {
* @param headerToPayload bool (see sendFrame for more details) * @param headerToPayload bool (see sendFrame for more details)
* @return true if ok * @return true if ok
*/ */
bool WebSocketsServerCore::sendBIN(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) { bool WebSocketsServer::sendBIN(uint8_t num, uint8_t * payload, size_t length, bool headerToPayload) {
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) { if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
return false; return false;
} }
@ -236,7 +266,7 @@ bool WebSocketsServerCore::sendBIN(uint8_t num, uint8_t * payload, size_t length
return false; return false;
} }
bool WebSocketsServerCore::sendBIN(uint8_t num, const uint8_t * payload, size_t length) { bool WebSocketsServer::sendBIN(uint8_t num, const uint8_t * payload, size_t length) {
return sendBIN(num, (uint8_t *)payload, length); return sendBIN(num, (uint8_t *)payload, length);
} }
@ -247,7 +277,7 @@ bool WebSocketsServerCore::sendBIN(uint8_t num, const uint8_t * payload, size_t
* @param headerToPayload bool (see sendFrame for more details) * @param headerToPayload bool (see sendFrame for more details)
* @return true if ok * @return true if ok
*/ */
bool WebSocketsServerCore::broadcastBIN(uint8_t * payload, size_t length, bool headerToPayload) { bool WebSocketsServer::broadcastBIN(uint8_t * payload, size_t length, bool headerToPayload) {
WSclient_t * client; WSclient_t * client;
bool ret = true; bool ret = true;
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
@ -257,12 +287,14 @@ bool WebSocketsServerCore::broadcastBIN(uint8_t * payload, size_t length, bool h
ret = false; ret = false;
} }
} }
WEBSOCKETS_YIELD(); #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
delay(0);
#endif
} }
return ret; return ret;
} }
bool WebSocketsServerCore::broadcastBIN(const uint8_t * payload, size_t length) { bool WebSocketsServer::broadcastBIN(const uint8_t * payload, size_t length) {
return broadcastBIN((uint8_t *)payload, length); return broadcastBIN((uint8_t *)payload, length);
} }
@ -273,7 +305,7 @@ bool WebSocketsServerCore::broadcastBIN(const uint8_t * payload, size_t length)
* @param length size_t * @param length size_t
* @return true if ping is send out * @return true if ping is send out
*/ */
bool WebSocketsServerCore::sendPing(uint8_t num, uint8_t * payload, size_t length) { bool WebSocketsServer::sendPing(uint8_t num, uint8_t * payload, size_t length) {
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) { if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
return false; return false;
} }
@ -284,7 +316,7 @@ bool WebSocketsServerCore::sendPing(uint8_t num, uint8_t * payload, size_t lengt
return false; return false;
} }
bool WebSocketsServerCore::sendPing(uint8_t num, String & payload) { bool WebSocketsServer::sendPing(uint8_t num, String & payload) {
return sendPing(num, (uint8_t *)payload.c_str(), payload.length()); return sendPing(num, (uint8_t *)payload.c_str(), payload.length());
} }
@ -294,7 +326,7 @@ bool WebSocketsServerCore::sendPing(uint8_t num, String & payload) {
* @param length size_t * @param length size_t
* @return true if ping is send out * @return true if ping is send out
*/ */
bool WebSocketsServerCore::broadcastPing(uint8_t * payload, size_t length) { bool WebSocketsServer::broadcastPing(uint8_t * payload, size_t length) {
WSclient_t * client; WSclient_t * client;
bool ret = true; bool ret = true;
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
@ -304,19 +336,21 @@ bool WebSocketsServerCore::broadcastPing(uint8_t * payload, size_t length) {
ret = false; ret = false;
} }
} }
WEBSOCKETS_YIELD(); #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
delay(0);
#endif
} }
return ret; return ret;
} }
bool WebSocketsServerCore::broadcastPing(String & payload) { bool WebSocketsServer::broadcastPing(String & payload) {
return broadcastPing((uint8_t *)payload.c_str(), payload.length()); return broadcastPing((uint8_t *)payload.c_str(), payload.length());
} }
/** /**
* disconnect all clients * disconnect all clients
*/ */
void WebSocketsServerCore::disconnect(void) { void WebSocketsServer::disconnect(void) {
WSclient_t * client; WSclient_t * client;
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
client = &_clients[i]; client = &_clients[i];
@ -330,7 +364,7 @@ void WebSocketsServerCore::disconnect(void) {
* disconnect one client * disconnect one client
* @param num uint8_t client id * @param num uint8_t client id
*/ */
void WebSocketsServerCore::disconnect(uint8_t num) { void WebSocketsServer::disconnect(uint8_t num) {
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) { if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
return; return;
} }
@ -345,7 +379,7 @@ void WebSocketsServerCore::disconnect(uint8_t num) {
* @param user const char * * @param user const char *
* @param password const char * * @param password const char *
*/ */
void WebSocketsServerCore::setAuthorization(const char * user, const char * password) { void WebSocketsServer::setAuthorization(const char * user, const char * password) {
if(user && password) { if(user && password) {
String auth = user; String auth = user;
auth += ":"; auth += ":";
@ -358,7 +392,7 @@ void WebSocketsServerCore::setAuthorization(const char * user, const char * pass
* set the Authorizatio for the http request * set the Authorizatio for the http request
* @param auth const char * base64 * @param auth const char * base64
*/ */
void WebSocketsServerCore::setAuthorization(const char * auth) { void WebSocketsServer::setAuthorization(const char * auth) {
if(auth) { if(auth) {
_base64Authorization = auth; _base64Authorization = auth;
} }
@ -368,7 +402,7 @@ void WebSocketsServerCore::setAuthorization(const char * auth) {
* count the connected clients (optional ping them) * count the connected clients (optional ping them)
* @param ping bool ping the connected clients * @param ping bool ping the connected clients
*/ */
int WebSocketsServerCore::connectedClients(bool ping) { int WebSocketsServer::connectedClients(bool ping) {
WSclient_t * client; WSclient_t * client;
int count = 0; int count = 0;
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
@ -382,25 +416,13 @@ int WebSocketsServerCore::connectedClients(bool ping) {
return count; return count;
} }
/**
* see if one client is connected
* @param num uint8_t client id
*/
bool WebSocketsServerCore::clientIsConnected(uint8_t num) {
if(num >= WEBSOCKETS_SERVER_CLIENT_MAX) {
return false;
}
WSclient_t * client = &_clients[num];
return clientIsConnected(client);
}
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
/** /**
* get an IP for a client * get an IP for a client
* @param num uint8_t client id * @param num uint8_t client id
* @return IPAddress * @return IPAddress
*/ */
IPAddress WebSocketsServerCore::remoteIP(uint8_t num) { IPAddress WebSocketsServer::remoteIP(uint8_t num) {
if(num < WEBSOCKETS_SERVER_CLIENT_MAX) { if(num < WEBSOCKETS_SERVER_CLIENT_MAX) {
WSclient_t * client = &_clients[num]; WSclient_t * client = &_clients[num];
if(clientIsConnected(client)) { if(clientIsConnected(client)) {
@ -420,7 +442,7 @@ IPAddress WebSocketsServerCore::remoteIP(uint8_t num) {
* handle new client connection * handle new client connection
* @param client * @param client
*/ */
WSclient_t * WebSocketsServerCore::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient) { bool WebSocketsServer::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient) {
WSclient_t * client; WSclient_t * client;
// search free list entry for client // search free list entry for client
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
@ -440,16 +462,14 @@ WSclient_t * WebSocketsServerCore::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclien
#endif #endif
client->status = WSC_HEADER; client->status = WSC_HEADER;
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
#ifndef NODEBUG_WEBSOCKETS
IPAddress ip = client->tcp->remoteIP(); IPAddress ip = client->tcp->remoteIP();
#endif
DEBUG_WEBSOCKETS("[WS-Server][%d] new client from %d.%d.%d.%d\n", client->num, ip[0], ip[1], ip[2], ip[3]); DEBUG_WEBSOCKETS("[WS-Server][%d] new client from %d.%d.%d.%d\n", client->num, ip[0], ip[1], ip[2], ip[3]);
#else #else
DEBUG_WEBSOCKETS("[WS-Server][%d] new client\n", client->num); DEBUG_WEBSOCKETS("[WS-Server][%d] new client\n", client->num);
#endif #endif
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
client->tcp->onDisconnect(std::bind([](WebSocketsServerCore * server, AsyncTCPbuffer * obj, WSclient_t * client) -> bool { client->tcp->onDisconnect(std::bind([](WebSocketsServer * server, AsyncTCPbuffer * obj, WSclient_t * client) -> bool {
DEBUG_WEBSOCKETS("[WS-Server][%d] Disconnect client\n", client->num); DEBUG_WEBSOCKETS("[WS-Server][%d] Disconnect client\n", client->num);
AsyncTCPbuffer ** sl = &server->_clients[client->num].tcp; AsyncTCPbuffer ** sl = &server->_clients[client->num].tcp;
@ -461,20 +481,14 @@ WSclient_t * WebSocketsServerCore::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclien
}, },
this, std::placeholders::_1, client)); this, std::placeholders::_1, client));
client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServerCore::handleHeader, this, client, &(client->cHttpLine))); client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServer::handleHeader, this, client, &(client->cHttpLine)));
#endif #endif
client->pingInterval = _pingInterval; return true;
client->pongTimeout = _pongTimeout;
client->disconnectTimeoutCount = _disconnectTimeoutCount;
client->lastPing = millis();
client->pongReceived = false;
return client;
break; break;
} }
} }
return nullptr; return false;
} }
/** /**
@ -484,7 +498,7 @@ WSclient_t * WebSocketsServerCore::newClient(WEBSOCKETS_NETWORK_CLASS * TCPclien
* @param payload uint8_t * * @param payload uint8_t *
* @param length size_t * @param length size_t
*/ */
void WebSocketsServerCore::messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) { void WebSocketsServer::messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin) {
WStype_t type = WStype_ERROR; WStype_t type = WStype_ERROR;
switch(opcode) { switch(opcode) {
@ -511,32 +525,11 @@ void WebSocketsServerCore::messageReceived(WSclient_t * client, WSopcode_t opcod
runCbEvent(client->num, type, payload, length); runCbEvent(client->num, type, payload, length);
} }
/**
* Discard a native client
* @param client WSclient_t * ptr to the client struct contaning the native client "->tcp"
*/
void WebSocketsServerCore::dropNativeClient(WSclient_t * client) {
if(client->tcp) {
if(client->tcp->connected()) {
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) && (WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP32)
client->tcp->flush();
#endif
client->tcp->stop();
}
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
client->status = WSC_NOT_CONNECTED;
#else
delete client->tcp;
#endif
client->tcp = NULL;
}
}
/** /**
* Disconnect an client * Disconnect an client
* @param client WSclient_t * ptr to the client struct * @param client WSclient_t * ptr to the client struct
*/ */
void WebSocketsServerCore::clientDisconnect(WSclient_t * client) { void WebSocketsServer::clientDisconnect(WSclient_t * client) {
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
if(client->isSSL && client->ssl) { if(client->isSSL && client->ssl) {
if(client->ssl->connected()) { if(client->ssl->connected()) {
@ -549,7 +542,20 @@ void WebSocketsServerCore::clientDisconnect(WSclient_t * client) {
} }
#endif #endif
dropNativeClient(client); if(client->tcp) {
if(client->tcp->connected()) {
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
client->tcp->flush();
#endif
client->tcp->stop();
}
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
client->status = WSC_NOT_CONNECTED;
#else
delete client->tcp;
#endif
client->tcp = NULL;
}
client->cUrl = ""; client->cUrl = "";
client->cKey = ""; client->cKey = "";
@ -576,7 +582,7 @@ void WebSocketsServerCore::clientDisconnect(WSclient_t * client) {
* @param client WSclient_t * ptr to the client struct * @param client WSclient_t * ptr to the client struct
* @return true = connected * @return true = connected
*/ */
bool WebSocketsServerCore::clientIsConnected(WSclient_t * client) { bool WebSocketsServer::clientIsConnected(WSclient_t * client) {
if(!client->tcp) { if(!client->tcp) {
return false; return false;
} }
@ -603,30 +609,6 @@ bool WebSocketsServerCore::clientIsConnected(WSclient_t * client) {
return false; return false;
} }
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
/**
* Handle incoming Connection Request
*/
WSclient_t * WebSocketsServerCore::handleNewClient(WEBSOCKETS_NETWORK_CLASS * tcpClient) {
WSclient_t * client = newClient(tcpClient);
if(!client) {
// no free space to handle client
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
#ifndef NODEBUG_WEBSOCKETS
IPAddress ip = tcpClient->remoteIP();
#endif
DEBUG_WEBSOCKETS("[WS-Server] no free space new client from %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
#else
DEBUG_WEBSOCKETS("[WS-Server] no free space new client\n");
#endif
dropNativeClient(client);
}
WEBSOCKETS_YIELD();
return client;
}
/** /**
* Handle incoming Connection Request * Handle incoming Connection Request
*/ */
@ -634,17 +616,35 @@ void WebSocketsServer::handleNewClients(void) {
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
while(_server->hasClient()) { while(_server->hasClient()) {
#endif #endif
bool ok = false;
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
// store new connection // store new connection
WEBSOCKETS_NETWORK_CLASS * tcpClient = new WEBSOCKETS_NETWORK_CLASS(_server->available()); WEBSOCKETS_NETWORK_CLASS * tcpClient = new WEBSOCKETS_NETWORK_CLASS(_server->available());
#else
WEBSOCKETS_NETWORK_CLASS * tcpClient = new WEBSOCKETS_NETWORK_CLASS(_server->available());
#endif
if(!tcpClient) { if(!tcpClient) {
DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!"); DEBUG_WEBSOCKETS("[WS-Client] creating Network class failed!");
return; return;
} }
handleNewClient(tcpClient); ok = newClient(tcpClient);
if(!ok) {
// no free space to handle client
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
IPAddress ip = tcpClient->remoteIP();
DEBUG_WEBSOCKETS("[WS-Server] no free space new client from %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
#else
DEBUG_WEBSOCKETS("[WS-Server] no free space new client\n");
#endif
tcpClient->stop();
}
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
delay(0);
} }
#endif #endif
} }
@ -652,7 +652,7 @@ void WebSocketsServer::handleNewClients(void) {
/** /**
* Handel incomming data from Client * Handel incomming data from Client
*/ */
void WebSocketsServerCore::handleClientData(void) { void WebSocketsServer::handleClientData(void) {
WSclient_t * client; WSclient_t * client;
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) { for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
client = &_clients[i]; client = &_clients[i];
@ -669,16 +669,14 @@ void WebSocketsServerCore::handleClientData(void) {
WebSockets::handleWebsocket(client); WebSockets::handleWebsocket(client);
break; break;
default: default:
DEBUG_WEBSOCKETS("[WS-Server][%d][handleClientData] unknown client status %d\n", client->num, client->status);
WebSockets::clientDisconnect(client, 1002); WebSockets::clientDisconnect(client, 1002);
break; break;
} }
} }
handleHBPing(client);
handleHBTimeout(client);
} }
WEBSOCKETS_YIELD(); #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
delay(0);
#endif
} }
} }
#endif #endif
@ -687,7 +685,7 @@ void WebSocketsServerCore::handleClientData(void) {
* returns an indicator whether the given named header exists in the configured _mandatoryHttpHeaders collection * returns an indicator whether the given named header exists in the configured _mandatoryHttpHeaders collection
* @param headerName String ///< the name of the header being checked * @param headerName String ///< the name of the header being checked
*/ */
bool WebSocketsServerCore::hasMandatoryHeader(String headerName) { bool WebSocketsServer::hasMandatoryHeader(String headerName) {
for(size_t i = 0; i < _mandatoryHttpHeaderCount; i++) { for(size_t i = 0; i < _mandatoryHttpHeaderCount; i++) {
if(_mandatoryHttpHeaders[i].equalsIgnoreCase(headerName)) if(_mandatoryHttpHeaders[i].equalsIgnoreCase(headerName))
return true; return true;
@ -700,7 +698,7 @@ bool WebSocketsServerCore::hasMandatoryHeader(String headerName) {
* @param client WSclient_t * ///< pointer to the client struct * @param client WSclient_t * ///< pointer to the client struct
* @param headerLine String ///< the header being read / processed * @param headerLine String ///< the header being read / processed
*/ */
void WebSocketsServerCore::handleHeader(WSclient_t * client, String * headerLine) { void WebSocketsServer::handleHeader(WSclient_t * client, String * headerLine) {
static const char * NEW_LINE = "\r\n"; static const char * NEW_LINE = "\r\n";
headerLine->trim(); // remove \r headerLine->trim(); // remove \r
@ -759,7 +757,7 @@ void WebSocketsServerCore::handleHeader(WSclient_t * client, String * headerLine
(*headerLine) = ""; (*headerLine) = "";
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServerCore::handleHeader, this, client, &(client->cHttpLine))); client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServer::handleHeader, this, client, &(client->cHttpLine)));
#endif #endif
} else { } else {
DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] Header read fin.\n", client->num); DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] Header read fin.\n", client->num);
@ -852,97 +850,3 @@ void WebSocketsServerCore::handleHeader(WSclient_t * client, String * headerLine
} }
} }
} }
/**
* send heartbeat ping to server in set intervals
*/
void WebSocketsServerCore::handleHBPing(WSclient_t * client) {
if(client->pingInterval == 0)
return;
uint32_t pi = millis() - client->lastPing;
if(pi > client->pingInterval) {
DEBUG_WEBSOCKETS("[WS-Server][%d] sending HB ping\n", client->num);
if(sendPing(client->num)) {
client->lastPing = millis();
client->pongReceived = false;
}
}
}
/**
* enable ping/pong heartbeat process
* @param pingInterval uint32_t how often ping will be sent
* @param pongTimeout uint32_t millis after which pong should timout if not received
* @param disconnectTimeoutCount uint8_t how many timeouts before disconnect, 0=> do not disconnect
*/
void WebSocketsServerCore::enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount) {
_pingInterval = pingInterval;
_pongTimeout = pongTimeout;
_disconnectTimeoutCount = disconnectTimeoutCount;
WSclient_t * client;
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
client = &_clients[i];
WebSockets::enableHeartbeat(client, pingInterval, pongTimeout, disconnectTimeoutCount);
}
}
/**
* disable ping/pong heartbeat process
*/
void WebSocketsServerCore::disableHeartbeat() {
_pingInterval = 0;
WSclient_t * client;
for(uint8_t i = 0; i < WEBSOCKETS_SERVER_CLIENT_MAX; i++) {
client = &_clients[i];
client->pingInterval = 0;
}
}
////////////////////
// WebSocketServer
/**
* called to initialize the Websocket server
*/
void WebSocketsServer::begin(void) {
WebSocketsServerCore::begin();
_server->begin();
DEBUG_WEBSOCKETS("[WS-Server] Server Started.\n");
}
void WebSocketsServer::close(void) {
WebSocketsServerCore::close();
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266)
_server->close();
#elif(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC)
_server->end();
#else
// TODO how to close server?
#endif
}
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
/**
* called in arduino loop
*/
void WebSocketsServerCore::loop(void) {
if(_runnning) {
WEBSOCKETS_YIELD();
handleClientData();
}
}
/**
* called in arduino loop
*/
void WebSocketsServer::loop(void) {
if(_runnning) {
WEBSOCKETS_YIELD();
handleNewClients();
WebSocketsServerCore::loop();
}
}
#endif

View File

@ -31,14 +31,8 @@
#define WEBSOCKETS_SERVER_CLIENT_MAX (5) #define WEBSOCKETS_SERVER_CLIENT_MAX (5)
#endif #endif
class WebSocketsServerCore : protected WebSockets { class WebSocketsServer : protected WebSockets {
public: public:
WebSocketsServerCore(const String & origin = "", const String & protocol = "arduino");
virtual ~WebSocketsServerCore(void);
void begin(void);
void close(void);
#ifdef __AVR__ #ifdef __AVR__
typedef void (*WebSocketServerEvent)(uint8_t num, WStype_t type, uint8_t * payload, size_t length); typedef void (*WebSocketServerEvent)(uint8_t num, WStype_t type, uint8_t * payload, size_t length);
typedef bool (*WebSocketServerHttpHeaderValFunc)(String headerName, String headerValue); typedef bool (*WebSocketServerHttpHeaderValFunc)(String headerName, String headerValue);
@ -47,6 +41,19 @@ class WebSocketsServerCore : protected WebSockets {
typedef std::function<bool(String headerName, String headerValue)> WebSocketServerHttpHeaderValFunc; typedef std::function<bool(String headerName, String headerValue)> WebSocketServerHttpHeaderValFunc;
#endif #endif
WebSocketsServer(uint16_t port, String origin = "", String protocol = "arduino");
virtual ~WebSocketsServer(void);
void begin(void);
void close(void);
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
void loop(void);
#else
// Async interface not need a loop call
void loop(void) __attribute__((deprecated)) {}
#endif
void onEvent(WebSocketServerEvent cbEvent); void onEvent(WebSocketServerEvent cbEvent);
void onValidateHttpHeader( void onValidateHttpHeader(
WebSocketServerHttpHeaderValFunc validationFunc, WebSocketServerHttpHeaderValFunc validationFunc,
@ -85,28 +92,20 @@ class WebSocketsServerCore : protected WebSockets {
int connectedClients(bool ping = false); int connectedClients(bool ping = false);
bool clientIsConnected(uint8_t num);
void enableHeartbeat(uint32_t pingInterval, uint32_t pongTimeout, uint8_t disconnectTimeoutCount);
void disableHeartbeat();
#if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32) #if(WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) || (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP32)
IPAddress remoteIP(uint8_t num); IPAddress remoteIP(uint8_t num);
#endif #endif
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
void loop(void); // handle client data only
#endif
WSclient_t * newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient);
protected: protected:
uint16_t _port;
String _origin; String _origin;
String _protocol; String _protocol;
String _base64Authorization; ///< Base64 encoded Auth request String _base64Authorization; ///< Base64 encoded Auth request
String * _mandatoryHttpHeaders; String * _mandatoryHttpHeaders;
size_t _mandatoryHttpHeaderCount; size_t _mandatoryHttpHeaderCount;
WEBSOCKETS_NETWORK_SERVER_CLASS * _server;
WSclient_t _clients[WEBSOCKETS_SERVER_CLIENT_MAX]; WSclient_t _clients[WEBSOCKETS_SERVER_CLIENT_MAX];
WebSocketServerEvent _cbEvent; WebSocketServerEvent _cbEvent;
@ -114,9 +113,7 @@ class WebSocketsServerCore : protected WebSockets {
bool _runnning; bool _runnning;
uint32_t _pingInterval; bool newClient(WEBSOCKETS_NETWORK_CLASS * TCPclient);
uint32_t _pongTimeout;
uint8_t _disconnectTimeoutCount;
void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin); void messageReceived(WSclient_t * client, WSopcode_t opcode, uint8_t * payload, size_t length, bool fin);
@ -124,13 +121,12 @@ class WebSocketsServerCore : protected WebSockets {
bool clientIsConnected(WSclient_t * client); bool clientIsConnected(WSclient_t * client);
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC) #if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
void handleNewClients(void);
void handleClientData(void); void handleClientData(void);
#endif #endif
void handleHeader(WSclient_t * client, String * headerLine); void handleHeader(WSclient_t * client, String * headerLine);
void handleHBPing(WSclient_t * client); // send ping in specified intervals
/** /**
* called if a non Websocket connection is coming in. * called if a non Websocket connection is coming in.
* Note: can be override * Note: can be override
@ -199,15 +195,6 @@ class WebSocketsServerCore : protected WebSockets {
return true; return true;
} }
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
WSclient_t * handleNewClient(WEBSOCKETS_NETWORK_CLASS * tcpClient);
#endif
/**
* drop native tcp connection (client->tcp)
*/
void dropNativeClient(WSclient_t * client);
private: private:
/* /*
* returns an indicator whether the given named header exists in the configured _mandatoryHttpHeaders collection * returns an indicator whether the given named header exists in the configured _mandatoryHttpHeaders collection
@ -216,28 +203,4 @@ class WebSocketsServerCore : protected WebSockets {
bool hasMandatoryHeader(String headerName); bool hasMandatoryHeader(String headerName);
}; };
class WebSocketsServer : public WebSocketsServerCore {
public:
WebSocketsServer(uint16_t port, const String & origin = "", const String & protocol = "arduino");
virtual ~WebSocketsServer(void);
void begin(void);
void close(void);
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
void loop(void); // handle incoming client and client data
#else
// Async interface not need a loop call
void loop(void) __attribute__((deprecated)) {}
#endif
protected:
#if(WEBSOCKETS_NETWORK_TYPE != NETWORK_ESP8266_ASYNC)
void handleNewClients(void);
#endif
uint16_t _port;
WEBSOCKETS_NETWORK_SERVER_CLASS * _server;
};
#endif /* WEBSOCKETSSERVER_H_ */ #endif /* WEBSOCKETSSERVER_H_ */

View File

@ -1,36 +0,0 @@
/**
* @file WebSocketsVersion.h
* @date 09.02.2021
* @author Markus Sattler
*
* Copyright (c) 2015 Markus Sattler. All rights reserved.
* This file is part of the WebSockets for Arduino.
*
* 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 WEBSOCKETSVERSION_H_
#define WEBSOCKETSVERSION_H_
#define WEBSOCKETS_VERSION "2.3.5"
#define WEBSOCKETS_VERSION_MAJOR 2
#define WEBSOCKETS_VERSION_MINOR 3
#define WEBSOCKETS_VERSION_PATCH 5
#define WEBSOCKETS_VERSION_INT 2003005
#endif /* WEBSOCKETSVERSION_H_ */

View File

@ -27,64 +27,6 @@ function build_sketches()
done done
} }
function build_sketch()
{
local arduino=$1
local sketch=$2
$arduino --verify $sketch;
local result=$?
if [ $result -ne 0 ]; then
echo "Build failed ($sketch) build verbose..."
$arduino --verify --verbose --preserve-temp-files $sketch
result=$?
fi
if [ $result -ne 0 ]; then
echo "Build failed ($1) $sketch"
return $result
fi
}
function get_sketches_json()
{
local arduino=$1
local srcpath=$2
local platform=$3
local sketches=($(find $srcpath -name *.ino))
echo -en "["
for sketch in "${sketches[@]}" ; do
local sketchdir=$(dirname $sketch)
if [[ -f "$sketchdir/.$platform.skip" ]]; then
continue
fi
echo -en "\"$sketch\""
if [[ $sketch != ${sketches[-1]} ]] ; then
echo -en ","
fi
done
echo -en "]"
}
function get_sketches_json_matrix()
{
local arduino=$1
local srcpath=$2
local platform=$3
local ideversion=$4
local board=$5
local sketches=($(find $srcpath -name *.ino))
for sketch in "${sketches[@]}" ; do
local sketchdir=$(dirname $sketch)
local sketchname=$(basename $sketch)
if [[ -f "$sketchdir/.$platform.skip" ]]; then
continue
fi
echo -en "{\"name\":\"$sketchname\",\"board\":\"$board\",\"ideversion\":\"$ideversion\",\"cpu\":\"$platform\",\"sketch\":\"$sketch\"}"
if [[ $sketch != ${sketches[-1]} ]] ; then
echo -en ","
fi
done
}
function get_core() function get_core()
{ {
@ -95,37 +37,17 @@ function get_core()
if [ "$1" = "esp8266" ] ; then if [ "$1" = "esp8266" ] ; then
mkdir esp8266com mkdir esp8266com
cd esp8266com cd esp8266com
git clone --depth 1 https://github.com/esp8266/Arduino.git esp8266 git clone https://github.com/esp8266/Arduino.git esp8266
cd esp8266/ cd esp8266/tools
rm -rf .git
cd tools
python get.py python get.py
fi fi
if [ "$1" = "esp32" ] ; then if [ "$1" = "esp32" ] ; then
mkdir espressif mkdir espressif
cd espressif cd espressif
git clone --depth 1 https://github.com/espressif/arduino-esp32.git esp32 git clone https://github.com/espressif/arduino-esp32.git esp32
cd esp32/ cd esp32/tools
rm -rf .git
cd tools
python get.py python get.py
fi fi
} }
function clone_library() {
local url=$1
echo clone $(basename $url)
mkdir -p $HOME/Arduino/libraries
cd $HOME/Arduino/libraries
git clone --depth 1 $url
rm -rf */.git
rm -rf */.github
rm -rf */examples
}
function hash_library_names() {
cd $HOME/Arduino/libraries
ls | sha1sum -z | cut -c1-5
}

View File

@ -1,132 +0,0 @@
#!/usr/bin/python3
import json
import configparser
import argparse
import re
import os
import datetime
travis_dir = os.path.dirname(os.path.abspath(__file__))
base_dir = os.path.abspath(travis_dir + "/../")
def write_header_file(version):
hvs = version.split('.')
intversion = int(hvs[0]) * 1000000 + int(hvs[1]) * 1000 + int(hvs[2])
now = datetime.datetime.now()
text = f'''/**
* @file WebSocketsVersion.h
* @date {now.strftime("%d.%m.%Y")}
* @author Markus Sattler
*
* Copyright (c) 2015 Markus Sattler. All rights reserved.
* This file is part of the WebSockets for Arduino.
*
* 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 WEBSOCKETSVERSION_H_
#define WEBSOCKETSVERSION_H_
#define WEBSOCKETS_VERSION "{version}"
#define WEBSOCKETS_VERSION_MAJOR {hvs[0]}
#define WEBSOCKETS_VERSION_MINOR {hvs[1]}
#define WEBSOCKETS_VERSION_PATCH {hvs[2]}
#define WEBSOCKETS_VERSION_INT {intversion}
#endif /* WEBSOCKETSVERSION_H_ */
'''
with open(f'{base_dir}/src/WebSocketsVersion.h', 'w') as f:
f.write(text)
def get_library_properties_version():
library_properties = {}
with open(f'{base_dir}/library.properties', 'r') as f:
library_properties = configparser.ConfigParser()
library_properties.read_string('[root]\n' + f.read())
return library_properties['root']['version']
def get_library_json_version():
library_json = {}
with open(f'{base_dir}/library.json', 'r') as f:
library_json = json.load(f)
return library_json['version']
def get_header_versions():
data = {}
define = re.compile('^#define WEBSOCKETS_VERSION_?(.*) "?([0-9\.]*)"?$')
with open(f'{base_dir}/src/WebSocketsVersion.h', 'r') as f:
for line in f:
m = define.match(line)
if m:
name = m[1]
if name == "":
name = "VERSION"
data[name] = m[2]
return data
parser = argparse.ArgumentParser(description='Checks and update Version files')
parser.add_argument(
'--update', action='store_true', default=False)
parser.add_argument(
'--check', action='store_true', default=True)
args = parser.parse_args()
if args.update:
library_properties_version = get_library_properties_version()
with open(f'{base_dir}/library.json', 'r') as f:
library_json = json.load(f)
library_json['version'] = library_properties_version
with open(f'{base_dir}/library.json', 'w') as f:
json.dump(library_json, f, indent=4, sort_keys=True)
write_header_file(library_properties_version)
library_json_version = get_library_json_version()
library_properties_version = get_library_properties_version()
header_version = get_header_versions()
print("WebSocketsVersion.h", header_version)
print(f"library.json: {library_json_version}")
print(f"library.properties: {library_properties_version}")
if args.check:
if library_json_version != library_properties_version or header_version['VERSION'] != library_properties_version:
raise Exception('versions did not match!')
hvs = header_version['VERSION'].split('.')
if header_version['MAJOR'] != hvs[0]:
raise Exception('header MAJOR version wrong!')
if header_version['MINOR'] != hvs[1]:
raise Exception('header MINOR version wrong!')
if header_version['PATCH'] != hvs[2]:
raise Exception('header PATCH version wrong!')
intversion = int(hvs[0]) * 1000000 + int(hvs[1]) * 1000 + int(hvs[2])
if int(header_version['INT']) != intversion:
raise Exception('header INT version wrong!')