mirror of
https://github.com/esp8266/Arduino.git
synced 2025-06-13 13:01:55 +03:00
Allman now (#6080)
* switch restyle script for CI * remove confirmation * restyle with allman
This commit is contained in:
committed by
david gauchard
parent
625c3a62c4
commit
98125f8860
@ -8,9 +8,9 @@
|
||||
#include "StreamString.h"
|
||||
|
||||
extern "C" {
|
||||
#include "osapi.h"
|
||||
#include "ets_sys.h"
|
||||
#include "user_interface.h"
|
||||
#include "osapi.h"
|
||||
#include "ets_sys.h"
|
||||
#include "user_interface.h"
|
||||
}
|
||||
|
||||
#include "lwip/opt.h"
|
||||
@ -31,348 +31,435 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
ArduinoOTAClass::ArduinoOTAClass()
|
||||
: _port(0)
|
||||
, _udp_ota(0)
|
||||
, _initialized(false)
|
||||
, _rebootOnSuccess(true)
|
||||
, _useMDNS(true)
|
||||
, _state(OTA_IDLE)
|
||||
, _size(0)
|
||||
, _cmd(0)
|
||||
, _ota_port(0)
|
||||
, _start_callback(NULL)
|
||||
, _end_callback(NULL)
|
||||
, _error_callback(NULL)
|
||||
, _progress_callback(NULL)
|
||||
: _port(0)
|
||||
, _udp_ota(0)
|
||||
, _initialized(false)
|
||||
, _rebootOnSuccess(true)
|
||||
, _useMDNS(true)
|
||||
, _state(OTA_IDLE)
|
||||
, _size(0)
|
||||
, _cmd(0)
|
||||
, _ota_port(0)
|
||||
, _start_callback(NULL)
|
||||
, _end_callback(NULL)
|
||||
, _error_callback(NULL)
|
||||
, _progress_callback(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
ArduinoOTAClass::~ArduinoOTAClass(){
|
||||
if(_udp_ota){
|
||||
_udp_ota->unref();
|
||||
_udp_ota = 0;
|
||||
}
|
||||
ArduinoOTAClass::~ArduinoOTAClass()
|
||||
{
|
||||
if (_udp_ota)
|
||||
{
|
||||
_udp_ota->unref();
|
||||
_udp_ota = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::onStart(THandlerFunction fn) {
|
||||
void ArduinoOTAClass::onStart(THandlerFunction fn)
|
||||
{
|
||||
_start_callback = fn;
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::onEnd(THandlerFunction fn) {
|
||||
void ArduinoOTAClass::onEnd(THandlerFunction fn)
|
||||
{
|
||||
_end_callback = fn;
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::onProgress(THandlerFunction_Progress fn) {
|
||||
void ArduinoOTAClass::onProgress(THandlerFunction_Progress fn)
|
||||
{
|
||||
_progress_callback = fn;
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::onError(THandlerFunction_Error fn) {
|
||||
void ArduinoOTAClass::onError(THandlerFunction_Error fn)
|
||||
{
|
||||
_error_callback = fn;
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::setPort(uint16_t port) {
|
||||
if (!_initialized && !_port && port) {
|
||||
_port = port;
|
||||
}
|
||||
void ArduinoOTAClass::setPort(uint16_t port)
|
||||
{
|
||||
if (!_initialized && !_port && port)
|
||||
{
|
||||
_port = port;
|
||||
}
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::setHostname(const char * hostname) {
|
||||
if (!_initialized && !_hostname.length() && hostname) {
|
||||
_hostname = hostname;
|
||||
}
|
||||
void ArduinoOTAClass::setHostname(const char * hostname)
|
||||
{
|
||||
if (!_initialized && !_hostname.length() && hostname)
|
||||
{
|
||||
_hostname = hostname;
|
||||
}
|
||||
}
|
||||
|
||||
String ArduinoOTAClass::getHostname() {
|
||||
return _hostname;
|
||||
String ArduinoOTAClass::getHostname()
|
||||
{
|
||||
return _hostname;
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::setPassword(const char * password) {
|
||||
if (!_initialized && !_password.length() && password) {
|
||||
MD5Builder passmd5;
|
||||
passmd5.begin();
|
||||
passmd5.add(password);
|
||||
passmd5.calculate();
|
||||
_password = passmd5.toString();
|
||||
}
|
||||
void ArduinoOTAClass::setPassword(const char * password)
|
||||
{
|
||||
if (!_initialized && !_password.length() && password)
|
||||
{
|
||||
MD5Builder passmd5;
|
||||
passmd5.begin();
|
||||
passmd5.add(password);
|
||||
passmd5.calculate();
|
||||
_password = passmd5.toString();
|
||||
}
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::setPasswordHash(const char * password) {
|
||||
if (!_initialized && !_password.length() && password) {
|
||||
_password = password;
|
||||
}
|
||||
void ArduinoOTAClass::setPasswordHash(const char * password)
|
||||
{
|
||||
if (!_initialized && !_password.length() && password)
|
||||
{
|
||||
_password = password;
|
||||
}
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::setRebootOnSuccess(bool reboot){
|
||||
_rebootOnSuccess = reboot;
|
||||
void ArduinoOTAClass::setRebootOnSuccess(bool reboot)
|
||||
{
|
||||
_rebootOnSuccess = reboot;
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::begin(bool useMDNS) {
|
||||
if (_initialized)
|
||||
return;
|
||||
void ArduinoOTAClass::begin(bool useMDNS)
|
||||
{
|
||||
if (_initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_useMDNS = useMDNS;
|
||||
_useMDNS = useMDNS;
|
||||
|
||||
if (!_hostname.length()) {
|
||||
char tmp[15];
|
||||
sprintf(tmp, "esp8266-%06x", ESP.getChipId());
|
||||
_hostname = tmp;
|
||||
}
|
||||
if (!_port) {
|
||||
_port = 8266;
|
||||
}
|
||||
if (!_hostname.length())
|
||||
{
|
||||
char tmp[15];
|
||||
sprintf(tmp, "esp8266-%06x", ESP.getChipId());
|
||||
_hostname = tmp;
|
||||
}
|
||||
if (!_port)
|
||||
{
|
||||
_port = 8266;
|
||||
}
|
||||
|
||||
if(_udp_ota){
|
||||
_udp_ota->unref();
|
||||
_udp_ota = 0;
|
||||
}
|
||||
if (_udp_ota)
|
||||
{
|
||||
_udp_ota->unref();
|
||||
_udp_ota = 0;
|
||||
}
|
||||
|
||||
_udp_ota = new UdpContext;
|
||||
_udp_ota->ref();
|
||||
_udp_ota = new UdpContext;
|
||||
_udp_ota->ref();
|
||||
|
||||
if (!_udp_ota->listen(IP_ADDR_ANY, _port))
|
||||
{
|
||||
return;
|
||||
}
|
||||
_udp_ota->onRx(std::bind(&ArduinoOTAClass::_onRx, this));
|
||||
|
||||
if(!_udp_ota->listen(IP_ADDR_ANY, _port))
|
||||
return;
|
||||
_udp_ota->onRx(std::bind(&ArduinoOTAClass::_onRx, this));
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS)
|
||||
if(_useMDNS) {
|
||||
MDNS.begin(_hostname.c_str());
|
||||
if (_useMDNS)
|
||||
{
|
||||
MDNS.begin(_hostname.c_str());
|
||||
|
||||
if (_password.length()) {
|
||||
MDNS.enableArduino(_port, true);
|
||||
} else {
|
||||
MDNS.enableArduino(_port);
|
||||
if (_password.length())
|
||||
{
|
||||
MDNS.enableArduino(_port, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
MDNS.enableArduino(_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
_initialized = true;
|
||||
_state = OTA_IDLE;
|
||||
_initialized = true;
|
||||
_state = OTA_IDLE;
|
||||
#ifdef OTA_DEBUG
|
||||
OTA_DEBUG.printf("OTA server at: %s.local:%u\n", _hostname.c_str(), _port);
|
||||
OTA_DEBUG.printf("OTA server at: %s.local:%u\n", _hostname.c_str(), _port);
|
||||
#endif
|
||||
}
|
||||
|
||||
int ArduinoOTAClass::parseInt(){
|
||||
char data[16];
|
||||
uint8_t index;
|
||||
char value;
|
||||
while(_udp_ota->peek() == ' ') _udp_ota->read();
|
||||
for(index = 0; index < sizeof(data); ++index){
|
||||
value = _udp_ota->peek();
|
||||
if(value < '0' || value > '9'){
|
||||
data[index] = '\0';
|
||||
return atoi(data);
|
||||
int ArduinoOTAClass::parseInt()
|
||||
{
|
||||
char data[16];
|
||||
uint8_t index;
|
||||
char value;
|
||||
while (_udp_ota->peek() == ' ')
|
||||
{
|
||||
_udp_ota->read();
|
||||
}
|
||||
data[index] = _udp_ota->read();
|
||||
}
|
||||
return 0;
|
||||
for (index = 0; index < sizeof(data); ++index)
|
||||
{
|
||||
value = _udp_ota->peek();
|
||||
if (value < '0' || value > '9')
|
||||
{
|
||||
data[index] = '\0';
|
||||
return atoi(data);
|
||||
}
|
||||
data[index] = _udp_ota->read();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
String ArduinoOTAClass::readStringUntil(char end){
|
||||
String res = "";
|
||||
int value;
|
||||
while(true){
|
||||
value = _udp_ota->read();
|
||||
if(value < 0 || value == '\0' || value == end){
|
||||
return res;
|
||||
String ArduinoOTAClass::readStringUntil(char end)
|
||||
{
|
||||
String res = "";
|
||||
int value;
|
||||
while (true)
|
||||
{
|
||||
value = _udp_ota->read();
|
||||
if (value < 0 || value == '\0' || value == end)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
res += static_cast<char>(value);
|
||||
}
|
||||
res += static_cast<char>(value);
|
||||
}
|
||||
return res;
|
||||
return res;
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::_onRx(){
|
||||
if(!_udp_ota->next()) return;
|
||||
IPAddress ota_ip;
|
||||
|
||||
if (_state == OTA_IDLE) {
|
||||
int cmd = parseInt();
|
||||
if (cmd != U_FLASH && cmd != U_SPIFFS)
|
||||
return;
|
||||
_ota_ip = _udp_ota->getRemoteAddress();
|
||||
_cmd = cmd;
|
||||
_ota_port = parseInt();
|
||||
_ota_udp_port = _udp_ota->getRemotePort();
|
||||
_size = parseInt();
|
||||
_udp_ota->read();
|
||||
_md5 = readStringUntil('\n');
|
||||
_md5.trim();
|
||||
if(_md5.length() != 32)
|
||||
return;
|
||||
|
||||
ota_ip = _ota_ip;
|
||||
|
||||
if (_password.length()){
|
||||
MD5Builder nonce_md5;
|
||||
nonce_md5.begin();
|
||||
nonce_md5.add(String(micros()));
|
||||
nonce_md5.calculate();
|
||||
_nonce = nonce_md5.toString();
|
||||
|
||||
char auth_req[38];
|
||||
sprintf(auth_req, "AUTH %s", _nonce.c_str());
|
||||
_udp_ota->append((const char *)auth_req, strlen(auth_req));
|
||||
_udp_ota->send(ota_ip, _ota_udp_port);
|
||||
_state = OTA_WAITAUTH;
|
||||
return;
|
||||
} else {
|
||||
_state = OTA_RUNUPDATE;
|
||||
void ArduinoOTAClass::_onRx()
|
||||
{
|
||||
if (!_udp_ota->next())
|
||||
{
|
||||
return;
|
||||
}
|
||||
} else if (_state == OTA_WAITAUTH) {
|
||||
int cmd = parseInt();
|
||||
if (cmd != U_AUTH) {
|
||||
_state = OTA_IDLE;
|
||||
return;
|
||||
IPAddress ota_ip;
|
||||
|
||||
if (_state == OTA_IDLE)
|
||||
{
|
||||
int cmd = parseInt();
|
||||
if (cmd != U_FLASH && cmd != U_SPIFFS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_ota_ip = _udp_ota->getRemoteAddress();
|
||||
_cmd = cmd;
|
||||
_ota_port = parseInt();
|
||||
_ota_udp_port = _udp_ota->getRemotePort();
|
||||
_size = parseInt();
|
||||
_udp_ota->read();
|
||||
_md5 = readStringUntil('\n');
|
||||
_md5.trim();
|
||||
if (_md5.length() != 32)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ota_ip = _ota_ip;
|
||||
|
||||
if (_password.length())
|
||||
{
|
||||
MD5Builder nonce_md5;
|
||||
nonce_md5.begin();
|
||||
nonce_md5.add(String(micros()));
|
||||
nonce_md5.calculate();
|
||||
_nonce = nonce_md5.toString();
|
||||
|
||||
char auth_req[38];
|
||||
sprintf(auth_req, "AUTH %s", _nonce.c_str());
|
||||
_udp_ota->append((const char *)auth_req, strlen(auth_req));
|
||||
_udp_ota->send(ota_ip, _ota_udp_port);
|
||||
_state = OTA_WAITAUTH;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
_state = OTA_RUNUPDATE;
|
||||
}
|
||||
}
|
||||
_udp_ota->read();
|
||||
String cnonce = readStringUntil(' ');
|
||||
String response = readStringUntil('\n');
|
||||
if (cnonce.length() != 32 || response.length() != 32) {
|
||||
_state = OTA_IDLE;
|
||||
return;
|
||||
else if (_state == OTA_WAITAUTH)
|
||||
{
|
||||
int cmd = parseInt();
|
||||
if (cmd != U_AUTH)
|
||||
{
|
||||
_state = OTA_IDLE;
|
||||
return;
|
||||
}
|
||||
_udp_ota->read();
|
||||
String cnonce = readStringUntil(' ');
|
||||
String response = readStringUntil('\n');
|
||||
if (cnonce.length() != 32 || response.length() != 32)
|
||||
{
|
||||
_state = OTA_IDLE;
|
||||
return;
|
||||
}
|
||||
|
||||
String challenge = _password + ":" + String(_nonce) + ":" + cnonce;
|
||||
MD5Builder _challengemd5;
|
||||
_challengemd5.begin();
|
||||
_challengemd5.add(challenge);
|
||||
_challengemd5.calculate();
|
||||
String result = _challengemd5.toString();
|
||||
|
||||
ota_ip = _ota_ip;
|
||||
if (result.equalsConstantTime(response))
|
||||
{
|
||||
_state = OTA_RUNUPDATE;
|
||||
}
|
||||
else
|
||||
{
|
||||
_udp_ota->append("Authentication Failed", 21);
|
||||
_udp_ota->send(ota_ip, _ota_udp_port);
|
||||
if (_error_callback)
|
||||
{
|
||||
_error_callback(OTA_AUTH_ERROR);
|
||||
}
|
||||
_state = OTA_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
String challenge = _password + ":" + String(_nonce) + ":" + cnonce;
|
||||
MD5Builder _challengemd5;
|
||||
_challengemd5.begin();
|
||||
_challengemd5.add(challenge);
|
||||
_challengemd5.calculate();
|
||||
String result = _challengemd5.toString();
|
||||
|
||||
ota_ip = _ota_ip;
|
||||
if(result.equalsConstantTime(response)) {
|
||||
_state = OTA_RUNUPDATE;
|
||||
} else {
|
||||
_udp_ota->append("Authentication Failed", 21);
|
||||
_udp_ota->send(ota_ip, _ota_udp_port);
|
||||
if (_error_callback) _error_callback(OTA_AUTH_ERROR);
|
||||
_state = OTA_IDLE;
|
||||
while (_udp_ota->next())
|
||||
{
|
||||
_udp_ota->flush();
|
||||
}
|
||||
}
|
||||
|
||||
while(_udp_ota->next()) _udp_ota->flush();
|
||||
}
|
||||
|
||||
void ArduinoOTAClass::_runUpdate() {
|
||||
IPAddress ota_ip = _ota_ip;
|
||||
void ArduinoOTAClass::_runUpdate()
|
||||
{
|
||||
IPAddress ota_ip = _ota_ip;
|
||||
|
||||
if (!Update.begin(_size, _cmd)) {
|
||||
if (!Update.begin(_size, _cmd))
|
||||
{
|
||||
#ifdef OTA_DEBUG
|
||||
OTA_DEBUG.println("Update Begin Error");
|
||||
OTA_DEBUG.println("Update Begin Error");
|
||||
#endif
|
||||
if (_error_callback) {
|
||||
_error_callback(OTA_BEGIN_ERROR);
|
||||
if (_error_callback)
|
||||
{
|
||||
_error_callback(OTA_BEGIN_ERROR);
|
||||
}
|
||||
|
||||
StreamString ss;
|
||||
Update.printError(ss);
|
||||
_udp_ota->append("ERR: ", 5);
|
||||
_udp_ota->append(ss.c_str(), ss.length());
|
||||
_udp_ota->send(ota_ip, _ota_udp_port);
|
||||
delay(100);
|
||||
_udp_ota->listen(IP_ADDR_ANY, _port);
|
||||
_state = OTA_IDLE;
|
||||
return;
|
||||
}
|
||||
|
||||
StreamString ss;
|
||||
Update.printError(ss);
|
||||
_udp_ota->append("ERR: ", 5);
|
||||
_udp_ota->append(ss.c_str(), ss.length());
|
||||
_udp_ota->append("OK", 2);
|
||||
_udp_ota->send(ota_ip, _ota_udp_port);
|
||||
delay(100);
|
||||
_udp_ota->listen(IP_ADDR_ANY, _port);
|
||||
_state = OTA_IDLE;
|
||||
return;
|
||||
}
|
||||
_udp_ota->append("OK", 2);
|
||||
_udp_ota->send(ota_ip, _ota_udp_port);
|
||||
delay(100);
|
||||
|
||||
Update.setMD5(_md5.c_str());
|
||||
WiFiUDP::stopAll();
|
||||
WiFiClient::stopAll();
|
||||
Update.setMD5(_md5.c_str());
|
||||
WiFiUDP::stopAll();
|
||||
WiFiClient::stopAll();
|
||||
|
||||
if (_start_callback) {
|
||||
_start_callback();
|
||||
}
|
||||
if (_progress_callback) {
|
||||
_progress_callback(0, _size);
|
||||
}
|
||||
if (_start_callback)
|
||||
{
|
||||
_start_callback();
|
||||
}
|
||||
if (_progress_callback)
|
||||
{
|
||||
_progress_callback(0, _size);
|
||||
}
|
||||
|
||||
WiFiClient client;
|
||||
if (!client.connect(_ota_ip, _ota_port)) {
|
||||
WiFiClient client;
|
||||
if (!client.connect(_ota_ip, _ota_port))
|
||||
{
|
||||
#ifdef OTA_DEBUG
|
||||
OTA_DEBUG.printf("Connect Failed\n");
|
||||
OTA_DEBUG.printf("Connect Failed\n");
|
||||
#endif
|
||||
_udp_ota->listen(IP_ADDR_ANY, _port);
|
||||
if (_error_callback) {
|
||||
_error_callback(OTA_CONNECT_ERROR);
|
||||
_udp_ota->listen(IP_ADDR_ANY, _port);
|
||||
if (_error_callback)
|
||||
{
|
||||
_error_callback(OTA_CONNECT_ERROR);
|
||||
}
|
||||
_state = OTA_IDLE;
|
||||
}
|
||||
_state = OTA_IDLE;
|
||||
}
|
||||
// OTA sends little packets
|
||||
client.setNoDelay(true);
|
||||
// OTA sends little packets
|
||||
client.setNoDelay(true);
|
||||
|
||||
uint32_t written, total = 0;
|
||||
while (!Update.isFinished() && client.connected()) {
|
||||
int waited = 1000;
|
||||
while (!client.available() && waited--)
|
||||
delay(1);
|
||||
if (!waited){
|
||||
uint32_t written, total = 0;
|
||||
while (!Update.isFinished() && client.connected())
|
||||
{
|
||||
int waited = 1000;
|
||||
while (!client.available() && waited--)
|
||||
{
|
||||
delay(1);
|
||||
}
|
||||
if (!waited)
|
||||
{
|
||||
#ifdef OTA_DEBUG
|
||||
OTA_DEBUG.printf("Receive Failed\n");
|
||||
OTA_DEBUG.printf("Receive Failed\n");
|
||||
#endif
|
||||
_udp_ota->listen(IP_ADDR_ANY, _port);
|
||||
if (_error_callback) {
|
||||
_error_callback(OTA_RECEIVE_ERROR);
|
||||
}
|
||||
_state = OTA_IDLE;
|
||||
_udp_ota->listen(IP_ADDR_ANY, _port);
|
||||
if (_error_callback)
|
||||
{
|
||||
_error_callback(OTA_RECEIVE_ERROR);
|
||||
}
|
||||
_state = OTA_IDLE;
|
||||
}
|
||||
written = Update.write(client);
|
||||
if (written > 0)
|
||||
{
|
||||
client.print(written, DEC);
|
||||
total += written;
|
||||
if (_progress_callback)
|
||||
{
|
||||
_progress_callback(total, _size);
|
||||
}
|
||||
}
|
||||
}
|
||||
written = Update.write(client);
|
||||
if (written > 0) {
|
||||
client.print(written, DEC);
|
||||
total += written;
|
||||
if(_progress_callback) {
|
||||
_progress_callback(total, _size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Update.end()) {
|
||||
client.print("OK");
|
||||
client.stop();
|
||||
delay(10);
|
||||
if (Update.end())
|
||||
{
|
||||
client.print("OK");
|
||||
client.stop();
|
||||
delay(10);
|
||||
#ifdef OTA_DEBUG
|
||||
OTA_DEBUG.printf("Update Success\n");
|
||||
OTA_DEBUG.printf("Update Success\n");
|
||||
#endif
|
||||
if (_end_callback) {
|
||||
_end_callback();
|
||||
}
|
||||
if(_rebootOnSuccess){
|
||||
if (_end_callback)
|
||||
{
|
||||
_end_callback();
|
||||
}
|
||||
if (_rebootOnSuccess)
|
||||
{
|
||||
#ifdef OTA_DEBUG
|
||||
OTA_DEBUG.printf("Rebooting...\n");
|
||||
OTA_DEBUG.printf("Rebooting...\n");
|
||||
#endif
|
||||
//let serial/network finish tasks that might be given in _end_callback
|
||||
delay(100);
|
||||
ESP.restart();
|
||||
//let serial/network finish tasks that might be given in _end_callback
|
||||
delay(100);
|
||||
ESP.restart();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_udp_ota->listen(IP_ADDR_ANY, _port);
|
||||
if (_error_callback) {
|
||||
_error_callback(OTA_END_ERROR);
|
||||
}
|
||||
Update.printError(client);
|
||||
else
|
||||
{
|
||||
_udp_ota->listen(IP_ADDR_ANY, _port);
|
||||
if (_error_callback)
|
||||
{
|
||||
_error_callback(OTA_END_ERROR);
|
||||
}
|
||||
Update.printError(client);
|
||||
#ifdef OTA_DEBUG
|
||||
Update.printError(OTA_DEBUG);
|
||||
Update.printError(OTA_DEBUG);
|
||||
#endif
|
||||
_state = OTA_IDLE;
|
||||
}
|
||||
_state = OTA_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
//this needs to be called in the loop()
|
||||
void ArduinoOTAClass::handle() {
|
||||
if (_state == OTA_RUNUPDATE) {
|
||||
_runUpdate();
|
||||
_state = OTA_IDLE;
|
||||
}
|
||||
void ArduinoOTAClass::handle()
|
||||
{
|
||||
if (_state == OTA_RUNUPDATE)
|
||||
{
|
||||
_runUpdate();
|
||||
_state = OTA_IDLE;
|
||||
}
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS)
|
||||
if(_useMDNS)
|
||||
MDNS.update(); //handle MDNS update as well, given that ArduinoOTA relies on it anyways
|
||||
if (_useMDNS)
|
||||
{
|
||||
MDNS.update(); //handle MDNS update as well, given that ArduinoOTA relies on it anyways
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int ArduinoOTAClass::getCommand() {
|
||||
return _cmd;
|
||||
int ArduinoOTAClass::getCommand()
|
||||
{
|
||||
return _cmd;
|
||||
}
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_ARDUINOOTA)
|
||||
|
@ -7,26 +7,28 @@
|
||||
|
||||
class UdpContext;
|
||||
|
||||
typedef enum {
|
||||
OTA_IDLE,
|
||||
OTA_WAITAUTH,
|
||||
OTA_RUNUPDATE
|
||||
typedef enum
|
||||
{
|
||||
OTA_IDLE,
|
||||
OTA_WAITAUTH,
|
||||
OTA_RUNUPDATE
|
||||
} ota_state_t;
|
||||
|
||||
typedef enum {
|
||||
OTA_AUTH_ERROR,
|
||||
OTA_BEGIN_ERROR,
|
||||
OTA_CONNECT_ERROR,
|
||||
OTA_RECEIVE_ERROR,
|
||||
OTA_END_ERROR
|
||||
typedef enum
|
||||
{
|
||||
OTA_AUTH_ERROR,
|
||||
OTA_BEGIN_ERROR,
|
||||
OTA_CONNECT_ERROR,
|
||||
OTA_RECEIVE_ERROR,
|
||||
OTA_END_ERROR
|
||||
} ota_error_t;
|
||||
|
||||
class ArduinoOTAClass
|
||||
{
|
||||
public:
|
||||
typedef std::function<void(void)> THandlerFunction;
|
||||
typedef std::function<void(ota_error_t)> THandlerFunction_Error;
|
||||
typedef std::function<void(unsigned int, unsigned int)> THandlerFunction_Progress;
|
||||
public:
|
||||
typedef std::function<void(void)> THandlerFunction;
|
||||
typedef std::function<void(ota_error_t)> THandlerFunction_Error;
|
||||
typedef std::function<void(unsigned int, unsigned int)> THandlerFunction_Progress;
|
||||
|
||||
ArduinoOTAClass();
|
||||
~ArduinoOTAClass();
|
||||
@ -68,7 +70,7 @@ class ArduinoOTAClass
|
||||
//Gets update command type after OTA has started. Either U_FLASH or U_SPIFFS
|
||||
int getCommand();
|
||||
|
||||
private:
|
||||
private:
|
||||
int _port;
|
||||
String _password;
|
||||
String _hostname;
|
||||
|
@ -13,244 +13,281 @@
|
||||
|
||||
DNSServer::DNSServer()
|
||||
{
|
||||
_ttl = lwip_htonl(60);
|
||||
_errorReplyCode = DNSReplyCode::NonExistentDomain;
|
||||
_ttl = lwip_htonl(60);
|
||||
_errorReplyCode = DNSReplyCode::NonExistentDomain;
|
||||
}
|
||||
|
||||
bool DNSServer::start(const uint16_t &port, const String &domainName,
|
||||
const IPAddress &resolvedIP)
|
||||
const IPAddress &resolvedIP)
|
||||
{
|
||||
_port = port;
|
||||
|
||||
_domainName = domainName;
|
||||
_resolvedIP[0] = resolvedIP[0];
|
||||
_resolvedIP[1] = resolvedIP[1];
|
||||
_resolvedIP[2] = resolvedIP[2];
|
||||
_resolvedIP[3] = resolvedIP[3];
|
||||
downcaseAndRemoveWwwPrefix(_domainName);
|
||||
return _udp.begin(_port) == 1;
|
||||
_port = port;
|
||||
|
||||
_domainName = domainName;
|
||||
_resolvedIP[0] = resolvedIP[0];
|
||||
_resolvedIP[1] = resolvedIP[1];
|
||||
_resolvedIP[2] = resolvedIP[2];
|
||||
_resolvedIP[3] = resolvedIP[3];
|
||||
downcaseAndRemoveWwwPrefix(_domainName);
|
||||
return _udp.begin(_port) == 1;
|
||||
}
|
||||
|
||||
void DNSServer::setErrorReplyCode(const DNSReplyCode &replyCode)
|
||||
{
|
||||
_errorReplyCode = replyCode;
|
||||
_errorReplyCode = replyCode;
|
||||
}
|
||||
|
||||
void DNSServer::setTTL(const uint32_t &ttl)
|
||||
{
|
||||
_ttl = lwip_htonl(ttl);
|
||||
_ttl = lwip_htonl(ttl);
|
||||
}
|
||||
|
||||
void DNSServer::stop()
|
||||
{
|
||||
_udp.stop();
|
||||
_udp.stop();
|
||||
}
|
||||
|
||||
void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName)
|
||||
{
|
||||
domainName.toLowerCase();
|
||||
if (domainName.startsWith("www."))
|
||||
domainName.remove(0, 4);
|
||||
domainName.toLowerCase();
|
||||
if (domainName.startsWith("www."))
|
||||
{
|
||||
domainName.remove(0, 4);
|
||||
}
|
||||
}
|
||||
|
||||
void DNSServer::respondToRequest(uint8_t *buffer, size_t length)
|
||||
{
|
||||
DNSHeader *dnsHeader;
|
||||
uint8_t *query, *start;
|
||||
const char *matchString;
|
||||
size_t remaining, labelLength, queryLength;
|
||||
uint16_t qtype, qclass;
|
||||
DNSHeader *dnsHeader;
|
||||
uint8_t *query, *start;
|
||||
const char *matchString;
|
||||
size_t remaining, labelLength, queryLength;
|
||||
uint16_t qtype, qclass;
|
||||
|
||||
dnsHeader = (DNSHeader *)buffer;
|
||||
dnsHeader = (DNSHeader *)buffer;
|
||||
|
||||
// Must be a query for us to do anything with it
|
||||
if (dnsHeader->QR != DNS_QR_QUERY)
|
||||
return;
|
||||
|
||||
// If operation is anything other than query, we don't do it
|
||||
if (dnsHeader->OPCode != DNS_OPCODE_QUERY)
|
||||
return replyWithError(dnsHeader, DNSReplyCode::NotImplemented);
|
||||
|
||||
// Only support requests containing single queries - everything else
|
||||
// is badly defined
|
||||
if (dnsHeader->QDCount != lwip_htons(1))
|
||||
return replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
|
||||
// We must return a FormError in the case of a non-zero ARCount to
|
||||
// be minimally compatible with EDNS resolvers
|
||||
if (dnsHeader->ANCount != 0 || dnsHeader->NSCount != 0
|
||||
|| dnsHeader->ARCount != 0)
|
||||
return replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
|
||||
// Even if we're not going to use the query, we need to parse it
|
||||
// so we can check the address type that's being queried
|
||||
|
||||
query = start = buffer + DNS_HEADER_SIZE;
|
||||
remaining = length - DNS_HEADER_SIZE;
|
||||
while (remaining != 0 && *start != 0) {
|
||||
labelLength = *start;
|
||||
if (labelLength + 1 > remaining)
|
||||
return replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
remaining -= (labelLength + 1);
|
||||
start += (labelLength + 1);
|
||||
}
|
||||
|
||||
// 1 octet labelLength, 2 octet qtype, 2 octet qclass
|
||||
if (remaining < 5)
|
||||
return replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
|
||||
start += 1; // Skip the 0 length label that we found above
|
||||
|
||||
memcpy(&qtype, start, sizeof(qtype));
|
||||
start += 2;
|
||||
memcpy(&qclass, start, sizeof(qclass));
|
||||
start += 2;
|
||||
|
||||
queryLength = start - query;
|
||||
|
||||
if (qclass != lwip_htons(DNS_QCLASS_ANY)
|
||||
&& qclass != lwip_htons(DNS_QCLASS_IN))
|
||||
return replyWithError(dnsHeader, DNSReplyCode::NonExistentDomain,
|
||||
query, queryLength);
|
||||
|
||||
if (qtype != lwip_htons(DNS_QTYPE_A)
|
||||
&& qtype != lwip_htons(DNS_QTYPE_ANY))
|
||||
return replyWithError(dnsHeader, DNSReplyCode::NonExistentDomain,
|
||||
query, queryLength);
|
||||
|
||||
// If we have no domain name configured, just return an error
|
||||
if (_domainName == "")
|
||||
return replyWithError(dnsHeader, _errorReplyCode,
|
||||
query, queryLength);
|
||||
|
||||
// If we're running with a wildcard we can just return a result now
|
||||
if (_domainName == "*")
|
||||
return replyWithIP(dnsHeader, query, queryLength);
|
||||
|
||||
matchString = _domainName.c_str();
|
||||
|
||||
start = query;
|
||||
|
||||
// If there's a leading 'www', skip it
|
||||
if (*start == 3 && strncasecmp("www", (char *) start + 1, 3) == 0)
|
||||
start += 4;
|
||||
|
||||
while (*start != 0) {
|
||||
labelLength = *start;
|
||||
start += 1;
|
||||
while (labelLength > 0) {
|
||||
if (tolower(*start) != *matchString)
|
||||
return replyWithError(dnsHeader, _errorReplyCode,
|
||||
query, queryLength);
|
||||
++start;
|
||||
++matchString;
|
||||
--labelLength;
|
||||
// Must be a query for us to do anything with it
|
||||
if (dnsHeader->QR != DNS_QR_QUERY)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (*start == 0 && *matchString == '\0')
|
||||
return replyWithIP(dnsHeader, query, queryLength);
|
||||
|
||||
if (*matchString != '.')
|
||||
return replyWithError(dnsHeader, _errorReplyCode,
|
||||
query, queryLength);
|
||||
++matchString;
|
||||
}
|
||||
// If operation is anything other than query, we don't do it
|
||||
if (dnsHeader->OPCode != DNS_OPCODE_QUERY)
|
||||
{
|
||||
return replyWithError(dnsHeader, DNSReplyCode::NotImplemented);
|
||||
}
|
||||
|
||||
return replyWithError(dnsHeader, _errorReplyCode,
|
||||
query, queryLength);
|
||||
// Only support requests containing single queries - everything else
|
||||
// is badly defined
|
||||
if (dnsHeader->QDCount != lwip_htons(1))
|
||||
{
|
||||
return replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
}
|
||||
|
||||
// We must return a FormError in the case of a non-zero ARCount to
|
||||
// be minimally compatible with EDNS resolvers
|
||||
if (dnsHeader->ANCount != 0 || dnsHeader->NSCount != 0
|
||||
|| dnsHeader->ARCount != 0)
|
||||
{
|
||||
return replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
}
|
||||
|
||||
// Even if we're not going to use the query, we need to parse it
|
||||
// so we can check the address type that's being queried
|
||||
|
||||
query = start = buffer + DNS_HEADER_SIZE;
|
||||
remaining = length - DNS_HEADER_SIZE;
|
||||
while (remaining != 0 && *start != 0)
|
||||
{
|
||||
labelLength = *start;
|
||||
if (labelLength + 1 > remaining)
|
||||
{
|
||||
return replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
}
|
||||
remaining -= (labelLength + 1);
|
||||
start += (labelLength + 1);
|
||||
}
|
||||
|
||||
// 1 octet labelLength, 2 octet qtype, 2 octet qclass
|
||||
if (remaining < 5)
|
||||
{
|
||||
return replyWithError(dnsHeader, DNSReplyCode::FormError);
|
||||
}
|
||||
|
||||
start += 1; // Skip the 0 length label that we found above
|
||||
|
||||
memcpy(&qtype, start, sizeof(qtype));
|
||||
start += 2;
|
||||
memcpy(&qclass, start, sizeof(qclass));
|
||||
start += 2;
|
||||
|
||||
queryLength = start - query;
|
||||
|
||||
if (qclass != lwip_htons(DNS_QCLASS_ANY)
|
||||
&& qclass != lwip_htons(DNS_QCLASS_IN))
|
||||
return replyWithError(dnsHeader, DNSReplyCode::NonExistentDomain,
|
||||
query, queryLength);
|
||||
|
||||
if (qtype != lwip_htons(DNS_QTYPE_A)
|
||||
&& qtype != lwip_htons(DNS_QTYPE_ANY))
|
||||
return replyWithError(dnsHeader, DNSReplyCode::NonExistentDomain,
|
||||
query, queryLength);
|
||||
|
||||
// If we have no domain name configured, just return an error
|
||||
if (_domainName == "")
|
||||
return replyWithError(dnsHeader, _errorReplyCode,
|
||||
query, queryLength);
|
||||
|
||||
// If we're running with a wildcard we can just return a result now
|
||||
if (_domainName == "*")
|
||||
{
|
||||
return replyWithIP(dnsHeader, query, queryLength);
|
||||
}
|
||||
|
||||
matchString = _domainName.c_str();
|
||||
|
||||
start = query;
|
||||
|
||||
// If there's a leading 'www', skip it
|
||||
if (*start == 3 && strncasecmp("www", (char *) start + 1, 3) == 0)
|
||||
{
|
||||
start += 4;
|
||||
}
|
||||
|
||||
while (*start != 0)
|
||||
{
|
||||
labelLength = *start;
|
||||
start += 1;
|
||||
while (labelLength > 0)
|
||||
{
|
||||
if (tolower(*start) != *matchString)
|
||||
return replyWithError(dnsHeader, _errorReplyCode,
|
||||
query, queryLength);
|
||||
++start;
|
||||
++matchString;
|
||||
--labelLength;
|
||||
}
|
||||
if (*start == 0 && *matchString == '\0')
|
||||
{
|
||||
return replyWithIP(dnsHeader, query, queryLength);
|
||||
}
|
||||
|
||||
if (*matchString != '.')
|
||||
return replyWithError(dnsHeader, _errorReplyCode,
|
||||
query, queryLength);
|
||||
++matchString;
|
||||
}
|
||||
|
||||
return replyWithError(dnsHeader, _errorReplyCode,
|
||||
query, queryLength);
|
||||
}
|
||||
|
||||
void DNSServer::processNextRequest()
|
||||
{
|
||||
size_t currentPacketSize;
|
||||
size_t currentPacketSize;
|
||||
|
||||
currentPacketSize = _udp.parsePacket();
|
||||
if (currentPacketSize == 0)
|
||||
return;
|
||||
currentPacketSize = _udp.parsePacket();
|
||||
if (currentPacketSize == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// The DNS RFC requires that DNS packets be less than 512 bytes in size,
|
||||
// so just discard them if they are larger
|
||||
if (currentPacketSize > MAX_DNS_PACKETSIZE)
|
||||
return;
|
||||
// The DNS RFC requires that DNS packets be less than 512 bytes in size,
|
||||
// so just discard them if they are larger
|
||||
if (currentPacketSize > MAX_DNS_PACKETSIZE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If the packet size is smaller than the DNS header, then someone is
|
||||
// messing with us
|
||||
if (currentPacketSize < DNS_HEADER_SIZE)
|
||||
return;
|
||||
// If the packet size is smaller than the DNS header, then someone is
|
||||
// messing with us
|
||||
if (currentPacketSize < DNS_HEADER_SIZE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<uint8_t[]> buffer(new (std::nothrow) uint8_t[currentPacketSize]);
|
||||
std::unique_ptr<uint8_t[]> buffer(new (std::nothrow) uint8_t[currentPacketSize]);
|
||||
|
||||
if (buffer == NULL)
|
||||
return;
|
||||
if (buffer == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_udp.read(buffer.get(), currentPacketSize);
|
||||
respondToRequest(buffer.get(), currentPacketSize);
|
||||
_udp.read(buffer.get(), currentPacketSize);
|
||||
respondToRequest(buffer.get(), currentPacketSize);
|
||||
}
|
||||
|
||||
void DNSServer::writeNBOShort(uint16_t value)
|
||||
{
|
||||
_udp.write((unsigned char *)&value, 2);
|
||||
_udp.write((unsigned char *)&value, 2);
|
||||
}
|
||||
|
||||
void DNSServer::replyWithIP(DNSHeader *dnsHeader,
|
||||
unsigned char * query,
|
||||
size_t queryLength)
|
||||
unsigned char * query,
|
||||
size_t queryLength)
|
||||
{
|
||||
uint16_t value;
|
||||
uint16_t value;
|
||||
|
||||
dnsHeader->QR = DNS_QR_RESPONSE;
|
||||
dnsHeader->QDCount = lwip_htons(1);
|
||||
dnsHeader->ANCount = lwip_htons(1);
|
||||
dnsHeader->NSCount = 0;
|
||||
dnsHeader->ARCount = 0;
|
||||
dnsHeader->QR = DNS_QR_RESPONSE;
|
||||
dnsHeader->QDCount = lwip_htons(1);
|
||||
dnsHeader->ANCount = lwip_htons(1);
|
||||
dnsHeader->NSCount = 0;
|
||||
dnsHeader->ARCount = 0;
|
||||
|
||||
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
|
||||
_udp.write((unsigned char *) dnsHeader, sizeof(DNSHeader));
|
||||
_udp.write(query, queryLength);
|
||||
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
|
||||
_udp.write((unsigned char *) dnsHeader, sizeof(DNSHeader));
|
||||
_udp.write(query, queryLength);
|
||||
|
||||
// Rather than restate the name here, we use a pointer to the name contained
|
||||
// in the query section. Pointers have the top two bits set.
|
||||
value = 0xC000 | DNS_HEADER_SIZE;
|
||||
writeNBOShort(lwip_htons(value));
|
||||
// Rather than restate the name here, we use a pointer to the name contained
|
||||
// in the query section. Pointers have the top two bits set.
|
||||
value = 0xC000 | DNS_HEADER_SIZE;
|
||||
writeNBOShort(lwip_htons(value));
|
||||
|
||||
// Answer is type A (an IPv4 address)
|
||||
writeNBOShort(lwip_htons(DNS_QTYPE_A));
|
||||
// Answer is type A (an IPv4 address)
|
||||
writeNBOShort(lwip_htons(DNS_QTYPE_A));
|
||||
|
||||
// Answer is in the Internet Class
|
||||
writeNBOShort(lwip_htons(DNS_QCLASS_IN));
|
||||
// Answer is in the Internet Class
|
||||
writeNBOShort(lwip_htons(DNS_QCLASS_IN));
|
||||
|
||||
// Output TTL (already NBO)
|
||||
_udp.write((unsigned char*)&_ttl, 4);
|
||||
// Output TTL (already NBO)
|
||||
_udp.write((unsigned char*)&_ttl, 4);
|
||||
|
||||
// Length of RData is 4 bytes (because, in this case, RData is IPv4)
|
||||
writeNBOShort(lwip_htons(sizeof(_resolvedIP)));
|
||||
_udp.write(_resolvedIP, sizeof(_resolvedIP));
|
||||
_udp.endPacket();
|
||||
// Length of RData is 4 bytes (because, in this case, RData is IPv4)
|
||||
writeNBOShort(lwip_htons(sizeof(_resolvedIP)));
|
||||
_udp.write(_resolvedIP, sizeof(_resolvedIP));
|
||||
_udp.endPacket();
|
||||
}
|
||||
|
||||
void DNSServer::replyWithError(DNSHeader *dnsHeader,
|
||||
DNSReplyCode rcode,
|
||||
unsigned char *query,
|
||||
size_t queryLength)
|
||||
DNSReplyCode rcode,
|
||||
unsigned char *query,
|
||||
size_t queryLength)
|
||||
{
|
||||
dnsHeader->QR = DNS_QR_RESPONSE;
|
||||
dnsHeader->RCode = (unsigned char) rcode;
|
||||
if (query)
|
||||
dnsHeader->QDCount = lwip_htons(1);
|
||||
else
|
||||
dnsHeader->QDCount = 0;
|
||||
dnsHeader->ANCount = 0;
|
||||
dnsHeader->NSCount = 0;
|
||||
dnsHeader->ARCount = 0;
|
||||
dnsHeader->QR = DNS_QR_RESPONSE;
|
||||
dnsHeader->RCode = (unsigned char) rcode;
|
||||
if (query)
|
||||
{
|
||||
dnsHeader->QDCount = lwip_htons(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
dnsHeader->QDCount = 0;
|
||||
}
|
||||
dnsHeader->ANCount = 0;
|
||||
dnsHeader->NSCount = 0;
|
||||
dnsHeader->ARCount = 0;
|
||||
|
||||
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
|
||||
_udp.write((unsigned char *)dnsHeader, sizeof(DNSHeader));
|
||||
if (query != NULL)
|
||||
_udp.write(query, queryLength);
|
||||
_udp.endPacket();
|
||||
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
|
||||
_udp.write((unsigned char *)dnsHeader, sizeof(DNSHeader));
|
||||
if (query != NULL)
|
||||
{
|
||||
_udp.write(query, queryLength);
|
||||
}
|
||||
_udp.endPacket();
|
||||
}
|
||||
|
||||
void DNSServer::replyWithError(DNSHeader *dnsHeader,
|
||||
DNSReplyCode rcode)
|
||||
DNSReplyCode rcode)
|
||||
{
|
||||
replyWithError(dnsHeader, rcode, NULL, 0);
|
||||
replyWithError(dnsHeader, rcode, NULL, 0);
|
||||
}
|
||||
|
@ -17,39 +17,40 @@
|
||||
|
||||
enum class DNSReplyCode
|
||||
{
|
||||
NoError = 0,
|
||||
FormError = 1,
|
||||
ServerFailure = 2,
|
||||
NonExistentDomain = 3,
|
||||
NotImplemented = 4,
|
||||
Refused = 5,
|
||||
YXDomain = 6,
|
||||
YXRRSet = 7,
|
||||
NXRRSet = 8
|
||||
NoError = 0,
|
||||
FormError = 1,
|
||||
ServerFailure = 2,
|
||||
NonExistentDomain = 3,
|
||||
NotImplemented = 4,
|
||||
Refused = 5,
|
||||
YXDomain = 6,
|
||||
YXRRSet = 7,
|
||||
NXRRSet = 8
|
||||
};
|
||||
|
||||
struct DNSHeader
|
||||
{
|
||||
uint16_t ID; // identification number
|
||||
unsigned char RD : 1; // recursion desired
|
||||
unsigned char TC : 1; // truncated message
|
||||
unsigned char AA : 1; // authoritive answer
|
||||
unsigned char OPCode : 4; // message_type
|
||||
unsigned char QR : 1; // query/response flag
|
||||
unsigned char RCode : 4; // response code
|
||||
unsigned char Z : 3; // its z! reserved
|
||||
unsigned char RA : 1; // recursion available
|
||||
uint16_t QDCount; // number of question entries
|
||||
uint16_t ANCount; // number of answer entries
|
||||
uint16_t NSCount; // number of authority entries
|
||||
uint16_t ARCount; // number of resource entries
|
||||
uint16_t ID; // identification number
|
||||
unsigned char RD : 1; // recursion desired
|
||||
unsigned char TC : 1; // truncated message
|
||||
unsigned char AA : 1; // authoritive answer
|
||||
unsigned char OPCode : 4; // message_type
|
||||
unsigned char QR : 1; // query/response flag
|
||||
unsigned char RCode : 4; // response code
|
||||
unsigned char Z : 3; // its z! reserved
|
||||
unsigned char RA : 1; // recursion available
|
||||
uint16_t QDCount; // number of question entries
|
||||
uint16_t ANCount; // number of answer entries
|
||||
uint16_t NSCount; // number of authority entries
|
||||
uint16_t ARCount; // number of resource entries
|
||||
};
|
||||
|
||||
class DNSServer
|
||||
{
|
||||
public:
|
||||
public:
|
||||
DNSServer();
|
||||
~DNSServer() {
|
||||
~DNSServer()
|
||||
{
|
||||
stop();
|
||||
};
|
||||
void processNextRequest();
|
||||
@ -58,12 +59,12 @@ class DNSServer
|
||||
|
||||
// Returns true if successful, false if there are no sockets available
|
||||
bool start(const uint16_t &port,
|
||||
const String &domainName,
|
||||
const IPAddress &resolvedIP);
|
||||
const String &domainName,
|
||||
const IPAddress &resolvedIP);
|
||||
// stops the DNS server
|
||||
void stop();
|
||||
|
||||
private:
|
||||
private:
|
||||
WiFiUDP _udp;
|
||||
uint16_t _port;
|
||||
String _domainName;
|
||||
@ -73,14 +74,14 @@ class DNSServer
|
||||
|
||||
void downcaseAndRemoveWwwPrefix(String &domainName);
|
||||
void replyWithIP(DNSHeader *dnsHeader,
|
||||
unsigned char * query,
|
||||
size_t queryLength);
|
||||
unsigned char * query,
|
||||
size_t queryLength);
|
||||
void replyWithError(DNSHeader *dnsHeader,
|
||||
DNSReplyCode rcode,
|
||||
unsigned char *query,
|
||||
size_t queryLength);
|
||||
DNSReplyCode rcode,
|
||||
unsigned char *query,
|
||||
size_t queryLength);
|
||||
void replyWithError(DNSHeader *dnsHeader,
|
||||
DNSReplyCode rcode);
|
||||
DNSReplyCode rcode);
|
||||
void respondToRequest(uint8_t *buffer, size_t length);
|
||||
void writeNBOShort(uint16_t value);
|
||||
};
|
||||
|
@ -1,22 +1,22 @@
|
||||
/*
|
||||
EEPROM.cpp - esp8266 EEPROM emulation
|
||||
EEPROM.cpp - esp8266 EEPROM emulation
|
||||
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This library is 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.
|
||||
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
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "Arduino.h"
|
||||
@ -33,112 +33,145 @@ extern "C" {
|
||||
extern "C" uint32_t _SPIFFS_end;
|
||||
|
||||
EEPROMClass::EEPROMClass(uint32_t sector)
|
||||
: _sector(sector)
|
||||
, _data(0)
|
||||
, _size(0)
|
||||
, _dirty(false)
|
||||
: _sector(sector)
|
||||
, _data(0)
|
||||
, _size(0)
|
||||
, _dirty(false)
|
||||
{
|
||||
}
|
||||
|
||||
EEPROMClass::EEPROMClass(void)
|
||||
: _sector((((uint32_t)&_SPIFFS_end - 0x40200000) / SPI_FLASH_SEC_SIZE))
|
||||
, _data(0)
|
||||
, _size(0)
|
||||
, _dirty(false)
|
||||
: _sector((((uint32_t) & _SPIFFS_end - 0x40200000) / SPI_FLASH_SEC_SIZE))
|
||||
, _data(0)
|
||||
, _size(0)
|
||||
, _dirty(false)
|
||||
{
|
||||
}
|
||||
|
||||
void EEPROMClass::begin(size_t size) {
|
||||
if (size <= 0)
|
||||
return;
|
||||
if (size > SPI_FLASH_SEC_SIZE)
|
||||
size = SPI_FLASH_SEC_SIZE;
|
||||
|
||||
size = (size + 3) & (~3);
|
||||
|
||||
//In case begin() is called a 2nd+ time, don't reallocate if size is the same
|
||||
if(_data && size != _size) {
|
||||
delete[] _data;
|
||||
_data = new uint8_t[size];
|
||||
} else if(!_data) {
|
||||
_data = new uint8_t[size];
|
||||
}
|
||||
|
||||
_size = size;
|
||||
|
||||
noInterrupts();
|
||||
spi_flash_read(_sector * SPI_FLASH_SEC_SIZE, reinterpret_cast<uint32_t*>(_data), _size);
|
||||
interrupts();
|
||||
|
||||
_dirty = false; //make sure dirty is cleared in case begin() is called 2nd+ time
|
||||
}
|
||||
|
||||
void EEPROMClass::end() {
|
||||
if (!_size)
|
||||
return;
|
||||
|
||||
commit();
|
||||
if(_data) {
|
||||
delete[] _data;
|
||||
}
|
||||
_data = 0;
|
||||
_size = 0;
|
||||
_dirty = false;
|
||||
}
|
||||
|
||||
|
||||
uint8_t EEPROMClass::read(int const address) {
|
||||
if (address < 0 || (size_t)address >= _size)
|
||||
return 0;
|
||||
if(!_data)
|
||||
return 0;
|
||||
|
||||
return _data[address];
|
||||
}
|
||||
|
||||
void EEPROMClass::write(int const address, uint8_t const value) {
|
||||
if (address < 0 || (size_t)address >= _size)
|
||||
return;
|
||||
if(!_data)
|
||||
return;
|
||||
|
||||
// Optimise _dirty. Only flagged if data written is different.
|
||||
uint8_t* pData = &_data[address];
|
||||
if (*pData != value)
|
||||
{
|
||||
*pData = value;
|
||||
_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool EEPROMClass::commit() {
|
||||
bool ret = false;
|
||||
if (!_size)
|
||||
return false;
|
||||
if(!_dirty)
|
||||
return true;
|
||||
if(!_data)
|
||||
return false;
|
||||
|
||||
noInterrupts();
|
||||
if(spi_flash_erase_sector(_sector) == SPI_FLASH_RESULT_OK) {
|
||||
if(spi_flash_write(_sector * SPI_FLASH_SEC_SIZE, reinterpret_cast<uint32_t*>(_data), _size) == SPI_FLASH_RESULT_OK) {
|
||||
_dirty = false;
|
||||
ret = true;
|
||||
void EEPROMClass::begin(size_t size)
|
||||
{
|
||||
if (size <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (size > SPI_FLASH_SEC_SIZE)
|
||||
{
|
||||
size = SPI_FLASH_SEC_SIZE;
|
||||
}
|
||||
}
|
||||
interrupts();
|
||||
|
||||
return ret;
|
||||
size = (size + 3) & (~3);
|
||||
|
||||
//In case begin() is called a 2nd+ time, don't reallocate if size is the same
|
||||
if (_data && size != _size)
|
||||
{
|
||||
delete[] _data;
|
||||
_data = new uint8_t[size];
|
||||
}
|
||||
else if (!_data)
|
||||
{
|
||||
_data = new uint8_t[size];
|
||||
}
|
||||
|
||||
_size = size;
|
||||
|
||||
noInterrupts();
|
||||
spi_flash_read(_sector * SPI_FLASH_SEC_SIZE, reinterpret_cast<uint32_t*>(_data), _size);
|
||||
interrupts();
|
||||
|
||||
_dirty = false; //make sure dirty is cleared in case begin() is called 2nd+ time
|
||||
}
|
||||
|
||||
uint8_t * EEPROMClass::getDataPtr() {
|
||||
_dirty = true;
|
||||
return &_data[0];
|
||||
void EEPROMClass::end()
|
||||
{
|
||||
if (!_size)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
commit();
|
||||
if (_data)
|
||||
{
|
||||
delete[] _data;
|
||||
}
|
||||
_data = 0;
|
||||
_size = 0;
|
||||
_dirty = false;
|
||||
}
|
||||
|
||||
uint8_t const * EEPROMClass::getConstDataPtr() const {
|
||||
return &_data[0];
|
||||
|
||||
uint8_t EEPROMClass::read(int const address)
|
||||
{
|
||||
if (address < 0 || (size_t)address >= _size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (!_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _data[address];
|
||||
}
|
||||
|
||||
void EEPROMClass::write(int const address, uint8_t const value)
|
||||
{
|
||||
if (address < 0 || (size_t)address >= _size)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!_data)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Optimise _dirty. Only flagged if data written is different.
|
||||
uint8_t* pData = &_data[address];
|
||||
if (*pData != value)
|
||||
{
|
||||
*pData = value;
|
||||
_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool EEPROMClass::commit()
|
||||
{
|
||||
bool ret = false;
|
||||
if (!_size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!_dirty)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (!_data)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
noInterrupts();
|
||||
if (spi_flash_erase_sector(_sector) == SPI_FLASH_RESULT_OK)
|
||||
{
|
||||
if (spi_flash_write(_sector * SPI_FLASH_SEC_SIZE, reinterpret_cast<uint32_t*>(_data), _size) == SPI_FLASH_RESULT_OK)
|
||||
{
|
||||
_dirty = false;
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
interrupts();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t * EEPROMClass::getDataPtr()
|
||||
{
|
||||
_dirty = true;
|
||||
return &_data[0];
|
||||
}
|
||||
|
||||
uint8_t const * EEPROMClass::getConstDataPtr() const
|
||||
{
|
||||
return &_data[0];
|
||||
}
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_EEPROM)
|
||||
|
@ -1,22 +1,22 @@
|
||||
/*
|
||||
EEPROM.cpp - esp8266 EEPROM emulation
|
||||
/*
|
||||
EEPROM.cpp - esp8266 EEPROM emulation
|
||||
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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
|
||||
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 EEPROM_h
|
||||
@ -26,51 +26,68 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
class EEPROMClass {
|
||||
class EEPROMClass
|
||||
{
|
||||
public:
|
||||
EEPROMClass(uint32_t sector);
|
||||
EEPROMClass(void);
|
||||
EEPROMClass(uint32_t sector);
|
||||
EEPROMClass(void);
|
||||
|
||||
void begin(size_t size);
|
||||
uint8_t read(int const address);
|
||||
void write(int const address, uint8_t const val);
|
||||
bool commit();
|
||||
void end();
|
||||
void begin(size_t size);
|
||||
uint8_t read(int const address);
|
||||
void write(int const address, uint8_t const val);
|
||||
bool commit();
|
||||
void end();
|
||||
|
||||
uint8_t * getDataPtr();
|
||||
uint8_t const * getConstDataPtr() const;
|
||||
uint8_t * getDataPtr();
|
||||
uint8_t const * getConstDataPtr() const;
|
||||
|
||||
template<typename T>
|
||||
T &get(int const address, T &t) {
|
||||
if (address < 0 || address + sizeof(T) > _size)
|
||||
return t;
|
||||
template<typename T>
|
||||
T &get(int const address, T &t)
|
||||
{
|
||||
if (address < 0 || address + sizeof(T) > _size)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
memcpy((uint8_t*) &t, _data + address, sizeof(T));
|
||||
return t;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T &put(int const address, const T &t) {
|
||||
if (address < 0 || address + sizeof(T) > _size)
|
||||
return t;
|
||||
if (memcmp(_data + address, (const uint8_t*)&t, sizeof(T)) != 0) {
|
||||
_dirty = true;
|
||||
memcpy(_data + address, (const uint8_t*)&t, sizeof(T));
|
||||
memcpy((uint8_t*) &t, _data + address, sizeof(T));
|
||||
return t;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
template<typename T>
|
||||
const T &put(int const address, const T &t)
|
||||
{
|
||||
if (address < 0 || address + sizeof(T) > _size)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
if (memcmp(_data + address, (const uint8_t*)&t, sizeof(T)) != 0)
|
||||
{
|
||||
_dirty = true;
|
||||
memcpy(_data + address, (const uint8_t*)&t, sizeof(T));
|
||||
}
|
||||
|
||||
size_t length() {return _size;}
|
||||
return t;
|
||||
}
|
||||
|
||||
uint8_t& operator[](int const address) {return getDataPtr()[address];}
|
||||
uint8_t const & operator[](int const address) const {return getConstDataPtr()[address];}
|
||||
size_t length()
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
|
||||
uint8_t& operator[](int const address)
|
||||
{
|
||||
return getDataPtr()[address];
|
||||
}
|
||||
uint8_t const & operator[](int const address) const
|
||||
{
|
||||
return getConstDataPtr()[address];
|
||||
}
|
||||
|
||||
protected:
|
||||
uint32_t _sector;
|
||||
uint8_t* _data;
|
||||
size_t _size;
|
||||
bool _dirty;
|
||||
uint32_t _sector;
|
||||
uint8_t* _data;
|
||||
size_t _size;
|
||||
bool _dirty;
|
||||
};
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_EEPROM)
|
||||
|
@ -1,8 +1,8 @@
|
||||
/*
|
||||
AVR In-System Programming over WiFi for ESP8266
|
||||
Copyright (c) Kiril Zyapkov <kiril@robotev.com>
|
||||
AVR In-System Programming over WiFi for ESP8266
|
||||
Copyright (c) Kiril Zyapkov <kiril@robotev.com>
|
||||
|
||||
Original version:
|
||||
Original version:
|
||||
ArduinoISP version 04m3
|
||||
Copyright (c) 2008-2011 Randall Bohn
|
||||
If you require a license, see
|
||||
@ -19,16 +19,16 @@ Original version:
|
||||
#include "command.h"
|
||||
|
||||
extern "C" {
|
||||
#include "user_interface.h"
|
||||
#include "mem.h"
|
||||
#include "user_interface.h"
|
||||
#include "mem.h"
|
||||
}
|
||||
|
||||
#ifdef malloc
|
||||
#undef malloc
|
||||
#undef malloc
|
||||
#endif
|
||||
#define malloc os_malloc
|
||||
#ifdef free
|
||||
#undef free
|
||||
#undef free
|
||||
#endif
|
||||
#define free os_free
|
||||
|
||||
@ -52,126 +52,165 @@ ESP8266AVRISP::ESP8266AVRISP(uint16_t port, uint8_t reset_pin, uint32_t spi_freq
|
||||
setReset(_reset_state);
|
||||
}
|
||||
|
||||
void ESP8266AVRISP::begin() {
|
||||
void ESP8266AVRISP::begin()
|
||||
{
|
||||
_server.begin();
|
||||
}
|
||||
|
||||
void ESP8266AVRISP::setSpiFrequency(uint32_t freq) {
|
||||
void ESP8266AVRISP::setSpiFrequency(uint32_t freq)
|
||||
{
|
||||
_spi_freq = freq;
|
||||
if (_state == AVRISP_STATE_ACTIVE) {
|
||||
if (_state == AVRISP_STATE_ACTIVE)
|
||||
{
|
||||
SPI.setFrequency(freq);
|
||||
}
|
||||
}
|
||||
|
||||
void ESP8266AVRISP::setReset(bool rst) {
|
||||
void ESP8266AVRISP::setReset(bool rst)
|
||||
{
|
||||
_reset_state = rst;
|
||||
digitalWrite(_reset_pin, _resetLevel(_reset_state));
|
||||
}
|
||||
|
||||
AVRISPState_t ESP8266AVRISP::update() {
|
||||
switch (_state) {
|
||||
case AVRISP_STATE_IDLE: {
|
||||
if (_server.hasClient()) {
|
||||
_client = _server.available();
|
||||
_client.setNoDelay(true);
|
||||
AVRISP_DEBUG("client connect %s:%d", _client.remoteIP().toString().c_str(), _client.remotePort());
|
||||
_client.setTimeout(100); // for getch()
|
||||
_state = AVRISP_STATE_PENDING;
|
||||
_reject_incoming();
|
||||
}
|
||||
break;
|
||||
AVRISPState_t ESP8266AVRISP::update()
|
||||
{
|
||||
switch (_state)
|
||||
{
|
||||
case AVRISP_STATE_IDLE:
|
||||
{
|
||||
if (_server.hasClient())
|
||||
{
|
||||
_client = _server.available();
|
||||
_client.setNoDelay(true);
|
||||
AVRISP_DEBUG("client connect %s:%d", _client.remoteIP().toString().c_str(), _client.remotePort());
|
||||
_client.setTimeout(100); // for getch()
|
||||
_state = AVRISP_STATE_PENDING;
|
||||
_reject_incoming();
|
||||
}
|
||||
case AVRISP_STATE_PENDING:
|
||||
case AVRISP_STATE_ACTIVE: {
|
||||
// handle disconnect
|
||||
if (!_client.connected()) {
|
||||
_client.stop();
|
||||
AVRISP_DEBUG("client disconnect");
|
||||
if (pmode) {
|
||||
SPI.end();
|
||||
pmode = 0;
|
||||
}
|
||||
setReset(_reset_state);
|
||||
_state = AVRISP_STATE_IDLE;
|
||||
} else {
|
||||
_reject_incoming();
|
||||
break;
|
||||
}
|
||||
case AVRISP_STATE_PENDING:
|
||||
case AVRISP_STATE_ACTIVE:
|
||||
{
|
||||
// handle disconnect
|
||||
if (!_client.connected())
|
||||
{
|
||||
_client.stop();
|
||||
AVRISP_DEBUG("client disconnect");
|
||||
if (pmode)
|
||||
{
|
||||
SPI.end();
|
||||
pmode = 0;
|
||||
}
|
||||
break;
|
||||
setReset(_reset_state);
|
||||
_state = AVRISP_STATE_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
_reject_incoming();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return _state;
|
||||
}
|
||||
|
||||
AVRISPState_t ESP8266AVRISP::serve() {
|
||||
switch (update()) {
|
||||
case AVRISP_STATE_IDLE:
|
||||
// should not be called when idle, error?
|
||||
break;
|
||||
case AVRISP_STATE_PENDING: {
|
||||
_state = AVRISP_STATE_ACTIVE;
|
||||
AVRISPState_t ESP8266AVRISP::serve()
|
||||
{
|
||||
switch (update())
|
||||
{
|
||||
case AVRISP_STATE_IDLE:
|
||||
// should not be called when idle, error?
|
||||
break;
|
||||
case AVRISP_STATE_PENDING:
|
||||
{
|
||||
_state = AVRISP_STATE_ACTIVE;
|
||||
// fallthrough
|
||||
}
|
||||
case AVRISP_STATE_ACTIVE:
|
||||
{
|
||||
while (_client.available())
|
||||
{
|
||||
avrisp();
|
||||
}
|
||||
case AVRISP_STATE_ACTIVE: {
|
||||
while (_client.available()) {
|
||||
avrisp();
|
||||
}
|
||||
return update();
|
||||
}
|
||||
return update();
|
||||
}
|
||||
}
|
||||
return _state;
|
||||
}
|
||||
|
||||
inline void ESP8266AVRISP::_reject_incoming(void) {
|
||||
while (_server.hasClient()) _server.available().stop();
|
||||
inline void ESP8266AVRISP::_reject_incoming(void)
|
||||
{
|
||||
while (_server.hasClient())
|
||||
{
|
||||
_server.available().stop();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ESP8266AVRISP::getch() {
|
||||
while (!_client.available()) yield();
|
||||
uint8_t ESP8266AVRISP::getch()
|
||||
{
|
||||
while (!_client.available())
|
||||
{
|
||||
yield();
|
||||
}
|
||||
uint8_t b = (uint8_t)_client.read();
|
||||
// AVRISP_DEBUG("< %02x", b);
|
||||
return b;
|
||||
}
|
||||
|
||||
void ESP8266AVRISP::fill(int n) {
|
||||
void ESP8266AVRISP::fill(int n)
|
||||
{
|
||||
// AVRISP_DEBUG("fill(%u)", n);
|
||||
for (int x = 0; x < n; x++) {
|
||||
for (int x = 0; x < n; x++)
|
||||
{
|
||||
buff[x] = getch();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ESP8266AVRISP::spi_transaction(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
|
||||
uint8_t ESP8266AVRISP::spi_transaction(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
|
||||
{
|
||||
SPI.transfer(a);
|
||||
SPI.transfer(b);
|
||||
SPI.transfer(c);
|
||||
return SPI.transfer(d);
|
||||
}
|
||||
|
||||
void ESP8266AVRISP::empty_reply() {
|
||||
if (Sync_CRC_EOP == getch()) {
|
||||
void ESP8266AVRISP::empty_reply()
|
||||
{
|
||||
if (Sync_CRC_EOP == getch())
|
||||
{
|
||||
_client.print((char)Resp_STK_INSYNC);
|
||||
_client.print((char)Resp_STK_OK);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
error++;
|
||||
_client.print((char)Resp_STK_NOSYNC);
|
||||
}
|
||||
}
|
||||
|
||||
void ESP8266AVRISP::breply(uint8_t b) {
|
||||
if (Sync_CRC_EOP == getch()) {
|
||||
void ESP8266AVRISP::breply(uint8_t b)
|
||||
{
|
||||
if (Sync_CRC_EOP == getch())
|
||||
{
|
||||
uint8_t resp[3];
|
||||
resp[0] = Resp_STK_INSYNC;
|
||||
resp[1] = b;
|
||||
resp[2] = Resp_STK_OK;
|
||||
_client.write((const uint8_t *)resp, (size_t)3);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
error++;
|
||||
_client.print((char)Resp_STK_NOSYNC);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ESP8266AVRISP::get_parameter(uint8_t c) {
|
||||
switch (c) {
|
||||
void ESP8266AVRISP::get_parameter(uint8_t c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 0x80:
|
||||
breply(AVRISP_HWVER);
|
||||
break;
|
||||
@ -189,7 +228,8 @@ void ESP8266AVRISP::get_parameter(uint8_t c) {
|
||||
}
|
||||
}
|
||||
|
||||
void ESP8266AVRISP::set_parameters() {
|
||||
void ESP8266AVRISP::set_parameters()
|
||||
{
|
||||
// call this after reading paramter packet into buff[]
|
||||
param.devicecode = buff[0];
|
||||
param.revision = buff[1];
|
||||
@ -208,12 +248,13 @@ void ESP8266AVRISP::set_parameters() {
|
||||
|
||||
// 32 bits flashsize (big endian)
|
||||
param.flashsize = buff[16] * 0x01000000
|
||||
+ buff[17] * 0x00010000
|
||||
+ buff[18] * 0x00000100
|
||||
+ buff[19];
|
||||
+ buff[17] * 0x00010000
|
||||
+ buff[18] * 0x00000100
|
||||
+ buff[19];
|
||||
}
|
||||
|
||||
void ESP8266AVRISP::start_pmode() {
|
||||
void ESP8266AVRISP::start_pmode()
|
||||
{
|
||||
SPI.begin();
|
||||
SPI.setFrequency(_spi_freq);
|
||||
SPI.setHwCs(false);
|
||||
@ -229,13 +270,15 @@ void ESP8266AVRISP::start_pmode() {
|
||||
pmode = 1;
|
||||
}
|
||||
|
||||
void ESP8266AVRISP::end_pmode() {
|
||||
void ESP8266AVRISP::end_pmode()
|
||||
{
|
||||
SPI.end();
|
||||
setReset(_reset_state);
|
||||
pmode = 0;
|
||||
}
|
||||
|
||||
void ESP8266AVRISP::universal() {
|
||||
void ESP8266AVRISP::universal()
|
||||
{
|
||||
uint8_t ch;
|
||||
|
||||
fill(4);
|
||||
@ -243,47 +286,69 @@ void ESP8266AVRISP::universal() {
|
||||
breply(ch);
|
||||
}
|
||||
|
||||
void ESP8266AVRISP::flash(uint8_t hilo, int addr, uint8_t data) {
|
||||
void ESP8266AVRISP::flash(uint8_t hilo, int addr, uint8_t data)
|
||||
{
|
||||
spi_transaction(0x40 + 8 * hilo,
|
||||
addr >> 8 & 0xFF,
|
||||
addr & 0xFF,
|
||||
data);
|
||||
}
|
||||
|
||||
void ESP8266AVRISP::commit(int addr) {
|
||||
void ESP8266AVRISP::commit(int addr)
|
||||
{
|
||||
spi_transaction(0x4C, (addr >> 8) & 0xFF, addr & 0xFF, 0);
|
||||
delay(AVRISP_PTIME);
|
||||
}
|
||||
|
||||
//#define _addr_page(x) (here & 0xFFFFE0)
|
||||
int ESP8266AVRISP::addr_page(int addr) {
|
||||
if (param.pagesize == 32) return addr & 0xFFFFFFF0;
|
||||
if (param.pagesize == 64) return addr & 0xFFFFFFE0;
|
||||
if (param.pagesize == 128) return addr & 0xFFFFFFC0;
|
||||
if (param.pagesize == 256) return addr & 0xFFFFFF80;
|
||||
int ESP8266AVRISP::addr_page(int addr)
|
||||
{
|
||||
if (param.pagesize == 32)
|
||||
{
|
||||
return addr & 0xFFFFFFF0;
|
||||
}
|
||||
if (param.pagesize == 64)
|
||||
{
|
||||
return addr & 0xFFFFFFE0;
|
||||
}
|
||||
if (param.pagesize == 128)
|
||||
{
|
||||
return addr & 0xFFFFFFC0;
|
||||
}
|
||||
if (param.pagesize == 256)
|
||||
{
|
||||
return addr & 0xFFFFFF80;
|
||||
}
|
||||
AVRISP_DEBUG("unknown page size: %d", param.pagesize);
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
void ESP8266AVRISP::write_flash(int length) {
|
||||
void ESP8266AVRISP::write_flash(int length)
|
||||
{
|
||||
fill(length);
|
||||
|
||||
if (Sync_CRC_EOP == getch()) {
|
||||
if (Sync_CRC_EOP == getch())
|
||||
{
|
||||
_client.print((char) Resp_STK_INSYNC);
|
||||
_client.print((char) write_flash_pages(length));
|
||||
} else {
|
||||
error++;
|
||||
_client.print((char) Resp_STK_NOSYNC);
|
||||
}
|
||||
else
|
||||
{
|
||||
error++;
|
||||
_client.print((char) Resp_STK_NOSYNC);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ESP8266AVRISP::write_flash_pages(int length) {
|
||||
uint8_t ESP8266AVRISP::write_flash_pages(int length)
|
||||
{
|
||||
int x = 0;
|
||||
int page = addr_page(here);
|
||||
while (x < length) {
|
||||
while (x < length)
|
||||
{
|
||||
yield();
|
||||
if (page != addr_page(here)) {
|
||||
if (page != addr_page(here))
|
||||
{
|
||||
commit(page);
|
||||
page = addr_page(here);
|
||||
}
|
||||
@ -295,15 +360,18 @@ uint8_t ESP8266AVRISP::write_flash_pages(int length) {
|
||||
return Resp_STK_OK;
|
||||
}
|
||||
|
||||
uint8_t ESP8266AVRISP::write_eeprom(int length) {
|
||||
uint8_t ESP8266AVRISP::write_eeprom(int length)
|
||||
{
|
||||
// here is a word address, get the byte address
|
||||
int start = here * 2;
|
||||
int remaining = length;
|
||||
if (length > param.eepromsize) {
|
||||
if (length > param.eepromsize)
|
||||
{
|
||||
error++;
|
||||
return Resp_STK_FAILED;
|
||||
}
|
||||
while (remaining > EECHUNK) {
|
||||
while (remaining > EECHUNK)
|
||||
{
|
||||
write_eeprom_chunk(start, EECHUNK);
|
||||
start += EECHUNK;
|
||||
remaining -= EECHUNK;
|
||||
@ -312,12 +380,14 @@ uint8_t ESP8266AVRISP::write_eeprom(int length) {
|
||||
return Resp_STK_OK;
|
||||
}
|
||||
// write (length) bytes, (start) is a byte address
|
||||
uint8_t ESP8266AVRISP::write_eeprom_chunk(int start, int length) {
|
||||
uint8_t ESP8266AVRISP::write_eeprom_chunk(int start, int length)
|
||||
{
|
||||
// this writes byte-by-byte,
|
||||
// page writing may be faster (4 bytes at a time)
|
||||
fill(length);
|
||||
// prog_lamp(LOW);
|
||||
for (int x = 0; x < length; x++) {
|
||||
for (int x = 0; x < length; x++)
|
||||
{
|
||||
int addr = start + x;
|
||||
spi_transaction(0xC0, (addr >> 8) & 0xFF, addr & 0xFF, buff[x]);
|
||||
delay(45);
|
||||
@ -326,43 +396,52 @@ uint8_t ESP8266AVRISP::write_eeprom_chunk(int start, int length) {
|
||||
return Resp_STK_OK;
|
||||
}
|
||||
|
||||
void ESP8266AVRISP::program_page() {
|
||||
void ESP8266AVRISP::program_page()
|
||||
{
|
||||
char result = (char) Resp_STK_FAILED;
|
||||
int length = 256 * getch();
|
||||
length += getch();
|
||||
char memtype = getch();
|
||||
// flash memory @here, (length) bytes
|
||||
if (memtype == 'F') {
|
||||
if (memtype == 'F')
|
||||
{
|
||||
write_flash(length);
|
||||
return;
|
||||
}
|
||||
|
||||
if (memtype == 'E') {
|
||||
if (memtype == 'E')
|
||||
{
|
||||
result = (char)write_eeprom(length);
|
||||
if (Sync_CRC_EOP == getch()) {
|
||||
if (Sync_CRC_EOP == getch())
|
||||
{
|
||||
_client.print((char) Resp_STK_INSYNC);
|
||||
_client.print(result);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
error++;
|
||||
_client.print((char) Resp_STK_NOSYNC);
|
||||
}
|
||||
return;
|
||||
}
|
||||
_client.print((char)Resp_STK_FAILED);
|
||||
return;
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
uint8_t ESP8266AVRISP::flash_read(uint8_t hilo, int addr) {
|
||||
uint8_t ESP8266AVRISP::flash_read(uint8_t hilo, int addr)
|
||||
{
|
||||
return spi_transaction(0x20 + hilo * 8,
|
||||
(addr >> 8) & 0xFF,
|
||||
addr & 0xFF,
|
||||
0);
|
||||
}
|
||||
|
||||
void ESP8266AVRISP::flash_read_page(int length) {
|
||||
void ESP8266AVRISP::flash_read_page(int length)
|
||||
{
|
||||
uint8_t *data = (uint8_t *) malloc(length + 1);
|
||||
for (int x = 0; x < length; x += 2) {
|
||||
for (int x = 0; x < length; x += 2)
|
||||
{
|
||||
*(data + x) = flash_read(LOW, here);
|
||||
*(data + x + 1) = flash_read(HIGH, here);
|
||||
here++;
|
||||
@ -373,11 +452,13 @@ void ESP8266AVRISP::flash_read_page(int length) {
|
||||
return;
|
||||
}
|
||||
|
||||
void ESP8266AVRISP::eeprom_read_page(int length) {
|
||||
void ESP8266AVRISP::eeprom_read_page(int length)
|
||||
{
|
||||
// here again we have a word address
|
||||
uint8_t *data = (uint8_t *) malloc(length + 1);
|
||||
int start = here * 2;
|
||||
for (int x = 0; x < length; x++) {
|
||||
for (int x = 0; x < length; x++)
|
||||
{
|
||||
int addr = start + x;
|
||||
uint8_t ee = spi_transaction(0xA0, (addr >> 8) & 0xFF, addr & 0xFF, 0xFF);
|
||||
*(data + x) = ee;
|
||||
@ -388,23 +469,33 @@ void ESP8266AVRISP::eeprom_read_page(int length) {
|
||||
return;
|
||||
}
|
||||
|
||||
void ESP8266AVRISP::read_page() {
|
||||
void ESP8266AVRISP::read_page()
|
||||
{
|
||||
int length = 256 * getch();
|
||||
length += getch();
|
||||
char memtype = getch();
|
||||
if (Sync_CRC_EOP != getch()) {
|
||||
if (Sync_CRC_EOP != getch())
|
||||
{
|
||||
error++;
|
||||
_client.print((char) Resp_STK_NOSYNC);
|
||||
return;
|
||||
}
|
||||
_client.print((char) Resp_STK_INSYNC);
|
||||
if (memtype == 'F') flash_read_page(length);
|
||||
if (memtype == 'E') eeprom_read_page(length);
|
||||
if (memtype == 'F')
|
||||
{
|
||||
flash_read_page(length);
|
||||
}
|
||||
if (memtype == 'E')
|
||||
{
|
||||
eeprom_read_page(length);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void ESP8266AVRISP::read_signature() {
|
||||
if (Sync_CRC_EOP != getch()) {
|
||||
void ESP8266AVRISP::read_signature()
|
||||
{
|
||||
if (Sync_CRC_EOP != getch())
|
||||
{
|
||||
error++;
|
||||
_client.print((char) Resp_STK_NOSYNC);
|
||||
return;
|
||||
@ -422,7 +513,8 @@ void ESP8266AVRISP::read_signature() {
|
||||
|
||||
// It seems ArduinoISP is based on the original STK500 (not v2)
|
||||
// but implements only a subset of the commands.
|
||||
void ESP8266AVRISP::avrisp() {
|
||||
void ESP8266AVRISP::avrisp()
|
||||
{
|
||||
uint8_t data, low, high;
|
||||
uint8_t ch = getch();
|
||||
// Avoid set but not used warning. Leaving them in as it helps document the code
|
||||
@ -430,14 +522,16 @@ void ESP8266AVRISP::avrisp() {
|
||||
(void) low;
|
||||
(void) high;
|
||||
// AVRISP_DEBUG("CMD 0x%02x", ch);
|
||||
switch (ch) {
|
||||
switch (ch)
|
||||
{
|
||||
case Cmnd_STK_GET_SYNC:
|
||||
error = 0;
|
||||
empty_reply();
|
||||
break;
|
||||
|
||||
case Cmnd_STK_GET_SIGN_ON:
|
||||
if (getch() == Sync_CRC_EOP) {
|
||||
if (getch() == Sync_CRC_EOP)
|
||||
{
|
||||
_client.print((char) Resp_STK_INSYNC);
|
||||
_client.print(F("AVR ISP")); // AVR061 says "AVR STK"?
|
||||
_client.print((char) Resp_STK_OK);
|
||||
@ -510,21 +604,24 @@ void ESP8266AVRISP::avrisp() {
|
||||
case Cmnd_STK_READ_SIGN:
|
||||
read_signature();
|
||||
break;
|
||||
// expecting a command, not Sync_CRC_EOP
|
||||
// this is how we can get back in sync
|
||||
// expecting a command, not Sync_CRC_EOP
|
||||
// this is how we can get back in sync
|
||||
case Sync_CRC_EOP: // 0x20, space
|
||||
error++;
|
||||
_client.print((char) Resp_STK_NOSYNC);
|
||||
break;
|
||||
|
||||
// anything else we will return STK_UNKNOWN
|
||||
// anything else we will return STK_UNKNOWN
|
||||
default:
|
||||
AVRISP_DEBUG("?!?");
|
||||
error++;
|
||||
if (Sync_CRC_EOP == getch()) {
|
||||
if (Sync_CRC_EOP == getch())
|
||||
{
|
||||
_client.print((char)Resp_STK_UNKNOWN);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
_client.print((char)Resp_STK_NOSYNC);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
/*
|
||||
AVR In-System Programming over WiFi for ESP8266
|
||||
Copyright (c) Kiril Zyapkov <kiril@robotev.com>
|
||||
AVR In-System Programming over WiFi for ESP8266
|
||||
Copyright (c) Kiril Zyapkov <kiril@robotev.com>
|
||||
|
||||
Original version:
|
||||
Original version:
|
||||
ArduinoISP version 04m3
|
||||
Copyright (c) 2008-2011 Randall Bohn
|
||||
If you require a license, see
|
||||
@ -21,14 +21,16 @@ Original version:
|
||||
#define AVRISP_SPI_FREQ 300e3
|
||||
|
||||
// programmer states
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
AVRISP_STATE_IDLE = 0, // no active TCP session
|
||||
AVRISP_STATE_PENDING, // TCP connected, pending SPI activation
|
||||
AVRISP_STATE_ACTIVE // programmer is active and owns the SPI bus
|
||||
} AVRISPState_t;
|
||||
|
||||
// stk500 parameters
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
uint8_t devicecode;
|
||||
uint8_t revision;
|
||||
uint8_t progtype;
|
||||
@ -45,9 +47,10 @@ typedef struct {
|
||||
} AVRISP_parameter_t;
|
||||
|
||||
|
||||
class ESP8266AVRISP {
|
||||
class ESP8266AVRISP
|
||||
{
|
||||
public:
|
||||
ESP8266AVRISP(uint16_t port, uint8_t reset_pin, uint32_t spi_freq=AVRISP_SPI_FREQ, bool reset_state=false, bool reset_activehigh=false);
|
||||
ESP8266AVRISP(uint16_t port, uint8_t reset_pin, uint32_t spi_freq = AVRISP_SPI_FREQ, bool reset_state = false, bool reset_activehigh = false);
|
||||
|
||||
void begin();
|
||||
|
||||
@ -100,7 +103,10 @@ protected:
|
||||
void start_pmode(void); // enter program mode
|
||||
void end_pmode(void); // exit program mode
|
||||
|
||||
inline bool _resetLevel(bool reset_state) { return reset_state == _reset_activehigh; }
|
||||
inline bool _resetLevel(bool reset_state)
|
||||
{
|
||||
return reset_state == _reset_activehigh;
|
||||
}
|
||||
|
||||
uint32_t _spi_freq;
|
||||
WiFiServer _server;
|
||||
|
@ -1,108 +1,108 @@
|
||||
//**** ATMEL AVR - A P P L I C A T I O N N O T E ************************
|
||||
//*
|
||||
//* Title: AVR061 - STK500 Communication Protocol
|
||||
//* Filename: command.h
|
||||
//* Version: 1.0
|
||||
//* Last updated: 09.09.2002
|
||||
//*
|
||||
//* Support E-mail: avr@atmel.com
|
||||
//*
|
||||
//**************************************************************************
|
||||
|
||||
// *****************[ STK Message constants ]***************************
|
||||
|
||||
#define STK_SIGN_ON_MESSAGE "AVR STK" // Sign on string for Cmnd_STK_GET_SIGN_ON
|
||||
|
||||
// *****************[ STK Response constants ]***************************
|
||||
|
||||
#define Resp_STK_OK 0x10 // ' '
|
||||
#define Resp_STK_FAILED 0x11 // ' '
|
||||
#define Resp_STK_UNKNOWN 0x12 // ' '
|
||||
#define Resp_STK_NODEVICE 0x13 // ' '
|
||||
#define Resp_STK_INSYNC 0x14 // ' '
|
||||
#define Resp_STK_NOSYNC 0x15 // ' '
|
||||
|
||||
#define Resp_ADC_CHANNEL_ERROR 0x16 // ' '
|
||||
#define Resp_ADC_MEASURE_OK 0x17 // ' '
|
||||
#define Resp_PWM_CHANNEL_ERROR 0x18 // ' '
|
||||
#define Resp_PWM_ADJUST_OK 0x19 // ' '
|
||||
|
||||
// *****************[ STK Special constants ]***************************
|
||||
|
||||
#define Sync_CRC_EOP 0x20 // 'SPACE'
|
||||
|
||||
// *****************[ STK Command constants ]***************************
|
||||
|
||||
#define Cmnd_STK_GET_SYNC 0x30 // ' '
|
||||
#define Cmnd_STK_GET_SIGN_ON 0x31 // ' '
|
||||
#define Cmnd_STK_RESET 0x32 // ' '
|
||||
#define Cmnd_STK_SINGLE_CLOCK 0x33 // ' '
|
||||
#define Cmnd_STK_STORE_PARAMETERS 0x34 // ' '
|
||||
|
||||
#define Cmnd_STK_SET_PARAMETER 0x40 // ' '
|
||||
#define Cmnd_STK_GET_PARAMETER 0x41 // ' '
|
||||
#define Cmnd_STK_SET_DEVICE 0x42 // ' '
|
||||
#define Cmnd_STK_GET_DEVICE 0x43 // ' '
|
||||
#define Cmnd_STK_GET_STATUS 0x44 // ' '
|
||||
#define Cmnd_STK_SET_DEVICE_EXT 0x45 // ' '
|
||||
|
||||
#define Cmnd_STK_ENTER_PROGMODE 0x50 // ' '
|
||||
#define Cmnd_STK_LEAVE_PROGMODE 0x51 // ' '
|
||||
#define Cmnd_STK_CHIP_ERASE 0x52 // ' '
|
||||
#define Cmnd_STK_CHECK_AUTOINC 0x53 // ' '
|
||||
#define Cmnd_STK_CHECK_DEVICE 0x54 // ' '
|
||||
#define Cmnd_STK_LOAD_ADDRESS 0x55 // ' '
|
||||
#define Cmnd_STK_UNIVERSAL 0x56 // ' '
|
||||
|
||||
#define Cmnd_STK_PROG_FLASH 0x60 // ' '
|
||||
#define Cmnd_STK_PROG_DATA 0x61 // ' '
|
||||
#define Cmnd_STK_PROG_FUSE 0x62 // ' '
|
||||
#define Cmnd_STK_PROG_LOCK 0x63 // ' '
|
||||
#define Cmnd_STK_PROG_PAGE 0x64 // ' '
|
||||
#define Cmnd_STK_PROG_FUSE_EXT 0x65 // ' '
|
||||
|
||||
#define Cmnd_STK_READ_FLASH 0x70 // ' '
|
||||
#define Cmnd_STK_READ_DATA 0x71 // ' '
|
||||
#define Cmnd_STK_READ_FUSE 0x72 // ' '
|
||||
#define Cmnd_STK_READ_LOCK 0x73 // ' '
|
||||
#define Cmnd_STK_READ_PAGE 0x74 // ' '
|
||||
#define Cmnd_STK_READ_SIGN 0x75 // ' '
|
||||
#define Cmnd_STK_READ_OSCCAL 0x76 // ' '
|
||||
#define Cmnd_STK_READ_FUSE_EXT 0x77 // ' '
|
||||
#define Cmnd_STK_READ_OSCCAL_EXT 0x78 // ' '
|
||||
|
||||
// *****************[ STK Parameter constants ]***************************
|
||||
|
||||
#define Parm_STK_HW_VER 0x80 // ' ' - R
|
||||
#define Parm_STK_SW_MAJOR 0x81 // ' ' - R
|
||||
#define Parm_STK_SW_MINOR 0x82 // ' ' - R
|
||||
#define Parm_STK_LEDS 0x83 // ' ' - R/W
|
||||
#define Parm_STK_VTARGET 0x84 // ' ' - R/W
|
||||
#define Parm_STK_VADJUST 0x85 // ' ' - R/W
|
||||
#define Parm_STK_OSC_PSCALE 0x86 // ' ' - R/W
|
||||
#define Parm_STK_OSC_CMATCH 0x87 // ' ' - R/W
|
||||
#define Parm_STK_RESET_DURATION 0x88 // ' ' - R/W
|
||||
#define Parm_STK_SCK_DURATION 0x89 // ' ' - R/W
|
||||
|
||||
#define Parm_STK_BUFSIZEL 0x90 // ' ' - R/W, Range {0..255}
|
||||
#define Parm_STK_BUFSIZEH 0x91 // ' ' - R/W, Range {0..255}
|
||||
#define Parm_STK_DEVICE 0x92 // ' ' - R/W, Range {0..255}
|
||||
#define Parm_STK_PROGMODE 0x93 // ' ' - 'P' or 'S'
|
||||
#define Parm_STK_PARAMODE 0x94 // ' ' - TRUE or FALSE
|
||||
#define Parm_STK_POLLING 0x95 // ' ' - TRUE or FALSE
|
||||
#define Parm_STK_SELFTIMED 0x96 // ' ' - TRUE or FALSE
|
||||
|
||||
|
||||
// *****************[ STK status bit definitions ]***************************
|
||||
|
||||
#define Stat_STK_INSYNC 0x01 // INSYNC status bit, '1' - INSYNC
|
||||
#define Stat_STK_PROGMODE 0x02 // Programming mode, '1' - PROGMODE
|
||||
#define Stat_STK_STANDALONE 0x04 // Standalone mode, '1' - SM mode
|
||||
#define Stat_STK_RESET 0x08 // RESET button, '1' - Pushed
|
||||
#define Stat_STK_PROGRAM 0x10 // Program button, ' 1' - Pushed
|
||||
#define Stat_STK_LEDG 0x20 // Green LED status, '1' - Lit
|
||||
#define Stat_STK_LEDR 0x40 // Red LED status, '1' - Lit
|
||||
#define Stat_STK_LEDBLINK 0x80 // LED blink ON/OFF, '1' - Blink
|
||||
|
||||
|
||||
// *****************************[ End Of COMMAND.H ]**************************
|
||||
//**** ATMEL AVR - A P P L I C A T I O N N O T E ************************
|
||||
//*
|
||||
//* Title: AVR061 - STK500 Communication Protocol
|
||||
//* Filename: command.h
|
||||
//* Version: 1.0
|
||||
//* Last updated: 09.09.2002
|
||||
//*
|
||||
//* Support E-mail: avr@atmel.com
|
||||
//*
|
||||
//**************************************************************************
|
||||
|
||||
// *****************[ STK Message constants ]***************************
|
||||
|
||||
#define STK_SIGN_ON_MESSAGE "AVR STK" // Sign on string for Cmnd_STK_GET_SIGN_ON
|
||||
|
||||
// *****************[ STK Response constants ]***************************
|
||||
|
||||
#define Resp_STK_OK 0x10 // ' '
|
||||
#define Resp_STK_FAILED 0x11 // ' '
|
||||
#define Resp_STK_UNKNOWN 0x12 // ' '
|
||||
#define Resp_STK_NODEVICE 0x13 // ' '
|
||||
#define Resp_STK_INSYNC 0x14 // ' '
|
||||
#define Resp_STK_NOSYNC 0x15 // ' '
|
||||
|
||||
#define Resp_ADC_CHANNEL_ERROR 0x16 // ' '
|
||||
#define Resp_ADC_MEASURE_OK 0x17 // ' '
|
||||
#define Resp_PWM_CHANNEL_ERROR 0x18 // ' '
|
||||
#define Resp_PWM_ADJUST_OK 0x19 // ' '
|
||||
|
||||
// *****************[ STK Special constants ]***************************
|
||||
|
||||
#define Sync_CRC_EOP 0x20 // 'SPACE'
|
||||
|
||||
// *****************[ STK Command constants ]***************************
|
||||
|
||||
#define Cmnd_STK_GET_SYNC 0x30 // ' '
|
||||
#define Cmnd_STK_GET_SIGN_ON 0x31 // ' '
|
||||
#define Cmnd_STK_RESET 0x32 // ' '
|
||||
#define Cmnd_STK_SINGLE_CLOCK 0x33 // ' '
|
||||
#define Cmnd_STK_STORE_PARAMETERS 0x34 // ' '
|
||||
|
||||
#define Cmnd_STK_SET_PARAMETER 0x40 // ' '
|
||||
#define Cmnd_STK_GET_PARAMETER 0x41 // ' '
|
||||
#define Cmnd_STK_SET_DEVICE 0x42 // ' '
|
||||
#define Cmnd_STK_GET_DEVICE 0x43 // ' '
|
||||
#define Cmnd_STK_GET_STATUS 0x44 // ' '
|
||||
#define Cmnd_STK_SET_DEVICE_EXT 0x45 // ' '
|
||||
|
||||
#define Cmnd_STK_ENTER_PROGMODE 0x50 // ' '
|
||||
#define Cmnd_STK_LEAVE_PROGMODE 0x51 // ' '
|
||||
#define Cmnd_STK_CHIP_ERASE 0x52 // ' '
|
||||
#define Cmnd_STK_CHECK_AUTOINC 0x53 // ' '
|
||||
#define Cmnd_STK_CHECK_DEVICE 0x54 // ' '
|
||||
#define Cmnd_STK_LOAD_ADDRESS 0x55 // ' '
|
||||
#define Cmnd_STK_UNIVERSAL 0x56 // ' '
|
||||
|
||||
#define Cmnd_STK_PROG_FLASH 0x60 // ' '
|
||||
#define Cmnd_STK_PROG_DATA 0x61 // ' '
|
||||
#define Cmnd_STK_PROG_FUSE 0x62 // ' '
|
||||
#define Cmnd_STK_PROG_LOCK 0x63 // ' '
|
||||
#define Cmnd_STK_PROG_PAGE 0x64 // ' '
|
||||
#define Cmnd_STK_PROG_FUSE_EXT 0x65 // ' '
|
||||
|
||||
#define Cmnd_STK_READ_FLASH 0x70 // ' '
|
||||
#define Cmnd_STK_READ_DATA 0x71 // ' '
|
||||
#define Cmnd_STK_READ_FUSE 0x72 // ' '
|
||||
#define Cmnd_STK_READ_LOCK 0x73 // ' '
|
||||
#define Cmnd_STK_READ_PAGE 0x74 // ' '
|
||||
#define Cmnd_STK_READ_SIGN 0x75 // ' '
|
||||
#define Cmnd_STK_READ_OSCCAL 0x76 // ' '
|
||||
#define Cmnd_STK_READ_FUSE_EXT 0x77 // ' '
|
||||
#define Cmnd_STK_READ_OSCCAL_EXT 0x78 // ' '
|
||||
|
||||
// *****************[ STK Parameter constants ]***************************
|
||||
|
||||
#define Parm_STK_HW_VER 0x80 // ' ' - R
|
||||
#define Parm_STK_SW_MAJOR 0x81 // ' ' - R
|
||||
#define Parm_STK_SW_MINOR 0x82 // ' ' - R
|
||||
#define Parm_STK_LEDS 0x83 // ' ' - R/W
|
||||
#define Parm_STK_VTARGET 0x84 // ' ' - R/W
|
||||
#define Parm_STK_VADJUST 0x85 // ' ' - R/W
|
||||
#define Parm_STK_OSC_PSCALE 0x86 // ' ' - R/W
|
||||
#define Parm_STK_OSC_CMATCH 0x87 // ' ' - R/W
|
||||
#define Parm_STK_RESET_DURATION 0x88 // ' ' - R/W
|
||||
#define Parm_STK_SCK_DURATION 0x89 // ' ' - R/W
|
||||
|
||||
#define Parm_STK_BUFSIZEL 0x90 // ' ' - R/W, Range {0..255}
|
||||
#define Parm_STK_BUFSIZEH 0x91 // ' ' - R/W, Range {0..255}
|
||||
#define Parm_STK_DEVICE 0x92 // ' ' - R/W, Range {0..255}
|
||||
#define Parm_STK_PROGMODE 0x93 // ' ' - 'P' or 'S'
|
||||
#define Parm_STK_PARAMODE 0x94 // ' ' - TRUE or FALSE
|
||||
#define Parm_STK_POLLING 0x95 // ' ' - TRUE or FALSE
|
||||
#define Parm_STK_SELFTIMED 0x96 // ' ' - TRUE or FALSE
|
||||
|
||||
|
||||
// *****************[ STK status bit definitions ]***************************
|
||||
|
||||
#define Stat_STK_INSYNC 0x01 // INSYNC status bit, '1' - INSYNC
|
||||
#define Stat_STK_PROGMODE 0x02 // Programming mode, '1' - PROGMODE
|
||||
#define Stat_STK_STANDALONE 0x04 // Standalone mode, '1' - SM mode
|
||||
#define Stat_STK_RESET 0x08 // RESET button, '1' - Pushed
|
||||
#define Stat_STK_PROGRAM 0x10 // Program button, ' 1' - Pushed
|
||||
#define Stat_STK_LEDG 0x20 // Green LED status, '1' - Lit
|
||||
#define Stat_STK_LEDR 0x40 // Red LED status, '1' - Lit
|
||||
#define Stat_STK_LEDBLINK 0x80 // LED blink ON/OFF, '1' - Blink
|
||||
|
||||
|
||||
// *****************************[ End Of COMMAND.H ]**************************
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,27 +1,27 @@
|
||||
/**
|
||||
* ESP8266HTTPClient.h
|
||||
*
|
||||
* Created on: 02.11.2015
|
||||
*
|
||||
* Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||
* This file is part of the ESP8266HTTPClient 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
|
||||
*
|
||||
* Modified by Jeroen Döll, June 2018
|
||||
*/
|
||||
ESP8266HTTPClient.h
|
||||
|
||||
Created on: 02.11.2015
|
||||
|
||||
Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||
This file is part of the ESP8266HTTPClient 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
|
||||
|
||||
Modified by Jeroen Döll, June 2018
|
||||
*/
|
||||
|
||||
#ifndef ESP8266HTTPClient_H_
|
||||
#define ESP8266HTTPClient_H_
|
||||
@ -64,7 +64,8 @@
|
||||
#define HTTP_TCP_BUFFER_SIZE (1460)
|
||||
|
||||
/// HTTP codes see RFC7231
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
HTTP_CODE_CONTINUE = 100,
|
||||
HTTP_CODE_SWITCHING_PROTOCOLS = 101,
|
||||
HTTP_CODE_PROCESSING = 102,
|
||||
@ -125,7 +126,8 @@ typedef enum {
|
||||
HTTP_CODE_NETWORK_AUTHENTICATION_REQUIRED = 511
|
||||
} t_http_codes;
|
||||
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
HTTPC_TE_IDENTITY,
|
||||
HTTPC_TE_CHUNKED
|
||||
} transferEncoding_t;
|
||||
@ -143,25 +145,25 @@ public:
|
||||
HTTPClient();
|
||||
~HTTPClient();
|
||||
|
||||
/*
|
||||
* Since both begin() functions take a reference to client as a parameter, you need to
|
||||
* ensure the client object lives the entire time of the HTTPClient
|
||||
*/
|
||||
/*
|
||||
Since both begin() functions take a reference to client as a parameter, you need to
|
||||
ensure the client object lives the entire time of the HTTPClient
|
||||
*/
|
||||
bool begin(WiFiClient &client, String url);
|
||||
bool begin(WiFiClient &client, String host, uint16_t port, String uri = "/", bool https = false);
|
||||
|
||||
#if HTTPCLIENT_1_1_COMPATIBLE
|
||||
// Plain HTTP connection, unencrypted
|
||||
bool begin(String url) __attribute__ ((deprecated));
|
||||
bool begin(String host, uint16_t port, String uri = "/") __attribute__ ((deprecated));
|
||||
bool begin(String url) __attribute__((deprecated));
|
||||
bool begin(String host, uint16_t port, String uri = "/") __attribute__((deprecated));
|
||||
// Use axTLS for secure HTTPS connection
|
||||
bool begin(String url, String httpsFingerprint) __attribute__ ((deprecated));
|
||||
bool begin(String host, uint16_t port, String uri, String httpsFingerprint) __attribute__ ((deprecated));
|
||||
bool begin(String url, String httpsFingerprint) __attribute__((deprecated));
|
||||
bool begin(String host, uint16_t port, String uri, String httpsFingerprint) __attribute__((deprecated));
|
||||
// Use BearSSL for secure HTTPS connection
|
||||
bool begin(String url, const uint8_t httpsFingerprint[20]) __attribute__ ((deprecated));
|
||||
bool begin(String host, uint16_t port, String uri, const uint8_t httpsFingerprint[20]) __attribute__ ((deprecated));
|
||||
bool begin(String url, const uint8_t httpsFingerprint[20]) __attribute__((deprecated));
|
||||
bool begin(String host, uint16_t port, String uri, const uint8_t httpsFingerprint[20]) __attribute__((deprecated));
|
||||
// deprecated, use the overload above instead
|
||||
bool begin(String host, uint16_t port, String uri, bool https, String httpsFingerprint) __attribute__ ((deprecated));
|
||||
bool begin(String host, uint16_t port, String uri, bool https, String httpsFingerprint) __attribute__((deprecated));
|
||||
#endif
|
||||
|
||||
void end(void);
|
||||
@ -211,7 +213,8 @@ public:
|
||||
static String errorToString(int error);
|
||||
|
||||
protected:
|
||||
struct RequestArgument {
|
||||
struct RequestArgument
|
||||
{
|
||||
String key;
|
||||
String value;
|
||||
};
|
||||
|
@ -8,21 +8,21 @@
|
||||
|
||||
|
||||
static const char serverIndex[] PROGMEM =
|
||||
R"(<html><body><form method='POST' action='' enctype='multipart/form-data'>
|
||||
R"(<html><body><form method='POST' action='' enctype='multipart/form-data'>
|
||||
<input type='file' name='update'>
|
||||
<input type='submit' value='Update'>
|
||||
</form>
|
||||
</body></html>)";
|
||||
static const char successResponse[] PROGMEM =
|
||||
"<META http-equiv=\"refresh\" content=\"15;URL=/\">Update Success! Rebooting...\n";
|
||||
static const char successResponse[] PROGMEM =
|
||||
"<META http-equiv=\"refresh\" content=\"15;URL=/\">Update Success! Rebooting...\n";
|
||||
|
||||
ESP8266HTTPUpdateServer::ESP8266HTTPUpdateServer(bool serial_debug)
|
||||
{
|
||||
_serial_output = serial_debug;
|
||||
_server = NULL;
|
||||
_username = emptyString;
|
||||
_password = emptyString;
|
||||
_authenticated = false;
|
||||
_serial_output = serial_debug;
|
||||
_server = NULL;
|
||||
_username = emptyString;
|
||||
_password = emptyString;
|
||||
_authenticated = false;
|
||||
}
|
||||
|
||||
void ESP8266HTTPUpdateServer::setup(ESP8266WebServer *server, const String& path, const String& username, const String& password)
|
||||
@ -32,73 +32,117 @@ void ESP8266HTTPUpdateServer::setup(ESP8266WebServer *server, const String& path
|
||||
_password = password;
|
||||
|
||||
// handler for the /update form page
|
||||
_server->on(path.c_str(), HTTP_GET, [&](){
|
||||
if(_username != emptyString && _password != emptyString && !_server->authenticate(_username.c_str(), _password.c_str()))
|
||||
return _server->requestAuthentication();
|
||||
_server->send_P(200, PSTR("text/html"), serverIndex);
|
||||
_server->on(path.c_str(), HTTP_GET, [&]()
|
||||
{
|
||||
if (_username != emptyString && _password != emptyString && !_server->authenticate(_username.c_str(), _password.c_str()))
|
||||
{
|
||||
return _server->requestAuthentication();
|
||||
}
|
||||
_server->send_P(200, PSTR("text/html"), serverIndex);
|
||||
});
|
||||
|
||||
// handler for the /update form POST (once file upload finishes)
|
||||
_server->on(path.c_str(), HTTP_POST, [&](){
|
||||
if(!_authenticated)
|
||||
return _server->requestAuthentication();
|
||||
if (Update.hasError()) {
|
||||
_server->send(200, F("text/html"), String(F("Update error: ")) + _updaterError);
|
||||
} else {
|
||||
_server->client().setNoDelay(true);
|
||||
_server->send_P(200, PSTR("text/html"), successResponse);
|
||||
delay(100);
|
||||
_server->client().stop();
|
||||
ESP.restart();
|
||||
}
|
||||
},[&](){
|
||||
// handler for the file upload, get's the sketch bytes, and writes
|
||||
// them through the Update object
|
||||
HTTPUpload& upload = _server->upload();
|
||||
_server->on(path.c_str(), HTTP_POST, [&]()
|
||||
{
|
||||
if (!_authenticated)
|
||||
{
|
||||
return _server->requestAuthentication();
|
||||
}
|
||||
if (Update.hasError())
|
||||
{
|
||||
_server->send(200, F("text/html"), String(F("Update error: ")) + _updaterError);
|
||||
}
|
||||
else
|
||||
{
|
||||
_server->client().setNoDelay(true);
|
||||
_server->send_P(200, PSTR("text/html"), successResponse);
|
||||
delay(100);
|
||||
_server->client().stop();
|
||||
ESP.restart();
|
||||
}
|
||||
}, [&]()
|
||||
{
|
||||
// handler for the file upload, get's the sketch bytes, and writes
|
||||
// them through the Update object
|
||||
HTTPUpload& upload = _server->upload();
|
||||
|
||||
if(upload.status == UPLOAD_FILE_START){
|
||||
_updaterError = String();
|
||||
if (_serial_output)
|
||||
Serial.setDebugOutput(true);
|
||||
if (upload.status == UPLOAD_FILE_START)
|
||||
{
|
||||
_updaterError = String();
|
||||
if (_serial_output)
|
||||
{
|
||||
Serial.setDebugOutput(true);
|
||||
}
|
||||
|
||||
_authenticated = (_username == emptyString || _password == emptyString || _server->authenticate(_username.c_str(), _password.c_str()));
|
||||
if(!_authenticated){
|
||||
if (_serial_output)
|
||||
Serial.printf("Unauthenticated Update\n");
|
||||
return;
|
||||
}
|
||||
_authenticated = (_username == emptyString || _password == emptyString || _server->authenticate(_username.c_str(), _password.c_str()));
|
||||
if (!_authenticated)
|
||||
{
|
||||
if (_serial_output)
|
||||
{
|
||||
Serial.printf("Unauthenticated Update\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
WiFiUDP::stopAll();
|
||||
if (_serial_output)
|
||||
Serial.printf("Update: %s\n", upload.filename.c_str());
|
||||
uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
|
||||
if(!Update.begin(maxSketchSpace)){//start with max available size
|
||||
_setUpdaterError();
|
||||
WiFiUDP::stopAll();
|
||||
if (_serial_output)
|
||||
{
|
||||
Serial.printf("Update: %s\n", upload.filename.c_str());
|
||||
}
|
||||
uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
|
||||
if (!Update.begin(maxSketchSpace)) //start with max available size
|
||||
{
|
||||
_setUpdaterError();
|
||||
}
|
||||
}
|
||||
} else if(_authenticated && upload.status == UPLOAD_FILE_WRITE && !_updaterError.length()){
|
||||
if (_serial_output) Serial.printf(".");
|
||||
if(Update.write(upload.buf, upload.currentSize) != upload.currentSize){
|
||||
_setUpdaterError();
|
||||
else if (_authenticated && upload.status == UPLOAD_FILE_WRITE && !_updaterError.length())
|
||||
{
|
||||
if (_serial_output)
|
||||
{
|
||||
Serial.printf(".");
|
||||
}
|
||||
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize)
|
||||
{
|
||||
_setUpdaterError();
|
||||
}
|
||||
}
|
||||
} else if(_authenticated && upload.status == UPLOAD_FILE_END && !_updaterError.length()){
|
||||
if(Update.end(true)){ //true to set the size to the current progress
|
||||
if (_serial_output) Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
|
||||
} else {
|
||||
_setUpdaterError();
|
||||
else if (_authenticated && upload.status == UPLOAD_FILE_END && !_updaterError.length())
|
||||
{
|
||||
if (Update.end(true)) //true to set the size to the current progress
|
||||
{
|
||||
if (_serial_output)
|
||||
{
|
||||
Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_setUpdaterError();
|
||||
}
|
||||
if (_serial_output)
|
||||
{
|
||||
Serial.setDebugOutput(false);
|
||||
}
|
||||
}
|
||||
if (_serial_output) Serial.setDebugOutput(false);
|
||||
} else if(_authenticated && upload.status == UPLOAD_FILE_ABORTED){
|
||||
Update.end();
|
||||
if (_serial_output) Serial.println("Update was aborted");
|
||||
}
|
||||
delay(0);
|
||||
else if (_authenticated && upload.status == UPLOAD_FILE_ABORTED)
|
||||
{
|
||||
Update.end();
|
||||
if (_serial_output)
|
||||
{
|
||||
Serial.println("Update was aborted");
|
||||
}
|
||||
}
|
||||
delay(0);
|
||||
});
|
||||
}
|
||||
|
||||
void ESP8266HTTPUpdateServer::_setUpdaterError()
|
||||
{
|
||||
if (_serial_output) Update.printError(Serial);
|
||||
StreamString str;
|
||||
Update.printError(str);
|
||||
_updaterError = str.c_str();
|
||||
if (_serial_output)
|
||||
{
|
||||
Update.printError(Serial);
|
||||
}
|
||||
StreamString str;
|
||||
Update.printError(str);
|
||||
_updaterError = str.c_str();
|
||||
}
|
||||
|
@ -5,36 +5,36 @@ class ESP8266WebServer;
|
||||
|
||||
class ESP8266HTTPUpdateServer
|
||||
{
|
||||
public:
|
||||
ESP8266HTTPUpdateServer(bool serial_debug=false);
|
||||
public:
|
||||
ESP8266HTTPUpdateServer(bool serial_debug = false);
|
||||
|
||||
void setup(ESP8266WebServer *server)
|
||||
{
|
||||
setup(server, emptyString, emptyString);
|
||||
setup(server, emptyString, emptyString);
|
||||
}
|
||||
|
||||
void setup(ESP8266WebServer *server, const String& path)
|
||||
{
|
||||
setup(server, path, emptyString, emptyString);
|
||||
setup(server, path, emptyString, emptyString);
|
||||
}
|
||||
|
||||
void setup(ESP8266WebServer *server, const String& username, const String& password)
|
||||
{
|
||||
setup(server, "/update", username, password);
|
||||
setup(server, "/update", username, password);
|
||||
}
|
||||
|
||||
void setup(ESP8266WebServer *server, const String& path, const String& username, const String& password);
|
||||
|
||||
void updateCredentials(const String& username, const String& password)
|
||||
{
|
||||
_username = username;
|
||||
_password = password;
|
||||
_username = username;
|
||||
_password = password;
|
||||
}
|
||||
|
||||
protected:
|
||||
protected:
|
||||
void _setUpdaterError();
|
||||
|
||||
private:
|
||||
private:
|
||||
bool _serial_output;
|
||||
ESP8266WebServer *_server;
|
||||
String _username;
|
||||
|
@ -1,39 +1,39 @@
|
||||
/*
|
||||
* ESP8266 LLMNR responder
|
||||
* Copyright (C) 2017 Stephen Warren <swarren@wwwdotorg.org>
|
||||
*
|
||||
* Based on:
|
||||
* ESP8266 Multicast DNS (port of CC3000 Multicast DNS library)
|
||||
* Version 1.1
|
||||
* Copyright (c) 2013 Tony DiCola (tony@tonydicola.com)
|
||||
* ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com)
|
||||
* MDNS-SD Suport 2015 Hristo Gochkov
|
||||
* Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com)
|
||||
*
|
||||
* License (MIT license):
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* Reference:
|
||||
* https://tools.ietf.org/html/rfc4795 (LLMNR)
|
||||
* https://tools.ietf.org/html/rfc1035 (DNS)
|
||||
*/
|
||||
ESP8266 LLMNR responder
|
||||
Copyright (C) 2017 Stephen Warren <swarren@wwwdotorg.org>
|
||||
|
||||
Based on:
|
||||
ESP8266 Multicast DNS (port of CC3000 Multicast DNS library)
|
||||
Version 1.1
|
||||
Copyright (c) 2013 Tony DiCola (tony@tonydicola.com)
|
||||
ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com)
|
||||
MDNS-SD Suport 2015 Hristo Gochkov
|
||||
Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com)
|
||||
|
||||
License (MIT license):
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
Reference:
|
||||
https://tools.ietf.org/html/rfc4795 (LLMNR)
|
||||
https://tools.ietf.org/html/rfc1035 (DNS)
|
||||
*/
|
||||
|
||||
#include <debug.h>
|
||||
#include <functional>
|
||||
@ -72,28 +72,37 @@ static const int LLMNR_MULTICAST_TTL = 1;
|
||||
static const int LLMNR_PORT = 5355;
|
||||
|
||||
LLMNRResponder::LLMNRResponder() :
|
||||
_conn(0) {
|
||||
_conn(0)
|
||||
{
|
||||
}
|
||||
|
||||
LLMNRResponder::~LLMNRResponder() {
|
||||
LLMNRResponder::~LLMNRResponder()
|
||||
{
|
||||
if (_conn)
|
||||
{
|
||||
_conn->unref();
|
||||
}
|
||||
}
|
||||
|
||||
bool LLMNRResponder::begin(const char* hostname) {
|
||||
bool LLMNRResponder::begin(const char* hostname)
|
||||
{
|
||||
// Max length for a single label in DNS
|
||||
if (strlen(hostname) > 63)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_hostname = hostname;
|
||||
_hostname.toLowerCase();
|
||||
|
||||
_sta_got_ip_handler = WiFi.onStationModeGotIP([this](const WiFiEventStationModeGotIP& event){
|
||||
_sta_got_ip_handler = WiFi.onStationModeGotIP([this](const WiFiEventStationModeGotIP & event)
|
||||
{
|
||||
(void) event;
|
||||
_restart();
|
||||
});
|
||||
|
||||
_sta_disconnected_handler = WiFi.onStationModeDisconnected([this](const WiFiEventStationModeDisconnected& event) {
|
||||
_sta_disconnected_handler = WiFi.onStationModeDisconnected([this](const WiFiEventStationModeDisconnected & event)
|
||||
{
|
||||
(void) event;
|
||||
_restart();
|
||||
});
|
||||
@ -101,12 +110,15 @@ bool LLMNRResponder::begin(const char* hostname) {
|
||||
return _restart();
|
||||
}
|
||||
|
||||
void LLMNRResponder::notify_ap_change() {
|
||||
void LLMNRResponder::notify_ap_change()
|
||||
{
|
||||
_restart();
|
||||
}
|
||||
|
||||
bool LLMNRResponder::_restart() {
|
||||
if (_conn) {
|
||||
bool LLMNRResponder::_restart()
|
||||
{
|
||||
if (_conn)
|
||||
{
|
||||
_conn->unref();
|
||||
_conn = 0;
|
||||
}
|
||||
@ -114,13 +126,17 @@ bool LLMNRResponder::_restart() {
|
||||
IPAddress llmnr(LLMNR_MULTICAST_ADDR);
|
||||
|
||||
if (igmp_joingroup(IP4_ADDR_ANY4, llmnr) != ERR_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_conn = new UdpContext;
|
||||
_conn->ref();
|
||||
|
||||
if (!_conn->listen(IP_ADDR_ANY, LLMNR_PORT))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_conn->setMulticastTTL(LLMNR_MULTICAST_TTL);
|
||||
_conn->onRx(std::bind(&LLMNRResponder::_process_packet, this));
|
||||
@ -128,9 +144,12 @@ bool LLMNRResponder::_restart() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLMNRResponder::_process_packet() {
|
||||
void LLMNRResponder::_process_packet()
|
||||
{
|
||||
if (!_conn || !_conn->next())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef LLMNR_DEBUG
|
||||
Serial.println("LLMNR: RX'd packet");
|
||||
@ -159,21 +178,24 @@ void LLMNRResponder::_process_packet() {
|
||||
#endif
|
||||
|
||||
#define BAD_FLAGS (FLAGS_QR | (FLAGS_OP_MASK << FLAGS_OP_SHIFT) | FLAGS_C)
|
||||
if (flags & BAD_FLAGS) {
|
||||
if (flags & BAD_FLAGS)
|
||||
{
|
||||
#ifdef LLMNR_DEBUG
|
||||
Serial.println("Bad flags");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if (qdcount != 1) {
|
||||
if (qdcount != 1)
|
||||
{
|
||||
#ifdef LLMNR_DEBUG
|
||||
Serial.println("QDCOUNT != 1");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
if (ancount || nscount || arcount) {
|
||||
if (ancount || nscount || arcount)
|
||||
{
|
||||
#ifdef LLMNR_DEBUG
|
||||
Serial.println("AN/NS/AR-COUNT != 0");
|
||||
#endif
|
||||
@ -185,7 +207,8 @@ void LLMNRResponder::_process_packet() {
|
||||
Serial.print("QNAME len ");
|
||||
Serial.println(namelen);
|
||||
#endif
|
||||
if (namelen != _hostname.length()) {
|
||||
if (namelen != _hostname.length())
|
||||
{
|
||||
#ifdef LLMNR_DEBUG
|
||||
Serial.println("QNAME len mismatch");
|
||||
#endif
|
||||
@ -201,7 +224,8 @@ void LLMNRResponder::_process_packet() {
|
||||
Serial.println(qname);
|
||||
#endif
|
||||
|
||||
if (strcmp(_hostname.c_str(), qname)) {
|
||||
if (strcmp(_hostname.c_str(), qname))
|
||||
{
|
||||
#ifdef LLMNR_DEBUG
|
||||
Serial.println("QNAME mismatch");
|
||||
#endif
|
||||
@ -227,26 +251,34 @@ void LLMNRResponder::_process_packet() {
|
||||
#ifdef LLMNR_DEBUG
|
||||
Serial.println("Match; responding");
|
||||
if (!have_rr)
|
||||
{
|
||||
Serial.println("(no matching RRs)");
|
||||
}
|
||||
#endif
|
||||
|
||||
IPAddress remote_ip = _conn->getRemoteAddress();
|
||||
|
||||
struct ip_info ip_info;
|
||||
bool match_ap = false;
|
||||
if (wifi_get_opmode() & SOFTAP_MODE) {
|
||||
if (wifi_get_opmode() & SOFTAP_MODE)
|
||||
{
|
||||
wifi_get_ip_info(SOFTAP_IF, &ip_info);
|
||||
IPAddress infoIp(ip_info.ip);
|
||||
IPAddress infoMask(ip_info.netmask);
|
||||
if (ip_info.ip.addr && ip_addr_netcmp((const ip_addr_t*)remote_ip, (const ip_addr_t*)infoIp, ip_2_ip4((const ip_addr_t*)infoMask)))
|
||||
{
|
||||
match_ap = true;
|
||||
}
|
||||
}
|
||||
if (!match_ap)
|
||||
{
|
||||
wifi_get_ip_info(STATION_IF, &ip_info);
|
||||
}
|
||||
uint32_t ip = ip_info.ip.addr;
|
||||
|
||||
// Header
|
||||
uint8_t header[] = {
|
||||
uint8_t header[] =
|
||||
{
|
||||
(uint8_t)(id >> 8), (uint8_t)(id & 0xff), // ID
|
||||
(uint8_t)(FLAGS_QR >> 8), 0, // FLAGS
|
||||
0, 1, // QDCOUNT
|
||||
@ -258,17 +290,20 @@ void LLMNRResponder::_process_packet() {
|
||||
// Question
|
||||
_conn->append(reinterpret_cast<const char*>(&namelen), 1);
|
||||
_conn->append(qname, namelen);
|
||||
uint8_t q[] = {
|
||||
uint8_t q[] =
|
||||
{
|
||||
0, // Name terminator
|
||||
0, 1, // TYPE (A)
|
||||
0, 1, // CLASS (IN)
|
||||
};
|
||||
_conn->append(reinterpret_cast<const char*>(q), sizeof(q));
|
||||
// Answer, if we have one
|
||||
if (have_rr) {
|
||||
if (have_rr)
|
||||
{
|
||||
_conn->append(reinterpret_cast<const char*>(&namelen), 1);
|
||||
_conn->append(qname, namelen);
|
||||
uint8_t rr[] = {
|
||||
uint8_t rr[] =
|
||||
{
|
||||
0, // Name terminator
|
||||
0, 1, // TYPE (A)
|
||||
0, 1, // CLASS (IN)
|
||||
|
@ -1,35 +1,35 @@
|
||||
/*
|
||||
* ESP8266 LLMNR responder
|
||||
* Copyright (C) 2017 Stephen Warren <swarren@wwwdotorg.org>
|
||||
*
|
||||
* Based on:
|
||||
* ESP8266 Multicast DNS (port of CC3000 Multicast DNS library)
|
||||
* Version 1.1
|
||||
* Copyright (c) 2013 Tony DiCola (tony@tonydicola.com)
|
||||
* ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com)
|
||||
* MDNS-SD Suport 2015 Hristo Gochkov
|
||||
* Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com)
|
||||
*
|
||||
* License (MIT license):
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
ESP8266 LLMNR responder
|
||||
Copyright (C) 2017 Stephen Warren <swarren@wwwdotorg.org>
|
||||
|
||||
Based on:
|
||||
ESP8266 Multicast DNS (port of CC3000 Multicast DNS library)
|
||||
Version 1.1
|
||||
Copyright (c) 2013 Tony DiCola (tony@tonydicola.com)
|
||||
ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com)
|
||||
MDNS-SD Suport 2015 Hristo Gochkov
|
||||
Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com)
|
||||
|
||||
License (MIT license):
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef ESP8266LLMNR_H
|
||||
#define ESP8266LLMNR_H
|
||||
@ -38,7 +38,8 @@
|
||||
|
||||
class UdpContext;
|
||||
|
||||
class LLMNRResponder {
|
||||
class LLMNRResponder
|
||||
{
|
||||
public:
|
||||
LLMNRResponder();
|
||||
~LLMNRResponder();
|
||||
|
@ -1,279 +1,302 @@
|
||||
/* Klient sluzby NBNS
|
||||
*/
|
||||
|
||||
#include "ESP8266NetBIOS.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
extern "C" {
|
||||
#include "osapi.h"
|
||||
#include "ets_sys.h"
|
||||
#include "user_interface.h"
|
||||
}
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/udp.h"
|
||||
|
||||
#define NBNSQ_TYPE_NB (0x0020)
|
||||
#define NBNSQ_CLASS_IN (0x0001)
|
||||
#ifndef LWIP_PLATFORM_HTONS
|
||||
#define LWIP_PLATFORM_HTONS(_n) ((u16_t)((((_n) & 0xff) << 8) | (((_n) >> 8) & 0xff)))
|
||||
#endif
|
||||
#ifndef LWIP_PLATFORM_HTONL
|
||||
#define LWIP_PLATFORM_HTONL(_n) ((u32_t)( (((_n) & 0xff) << 24) | (((_n) & 0xff00) << 8) | (((_n) >> 8) & 0xff00) | (((_n) >> 24) & 0xff) ))
|
||||
#endif
|
||||
|
||||
// Definice struktury NBNS dotazu (alespon veci, ktere jsem vypozoroval):
|
||||
struct NBNSQUESTION {
|
||||
uint16_t NBNSQ_ID; // ID dotazu
|
||||
uint8_t NBNSQ_FLAGS1;
|
||||
uint8_t NBNSQ_FLAGS2;
|
||||
uint16_t NBNSQ_QUESTIONCOUNT;
|
||||
uint16_t NBNSQ_ANSWERCOUNT;
|
||||
uint16_t NBNSQ_AUTHORITYCOUNT;
|
||||
uint16_t NBNSQ_ADDITIONALRECORDCOUNT;
|
||||
uint8_t NBNSQ_NAMESIZE; // delka nasledujiciho retezce
|
||||
char NBNSQ_NAME[32+1]; // POZOR!!! mozna tato polozka muze byt ruzne dlouha
|
||||
uint16_t NBNSQ_TYPE;
|
||||
uint16_t NBNSQ_CLASS;
|
||||
} __attribute__((packed));
|
||||
|
||||
// Definice struktury NBNS odpovedi (stejne jako u dotazu)
|
||||
struct NBNSANSWER {
|
||||
uint16_t NBNSA_ID; // ID dotazu
|
||||
uint8_t NBNSA_FLAGS1;
|
||||
uint8_t NBNSA_FLAGS2;
|
||||
uint16_t NBNSA_QUESTIONCOUNT;
|
||||
uint16_t NBNSA_ANSWERCOUNT;
|
||||
uint16_t NBNSA_AUTHORITYCOUNT;
|
||||
uint16_t NBNSA_ADDITIONALRECORDCOUNT;
|
||||
uint8_t NBNSA_NAMESIZE; // delka nasledujiciho retezce
|
||||
char NBNSA_NAME[32 + 1]; // POZOR!!! mozna tato polozka muze byt ruzne dlouha
|
||||
uint16_t NBNSA_TYPE;
|
||||
uint16_t NBNSA_CLASS;
|
||||
uint32_t NBNSA_TIMETOLIVE;
|
||||
uint16_t NBNSA_LENGTH;
|
||||
uint16_t NBNSA_NODEFLAGS; // POZOR!!! tady si nejsem moc jisty
|
||||
uint32_t NBNSA_NODEADDRESS;
|
||||
} __attribute__((packed));
|
||||
|
||||
// Definice struktury NBNS odpovedi na dotaz na jmeno
|
||||
struct NBNSANSWERN {
|
||||
uint16_t NBNSAN_ID; // ID dotazu
|
||||
uint8_t NBNSAN_FLAGS1;
|
||||
uint8_t NBNSAN_FLAGS2;
|
||||
uint16_t NBNSAN_QUESTIONCOUNT;
|
||||
uint16_t NBNSAN_ANSWERCOUNT;
|
||||
uint16_t NBNSAN_AUTHORITYCOUNT;
|
||||
uint16_t NBNSAN_ADDITIONALRECORDCOUNT;
|
||||
uint8_t NBNSAN_NAMESIZE; // delka nasledujiciho retezce
|
||||
char NBNSAN_NAME[32 + 1]; // POZOR!!! mozna tato polozka muze byt ruzne dlouha
|
||||
uint16_t NBNSAN_TYPE;
|
||||
uint16_t NBNSAN_CLASS;
|
||||
uint32_t NBNSAN_TIMETOLIVE;
|
||||
uint16_t NBNSAN_LENGTH;
|
||||
uint8_t NBNSAN_NUMBER; // number of names
|
||||
char NBNSAN_NNAME[15]; // jmeno nodu
|
||||
uint8_t NBNSAN_NTYPE; // typ jmena
|
||||
uint16_t NBNSAN_NFLAGS; // node flags
|
||||
} __attribute__((packed));
|
||||
|
||||
/** Metoda pro ziskani jmena z kodovani NETBIOS.
|
||||
* \param nbname Ukazatel na jmeno v NETBIOS kodovani.
|
||||
* \param name Ukazatel na misto, kam prevadime jmeno.
|
||||
* \param maxlen Maximalni pocet znaku v nbname.
|
||||
*/
|
||||
void ESP8266NetBIOS::_getnbname(char *nbname, char *name, uint8_t maxlen)
|
||||
{
|
||||
uint8_t b;
|
||||
uint8_t c = 0;
|
||||
|
||||
while ((*nbname != 0x0) && (c < maxlen)) {
|
||||
b = (*nbname++ - 'A') << 4; // opravime nibble a prevedeme ho do vyssich bitu
|
||||
c++; // pocitame pocet odebranych bytu
|
||||
if (*nbname != 0x0) {
|
||||
b |= *nbname++ - 'A'; // pridame nizsi nibble
|
||||
c++; // opet spocitame pocet odebranych znaku
|
||||
}
|
||||
*name++ = b; // ulozime znak do vysledku a posuneme ukazatel
|
||||
}
|
||||
*name = 0x0; // ulozime ukoncovaci 0
|
||||
}
|
||||
|
||||
/** Prevod zadaneho textu do NETBIOS kodovani
|
||||
* \param name Ukazatel na prevadene jmeno.
|
||||
* \param nbname Ukazatel na misto, kam vytvarime jmeno.
|
||||
* \param outlen Pocet vystupnich znaku (mimo ukoncovaci 0) musi byt delitelne 2
|
||||
*/
|
||||
void ESP8266NetBIOS::_makenbname(char *name, char *nbname, uint8_t outlen)
|
||||
{
|
||||
uint8_t b;
|
||||
uint8_t c = 0;
|
||||
|
||||
while (c < (outlen - 2)) {
|
||||
b = *name; // prevadeny znak
|
||||
if (b) {
|
||||
name++; // zatim se posunujeme
|
||||
} else {
|
||||
b = 0x20; // konec retezce je nahrazeny mezerou
|
||||
}
|
||||
*nbname++ = (b >> 4) + 'A'; // jeden nibble ze znaku
|
||||
*nbname++ = (b & 0xf) + 'A'; // druhy nibble ze znaku
|
||||
c += 2; // pocet prevedenych znaku
|
||||
}
|
||||
*nbname++ = 'A';
|
||||
*nbname++ = 'A'; // ulozime ukoncovaci 0 v NBNS kodovani
|
||||
*nbname = 0; // ulozime ukoncovaci 0 retezce
|
||||
}
|
||||
|
||||
ESP8266NetBIOS::ESP8266NetBIOS():_pcb(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
ESP8266NetBIOS::~ESP8266NetBIOS()
|
||||
{
|
||||
end();
|
||||
}
|
||||
|
||||
// Vytvoreni a otevreni UDP soketu, pokud jeste neni...
|
||||
bool ESP8266NetBIOS::begin(const char *name)
|
||||
{
|
||||
size_t n = strlen(name);
|
||||
if (n > sizeof(_name)) {
|
||||
// prilis dlouhe jmeno
|
||||
return false;
|
||||
}
|
||||
|
||||
// presuneme jmeno zarizeni se soucasnou upravou na UPPER case
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
_name[i] = toupper(name[i]);
|
||||
}
|
||||
_name[n] = '\0';
|
||||
|
||||
if(_pcb != NULL) {
|
||||
return true;
|
||||
}
|
||||
_pcb = udp_new();
|
||||
udp_recv(_pcb, &_s_recv, (void *) this);
|
||||
err_t err = udp_bind(_pcb, INADDR_ANY, NBNS_PORT);
|
||||
if(err != ERR_OK) {
|
||||
end();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ESP8266NetBIOS::end()
|
||||
{
|
||||
if(_pcb != NULL) {
|
||||
udp_remove(_pcb);
|
||||
_pcb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ESP8266NetBIOS::_recv(udp_pcb *upcb, pbuf *pb, CONST ip_addr_t *addr, uint16_t port)
|
||||
{
|
||||
(void)upcb;
|
||||
(void)addr;
|
||||
(void)port;
|
||||
while(pb != NULL) {
|
||||
uint8_t * data = (uint8_t*)((pb)->payload);
|
||||
size_t len = pb->len;
|
||||
/* Klient sluzby NBNS
|
||||
*/
|
||||
|
||||
#include "ESP8266NetBIOS.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
extern "C" {
|
||||
#include "osapi.h"
|
||||
#include "ets_sys.h"
|
||||
#include "user_interface.h"
|
||||
}
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/udp.h"
|
||||
|
||||
#define NBNSQ_TYPE_NB (0x0020)
|
||||
#define NBNSQ_CLASS_IN (0x0001)
|
||||
#ifndef LWIP_PLATFORM_HTONS
|
||||
#define LWIP_PLATFORM_HTONS(_n) ((u16_t)((((_n) & 0xff) << 8) | (((_n) >> 8) & 0xff)))
|
||||
#endif
|
||||
#ifndef LWIP_PLATFORM_HTONL
|
||||
#define LWIP_PLATFORM_HTONL(_n) ((u32_t)( (((_n) & 0xff) << 24) | (((_n) & 0xff00) << 8) | (((_n) >> 8) & 0xff00) | (((_n) >> 24) & 0xff) ))
|
||||
#endif
|
||||
|
||||
// Definice struktury NBNS dotazu (alespon veci, ktere jsem vypozoroval):
|
||||
struct NBNSQUESTION
|
||||
{
|
||||
uint16_t NBNSQ_ID; // ID dotazu
|
||||
uint8_t NBNSQ_FLAGS1;
|
||||
uint8_t NBNSQ_FLAGS2;
|
||||
uint16_t NBNSQ_QUESTIONCOUNT;
|
||||
uint16_t NBNSQ_ANSWERCOUNT;
|
||||
uint16_t NBNSQ_AUTHORITYCOUNT;
|
||||
uint16_t NBNSQ_ADDITIONALRECORDCOUNT;
|
||||
uint8_t NBNSQ_NAMESIZE; // delka nasledujiciho retezce
|
||||
char NBNSQ_NAME[32 + 1]; // POZOR!!! mozna tato polozka muze byt ruzne dlouha
|
||||
uint16_t NBNSQ_TYPE;
|
||||
uint16_t NBNSQ_CLASS;
|
||||
} __attribute__((packed));
|
||||
|
||||
// Definice struktury NBNS odpovedi (stejne jako u dotazu)
|
||||
struct NBNSANSWER
|
||||
{
|
||||
uint16_t NBNSA_ID; // ID dotazu
|
||||
uint8_t NBNSA_FLAGS1;
|
||||
uint8_t NBNSA_FLAGS2;
|
||||
uint16_t NBNSA_QUESTIONCOUNT;
|
||||
uint16_t NBNSA_ANSWERCOUNT;
|
||||
uint16_t NBNSA_AUTHORITYCOUNT;
|
||||
uint16_t NBNSA_ADDITIONALRECORDCOUNT;
|
||||
uint8_t NBNSA_NAMESIZE; // delka nasledujiciho retezce
|
||||
char NBNSA_NAME[32 + 1]; // POZOR!!! mozna tato polozka muze byt ruzne dlouha
|
||||
uint16_t NBNSA_TYPE;
|
||||
uint16_t NBNSA_CLASS;
|
||||
uint32_t NBNSA_TIMETOLIVE;
|
||||
uint16_t NBNSA_LENGTH;
|
||||
uint16_t NBNSA_NODEFLAGS; // POZOR!!! tady si nejsem moc jisty
|
||||
uint32_t NBNSA_NODEADDRESS;
|
||||
} __attribute__((packed));
|
||||
|
||||
// Definice struktury NBNS odpovedi na dotaz na jmeno
|
||||
struct NBNSANSWERN
|
||||
{
|
||||
uint16_t NBNSAN_ID; // ID dotazu
|
||||
uint8_t NBNSAN_FLAGS1;
|
||||
uint8_t NBNSAN_FLAGS2;
|
||||
uint16_t NBNSAN_QUESTIONCOUNT;
|
||||
uint16_t NBNSAN_ANSWERCOUNT;
|
||||
uint16_t NBNSAN_AUTHORITYCOUNT;
|
||||
uint16_t NBNSAN_ADDITIONALRECORDCOUNT;
|
||||
uint8_t NBNSAN_NAMESIZE; // delka nasledujiciho retezce
|
||||
char NBNSAN_NAME[32 + 1]; // POZOR!!! mozna tato polozka muze byt ruzne dlouha
|
||||
uint16_t NBNSAN_TYPE;
|
||||
uint16_t NBNSAN_CLASS;
|
||||
uint32_t NBNSAN_TIMETOLIVE;
|
||||
uint16_t NBNSAN_LENGTH;
|
||||
uint8_t NBNSAN_NUMBER; // number of names
|
||||
char NBNSAN_NNAME[15]; // jmeno nodu
|
||||
uint8_t NBNSAN_NTYPE; // typ jmena
|
||||
uint16_t NBNSAN_NFLAGS; // node flags
|
||||
} __attribute__((packed));
|
||||
|
||||
/** Metoda pro ziskani jmena z kodovani NETBIOS.
|
||||
\param nbname Ukazatel na jmeno v NETBIOS kodovani.
|
||||
\param name Ukazatel na misto, kam prevadime jmeno.
|
||||
\param maxlen Maximalni pocet znaku v nbname.
|
||||
*/
|
||||
void ESP8266NetBIOS::_getnbname(char *nbname, char *name, uint8_t maxlen)
|
||||
{
|
||||
uint8_t b;
|
||||
uint8_t c = 0;
|
||||
|
||||
while ((*nbname != 0x0) && (c < maxlen))
|
||||
{
|
||||
b = (*nbname++ - 'A') << 4; // opravime nibble a prevedeme ho do vyssich bitu
|
||||
c++; // pocitame pocet odebranych bytu
|
||||
if (*nbname != 0x0)
|
||||
{
|
||||
b |= *nbname++ - 'A'; // pridame nizsi nibble
|
||||
c++; // opet spocitame pocet odebranych znaku
|
||||
}
|
||||
*name++ = b; // ulozime znak do vysledku a posuneme ukazatel
|
||||
}
|
||||
*name = 0x0; // ulozime ukoncovaci 0
|
||||
}
|
||||
|
||||
/** Prevod zadaneho textu do NETBIOS kodovani
|
||||
\param name Ukazatel na prevadene jmeno.
|
||||
\param nbname Ukazatel na misto, kam vytvarime jmeno.
|
||||
\param outlen Pocet vystupnich znaku (mimo ukoncovaci 0) musi byt delitelne 2
|
||||
*/
|
||||
void ESP8266NetBIOS::_makenbname(char *name, char *nbname, uint8_t outlen)
|
||||
{
|
||||
uint8_t b;
|
||||
uint8_t c = 0;
|
||||
|
||||
while (c < (outlen - 2))
|
||||
{
|
||||
b = *name; // prevadeny znak
|
||||
if (b)
|
||||
{
|
||||
name++; // zatim se posunujeme
|
||||
}
|
||||
else
|
||||
{
|
||||
b = 0x20; // konec retezce je nahrazeny mezerou
|
||||
}
|
||||
*nbname++ = (b >> 4) + 'A'; // jeden nibble ze znaku
|
||||
*nbname++ = (b & 0xf) + 'A'; // druhy nibble ze znaku
|
||||
c += 2; // pocet prevedenych znaku
|
||||
}
|
||||
*nbname++ = 'A';
|
||||
*nbname++ = 'A'; // ulozime ukoncovaci 0 v NBNS kodovani
|
||||
*nbname = 0; // ulozime ukoncovaci 0 retezce
|
||||
}
|
||||
|
||||
ESP8266NetBIOS::ESP8266NetBIOS(): _pcb(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
ESP8266NetBIOS::~ESP8266NetBIOS()
|
||||
{
|
||||
end();
|
||||
}
|
||||
|
||||
// Vytvoreni a otevreni UDP soketu, pokud jeste neni...
|
||||
bool ESP8266NetBIOS::begin(const char *name)
|
||||
{
|
||||
size_t n = strlen(name);
|
||||
if (n > sizeof(_name))
|
||||
{
|
||||
// prilis dlouhe jmeno
|
||||
return false;
|
||||
}
|
||||
|
||||
// presuneme jmeno zarizeni se soucasnou upravou na UPPER case
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
_name[i] = toupper(name[i]);
|
||||
}
|
||||
_name[n] = '\0';
|
||||
|
||||
if (_pcb != NULL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
_pcb = udp_new();
|
||||
udp_recv(_pcb, &_s_recv, (void *) this);
|
||||
err_t err = udp_bind(_pcb, INADDR_ANY, NBNS_PORT);
|
||||
if (err != ERR_OK)
|
||||
{
|
||||
end();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ESP8266NetBIOS::end()
|
||||
{
|
||||
if (_pcb != NULL)
|
||||
{
|
||||
udp_remove(_pcb);
|
||||
_pcb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ESP8266NetBIOS::_recv(udp_pcb *upcb, pbuf *pb, CONST ip_addr_t *addr, uint16_t port)
|
||||
{
|
||||
(void)upcb;
|
||||
(void)addr;
|
||||
(void)port;
|
||||
while (pb != NULL)
|
||||
{
|
||||
uint8_t * data = (uint8_t*)((pb)->payload);
|
||||
size_t len = pb->len;
|
||||
#if LWIP_VERSION_MAJOR == 1
|
||||
// check UdpContext.h
|
||||
// check UdpContext.h
|
||||
ip_addr_t* saddr = ¤t_iphdr_src;
|
||||
#else
|
||||
// check UdpContext.h
|
||||
// check UdpContext.h
|
||||
const ip_addr_t* saddr = &ip_data.current_iphdr_src;
|
||||
#endif
|
||||
|
||||
if (len >= sizeof(struct NBNSQUESTION)) {
|
||||
struct NBNSQUESTION * question = (struct NBNSQUESTION *)data;
|
||||
if (0 == (question->NBNSQ_FLAGS1 & 0x80)) {
|
||||
char name[ NBNS_MAX_HOSTNAME_LEN + 1 ]; // dekodovane dotazovane jmeno
|
||||
char *str; // pomocna promenna, pouze pro praci s retezcem
|
||||
|
||||
_getnbname(&question->NBNSQ_NAME[0], (char *)&name, question->NBNSQ_NAMESIZE); // prevedeme dotazovane jmeno
|
||||
if ((str = strchr(name, ' ')) != NULL) { // jmeno hledaneho zarizeni v tomto pripade ukoncuje i mezera
|
||||
*str = '\0'; // ukoncime retezec na vyskytu prvni mezery
|
||||
}
|
||||
|
||||
if (0 == strcmp(name, _name)) {
|
||||
// dotaz primo na nas
|
||||
struct NBNSANSWER nbnsa; // buffer, do ktereho je sestavena odpoved na dotaz
|
||||
|
||||
nbnsa.NBNSA_ID = question->NBNSQ_ID;// ID dotazu kopirujeme do ID odpovedi
|
||||
nbnsa.NBNSA_FLAGS1 = 0x85; // priznak odpovedi
|
||||
nbnsa.NBNSA_FLAGS2 = 0; // vlajky 2 a response code
|
||||
nbnsa.NBNSA_QUESTIONCOUNT = LWIP_PLATFORM_HTONS(0);
|
||||
nbnsa.NBNSA_ANSWERCOUNT = LWIP_PLATFORM_HTONS(1);// poradove cislo odpovedi
|
||||
nbnsa.NBNSA_AUTHORITYCOUNT = LWIP_PLATFORM_HTONS(0);
|
||||
nbnsa.NBNSA_ADDITIONALRECORDCOUNT = LWIP_PLATFORM_HTONS(0);
|
||||
nbnsa.NBNSA_NAMESIZE = sizeof(nbnsa.NBNSA_NAME) - 1; // prekopirujeme delku jmena stanice
|
||||
_makenbname(_name, &nbnsa.NBNSA_NAME[0], sizeof(nbnsa.NBNSA_NAME) - 1); // prevedeme jmeno
|
||||
nbnsa.NBNSA_TYPE = LWIP_PLATFORM_HTONS(0x20); // NetBIOS name
|
||||
nbnsa.NBNSA_CLASS = LWIP_PLATFORM_HTONS(1); // Internet name
|
||||
nbnsa.NBNSA_TIMETOLIVE = LWIP_PLATFORM_HTONL(300000UL);// Time to live (30000 sekund)
|
||||
nbnsa.NBNSA_LENGTH = LWIP_PLATFORM_HTONS(6);
|
||||
nbnsa.NBNSA_NODEFLAGS = LWIP_PLATFORM_HTONS(0);
|
||||
nbnsa.NBNSA_NODEADDRESS = WiFi.localIP(); // ulozime nasi IP adresu
|
||||
|
||||
pbuf* pbt = pbuf_alloc(PBUF_TRANSPORT, sizeof(nbnsa), PBUF_RAM);
|
||||
if(pbt != NULL) {
|
||||
uint8_t* dst = reinterpret_cast<uint8_t*>(pbt->payload);
|
||||
memcpy(dst, (uint8_t *)&nbnsa, sizeof(nbnsa));
|
||||
udp_sendto(_pcb, pbt, saddr, NBNS_PORT);
|
||||
pbuf_free(pbt);
|
||||
}
|
||||
} else if (0 == strcmp(name, "*")) {
|
||||
// obecny dotaz - mireny nejspis na nasi IP adresu
|
||||
struct NBNSANSWERN nbnsan; // buffer, do ktereho je sestavena odpoved na dotaz
|
||||
|
||||
nbnsan.NBNSAN_ID = question->NBNSQ_ID;// ID dotazu kopirujeme do ID odpovedi
|
||||
nbnsan.NBNSAN_FLAGS1 = 0x84; // priznak odpovedi
|
||||
nbnsan.NBNSAN_FLAGS2 = 0; // vlajky 2 a response code
|
||||
nbnsan.NBNSAN_QUESTIONCOUNT = LWIP_PLATFORM_HTONS(0);
|
||||
nbnsan.NBNSAN_ANSWERCOUNT = LWIP_PLATFORM_HTONS(1);// poradove cislo odpovedi
|
||||
nbnsan.NBNSAN_AUTHORITYCOUNT = LWIP_PLATFORM_HTONS(0);
|
||||
nbnsan.NBNSAN_ADDITIONALRECORDCOUNT = LWIP_PLATFORM_HTONS(0);
|
||||
nbnsan.NBNSAN_NAMESIZE = question->NBNSQ_NAMESIZE; // prekopirujeme delku jmena stanice
|
||||
memcpy(nbnsan.NBNSAN_NAME, question->NBNSQ_NAME, sizeof(nbnsan.NBNSAN_NAME)); // prekopirujeme dotazovane jmeno
|
||||
nbnsan.NBNSAN_TYPE = LWIP_PLATFORM_HTONS(0x21); // NBSTAT
|
||||
nbnsan.NBNSAN_CLASS = LWIP_PLATFORM_HTONS(1); // Internet name
|
||||
nbnsan.NBNSAN_TIMETOLIVE = LWIP_PLATFORM_HTONL(0);
|
||||
nbnsan.NBNSAN_LENGTH = LWIP_PLATFORM_HTONS(4 + sizeof(nbnsan.NBNSAN_NNAME));
|
||||
nbnsan.NBNSAN_NUMBER = 1; // Number of names
|
||||
memset(nbnsan.NBNSAN_NNAME, 0x20, sizeof(nbnsan.NBNSAN_NNAME));
|
||||
memcpy(nbnsan.NBNSAN_NNAME, _name, strlen(_name));
|
||||
nbnsan.NBNSAN_NTYPE = 0; // Workstation/Redirector
|
||||
nbnsan.NBNSAN_NFLAGS = LWIP_PLATFORM_HTONS(0x400); // b-node, unique, active
|
||||
|
||||
pbuf* pbt = pbuf_alloc(PBUF_TRANSPORT, sizeof(nbnsan), PBUF_RAM);
|
||||
if(pbt != NULL) {
|
||||
uint8_t* dst = reinterpret_cast<uint8_t*>(pbt->payload);
|
||||
memcpy(dst, (uint8_t *)&nbnsan, sizeof(nbnsan));
|
||||
udp_sendto(_pcb, pbt, saddr, NBNS_PORT);
|
||||
pbuf_free(pbt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pbuf * this_pb = pb;
|
||||
pb = pb->next;
|
||||
this_pb->next = NULL;
|
||||
pbuf_free(this_pb);
|
||||
}
|
||||
}
|
||||
|
||||
void ESP8266NetBIOS::_s_recv(void *arg, udp_pcb *upcb, pbuf *p, CONST ip_addr_t *addr, uint16_t port)
|
||||
{
|
||||
reinterpret_cast<ESP8266NetBIOS*>(arg)->_recv(upcb, p, addr, port);
|
||||
}
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_NETBIOS)
|
||||
ESP8266NetBIOS NBNS;
|
||||
#endif
|
||||
|
||||
// EOF
|
||||
|
||||
if (len >= sizeof(struct NBNSQUESTION))
|
||||
{
|
||||
struct NBNSQUESTION * question = (struct NBNSQUESTION *)data;
|
||||
if (0 == (question->NBNSQ_FLAGS1 & 0x80))
|
||||
{
|
||||
char name[ NBNS_MAX_HOSTNAME_LEN + 1 ]; // dekodovane dotazovane jmeno
|
||||
char *str; // pomocna promenna, pouze pro praci s retezcem
|
||||
|
||||
_getnbname(&question->NBNSQ_NAME[0], (char *)&name, question->NBNSQ_NAMESIZE); // prevedeme dotazovane jmeno
|
||||
if ((str = strchr(name, ' ')) != NULL) // jmeno hledaneho zarizeni v tomto pripade ukoncuje i mezera
|
||||
{
|
||||
*str = '\0'; // ukoncime retezec na vyskytu prvni mezery
|
||||
}
|
||||
|
||||
if (0 == strcmp(name, _name))
|
||||
{
|
||||
// dotaz primo na nas
|
||||
struct NBNSANSWER nbnsa; // buffer, do ktereho je sestavena odpoved na dotaz
|
||||
|
||||
nbnsa.NBNSA_ID = question->NBNSQ_ID;// ID dotazu kopirujeme do ID odpovedi
|
||||
nbnsa.NBNSA_FLAGS1 = 0x85; // priznak odpovedi
|
||||
nbnsa.NBNSA_FLAGS2 = 0; // vlajky 2 a response code
|
||||
nbnsa.NBNSA_QUESTIONCOUNT = LWIP_PLATFORM_HTONS(0);
|
||||
nbnsa.NBNSA_ANSWERCOUNT = LWIP_PLATFORM_HTONS(1);// poradove cislo odpovedi
|
||||
nbnsa.NBNSA_AUTHORITYCOUNT = LWIP_PLATFORM_HTONS(0);
|
||||
nbnsa.NBNSA_ADDITIONALRECORDCOUNT = LWIP_PLATFORM_HTONS(0);
|
||||
nbnsa.NBNSA_NAMESIZE = sizeof(nbnsa.NBNSA_NAME) - 1; // prekopirujeme delku jmena stanice
|
||||
_makenbname(_name, &nbnsa.NBNSA_NAME[0], sizeof(nbnsa.NBNSA_NAME) - 1); // prevedeme jmeno
|
||||
nbnsa.NBNSA_TYPE = LWIP_PLATFORM_HTONS(0x20); // NetBIOS name
|
||||
nbnsa.NBNSA_CLASS = LWIP_PLATFORM_HTONS(1); // Internet name
|
||||
nbnsa.NBNSA_TIMETOLIVE = LWIP_PLATFORM_HTONL(300000UL);// Time to live (30000 sekund)
|
||||
nbnsa.NBNSA_LENGTH = LWIP_PLATFORM_HTONS(6);
|
||||
nbnsa.NBNSA_NODEFLAGS = LWIP_PLATFORM_HTONS(0);
|
||||
nbnsa.NBNSA_NODEADDRESS = WiFi.localIP(); // ulozime nasi IP adresu
|
||||
|
||||
pbuf* pbt = pbuf_alloc(PBUF_TRANSPORT, sizeof(nbnsa), PBUF_RAM);
|
||||
if (pbt != NULL)
|
||||
{
|
||||
uint8_t* dst = reinterpret_cast<uint8_t*>(pbt->payload);
|
||||
memcpy(dst, (uint8_t *)&nbnsa, sizeof(nbnsa));
|
||||
udp_sendto(_pcb, pbt, saddr, NBNS_PORT);
|
||||
pbuf_free(pbt);
|
||||
}
|
||||
}
|
||||
else if (0 == strcmp(name, "*"))
|
||||
{
|
||||
// obecny dotaz - mireny nejspis na nasi IP adresu
|
||||
struct NBNSANSWERN nbnsan; // buffer, do ktereho je sestavena odpoved na dotaz
|
||||
|
||||
nbnsan.NBNSAN_ID = question->NBNSQ_ID;// ID dotazu kopirujeme do ID odpovedi
|
||||
nbnsan.NBNSAN_FLAGS1 = 0x84; // priznak odpovedi
|
||||
nbnsan.NBNSAN_FLAGS2 = 0; // vlajky 2 a response code
|
||||
nbnsan.NBNSAN_QUESTIONCOUNT = LWIP_PLATFORM_HTONS(0);
|
||||
nbnsan.NBNSAN_ANSWERCOUNT = LWIP_PLATFORM_HTONS(1);// poradove cislo odpovedi
|
||||
nbnsan.NBNSAN_AUTHORITYCOUNT = LWIP_PLATFORM_HTONS(0);
|
||||
nbnsan.NBNSAN_ADDITIONALRECORDCOUNT = LWIP_PLATFORM_HTONS(0);
|
||||
nbnsan.NBNSAN_NAMESIZE = question->NBNSQ_NAMESIZE; // prekopirujeme delku jmena stanice
|
||||
memcpy(nbnsan.NBNSAN_NAME, question->NBNSQ_NAME, sizeof(nbnsan.NBNSAN_NAME)); // prekopirujeme dotazovane jmeno
|
||||
nbnsan.NBNSAN_TYPE = LWIP_PLATFORM_HTONS(0x21); // NBSTAT
|
||||
nbnsan.NBNSAN_CLASS = LWIP_PLATFORM_HTONS(1); // Internet name
|
||||
nbnsan.NBNSAN_TIMETOLIVE = LWIP_PLATFORM_HTONL(0);
|
||||
nbnsan.NBNSAN_LENGTH = LWIP_PLATFORM_HTONS(4 + sizeof(nbnsan.NBNSAN_NNAME));
|
||||
nbnsan.NBNSAN_NUMBER = 1; // Number of names
|
||||
memset(nbnsan.NBNSAN_NNAME, 0x20, sizeof(nbnsan.NBNSAN_NNAME));
|
||||
memcpy(nbnsan.NBNSAN_NNAME, _name, strlen(_name));
|
||||
nbnsan.NBNSAN_NTYPE = 0; // Workstation/Redirector
|
||||
nbnsan.NBNSAN_NFLAGS = LWIP_PLATFORM_HTONS(0x400); // b-node, unique, active
|
||||
|
||||
pbuf* pbt = pbuf_alloc(PBUF_TRANSPORT, sizeof(nbnsan), PBUF_RAM);
|
||||
if (pbt != NULL)
|
||||
{
|
||||
uint8_t* dst = reinterpret_cast<uint8_t*>(pbt->payload);
|
||||
memcpy(dst, (uint8_t *)&nbnsan, sizeof(nbnsan));
|
||||
udp_sendto(_pcb, pbt, saddr, NBNS_PORT);
|
||||
pbuf_free(pbt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pbuf * this_pb = pb;
|
||||
pb = pb->next;
|
||||
this_pb->next = NULL;
|
||||
pbuf_free(this_pb);
|
||||
}
|
||||
}
|
||||
|
||||
void ESP8266NetBIOS::_s_recv(void *arg, udp_pcb *upcb, pbuf *p, CONST ip_addr_t *addr, uint16_t port)
|
||||
{
|
||||
reinterpret_cast<ESP8266NetBIOS*>(arg)->_recv(upcb, p, addr, port);
|
||||
}
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_NETBIOS)
|
||||
ESP8266NetBIOS NBNS;
|
||||
#endif
|
||||
|
||||
// EOF
|
||||
|
@ -1,45 +1,45 @@
|
||||
//
|
||||
#ifndef __ESPNBNS_h__
|
||||
#define __ESPNBNS_h__
|
||||
|
||||
extern "C" {
|
||||
#include "lwip/init.h" // LWIP_VERSION_
|
||||
#include <lwip/ip_addr.h>
|
||||
}
|
||||
#include <ESP8266WiFi.h>
|
||||
|
||||
#define NBNS_PORT 137
|
||||
/**
|
||||
* @def NBNS_MAX_HOSTNAME_LEN
|
||||
* @brief maximalni delka NBNS jmena zarizeni
|
||||
* @remarks
|
||||
* Jmeno zarizeni musi byt uvedeno VELKYMI pismenami a nesmi obsahovat mezery (whitespaces).
|
||||
*/
|
||||
#define NBNS_MAX_HOSTNAME_LEN 16
|
||||
|
||||
struct udp_pcb;
|
||||
struct pbuf;
|
||||
|
||||
class ESP8266NetBIOS
|
||||
{
|
||||
protected:
|
||||
udp_pcb* _pcb;
|
||||
char _name[NBNS_MAX_HOSTNAME_LEN + 1];
|
||||
void _getnbname(char *nbname, char *name, uint8_t maxlen);
|
||||
void _makenbname(char *name, char *nbname, uint8_t outlen);
|
||||
|
||||
void _recv(udp_pcb *upcb, pbuf *pb, CONST ip_addr_t *addr, uint16_t port);
|
||||
static void _s_recv(void *arg, udp_pcb *upcb, pbuf *p, CONST ip_addr_t *addr, uint16_t port);
|
||||
|
||||
public:
|
||||
ESP8266NetBIOS();
|
||||
~ESP8266NetBIOS();
|
||||
bool begin(const char *name);
|
||||
void end();
|
||||
};
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_NETBIOS)
|
||||
extern ESP8266NetBIOS NBNS;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
//
|
||||
#ifndef __ESPNBNS_h__
|
||||
#define __ESPNBNS_h__
|
||||
|
||||
extern "C" {
|
||||
#include "lwip/init.h" // LWIP_VERSION_
|
||||
#include <lwip/ip_addr.h>
|
||||
}
|
||||
#include <ESP8266WiFi.h>
|
||||
|
||||
#define NBNS_PORT 137
|
||||
/**
|
||||
@def NBNS_MAX_HOSTNAME_LEN
|
||||
@brief maximalni delka NBNS jmena zarizeni
|
||||
@remarks
|
||||
Jmeno zarizeni musi byt uvedeno VELKYMI pismenami a nesmi obsahovat mezery (whitespaces).
|
||||
*/
|
||||
#define NBNS_MAX_HOSTNAME_LEN 16
|
||||
|
||||
struct udp_pcb;
|
||||
struct pbuf;
|
||||
|
||||
class ESP8266NetBIOS
|
||||
{
|
||||
protected:
|
||||
udp_pcb* _pcb;
|
||||
char _name[NBNS_MAX_HOSTNAME_LEN + 1];
|
||||
void _getnbname(char *nbname, char *name, uint8_t maxlen);
|
||||
void _makenbname(char *name, char *nbname, uint8_t outlen);
|
||||
|
||||
void _recv(udp_pcb *upcb, pbuf *pb, CONST ip_addr_t *addr, uint16_t port);
|
||||
static void _s_recv(void *arg, udp_pcb *upcb, pbuf *p, CONST ip_addr_t *addr, uint16_t port);
|
||||
|
||||
public:
|
||||
ESP8266NetBIOS();
|
||||
~ESP8266NetBIOS();
|
||||
bool begin(const char *name);
|
||||
void end();
|
||||
};
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_NETBIOS)
|
||||
extern ESP8266NetBIOS NBNS;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -1,28 +1,28 @@
|
||||
/*
|
||||
ESP8266 Simple Service Discovery
|
||||
Copyright (c) 2015 Hristo Gochkov
|
||||
ESP8266 Simple Service Discovery
|
||||
Copyright (c) 2015 Hristo Gochkov
|
||||
|
||||
Original (Arduino) version by Filippo Sallemi, July 23, 2014.
|
||||
Can be found at: https://github.com/nomadnt/uSSDP
|
||||
Original (Arduino) version by Filippo Sallemi, July 23, 2014.
|
||||
Can be found at: https://github.com/nomadnt/uSSDP
|
||||
|
||||
License (MIT license):
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
License (MIT license):
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
#ifndef LWIP_OPEN_SRC
|
||||
@ -59,467 +59,558 @@ extern "C" {
|
||||
#define SSDP_MULTICAST_ADDR 239, 255, 255, 250
|
||||
|
||||
static const char _ssdp_response_template[] PROGMEM =
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"EXT:\r\n";
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"EXT:\r\n";
|
||||
|
||||
static const char _ssdp_notify_template[] PROGMEM =
|
||||
"NOTIFY * HTTP/1.1\r\n"
|
||||
"HOST: 239.255.255.250:1900\r\n"
|
||||
"NTS: ssdp:alive\r\n";
|
||||
"NOTIFY * HTTP/1.1\r\n"
|
||||
"HOST: 239.255.255.250:1900\r\n"
|
||||
"NTS: ssdp:alive\r\n";
|
||||
|
||||
static const char _ssdp_packet_template[] PROGMEM =
|
||||
"%s" // _ssdp_response_template / _ssdp_notify_template
|
||||
"CACHE-CONTROL: max-age=%u\r\n" // SSDP_INTERVAL
|
||||
"SERVER: Arduino/1.0 UPNP/1.1 %s/%s\r\n" // _modelName, _modelNumber
|
||||
"USN: %s\r\n" // _uuid
|
||||
"%s: %s\r\n" // "NT" or "ST", _deviceType
|
||||
"LOCATION: http://%u.%u.%u.%u:%u/%s\r\n" // WiFi.localIP(), _port, _schemaURL
|
||||
"\r\n";
|
||||
"%s" // _ssdp_response_template / _ssdp_notify_template
|
||||
"CACHE-CONTROL: max-age=%u\r\n" // SSDP_INTERVAL
|
||||
"SERVER: Arduino/1.0 UPNP/1.1 %s/%s\r\n" // _modelName, _modelNumber
|
||||
"USN: %s\r\n" // _uuid
|
||||
"%s: %s\r\n" // "NT" or "ST", _deviceType
|
||||
"LOCATION: http://%u.%u.%u.%u:%u/%s\r\n" // WiFi.localIP(), _port, _schemaURL
|
||||
"\r\n";
|
||||
|
||||
static const char _ssdp_schema_template[] PROGMEM =
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: text/xml\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Access-Control-Allow-Origin: *\r\n"
|
||||
"\r\n"
|
||||
"<?xml version=\"1.0\"?>"
|
||||
"<root xmlns=\"urn:schemas-upnp-org:device-1-0\">"
|
||||
"<specVersion>"
|
||||
"<major>1</major>"
|
||||
"<minor>0</minor>"
|
||||
"</specVersion>"
|
||||
"<URLBase>http://%u.%u.%u.%u:%u/</URLBase>" // WiFi.localIP(), _port
|
||||
"<device>"
|
||||
"<deviceType>%s</deviceType>"
|
||||
"<friendlyName>%s</friendlyName>"
|
||||
"<presentationURL>%s</presentationURL>"
|
||||
"<serialNumber>%s</serialNumber>"
|
||||
"<modelName>%s</modelName>"
|
||||
"<modelNumber>%s</modelNumber>"
|
||||
"<modelURL>%s</modelURL>"
|
||||
"<manufacturer>%s</manufacturer>"
|
||||
"<manufacturerURL>%s</manufacturerURL>"
|
||||
"<UDN>%s</UDN>"
|
||||
"</device>"
|
||||
//"<iconList>"
|
||||
//"<icon>"
|
||||
//"<mimetype>image/png</mimetype>"
|
||||
//"<height>48</height>"
|
||||
//"<width>48</width>"
|
||||
//"<depth>24</depth>"
|
||||
//"<url>icon48.png</url>"
|
||||
//"</icon>"
|
||||
//"<icon>"
|
||||
//"<mimetype>image/png</mimetype>"
|
||||
//"<height>120</height>"
|
||||
//"<width>120</width>"
|
||||
//"<depth>24</depth>"
|
||||
//"<url>icon120.png</url>"
|
||||
//"</icon>"
|
||||
//"</iconList>"
|
||||
"</root>\r\n"
|
||||
"\r\n";
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: text/xml\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Access-Control-Allow-Origin: *\r\n"
|
||||
"\r\n"
|
||||
"<?xml version=\"1.0\"?>"
|
||||
"<root xmlns=\"urn:schemas-upnp-org:device-1-0\">"
|
||||
"<specVersion>"
|
||||
"<major>1</major>"
|
||||
"<minor>0</minor>"
|
||||
"</specVersion>"
|
||||
"<URLBase>http://%u.%u.%u.%u:%u/</URLBase>" // WiFi.localIP(), _port
|
||||
"<device>"
|
||||
"<deviceType>%s</deviceType>"
|
||||
"<friendlyName>%s</friendlyName>"
|
||||
"<presentationURL>%s</presentationURL>"
|
||||
"<serialNumber>%s</serialNumber>"
|
||||
"<modelName>%s</modelName>"
|
||||
"<modelNumber>%s</modelNumber>"
|
||||
"<modelURL>%s</modelURL>"
|
||||
"<manufacturer>%s</manufacturer>"
|
||||
"<manufacturerURL>%s</manufacturerURL>"
|
||||
"<UDN>%s</UDN>"
|
||||
"</device>"
|
||||
//"<iconList>"
|
||||
//"<icon>"
|
||||
//"<mimetype>image/png</mimetype>"
|
||||
//"<height>48</height>"
|
||||
//"<width>48</width>"
|
||||
//"<depth>24</depth>"
|
||||
//"<url>icon48.png</url>"
|
||||
//"</icon>"
|
||||
//"<icon>"
|
||||
//"<mimetype>image/png</mimetype>"
|
||||
//"<height>120</height>"
|
||||
//"<width>120</width>"
|
||||
//"<depth>24</depth>"
|
||||
//"<url>icon120.png</url>"
|
||||
//"</icon>"
|
||||
//"</iconList>"
|
||||
"</root>\r\n"
|
||||
"\r\n";
|
||||
|
||||
|
||||
struct SSDPTimer {
|
||||
ETSTimer timer;
|
||||
struct SSDPTimer
|
||||
{
|
||||
ETSTimer timer;
|
||||
};
|
||||
|
||||
SSDPClass::SSDPClass() :
|
||||
_server(0),
|
||||
_timer(0),
|
||||
_port(80),
|
||||
_ttl(SSDP_MULTICAST_TTL),
|
||||
_respondToAddr(0,0,0,0),
|
||||
_respondToPort(0),
|
||||
_pending(false),
|
||||
_st_is_uuid(false),
|
||||
_delay(0),
|
||||
_process_time(0),
|
||||
_notify_time(0)
|
||||
_server(0),
|
||||
_timer(0),
|
||||
_port(80),
|
||||
_ttl(SSDP_MULTICAST_TTL),
|
||||
_respondToAddr(0, 0, 0, 0),
|
||||
_respondToPort(0),
|
||||
_pending(false),
|
||||
_st_is_uuid(false),
|
||||
_delay(0),
|
||||
_process_time(0),
|
||||
_notify_time(0)
|
||||
{
|
||||
_uuid[0] = '\0';
|
||||
_modelNumber[0] = '\0';
|
||||
sprintf(_deviceType, "urn:schemas-upnp-org:device:Basic:1");
|
||||
_friendlyName[0] = '\0';
|
||||
_presentationURL[0] = '\0';
|
||||
_serialNumber[0] = '\0';
|
||||
_modelName[0] = '\0';
|
||||
_modelURL[0] = '\0';
|
||||
_manufacturer[0] = '\0';
|
||||
_manufacturerURL[0] = '\0';
|
||||
sprintf(_schemaURL, "ssdp/schema.xml");
|
||||
_uuid[0] = '\0';
|
||||
_modelNumber[0] = '\0';
|
||||
sprintf(_deviceType, "urn:schemas-upnp-org:device:Basic:1");
|
||||
_friendlyName[0] = '\0';
|
||||
_presentationURL[0] = '\0';
|
||||
_serialNumber[0] = '\0';
|
||||
_modelName[0] = '\0';
|
||||
_modelURL[0] = '\0';
|
||||
_manufacturer[0] = '\0';
|
||||
_manufacturerURL[0] = '\0';
|
||||
sprintf(_schemaURL, "ssdp/schema.xml");
|
||||
}
|
||||
|
||||
SSDPClass::~SSDPClass() {
|
||||
end();
|
||||
SSDPClass::~SSDPClass()
|
||||
{
|
||||
end();
|
||||
}
|
||||
|
||||
bool SSDPClass::begin() {
|
||||
end();
|
||||
|
||||
_pending = false;
|
||||
_st_is_uuid = false;
|
||||
if (strcmp(_uuid,"") == 0) {
|
||||
uint32_t chipId = ESP.getChipId();
|
||||
sprintf_P(_uuid, PSTR("uuid:38323636-4558-4dda-9188-cda0e6%02x%02x%02x"),
|
||||
(uint16_t) ((chipId >> 16) & 0xff),
|
||||
(uint16_t) ((chipId >> 8) & 0xff),
|
||||
(uint16_t) chipId & 0xff);
|
||||
}
|
||||
|
||||
bool SSDPClass::begin()
|
||||
{
|
||||
end();
|
||||
|
||||
_pending = false;
|
||||
_st_is_uuid = false;
|
||||
if (strcmp(_uuid, "") == 0)
|
||||
{
|
||||
uint32_t chipId = ESP.getChipId();
|
||||
sprintf_P(_uuid, PSTR("uuid:38323636-4558-4dda-9188-cda0e6%02x%02x%02x"),
|
||||
(uint16_t)((chipId >> 16) & 0xff),
|
||||
(uint16_t)((chipId >> 8) & 0xff),
|
||||
(uint16_t) chipId & 0xff);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_SSDP
|
||||
DEBUG_SSDP.printf("SSDP UUID: %s\n", (char *)_uuid);
|
||||
DEBUG_SSDP.printf("SSDP UUID: %s\n", (char *)_uuid);
|
||||
#endif
|
||||
|
||||
assert(NULL == _server);
|
||||
assert(NULL == _server);
|
||||
|
||||
_server = new UdpContext;
|
||||
_server->ref();
|
||||
_server = new UdpContext;
|
||||
_server->ref();
|
||||
|
||||
IPAddress local = WiFi.localIP();
|
||||
IPAddress mcast(SSDP_MULTICAST_ADDR);
|
||||
IPAddress local = WiFi.localIP();
|
||||
IPAddress mcast(SSDP_MULTICAST_ADDR);
|
||||
|
||||
if (igmp_joingroup(local, mcast) != ERR_OK ) {
|
||||
if (igmp_joingroup(local, mcast) != ERR_OK)
|
||||
{
|
||||
#ifdef DEBUG_SSDP
|
||||
DEBUG_SSDP.printf_P(PSTR("SSDP failed to join igmp group\n"));
|
||||
DEBUG_SSDP.printf_P(PSTR("SSDP failed to join igmp group\n"));
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_server->listen(IP_ADDR_ANY, SSDP_PORT)) {
|
||||
return false;
|
||||
}
|
||||
if (!_server->listen(IP_ADDR_ANY, SSDP_PORT))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_server->setMulticastInterface(local);
|
||||
_server->setMulticastTTL(_ttl);
|
||||
_server->onRx(std::bind(&SSDPClass::_update, this));
|
||||
if (!_server->connect(mcast, SSDP_PORT)) {
|
||||
return false;
|
||||
}
|
||||
_server->setMulticastInterface(local);
|
||||
_server->setMulticastTTL(_ttl);
|
||||
_server->onRx(std::bind(&SSDPClass::_update, this));
|
||||
if (!_server->connect(mcast, SSDP_PORT))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_startTimer();
|
||||
_startTimer();
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SSDPClass::end() {
|
||||
if(!_server)
|
||||
return; // object is zeroed already, nothing to do
|
||||
void SSDPClass::end()
|
||||
{
|
||||
if (!_server)
|
||||
{
|
||||
return; // object is zeroed already, nothing to do
|
||||
}
|
||||
|
||||
#ifdef DEBUG_SSDP
|
||||
DEBUG_SSDP.printf_P(PSTR("SSDP end ... "));
|
||||
#endif
|
||||
// undo all initializations done in begin(), in reverse order
|
||||
_stopTimer();
|
||||
// undo all initializations done in begin(), in reverse order
|
||||
_stopTimer();
|
||||
|
||||
_server->disconnect();
|
||||
_server->disconnect();
|
||||
|
||||
IPAddress local = WiFi.localIP();
|
||||
IPAddress mcast(SSDP_MULTICAST_ADDR);
|
||||
IPAddress local = WiFi.localIP();
|
||||
IPAddress mcast(SSDP_MULTICAST_ADDR);
|
||||
|
||||
if (igmp_leavegroup(local, mcast) != ERR_OK ) {
|
||||
if (igmp_leavegroup(local, mcast) != ERR_OK)
|
||||
{
|
||||
#ifdef DEBUG_SSDP
|
||||
DEBUG_SSDP.printf_P(PSTR("SSDP failed to leave igmp group\n"));
|
||||
DEBUG_SSDP.printf_P(PSTR("SSDP failed to leave igmp group\n"));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
_server->unref();
|
||||
_server = 0;
|
||||
_server->unref();
|
||||
_server = 0;
|
||||
|
||||
#ifdef DEBUG_SSDP
|
||||
DEBUG_SSDP.printf_P(PSTR("ok\n"));
|
||||
#endif
|
||||
}
|
||||
void SSDPClass::_send(ssdp_method_t method) {
|
||||
char buffer[1460];
|
||||
IPAddress ip = WiFi.localIP();
|
||||
void SSDPClass::_send(ssdp_method_t method)
|
||||
{
|
||||
char buffer[1460];
|
||||
IPAddress ip = WiFi.localIP();
|
||||
|
||||
char valueBuffer[strlen_P(_ssdp_notify_template) + 1];
|
||||
strcpy_P(valueBuffer, (method == NONE) ? _ssdp_response_template : _ssdp_notify_template);
|
||||
char valueBuffer[strlen_P(_ssdp_notify_template) + 1];
|
||||
strcpy_P(valueBuffer, (method == NONE) ? _ssdp_response_template : _ssdp_notify_template);
|
||||
|
||||
int len = snprintf_P(buffer, sizeof(buffer),
|
||||
_ssdp_packet_template,
|
||||
valueBuffer,
|
||||
SSDP_INTERVAL,
|
||||
_modelName,
|
||||
_modelNumber,
|
||||
_uuid,
|
||||
(method == NONE) ? "ST" : "NT",
|
||||
(_st_is_uuid) ? _uuid : _deviceType,
|
||||
ip[0], ip[1], ip[2], ip[3], _port, _schemaURL
|
||||
);
|
||||
int len = snprintf_P(buffer, sizeof(buffer),
|
||||
_ssdp_packet_template,
|
||||
valueBuffer,
|
||||
SSDP_INTERVAL,
|
||||
_modelName,
|
||||
_modelNumber,
|
||||
_uuid,
|
||||
(method == NONE) ? "ST" : "NT",
|
||||
(_st_is_uuid) ? _uuid : _deviceType,
|
||||
ip[0], ip[1], ip[2], ip[3], _port, _schemaURL
|
||||
);
|
||||
|
||||
_server->append(buffer, len);
|
||||
_server->append(buffer, len);
|
||||
|
||||
IPAddress remoteAddr;
|
||||
uint16_t remotePort;
|
||||
if (method == NONE) {
|
||||
remoteAddr = _respondToAddr;
|
||||
remotePort = _respondToPort;
|
||||
IPAddress remoteAddr;
|
||||
uint16_t remotePort;
|
||||
if (method == NONE)
|
||||
{
|
||||
remoteAddr = _respondToAddr;
|
||||
remotePort = _respondToPort;
|
||||
#ifdef DEBUG_SSDP
|
||||
DEBUG_SSDP.print("Sending Response to ");
|
||||
DEBUG_SSDP.print("Sending Response to ");
|
||||
#endif
|
||||
} else {
|
||||
remoteAddr = IPAddress(SSDP_MULTICAST_ADDR);
|
||||
remotePort = SSDP_PORT;
|
||||
#ifdef DEBUG_SSDP
|
||||
DEBUG_SSDP.println("Sending Notify to ");
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG_SSDP
|
||||
DEBUG_SSDP.print(IPAddress(remoteAddr));
|
||||
DEBUG_SSDP.print(":");
|
||||
DEBUG_SSDP.println(remotePort);
|
||||
#endif
|
||||
|
||||
_server->send(remoteAddr, remotePort);
|
||||
}
|
||||
|
||||
void SSDPClass::schema(WiFiClient client) {
|
||||
IPAddress ip = WiFi.localIP();
|
||||
char buffer[strlen_P(_ssdp_schema_template) + 1];
|
||||
strcpy_P(buffer, _ssdp_schema_template);
|
||||
client.printf(buffer,
|
||||
ip[0], ip[1], ip[2], ip[3], _port,
|
||||
_deviceType,
|
||||
_friendlyName,
|
||||
_presentationURL,
|
||||
_serialNumber,
|
||||
_modelName,
|
||||
_modelNumber,
|
||||
_modelURL,
|
||||
_manufacturer,
|
||||
_manufacturerURL,
|
||||
_uuid
|
||||
);
|
||||
}
|
||||
|
||||
void SSDPClass::_update() {
|
||||
if (!_pending && _server->next()) {
|
||||
ssdp_method_t method = NONE;
|
||||
|
||||
_respondToAddr = _server->getRemoteAddress();
|
||||
_respondToPort = _server->getRemotePort();
|
||||
|
||||
typedef enum {METHOD, URI, PROTO, KEY, VALUE, ABORT} states;
|
||||
states state = METHOD;
|
||||
|
||||
typedef enum {START, MAN, ST, MX} headers;
|
||||
headers header = START;
|
||||
|
||||
uint8_t cursor = 0;
|
||||
uint8_t cr = 0;
|
||||
|
||||
char buffer[SSDP_BUFFER_SIZE] = {0};
|
||||
|
||||
while (_server->getSize() > 0) {
|
||||
char c = _server->read();
|
||||
|
||||
(c == '\r' || c == '\n') ? cr++ : cr = 0;
|
||||
|
||||
switch (state) {
|
||||
case METHOD:
|
||||
if (c == ' ') {
|
||||
if (strcmp(buffer, "M-SEARCH") == 0) method = SEARCH;
|
||||
|
||||
if (method == NONE) state = ABORT;
|
||||
else state = URI;
|
||||
cursor = 0;
|
||||
|
||||
} else if (cursor < SSDP_METHOD_SIZE - 1) {
|
||||
buffer[cursor++] = c;
|
||||
buffer[cursor] = '\0';
|
||||
}
|
||||
break;
|
||||
case URI:
|
||||
if (c == ' ') {
|
||||
if (strcmp(buffer, "*")) state = ABORT;
|
||||
else state = PROTO;
|
||||
cursor = 0;
|
||||
} else if (cursor < SSDP_URI_SIZE - 1) {
|
||||
buffer[cursor++] = c;
|
||||
buffer[cursor] = '\0';
|
||||
}
|
||||
break;
|
||||
case PROTO:
|
||||
if (cr == 2) {
|
||||
state = KEY;
|
||||
cursor = 0;
|
||||
}
|
||||
break;
|
||||
case KEY:
|
||||
if (cr == 4) {
|
||||
_pending = true;
|
||||
_process_time = millis();
|
||||
}
|
||||
else if (c == ' ') {
|
||||
cursor = 0;
|
||||
state = VALUE;
|
||||
}
|
||||
else if (c != '\r' && c != '\n' && c != ':' && cursor < SSDP_BUFFER_SIZE - 1) {
|
||||
buffer[cursor++] = c;
|
||||
buffer[cursor] = '\0';
|
||||
}
|
||||
break;
|
||||
case VALUE:
|
||||
if (cr == 2) {
|
||||
switch (header) {
|
||||
case START:
|
||||
break;
|
||||
case MAN:
|
||||
#ifdef DEBUG_SSDP
|
||||
DEBUG_SSDP.printf("MAN: %s\n", (char *)buffer);
|
||||
#endif
|
||||
break;
|
||||
case ST:
|
||||
if (strcmp(buffer, "ssdp:all")) {
|
||||
state = ABORT;
|
||||
#ifdef DEBUG_SSDP
|
||||
DEBUG_SSDP.printf("REJECT: %s\n", (char *)buffer);
|
||||
#endif
|
||||
}else{
|
||||
_st_is_uuid = false;
|
||||
}
|
||||
// if the search type matches our type, we should respond instead of ABORT
|
||||
if (strcasecmp(buffer, _deviceType) == 0) {
|
||||
_pending = true;
|
||||
_st_is_uuid = false;
|
||||
_process_time = millis();
|
||||
state = KEY;
|
||||
}
|
||||
if (strcasecmp(buffer, _uuid) == 0) {
|
||||
_pending = true;
|
||||
_st_is_uuid = true;
|
||||
_process_time = millis();
|
||||
state = KEY;
|
||||
}
|
||||
break;
|
||||
case MX:
|
||||
_delay = random(0, atoi(buffer)) * 1000L;
|
||||
break;
|
||||
}
|
||||
|
||||
if (state != ABORT) {
|
||||
state = KEY;
|
||||
header = START;
|
||||
cursor = 0;
|
||||
}
|
||||
} else if (c != '\r' && c != '\n') {
|
||||
if (header == START) {
|
||||
if (strncmp(buffer, "MA", 2) == 0) header = MAN;
|
||||
else if (strcmp(buffer, "ST") == 0) header = ST;
|
||||
else if (strcmp(buffer, "MX") == 0) header = MX;
|
||||
}
|
||||
|
||||
if (cursor < SSDP_BUFFER_SIZE - 1) {
|
||||
buffer[cursor++] = c;
|
||||
buffer[cursor] = '\0';
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ABORT:
|
||||
_pending = false; _delay = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
remoteAddr = IPAddress(SSDP_MULTICAST_ADDR);
|
||||
remotePort = SSDP_PORT;
|
||||
#ifdef DEBUG_SSDP
|
||||
DEBUG_SSDP.println("Sending Notify to ");
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG_SSDP
|
||||
DEBUG_SSDP.print(IPAddress(remoteAddr));
|
||||
DEBUG_SSDP.print(":");
|
||||
DEBUG_SSDP.println(remotePort);
|
||||
#endif
|
||||
|
||||
if (_pending && (millis() - _process_time) > _delay) {
|
||||
_pending = false; _delay = 0;
|
||||
_send(NONE);
|
||||
} else if(_notify_time == 0 || (millis() - _notify_time) > (SSDP_INTERVAL * 1000L)){
|
||||
_notify_time = millis();
|
||||
_st_is_uuid = false;
|
||||
_send(NOTIFY);
|
||||
}
|
||||
_server->send(remoteAddr, remotePort);
|
||||
}
|
||||
|
||||
if (_pending) {
|
||||
while (_server->next())
|
||||
_server->flush();
|
||||
}
|
||||
void SSDPClass::schema(WiFiClient client)
|
||||
{
|
||||
IPAddress ip = WiFi.localIP();
|
||||
char buffer[strlen_P(_ssdp_schema_template) + 1];
|
||||
strcpy_P(buffer, _ssdp_schema_template);
|
||||
client.printf(buffer,
|
||||
ip[0], ip[1], ip[2], ip[3], _port,
|
||||
_deviceType,
|
||||
_friendlyName,
|
||||
_presentationURL,
|
||||
_serialNumber,
|
||||
_modelName,
|
||||
_modelNumber,
|
||||
_modelURL,
|
||||
_manufacturer,
|
||||
_manufacturerURL,
|
||||
_uuid
|
||||
);
|
||||
}
|
||||
|
||||
void SSDPClass::_update()
|
||||
{
|
||||
if (!_pending && _server->next())
|
||||
{
|
||||
ssdp_method_t method = NONE;
|
||||
|
||||
_respondToAddr = _server->getRemoteAddress();
|
||||
_respondToPort = _server->getRemotePort();
|
||||
|
||||
typedef enum {METHOD, URI, PROTO, KEY, VALUE, ABORT} states;
|
||||
states state = METHOD;
|
||||
|
||||
typedef enum {START, MAN, ST, MX} headers;
|
||||
headers header = START;
|
||||
|
||||
uint8_t cursor = 0;
|
||||
uint8_t cr = 0;
|
||||
|
||||
char buffer[SSDP_BUFFER_SIZE] = {0};
|
||||
|
||||
while (_server->getSize() > 0)
|
||||
{
|
||||
char c = _server->read();
|
||||
|
||||
(c == '\r' || c == '\n') ? cr++ : cr = 0;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case METHOD:
|
||||
if (c == ' ')
|
||||
{
|
||||
if (strcmp(buffer, "M-SEARCH") == 0)
|
||||
{
|
||||
method = SEARCH;
|
||||
}
|
||||
|
||||
if (method == NONE)
|
||||
{
|
||||
state = ABORT;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = URI;
|
||||
}
|
||||
cursor = 0;
|
||||
|
||||
}
|
||||
else if (cursor < SSDP_METHOD_SIZE - 1)
|
||||
{
|
||||
buffer[cursor++] = c;
|
||||
buffer[cursor] = '\0';
|
||||
}
|
||||
break;
|
||||
case URI:
|
||||
if (c == ' ')
|
||||
{
|
||||
if (strcmp(buffer, "*"))
|
||||
{
|
||||
state = ABORT;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = PROTO;
|
||||
}
|
||||
cursor = 0;
|
||||
}
|
||||
else if (cursor < SSDP_URI_SIZE - 1)
|
||||
{
|
||||
buffer[cursor++] = c;
|
||||
buffer[cursor] = '\0';
|
||||
}
|
||||
break;
|
||||
case PROTO:
|
||||
if (cr == 2)
|
||||
{
|
||||
state = KEY;
|
||||
cursor = 0;
|
||||
}
|
||||
break;
|
||||
case KEY:
|
||||
if (cr == 4)
|
||||
{
|
||||
_pending = true;
|
||||
_process_time = millis();
|
||||
}
|
||||
else if (c == ' ')
|
||||
{
|
||||
cursor = 0;
|
||||
state = VALUE;
|
||||
}
|
||||
else if (c != '\r' && c != '\n' && c != ':' && cursor < SSDP_BUFFER_SIZE - 1)
|
||||
{
|
||||
buffer[cursor++] = c;
|
||||
buffer[cursor] = '\0';
|
||||
}
|
||||
break;
|
||||
case VALUE:
|
||||
if (cr == 2)
|
||||
{
|
||||
switch (header)
|
||||
{
|
||||
case START:
|
||||
break;
|
||||
case MAN:
|
||||
#ifdef DEBUG_SSDP
|
||||
DEBUG_SSDP.printf("MAN: %s\n", (char *)buffer);
|
||||
#endif
|
||||
break;
|
||||
case ST:
|
||||
if (strcmp(buffer, "ssdp:all"))
|
||||
{
|
||||
state = ABORT;
|
||||
#ifdef DEBUG_SSDP
|
||||
DEBUG_SSDP.printf("REJECT: %s\n", (char *)buffer);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
_st_is_uuid = false;
|
||||
}
|
||||
// if the search type matches our type, we should respond instead of ABORT
|
||||
if (strcasecmp(buffer, _deviceType) == 0)
|
||||
{
|
||||
_pending = true;
|
||||
_st_is_uuid = false;
|
||||
_process_time = millis();
|
||||
state = KEY;
|
||||
}
|
||||
if (strcasecmp(buffer, _uuid) == 0)
|
||||
{
|
||||
_pending = true;
|
||||
_st_is_uuid = true;
|
||||
_process_time = millis();
|
||||
state = KEY;
|
||||
}
|
||||
break;
|
||||
case MX:
|
||||
_delay = random(0, atoi(buffer)) * 1000L;
|
||||
break;
|
||||
}
|
||||
|
||||
if (state != ABORT)
|
||||
{
|
||||
state = KEY;
|
||||
header = START;
|
||||
cursor = 0;
|
||||
}
|
||||
}
|
||||
else if (c != '\r' && c != '\n')
|
||||
{
|
||||
if (header == START)
|
||||
{
|
||||
if (strncmp(buffer, "MA", 2) == 0)
|
||||
{
|
||||
header = MAN;
|
||||
}
|
||||
else if (strcmp(buffer, "ST") == 0)
|
||||
{
|
||||
header = ST;
|
||||
}
|
||||
else if (strcmp(buffer, "MX") == 0)
|
||||
{
|
||||
header = MX;
|
||||
}
|
||||
}
|
||||
|
||||
if (cursor < SSDP_BUFFER_SIZE - 1)
|
||||
{
|
||||
buffer[cursor++] = c;
|
||||
buffer[cursor] = '\0';
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ABORT:
|
||||
_pending = false; _delay = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_pending && (millis() - _process_time) > _delay)
|
||||
{
|
||||
_pending = false; _delay = 0;
|
||||
_send(NONE);
|
||||
}
|
||||
else if (_notify_time == 0 || (millis() - _notify_time) > (SSDP_INTERVAL * 1000L))
|
||||
{
|
||||
_notify_time = millis();
|
||||
_st_is_uuid = false;
|
||||
_send(NOTIFY);
|
||||
}
|
||||
|
||||
if (_pending)
|
||||
{
|
||||
while (_server->next())
|
||||
{
|
||||
_server->flush();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SSDPClass::setSchemaURL(const char *url) {
|
||||
strlcpy(_schemaURL, url, sizeof(_schemaURL));
|
||||
void SSDPClass::setSchemaURL(const char *url)
|
||||
{
|
||||
strlcpy(_schemaURL, url, sizeof(_schemaURL));
|
||||
}
|
||||
|
||||
void SSDPClass::setHTTPPort(uint16_t port) {
|
||||
_port = port;
|
||||
void SSDPClass::setHTTPPort(uint16_t port)
|
||||
{
|
||||
_port = port;
|
||||
}
|
||||
|
||||
void SSDPClass::setDeviceType(const char *deviceType) {
|
||||
strlcpy(_deviceType, deviceType, sizeof(_deviceType));
|
||||
void SSDPClass::setDeviceType(const char *deviceType)
|
||||
{
|
||||
strlcpy(_deviceType, deviceType, sizeof(_deviceType));
|
||||
}
|
||||
|
||||
void SSDPClass::setUUID(const char *uuid) {
|
||||
snprintf_P(_uuid, sizeof(_uuid), PSTR("uuid:%s"), uuid);
|
||||
void SSDPClass::setUUID(const char *uuid)
|
||||
{
|
||||
snprintf_P(_uuid, sizeof(_uuid), PSTR("uuid:%s"), uuid);
|
||||
}
|
||||
|
||||
void SSDPClass::setName(const char *name) {
|
||||
strlcpy(_friendlyName, name, sizeof(_friendlyName));
|
||||
void SSDPClass::setName(const char *name)
|
||||
{
|
||||
strlcpy(_friendlyName, name, sizeof(_friendlyName));
|
||||
}
|
||||
|
||||
void SSDPClass::setURL(const char *url) {
|
||||
strlcpy(_presentationURL, url, sizeof(_presentationURL));
|
||||
void SSDPClass::setURL(const char *url)
|
||||
{
|
||||
strlcpy(_presentationURL, url, sizeof(_presentationURL));
|
||||
}
|
||||
|
||||
void SSDPClass::setSerialNumber(const char *serialNumber) {
|
||||
strlcpy(_serialNumber, serialNumber, sizeof(_serialNumber));
|
||||
void SSDPClass::setSerialNumber(const char *serialNumber)
|
||||
{
|
||||
strlcpy(_serialNumber, serialNumber, sizeof(_serialNumber));
|
||||
}
|
||||
|
||||
void SSDPClass::setSerialNumber(const uint32_t serialNumber) {
|
||||
snprintf(_serialNumber, sizeof(uint32_t) * 2 + 1, "%08X", serialNumber);
|
||||
void SSDPClass::setSerialNumber(const uint32_t serialNumber)
|
||||
{
|
||||
snprintf(_serialNumber, sizeof(uint32_t) * 2 + 1, "%08X", serialNumber);
|
||||
}
|
||||
|
||||
void SSDPClass::setModelName(const char *name) {
|
||||
strlcpy(_modelName, name, sizeof(_modelName));
|
||||
void SSDPClass::setModelName(const char *name)
|
||||
{
|
||||
strlcpy(_modelName, name, sizeof(_modelName));
|
||||
}
|
||||
|
||||
void SSDPClass::setModelNumber(const char *num) {
|
||||
strlcpy(_modelNumber, num, sizeof(_modelNumber));
|
||||
void SSDPClass::setModelNumber(const char *num)
|
||||
{
|
||||
strlcpy(_modelNumber, num, sizeof(_modelNumber));
|
||||
}
|
||||
|
||||
void SSDPClass::setModelURL(const char *url) {
|
||||
strlcpy(_modelURL, url, sizeof(_modelURL));
|
||||
void SSDPClass::setModelURL(const char *url)
|
||||
{
|
||||
strlcpy(_modelURL, url, sizeof(_modelURL));
|
||||
}
|
||||
|
||||
void SSDPClass::setManufacturer(const char *name) {
|
||||
strlcpy(_manufacturer, name, sizeof(_manufacturer));
|
||||
void SSDPClass::setManufacturer(const char *name)
|
||||
{
|
||||
strlcpy(_manufacturer, name, sizeof(_manufacturer));
|
||||
}
|
||||
|
||||
void SSDPClass::setManufacturerURL(const char *url) {
|
||||
strlcpy(_manufacturerURL, url, sizeof(_manufacturerURL));
|
||||
void SSDPClass::setManufacturerURL(const char *url)
|
||||
{
|
||||
strlcpy(_manufacturerURL, url, sizeof(_manufacturerURL));
|
||||
}
|
||||
|
||||
|
||||
void SSDPClass::setTTL(const uint8_t ttl) {
|
||||
_ttl = ttl;
|
||||
void SSDPClass::setTTL(const uint8_t ttl)
|
||||
{
|
||||
_ttl = ttl;
|
||||
}
|
||||
|
||||
void SSDPClass::_onTimerStatic(SSDPClass* self) {
|
||||
self->_update();
|
||||
void SSDPClass::_onTimerStatic(SSDPClass* self)
|
||||
{
|
||||
self->_update();
|
||||
}
|
||||
|
||||
void SSDPClass::_startTimer() {
|
||||
_stopTimer();
|
||||
_timer = new SSDPTimer();
|
||||
ETSTimer* tm = &(_timer->timer);
|
||||
const int interval = 1000;
|
||||
os_timer_disarm(tm);
|
||||
os_timer_setfn(tm, reinterpret_cast<ETSTimerFunc*>(&SSDPClass::_onTimerStatic), reinterpret_cast<void*>(this));
|
||||
os_timer_arm(tm, interval, 1 /* repeat */);
|
||||
void SSDPClass::_startTimer()
|
||||
{
|
||||
_stopTimer();
|
||||
_timer = new SSDPTimer();
|
||||
ETSTimer* tm = &(_timer->timer);
|
||||
const int interval = 1000;
|
||||
os_timer_disarm(tm);
|
||||
os_timer_setfn(tm, reinterpret_cast<ETSTimerFunc*>(&SSDPClass::_onTimerStatic), reinterpret_cast<void*>(this));
|
||||
os_timer_arm(tm, interval, 1 /* repeat */);
|
||||
}
|
||||
|
||||
void SSDPClass::_stopTimer() {
|
||||
if(!_timer)
|
||||
return;
|
||||
void SSDPClass::_stopTimer()
|
||||
{
|
||||
if (!_timer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ETSTimer* tm = &(_timer->timer);
|
||||
os_timer_disarm(tm);
|
||||
delete _timer;
|
||||
_timer = NULL;
|
||||
ETSTimer* tm = &(_timer->timer);
|
||||
os_timer_disarm(tm);
|
||||
delete _timer;
|
||||
_timer = NULL;
|
||||
}
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SSDP)
|
||||
|
@ -1,28 +1,28 @@
|
||||
/*
|
||||
ESP8266 Simple Service Discovery
|
||||
Copyright (c) 2015 Hristo Gochkov
|
||||
ESP8266 Simple Service Discovery
|
||||
Copyright (c) 2015 Hristo Gochkov
|
||||
|
||||
Original (Arduino) version by Filippo Sallemi, July 23, 2014.
|
||||
Can be found at: https://github.com/nomadnt/uSSDP
|
||||
Original (Arduino) version by Filippo Sallemi, July 23, 2014.
|
||||
Can be found at: https://github.com/nomadnt/uSSDP
|
||||
|
||||
License (MIT license):
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
License (MIT license):
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
@ -47,52 +47,87 @@ class UdpContext;
|
||||
#define SSDP_MANUFACTURER_SIZE 64
|
||||
#define SSDP_MANUFACTURER_URL_SIZE 128
|
||||
|
||||
typedef enum {
|
||||
NONE,
|
||||
SEARCH,
|
||||
NOTIFY
|
||||
typedef enum
|
||||
{
|
||||
NONE,
|
||||
SEARCH,
|
||||
NOTIFY
|
||||
} ssdp_method_t;
|
||||
|
||||
|
||||
struct SSDPTimer;
|
||||
|
||||
class SSDPClass{
|
||||
public:
|
||||
class SSDPClass
|
||||
{
|
||||
public:
|
||||
SSDPClass();
|
||||
~SSDPClass();
|
||||
bool begin();
|
||||
void end();
|
||||
void schema(WiFiClient client);
|
||||
void setDeviceType(const String& deviceType) { setDeviceType(deviceType.c_str()); }
|
||||
void setDeviceType(const String& deviceType)
|
||||
{
|
||||
setDeviceType(deviceType.c_str());
|
||||
}
|
||||
void setDeviceType(const char *deviceType);
|
||||
|
||||
|
||||
/*To define a custom UUID, you must call the method before begin(). Otherwise an automatic UUID based on CHIPID will be generated.*/
|
||||
void setUUID(const String& uuid) { setUUID(uuid.c_str()); }
|
||||
void setUUID(const String& uuid)
|
||||
{
|
||||
setUUID(uuid.c_str());
|
||||
}
|
||||
void setUUID(const char *uuid);
|
||||
|
||||
void setName(const String& name) { setName(name.c_str()); }
|
||||
|
||||
void setName(const String& name)
|
||||
{
|
||||
setName(name.c_str());
|
||||
}
|
||||
void setName(const char *name);
|
||||
void setURL(const String& url) { setURL(url.c_str()); }
|
||||
void setURL(const String& url)
|
||||
{
|
||||
setURL(url.c_str());
|
||||
}
|
||||
void setURL(const char *url);
|
||||
void setSchemaURL(const String& url) { setSchemaURL(url.c_str()); }
|
||||
void setSchemaURL(const String& url)
|
||||
{
|
||||
setSchemaURL(url.c_str());
|
||||
}
|
||||
void setSchemaURL(const char *url);
|
||||
void setSerialNumber(const String& serialNumber) { setSerialNumber(serialNumber.c_str()); }
|
||||
void setSerialNumber(const String& serialNumber)
|
||||
{
|
||||
setSerialNumber(serialNumber.c_str());
|
||||
}
|
||||
void setSerialNumber(const char *serialNumber);
|
||||
void setSerialNumber(const uint32_t serialNumber);
|
||||
void setModelName(const String& name) { setModelName(name.c_str()); }
|
||||
void setModelName(const String& name)
|
||||
{
|
||||
setModelName(name.c_str());
|
||||
}
|
||||
void setModelName(const char *name);
|
||||
void setModelNumber(const String& num) { setModelNumber(num.c_str()); }
|
||||
void setModelNumber(const String& num)
|
||||
{
|
||||
setModelNumber(num.c_str());
|
||||
}
|
||||
void setModelNumber(const char *num);
|
||||
void setModelURL(const String& url) { setModelURL(url.c_str()); }
|
||||
void setModelURL(const String& url)
|
||||
{
|
||||
setModelURL(url.c_str());
|
||||
}
|
||||
void setModelURL(const char *url);
|
||||
void setManufacturer(const String& name) { setManufacturer(name.c_str()); }
|
||||
void setManufacturer(const String& name)
|
||||
{
|
||||
setManufacturer(name.c_str());
|
||||
}
|
||||
void setManufacturer(const char *name);
|
||||
void setManufacturerURL(const String& url) { setManufacturerURL(url.c_str()); }
|
||||
void setManufacturerURL(const String& url)
|
||||
{
|
||||
setManufacturerURL(url.c_str());
|
||||
}
|
||||
void setManufacturerURL(const char *url);
|
||||
void setHTTPPort(uint16_t port);
|
||||
void setTTL(uint8_t ttl);
|
||||
|
||||
protected:
|
||||
protected:
|
||||
void _send(ssdp_method_t method);
|
||||
void _update();
|
||||
void _startTimer();
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,23 +1,23 @@
|
||||
/*
|
||||
ESP8266WebServer.h - Dead simple web-server.
|
||||
Supports only one simultaneous client, knows how to handle GET and POST.
|
||||
ESP8266WebServer.h - Dead simple web-server.
|
||||
Supports only one simultaneous client, knows how to handle GET and POST.
|
||||
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
|
||||
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 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.
|
||||
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
|
||||
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
|
||||
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
|
||||
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
|
||||
*/
|
||||
|
||||
|
||||
@ -30,7 +30,8 @@
|
||||
|
||||
enum HTTPMethod { HTTP_ANY, HTTP_GET, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE, HTTP_OPTIONS };
|
||||
enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END,
|
||||
UPLOAD_FILE_ABORTED };
|
||||
UPLOAD_FILE_ABORTED
|
||||
};
|
||||
enum HTTPClientStatus { HC_NONE, HC_WAIT_READ, HC_WAIT_CLOSE };
|
||||
enum HTTPAuthMethod { BASIC_AUTH, DIGEST_AUTH };
|
||||
|
||||
@ -50,153 +51,175 @@ enum HTTPAuthMethod { BASIC_AUTH, DIGEST_AUTH };
|
||||
|
||||
class ESP8266WebServer;
|
||||
|
||||
typedef struct {
|
||||
HTTPUploadStatus status;
|
||||
String filename;
|
||||
String name;
|
||||
String type;
|
||||
size_t totalSize; // total size of uploaded file so far
|
||||
size_t currentSize; // size of data currently in buf
|
||||
size_t contentLength; // size of entire post request, file size + headers and other request data.
|
||||
uint8_t buf[HTTP_UPLOAD_BUFLEN];
|
||||
typedef struct
|
||||
{
|
||||
HTTPUploadStatus status;
|
||||
String filename;
|
||||
String name;
|
||||
String type;
|
||||
size_t totalSize; // total size of uploaded file so far
|
||||
size_t currentSize; // size of data currently in buf
|
||||
size_t contentLength; // size of entire post request, file size + headers and other request data.
|
||||
uint8_t buf[HTTP_UPLOAD_BUFLEN];
|
||||
} HTTPUpload;
|
||||
|
||||
#include "detail/RequestHandler.h"
|
||||
|
||||
namespace fs {
|
||||
namespace fs
|
||||
{
|
||||
class FS;
|
||||
}
|
||||
|
||||
class ESP8266WebServer
|
||||
{
|
||||
public:
|
||||
ESP8266WebServer(IPAddress addr, int port = 80);
|
||||
ESP8266WebServer(int port = 80);
|
||||
virtual ~ESP8266WebServer();
|
||||
ESP8266WebServer(IPAddress addr, int port = 80);
|
||||
ESP8266WebServer(int port = 80);
|
||||
virtual ~ESP8266WebServer();
|
||||
|
||||
virtual void begin();
|
||||
virtual void begin(uint16_t port);
|
||||
virtual void handleClient();
|
||||
virtual void begin();
|
||||
virtual void begin(uint16_t port);
|
||||
virtual void handleClient();
|
||||
|
||||
virtual void close();
|
||||
void stop();
|
||||
virtual void close();
|
||||
void stop();
|
||||
|
||||
bool authenticate(const char * username, const char * password);
|
||||
void requestAuthentication(HTTPAuthMethod mode = BASIC_AUTH, const char* realm = NULL, const String& authFailMsg = String("") );
|
||||
bool authenticate(const char * username, const char * password);
|
||||
void requestAuthentication(HTTPAuthMethod mode = BASIC_AUTH, const char* realm = NULL, const String& authFailMsg = String(""));
|
||||
|
||||
typedef std::function<void(void)> THandlerFunction;
|
||||
void on(const String &uri, THandlerFunction handler);
|
||||
void on(const String &uri, HTTPMethod method, THandlerFunction fn);
|
||||
void on(const String &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn);
|
||||
void addHandler(RequestHandler* handler);
|
||||
void serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header = NULL );
|
||||
void onNotFound(THandlerFunction fn); //called when handler is not assigned
|
||||
void onFileUpload(THandlerFunction fn); //handle file uploads
|
||||
typedef std::function<void(void)> THandlerFunction;
|
||||
void on(const String &uri, THandlerFunction handler);
|
||||
void on(const String &uri, HTTPMethod method, THandlerFunction fn);
|
||||
void on(const String &uri, HTTPMethod method, THandlerFunction fn, THandlerFunction ufn);
|
||||
void addHandler(RequestHandler* handler);
|
||||
void serveStatic(const char* uri, fs::FS& fs, const char* path, const char* cache_header = NULL);
|
||||
void onNotFound(THandlerFunction fn); //called when handler is not assigned
|
||||
void onFileUpload(THandlerFunction fn); //handle file uploads
|
||||
|
||||
const String& uri() const { return _currentUri; }
|
||||
HTTPMethod method() const { return _currentMethod; }
|
||||
virtual WiFiClient client() { return _currentClient; }
|
||||
HTTPUpload& upload() { return *_currentUpload; }
|
||||
const String& uri() const
|
||||
{
|
||||
return _currentUri;
|
||||
}
|
||||
HTTPMethod method() const
|
||||
{
|
||||
return _currentMethod;
|
||||
}
|
||||
virtual WiFiClient client()
|
||||
{
|
||||
return _currentClient;
|
||||
}
|
||||
HTTPUpload& upload()
|
||||
{
|
||||
return *_currentUpload;
|
||||
}
|
||||
|
||||
const String& arg(String name) const; // get request argument value by name
|
||||
const String& arg(int i) const; // get request argument value by number
|
||||
const String& argName(int i) const; // get request argument name by number
|
||||
int args() const; // get arguments count
|
||||
bool hasArg(const String& name) const; // check if argument exists
|
||||
void collectHeaders(const char* headerKeys[], const size_t headerKeysCount); // set the request headers to collect
|
||||
const String& header(String name) const; // get request header value by name
|
||||
const String& header(int i) const; // get request header value by number
|
||||
const String& headerName(int i) const; // get request header name by number
|
||||
int headers() const; // get header count
|
||||
bool hasHeader(String name) const; // check if header exists
|
||||
const String& hostHeader() const; // get request host header if available or empty String if not
|
||||
const String& arg(String name) const; // get request argument value by name
|
||||
const String& arg(int i) const; // get request argument value by number
|
||||
const String& argName(int i) const; // get request argument name by number
|
||||
int args() const; // get arguments count
|
||||
bool hasArg(const String& name) const; // check if argument exists
|
||||
void collectHeaders(const char* headerKeys[], const size_t headerKeysCount); // set the request headers to collect
|
||||
const String& header(String name) const; // get request header value by name
|
||||
const String& header(int i) const; // get request header value by number
|
||||
const String& headerName(int i) const; // get request header name by number
|
||||
int headers() const; // get header count
|
||||
bool hasHeader(String name) const; // check if header exists
|
||||
const String& hostHeader() const; // get request host header if available or empty String if not
|
||||
|
||||
// send response to the client
|
||||
// code - HTTP response code, can be 200 or 404
|
||||
// content_type - HTTP content type, like "text/plain" or "image/png"
|
||||
// content - actual content body
|
||||
void send(int code, const char* content_type = NULL, const String& content = String(""));
|
||||
void send(int code, char* content_type, const String& content);
|
||||
void send(int code, const String& content_type, const String& content);
|
||||
void send_P(int code, PGM_P content_type, PGM_P content);
|
||||
void send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength);
|
||||
// send response to the client
|
||||
// code - HTTP response code, can be 200 or 404
|
||||
// content_type - HTTP content type, like "text/plain" or "image/png"
|
||||
// content - actual content body
|
||||
void send(int code, const char* content_type = NULL, const String& content = String(""));
|
||||
void send(int code, char* content_type, const String& content);
|
||||
void send(int code, const String& content_type, const String& content);
|
||||
void send_P(int code, PGM_P content_type, PGM_P content);
|
||||
void send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength);
|
||||
|
||||
void setContentLength(const size_t contentLength);
|
||||
void sendHeader(const String& name, const String& value, bool first = false);
|
||||
void sendContent(const String& content);
|
||||
void sendContent_P(PGM_P content);
|
||||
void sendContent_P(PGM_P content, size_t size);
|
||||
void setContentLength(const size_t contentLength);
|
||||
void sendHeader(const String& name, const String& value, bool first = false);
|
||||
void sendContent(const String& content);
|
||||
void sendContent_P(PGM_P content);
|
||||
void sendContent_P(PGM_P content, size_t size);
|
||||
|
||||
static String urlDecode(const String& text);
|
||||
static String urlDecode(const String& text);
|
||||
|
||||
template<typename T>
|
||||
size_t streamFile(T &file, const String& contentType) {
|
||||
_streamFileCore(file.size(), file.name(), contentType);
|
||||
return _currentClient.write(file);
|
||||
}
|
||||
template<typename T>
|
||||
size_t streamFile(T &file, const String& contentType)
|
||||
{
|
||||
_streamFileCore(file.size(), file.name(), contentType);
|
||||
return _currentClient.write(file);
|
||||
}
|
||||
|
||||
static const String responseCodeToString(const int code);
|
||||
static const String responseCodeToString(const int code);
|
||||
|
||||
protected:
|
||||
virtual size_t _currentClientWrite(const char* b, size_t l) { return _currentClient.write( b, l ); }
|
||||
virtual size_t _currentClientWrite_P(PGM_P b, size_t l) { return _currentClient.write_P( b, l ); }
|
||||
void _addRequestHandler(RequestHandler* handler);
|
||||
void _handleRequest();
|
||||
void _finalizeResponse();
|
||||
bool _parseRequest(WiFiClient& client);
|
||||
void _parseArguments(const String& data);
|
||||
int _parseArgumentsPrivate(const String& data, std::function<void(String&,String&,const String&,int,int,int,int)> handler);
|
||||
bool _parseForm(WiFiClient& client, const String& boundary, uint32_t len);
|
||||
bool _parseFormUploadAborted();
|
||||
void _uploadWriteByte(uint8_t b);
|
||||
uint8_t _uploadReadByte(WiFiClient& client);
|
||||
void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength);
|
||||
bool _collectHeader(const char* headerName, const char* headerValue);
|
||||
virtual size_t _currentClientWrite(const char* b, size_t l)
|
||||
{
|
||||
return _currentClient.write(b, l);
|
||||
}
|
||||
virtual size_t _currentClientWrite_P(PGM_P b, size_t l)
|
||||
{
|
||||
return _currentClient.write_P(b, l);
|
||||
}
|
||||
void _addRequestHandler(RequestHandler* handler);
|
||||
void _handleRequest();
|
||||
void _finalizeResponse();
|
||||
bool _parseRequest(WiFiClient& client);
|
||||
void _parseArguments(const String& data);
|
||||
int _parseArgumentsPrivate(const String& data, std::function<void(String&, String&, const String&, int, int, int, int)> handler);
|
||||
bool _parseForm(WiFiClient& client, const String& boundary, uint32_t len);
|
||||
bool _parseFormUploadAborted();
|
||||
void _uploadWriteByte(uint8_t b);
|
||||
uint8_t _uploadReadByte(WiFiClient& client);
|
||||
void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength);
|
||||
bool _collectHeader(const char* headerName, const char* headerValue);
|
||||
|
||||
void _streamFileCore(const size_t fileSize, const String & fileName, const String & contentType);
|
||||
void _streamFileCore(const size_t fileSize, const String & fileName, const String & contentType);
|
||||
|
||||
static String _getRandomHexString();
|
||||
// for extracting Auth parameters
|
||||
String _extractParam(String& authReq,const String& param,const char delimit = '"') const;
|
||||
static String _getRandomHexString();
|
||||
// for extracting Auth parameters
|
||||
String _extractParam(String& authReq, const String& param, const char delimit = '"') const;
|
||||
|
||||
struct RequestArgument {
|
||||
String key;
|
||||
String value;
|
||||
};
|
||||
struct RequestArgument
|
||||
{
|
||||
String key;
|
||||
String value;
|
||||
};
|
||||
|
||||
WiFiServer _server;
|
||||
WiFiServer _server;
|
||||
|
||||
WiFiClient _currentClient;
|
||||
HTTPMethod _currentMethod;
|
||||
String _currentUri;
|
||||
uint8_t _currentVersion;
|
||||
HTTPClientStatus _currentStatus;
|
||||
unsigned long _statusChange;
|
||||
WiFiClient _currentClient;
|
||||
HTTPMethod _currentMethod;
|
||||
String _currentUri;
|
||||
uint8_t _currentVersion;
|
||||
HTTPClientStatus _currentStatus;
|
||||
unsigned long _statusChange;
|
||||
|
||||
RequestHandler* _currentHandler;
|
||||
RequestHandler* _firstHandler;
|
||||
RequestHandler* _lastHandler;
|
||||
THandlerFunction _notFoundHandler;
|
||||
THandlerFunction _fileUploadHandler;
|
||||
RequestHandler* _currentHandler;
|
||||
RequestHandler* _firstHandler;
|
||||
RequestHandler* _lastHandler;
|
||||
THandlerFunction _notFoundHandler;
|
||||
THandlerFunction _fileUploadHandler;
|
||||
|
||||
int _currentArgCount;
|
||||
RequestArgument* _currentArgs;
|
||||
std::unique_ptr<HTTPUpload> _currentUpload;
|
||||
int _postArgsLen;
|
||||
RequestArgument* _postArgs;
|
||||
|
||||
int _headerKeysCount;
|
||||
RequestArgument* _currentHeaders;
|
||||
|
||||
size_t _contentLength;
|
||||
String _responseHeaders;
|
||||
int _currentArgCount;
|
||||
RequestArgument* _currentArgs;
|
||||
std::unique_ptr<HTTPUpload> _currentUpload;
|
||||
int _postArgsLen;
|
||||
RequestArgument* _postArgs;
|
||||
|
||||
String _hostHeader;
|
||||
bool _chunked;
|
||||
int _headerKeysCount;
|
||||
RequestArgument* _currentHeaders;
|
||||
|
||||
String _snonce; // Store noance and opaque for future comparison
|
||||
String _sopaque;
|
||||
String _srealm; // Store the Auth realm between Calls
|
||||
size_t _contentLength;
|
||||
String _responseHeaders;
|
||||
|
||||
String _hostHeader;
|
||||
bool _chunked;
|
||||
|
||||
String _snonce; // Store noance and opaque for future comparison
|
||||
String _sopaque;
|
||||
String _srealm; // Store the Auth realm between Calls
|
||||
|
||||
};
|
||||
|
||||
|
@ -1,22 +1,22 @@
|
||||
/*
|
||||
ESP8266WebServerSecure.h - Dead simple HTTPS web-server.
|
||||
Supports only one simultaneous client, knows how to handle GET and POST.
|
||||
ESP8266WebServerSecure.h - Dead simple HTTPS web-server.
|
||||
Supports only one simultaneous client, knows how to handle GET and POST.
|
||||
|
||||
Copyright (c) 2017 Earle F. Philhower, III. All rights reserved.
|
||||
Copyright (c) 2017 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
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 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.
|
||||
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
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <WiFiClientSecure.h>
|
||||
|
@ -1,23 +1,23 @@
|
||||
/*
|
||||
ESP8266WebServerSecure.cpp - Dead simple HTTPS web-server.
|
||||
Supports only one simultaneous client, knows how to handle GET and POST.
|
||||
ESP8266WebServerSecure.cpp - Dead simple HTTPS web-server.
|
||||
Supports only one simultaneous client, knows how to handle GET and POST.
|
||||
|
||||
Copyright (c) 2017 Earle F. Philhower, III. All rights reserved.
|
||||
Copyright (c) 2017 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
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 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.
|
||||
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
|
||||
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
|
||||
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
|
||||
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
|
||||
*/
|
||||
|
||||
|
||||
@ -34,18 +34,19 @@
|
||||
#define DEBUG_OUTPUT Serial
|
||||
#endif
|
||||
|
||||
namespace axTLS {
|
||||
namespace axTLS
|
||||
{
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
|
||||
ESP8266WebServerSecure::ESP8266WebServerSecure(IPAddress addr, int port)
|
||||
: _serverSecure(addr, port)
|
||||
ESP8266WebServerSecure::ESP8266WebServerSecure(IPAddress addr, int port)
|
||||
: _serverSecure(addr, port)
|
||||
{
|
||||
}
|
||||
|
||||
ESP8266WebServerSecure::ESP8266WebServerSecure(int port)
|
||||
: _serverSecure(port)
|
||||
: _serverSecure(port)
|
||||
{
|
||||
}
|
||||
|
||||
@ -61,97 +62,116 @@ void ESP8266WebServerSecure::setServerKeyAndCert(const uint8_t *key, int keyLen,
|
||||
_serverSecure.setServerKeyAndCert(key, keyLen, cert, certLen);
|
||||
}
|
||||
|
||||
ESP8266WebServerSecure::~ESP8266WebServerSecure() {
|
||||
// Nothing to do here.
|
||||
// Base class's destructor will be called to clean up itself
|
||||
ESP8266WebServerSecure::~ESP8266WebServerSecure()
|
||||
{
|
||||
// Nothing to do here.
|
||||
// Base class's destructor will be called to clean up itself
|
||||
}
|
||||
|
||||
// We need to basically cut-n-paste these from WebServer because of the problem
|
||||
// of object slicing. The class uses assignment operators like "WiFiClient x=y;"
|
||||
// When this happens, even if "y" is a WiFiClientSecure, the main class is
|
||||
// When this happens, even if "y" is a WiFiClientSecure, the main class is
|
||||
// already compiled down into code which will only copy the WiFiClient superclass
|
||||
// and not the extra bits for our own class (since when it was compiled it needed
|
||||
// to know the size of memory to allocate on the stack for this local variable
|
||||
// there's not realy anything else it could do).
|
||||
|
||||
void ESP8266WebServerSecure::begin() {
|
||||
_currentStatus = HC_NONE;
|
||||
_serverSecure.begin();
|
||||
if(!_headerKeysCount)
|
||||
collectHeaders(0, 0);
|
||||
void ESP8266WebServerSecure::begin()
|
||||
{
|
||||
_currentStatus = HC_NONE;
|
||||
_serverSecure.begin();
|
||||
if (!_headerKeysCount)
|
||||
{
|
||||
collectHeaders(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void ESP8266WebServerSecure::handleClient() {
|
||||
if (_currentStatus == HC_NONE) {
|
||||
WiFiClientSecure client = _serverSecure.available();
|
||||
if (!client) {
|
||||
return;
|
||||
}
|
||||
void ESP8266WebServerSecure::handleClient()
|
||||
{
|
||||
if (_currentStatus == HC_NONE)
|
||||
{
|
||||
WiFiClientSecure client = _serverSecure.available();
|
||||
if (!client)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ESP_HTTP_SERVER
|
||||
DEBUG_OUTPUT.println("New secure client");
|
||||
DEBUG_OUTPUT.println("New secure client");
|
||||
#endif
|
||||
|
||||
_currentClientSecure = client;
|
||||
_currentStatus = HC_WAIT_READ;
|
||||
_statusChange = millis();
|
||||
}
|
||||
|
||||
bool keepCurrentClient = false;
|
||||
bool callYield = false;
|
||||
|
||||
if (_currentClientSecure.connected()) {
|
||||
switch (_currentStatus) {
|
||||
case HC_NONE:
|
||||
// No-op to avoid C++ compiler warning
|
||||
break;
|
||||
case HC_WAIT_READ:
|
||||
// Wait for data from client to become available
|
||||
if (_currentClientSecure.available()) {
|
||||
if (_parseRequest(_currentClientSecure)) {
|
||||
_currentClientSecure.setTimeout(HTTP_MAX_SEND_WAIT);
|
||||
_contentLength = CONTENT_LENGTH_NOT_SET;
|
||||
_handleRequest();
|
||||
|
||||
if (_currentClientSecure.connected()) {
|
||||
_currentStatus = HC_WAIT_CLOSE;
|
||||
_statusChange = millis();
|
||||
keepCurrentClient = true;
|
||||
}
|
||||
}
|
||||
} else { // !_currentClient.available()
|
||||
if (millis() - _statusChange <= HTTP_MAX_DATA_WAIT) {
|
||||
keepCurrentClient = true;
|
||||
}
|
||||
callYield = true;
|
||||
}
|
||||
break;
|
||||
case HC_WAIT_CLOSE:
|
||||
// Wait for client to close the connection
|
||||
if (millis() - _statusChange <= HTTP_MAX_CLOSE_WAIT) {
|
||||
keepCurrentClient = true;
|
||||
callYield = true;
|
||||
}
|
||||
_currentClientSecure = client;
|
||||
_currentStatus = HC_WAIT_READ;
|
||||
_statusChange = millis();
|
||||
}
|
||||
}
|
||||
|
||||
if (!keepCurrentClient) {
|
||||
bool keepCurrentClient = false;
|
||||
bool callYield = false;
|
||||
|
||||
if (_currentClientSecure.connected())
|
||||
{
|
||||
switch (_currentStatus)
|
||||
{
|
||||
case HC_NONE:
|
||||
// No-op to avoid C++ compiler warning
|
||||
break;
|
||||
case HC_WAIT_READ:
|
||||
// Wait for data from client to become available
|
||||
if (_currentClientSecure.available())
|
||||
{
|
||||
if (_parseRequest(_currentClientSecure))
|
||||
{
|
||||
_currentClientSecure.setTimeout(HTTP_MAX_SEND_WAIT);
|
||||
_contentLength = CONTENT_LENGTH_NOT_SET;
|
||||
_handleRequest();
|
||||
|
||||
if (_currentClientSecure.connected())
|
||||
{
|
||||
_currentStatus = HC_WAIT_CLOSE;
|
||||
_statusChange = millis();
|
||||
keepCurrentClient = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // !_currentClient.available()
|
||||
{
|
||||
if (millis() - _statusChange <= HTTP_MAX_DATA_WAIT)
|
||||
{
|
||||
keepCurrentClient = true;
|
||||
}
|
||||
callYield = true;
|
||||
}
|
||||
break;
|
||||
case HC_WAIT_CLOSE:
|
||||
// Wait for client to close the connection
|
||||
if (millis() - _statusChange <= HTTP_MAX_CLOSE_WAIT)
|
||||
{
|
||||
keepCurrentClient = true;
|
||||
callYield = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!keepCurrentClient)
|
||||
{
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
_currentClientSecure = WiFiClientSecure();
|
||||
_currentClientSecure = WiFiClientSecure();
|
||||
#pragma GCC diagnostic pop
|
||||
_currentStatus = HC_NONE;
|
||||
_currentUpload.reset();
|
||||
}
|
||||
_currentStatus = HC_NONE;
|
||||
_currentUpload.reset();
|
||||
}
|
||||
|
||||
if (callYield) {
|
||||
yield();
|
||||
}
|
||||
if (callYield)
|
||||
{
|
||||
yield();
|
||||
}
|
||||
}
|
||||
|
||||
void ESP8266WebServerSecure::close() {
|
||||
_currentClientSecure.stop();
|
||||
_serverSecure.close();
|
||||
void ESP8266WebServerSecure::close()
|
||||
{
|
||||
_currentClientSecure.stop();
|
||||
_serverSecure.close();
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -1,22 +1,22 @@
|
||||
/*
|
||||
ESP8266WebServerSecure.h - Dead simple HTTPS web-server.
|
||||
Supports only one simultaneous client, knows how to handle GET and POST.
|
||||
ESP8266WebServerSecure.h - Dead simple HTTPS web-server.
|
||||
Supports only one simultaneous client, knows how to handle GET and POST.
|
||||
|
||||
Copyright (c) 2017 Earle F. Philhower, III. All rights reserved.
|
||||
Copyright (c) 2017 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
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 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.
|
||||
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
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
@ -27,37 +27,48 @@
|
||||
#include <WiFiServerSecureAxTLS.h>
|
||||
#include <WiFiClientSecureAxTLS.h>
|
||||
|
||||
namespace axTLS {
|
||||
namespace axTLS
|
||||
{
|
||||
|
||||
class ESP8266WebServerSecure : public ESP8266WebServer
|
||||
{
|
||||
public:
|
||||
ESP8266WebServerSecure(IPAddress addr, int port = 443);
|
||||
ESP8266WebServerSecure(int port = 443);
|
||||
virtual ~ESP8266WebServerSecure();
|
||||
ESP8266WebServerSecure(IPAddress addr, int port = 443);
|
||||
ESP8266WebServerSecure(int port = 443);
|
||||
virtual ~ESP8266WebServerSecure();
|
||||
|
||||
void setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen);
|
||||
void setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen);
|
||||
void setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen);
|
||||
void setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen);
|
||||
|
||||
WiFiClient client() override { return _currentClientSecure; }
|
||||
WiFiClient client() override
|
||||
{
|
||||
return _currentClientSecure;
|
||||
}
|
||||
|
||||
void begin() override;
|
||||
void handleClient() override;
|
||||
void close() override;
|
||||
void begin() override;
|
||||
void handleClient() override;
|
||||
void close() override;
|
||||
|
||||
template<typename T>
|
||||
size_t streamFile(T &file, const String& contentType) {
|
||||
_streamFileCore(file.size(), file.name(), contentType);
|
||||
return _currentClientSecure.write(file);
|
||||
}
|
||||
template<typename T>
|
||||
size_t streamFile(T &file, const String& contentType)
|
||||
{
|
||||
_streamFileCore(file.size(), file.name(), contentType);
|
||||
return _currentClientSecure.write(file);
|
||||
}
|
||||
|
||||
private:
|
||||
size_t _currentClientWrite (const char *bytes, size_t len) override { return _currentClientSecure.write((const uint8_t *)bytes, len); }
|
||||
size_t _currentClientWrite_P (PGM_P bytes, size_t len) override { return _currentClientSecure.write_P(bytes, len); }
|
||||
size_t _currentClientWrite(const char *bytes, size_t len) override
|
||||
{
|
||||
return _currentClientSecure.write((const uint8_t *)bytes, len);
|
||||
}
|
||||
size_t _currentClientWrite_P(PGM_P bytes, size_t len) override
|
||||
{
|
||||
return _currentClientSecure.write_P(bytes, len);
|
||||
}
|
||||
|
||||
protected:
|
||||
WiFiServerSecure _serverSecure;
|
||||
WiFiClientSecure _currentClientSecure;
|
||||
WiFiServerSecure _serverSecure;
|
||||
WiFiClientSecure _currentClientSecure;
|
||||
};
|
||||
|
||||
};
|
||||
|
@ -1,23 +1,23 @@
|
||||
/*
|
||||
ESP8266WebServerSecure.cpp - Dead simple HTTPS web-server.
|
||||
Supports only one simultaneous client, knows how to handle GET and POST.
|
||||
ESP8266WebServerSecure.cpp - Dead simple HTTPS web-server.
|
||||
Supports only one simultaneous client, knows how to handle GET and POST.
|
||||
|
||||
Copyright (c) 2017 Earle F. Philhower, III. All rights reserved.
|
||||
Copyright (c) 2017 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
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 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.
|
||||
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
|
||||
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
|
||||
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
|
||||
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
|
||||
*/
|
||||
|
||||
|
||||
@ -34,132 +34,153 @@
|
||||
#define DEBUG_OUTPUT Serial
|
||||
#endif
|
||||
|
||||
namespace BearSSL {
|
||||
namespace BearSSL
|
||||
{
|
||||
|
||||
ESP8266WebServerSecure::ESP8266WebServerSecure(IPAddress addr, int port)
|
||||
: _serverSecure(addr, port)
|
||||
ESP8266WebServerSecure::ESP8266WebServerSecure(IPAddress addr, int port)
|
||||
: _serverSecure(addr, port)
|
||||
{
|
||||
}
|
||||
|
||||
ESP8266WebServerSecure::ESP8266WebServerSecure(int port)
|
||||
: _serverSecure(port)
|
||||
: _serverSecure(port)
|
||||
{
|
||||
}
|
||||
|
||||
void ESP8266WebServerSecure::setRSACert(const X509List *chain, const PrivateKey *sk)
|
||||
{
|
||||
_serverSecure.setRSACert(chain, sk);
|
||||
_serverSecure.setRSACert(chain, sk);
|
||||
}
|
||||
|
||||
void ESP8266WebServerSecure::setECCert(const X509List *chain, unsigned cert_issuer_key_type, const PrivateKey *sk)
|
||||
{
|
||||
_serverSecure.setECCert(chain, cert_issuer_key_type, sk);
|
||||
_serverSecure.setECCert(chain, cert_issuer_key_type, sk);
|
||||
}
|
||||
|
||||
void ESP8266WebServerSecure::setBufferSizes(int recv, int xmit)
|
||||
{
|
||||
_serverSecure.setBufferSizes(recv, xmit);
|
||||
_serverSecure.setBufferSizes(recv, xmit);
|
||||
}
|
||||
|
||||
ESP8266WebServerSecure::~ESP8266WebServerSecure() {
|
||||
// Nothing to do here.
|
||||
// Base class's destructor will be called to clean up itself
|
||||
ESP8266WebServerSecure::~ESP8266WebServerSecure()
|
||||
{
|
||||
// Nothing to do here.
|
||||
// Base class's destructor will be called to clean up itself
|
||||
}
|
||||
|
||||
// We need to basically cut-n-paste these from WebServer because of the problem
|
||||
// of object slicing. The class uses assignment operators like "WiFiClient x=y;"
|
||||
// When this happens, even if "y" is a WiFiClientSecure, the main class is
|
||||
// When this happens, even if "y" is a WiFiClientSecure, the main class is
|
||||
// already compiled down into code which will only copy the WiFiClient superclass
|
||||
// and not the extra bits for our own class (since when it was compiled it needed
|
||||
// to know the size of memory to allocate on the stack for this local variable
|
||||
// there's not realy anything else it could do).
|
||||
|
||||
void ESP8266WebServerSecure::begin() {
|
||||
_currentStatus = HC_NONE;
|
||||
_serverSecure.begin();
|
||||
if(!_headerKeysCount)
|
||||
collectHeaders(0, 0);
|
||||
void ESP8266WebServerSecure::begin()
|
||||
{
|
||||
_currentStatus = HC_NONE;
|
||||
_serverSecure.begin();
|
||||
if (!_headerKeysCount)
|
||||
{
|
||||
collectHeaders(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void ESP8266WebServerSecure::handleClient() {
|
||||
if (_currentStatus == HC_NONE) {
|
||||
WiFiClientSecure client = _serverSecure.available();
|
||||
if (!client) {
|
||||
return;
|
||||
}
|
||||
void ESP8266WebServerSecure::handleClient()
|
||||
{
|
||||
if (_currentStatus == HC_NONE)
|
||||
{
|
||||
WiFiClientSecure client = _serverSecure.available();
|
||||
if (!client)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ESP_HTTP_SERVER
|
||||
DEBUG_OUTPUT.println("New secure client");
|
||||
DEBUG_OUTPUT.println("New secure client");
|
||||
#endif
|
||||
|
||||
_currentClientSecure = client;
|
||||
_currentStatus = HC_WAIT_READ;
|
||||
_statusChange = millis();
|
||||
}
|
||||
|
||||
bool keepCurrentClient = false;
|
||||
bool callYield = false;
|
||||
|
||||
if (_currentClientSecure.connected()) {
|
||||
switch (_currentStatus) {
|
||||
case HC_NONE:
|
||||
// No-op to avoid C++ compiler warning
|
||||
break;
|
||||
case HC_WAIT_READ:
|
||||
// Wait for data from client to become available
|
||||
if (_currentClientSecure.available()) {
|
||||
if (_parseRequest(_currentClientSecure)) {
|
||||
_currentClientSecure.setTimeout(HTTP_MAX_SEND_WAIT);
|
||||
_contentLength = CONTENT_LENGTH_NOT_SET;
|
||||
_handleRequest();
|
||||
|
||||
if (_currentClientSecure.connected()) {
|
||||
_currentStatus = HC_WAIT_CLOSE;
|
||||
_statusChange = millis();
|
||||
keepCurrentClient = true;
|
||||
}
|
||||
}
|
||||
} else { // !_currentClient.available()
|
||||
if (millis() - _statusChange <= HTTP_MAX_DATA_WAIT) {
|
||||
keepCurrentClient = true;
|
||||
}
|
||||
callYield = true;
|
||||
}
|
||||
break;
|
||||
case HC_WAIT_CLOSE:
|
||||
// Wait for client to close the connection
|
||||
if (millis() - _statusChange <= HTTP_MAX_CLOSE_WAIT) {
|
||||
keepCurrentClient = true;
|
||||
callYield = true;
|
||||
}
|
||||
_currentClientSecure = client;
|
||||
_currentStatus = HC_WAIT_READ;
|
||||
_statusChange = millis();
|
||||
}
|
||||
}
|
||||
|
||||
if (!keepCurrentClient) {
|
||||
_currentClientSecure = WiFiClientSecure();
|
||||
_currentStatus = HC_NONE;
|
||||
_currentUpload.reset();
|
||||
}
|
||||
bool keepCurrentClient = false;
|
||||
bool callYield = false;
|
||||
|
||||
if (callYield) {
|
||||
yield();
|
||||
}
|
||||
if (_currentClientSecure.connected())
|
||||
{
|
||||
switch (_currentStatus)
|
||||
{
|
||||
case HC_NONE:
|
||||
// No-op to avoid C++ compiler warning
|
||||
break;
|
||||
case HC_WAIT_READ:
|
||||
// Wait for data from client to become available
|
||||
if (_currentClientSecure.available())
|
||||
{
|
||||
if (_parseRequest(_currentClientSecure))
|
||||
{
|
||||
_currentClientSecure.setTimeout(HTTP_MAX_SEND_WAIT);
|
||||
_contentLength = CONTENT_LENGTH_NOT_SET;
|
||||
_handleRequest();
|
||||
|
||||
if (_currentClientSecure.connected())
|
||||
{
|
||||
_currentStatus = HC_WAIT_CLOSE;
|
||||
_statusChange = millis();
|
||||
keepCurrentClient = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // !_currentClient.available()
|
||||
{
|
||||
if (millis() - _statusChange <= HTTP_MAX_DATA_WAIT)
|
||||
{
|
||||
keepCurrentClient = true;
|
||||
}
|
||||
callYield = true;
|
||||
}
|
||||
break;
|
||||
case HC_WAIT_CLOSE:
|
||||
// Wait for client to close the connection
|
||||
if (millis() - _statusChange <= HTTP_MAX_CLOSE_WAIT)
|
||||
{
|
||||
keepCurrentClient = true;
|
||||
callYield = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!keepCurrentClient)
|
||||
{
|
||||
_currentClientSecure = WiFiClientSecure();
|
||||
_currentStatus = HC_NONE;
|
||||
_currentUpload.reset();
|
||||
}
|
||||
|
||||
if (callYield)
|
||||
{
|
||||
yield();
|
||||
}
|
||||
}
|
||||
|
||||
void ESP8266WebServerSecure::close() {
|
||||
_currentClientSecure.flush();
|
||||
_currentClientSecure.stop();
|
||||
_serverSecure.close();
|
||||
void ESP8266WebServerSecure::close()
|
||||
{
|
||||
_currentClientSecure.flush();
|
||||
_currentClientSecure.stop();
|
||||
_serverSecure.close();
|
||||
}
|
||||
|
||||
|
||||
void ESP8266WebServerSecure::setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen) {
|
||||
_serverSecure.setServerKeyAndCert_P(key, keyLen, cert, certLen);
|
||||
void ESP8266WebServerSecure::setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen)
|
||||
{
|
||||
_serverSecure.setServerKeyAndCert_P(key, keyLen, cert, certLen);
|
||||
}
|
||||
|
||||
void ESP8266WebServerSecure::setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen)
|
||||
{
|
||||
_serverSecure.setServerKeyAndCert(key, keyLen, cert, certLen);
|
||||
_serverSecure.setServerKeyAndCert(key, keyLen, cert, certLen);
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -1,22 +1,22 @@
|
||||
/*
|
||||
ESP8266WebServerSecure.h - Dead simple HTTPS web-server.
|
||||
Supports only one simultaneous client, knows how to handle GET and POST.
|
||||
ESP8266WebServerSecure.h - Dead simple HTTPS web-server.
|
||||
Supports only one simultaneous client, knows how to handle GET and POST.
|
||||
|
||||
Copyright (c) 2017 Earle F. Philhower, III. All rights reserved.
|
||||
Copyright (c) 2017 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
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 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.
|
||||
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
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
@ -27,42 +27,53 @@
|
||||
#include <BearSSLHelpers.h>
|
||||
#include <WiFiServerSecureBearSSL.h>
|
||||
|
||||
namespace BearSSL {
|
||||
namespace BearSSL
|
||||
{
|
||||
|
||||
class ESP8266WebServerSecure : public ESP8266WebServer
|
||||
{
|
||||
public:
|
||||
ESP8266WebServerSecure(IPAddress addr, int port = 443);
|
||||
ESP8266WebServerSecure(int port = 443);
|
||||
virtual ~ESP8266WebServerSecure();
|
||||
ESP8266WebServerSecure(IPAddress addr, int port = 443);
|
||||
ESP8266WebServerSecure(int port = 443);
|
||||
virtual ~ESP8266WebServerSecure();
|
||||
|
||||
void setBufferSizes(int recv, int xmit);
|
||||
void setRSACert(const X509List *chain, const PrivateKey *sk);
|
||||
void setECCert(const X509List *chain, unsigned cert_issuer_key_type, const PrivateKey *sk);
|
||||
void setBufferSizes(int recv, int xmit);
|
||||
void setRSACert(const X509List *chain, const PrivateKey *sk);
|
||||
void setECCert(const X509List *chain, unsigned cert_issuer_key_type, const PrivateKey *sk);
|
||||
|
||||
WiFiClient client() override { return _currentClientSecure; }
|
||||
WiFiClient client() override
|
||||
{
|
||||
return _currentClientSecure;
|
||||
}
|
||||
|
||||
void begin() override;
|
||||
void handleClient() override;
|
||||
void close() override;
|
||||
void begin() override;
|
||||
void handleClient() override;
|
||||
void close() override;
|
||||
|
||||
template<typename T>
|
||||
size_t streamFile(T &file, const String& contentType) {
|
||||
_streamFileCore(file.size(), file.name(), contentType);
|
||||
return _currentClientSecure.write(file);
|
||||
}
|
||||
template<typename T>
|
||||
size_t streamFile(T &file, const String& contentType)
|
||||
{
|
||||
_streamFileCore(file.size(), file.name(), contentType);
|
||||
return _currentClientSecure.write(file);
|
||||
}
|
||||
|
||||
// AXTLS Compatibility
|
||||
void setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen);
|
||||
void setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen);
|
||||
// AXTLS Compatibility
|
||||
void setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen);
|
||||
void setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen);
|
||||
|
||||
private:
|
||||
size_t _currentClientWrite (const char *bytes, size_t len) override { return _currentClientSecure.write((const uint8_t *)bytes, len); }
|
||||
size_t _currentClientWrite_P (PGM_P bytes, size_t len) override { return _currentClientSecure.write_P(bytes, len); }
|
||||
size_t _currentClientWrite(const char *bytes, size_t len) override
|
||||
{
|
||||
return _currentClientSecure.write((const uint8_t *)bytes, len);
|
||||
}
|
||||
size_t _currentClientWrite_P(PGM_P bytes, size_t len) override
|
||||
{
|
||||
return _currentClientSecure.write_P(bytes, len);
|
||||
}
|
||||
|
||||
protected:
|
||||
WiFiServerSecure _serverSecure;
|
||||
WiFiClientSecure _currentClientSecure;
|
||||
WiFiServerSecure _serverSecure;
|
||||
WiFiClientSecure _currentClientSecure;
|
||||
};
|
||||
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,16 +1,43 @@
|
||||
#ifndef REQUESTHANDLER_H
|
||||
#define REQUESTHANDLER_H
|
||||
|
||||
class RequestHandler {
|
||||
class RequestHandler
|
||||
{
|
||||
public:
|
||||
virtual ~RequestHandler() { }
|
||||
virtual bool canHandle(HTTPMethod method, String uri) { (void) method; (void) uri; return false; }
|
||||
virtual bool canUpload(String uri) { (void) uri; return false; }
|
||||
virtual bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) { (void) server; (void) requestMethod; (void) requestUri; return false; }
|
||||
virtual void upload(ESP8266WebServer& server, String requestUri, HTTPUpload& upload) { (void) server; (void) requestUri; (void) upload; }
|
||||
virtual bool canHandle(HTTPMethod method, String uri)
|
||||
{
|
||||
(void) method;
|
||||
(void) uri;
|
||||
return false;
|
||||
}
|
||||
virtual bool canUpload(String uri)
|
||||
{
|
||||
(void) uri;
|
||||
return false;
|
||||
}
|
||||
virtual bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri)
|
||||
{
|
||||
(void) server;
|
||||
(void) requestMethod;
|
||||
(void) requestUri;
|
||||
return false;
|
||||
}
|
||||
virtual void upload(ESP8266WebServer& server, String requestUri, HTTPUpload& upload)
|
||||
{
|
||||
(void) server;
|
||||
(void) requestUri;
|
||||
(void) upload;
|
||||
}
|
||||
|
||||
RequestHandler* next() { return _next; }
|
||||
void next(RequestHandler* r) { _next = r; }
|
||||
RequestHandler* next()
|
||||
{
|
||||
return _next;
|
||||
}
|
||||
void next(RequestHandler* r)
|
||||
{
|
||||
_next = r;
|
||||
}
|
||||
|
||||
private:
|
||||
RequestHandler* _next = nullptr;
|
||||
|
@ -7,47 +7,62 @@
|
||||
|
||||
using namespace mime;
|
||||
|
||||
class FunctionRequestHandler : public RequestHandler {
|
||||
class FunctionRequestHandler : public RequestHandler
|
||||
{
|
||||
public:
|
||||
FunctionRequestHandler(ESP8266WebServer::THandlerFunction fn, ESP8266WebServer::THandlerFunction ufn, const String &uri, HTTPMethod method)
|
||||
: _fn(fn)
|
||||
, _ufn(ufn)
|
||||
, _uri(uri)
|
||||
, _method(method)
|
||||
: _fn(fn)
|
||||
, _ufn(ufn)
|
||||
, _uri(uri)
|
||||
, _method(method)
|
||||
{
|
||||
}
|
||||
|
||||
bool canHandle(HTTPMethod requestMethod, String requestUri) override {
|
||||
bool canHandle(HTTPMethod requestMethod, String requestUri) override
|
||||
{
|
||||
if (_method != HTTP_ANY && _method != requestMethod)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (requestUri != _uri)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool canUpload(String requestUri) override {
|
||||
bool canUpload(String requestUri) override
|
||||
{
|
||||
if (!_ufn || !canHandle(HTTP_POST, requestUri))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) override {
|
||||
bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) override
|
||||
{
|
||||
(void) server;
|
||||
if (!canHandle(requestMethod, requestUri))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_fn();
|
||||
return true;
|
||||
}
|
||||
|
||||
void upload(ESP8266WebServer& server, String requestUri, HTTPUpload& upload) override {
|
||||
void upload(ESP8266WebServer& server, String requestUri, HTTPUpload& upload) override
|
||||
{
|
||||
(void) server;
|
||||
(void) upload;
|
||||
if (canUpload(requestUri))
|
||||
{
|
||||
_ufn();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -57,42 +72,54 @@ protected:
|
||||
HTTPMethod _method;
|
||||
};
|
||||
|
||||
class StaticRequestHandler : public RequestHandler {
|
||||
class StaticRequestHandler : public RequestHandler
|
||||
{
|
||||
public:
|
||||
StaticRequestHandler(FS& fs, const char* path, const char* uri, const char* cache_header)
|
||||
: _fs(fs)
|
||||
, _uri(uri)
|
||||
, _path(path)
|
||||
, _cache_header(cache_header)
|
||||
: _fs(fs)
|
||||
, _uri(uri)
|
||||
, _path(path)
|
||||
, _cache_header(cache_header)
|
||||
{
|
||||
_isFile = fs.exists(path);
|
||||
DEBUGV("StaticRequestHandler: path=%s uri=%s isFile=%d, cache_header=%s\r\n", path, uri, _isFile, cache_header);
|
||||
_baseUriLength = _uri.length();
|
||||
}
|
||||
|
||||
bool canHandle(HTTPMethod requestMethod, String requestUri) override {
|
||||
bool canHandle(HTTPMethod requestMethod, String requestUri) override
|
||||
{
|
||||
if (requestMethod != HTTP_GET)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((_isFile && requestUri != _uri) || !requestUri.startsWith(_uri))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) override {
|
||||
bool handle(ESP8266WebServer& server, HTTPMethod requestMethod, String requestUri) override
|
||||
{
|
||||
if (!canHandle(requestMethod, requestUri))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUGV("StaticRequestHandler::handle: request=%s _uri=%s\r\n", requestUri.c_str(), _uri.c_str());
|
||||
|
||||
String path(_path);
|
||||
|
||||
if (!_isFile) {
|
||||
if (!_isFile)
|
||||
{
|
||||
// Base URI doesn't point to a file.
|
||||
// If a directory is requested, look for index file.
|
||||
if (requestUri.endsWith("/"))
|
||||
requestUri += "index.htm";
|
||||
if (requestUri.endsWith("/"))
|
||||
{
|
||||
requestUri += "index.htm";
|
||||
}
|
||||
|
||||
// Append whatever follows this URI in request to get the file path.
|
||||
path += requestUri.substring(_baseUriLength);
|
||||
@ -103,35 +130,45 @@ public:
|
||||
|
||||
// look for gz file, only if the original specified path is not a gz. So part only works to send gzip via content encoding when a non compressed is asked for
|
||||
// if you point the the path to gzip you will serve the gzip as content type "application/x-gzip", not text or javascript etc...
|
||||
if (!path.endsWith(FPSTR(mimeTable[gz].endsWith)) && !_fs.exists(path)) {
|
||||
if (!path.endsWith(FPSTR(mimeTable[gz].endsWith)) && !_fs.exists(path))
|
||||
{
|
||||
String pathWithGz = path + FPSTR(mimeTable[gz].endsWith);
|
||||
if(_fs.exists(pathWithGz))
|
||||
if (_fs.exists(pathWithGz))
|
||||
{
|
||||
path += FPSTR(mimeTable[gz].endsWith);
|
||||
}
|
||||
}
|
||||
|
||||
File f = _fs.open(path, "r");
|
||||
if (!f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_cache_header.length() != 0)
|
||||
{
|
||||
server.sendHeader("Cache-Control", _cache_header);
|
||||
}
|
||||
|
||||
server.streamFile(f, contentType);
|
||||
return true;
|
||||
}
|
||||
|
||||
static String getContentType(const String& path) {
|
||||
static String getContentType(const String& path)
|
||||
{
|
||||
char buff[sizeof(mimeTable[0].mimeType)];
|
||||
// Check all entries but last one for match, return if found
|
||||
for (size_t i=0; i < sizeof(mimeTable)/sizeof(mimeTable[0])-1; i++) {
|
||||
for (size_t i = 0; i < sizeof(mimeTable) / sizeof(mimeTable[0]) - 1; i++)
|
||||
{
|
||||
strcpy_P(buff, mimeTable[i].endsWith);
|
||||
if (path.endsWith(buff)) {
|
||||
if (path.endsWith(buff))
|
||||
{
|
||||
strcpy_P(buff, mimeTable[i].mimeType);
|
||||
return String(buff);
|
||||
}
|
||||
}
|
||||
// Fall-through and just return default type
|
||||
strcpy_P(buff, mimeTable[sizeof(mimeTable)/sizeof(mimeTable[0])-1].mimeType);
|
||||
strcpy_P(buff, mimeTable[sizeof(mimeTable) / sizeof(mimeTable[0]) - 1].mimeType);
|
||||
return String(buff);
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ namespace mime
|
||||
{
|
||||
|
||||
// Table of extension->MIME strings stored in PROGMEM, needs to be global due to GCC section typing rules
|
||||
const Entry mimeTable[maxType] PROGMEM =
|
||||
const Entry mimeTable[maxType] PROGMEM =
|
||||
{
|
||||
{ ".html", "text/html" },
|
||||
{ ".htm", "text/html" },
|
||||
@ -29,7 +29,7 @@ const Entry mimeTable[maxType] PROGMEM =
|
||||
{ ".zip", "application/zip" },
|
||||
{ ".gz", "application/x-gzip" },
|
||||
{ ".appcache", "text/cache-manifest" },
|
||||
{ "", "application/octet-stream" }
|
||||
{ "", "application/octet-stream" }
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -7,36 +7,36 @@ namespace mime
|
||||
|
||||
enum type
|
||||
{
|
||||
html,
|
||||
htm,
|
||||
css,
|
||||
txt,
|
||||
js,
|
||||
json,
|
||||
png,
|
||||
gif,
|
||||
jpg,
|
||||
ico,
|
||||
svg,
|
||||
ttf,
|
||||
otf,
|
||||
woff,
|
||||
woff2,
|
||||
eot,
|
||||
sfnt,
|
||||
xml,
|
||||
pdf,
|
||||
zip,
|
||||
gz,
|
||||
appcache,
|
||||
none,
|
||||
maxType
|
||||
html,
|
||||
htm,
|
||||
css,
|
||||
txt,
|
||||
js,
|
||||
json,
|
||||
png,
|
||||
gif,
|
||||
jpg,
|
||||
ico,
|
||||
svg,
|
||||
ttf,
|
||||
otf,
|
||||
woff,
|
||||
woff2,
|
||||
eot,
|
||||
sfnt,
|
||||
xml,
|
||||
pdf,
|
||||
zip,
|
||||
gz,
|
||||
appcache,
|
||||
none,
|
||||
maxType
|
||||
};
|
||||
|
||||
struct Entry
|
||||
{
|
||||
const char endsWith[16];
|
||||
const char mimeType[32];
|
||||
const char endsWith[16];
|
||||
const char mimeType[32];
|
||||
};
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,23 +1,23 @@
|
||||
/*
|
||||
WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries
|
||||
- Mostly compatible with Arduino WiFi shield library and standard
|
||||
WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries
|
||||
- Mostly compatible with Arduino WiFi shield library and standard
|
||||
WiFiClient/ServerSecure (except for certificate handling).
|
||||
|
||||
Copyright (c) 2018 Earle F. Philhower, III
|
||||
Copyright (c) 2018 Earle F. Philhower, III
|
||||
|
||||
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 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.
|
||||
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
|
||||
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 _BEARSSLHELPERS_H
|
||||
@ -28,18 +28,21 @@
|
||||
|
||||
|
||||
// Internal opaque structures, not needed by user applications
|
||||
namespace brssl {
|
||||
class public_key;
|
||||
class private_key;
|
||||
namespace brssl
|
||||
{
|
||||
class public_key;
|
||||
class private_key;
|
||||
};
|
||||
|
||||
namespace BearSSL {
|
||||
namespace BearSSL
|
||||
{
|
||||
|
||||
// Holds either a single public RSA or EC key for use when BearSSL wants a pubkey.
|
||||
// Copies all associated data so no need to keep input PEM/DER keys.
|
||||
// All inputs can be either in RAM or PROGMEM.
|
||||
class PublicKey {
|
||||
public:
|
||||
class PublicKey
|
||||
{
|
||||
public:
|
||||
PublicKey();
|
||||
PublicKey(const char *pemKey);
|
||||
PublicKey(const uint8_t *derKey, size_t derLen);
|
||||
@ -57,15 +60,16 @@ class PublicKey {
|
||||
// Disable the copy constructor, we're pointer based
|
||||
PublicKey(const PublicKey& that) = delete;
|
||||
|
||||
private:
|
||||
private:
|
||||
brssl::public_key *_key;
|
||||
};
|
||||
|
||||
// Holds either a single private RSA or EC key for use when BearSSL wants a secretkey.
|
||||
// Copies all associated data so no need to keep input PEM/DER keys.
|
||||
// All inputs can be either in RAM or PROGMEM.
|
||||
class PrivateKey {
|
||||
public:
|
||||
class PrivateKey
|
||||
{
|
||||
public:
|
||||
PrivateKey();
|
||||
PrivateKey(const char *pemKey);
|
||||
PrivateKey(const uint8_t *derKey, size_t derLen);
|
||||
@ -83,7 +87,7 @@ class PrivateKey {
|
||||
// Disable the copy constructor, we're pointer based
|
||||
PrivateKey(const PrivateKey& that) = delete;
|
||||
|
||||
private:
|
||||
private:
|
||||
brssl::private_key *_key;
|
||||
};
|
||||
|
||||
@ -93,8 +97,9 @@ class PrivateKey {
|
||||
// for a more memory efficient way).
|
||||
// Copies all associated data so no need to keep input PEM/DER certs.
|
||||
// All inputs can be either in RAM or PROGMEM.
|
||||
class X509List {
|
||||
public:
|
||||
class X509List
|
||||
{
|
||||
public:
|
||||
X509List();
|
||||
X509List(const char *pemCert);
|
||||
X509List(const uint8_t *derCert, size_t derLen);
|
||||
@ -104,20 +109,23 @@ class X509List {
|
||||
bool append(const uint8_t *derCert, size_t derLen);
|
||||
|
||||
// Accessors
|
||||
size_t getCount() const {
|
||||
return _count;
|
||||
size_t getCount() const
|
||||
{
|
||||
return _count;
|
||||
}
|
||||
const br_x509_certificate *getX509Certs() const {
|
||||
return _cert;
|
||||
const br_x509_certificate *getX509Certs() const
|
||||
{
|
||||
return _cert;
|
||||
}
|
||||
const br_x509_trust_anchor *getTrustAnchors() const {
|
||||
return _ta;
|
||||
const br_x509_trust_anchor *getTrustAnchors() const
|
||||
{
|
||||
return _ta;
|
||||
}
|
||||
|
||||
// Disable the copy constructor, we're pointer based
|
||||
X509List(const X509List& that) = delete;
|
||||
|
||||
private:
|
||||
private:
|
||||
size_t _count;
|
||||
br_x509_certificate *_cert;
|
||||
br_x509_trust_anchor *_ta;
|
||||
@ -127,52 +135,64 @@ class X509List {
|
||||
// significantly faster. Completely optional.
|
||||
class WiFiClientSecure;
|
||||
|
||||
class Session {
|
||||
friend class WiFiClientSecure;
|
||||
class Session
|
||||
{
|
||||
friend class WiFiClientSecure;
|
||||
|
||||
public:
|
||||
Session() { memset(&_session, 0, sizeof(_session)); }
|
||||
private:
|
||||
br_ssl_session_parameters *getSession() { return &_session; }
|
||||
public:
|
||||
Session()
|
||||
{
|
||||
memset(&_session, 0, sizeof(_session));
|
||||
}
|
||||
private:
|
||||
br_ssl_session_parameters *getSession()
|
||||
{
|
||||
return &_session;
|
||||
}
|
||||
// The actual BearSSL ession information
|
||||
br_ssl_session_parameters _session;
|
||||
};
|
||||
|
||||
// Updater SHA256 hash and signature verification
|
||||
class HashSHA256 : public UpdaterHashClass {
|
||||
public:
|
||||
class HashSHA256 : public UpdaterHashClass
|
||||
{
|
||||
public:
|
||||
virtual void begin() override;
|
||||
virtual void add(const void *data, uint32_t len) override;
|
||||
virtual void end() override;
|
||||
virtual int len() override;
|
||||
virtual const void *hash() override;
|
||||
private:
|
||||
private:
|
||||
br_sha256_context _cc;
|
||||
unsigned char _sha256[32];
|
||||
};
|
||||
|
||||
class SigningVerifier : public UpdaterVerifyClass {
|
||||
public:
|
||||
class SigningVerifier : public UpdaterVerifyClass
|
||||
{
|
||||
public:
|
||||
virtual uint32_t length() override;
|
||||
virtual bool verify(UpdaterHashClass *hash, const void *signature, uint32_t signatureLen) override;
|
||||
|
||||
public:
|
||||
SigningVerifier(PublicKey *pubKey) { _pubKey = pubKey; }
|
||||
public:
|
||||
SigningVerifier(PublicKey *pubKey)
|
||||
{
|
||||
_pubKey = pubKey;
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
PublicKey *_pubKey;
|
||||
};
|
||||
|
||||
|
||||
// Stack thunked versions of calls
|
||||
extern "C" {
|
||||
extern unsigned char *thunk_br_ssl_engine_recvapp_buf( const br_ssl_engine_context *cc, size_t *len);
|
||||
extern void thunk_br_ssl_engine_recvapp_ack(br_ssl_engine_context *cc, size_t len);
|
||||
extern unsigned char *thunk_br_ssl_engine_recvrec_buf( const br_ssl_engine_context *cc, size_t *len);
|
||||
extern void thunk_br_ssl_engine_recvrec_ack(br_ssl_engine_context *cc, size_t len);
|
||||
extern unsigned char *thunk_br_ssl_engine_sendapp_buf( const br_ssl_engine_context *cc, size_t *len);
|
||||
extern void thunk_br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len);
|
||||
extern unsigned char *thunk_br_ssl_engine_sendrec_buf( const br_ssl_engine_context *cc, size_t *len);
|
||||
extern void thunk_br_ssl_engine_sendrec_ack(br_ssl_engine_context *cc, size_t len);
|
||||
extern unsigned char *thunk_br_ssl_engine_recvapp_buf(const br_ssl_engine_context *cc, size_t *len);
|
||||
extern void thunk_br_ssl_engine_recvapp_ack(br_ssl_engine_context *cc, size_t len);
|
||||
extern unsigned char *thunk_br_ssl_engine_recvrec_buf(const br_ssl_engine_context *cc, size_t *len);
|
||||
extern void thunk_br_ssl_engine_recvrec_ack(br_ssl_engine_context *cc, size_t len);
|
||||
extern unsigned char *thunk_br_ssl_engine_sendapp_buf(const br_ssl_engine_context *cc, size_t *len);
|
||||
extern void thunk_br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len);
|
||||
extern unsigned char *thunk_br_ssl_engine_sendrec_buf(const br_ssl_engine_context *cc, size_t *len);
|
||||
extern void thunk_br_ssl_engine_sendrec_ack(br_ssl_engine_context *cc, size_t len);
|
||||
};
|
||||
|
||||
};
|
||||
|
@ -1,20 +1,20 @@
|
||||
/*
|
||||
CertStoreBearSSL.cpp - Library for Arduino ESP8266
|
||||
Copyright (c) 2018 Earle F. Philhower, III
|
||||
CertStoreBearSSL.cpp - Library for Arduino ESP8266
|
||||
Copyright (c) 2018 Earle F. Philhower, III
|
||||
|
||||
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 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.
|
||||
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
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "CertStoreBearSSL.h"
|
||||
@ -27,184 +27,213 @@
|
||||
#define DEBUG_BSSL(...)
|
||||
#endif
|
||||
|
||||
namespace BearSSL {
|
||||
namespace BearSSL
|
||||
{
|
||||
|
||||
extern "C" {
|
||||
// Callback for the x509 decoder
|
||||
static void dn_append(void *ctx, const void *buf, size_t len) {
|
||||
br_sha256_context *sha1 = (br_sha256_context*)ctx;
|
||||
br_sha256_update(sha1, buf, len);
|
||||
}
|
||||
// Callback for the x509 decoder
|
||||
static void dn_append(void *ctx, const void *buf, size_t len)
|
||||
{
|
||||
br_sha256_context *sha1 = (br_sha256_context*)ctx;
|
||||
br_sha256_update(sha1, buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
CertStore::CertInfo CertStore::_preprocessCert(uint32_t length, uint32_t offset, const void *raw) {
|
||||
CertStore::CertInfo ci;
|
||||
CertStore::CertInfo CertStore::_preprocessCert(uint32_t length, uint32_t offset, const void *raw)
|
||||
{
|
||||
CertStore::CertInfo ci;
|
||||
|
||||
// Clear the CertInfo
|
||||
memset(&ci, 0, sizeof(ci));
|
||||
// Clear the CertInfo
|
||||
memset(&ci, 0, sizeof(ci));
|
||||
|
||||
// Process it using SHA256, same as the hashed_dn
|
||||
br_x509_decoder_context *ctx = new br_x509_decoder_context;
|
||||
br_sha256_context *sha256 = new br_sha256_context;
|
||||
if (!ctx || !sha256) {
|
||||
DEBUG_BSSL("CertStore::_preprocessCert: OOM\n");
|
||||
// Process it using SHA256, same as the hashed_dn
|
||||
br_x509_decoder_context *ctx = new br_x509_decoder_context;
|
||||
br_sha256_context *sha256 = new br_sha256_context;
|
||||
if (!ctx || !sha256)
|
||||
{
|
||||
DEBUG_BSSL("CertStore::_preprocessCert: OOM\n");
|
||||
return ci;
|
||||
}
|
||||
|
||||
br_sha256_init(sha256);
|
||||
br_x509_decoder_init(ctx, dn_append, sha256, nullptr, nullptr);
|
||||
br_x509_decoder_push(ctx, (const void*)raw, length);
|
||||
|
||||
// Copy result to structure
|
||||
br_sha256_out(sha256, &ci.sha256);
|
||||
ci.length = length;
|
||||
ci.offset = offset;
|
||||
|
||||
// Clean up allocated memory
|
||||
delete sha256;
|
||||
delete ctx;
|
||||
|
||||
// Return result
|
||||
return ci;
|
||||
}
|
||||
|
||||
br_sha256_init(sha256);
|
||||
br_x509_decoder_init(ctx, dn_append, sha256, nullptr, nullptr);
|
||||
br_x509_decoder_push(ctx, (const void*)raw, length);
|
||||
|
||||
// Copy result to structure
|
||||
br_sha256_out(sha256, &ci.sha256);
|
||||
ci.length = length;
|
||||
ci.offset = offset;
|
||||
|
||||
// Clean up allocated memory
|
||||
delete sha256;
|
||||
delete ctx;
|
||||
|
||||
// Return result
|
||||
return ci;
|
||||
}
|
||||
|
||||
// The certs.ar file is a UNIX ar format file, concatenating all the
|
||||
// The certs.ar file is a UNIX ar format file, concatenating all the
|
||||
// individual certificates into a single blob in a space-efficient way.
|
||||
int CertStore::initCertStore(CertStoreFile *index, CertStoreFile *data) {
|
||||
int count = 0;
|
||||
uint32_t offset = 0;
|
||||
int CertStore::initCertStore(CertStoreFile *index, CertStoreFile *data)
|
||||
{
|
||||
int count = 0;
|
||||
uint32_t offset = 0;
|
||||
|
||||
_index = index;
|
||||
_data = data;
|
||||
_index = index;
|
||||
_data = data;
|
||||
|
||||
if (!_index || !data) {
|
||||
return 0;
|
||||
}
|
||||
if (!_index || !data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_index->open(true)) {
|
||||
return 0;
|
||||
}
|
||||
if (!_index->open(true))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_data->open(false)) {
|
||||
_index->close();
|
||||
return 0;
|
||||
}
|
||||
if (!_data->open(false))
|
||||
{
|
||||
_index->close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
char magic[8];
|
||||
if (_data->read(magic, sizeof(magic)) != sizeof(magic) ||
|
||||
memcmp(magic, "!<arch>\n", sizeof(magic)) ) {
|
||||
char magic[8];
|
||||
if (_data->read(magic, sizeof(magic)) != sizeof(magic) ||
|
||||
memcmp(magic, "!<arch>\n", sizeof(magic)))
|
||||
{
|
||||
_data->close();
|
||||
_index->close();
|
||||
return 0;
|
||||
}
|
||||
offset += sizeof(magic);
|
||||
|
||||
while (true)
|
||||
{
|
||||
char fileHeader[60];
|
||||
// 0..15 = filename in ASCII
|
||||
// 48...57 = length in decimal ASCII
|
||||
uint32_t length;
|
||||
if (data->read(fileHeader, sizeof(fileHeader)) != sizeof(fileHeader))
|
||||
{
|
||||
break;
|
||||
}
|
||||
offset += sizeof(fileHeader);
|
||||
fileHeader[58] = 0;
|
||||
if (1 != sscanf(fileHeader + 48, "%d", &length) || !length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
void *raw = malloc(length);
|
||||
if (!raw)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (_data->read(raw, length) != (ssize_t)length)
|
||||
{
|
||||
free(raw);
|
||||
break;
|
||||
}
|
||||
|
||||
// If the filename starts with "//" then this is a rename file, skip it
|
||||
if (fileHeader[0] != '/' || fileHeader[1] != '/')
|
||||
{
|
||||
CertStore::CertInfo ci = _preprocessCert(length, offset, raw);
|
||||
if (_index->write(&ci, sizeof(ci)) != (ssize_t)sizeof(ci))
|
||||
{
|
||||
free(raw);
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
offset += length;
|
||||
free(raw);
|
||||
if (offset & 1)
|
||||
{
|
||||
char x;
|
||||
_data->read(&x, 1);
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
_data->close();
|
||||
_index->close();
|
||||
return 0;
|
||||
}
|
||||
offset += sizeof(magic);
|
||||
|
||||
while (true) {
|
||||
char fileHeader[60];
|
||||
// 0..15 = filename in ASCII
|
||||
// 48...57 = length in decimal ASCII
|
||||
uint32_t length;
|
||||
if (data->read(fileHeader, sizeof(fileHeader)) != sizeof(fileHeader)) {
|
||||
break;
|
||||
}
|
||||
offset += sizeof(fileHeader);
|
||||
fileHeader[58] = 0;
|
||||
if (1 != sscanf(fileHeader + 48, "%d", &length) || !length) {
|
||||
break;
|
||||
}
|
||||
|
||||
void *raw = malloc(length);
|
||||
if (!raw) {
|
||||
break;
|
||||
}
|
||||
if (_data->read(raw, length) != (ssize_t)length) {
|
||||
free(raw);
|
||||
break;
|
||||
}
|
||||
|
||||
// If the filename starts with "//" then this is a rename file, skip it
|
||||
if (fileHeader[0] != '/' || fileHeader[1] != '/') {
|
||||
CertStore::CertInfo ci = _preprocessCert(length, offset, raw);
|
||||
if (_index->write(&ci, sizeof(ci)) != (ssize_t)sizeof(ci)) {
|
||||
free(raw);
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
offset += length;
|
||||
free(raw);
|
||||
if (offset & 1) {
|
||||
char x;
|
||||
_data->read(&x, 1);
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
_data->close();
|
||||
_index->close();
|
||||
return count;
|
||||
return count;
|
||||
}
|
||||
|
||||
void CertStore::installCertStore(br_x509_minimal_context *ctx) {
|
||||
br_x509_minimal_set_dynamic(ctx, (void*)this, findHashedTA, freeHashedTA);
|
||||
void CertStore::installCertStore(br_x509_minimal_context *ctx)
|
||||
{
|
||||
br_x509_minimal_set_dynamic(ctx, (void*)this, findHashedTA, freeHashedTA);
|
||||
}
|
||||
|
||||
const br_x509_trust_anchor *CertStore::findHashedTA(void *ctx, void *hashed_dn, size_t len) {
|
||||
CertStore *cs = static_cast<CertStore*>(ctx);
|
||||
CertStore::CertInfo ci;
|
||||
const br_x509_trust_anchor *CertStore::findHashedTA(void *ctx, void *hashed_dn, size_t len)
|
||||
{
|
||||
CertStore *cs = static_cast<CertStore*>(ctx);
|
||||
CertStore::CertInfo ci;
|
||||
|
||||
if (!cs || len != sizeof(ci.sha256) || !cs->_index || !cs->_data) {
|
||||
if (!cs || len != sizeof(ci.sha256) || !cs->_index || !cs->_data)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!cs->_index->open(false))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
while (cs->_index->read(&ci, sizeof(ci)) == sizeof(ci))
|
||||
{
|
||||
if (!memcmp(ci.sha256, hashed_dn, sizeof(ci.sha256)))
|
||||
{
|
||||
cs->_index->close();
|
||||
uint8_t *der = (uint8_t*)malloc(ci.length);
|
||||
if (!der)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (!cs->_data->open(false))
|
||||
{
|
||||
free(der);
|
||||
return nullptr;
|
||||
}
|
||||
if (!cs->_data->seek(ci.offset))
|
||||
{
|
||||
cs->_data->close();
|
||||
free(der);
|
||||
return nullptr;
|
||||
}
|
||||
if (cs->_data->read(der, ci.length) != (ssize_t)ci.length)
|
||||
{
|
||||
free(der);
|
||||
return nullptr;
|
||||
}
|
||||
cs->_data->close();
|
||||
cs->_x509 = new X509List(der, ci.length);
|
||||
free(der);
|
||||
if (!cs->_x509)
|
||||
{
|
||||
DEBUG_BSSL("CertStore::findHashedTA: OOM\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
br_x509_trust_anchor *ta = (br_x509_trust_anchor*)cs->_x509->getTrustAnchors();
|
||||
memcpy(ta->dn.data, ci.sha256, sizeof(ci.sha256));
|
||||
ta->dn.len = sizeof(ci.sha256);
|
||||
|
||||
return ta;
|
||||
}
|
||||
}
|
||||
cs->_index->close();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!cs->_index->open(false)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
while (cs->_index->read(&ci, sizeof(ci)) == sizeof(ci)) {
|
||||
if (!memcmp(ci.sha256, hashed_dn, sizeof(ci.sha256))) {
|
||||
cs->_index->close();
|
||||
uint8_t *der = (uint8_t*)malloc(ci.length);
|
||||
if (!der) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!cs->_data->open(false)) {
|
||||
free(der);
|
||||
return nullptr;
|
||||
}
|
||||
if (!cs->_data->seek(ci.offset)) {
|
||||
cs->_data->close();
|
||||
free(der);
|
||||
return nullptr;
|
||||
}
|
||||
if (cs->_data->read(der, ci.length) != (ssize_t)ci.length) {
|
||||
free(der);
|
||||
return nullptr;
|
||||
}
|
||||
cs->_data->close();
|
||||
cs->_x509 = new X509List(der, ci.length);
|
||||
free(der);
|
||||
if (!cs->_x509) {
|
||||
DEBUG_BSSL("CertStore::findHashedTA: OOM\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
br_x509_trust_anchor *ta = (br_x509_trust_anchor*)cs->_x509->getTrustAnchors();
|
||||
memcpy(ta->dn.data, ci.sha256, sizeof(ci.sha256));
|
||||
ta->dn.len = sizeof(ci.sha256);
|
||||
|
||||
return ta;
|
||||
}
|
||||
}
|
||||
cs->_index->close();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CertStore::freeHashedTA(void *ctx, const br_x509_trust_anchor *ta) {
|
||||
CertStore *cs = static_cast<CertStore*>(ctx);
|
||||
(void) ta; // Unused
|
||||
delete cs->_x509;
|
||||
cs->_x509 = nullptr;
|
||||
void CertStore::freeHashedTA(void *ctx, const br_x509_trust_anchor *ta)
|
||||
{
|
||||
CertStore *cs = static_cast<CertStore*>(ctx);
|
||||
(void) ta; // Unused
|
||||
delete cs->_x509;
|
||||
cs->_x509 = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,20 +1,20 @@
|
||||
/*
|
||||
CertStoreBearSSL.h - Library for Arduino ESP8266
|
||||
Copyright (c) 2018 Earle F. Philhower, III
|
||||
CertStoreBearSSL.h - Library for Arduino ESP8266
|
||||
Copyright (c) 2018 Earle F. Philhower, III
|
||||
|
||||
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 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.
|
||||
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
|
||||
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 _CERTSTORE_BEARSSL_H
|
||||
@ -28,7 +28,8 @@
|
||||
// of a large set of certificates stored on SPIFFS of SD card to
|
||||
// be dynamically used when validating a X509 certificate
|
||||
|
||||
namespace BearSSL {
|
||||
namespace BearSSL
|
||||
{
|
||||
|
||||
// Subclass this and provide virtual functions appropriate for your storage.
|
||||
// Required because there are conflicting definitions for a "File" in the
|
||||
@ -39,13 +40,14 @@ namespace BearSSL {
|
||||
// NOTE: This virtual class may migrate to a templated model in a future
|
||||
// release. Expect some changes to the interface, no matter what, as the
|
||||
// SD and SPIFFS filesystem get unified.
|
||||
class CertStoreFile {
|
||||
public:
|
||||
class CertStoreFile
|
||||
{
|
||||
public:
|
||||
CertStoreFile() {};
|
||||
virtual ~CertStoreFile() {};
|
||||
|
||||
// The main API
|
||||
virtual bool open(bool write=false) = 0;
|
||||
virtual bool open(bool write = false) = 0;
|
||||
virtual bool seek(size_t absolute_pos) = 0;
|
||||
virtual ssize_t read(void *dest, size_t bytes) = 0;
|
||||
virtual ssize_t write(void *dest, size_t bytes) = 0;
|
||||
@ -53,8 +55,9 @@ class CertStoreFile {
|
||||
};
|
||||
|
||||
|
||||
class CertStore {
|
||||
public:
|
||||
class CertStore
|
||||
{
|
||||
public:
|
||||
CertStore() { };
|
||||
~CertStore() { };
|
||||
|
||||
@ -64,7 +67,7 @@ class CertStore {
|
||||
// Installs the cert store into the X509 decoder (normally via static function callbacks)
|
||||
void installCertStore(br_x509_minimal_context *ctx);
|
||||
|
||||
protected:
|
||||
protected:
|
||||
CertStoreFile *_index = nullptr;
|
||||
CertStoreFile *_data = nullptr;
|
||||
X509List *_x509 = nullptr;
|
||||
@ -74,11 +77,12 @@ class CertStore {
|
||||
static void freeHashedTA(void *ctx, const br_x509_trust_anchor *ta);
|
||||
|
||||
// The binary format of the index file
|
||||
class CertInfo {
|
||||
class CertInfo
|
||||
{
|
||||
public:
|
||||
uint8_t sha256[32];
|
||||
uint32_t offset;
|
||||
uint32_t length;
|
||||
uint8_t sha256[32];
|
||||
uint32_t offset;
|
||||
uint32_t length;
|
||||
};
|
||||
static CertInfo _preprocessCert(uint32_t length, uint32_t offset, const void *raw);
|
||||
|
||||
|
@ -1,26 +1,26 @@
|
||||
/*
|
||||
ESP8266WiFi.cpp - WiFi library for esp8266
|
||||
ESP8266WiFi.cpp - WiFi library for esp8266
|
||||
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This library is 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.
|
||||
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
|
||||
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
|
||||
|
||||
Reworked on 28 Dec 2015 by Markus Sattler
|
||||
Reworked on 28 Dec 2015 by Markus Sattler
|
||||
|
||||
*/
|
||||
*/
|
||||
|
||||
#include "ESP8266WiFi.h"
|
||||
|
||||
@ -45,10 +45,11 @@ extern "C" {
|
||||
|
||||
|
||||
/**
|
||||
* Output WiFi settings to an object derived from Print interface (like Serial).
|
||||
* @param p Print interface
|
||||
*/
|
||||
void ESP8266WiFiClass::printDiag(Print& p) {
|
||||
Output WiFi settings to an object derived from Print interface (like Serial).
|
||||
@param p Print interface
|
||||
*/
|
||||
void ESP8266WiFiClass::printDiag(Print& p)
|
||||
{
|
||||
const char* modes[] = { "NULL", "STA", "AP", "STA+AP" };
|
||||
p.print("Mode: ");
|
||||
p.println(modes[wifi_get_opmode()]);
|
||||
@ -75,7 +76,7 @@ void ESP8266WiFiClass::printDiag(Print& p) {
|
||||
char ssid[33]; //ssid can be up to 32chars, => plus null term
|
||||
memcpy(ssid, conf.ssid, sizeof(conf.ssid));
|
||||
ssid[32] = 0; //nullterm in case of 32 char ssid
|
||||
|
||||
|
||||
p.print("SSID (");
|
||||
p.print(strlen(ssid));
|
||||
p.print("): ");
|
||||
|
@ -1,23 +1,23 @@
|
||||
/*
|
||||
ESP8266WiFi.h - esp8266 Wifi support.
|
||||
Based on WiFi.h from Arduino WiFi shield library.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
Modified by Ivan Grokhotkov, December 2014
|
||||
ESP8266WiFi.h - esp8266 Wifi support.
|
||||
Based on WiFi.h from Arduino WiFi shield library.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
Modified by Ivan Grokhotkov, December 2014
|
||||
|
||||
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 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.
|
||||
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
|
||||
*/
|
||||
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 WiFi_h
|
||||
#define WiFi_h
|
||||
@ -54,35 +54,36 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
class ESP8266WiFiClass : public ESP8266WiFiGenericClass, public ESP8266WiFiSTAClass, public ESP8266WiFiScanClass, public ESP8266WiFiAPClass {
|
||||
public:
|
||||
class ESP8266WiFiClass : public ESP8266WiFiGenericClass, public ESP8266WiFiSTAClass, public ESP8266WiFiScanClass, public ESP8266WiFiAPClass
|
||||
{
|
||||
public:
|
||||
|
||||
// workaround same function name with different signature
|
||||
using ESP8266WiFiGenericClass::channel;
|
||||
// workaround same function name with different signature
|
||||
using ESP8266WiFiGenericClass::channel;
|
||||
|
||||
using ESP8266WiFiSTAClass::SSID;
|
||||
using ESP8266WiFiSTAClass::RSSI;
|
||||
using ESP8266WiFiSTAClass::BSSID;
|
||||
using ESP8266WiFiSTAClass::BSSIDstr;
|
||||
using ESP8266WiFiSTAClass::SSID;
|
||||
using ESP8266WiFiSTAClass::RSSI;
|
||||
using ESP8266WiFiSTAClass::BSSID;
|
||||
using ESP8266WiFiSTAClass::BSSIDstr;
|
||||
|
||||
using ESP8266WiFiScanClass::SSID;
|
||||
using ESP8266WiFiScanClass::encryptionType;
|
||||
using ESP8266WiFiScanClass::RSSI;
|
||||
using ESP8266WiFiScanClass::BSSID;
|
||||
using ESP8266WiFiScanClass::BSSIDstr;
|
||||
using ESP8266WiFiScanClass::channel;
|
||||
using ESP8266WiFiScanClass::isHidden;
|
||||
using ESP8266WiFiScanClass::SSID;
|
||||
using ESP8266WiFiScanClass::encryptionType;
|
||||
using ESP8266WiFiScanClass::RSSI;
|
||||
using ESP8266WiFiScanClass::BSSID;
|
||||
using ESP8266WiFiScanClass::BSSIDstr;
|
||||
using ESP8266WiFiScanClass::channel;
|
||||
using ESP8266WiFiScanClass::isHidden;
|
||||
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// ------------------------------------------- Debug --------------------------------------------
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// ------------------------------------------- Debug --------------------------------------------
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
public:
|
||||
|
||||
void printDiag(Print& dest);
|
||||
void printDiag(Print& dest);
|
||||
|
||||
friend class WiFiClient;
|
||||
friend class WiFiServer;
|
||||
friend class WiFiClient;
|
||||
friend class WiFiServer;
|
||||
|
||||
};
|
||||
|
||||
|
@ -1,383 +1,442 @@
|
||||
/*
|
||||
ESP8266WiFiSTA.cpp - WiFi library for esp8266
|
||||
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Reworked on 28 Dec 2015 by Markus Sattler
|
||||
|
||||
*/
|
||||
|
||||
#include "ESP8266WiFi.h"
|
||||
#include "ESP8266WiFiGeneric.h"
|
||||
#include "ESP8266WiFiAP.h"
|
||||
|
||||
extern "C" {
|
||||
#include "c_types.h"
|
||||
#include "ets_sys.h"
|
||||
#include "os_type.h"
|
||||
#include "osapi.h"
|
||||
#include "mem.h"
|
||||
#include "user_interface.h"
|
||||
}
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------
|
||||
// ---------------------------------------------------- Private functions ------------------------------------------------
|
||||
// -----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
static bool softap_config_equal(const softap_config& lhs, const softap_config& rhs);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* compare two AP configurations
|
||||
* @param lhs softap_config
|
||||
* @param rhs softap_config
|
||||
* @return equal
|
||||
*/
|
||||
static bool softap_config_equal(const softap_config& lhs, const softap_config& rhs) {
|
||||
if(strcmp(reinterpret_cast<const char*>(lhs.ssid), reinterpret_cast<const char*>(rhs.ssid)) != 0) {
|
||||
return false;
|
||||
}
|
||||
if(strcmp(reinterpret_cast<const char*>(lhs.password), reinterpret_cast<const char*>(rhs.password)) != 0) {
|
||||
return false;
|
||||
}
|
||||
if(lhs.channel != rhs.channel) {
|
||||
return false;
|
||||
}
|
||||
if(lhs.ssid_hidden != rhs.ssid_hidden) {
|
||||
return false;
|
||||
}
|
||||
if(lhs.max_connection != rhs.max_connection) {
|
||||
return false;
|
||||
}
|
||||
if(lhs.beacon_interval != rhs.beacon_interval) {
|
||||
return false;
|
||||
}
|
||||
if(lhs.authmode != rhs.authmode) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------
|
||||
// ----------------------------------------------------- AP function -----------------------------------------------------
|
||||
// -----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Set up an access point
|
||||
* @param ssid Pointer to the SSID (max 31 char).
|
||||
* @param passphrase For WPA2 min 8 char, for open use NULL (max 63 char).
|
||||
* @param channel WiFi channel number, 1 - 13.
|
||||
* @param ssid_hidden Network cloaking (0 = broadcast SSID, 1 = hide SSID)
|
||||
* @param max_connection Max simultaneous connected clients, 0 - 8. https://bbs.espressif.com/viewtopic.php?f=46&t=481&p=1832&hilit=max_connection#p1832
|
||||
*/
|
||||
bool ESP8266WiFiAPClass::softAP(const char* ssid, const char* passphrase, int channel, int ssid_hidden, int max_connection) {
|
||||
|
||||
if(!WiFi.enableAP(true)) {
|
||||
// enable AP failed
|
||||
DEBUG_WIFI("[AP] enableAP failed!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!ssid || strlen(ssid) == 0 || strlen(ssid) > 31) {
|
||||
// fail SSID too long or missing!
|
||||
DEBUG_WIFI("[AP] SSID too long or missing!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(passphrase && strlen(passphrase) > 0 && (strlen(passphrase) > 63 || strlen(passphrase) < 8)) {
|
||||
// fail passphrase to long or short!
|
||||
DEBUG_WIFI("[AP] fail passphrase to long or short!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = true;
|
||||
|
||||
struct softap_config conf;
|
||||
strcpy(reinterpret_cast<char*>(conf.ssid), ssid);
|
||||
conf.channel = channel;
|
||||
conf.ssid_len = strlen(ssid);
|
||||
conf.ssid_hidden = ssid_hidden;
|
||||
conf.max_connection = max_connection;
|
||||
conf.beacon_interval = 100;
|
||||
|
||||
if(!passphrase || strlen(passphrase) == 0) {
|
||||
conf.authmode = AUTH_OPEN;
|
||||
*conf.password = 0;
|
||||
} else {
|
||||
conf.authmode = AUTH_WPA2_PSK;
|
||||
strcpy(reinterpret_cast<char*>(conf.password), passphrase);
|
||||
}
|
||||
|
||||
struct softap_config conf_compare;
|
||||
if(WiFi._persistent){
|
||||
wifi_softap_get_config_default(&conf_compare);
|
||||
}
|
||||
else {
|
||||
wifi_softap_get_config(&conf_compare);
|
||||
}
|
||||
|
||||
if(!softap_config_equal(conf, conf_compare)) {
|
||||
|
||||
ETS_UART_INTR_DISABLE();
|
||||
if(WiFi._persistent) {
|
||||
ret = wifi_softap_set_config(&conf);
|
||||
} else {
|
||||
ret = wifi_softap_set_config_current(&conf);
|
||||
}
|
||||
ETS_UART_INTR_ENABLE();
|
||||
|
||||
if(!ret) {
|
||||
DEBUG_WIFI("[AP] set_config failed!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_WIFI("[AP] softap config unchanged\n");
|
||||
}
|
||||
|
||||
if(wifi_softap_dhcps_status() != DHCP_STARTED) {
|
||||
DEBUG_WIFI("[AP] DHCP not started, starting...\n");
|
||||
if(!wifi_softap_dhcps_start()) {
|
||||
DEBUG_WIFI("[AP] wifi_softap_dhcps_start failed!\n");
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
// check IP config
|
||||
struct ip_info ip;
|
||||
if(wifi_get_ip_info(SOFTAP_IF, &ip)) {
|
||||
if(ip.ip.addr == 0x00000000) {
|
||||
// Invalid config
|
||||
DEBUG_WIFI("[AP] IP config Invalid resetting...\n");
|
||||
//192.168.244.1 , 192.168.244.1 , 255.255.255.0
|
||||
ret = softAPConfig(0x01F4A8C0, 0x01F4A8C0, 0x00FFFFFF);
|
||||
if(!ret) {
|
||||
DEBUG_WIFI("[AP] softAPConfig failed!\n");
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DEBUG_WIFI("[AP] wifi_get_ip_info failed!\n");
|
||||
ret = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ESP8266WiFiAPClass::softAP(const String& ssid, const String& passphrase, int channel, int ssid_hidden, int max_connection) {
|
||||
return softAP(ssid.c_str(), passphrase.c_str(), channel, ssid_hidden, max_connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure access point
|
||||
* @param local_ip access point IP
|
||||
* @param gateway gateway IP (0.0.0.0 to disable)
|
||||
* @param subnet subnet mask
|
||||
*/
|
||||
bool ESP8266WiFiAPClass::softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet) {
|
||||
DEBUG_WIFI("[APConfig] local_ip: %s gateway: %s subnet: %s\n", local_ip.toString().c_str(), gateway.toString().c_str(), subnet.toString().c_str());
|
||||
if(!WiFi.enableAP(true)) {
|
||||
// enable AP failed
|
||||
DEBUG_WIFI("[APConfig] enableAP failed!\n");
|
||||
return false;
|
||||
}
|
||||
bool ret = true;
|
||||
|
||||
if ( !local_ip.isV4()
|
||||
|| !subnet.isV4()
|
||||
#if LWIP_IPV6
|
||||
// uninitialized gateway is valid
|
||||
|| gateway.isV6()
|
||||
#endif
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
struct ip_info info;
|
||||
info.ip.addr = local_ip.v4();
|
||||
info.gw.addr = gateway.v4();
|
||||
info.netmask.addr = subnet.v4();
|
||||
|
||||
if(!wifi_softap_dhcps_stop()) {
|
||||
DEBUG_WIFI("[APConfig] wifi_softap_dhcps_stop failed!\n");
|
||||
}
|
||||
|
||||
if(!wifi_set_ip_info(SOFTAP_IF, &info)) {
|
||||
DEBUG_WIFI("[APConfig] wifi_set_ip_info failed!\n");
|
||||
ret = false;
|
||||
}
|
||||
|
||||
struct dhcps_lease dhcp_lease;
|
||||
IPAddress ip = local_ip;
|
||||
ip[3] += 99;
|
||||
dhcp_lease.start_ip.addr = ip.v4();
|
||||
DEBUG_WIFI("[APConfig] DHCP IP start: %s\n", ip.toString().c_str());
|
||||
|
||||
ip[3] += 100;
|
||||
dhcp_lease.end_ip.addr = ip.v4();
|
||||
DEBUG_WIFI("[APConfig] DHCP IP end: %s\n", ip.toString().c_str());
|
||||
|
||||
if(!wifi_softap_set_dhcps_lease(&dhcp_lease)) {
|
||||
DEBUG_WIFI("[APConfig] wifi_set_ip_info failed!\n");
|
||||
ret = false;
|
||||
}
|
||||
|
||||
// set lease time to 720min --> 12h
|
||||
if(!wifi_softap_set_dhcps_lease_time(720)) {
|
||||
DEBUG_WIFI("[APConfig] wifi_softap_set_dhcps_lease_time failed!\n");
|
||||
ret = false;
|
||||
}
|
||||
|
||||
uint8 mode = info.gw.addr ? 1 : 0;
|
||||
if(!wifi_softap_set_dhcps_offer_option(OFFER_ROUTER, &mode)) {
|
||||
DEBUG_WIFI("[APConfig] wifi_softap_set_dhcps_offer_option failed!\n");
|
||||
ret = false;
|
||||
}
|
||||
|
||||
if(!wifi_softap_dhcps_start()) {
|
||||
DEBUG_WIFI("[APConfig] wifi_softap_dhcps_start failed!\n");
|
||||
ret = false;
|
||||
}
|
||||
|
||||
// check config
|
||||
if(wifi_get_ip_info(SOFTAP_IF, &info)) {
|
||||
if(info.ip.addr == 0x00000000) {
|
||||
DEBUG_WIFI("[APConfig] IP config Invalid?!\n");
|
||||
ret = false;
|
||||
} else if(local_ip.v4() != info.ip.addr) {
|
||||
ip = info.ip.addr;
|
||||
DEBUG_WIFI("[APConfig] IP config not set correct?! new IP: %s\n", ip.toString().c_str());
|
||||
ret = false;
|
||||
}
|
||||
} else {
|
||||
DEBUG_WIFI("[APConfig] wifi_get_ip_info failed!\n");
|
||||
ret = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Disconnect from the network (close AP)
|
||||
* @param wifioff disable mode?
|
||||
* @return one value of wl_status_t enum
|
||||
*/
|
||||
bool ESP8266WiFiAPClass::softAPdisconnect(bool wifioff) {
|
||||
bool ret;
|
||||
struct softap_config conf;
|
||||
*conf.ssid = 0;
|
||||
*conf.password = 0;
|
||||
conf.authmode = AUTH_OPEN;
|
||||
ETS_UART_INTR_DISABLE();
|
||||
if(WiFi._persistent) {
|
||||
ret = wifi_softap_set_config(&conf);
|
||||
} else {
|
||||
ret = wifi_softap_set_config_current(&conf);
|
||||
}
|
||||
ETS_UART_INTR_ENABLE();
|
||||
|
||||
if(!ret) {
|
||||
DEBUG_WIFI("[APdisconnect] set_config failed!\n");
|
||||
}
|
||||
|
||||
if(ret && wifioff) {
|
||||
ret = WiFi.enableAP(false);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the count of the Station / client that are connected to the softAP interface
|
||||
* @return Stations count
|
||||
*/
|
||||
uint8_t ESP8266WiFiAPClass::softAPgetStationNum() {
|
||||
return wifi_softap_get_station_num();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the softAP interface IP address.
|
||||
* @return IPAddress softAP IP
|
||||
*/
|
||||
IPAddress ESP8266WiFiAPClass::softAPIP() {
|
||||
struct ip_info ip;
|
||||
wifi_get_ip_info(SOFTAP_IF, &ip);
|
||||
return IPAddress(ip.ip.addr);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the softAP interface MAC address.
|
||||
* @param mac pointer to uint8_t array with length WL_MAC_ADDR_LENGTH
|
||||
* @return pointer to uint8_t*
|
||||
*/
|
||||
uint8_t* ESP8266WiFiAPClass::softAPmacAddress(uint8_t* mac) {
|
||||
wifi_get_macaddr(SOFTAP_IF, mac);
|
||||
return mac;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the softAP interface MAC address.
|
||||
* @return String mac
|
||||
*/
|
||||
String ESP8266WiFiAPClass::softAPmacAddress(void) {
|
||||
uint8_t mac[6];
|
||||
char macStr[18] = { 0 };
|
||||
wifi_get_macaddr(SOFTAP_IF, mac);
|
||||
|
||||
sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
return String(macStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configured(Not-In-Flash) softAP SSID name.
|
||||
* @return String SSID.
|
||||
*/
|
||||
String ESP8266WiFiAPClass::softAPSSID() const {
|
||||
struct softap_config config;
|
||||
wifi_softap_get_config(&config);
|
||||
char* name = reinterpret_cast<char*>(config.ssid);
|
||||
char ssid[sizeof(config.ssid) + 1];
|
||||
memcpy(ssid, name, sizeof(config.ssid));
|
||||
ssid[sizeof(config.ssid)] = '\0';
|
||||
|
||||
return String(ssid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configured(Not-In-Flash) softAP PSK or PASSWORD.
|
||||
* @return String psk.
|
||||
*/
|
||||
String ESP8266WiFiAPClass::softAPPSK() const {
|
||||
struct softap_config config;
|
||||
wifi_softap_get_config(&config);
|
||||
char* pass = reinterpret_cast<char*>(config.password);
|
||||
char psk[sizeof(config.password) + 1];
|
||||
memcpy(psk, pass, sizeof(config.password));
|
||||
psk[sizeof(config.password)] = '\0';
|
||||
|
||||
return String(psk);
|
||||
}
|
||||
/*
|
||||
ESP8266WiFiSTA.cpp - WiFi library for esp8266
|
||||
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Reworked on 28 Dec 2015 by Markus Sattler
|
||||
|
||||
*/
|
||||
|
||||
#include "ESP8266WiFi.h"
|
||||
#include "ESP8266WiFiGeneric.h"
|
||||
#include "ESP8266WiFiAP.h"
|
||||
|
||||
extern "C" {
|
||||
#include "c_types.h"
|
||||
#include "ets_sys.h"
|
||||
#include "os_type.h"
|
||||
#include "osapi.h"
|
||||
#include "mem.h"
|
||||
#include "user_interface.h"
|
||||
}
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------
|
||||
// ---------------------------------------------------- Private functions ------------------------------------------------
|
||||
// -----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
static bool softap_config_equal(const softap_config& lhs, const softap_config& rhs);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
compare two AP configurations
|
||||
@param lhs softap_config
|
||||
@param rhs softap_config
|
||||
@return equal
|
||||
*/
|
||||
static bool softap_config_equal(const softap_config& lhs, const softap_config& rhs)
|
||||
{
|
||||
if (strcmp(reinterpret_cast<const char*>(lhs.ssid), reinterpret_cast<const char*>(rhs.ssid)) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (strcmp(reinterpret_cast<const char*>(lhs.password), reinterpret_cast<const char*>(rhs.password)) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (lhs.channel != rhs.channel)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (lhs.ssid_hidden != rhs.ssid_hidden)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (lhs.max_connection != rhs.max_connection)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (lhs.beacon_interval != rhs.beacon_interval)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (lhs.authmode != rhs.authmode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------
|
||||
// ----------------------------------------------------- AP function -----------------------------------------------------
|
||||
// -----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
Set up an access point
|
||||
@param ssid Pointer to the SSID (max 31 char).
|
||||
@param passphrase For WPA2 min 8 char, for open use NULL (max 63 char).
|
||||
@param channel WiFi channel number, 1 - 13.
|
||||
@param ssid_hidden Network cloaking (0 = broadcast SSID, 1 = hide SSID)
|
||||
@param max_connection Max simultaneous connected clients, 0 - 8. https://bbs.espressif.com/viewtopic.php?f=46&t=481&p=1832&hilit=max_connection#p1832
|
||||
*/
|
||||
bool ESP8266WiFiAPClass::softAP(const char* ssid, const char* passphrase, int channel, int ssid_hidden, int max_connection)
|
||||
{
|
||||
|
||||
if (!WiFi.enableAP(true))
|
||||
{
|
||||
// enable AP failed
|
||||
DEBUG_WIFI("[AP] enableAP failed!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ssid || strlen(ssid) == 0 || strlen(ssid) > 31)
|
||||
{
|
||||
// fail SSID too long or missing!
|
||||
DEBUG_WIFI("[AP] SSID too long or missing!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (passphrase && strlen(passphrase) > 0 && (strlen(passphrase) > 63 || strlen(passphrase) < 8))
|
||||
{
|
||||
// fail passphrase to long or short!
|
||||
DEBUG_WIFI("[AP] fail passphrase to long or short!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = true;
|
||||
|
||||
struct softap_config conf;
|
||||
strcpy(reinterpret_cast<char*>(conf.ssid), ssid);
|
||||
conf.channel = channel;
|
||||
conf.ssid_len = strlen(ssid);
|
||||
conf.ssid_hidden = ssid_hidden;
|
||||
conf.max_connection = max_connection;
|
||||
conf.beacon_interval = 100;
|
||||
|
||||
if (!passphrase || strlen(passphrase) == 0)
|
||||
{
|
||||
conf.authmode = AUTH_OPEN;
|
||||
*conf.password = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
conf.authmode = AUTH_WPA2_PSK;
|
||||
strcpy(reinterpret_cast<char*>(conf.password), passphrase);
|
||||
}
|
||||
|
||||
struct softap_config conf_compare;
|
||||
if (WiFi._persistent)
|
||||
{
|
||||
wifi_softap_get_config_default(&conf_compare);
|
||||
}
|
||||
else
|
||||
{
|
||||
wifi_softap_get_config(&conf_compare);
|
||||
}
|
||||
|
||||
if (!softap_config_equal(conf, conf_compare))
|
||||
{
|
||||
|
||||
ETS_UART_INTR_DISABLE();
|
||||
if (WiFi._persistent)
|
||||
{
|
||||
ret = wifi_softap_set_config(&conf);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = wifi_softap_set_config_current(&conf);
|
||||
}
|
||||
ETS_UART_INTR_ENABLE();
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
DEBUG_WIFI("[AP] set_config failed!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_WIFI("[AP] softap config unchanged\n");
|
||||
}
|
||||
|
||||
if (wifi_softap_dhcps_status() != DHCP_STARTED)
|
||||
{
|
||||
DEBUG_WIFI("[AP] DHCP not started, starting...\n");
|
||||
if (!wifi_softap_dhcps_start())
|
||||
{
|
||||
DEBUG_WIFI("[AP] wifi_softap_dhcps_start failed!\n");
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
// check IP config
|
||||
struct ip_info ip;
|
||||
if (wifi_get_ip_info(SOFTAP_IF, &ip))
|
||||
{
|
||||
if (ip.ip.addr == 0x00000000)
|
||||
{
|
||||
// Invalid config
|
||||
DEBUG_WIFI("[AP] IP config Invalid resetting...\n");
|
||||
//192.168.244.1 , 192.168.244.1 , 255.255.255.0
|
||||
ret = softAPConfig(0x01F4A8C0, 0x01F4A8C0, 0x00FFFFFF);
|
||||
if (!ret)
|
||||
{
|
||||
DEBUG_WIFI("[AP] softAPConfig failed!\n");
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_WIFI("[AP] wifi_get_ip_info failed!\n");
|
||||
ret = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ESP8266WiFiAPClass::softAP(const String& ssid, const String& passphrase, int channel, int ssid_hidden, int max_connection)
|
||||
{
|
||||
return softAP(ssid.c_str(), passphrase.c_str(), channel, ssid_hidden, max_connection);
|
||||
}
|
||||
|
||||
/**
|
||||
Configure access point
|
||||
@param local_ip access point IP
|
||||
@param gateway gateway IP (0.0.0.0 to disable)
|
||||
@param subnet subnet mask
|
||||
*/
|
||||
bool ESP8266WiFiAPClass::softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet)
|
||||
{
|
||||
DEBUG_WIFI("[APConfig] local_ip: %s gateway: %s subnet: %s\n", local_ip.toString().c_str(), gateway.toString().c_str(), subnet.toString().c_str());
|
||||
if (!WiFi.enableAP(true))
|
||||
{
|
||||
// enable AP failed
|
||||
DEBUG_WIFI("[APConfig] enableAP failed!\n");
|
||||
return false;
|
||||
}
|
||||
bool ret = true;
|
||||
|
||||
if (!local_ip.isV4()
|
||||
|| !subnet.isV4()
|
||||
#if LWIP_IPV6
|
||||
// uninitialized gateway is valid
|
||||
|| gateway.isV6()
|
||||
#endif
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
struct ip_info info;
|
||||
info.ip.addr = local_ip.v4();
|
||||
info.gw.addr = gateway.v4();
|
||||
info.netmask.addr = subnet.v4();
|
||||
|
||||
if (!wifi_softap_dhcps_stop())
|
||||
{
|
||||
DEBUG_WIFI("[APConfig] wifi_softap_dhcps_stop failed!\n");
|
||||
}
|
||||
|
||||
if (!wifi_set_ip_info(SOFTAP_IF, &info))
|
||||
{
|
||||
DEBUG_WIFI("[APConfig] wifi_set_ip_info failed!\n");
|
||||
ret = false;
|
||||
}
|
||||
|
||||
struct dhcps_lease dhcp_lease;
|
||||
IPAddress ip = local_ip;
|
||||
ip[3] += 99;
|
||||
dhcp_lease.start_ip.addr = ip.v4();
|
||||
DEBUG_WIFI("[APConfig] DHCP IP start: %s\n", ip.toString().c_str());
|
||||
|
||||
ip[3] += 100;
|
||||
dhcp_lease.end_ip.addr = ip.v4();
|
||||
DEBUG_WIFI("[APConfig] DHCP IP end: %s\n", ip.toString().c_str());
|
||||
|
||||
if (!wifi_softap_set_dhcps_lease(&dhcp_lease))
|
||||
{
|
||||
DEBUG_WIFI("[APConfig] wifi_set_ip_info failed!\n");
|
||||
ret = false;
|
||||
}
|
||||
|
||||
// set lease time to 720min --> 12h
|
||||
if (!wifi_softap_set_dhcps_lease_time(720))
|
||||
{
|
||||
DEBUG_WIFI("[APConfig] wifi_softap_set_dhcps_lease_time failed!\n");
|
||||
ret = false;
|
||||
}
|
||||
|
||||
uint8 mode = info.gw.addr ? 1 : 0;
|
||||
if (!wifi_softap_set_dhcps_offer_option(OFFER_ROUTER, &mode))
|
||||
{
|
||||
DEBUG_WIFI("[APConfig] wifi_softap_set_dhcps_offer_option failed!\n");
|
||||
ret = false;
|
||||
}
|
||||
|
||||
if (!wifi_softap_dhcps_start())
|
||||
{
|
||||
DEBUG_WIFI("[APConfig] wifi_softap_dhcps_start failed!\n");
|
||||
ret = false;
|
||||
}
|
||||
|
||||
// check config
|
||||
if (wifi_get_ip_info(SOFTAP_IF, &info))
|
||||
{
|
||||
if (info.ip.addr == 0x00000000)
|
||||
{
|
||||
DEBUG_WIFI("[APConfig] IP config Invalid?!\n");
|
||||
ret = false;
|
||||
}
|
||||
else if (local_ip.v4() != info.ip.addr)
|
||||
{
|
||||
ip = info.ip.addr;
|
||||
DEBUG_WIFI("[APConfig] IP config not set correct?! new IP: %s\n", ip.toString().c_str());
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_WIFI("[APConfig] wifi_get_ip_info failed!\n");
|
||||
ret = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Disconnect from the network (close AP)
|
||||
@param wifioff disable mode?
|
||||
@return one value of wl_status_t enum
|
||||
*/
|
||||
bool ESP8266WiFiAPClass::softAPdisconnect(bool wifioff)
|
||||
{
|
||||
bool ret;
|
||||
struct softap_config conf;
|
||||
*conf.ssid = 0;
|
||||
*conf.password = 0;
|
||||
conf.authmode = AUTH_OPEN;
|
||||
ETS_UART_INTR_DISABLE();
|
||||
if (WiFi._persistent)
|
||||
{
|
||||
ret = wifi_softap_set_config(&conf);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = wifi_softap_set_config_current(&conf);
|
||||
}
|
||||
ETS_UART_INTR_ENABLE();
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
DEBUG_WIFI("[APdisconnect] set_config failed!\n");
|
||||
}
|
||||
|
||||
if (ret && wifioff)
|
||||
{
|
||||
ret = WiFi.enableAP(false);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get the count of the Station / client that are connected to the softAP interface
|
||||
@return Stations count
|
||||
*/
|
||||
uint8_t ESP8266WiFiAPClass::softAPgetStationNum()
|
||||
{
|
||||
return wifi_softap_get_station_num();
|
||||
}
|
||||
|
||||
/**
|
||||
Get the softAP interface IP address.
|
||||
@return IPAddress softAP IP
|
||||
*/
|
||||
IPAddress ESP8266WiFiAPClass::softAPIP()
|
||||
{
|
||||
struct ip_info ip;
|
||||
wifi_get_ip_info(SOFTAP_IF, &ip);
|
||||
return IPAddress(ip.ip.addr);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get the softAP interface MAC address.
|
||||
@param mac pointer to uint8_t array with length WL_MAC_ADDR_LENGTH
|
||||
@return pointer to uint8_t
|
||||
*/
|
||||
uint8_t* ESP8266WiFiAPClass::softAPmacAddress(uint8_t* mac)
|
||||
{
|
||||
wifi_get_macaddr(SOFTAP_IF, mac);
|
||||
return mac;
|
||||
}
|
||||
|
||||
/**
|
||||
Get the softAP interface MAC address.
|
||||
@return String mac
|
||||
*/
|
||||
String ESP8266WiFiAPClass::softAPmacAddress(void)
|
||||
{
|
||||
uint8_t mac[6];
|
||||
char macStr[18] = { 0 };
|
||||
wifi_get_macaddr(SOFTAP_IF, mac);
|
||||
|
||||
sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
return String(macStr);
|
||||
}
|
||||
|
||||
/**
|
||||
Get the configured(Not-In-Flash) softAP SSID name.
|
||||
@return String SSID.
|
||||
*/
|
||||
String ESP8266WiFiAPClass::softAPSSID() const
|
||||
{
|
||||
struct softap_config config;
|
||||
wifi_softap_get_config(&config);
|
||||
char* name = reinterpret_cast<char*>(config.ssid);
|
||||
char ssid[sizeof(config.ssid) + 1];
|
||||
memcpy(ssid, name, sizeof(config.ssid));
|
||||
ssid[sizeof(config.ssid)] = '\0';
|
||||
|
||||
return String(ssid);
|
||||
}
|
||||
|
||||
/**
|
||||
Get the configured(Not-In-Flash) softAP PSK or PASSWORD.
|
||||
@return String psk.
|
||||
*/
|
||||
String ESP8266WiFiAPClass::softAPPSK() const
|
||||
{
|
||||
struct softap_config config;
|
||||
wifi_softap_get_config(&config);
|
||||
char* pass = reinterpret_cast<char*>(config.password);
|
||||
char psk[sizeof(config.password) + 1];
|
||||
memcpy(psk, pass, sizeof(config.password));
|
||||
psk[sizeof(config.password)] = '\0';
|
||||
|
||||
return String(psk);
|
||||
}
|
||||
|
@ -1,58 +1,59 @@
|
||||
/*
|
||||
ESP8266WiFiAP.h - esp8266 Wifi support.
|
||||
Based on WiFi.h from Arduino WiFi shield library.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
Modified by Ivan Grokhotkov, December 2014
|
||||
Reworked by Markus Sattler, December 2015
|
||||
|
||||
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 ESP8266WIFIAP_H_
|
||||
#define ESP8266WIFIAP_H_
|
||||
|
||||
|
||||
#include "ESP8266WiFiType.h"
|
||||
#include "ESP8266WiFiGeneric.h"
|
||||
|
||||
|
||||
class ESP8266WiFiAPClass {
|
||||
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// ----------------------------------------- AP function ----------------------------------------
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
||||
bool softAP(const char* ssid, const char* passphrase = NULL, int channel = 1, int ssid_hidden = 0, int max_connection = 4);
|
||||
bool softAP(const String& ssid,const String& passphrase = emptyString,int channel = 1,int ssid_hidden = 0,int max_connection = 4);
|
||||
bool softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet);
|
||||
bool softAPdisconnect(bool wifioff = false);
|
||||
|
||||
uint8_t softAPgetStationNum();
|
||||
|
||||
IPAddress softAPIP();
|
||||
|
||||
uint8_t* softAPmacAddress(uint8_t* mac);
|
||||
String softAPmacAddress(void);
|
||||
|
||||
String softAPSSID() const;
|
||||
String softAPPSK() const;
|
||||
|
||||
protected:
|
||||
|
||||
};
|
||||
|
||||
#endif /* ESP8266WIFIAP_H_*/
|
||||
/*
|
||||
ESP8266WiFiAP.h - esp8266 Wifi support.
|
||||
Based on WiFi.h from Arduino WiFi shield library.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
Modified by Ivan Grokhotkov, December 2014
|
||||
Reworked by Markus Sattler, December 2015
|
||||
|
||||
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 ESP8266WIFIAP_H_
|
||||
#define ESP8266WIFIAP_H_
|
||||
|
||||
|
||||
#include "ESP8266WiFiType.h"
|
||||
#include "ESP8266WiFiGeneric.h"
|
||||
|
||||
|
||||
class ESP8266WiFiAPClass
|
||||
{
|
||||
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// ----------------------------------------- AP function ----------------------------------------
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
||||
bool softAP(const char* ssid, const char* passphrase = NULL, int channel = 1, int ssid_hidden = 0, int max_connection = 4);
|
||||
bool softAP(const String& ssid, const String& passphrase = emptyString, int channel = 1, int ssid_hidden = 0, int max_connection = 4);
|
||||
bool softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet);
|
||||
bool softAPdisconnect(bool wifioff = false);
|
||||
|
||||
uint8_t softAPgetStationNum();
|
||||
|
||||
IPAddress softAPIP();
|
||||
|
||||
uint8_t* softAPmacAddress(uint8_t* mac);
|
||||
String softAPmacAddress(void);
|
||||
|
||||
String softAPSSID() const;
|
||||
String softAPPSK() const;
|
||||
|
||||
protected:
|
||||
|
||||
};
|
||||
|
||||
#endif /* ESP8266WIFIAP_H_*/
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,115 +1,116 @@
|
||||
/*
|
||||
ESP8266WiFiGeneric.h - esp8266 Wifi support.
|
||||
Based on WiFi.h from Ardiono WiFi shield library.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
Modified by Ivan Grokhotkov, December 2014
|
||||
Reworked by Markus Sattler, December 2015
|
||||
|
||||
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 ESP8266WIFIGENERIC_H_
|
||||
#define ESP8266WIFIGENERIC_H_
|
||||
|
||||
#include "ESP8266WiFiType.h"
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#ifdef DEBUG_ESP_WIFI
|
||||
#ifdef DEBUG_ESP_PORT
|
||||
#define DEBUG_WIFI_GENERIC(fmt, ...) DEBUG_ESP_PORT.printf_P( (PGM_P)PSTR(fmt), ##__VA_ARGS__ )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_WIFI_GENERIC
|
||||
#define DEBUG_WIFI_GENERIC(...) do { (void)0; } while (0)
|
||||
#endif
|
||||
|
||||
struct WiFiEventHandlerOpaque;
|
||||
typedef std::shared_ptr<WiFiEventHandlerOpaque> WiFiEventHandler;
|
||||
|
||||
typedef void (*WiFiEventCb)(WiFiEvent_t);
|
||||
|
||||
class ESP8266WiFiGenericClass {
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// -------------------------------------- Generic WiFi function ---------------------------------
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
ESP8266WiFiGenericClass();
|
||||
|
||||
// Note: this function is deprecated. Use one of the functions below instead.
|
||||
void onEvent(WiFiEventCb cb, WiFiEvent_t event = WIFI_EVENT_ANY) __attribute__((deprecated));
|
||||
|
||||
// Subscribe to specific event and get event information as an argument to the callback
|
||||
WiFiEventHandler onStationModeConnected(std::function<void(const WiFiEventStationModeConnected&)>);
|
||||
WiFiEventHandler onStationModeDisconnected(std::function<void(const WiFiEventStationModeDisconnected&)>);
|
||||
WiFiEventHandler onStationModeAuthModeChanged(std::function<void(const WiFiEventStationModeAuthModeChanged&)>);
|
||||
WiFiEventHandler onStationModeGotIP(std::function<void(const WiFiEventStationModeGotIP&)>);
|
||||
WiFiEventHandler onStationModeDHCPTimeout(std::function<void(void)>);
|
||||
WiFiEventHandler onSoftAPModeStationConnected(std::function<void(const WiFiEventSoftAPModeStationConnected&)>);
|
||||
WiFiEventHandler onSoftAPModeStationDisconnected(std::function<void(const WiFiEventSoftAPModeStationDisconnected&)>);
|
||||
WiFiEventHandler onSoftAPModeProbeRequestReceived(std::function<void(const WiFiEventSoftAPModeProbeRequestReceived&)>);
|
||||
// WiFiEventHandler onWiFiModeChange(std::function<void(const WiFiEventModeChange&)>);
|
||||
|
||||
int32_t channel(void);
|
||||
|
||||
bool setSleepMode(WiFiSleepType_t type, uint8_t listenInterval = 0);
|
||||
|
||||
WiFiSleepType_t getSleepMode();
|
||||
uint8_t getListenInterval ();
|
||||
bool isSleepLevelMax ();
|
||||
|
||||
bool setPhyMode(WiFiPhyMode_t mode);
|
||||
WiFiPhyMode_t getPhyMode();
|
||||
|
||||
void setOutputPower(float dBm);
|
||||
|
||||
void persistent(bool persistent);
|
||||
|
||||
bool mode(WiFiMode_t);
|
||||
WiFiMode_t getMode();
|
||||
|
||||
bool enableSTA(bool enable);
|
||||
bool enableAP(bool enable);
|
||||
|
||||
bool forceSleepBegin(uint32 sleepUs = 0);
|
||||
bool forceSleepWake();
|
||||
|
||||
static void preinitWiFiOff (); //meant to be called in user-defined preinit()
|
||||
|
||||
protected:
|
||||
static bool _persistent;
|
||||
static WiFiMode_t _forceSleepLastMode;
|
||||
|
||||
static void _eventCallback(void *event);
|
||||
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// ------------------------------------ Generic Network function --------------------------------
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
||||
int hostByName(const char* aHostname, IPAddress& aResult);
|
||||
int hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms);
|
||||
bool getPersistent();
|
||||
protected:
|
||||
|
||||
friend class ESP8266WiFiSTAClass;
|
||||
friend class ESP8266WiFiScanClass;
|
||||
friend class ESP8266WiFiAPClass;
|
||||
};
|
||||
|
||||
#endif /* ESP8266WIFIGENERIC_H_ */
|
||||
/*
|
||||
ESP8266WiFiGeneric.h - esp8266 Wifi support.
|
||||
Based on WiFi.h from Ardiono WiFi shield library.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
Modified by Ivan Grokhotkov, December 2014
|
||||
Reworked by Markus Sattler, December 2015
|
||||
|
||||
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 ESP8266WIFIGENERIC_H_
|
||||
#define ESP8266WIFIGENERIC_H_
|
||||
|
||||
#include "ESP8266WiFiType.h"
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#ifdef DEBUG_ESP_WIFI
|
||||
#ifdef DEBUG_ESP_PORT
|
||||
#define DEBUG_WIFI_GENERIC(fmt, ...) DEBUG_ESP_PORT.printf_P( (PGM_P)PSTR(fmt), ##__VA_ARGS__ )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_WIFI_GENERIC
|
||||
#define DEBUG_WIFI_GENERIC(...) do { (void)0; } while (0)
|
||||
#endif
|
||||
|
||||
struct WiFiEventHandlerOpaque;
|
||||
typedef std::shared_ptr<WiFiEventHandlerOpaque> WiFiEventHandler;
|
||||
|
||||
typedef void (*WiFiEventCb)(WiFiEvent_t);
|
||||
|
||||
class ESP8266WiFiGenericClass
|
||||
{
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// -------------------------------------- Generic WiFi function ---------------------------------
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
ESP8266WiFiGenericClass();
|
||||
|
||||
// Note: this function is deprecated. Use one of the functions below instead.
|
||||
void onEvent(WiFiEventCb cb, WiFiEvent_t event = WIFI_EVENT_ANY) __attribute__((deprecated));
|
||||
|
||||
// Subscribe to specific event and get event information as an argument to the callback
|
||||
WiFiEventHandler onStationModeConnected(std::function<void(const WiFiEventStationModeConnected&)>);
|
||||
WiFiEventHandler onStationModeDisconnected(std::function<void(const WiFiEventStationModeDisconnected&)>);
|
||||
WiFiEventHandler onStationModeAuthModeChanged(std::function<void(const WiFiEventStationModeAuthModeChanged&)>);
|
||||
WiFiEventHandler onStationModeGotIP(std::function<void(const WiFiEventStationModeGotIP&)>);
|
||||
WiFiEventHandler onStationModeDHCPTimeout(std::function<void(void)>);
|
||||
WiFiEventHandler onSoftAPModeStationConnected(std::function<void(const WiFiEventSoftAPModeStationConnected&)>);
|
||||
WiFiEventHandler onSoftAPModeStationDisconnected(std::function<void(const WiFiEventSoftAPModeStationDisconnected&)>);
|
||||
WiFiEventHandler onSoftAPModeProbeRequestReceived(std::function<void(const WiFiEventSoftAPModeProbeRequestReceived&)>);
|
||||
// WiFiEventHandler onWiFiModeChange(std::function<void(const WiFiEventModeChange&)>);
|
||||
|
||||
int32_t channel(void);
|
||||
|
||||
bool setSleepMode(WiFiSleepType_t type, uint8_t listenInterval = 0);
|
||||
|
||||
WiFiSleepType_t getSleepMode();
|
||||
uint8_t getListenInterval();
|
||||
bool isSleepLevelMax();
|
||||
|
||||
bool setPhyMode(WiFiPhyMode_t mode);
|
||||
WiFiPhyMode_t getPhyMode();
|
||||
|
||||
void setOutputPower(float dBm);
|
||||
|
||||
void persistent(bool persistent);
|
||||
|
||||
bool mode(WiFiMode_t);
|
||||
WiFiMode_t getMode();
|
||||
|
||||
bool enableSTA(bool enable);
|
||||
bool enableAP(bool enable);
|
||||
|
||||
bool forceSleepBegin(uint32 sleepUs = 0);
|
||||
bool forceSleepWake();
|
||||
|
||||
static void preinitWiFiOff(); //meant to be called in user-defined preinit()
|
||||
|
||||
protected:
|
||||
static bool _persistent;
|
||||
static WiFiMode_t _forceSleepLastMode;
|
||||
|
||||
static void _eventCallback(void *event);
|
||||
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// ------------------------------------ Generic Network function --------------------------------
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
||||
int hostByName(const char* aHostname, IPAddress& aResult);
|
||||
int hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms);
|
||||
bool getPersistent();
|
||||
protected:
|
||||
|
||||
friend class ESP8266WiFiSTAClass;
|
||||
friend class ESP8266WiFiScanClass;
|
||||
friend class ESP8266WiFiAPClass;
|
||||
};
|
||||
|
||||
#endif /* ESP8266WIFIGENERIC_H_ */
|
||||
|
@ -1,265 +1,309 @@
|
||||
/**
|
||||
*
|
||||
* @file ESP8266WiFiMulti.cpp
|
||||
* @date 16.05.2015
|
||||
* @author Markus Sattler
|
||||
*
|
||||
* Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||
* This file is part of the esp8266 core for Arduino environment.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ESP8266WiFiMulti.h"
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
ESP8266WiFiMulti::ESP8266WiFiMulti() {
|
||||
}
|
||||
|
||||
ESP8266WiFiMulti::~ESP8266WiFiMulti() {
|
||||
APlistClean();
|
||||
}
|
||||
|
||||
bool ESP8266WiFiMulti::addAP(const char* ssid, const char *passphrase) {
|
||||
return APlistAdd(ssid, passphrase);
|
||||
}
|
||||
|
||||
bool ESP8266WiFiMulti::existsAP(const char* ssid, const char *passphrase) {
|
||||
return APlistExists(ssid, passphrase);
|
||||
}
|
||||
|
||||
wl_status_t ESP8266WiFiMulti::run(void) {
|
||||
|
||||
wl_status_t status = WiFi.status();
|
||||
if(status == WL_DISCONNECTED || status == WL_NO_SSID_AVAIL || status == WL_IDLE_STATUS || status == WL_CONNECT_FAILED) {
|
||||
|
||||
int8_t scanResult = WiFi.scanComplete();
|
||||
|
||||
if(scanResult == WIFI_SCAN_RUNNING) {
|
||||
// scan is running, do nothing yet
|
||||
status = WL_NO_SSID_AVAIL;
|
||||
return status;
|
||||
}
|
||||
|
||||
if(scanResult == 0) {
|
||||
// scan done, no ssids found. Start another scan.
|
||||
DEBUG_WIFI_MULTI("[WIFI] scan done\n");
|
||||
DEBUG_WIFI_MULTI("[WIFI] no networks found\n");
|
||||
WiFi.scanDelete();
|
||||
DEBUG_WIFI_MULTI("\n\n");
|
||||
delay(0);
|
||||
WiFi.disconnect();
|
||||
DEBUG_WIFI_MULTI("[WIFI] start scan\n");
|
||||
// scan wifi async mode
|
||||
WiFi.scanNetworks(true);
|
||||
return status;
|
||||
}
|
||||
|
||||
if(scanResult > 0) {
|
||||
// scan done, analyze
|
||||
WifiAPEntry bestNetwork { NULL, NULL };
|
||||
int bestNetworkDb = INT_MIN;
|
||||
uint8 bestBSSID[6];
|
||||
int32_t bestChannel;
|
||||
|
||||
DEBUG_WIFI_MULTI("[WIFI] scan done\n");
|
||||
delay(0);
|
||||
|
||||
DEBUG_WIFI_MULTI("[WIFI] %d networks found\n", scanResult);
|
||||
for(int8_t i = 0; i < scanResult; ++i) {
|
||||
|
||||
String ssid_scan;
|
||||
int32_t rssi_scan;
|
||||
uint8_t sec_scan;
|
||||
uint8_t* BSSID_scan;
|
||||
int32_t chan_scan;
|
||||
bool hidden_scan;
|
||||
|
||||
WiFi.getNetworkInfo(i, ssid_scan, sec_scan, rssi_scan, BSSID_scan, chan_scan, hidden_scan);
|
||||
|
||||
bool known = false;
|
||||
for(auto entry : APlist) {
|
||||
if(ssid_scan == entry.ssid) { // SSID match
|
||||
known = true;
|
||||
if(rssi_scan > bestNetworkDb) { // best network
|
||||
if(sec_scan == ENC_TYPE_NONE || entry.passphrase) { // check for passphrase if not open wlan
|
||||
bestNetworkDb = rssi_scan;
|
||||
bestChannel = chan_scan;
|
||||
bestNetwork = entry;
|
||||
memcpy((void*) &bestBSSID, (void*) BSSID_scan, sizeof(bestBSSID));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(known) {
|
||||
DEBUG_WIFI_MULTI(" ---> ");
|
||||
} else {
|
||||
DEBUG_WIFI_MULTI(" ");
|
||||
}
|
||||
|
||||
DEBUG_WIFI_MULTI(" %d: [%d][%02X:%02X:%02X:%02X:%02X:%02X] %s (%d) %c\n", i, chan_scan, BSSID_scan[0], BSSID_scan[1], BSSID_scan[2], BSSID_scan[3], BSSID_scan[4], BSSID_scan[5], ssid_scan.c_str(), rssi_scan, (sec_scan == ENC_TYPE_NONE) ? ' ' : '*');
|
||||
delay(0);
|
||||
}
|
||||
|
||||
// clean up ram
|
||||
WiFi.scanDelete();
|
||||
|
||||
DEBUG_WIFI_MULTI("\n\n");
|
||||
delay(0);
|
||||
|
||||
if(bestNetwork.ssid) {
|
||||
DEBUG_WIFI_MULTI("[WIFI] Connecting BSSID: %02X:%02X:%02X:%02X:%02X:%02X SSID: %s Channel: %d (%d)\n", bestBSSID[0], bestBSSID[1], bestBSSID[2], bestBSSID[3], bestBSSID[4], bestBSSID[5], bestNetwork.ssid, bestChannel, bestNetworkDb);
|
||||
|
||||
WiFi.begin(bestNetwork.ssid, bestNetwork.passphrase, bestChannel, bestBSSID);
|
||||
status = WiFi.status();
|
||||
|
||||
static const uint32_t connectTimeout = 5000; //5s timeout
|
||||
|
||||
auto startTime = millis();
|
||||
// wait for connection, fail, or timeout
|
||||
while(status != WL_CONNECTED && status != WL_NO_SSID_AVAIL && status != WL_CONNECT_FAILED && (millis() - startTime) <= connectTimeout) {
|
||||
delay(10);
|
||||
status = WiFi.status();
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ESP_WIFI
|
||||
IPAddress ip;
|
||||
uint8_t * mac;
|
||||
switch(status) {
|
||||
case WL_CONNECTED:
|
||||
ip = WiFi.localIP();
|
||||
mac = WiFi.BSSID();
|
||||
DEBUG_WIFI_MULTI("[WIFI] Connecting done.\n");
|
||||
DEBUG_WIFI_MULTI("[WIFI] SSID: %s\n", WiFi.SSID().c_str());
|
||||
DEBUG_WIFI_MULTI("[WIFI] IP: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
|
||||
DEBUG_WIFI_MULTI("[WIFI] MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
DEBUG_WIFI_MULTI("[WIFI] Channel: %d\n", WiFi.channel());
|
||||
break;
|
||||
case WL_NO_SSID_AVAIL:
|
||||
DEBUG_WIFI_MULTI("[WIFI] Connecting Failed AP not found.\n");
|
||||
break;
|
||||
case WL_CONNECT_FAILED:
|
||||
DEBUG_WIFI_MULTI("[WIFI] Connecting Failed.\n");
|
||||
break;
|
||||
default:
|
||||
DEBUG_WIFI_MULTI("[WIFI] Connecting Failed (%d).\n", status);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
DEBUG_WIFI_MULTI("[WIFI] no matching wifi found!\n");
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
// scan failed, or some other condition not handled above. Start another scan.
|
||||
DEBUG_WIFI_MULTI("[WIFI] delete old wifi config...\n");
|
||||
WiFi.disconnect();
|
||||
|
||||
DEBUG_WIFI_MULTI("[WIFI] start scan\n");
|
||||
// scan wifi async mode
|
||||
WiFi.scanNetworks(true);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// ##################################################################################
|
||||
|
||||
bool ESP8266WiFiMulti::APlistAdd(const char* ssid, const char *passphrase) {
|
||||
|
||||
WifiAPEntry newAP;
|
||||
|
||||
if(!ssid || *ssid == 0x00 || strlen(ssid) > 32) {
|
||||
// fail SSID too long or missing!
|
||||
DEBUG_WIFI_MULTI("[WIFI][APlistAdd] no ssid or ssid too long\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
//for passphrase, max is 63 ascii + null. For psk, 64hex + null.
|
||||
if(passphrase && strlen(passphrase) > 64) {
|
||||
// fail passphrase too long!
|
||||
DEBUG_WIFI_MULTI("[WIFI][APlistAdd] passphrase too long\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(APlistExists(ssid, passphrase)) {
|
||||
DEBUG_WIFI_MULTI("[WIFI][APlistAdd] SSID: %s already exists\n", ssid);
|
||||
return true;
|
||||
}
|
||||
|
||||
newAP.ssid = strdup(ssid);
|
||||
|
||||
if(!newAP.ssid) {
|
||||
DEBUG_WIFI_MULTI("[WIFI][APlistAdd] fail newAP.ssid == 0\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(passphrase) {
|
||||
newAP.passphrase = strdup(passphrase);
|
||||
} else {
|
||||
newAP.passphrase = strdup("");
|
||||
}
|
||||
|
||||
if(!newAP.passphrase) {
|
||||
DEBUG_WIFI_MULTI("[WIFI][APlistAdd] fail newAP.passphrase == 0\n");
|
||||
free(newAP.ssid);
|
||||
return false;
|
||||
}
|
||||
|
||||
APlist.push_back(newAP);
|
||||
DEBUG_WIFI_MULTI("[WIFI][APlistAdd] add SSID: %s\n", newAP.ssid);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ESP8266WiFiMulti::APlistExists(const char* ssid, const char *passphrase) {
|
||||
if(!ssid || *ssid == 0x00 || strlen(ssid) > 32) {
|
||||
// fail SSID too long or missing!
|
||||
DEBUG_WIFI_MULTI("[WIFI][APlistExists] no ssid or ssid too long\n");
|
||||
return false;
|
||||
}
|
||||
for(auto entry : APlist) {
|
||||
if(!strcmp(entry.ssid, ssid)) {
|
||||
if(!passphrase) {
|
||||
if(!strcmp(entry.passphrase, "")) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if(!strcmp(entry.passphrase, passphrase)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ESP8266WiFiMulti::APlistClean(void) {
|
||||
for(auto entry : APlist) {
|
||||
if(entry.ssid) {
|
||||
free(entry.ssid);
|
||||
}
|
||||
if(entry.passphrase) {
|
||||
free(entry.passphrase);
|
||||
}
|
||||
}
|
||||
APlist.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@file ESP8266WiFiMulti.cpp
|
||||
@date 16.05.2015
|
||||
@author Markus Sattler
|
||||
|
||||
Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "ESP8266WiFiMulti.h"
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
ESP8266WiFiMulti::ESP8266WiFiMulti()
|
||||
{
|
||||
}
|
||||
|
||||
ESP8266WiFiMulti::~ESP8266WiFiMulti()
|
||||
{
|
||||
APlistClean();
|
||||
}
|
||||
|
||||
bool ESP8266WiFiMulti::addAP(const char* ssid, const char *passphrase)
|
||||
{
|
||||
return APlistAdd(ssid, passphrase);
|
||||
}
|
||||
|
||||
bool ESP8266WiFiMulti::existsAP(const char* ssid, const char *passphrase)
|
||||
{
|
||||
return APlistExists(ssid, passphrase);
|
||||
}
|
||||
|
||||
wl_status_t ESP8266WiFiMulti::run(void)
|
||||
{
|
||||
|
||||
wl_status_t status = WiFi.status();
|
||||
if (status == WL_DISCONNECTED || status == WL_NO_SSID_AVAIL || status == WL_IDLE_STATUS || status == WL_CONNECT_FAILED)
|
||||
{
|
||||
|
||||
int8_t scanResult = WiFi.scanComplete();
|
||||
|
||||
if (scanResult == WIFI_SCAN_RUNNING)
|
||||
{
|
||||
// scan is running, do nothing yet
|
||||
status = WL_NO_SSID_AVAIL;
|
||||
return status;
|
||||
}
|
||||
|
||||
if (scanResult == 0)
|
||||
{
|
||||
// scan done, no ssids found. Start another scan.
|
||||
DEBUG_WIFI_MULTI("[WIFI] scan done\n");
|
||||
DEBUG_WIFI_MULTI("[WIFI] no networks found\n");
|
||||
WiFi.scanDelete();
|
||||
DEBUG_WIFI_MULTI("\n\n");
|
||||
delay(0);
|
||||
WiFi.disconnect();
|
||||
DEBUG_WIFI_MULTI("[WIFI] start scan\n");
|
||||
// scan wifi async mode
|
||||
WiFi.scanNetworks(true);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (scanResult > 0)
|
||||
{
|
||||
// scan done, analyze
|
||||
WifiAPEntry bestNetwork { NULL, NULL };
|
||||
int bestNetworkDb = INT_MIN;
|
||||
uint8 bestBSSID[6];
|
||||
int32_t bestChannel;
|
||||
|
||||
DEBUG_WIFI_MULTI("[WIFI] scan done\n");
|
||||
delay(0);
|
||||
|
||||
DEBUG_WIFI_MULTI("[WIFI] %d networks found\n", scanResult);
|
||||
for (int8_t i = 0; i < scanResult; ++i)
|
||||
{
|
||||
|
||||
String ssid_scan;
|
||||
int32_t rssi_scan;
|
||||
uint8_t sec_scan;
|
||||
uint8_t* BSSID_scan;
|
||||
int32_t chan_scan;
|
||||
bool hidden_scan;
|
||||
|
||||
WiFi.getNetworkInfo(i, ssid_scan, sec_scan, rssi_scan, BSSID_scan, chan_scan, hidden_scan);
|
||||
|
||||
bool known = false;
|
||||
for (auto entry : APlist)
|
||||
{
|
||||
if (ssid_scan == entry.ssid) // SSID match
|
||||
{
|
||||
known = true;
|
||||
if (rssi_scan > bestNetworkDb) // best network
|
||||
{
|
||||
if (sec_scan == ENC_TYPE_NONE || entry.passphrase) // check for passphrase if not open wlan
|
||||
{
|
||||
bestNetworkDb = rssi_scan;
|
||||
bestChannel = chan_scan;
|
||||
bestNetwork = entry;
|
||||
memcpy((void*) &bestBSSID, (void*) BSSID_scan, sizeof(bestBSSID));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (known)
|
||||
{
|
||||
DEBUG_WIFI_MULTI(" ---> ");
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_WIFI_MULTI(" ");
|
||||
}
|
||||
|
||||
DEBUG_WIFI_MULTI(" %d: [%d][%02X:%02X:%02X:%02X:%02X:%02X] %s (%d) %c\n", i, chan_scan, BSSID_scan[0], BSSID_scan[1], BSSID_scan[2], BSSID_scan[3], BSSID_scan[4], BSSID_scan[5], ssid_scan.c_str(), rssi_scan, (sec_scan == ENC_TYPE_NONE) ? ' ' : '*');
|
||||
delay(0);
|
||||
}
|
||||
|
||||
// clean up ram
|
||||
WiFi.scanDelete();
|
||||
|
||||
DEBUG_WIFI_MULTI("\n\n");
|
||||
delay(0);
|
||||
|
||||
if (bestNetwork.ssid)
|
||||
{
|
||||
DEBUG_WIFI_MULTI("[WIFI] Connecting BSSID: %02X:%02X:%02X:%02X:%02X:%02X SSID: %s Channel: %d (%d)\n", bestBSSID[0], bestBSSID[1], bestBSSID[2], bestBSSID[3], bestBSSID[4], bestBSSID[5], bestNetwork.ssid, bestChannel, bestNetworkDb);
|
||||
|
||||
WiFi.begin(bestNetwork.ssid, bestNetwork.passphrase, bestChannel, bestBSSID);
|
||||
status = WiFi.status();
|
||||
|
||||
static const uint32_t connectTimeout = 5000; //5s timeout
|
||||
|
||||
auto startTime = millis();
|
||||
// wait for connection, fail, or timeout
|
||||
while (status != WL_CONNECTED && status != WL_NO_SSID_AVAIL && status != WL_CONNECT_FAILED && (millis() - startTime) <= connectTimeout)
|
||||
{
|
||||
delay(10);
|
||||
status = WiFi.status();
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ESP_WIFI
|
||||
IPAddress ip;
|
||||
uint8_t * mac;
|
||||
switch (status)
|
||||
{
|
||||
case WL_CONNECTED:
|
||||
ip = WiFi.localIP();
|
||||
mac = WiFi.BSSID();
|
||||
DEBUG_WIFI_MULTI("[WIFI] Connecting done.\n");
|
||||
DEBUG_WIFI_MULTI("[WIFI] SSID: %s\n", WiFi.SSID().c_str());
|
||||
DEBUG_WIFI_MULTI("[WIFI] IP: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
|
||||
DEBUG_WIFI_MULTI("[WIFI] MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
DEBUG_WIFI_MULTI("[WIFI] Channel: %d\n", WiFi.channel());
|
||||
break;
|
||||
case WL_NO_SSID_AVAIL:
|
||||
DEBUG_WIFI_MULTI("[WIFI] Connecting Failed AP not found.\n");
|
||||
break;
|
||||
case WL_CONNECT_FAILED:
|
||||
DEBUG_WIFI_MULTI("[WIFI] Connecting Failed.\n");
|
||||
break;
|
||||
default:
|
||||
DEBUG_WIFI_MULTI("[WIFI] Connecting Failed (%d).\n", status);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_WIFI_MULTI("[WIFI] no matching wifi found!\n");
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
// scan failed, or some other condition not handled above. Start another scan.
|
||||
DEBUG_WIFI_MULTI("[WIFI] delete old wifi config...\n");
|
||||
WiFi.disconnect();
|
||||
|
||||
DEBUG_WIFI_MULTI("[WIFI] start scan\n");
|
||||
// scan wifi async mode
|
||||
WiFi.scanNetworks(true);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// ##################################################################################
|
||||
|
||||
bool ESP8266WiFiMulti::APlistAdd(const char* ssid, const char *passphrase)
|
||||
{
|
||||
|
||||
WifiAPEntry newAP;
|
||||
|
||||
if (!ssid || *ssid == 0x00 || strlen(ssid) > 32)
|
||||
{
|
||||
// fail SSID too long or missing!
|
||||
DEBUG_WIFI_MULTI("[WIFI][APlistAdd] no ssid or ssid too long\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
//for passphrase, max is 63 ascii + null. For psk, 64hex + null.
|
||||
if (passphrase && strlen(passphrase) > 64)
|
||||
{
|
||||
// fail passphrase too long!
|
||||
DEBUG_WIFI_MULTI("[WIFI][APlistAdd] passphrase too long\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (APlistExists(ssid, passphrase))
|
||||
{
|
||||
DEBUG_WIFI_MULTI("[WIFI][APlistAdd] SSID: %s already exists\n", ssid);
|
||||
return true;
|
||||
}
|
||||
|
||||
newAP.ssid = strdup(ssid);
|
||||
|
||||
if (!newAP.ssid)
|
||||
{
|
||||
DEBUG_WIFI_MULTI("[WIFI][APlistAdd] fail newAP.ssid == 0\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (passphrase)
|
||||
{
|
||||
newAP.passphrase = strdup(passphrase);
|
||||
}
|
||||
else
|
||||
{
|
||||
newAP.passphrase = strdup("");
|
||||
}
|
||||
|
||||
if (!newAP.passphrase)
|
||||
{
|
||||
DEBUG_WIFI_MULTI("[WIFI][APlistAdd] fail newAP.passphrase == 0\n");
|
||||
free(newAP.ssid);
|
||||
return false;
|
||||
}
|
||||
|
||||
APlist.push_back(newAP);
|
||||
DEBUG_WIFI_MULTI("[WIFI][APlistAdd] add SSID: %s\n", newAP.ssid);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ESP8266WiFiMulti::APlistExists(const char* ssid, const char *passphrase)
|
||||
{
|
||||
if (!ssid || *ssid == 0x00 || strlen(ssid) > 32)
|
||||
{
|
||||
// fail SSID too long or missing!
|
||||
DEBUG_WIFI_MULTI("[WIFI][APlistExists] no ssid or ssid too long\n");
|
||||
return false;
|
||||
}
|
||||
for (auto entry : APlist)
|
||||
{
|
||||
if (!strcmp(entry.ssid, ssid))
|
||||
{
|
||||
if (!passphrase)
|
||||
{
|
||||
if (!strcmp(entry.passphrase, ""))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!strcmp(entry.passphrase, passphrase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ESP8266WiFiMulti::APlistClean(void)
|
||||
{
|
||||
for (auto entry : APlist)
|
||||
{
|
||||
if (entry.ssid)
|
||||
{
|
||||
free(entry.ssid);
|
||||
}
|
||||
if (entry.passphrase)
|
||||
{
|
||||
free(entry.passphrase);
|
||||
}
|
||||
}
|
||||
APlist.clear();
|
||||
}
|
||||
|
||||
|
@ -1,68 +1,70 @@
|
||||
/**
|
||||
*
|
||||
* @file ESP8266WiFiMulti.h
|
||||
* @date 16.05.2015
|
||||
* @author Markus Sattler
|
||||
*
|
||||
* Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||
* This file is part of the esp8266 core for Arduino environment.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef WIFICLIENTMULTI_H_
|
||||
#define WIFICLIENTMULTI_H_
|
||||
|
||||
#include "ESP8266WiFi.h"
|
||||
#include <vector>
|
||||
|
||||
#ifdef DEBUG_ESP_WIFI
|
||||
#ifdef DEBUG_ESP_PORT
|
||||
#define DEBUG_WIFI_MULTI(fmt, ...) DEBUG_ESP_PORT.printf_P( (PGM_P)PSTR(fmt), ##__VA_ARGS__ )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_WIFI_MULTI
|
||||
#define DEBUG_WIFI_MULTI(...) do { (void)0; } while (0)
|
||||
#endif
|
||||
|
||||
struct WifiAPEntry {
|
||||
char * ssid;
|
||||
char * passphrase;
|
||||
};
|
||||
|
||||
typedef std::vector<WifiAPEntry> WifiAPlist;
|
||||
|
||||
class ESP8266WiFiMulti {
|
||||
public:
|
||||
ESP8266WiFiMulti();
|
||||
~ESP8266WiFiMulti();
|
||||
|
||||
bool addAP(const char* ssid, const char *passphrase = NULL);
|
||||
bool existsAP(const char* ssid, const char *passphrase = NULL);
|
||||
|
||||
wl_status_t run(void);
|
||||
|
||||
private:
|
||||
WifiAPlist APlist;
|
||||
bool APlistAdd(const char* ssid, const char *passphrase = NULL);
|
||||
bool APlistExists(const char* ssid, const char *passphrase = NULL);
|
||||
void APlistClean(void);
|
||||
|
||||
};
|
||||
|
||||
#endif /* WIFICLIENTMULTI_H_ */
|
||||
/**
|
||||
|
||||
@file ESP8266WiFiMulti.h
|
||||
@date 16.05.2015
|
||||
@author Markus Sattler
|
||||
|
||||
Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef WIFICLIENTMULTI_H_
|
||||
#define WIFICLIENTMULTI_H_
|
||||
|
||||
#include "ESP8266WiFi.h"
|
||||
#include <vector>
|
||||
|
||||
#ifdef DEBUG_ESP_WIFI
|
||||
#ifdef DEBUG_ESP_PORT
|
||||
#define DEBUG_WIFI_MULTI(fmt, ...) DEBUG_ESP_PORT.printf_P( (PGM_P)PSTR(fmt), ##__VA_ARGS__ )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_WIFI_MULTI
|
||||
#define DEBUG_WIFI_MULTI(...) do { (void)0; } while (0)
|
||||
#endif
|
||||
|
||||
struct WifiAPEntry
|
||||
{
|
||||
char * ssid;
|
||||
char * passphrase;
|
||||
};
|
||||
|
||||
typedef std::vector<WifiAPEntry> WifiAPlist;
|
||||
|
||||
class ESP8266WiFiMulti
|
||||
{
|
||||
public:
|
||||
ESP8266WiFiMulti();
|
||||
~ESP8266WiFiMulti();
|
||||
|
||||
bool addAP(const char* ssid, const char *passphrase = NULL);
|
||||
bool existsAP(const char* ssid, const char *passphrase = NULL);
|
||||
|
||||
wl_status_t run(void);
|
||||
|
||||
private:
|
||||
WifiAPlist APlist;
|
||||
bool APlistAdd(const char* ssid, const char *passphrase = NULL);
|
||||
bool APlistExists(const char* ssid, const char *passphrase = NULL);
|
||||
void APlistClean(void);
|
||||
|
||||
};
|
||||
|
||||
#endif /* WIFICLIENTMULTI_H_ */
|
||||
|
@ -1,111 +1,121 @@
|
||||
/*
|
||||
ESP8266WiFiSTA-WPS.cpp - WiFi library for esp8266
|
||||
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Reworked on 28 Dec 2015 by Markus Sattler
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "ESP8266WiFi.h"
|
||||
#include "ESP8266WiFiGeneric.h"
|
||||
#include "ESP8266WiFiSTA.h"
|
||||
#include "coredecls.h" // disable_extra4k_at_link_time()
|
||||
|
||||
static void wifi_wps_status_cb(wps_cb_status status);
|
||||
|
||||
/**
|
||||
* WPS config
|
||||
* so far only WPS_TYPE_PBC is supported (SDK 1.2.0)
|
||||
* @return ok
|
||||
*/
|
||||
bool ESP8266WiFiSTAClass::beginWPSConfig(void) {
|
||||
|
||||
// SYS ram is used by WPS, let's configure user stack inside user's HEAP
|
||||
disable_extra4k_at_link_time();
|
||||
|
||||
if(!WiFi.enableSTA(true)) {
|
||||
// enable STA failed
|
||||
return false;
|
||||
}
|
||||
|
||||
disconnect();
|
||||
|
||||
DEBUGV("wps begin\n");
|
||||
|
||||
if(!wifi_wps_disable()) {
|
||||
DEBUGV("wps disable failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// so far only WPS_TYPE_PBC is supported (SDK 1.2.0)
|
||||
if(!wifi_wps_enable(WPS_TYPE_PBC)) {
|
||||
DEBUGV("wps enable failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!wifi_set_wps_cb((wps_st_cb_t) &wifi_wps_status_cb)) {
|
||||
DEBUGV("wps cb failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!wifi_wps_start()) {
|
||||
DEBUGV("wps start failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
esp_yield();
|
||||
// will return here when wifi_wps_status_cb fires
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* WPS callback
|
||||
* @param status wps_cb_status
|
||||
*/
|
||||
void wifi_wps_status_cb(wps_cb_status status) {
|
||||
DEBUGV("wps cb status: %d\r\n", status);
|
||||
switch(status) {
|
||||
case WPS_CB_ST_SUCCESS:
|
||||
if(!wifi_wps_disable()) {
|
||||
DEBUGV("wps disable failed\n");
|
||||
}
|
||||
wifi_station_connect();
|
||||
break;
|
||||
case WPS_CB_ST_FAILED:
|
||||
DEBUGV("wps FAILED\n");
|
||||
break;
|
||||
case WPS_CB_ST_TIMEOUT:
|
||||
DEBUGV("wps TIMEOUT\n");
|
||||
break;
|
||||
case WPS_CB_ST_WEP:
|
||||
DEBUGV("wps WEP\n");
|
||||
break;
|
||||
case WPS_CB_ST_UNK:
|
||||
DEBUGV("wps UNKNOWN\n");
|
||||
if(!wifi_wps_disable()) {
|
||||
DEBUGV("wps disable failed\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
// TODO user function to get status
|
||||
|
||||
esp_schedule(); // resume the beginWPSConfig function
|
||||
}
|
||||
/*
|
||||
ESP8266WiFiSTA-WPS.cpp - WiFi library for esp8266
|
||||
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Reworked on 28 Dec 2015 by Markus Sattler
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "ESP8266WiFi.h"
|
||||
#include "ESP8266WiFiGeneric.h"
|
||||
#include "ESP8266WiFiSTA.h"
|
||||
#include "coredecls.h" // disable_extra4k_at_link_time()
|
||||
|
||||
static void wifi_wps_status_cb(wps_cb_status status);
|
||||
|
||||
/**
|
||||
WPS config
|
||||
so far only WPS_TYPE_PBC is supported (SDK 1.2.0)
|
||||
@return ok
|
||||
*/
|
||||
bool ESP8266WiFiSTAClass::beginWPSConfig(void)
|
||||
{
|
||||
|
||||
// SYS ram is used by WPS, let's configure user stack inside user's HEAP
|
||||
disable_extra4k_at_link_time();
|
||||
|
||||
if (!WiFi.enableSTA(true))
|
||||
{
|
||||
// enable STA failed
|
||||
return false;
|
||||
}
|
||||
|
||||
disconnect();
|
||||
|
||||
DEBUGV("wps begin\n");
|
||||
|
||||
if (!wifi_wps_disable())
|
||||
{
|
||||
DEBUGV("wps disable failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// so far only WPS_TYPE_PBC is supported (SDK 1.2.0)
|
||||
if (!wifi_wps_enable(WPS_TYPE_PBC))
|
||||
{
|
||||
DEBUGV("wps enable failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!wifi_set_wps_cb((wps_st_cb_t) &wifi_wps_status_cb))
|
||||
{
|
||||
DEBUGV("wps cb failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!wifi_wps_start())
|
||||
{
|
||||
DEBUGV("wps start failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
esp_yield();
|
||||
// will return here when wifi_wps_status_cb fires
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
WPS callback
|
||||
@param status wps_cb_status
|
||||
*/
|
||||
void wifi_wps_status_cb(wps_cb_status status)
|
||||
{
|
||||
DEBUGV("wps cb status: %d\r\n", status);
|
||||
switch (status)
|
||||
{
|
||||
case WPS_CB_ST_SUCCESS:
|
||||
if (!wifi_wps_disable())
|
||||
{
|
||||
DEBUGV("wps disable failed\n");
|
||||
}
|
||||
wifi_station_connect();
|
||||
break;
|
||||
case WPS_CB_ST_FAILED:
|
||||
DEBUGV("wps FAILED\n");
|
||||
break;
|
||||
case WPS_CB_ST_TIMEOUT:
|
||||
DEBUGV("wps TIMEOUT\n");
|
||||
break;
|
||||
case WPS_CB_ST_WEP:
|
||||
DEBUGV("wps WEP\n");
|
||||
break;
|
||||
case WPS_CB_ST_UNK:
|
||||
DEBUGV("wps UNKNOWN\n");
|
||||
if (!wifi_wps_disable())
|
||||
{
|
||||
DEBUGV("wps disable failed\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
// TODO user function to get status
|
||||
|
||||
esp_schedule(); // resume the beginWPSConfig function
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,114 +1,121 @@
|
||||
/*
|
||||
ESP8266WiFiSTA.h - esp8266 Wifi support.
|
||||
Based on WiFi.h from Ardiono WiFi shield library.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
Modified by Ivan Grokhotkov, December 2014
|
||||
Reworked by Markus Sattler, December 2015
|
||||
|
||||
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 ESP8266WIFISTA_H_
|
||||
#define ESP8266WIFISTA_H_
|
||||
|
||||
|
||||
#include "ESP8266WiFiType.h"
|
||||
#include "ESP8266WiFiGeneric.h"
|
||||
#include "user_interface.h"
|
||||
|
||||
|
||||
class ESP8266WiFiSTAClass {
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// ---------------------------------------- STA function ----------------------------------------
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
||||
wl_status_t begin(const char* ssid, const char *passphrase = NULL, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true);
|
||||
wl_status_t begin(char* ssid, char *passphrase = NULL, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true);
|
||||
wl_status_t begin(const String& ssid, const String& passphrase = emptyString, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true);
|
||||
wl_status_t begin();
|
||||
|
||||
//The argument order for ESP is not the same as for Arduino. However, there is compatibility code under the hood
|
||||
//to detect Arduino arg order, and handle it correctly. Be aware that the Arduino default value handling doesn't
|
||||
//work here (see Arduino docs for gway/subnet defaults). In other words: at least 3 args must always be given.
|
||||
bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1 = (uint32_t)0x00000000, IPAddress dns2 = (uint32_t)0x00000000);
|
||||
|
||||
bool reconnect();
|
||||
bool disconnect(bool wifioff = false);
|
||||
|
||||
bool isConnected();
|
||||
|
||||
bool setAutoConnect(bool autoConnect);
|
||||
bool getAutoConnect();
|
||||
|
||||
bool setAutoReconnect(bool autoReconnect);
|
||||
bool getAutoReconnect();
|
||||
|
||||
uint8_t waitForConnectResult();
|
||||
|
||||
// STA network info
|
||||
IPAddress localIP();
|
||||
|
||||
uint8_t * macAddress(uint8_t* mac);
|
||||
String macAddress();
|
||||
|
||||
IPAddress subnetMask();
|
||||
IPAddress gatewayIP();
|
||||
IPAddress dnsIP(uint8_t dns_no = 0);
|
||||
|
||||
String hostname();
|
||||
bool hostname(const String& aHostname) { return hostname(aHostname.c_str()); }
|
||||
bool hostname(const char* aHostname);
|
||||
|
||||
// STA WiFi info
|
||||
wl_status_t status();
|
||||
String SSID() const;
|
||||
String psk() const;
|
||||
|
||||
uint8_t * BSSID();
|
||||
String BSSIDstr();
|
||||
|
||||
int32_t RSSI();
|
||||
|
||||
static void enableInsecureWEP (bool enable = true) { _useInsecureWEP = enable; }
|
||||
|
||||
protected:
|
||||
|
||||
static bool _useStaticIp;
|
||||
static bool _useInsecureWEP;
|
||||
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// ------------------------------------ STA remote configure -----------------------------------
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
||||
bool beginWPSConfig(void);
|
||||
bool beginSmartConfig();
|
||||
bool stopSmartConfig();
|
||||
bool smartConfigDone();
|
||||
|
||||
protected:
|
||||
|
||||
static bool _smartConfigStarted;
|
||||
static bool _smartConfigDone;
|
||||
|
||||
static void _smartConfigCallback(uint32_t status, void* result);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* ESP8266WIFISTA_H_ */
|
||||
/*
|
||||
ESP8266WiFiSTA.h - esp8266 Wifi support.
|
||||
Based on WiFi.h from Ardiono WiFi shield library.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
Modified by Ivan Grokhotkov, December 2014
|
||||
Reworked by Markus Sattler, December 2015
|
||||
|
||||
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 ESP8266WIFISTA_H_
|
||||
#define ESP8266WIFISTA_H_
|
||||
|
||||
|
||||
#include "ESP8266WiFiType.h"
|
||||
#include "ESP8266WiFiGeneric.h"
|
||||
#include "user_interface.h"
|
||||
|
||||
|
||||
class ESP8266WiFiSTAClass
|
||||
{
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// ---------------------------------------- STA function ----------------------------------------
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
||||
wl_status_t begin(const char* ssid, const char *passphrase = NULL, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true);
|
||||
wl_status_t begin(char* ssid, char *passphrase = NULL, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true);
|
||||
wl_status_t begin(const String& ssid, const String& passphrase = emptyString, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true);
|
||||
wl_status_t begin();
|
||||
|
||||
//The argument order for ESP is not the same as for Arduino. However, there is compatibility code under the hood
|
||||
//to detect Arduino arg order, and handle it correctly. Be aware that the Arduino default value handling doesn't
|
||||
//work here (see Arduino docs for gway/subnet defaults). In other words: at least 3 args must always be given.
|
||||
bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1 = (uint32_t)0x00000000, IPAddress dns2 = (uint32_t)0x00000000);
|
||||
|
||||
bool reconnect();
|
||||
bool disconnect(bool wifioff = false);
|
||||
|
||||
bool isConnected();
|
||||
|
||||
bool setAutoConnect(bool autoConnect);
|
||||
bool getAutoConnect();
|
||||
|
||||
bool setAutoReconnect(bool autoReconnect);
|
||||
bool getAutoReconnect();
|
||||
|
||||
uint8_t waitForConnectResult();
|
||||
|
||||
// STA network info
|
||||
IPAddress localIP();
|
||||
|
||||
uint8_t * macAddress(uint8_t* mac);
|
||||
String macAddress();
|
||||
|
||||
IPAddress subnetMask();
|
||||
IPAddress gatewayIP();
|
||||
IPAddress dnsIP(uint8_t dns_no = 0);
|
||||
|
||||
String hostname();
|
||||
bool hostname(const String& aHostname)
|
||||
{
|
||||
return hostname(aHostname.c_str());
|
||||
}
|
||||
bool hostname(const char* aHostname);
|
||||
|
||||
// STA WiFi info
|
||||
wl_status_t status();
|
||||
String SSID() const;
|
||||
String psk() const;
|
||||
|
||||
uint8_t * BSSID();
|
||||
String BSSIDstr();
|
||||
|
||||
int32_t RSSI();
|
||||
|
||||
static void enableInsecureWEP(bool enable = true)
|
||||
{
|
||||
_useInsecureWEP = enable;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
static bool _useStaticIp;
|
||||
static bool _useInsecureWEP;
|
||||
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// ------------------------------------ STA remote configure -----------------------------------
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
||||
bool beginWPSConfig(void);
|
||||
bool beginSmartConfig();
|
||||
bool stopSmartConfig();
|
||||
bool smartConfigDone();
|
||||
|
||||
protected:
|
||||
|
||||
static bool _smartConfigStarted;
|
||||
static bool _smartConfigDone;
|
||||
|
||||
static void _smartConfigCallback(uint32_t status, void* result);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* ESP8266WIFISTA_H_ */
|
||||
|
@ -1,343 +1,386 @@
|
||||
/*
|
||||
ESP8266WiFiScan.cpp - WiFi library for esp8266
|
||||
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Reworked on 28 Dec 2015 by Markus Sattler
|
||||
|
||||
*/
|
||||
|
||||
#include "ESP8266WiFi.h"
|
||||
#include "ESP8266WiFiGeneric.h"
|
||||
#include "ESP8266WiFiScan.h"
|
||||
|
||||
extern "C" {
|
||||
#include "c_types.h"
|
||||
#include "ets_sys.h"
|
||||
#include "os_type.h"
|
||||
#include "osapi.h"
|
||||
#include "mem.h"
|
||||
#include "user_interface.h"
|
||||
}
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
extern "C" void esp_schedule();
|
||||
extern "C" void esp_yield();
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------
|
||||
// ---------------------------------------------------- Private functions ------------------------------------------------
|
||||
// -----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------
|
||||
// ----------------------------------------------------- scan function ---------------------------------------------------
|
||||
// -----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
bool ESP8266WiFiScanClass::_scanAsync = false;
|
||||
bool ESP8266WiFiScanClass::_scanStarted = false;
|
||||
bool ESP8266WiFiScanClass::_scanComplete = false;
|
||||
|
||||
size_t ESP8266WiFiScanClass::_scanCount = 0;
|
||||
void* ESP8266WiFiScanClass::_scanResult = 0;
|
||||
|
||||
std::function<void(int)> ESP8266WiFiScanClass::_onComplete;
|
||||
|
||||
/**
|
||||
* Start scan WiFi networks available
|
||||
* @param async run in async mode
|
||||
* @param show_hidden show hidden networks
|
||||
* @param channel scan only this channel (0 for all channels)
|
||||
* @param ssid* scan for only this ssid (NULL for all ssid's)
|
||||
* @return Number of discovered networks
|
||||
*/
|
||||
int8_t ESP8266WiFiScanClass::scanNetworks(bool async, bool show_hidden, uint8 channel, uint8* ssid) {
|
||||
if(ESP8266WiFiScanClass::_scanStarted) {
|
||||
return WIFI_SCAN_RUNNING;
|
||||
}
|
||||
|
||||
ESP8266WiFiScanClass::_scanAsync = async;
|
||||
|
||||
WiFi.enableSTA(true);
|
||||
|
||||
int status = wifi_station_get_connect_status();
|
||||
if(status != STATION_GOT_IP && status != STATION_IDLE) {
|
||||
wifi_station_disconnect();
|
||||
}
|
||||
|
||||
scanDelete();
|
||||
|
||||
struct scan_config config;
|
||||
memset(&config, 0, sizeof(config));
|
||||
config.ssid = ssid;
|
||||
config.channel = channel;
|
||||
config.show_hidden = show_hidden;
|
||||
if(wifi_station_scan(&config, reinterpret_cast<scan_done_cb_t>(&ESP8266WiFiScanClass::_scanDone))) {
|
||||
ESP8266WiFiScanClass::_scanComplete = false;
|
||||
ESP8266WiFiScanClass::_scanStarted = true;
|
||||
|
||||
if(ESP8266WiFiScanClass::_scanAsync) {
|
||||
delay(0); // time for the OS to trigger the scan
|
||||
return WIFI_SCAN_RUNNING;
|
||||
}
|
||||
|
||||
esp_yield();
|
||||
return ESP8266WiFiScanClass::_scanCount;
|
||||
} else {
|
||||
return WIFI_SCAN_FAILED;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts scanning WiFi networks available in async mode
|
||||
* @param onComplete the event handler executed when the scan is done
|
||||
* @param show_hidden show hidden networks
|
||||
*/
|
||||
void ESP8266WiFiScanClass::scanNetworksAsync(std::function<void(int)> onComplete, bool show_hidden) {
|
||||
_onComplete = onComplete;
|
||||
scanNetworks(true, show_hidden);
|
||||
}
|
||||
|
||||
/**
|
||||
* called to get the scan state in Async mode
|
||||
* @return scan result or status
|
||||
* -1 if scan not fin
|
||||
* -2 if scan not triggered
|
||||
*/
|
||||
int8_t ESP8266WiFiScanClass::scanComplete() {
|
||||
|
||||
if(_scanStarted) {
|
||||
return WIFI_SCAN_RUNNING;
|
||||
}
|
||||
|
||||
if(_scanComplete) {
|
||||
return ESP8266WiFiScanClass::_scanCount;
|
||||
}
|
||||
|
||||
return WIFI_SCAN_FAILED;
|
||||
}
|
||||
|
||||
/**
|
||||
* delete last scan result from RAM
|
||||
*/
|
||||
void ESP8266WiFiScanClass::scanDelete() {
|
||||
if(ESP8266WiFiScanClass::_scanResult) {
|
||||
delete[] reinterpret_cast<bss_info*>(ESP8266WiFiScanClass::_scanResult);
|
||||
ESP8266WiFiScanClass::_scanResult = 0;
|
||||
ESP8266WiFiScanClass::_scanCount = 0;
|
||||
}
|
||||
_scanComplete = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* loads all infos from a scanned wifi in to the ptr parameters
|
||||
* @param networkItem uint8_t
|
||||
* @param ssid const char**
|
||||
* @param encryptionType uint8_t *
|
||||
* @param RSSI int32_t *
|
||||
* @param BSSID uint8_t **
|
||||
* @param channel int32_t *
|
||||
* @param isHidden bool *
|
||||
* @return (true if ok)
|
||||
*/
|
||||
bool ESP8266WiFiScanClass::getNetworkInfo(uint8_t i, String &ssid, uint8_t &encType, int32_t &rssi, uint8_t* &bssid, int32_t &channel, bool &isHidden) {
|
||||
struct bss_info* it = reinterpret_cast<struct bss_info*>(_getScanInfoByIndex(i));
|
||||
if(!it) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char ssid_copy[33]; // Ensure space for maximum len SSID (32) plus trailing 0
|
||||
memcpy(ssid_copy, it->ssid, sizeof(it->ssid));
|
||||
ssid_copy[32] = 0; // Potentially add 0-termination if none present earlier
|
||||
ssid = (const char*) ssid_copy;
|
||||
encType = encryptionType(i);
|
||||
rssi = it->rssi;
|
||||
bssid = it->bssid; // move ptr
|
||||
channel = it->channel;
|
||||
isHidden = (it->is_hidden != 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the SSID discovered during the network scan.
|
||||
* @param i specify from which network item want to get the information
|
||||
* @return ssid string of the specified item on the networks scanned list
|
||||
*/
|
||||
String ESP8266WiFiScanClass::SSID(uint8_t i) {
|
||||
struct bss_info* it = reinterpret_cast<struct bss_info*>(_getScanInfoByIndex(i));
|
||||
if(!it) {
|
||||
return "";
|
||||
}
|
||||
char tmp[33]; //ssid can be up to 32chars, => plus null term
|
||||
memcpy(tmp, it->ssid, sizeof(it->ssid));
|
||||
tmp[32] = 0; //nullterm in case of 32 char ssid
|
||||
|
||||
return String(reinterpret_cast<const char*>(tmp));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the encryption type of the networks discovered during the scanNetworks
|
||||
* @param i specify from which network item want to get the information
|
||||
* @return encryption type (enum wl_enc_type) of the specified item on the networks scanned list
|
||||
*/
|
||||
uint8_t ESP8266WiFiScanClass::encryptionType(uint8_t i) {
|
||||
struct bss_info* it = reinterpret_cast<struct bss_info*>(_getScanInfoByIndex(i));
|
||||
if(!it) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(it->authmode) {
|
||||
case AUTH_OPEN:
|
||||
return ENC_TYPE_NONE;
|
||||
case AUTH_WEP:
|
||||
return ENC_TYPE_WEP;
|
||||
case AUTH_WPA_PSK:
|
||||
return ENC_TYPE_TKIP;
|
||||
case AUTH_WPA2_PSK:
|
||||
return ENC_TYPE_CCMP;
|
||||
case AUTH_WPA_WPA2_PSK:
|
||||
return ENC_TYPE_AUTO;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the RSSI of the networks discovered during the scanNetworks
|
||||
* @param i specify from which network item want to get the information
|
||||
* @return signed value of RSSI of the specified item on the networks scanned list
|
||||
*/
|
||||
int32_t ESP8266WiFiScanClass::RSSI(uint8_t i) {
|
||||
struct bss_info* it = reinterpret_cast<struct bss_info*>(_getScanInfoByIndex(i));
|
||||
if(!it) {
|
||||
return 0;
|
||||
}
|
||||
return it->rssi;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* return MAC / BSSID of scanned wifi
|
||||
* @param i specify from which network item want to get the information
|
||||
* @return uint8_t * MAC / BSSID of scanned wifi
|
||||
*/
|
||||
uint8_t * ESP8266WiFiScanClass::BSSID(uint8_t i) {
|
||||
struct bss_info* it = reinterpret_cast<struct bss_info*>(_getScanInfoByIndex(i));
|
||||
if(!it) {
|
||||
return 0;
|
||||
}
|
||||
return it->bssid;
|
||||
}
|
||||
|
||||
/**
|
||||
* return MAC / BSSID of scanned wifi
|
||||
* @param i specify from which network item want to get the information
|
||||
* @return String MAC / BSSID of scanned wifi
|
||||
*/
|
||||
String ESP8266WiFiScanClass::BSSIDstr(uint8_t i) {
|
||||
char mac[18] = { 0 };
|
||||
struct bss_info* it = reinterpret_cast<struct bss_info*>(_getScanInfoByIndex(i));
|
||||
if(!it) {
|
||||
return String("");
|
||||
}
|
||||
sprintf(mac, "%02X:%02X:%02X:%02X:%02X:%02X", it->bssid[0], it->bssid[1], it->bssid[2], it->bssid[3], it->bssid[4], it->bssid[5]);
|
||||
return String(mac);
|
||||
}
|
||||
|
||||
int32_t ESP8266WiFiScanClass::channel(uint8_t i) {
|
||||
struct bss_info* it = reinterpret_cast<struct bss_info*>(_getScanInfoByIndex(i));
|
||||
if(!it) {
|
||||
return 0;
|
||||
}
|
||||
return it->channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* return if the scanned wifi is Hidden (no SSID)
|
||||
* @param networkItem specify from which network item want to get the information
|
||||
* @return bool (true == hidden)
|
||||
*/
|
||||
bool ESP8266WiFiScanClass::isHidden(uint8_t i) {
|
||||
struct bss_info* it = reinterpret_cast<struct bss_info*>(_getScanInfoByIndex(i));
|
||||
if(!it) {
|
||||
return false;
|
||||
}
|
||||
return (it->is_hidden != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* private
|
||||
* scan callback
|
||||
* @param result void *arg
|
||||
* @param status STATUS
|
||||
*/
|
||||
void ESP8266WiFiScanClass::_scanDone(void* result, int status) {
|
||||
if(status != OK) {
|
||||
ESP8266WiFiScanClass::_scanCount = 0;
|
||||
ESP8266WiFiScanClass::_scanResult = 0;
|
||||
} else {
|
||||
|
||||
int i = 0;
|
||||
bss_info* head = reinterpret_cast<bss_info*>(result);
|
||||
|
||||
for(bss_info* it = head; it; it = STAILQ_NEXT(it, next), ++i)
|
||||
;
|
||||
ESP8266WiFiScanClass::_scanCount = i;
|
||||
if(i == 0) {
|
||||
ESP8266WiFiScanClass::_scanResult = 0;
|
||||
} else {
|
||||
bss_info* copied_info = new bss_info[i];
|
||||
i = 0;
|
||||
for(bss_info* it = head; it; it = STAILQ_NEXT(it, next), ++i) {
|
||||
memcpy(copied_info + i, it, sizeof(bss_info));
|
||||
}
|
||||
|
||||
ESP8266WiFiScanClass::_scanResult = copied_info;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ESP8266WiFiScanClass::_scanStarted = false;
|
||||
ESP8266WiFiScanClass::_scanComplete = true;
|
||||
|
||||
if(!ESP8266WiFiScanClass::_scanAsync) {
|
||||
esp_schedule();
|
||||
} else if (ESP8266WiFiScanClass::_onComplete) {
|
||||
ESP8266WiFiScanClass::_onComplete(ESP8266WiFiScanClass::_scanCount);
|
||||
ESP8266WiFiScanClass::_onComplete = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param i specify from which network item want to get the information
|
||||
* @return bss_info *
|
||||
*/
|
||||
void * ESP8266WiFiScanClass::_getScanInfoByIndex(int i) {
|
||||
if(!ESP8266WiFiScanClass::_scanResult || (size_t) i > ESP8266WiFiScanClass::_scanCount) {
|
||||
return 0;
|
||||
}
|
||||
return reinterpret_cast<bss_info*>(ESP8266WiFiScanClass::_scanResult) + i;
|
||||
}
|
||||
/*
|
||||
ESP8266WiFiScan.cpp - WiFi library for esp8266
|
||||
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Reworked on 28 Dec 2015 by Markus Sattler
|
||||
|
||||
*/
|
||||
|
||||
#include "ESP8266WiFi.h"
|
||||
#include "ESP8266WiFiGeneric.h"
|
||||
#include "ESP8266WiFiScan.h"
|
||||
|
||||
extern "C" {
|
||||
#include "c_types.h"
|
||||
#include "ets_sys.h"
|
||||
#include "os_type.h"
|
||||
#include "osapi.h"
|
||||
#include "mem.h"
|
||||
#include "user_interface.h"
|
||||
}
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
extern "C" void esp_schedule();
|
||||
extern "C" void esp_yield();
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------
|
||||
// ---------------------------------------------------- Private functions ------------------------------------------------
|
||||
// -----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------------
|
||||
// ----------------------------------------------------- scan function ---------------------------------------------------
|
||||
// -----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
bool ESP8266WiFiScanClass::_scanAsync = false;
|
||||
bool ESP8266WiFiScanClass::_scanStarted = false;
|
||||
bool ESP8266WiFiScanClass::_scanComplete = false;
|
||||
|
||||
size_t ESP8266WiFiScanClass::_scanCount = 0;
|
||||
void* ESP8266WiFiScanClass::_scanResult = 0;
|
||||
|
||||
std::function<void(int)> ESP8266WiFiScanClass::_onComplete;
|
||||
|
||||
/**
|
||||
Start scan WiFi networks available
|
||||
@param async run in async mode
|
||||
@param show_hidden show hidden networks
|
||||
@param channel scan only this channel (0 for all channels)
|
||||
@param ssid* scan for only this ssid (NULL for all ssid's)
|
||||
@return Number of discovered networks
|
||||
*/
|
||||
int8_t ESP8266WiFiScanClass::scanNetworks(bool async, bool show_hidden, uint8 channel, uint8* ssid)
|
||||
{
|
||||
if (ESP8266WiFiScanClass::_scanStarted)
|
||||
{
|
||||
return WIFI_SCAN_RUNNING;
|
||||
}
|
||||
|
||||
ESP8266WiFiScanClass::_scanAsync = async;
|
||||
|
||||
WiFi.enableSTA(true);
|
||||
|
||||
int status = wifi_station_get_connect_status();
|
||||
if (status != STATION_GOT_IP && status != STATION_IDLE)
|
||||
{
|
||||
wifi_station_disconnect();
|
||||
}
|
||||
|
||||
scanDelete();
|
||||
|
||||
struct scan_config config;
|
||||
memset(&config, 0, sizeof(config));
|
||||
config.ssid = ssid;
|
||||
config.channel = channel;
|
||||
config.show_hidden = show_hidden;
|
||||
if (wifi_station_scan(&config, reinterpret_cast<scan_done_cb_t>(&ESP8266WiFiScanClass::_scanDone)))
|
||||
{
|
||||
ESP8266WiFiScanClass::_scanComplete = false;
|
||||
ESP8266WiFiScanClass::_scanStarted = true;
|
||||
|
||||
if (ESP8266WiFiScanClass::_scanAsync)
|
||||
{
|
||||
delay(0); // time for the OS to trigger the scan
|
||||
return WIFI_SCAN_RUNNING;
|
||||
}
|
||||
|
||||
esp_yield();
|
||||
return ESP8266WiFiScanClass::_scanCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
return WIFI_SCAN_FAILED;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Starts scanning WiFi networks available in async mode
|
||||
@param onComplete the event handler executed when the scan is done
|
||||
@param show_hidden show hidden networks
|
||||
*/
|
||||
void ESP8266WiFiScanClass::scanNetworksAsync(std::function<void(int)> onComplete, bool show_hidden)
|
||||
{
|
||||
_onComplete = onComplete;
|
||||
scanNetworks(true, show_hidden);
|
||||
}
|
||||
|
||||
/**
|
||||
called to get the scan state in Async mode
|
||||
@return scan result or status
|
||||
-1 if scan not fin
|
||||
-2 if scan not triggered
|
||||
*/
|
||||
int8_t ESP8266WiFiScanClass::scanComplete()
|
||||
{
|
||||
|
||||
if (_scanStarted)
|
||||
{
|
||||
return WIFI_SCAN_RUNNING;
|
||||
}
|
||||
|
||||
if (_scanComplete)
|
||||
{
|
||||
return ESP8266WiFiScanClass::_scanCount;
|
||||
}
|
||||
|
||||
return WIFI_SCAN_FAILED;
|
||||
}
|
||||
|
||||
/**
|
||||
delete last scan result from RAM
|
||||
*/
|
||||
void ESP8266WiFiScanClass::scanDelete()
|
||||
{
|
||||
if (ESP8266WiFiScanClass::_scanResult)
|
||||
{
|
||||
delete[] reinterpret_cast<bss_info*>(ESP8266WiFiScanClass::_scanResult);
|
||||
ESP8266WiFiScanClass::_scanResult = 0;
|
||||
ESP8266WiFiScanClass::_scanCount = 0;
|
||||
}
|
||||
_scanComplete = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
loads all infos from a scanned wifi in to the ptr parameters
|
||||
@param networkItem uint8_t
|
||||
@param ssid const char*
|
||||
@param encryptionType uint8_t
|
||||
@param RSSI int32_t
|
||||
@param BSSID uint8_t *
|
||||
@param channel int32_t
|
||||
@param isHidden bool
|
||||
@return (true if ok)
|
||||
*/
|
||||
bool ESP8266WiFiScanClass::getNetworkInfo(uint8_t i, String &ssid, uint8_t &encType, int32_t &rssi, uint8_t* &bssid, int32_t &channel, bool &isHidden)
|
||||
{
|
||||
struct bss_info* it = reinterpret_cast<struct bss_info*>(_getScanInfoByIndex(i));
|
||||
if (!it)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
char ssid_copy[33]; // Ensure space for maximum len SSID (32) plus trailing 0
|
||||
memcpy(ssid_copy, it->ssid, sizeof(it->ssid));
|
||||
ssid_copy[32] = 0; // Potentially add 0-termination if none present earlier
|
||||
ssid = (const char*) ssid_copy;
|
||||
encType = encryptionType(i);
|
||||
rssi = it->rssi;
|
||||
bssid = it->bssid; // move ptr
|
||||
channel = it->channel;
|
||||
isHidden = (it->is_hidden != 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Return the SSID discovered during the network scan.
|
||||
@param i specify from which network item want to get the information
|
||||
@return ssid string of the specified item on the networks scanned list
|
||||
*/
|
||||
String ESP8266WiFiScanClass::SSID(uint8_t i)
|
||||
{
|
||||
struct bss_info* it = reinterpret_cast<struct bss_info*>(_getScanInfoByIndex(i));
|
||||
if (!it)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
char tmp[33]; //ssid can be up to 32chars, => plus null term
|
||||
memcpy(tmp, it->ssid, sizeof(it->ssid));
|
||||
tmp[32] = 0; //nullterm in case of 32 char ssid
|
||||
|
||||
return String(reinterpret_cast<const char*>(tmp));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Return the encryption type of the networks discovered during the scanNetworks
|
||||
@param i specify from which network item want to get the information
|
||||
@return encryption type (enum wl_enc_type) of the specified item on the networks scanned list
|
||||
*/
|
||||
uint8_t ESP8266WiFiScanClass::encryptionType(uint8_t i)
|
||||
{
|
||||
struct bss_info* it = reinterpret_cast<struct bss_info*>(_getScanInfoByIndex(i));
|
||||
if (!it)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (it->authmode)
|
||||
{
|
||||
case AUTH_OPEN:
|
||||
return ENC_TYPE_NONE;
|
||||
case AUTH_WEP:
|
||||
return ENC_TYPE_WEP;
|
||||
case AUTH_WPA_PSK:
|
||||
return ENC_TYPE_TKIP;
|
||||
case AUTH_WPA2_PSK:
|
||||
return ENC_TYPE_CCMP;
|
||||
case AUTH_WPA_WPA2_PSK:
|
||||
return ENC_TYPE_AUTO;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Return the RSSI of the networks discovered during the scanNetworks
|
||||
@param i specify from which network item want to get the information
|
||||
@return signed value of RSSI of the specified item on the networks scanned list
|
||||
*/
|
||||
int32_t ESP8266WiFiScanClass::RSSI(uint8_t i)
|
||||
{
|
||||
struct bss_info* it = reinterpret_cast<struct bss_info*>(_getScanInfoByIndex(i));
|
||||
if (!it)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return it->rssi;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
return MAC / BSSID of scanned wifi
|
||||
@param i specify from which network item want to get the information
|
||||
@return uint8_t * MAC / BSSID of scanned wifi
|
||||
*/
|
||||
uint8_t * ESP8266WiFiScanClass::BSSID(uint8_t i)
|
||||
{
|
||||
struct bss_info* it = reinterpret_cast<struct bss_info*>(_getScanInfoByIndex(i));
|
||||
if (!it)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return it->bssid;
|
||||
}
|
||||
|
||||
/**
|
||||
return MAC / BSSID of scanned wifi
|
||||
@param i specify from which network item want to get the information
|
||||
@return String MAC / BSSID of scanned wifi
|
||||
*/
|
||||
String ESP8266WiFiScanClass::BSSIDstr(uint8_t i)
|
||||
{
|
||||
char mac[18] = { 0 };
|
||||
struct bss_info* it = reinterpret_cast<struct bss_info*>(_getScanInfoByIndex(i));
|
||||
if (!it)
|
||||
{
|
||||
return String("");
|
||||
}
|
||||
sprintf(mac, "%02X:%02X:%02X:%02X:%02X:%02X", it->bssid[0], it->bssid[1], it->bssid[2], it->bssid[3], it->bssid[4], it->bssid[5]);
|
||||
return String(mac);
|
||||
}
|
||||
|
||||
int32_t ESP8266WiFiScanClass::channel(uint8_t i)
|
||||
{
|
||||
struct bss_info* it = reinterpret_cast<struct bss_info*>(_getScanInfoByIndex(i));
|
||||
if (!it)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return it->channel;
|
||||
}
|
||||
|
||||
/**
|
||||
return if the scanned wifi is Hidden (no SSID)
|
||||
@param networkItem specify from which network item want to get the information
|
||||
@return bool (true == hidden)
|
||||
*/
|
||||
bool ESP8266WiFiScanClass::isHidden(uint8_t i)
|
||||
{
|
||||
struct bss_info* it = reinterpret_cast<struct bss_info*>(_getScanInfoByIndex(i));
|
||||
if (!it)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (it->is_hidden != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
private
|
||||
scan callback
|
||||
@param result void *arg
|
||||
@param status STATUS
|
||||
*/
|
||||
void ESP8266WiFiScanClass::_scanDone(void* result, int status)
|
||||
{
|
||||
if (status != OK)
|
||||
{
|
||||
ESP8266WiFiScanClass::_scanCount = 0;
|
||||
ESP8266WiFiScanClass::_scanResult = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
int i = 0;
|
||||
bss_info* head = reinterpret_cast<bss_info*>(result);
|
||||
|
||||
for (bss_info* it = head; it; it = STAILQ_NEXT(it, next), ++i)
|
||||
;
|
||||
ESP8266WiFiScanClass::_scanCount = i;
|
||||
if (i == 0)
|
||||
{
|
||||
ESP8266WiFiScanClass::_scanResult = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
bss_info* copied_info = new bss_info[i];
|
||||
i = 0;
|
||||
for (bss_info* it = head; it; it = STAILQ_NEXT(it, next), ++i)
|
||||
{
|
||||
memcpy(copied_info + i, it, sizeof(bss_info));
|
||||
}
|
||||
|
||||
ESP8266WiFiScanClass::_scanResult = copied_info;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ESP8266WiFiScanClass::_scanStarted = false;
|
||||
ESP8266WiFiScanClass::_scanComplete = true;
|
||||
|
||||
if (!ESP8266WiFiScanClass::_scanAsync)
|
||||
{
|
||||
esp_schedule();
|
||||
}
|
||||
else if (ESP8266WiFiScanClass::_onComplete)
|
||||
{
|
||||
ESP8266WiFiScanClass::_onComplete(ESP8266WiFiScanClass::_scanCount);
|
||||
ESP8266WiFiScanClass::_onComplete = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@param i specify from which network item want to get the information
|
||||
@return bss_info
|
||||
*/
|
||||
void * ESP8266WiFiScanClass::_getScanInfoByIndex(int i)
|
||||
{
|
||||
if (!ESP8266WiFiScanClass::_scanResult || (size_t) i > ESP8266WiFiScanClass::_scanCount)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return reinterpret_cast<bss_info*>(ESP8266WiFiScanClass::_scanResult) + i;
|
||||
}
|
||||
|
@ -1,71 +1,72 @@
|
||||
/*
|
||||
ESP8266WiFiScan.h - esp8266 Wifi support.
|
||||
Based on WiFi.h from Ardiono WiFi shield library.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
Modified by Ivan Grokhotkov, December 2014
|
||||
Reworked by Markus Sattler, December 2015
|
||||
|
||||
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 ESP8266WIFISCAN_H_
|
||||
#define ESP8266WIFISCAN_H_
|
||||
|
||||
#include "ESP8266WiFiType.h"
|
||||
#include "ESP8266WiFiGeneric.h"
|
||||
|
||||
class ESP8266WiFiScanClass {
|
||||
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// ----------------------------------------- scan function --------------------------------------
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
||||
int8_t scanNetworks(bool async = false, bool show_hidden = false, uint8 channel = 0, uint8* ssid = NULL);
|
||||
void scanNetworksAsync(std::function<void(int)> onComplete, bool show_hidden = false);
|
||||
|
||||
int8_t scanComplete();
|
||||
void scanDelete();
|
||||
|
||||
// scan result
|
||||
bool getNetworkInfo(uint8_t networkItem, String &ssid, uint8_t &encryptionType, int32_t &RSSI, uint8_t* &BSSID, int32_t &channel, bool &isHidden);
|
||||
|
||||
String SSID(uint8_t networkItem);
|
||||
uint8_t encryptionType(uint8_t networkItem);
|
||||
int32_t RSSI(uint8_t networkItem);
|
||||
uint8_t * BSSID(uint8_t networkItem);
|
||||
String BSSIDstr(uint8_t networkItem);
|
||||
int32_t channel(uint8_t networkItem);
|
||||
bool isHidden(uint8_t networkItem);
|
||||
|
||||
protected:
|
||||
|
||||
static bool _scanAsync;
|
||||
static bool _scanStarted;
|
||||
static bool _scanComplete;
|
||||
|
||||
static size_t _scanCount;
|
||||
static void* _scanResult;
|
||||
|
||||
static std::function<void(int)> _onComplete;
|
||||
|
||||
static void _scanDone(void* result, int status);
|
||||
static void * _getScanInfoByIndex(int i);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* ESP8266WIFISCAN_H_ */
|
||||
/*
|
||||
ESP8266WiFiScan.h - esp8266 Wifi support.
|
||||
Based on WiFi.h from Ardiono WiFi shield library.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
Modified by Ivan Grokhotkov, December 2014
|
||||
Reworked by Markus Sattler, December 2015
|
||||
|
||||
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 ESP8266WIFISCAN_H_
|
||||
#define ESP8266WIFISCAN_H_
|
||||
|
||||
#include "ESP8266WiFiType.h"
|
||||
#include "ESP8266WiFiGeneric.h"
|
||||
|
||||
class ESP8266WiFiScanClass
|
||||
{
|
||||
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
// ----------------------------------------- scan function --------------------------------------
|
||||
// ----------------------------------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
|
||||
int8_t scanNetworks(bool async = false, bool show_hidden = false, uint8 channel = 0, uint8* ssid = NULL);
|
||||
void scanNetworksAsync(std::function<void(int)> onComplete, bool show_hidden = false);
|
||||
|
||||
int8_t scanComplete();
|
||||
void scanDelete();
|
||||
|
||||
// scan result
|
||||
bool getNetworkInfo(uint8_t networkItem, String &ssid, uint8_t &encryptionType, int32_t &RSSI, uint8_t* &BSSID, int32_t &channel, bool &isHidden);
|
||||
|
||||
String SSID(uint8_t networkItem);
|
||||
uint8_t encryptionType(uint8_t networkItem);
|
||||
int32_t RSSI(uint8_t networkItem);
|
||||
uint8_t * BSSID(uint8_t networkItem);
|
||||
String BSSIDstr(uint8_t networkItem);
|
||||
int32_t channel(uint8_t networkItem);
|
||||
bool isHidden(uint8_t networkItem);
|
||||
|
||||
protected:
|
||||
|
||||
static bool _scanAsync;
|
||||
static bool _scanStarted;
|
||||
static bool _scanComplete;
|
||||
|
||||
static size_t _scanCount;
|
||||
static void* _scanResult;
|
||||
|
||||
static std::function<void(int)> _onComplete;
|
||||
|
||||
static void _scanDone(void* result, int status);
|
||||
static void * _getScanInfoByIndex(int i);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* ESP8266WIFISCAN_H_ */
|
||||
|
@ -1,151 +1,151 @@
|
||||
/*
|
||||
ESP8266WiFiType.h - esp8266 Wifi support.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
Modified by Ivan Grokhotkov, December 2014
|
||||
Reworked by Markus Sattler, December 2015
|
||||
|
||||
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 ESP8266WIFITYPE_H_
|
||||
#define ESP8266WIFITYPE_H_
|
||||
|
||||
#include <queue.h>
|
||||
|
||||
#define WIFI_SCAN_RUNNING (-1)
|
||||
#define WIFI_SCAN_FAILED (-2)
|
||||
|
||||
// Note: these enums need to be in sync with the SDK!
|
||||
|
||||
// TODO: replace/deprecate/remove enum typedefs ending with _t below
|
||||
|
||||
typedef enum WiFiMode
|
||||
{
|
||||
WIFI_OFF = 0, WIFI_STA = 1, WIFI_AP = 2, WIFI_AP_STA = 3
|
||||
} WiFiMode_t;
|
||||
|
||||
typedef enum WiFiPhyMode
|
||||
{
|
||||
WIFI_PHY_MODE_11B = 1, WIFI_PHY_MODE_11G = 2, WIFI_PHY_MODE_11N = 3
|
||||
} WiFiPhyMode_t;
|
||||
|
||||
typedef enum WiFiSleepType
|
||||
{
|
||||
WIFI_NONE_SLEEP = 0, WIFI_LIGHT_SLEEP = 1, WIFI_MODEM_SLEEP = 2
|
||||
} WiFiSleepType_t;
|
||||
|
||||
|
||||
typedef enum WiFiEvent
|
||||
{
|
||||
WIFI_EVENT_STAMODE_CONNECTED = 0,
|
||||
WIFI_EVENT_STAMODE_DISCONNECTED,
|
||||
WIFI_EVENT_STAMODE_AUTHMODE_CHANGE,
|
||||
WIFI_EVENT_STAMODE_GOT_IP,
|
||||
WIFI_EVENT_STAMODE_DHCP_TIMEOUT,
|
||||
WIFI_EVENT_SOFTAPMODE_STACONNECTED,
|
||||
WIFI_EVENT_SOFTAPMODE_STADISCONNECTED,
|
||||
WIFI_EVENT_SOFTAPMODE_PROBEREQRECVED,
|
||||
WIFI_EVENT_MAX,
|
||||
WIFI_EVENT_ANY = WIFI_EVENT_MAX,
|
||||
WIFI_EVENT_MODE_CHANGE
|
||||
} WiFiEvent_t;
|
||||
|
||||
enum WiFiDisconnectReason
|
||||
{
|
||||
WIFI_DISCONNECT_REASON_UNSPECIFIED = 1,
|
||||
WIFI_DISCONNECT_REASON_AUTH_EXPIRE = 2,
|
||||
WIFI_DISCONNECT_REASON_AUTH_LEAVE = 3,
|
||||
WIFI_DISCONNECT_REASON_ASSOC_EXPIRE = 4,
|
||||
WIFI_DISCONNECT_REASON_ASSOC_TOOMANY = 5,
|
||||
WIFI_DISCONNECT_REASON_NOT_AUTHED = 6,
|
||||
WIFI_DISCONNECT_REASON_NOT_ASSOCED = 7,
|
||||
WIFI_DISCONNECT_REASON_ASSOC_LEAVE = 8,
|
||||
WIFI_DISCONNECT_REASON_ASSOC_NOT_AUTHED = 9,
|
||||
WIFI_DISCONNECT_REASON_DISASSOC_PWRCAP_BAD = 10, /* 11h */
|
||||
WIFI_DISCONNECT_REASON_DISASSOC_SUPCHAN_BAD = 11, /* 11h */
|
||||
WIFI_DISCONNECT_REASON_IE_INVALID = 13, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_MIC_FAILURE = 14, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_4WAY_HANDSHAKE_TIMEOUT = 15, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_GROUP_KEY_UPDATE_TIMEOUT = 16, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_IE_IN_4WAY_DIFFERS = 17, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_GROUP_CIPHER_INVALID = 18, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_PAIRWISE_CIPHER_INVALID = 19, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_AKMP_INVALID = 20, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_UNSUPP_RSN_IE_VERSION = 21, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_INVALID_RSN_IE_CAP = 22, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_802_1X_AUTH_FAILED = 23, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_CIPHER_SUITE_REJECTED = 24, /* 11i */
|
||||
|
||||
WIFI_DISCONNECT_REASON_BEACON_TIMEOUT = 200,
|
||||
WIFI_DISCONNECT_REASON_NO_AP_FOUND = 201,
|
||||
WIFI_DISCONNECT_REASON_AUTH_FAIL = 202,
|
||||
WIFI_DISCONNECT_REASON_ASSOC_FAIL = 203,
|
||||
WIFI_DISCONNECT_REASON_HANDSHAKE_TIMEOUT = 204,
|
||||
};
|
||||
|
||||
struct WiFiEventModeChange
|
||||
{
|
||||
WiFiMode oldMode;
|
||||
WiFiMode newMode;
|
||||
};
|
||||
|
||||
struct WiFiEventStationModeConnected
|
||||
{
|
||||
String ssid;
|
||||
uint8 bssid[6];
|
||||
uint8 channel;
|
||||
};
|
||||
|
||||
struct WiFiEventStationModeDisconnected
|
||||
{
|
||||
String ssid;
|
||||
uint8 bssid[6];
|
||||
WiFiDisconnectReason reason;
|
||||
};
|
||||
|
||||
struct WiFiEventStationModeAuthModeChanged
|
||||
{
|
||||
uint8 oldMode;
|
||||
uint8 newMode;
|
||||
};
|
||||
|
||||
struct WiFiEventStationModeGotIP
|
||||
{
|
||||
IPAddress ip;
|
||||
IPAddress mask;
|
||||
IPAddress gw;
|
||||
};
|
||||
|
||||
struct WiFiEventSoftAPModeStationConnected
|
||||
{
|
||||
uint8 mac[6];
|
||||
uint8 aid;
|
||||
};
|
||||
|
||||
struct WiFiEventSoftAPModeStationDisconnected
|
||||
{
|
||||
uint8 mac[6];
|
||||
uint8 aid;
|
||||
};
|
||||
|
||||
struct WiFiEventSoftAPModeProbeRequestReceived
|
||||
{
|
||||
int rssi;
|
||||
uint8 mac[6];
|
||||
};
|
||||
|
||||
|
||||
#endif /* ESP8266WIFITYPE_H_ */
|
||||
/*
|
||||
ESP8266WiFiType.h - esp8266 Wifi support.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
Modified by Ivan Grokhotkov, December 2014
|
||||
Reworked by Markus Sattler, December 2015
|
||||
|
||||
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 ESP8266WIFITYPE_H_
|
||||
#define ESP8266WIFITYPE_H_
|
||||
|
||||
#include <queue.h>
|
||||
|
||||
#define WIFI_SCAN_RUNNING (-1)
|
||||
#define WIFI_SCAN_FAILED (-2)
|
||||
|
||||
// Note: these enums need to be in sync with the SDK!
|
||||
|
||||
// TODO: replace/deprecate/remove enum typedefs ending with _t below
|
||||
|
||||
typedef enum WiFiMode
|
||||
{
|
||||
WIFI_OFF = 0, WIFI_STA = 1, WIFI_AP = 2, WIFI_AP_STA = 3
|
||||
} WiFiMode_t;
|
||||
|
||||
typedef enum WiFiPhyMode
|
||||
{
|
||||
WIFI_PHY_MODE_11B = 1, WIFI_PHY_MODE_11G = 2, WIFI_PHY_MODE_11N = 3
|
||||
} WiFiPhyMode_t;
|
||||
|
||||
typedef enum WiFiSleepType
|
||||
{
|
||||
WIFI_NONE_SLEEP = 0, WIFI_LIGHT_SLEEP = 1, WIFI_MODEM_SLEEP = 2
|
||||
} WiFiSleepType_t;
|
||||
|
||||
|
||||
typedef enum WiFiEvent
|
||||
{
|
||||
WIFI_EVENT_STAMODE_CONNECTED = 0,
|
||||
WIFI_EVENT_STAMODE_DISCONNECTED,
|
||||
WIFI_EVENT_STAMODE_AUTHMODE_CHANGE,
|
||||
WIFI_EVENT_STAMODE_GOT_IP,
|
||||
WIFI_EVENT_STAMODE_DHCP_TIMEOUT,
|
||||
WIFI_EVENT_SOFTAPMODE_STACONNECTED,
|
||||
WIFI_EVENT_SOFTAPMODE_STADISCONNECTED,
|
||||
WIFI_EVENT_SOFTAPMODE_PROBEREQRECVED,
|
||||
WIFI_EVENT_MAX,
|
||||
WIFI_EVENT_ANY = WIFI_EVENT_MAX,
|
||||
WIFI_EVENT_MODE_CHANGE
|
||||
} WiFiEvent_t;
|
||||
|
||||
enum WiFiDisconnectReason
|
||||
{
|
||||
WIFI_DISCONNECT_REASON_UNSPECIFIED = 1,
|
||||
WIFI_DISCONNECT_REASON_AUTH_EXPIRE = 2,
|
||||
WIFI_DISCONNECT_REASON_AUTH_LEAVE = 3,
|
||||
WIFI_DISCONNECT_REASON_ASSOC_EXPIRE = 4,
|
||||
WIFI_DISCONNECT_REASON_ASSOC_TOOMANY = 5,
|
||||
WIFI_DISCONNECT_REASON_NOT_AUTHED = 6,
|
||||
WIFI_DISCONNECT_REASON_NOT_ASSOCED = 7,
|
||||
WIFI_DISCONNECT_REASON_ASSOC_LEAVE = 8,
|
||||
WIFI_DISCONNECT_REASON_ASSOC_NOT_AUTHED = 9,
|
||||
WIFI_DISCONNECT_REASON_DISASSOC_PWRCAP_BAD = 10, /* 11h */
|
||||
WIFI_DISCONNECT_REASON_DISASSOC_SUPCHAN_BAD = 11, /* 11h */
|
||||
WIFI_DISCONNECT_REASON_IE_INVALID = 13, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_MIC_FAILURE = 14, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_4WAY_HANDSHAKE_TIMEOUT = 15, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_GROUP_KEY_UPDATE_TIMEOUT = 16, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_IE_IN_4WAY_DIFFERS = 17, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_GROUP_CIPHER_INVALID = 18, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_PAIRWISE_CIPHER_INVALID = 19, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_AKMP_INVALID = 20, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_UNSUPP_RSN_IE_VERSION = 21, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_INVALID_RSN_IE_CAP = 22, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_802_1X_AUTH_FAILED = 23, /* 11i */
|
||||
WIFI_DISCONNECT_REASON_CIPHER_SUITE_REJECTED = 24, /* 11i */
|
||||
|
||||
WIFI_DISCONNECT_REASON_BEACON_TIMEOUT = 200,
|
||||
WIFI_DISCONNECT_REASON_NO_AP_FOUND = 201,
|
||||
WIFI_DISCONNECT_REASON_AUTH_FAIL = 202,
|
||||
WIFI_DISCONNECT_REASON_ASSOC_FAIL = 203,
|
||||
WIFI_DISCONNECT_REASON_HANDSHAKE_TIMEOUT = 204,
|
||||
};
|
||||
|
||||
struct WiFiEventModeChange
|
||||
{
|
||||
WiFiMode oldMode;
|
||||
WiFiMode newMode;
|
||||
};
|
||||
|
||||
struct WiFiEventStationModeConnected
|
||||
{
|
||||
String ssid;
|
||||
uint8 bssid[6];
|
||||
uint8 channel;
|
||||
};
|
||||
|
||||
struct WiFiEventStationModeDisconnected
|
||||
{
|
||||
String ssid;
|
||||
uint8 bssid[6];
|
||||
WiFiDisconnectReason reason;
|
||||
};
|
||||
|
||||
struct WiFiEventStationModeAuthModeChanged
|
||||
{
|
||||
uint8 oldMode;
|
||||
uint8 newMode;
|
||||
};
|
||||
|
||||
struct WiFiEventStationModeGotIP
|
||||
{
|
||||
IPAddress ip;
|
||||
IPAddress mask;
|
||||
IPAddress gw;
|
||||
};
|
||||
|
||||
struct WiFiEventSoftAPModeStationConnected
|
||||
{
|
||||
uint8 mac[6];
|
||||
uint8 aid;
|
||||
};
|
||||
|
||||
struct WiFiEventSoftAPModeStationDisconnected
|
||||
{
|
||||
uint8 mac[6];
|
||||
uint8 aid;
|
||||
};
|
||||
|
||||
struct WiFiEventSoftAPModeProbeRequestReceived
|
||||
{
|
||||
int rssi;
|
||||
uint8 mac[6];
|
||||
};
|
||||
|
||||
|
||||
#endif /* ESP8266WIFITYPE_H_ */
|
||||
|
@ -1,32 +1,32 @@
|
||||
/*
|
||||
WiFiClient.cpp - TCP/IP client for esp8266, mostly compatible
|
||||
WiFiClient.cpp - TCP/IP client for esp8266, mostly compatible
|
||||
with Arduino WiFi shield library
|
||||
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This library is 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.
|
||||
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
|
||||
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
|
||||
*/
|
||||
|
||||
#define LWIP_INTERNAL
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "include/wl_definitions.h"
|
||||
#include "osapi.h"
|
||||
#include "ets_sys.h"
|
||||
#include "include/wl_definitions.h"
|
||||
#include "osapi.h"
|
||||
#include "ets_sys.h"
|
||||
}
|
||||
|
||||
#include "debug.h"
|
||||
@ -46,27 +46,27 @@ uint16_t WiFiClient::_localPort = 0;
|
||||
static bool defaultNoDelay = false; // false == Nagle enabled by default
|
||||
static bool defaultSync = false;
|
||||
|
||||
bool getDefaultPrivateGlobalSyncValue ()
|
||||
bool getDefaultPrivateGlobalSyncValue()
|
||||
{
|
||||
return defaultSync;
|
||||
}
|
||||
|
||||
void WiFiClient::setDefaultNoDelay (bool noDelay)
|
||||
void WiFiClient::setDefaultNoDelay(bool noDelay)
|
||||
{
|
||||
defaultNoDelay = noDelay;
|
||||
}
|
||||
|
||||
void WiFiClient::setDefaultSync (bool sync)
|
||||
void WiFiClient::setDefaultSync(bool sync)
|
||||
{
|
||||
defaultSync = sync;
|
||||
}
|
||||
|
||||
bool WiFiClient::getDefaultNoDelay ()
|
||||
bool WiFiClient::getDefaultNoDelay()
|
||||
{
|
||||
return defaultNoDelay;
|
||||
}
|
||||
|
||||
bool WiFiClient::getDefaultSync ()
|
||||
bool WiFiClient::getDefaultSync()
|
||||
{
|
||||
return defaultSync;
|
||||
}
|
||||
@ -76,14 +76,14 @@ WiFiClient* SList<WiFiClient>::_s_first = 0;
|
||||
|
||||
|
||||
WiFiClient::WiFiClient()
|
||||
: _client(0)
|
||||
: _client(0)
|
||||
{
|
||||
_timeout = 5000;
|
||||
WiFiClient::_add(this);
|
||||
}
|
||||
|
||||
WiFiClient::WiFiClient(ClientContext* client)
|
||||
: _client(client)
|
||||
: _client(client)
|
||||
{
|
||||
_timeout = 5000;
|
||||
_client->ref();
|
||||
@ -97,7 +97,9 @@ WiFiClient::~WiFiClient()
|
||||
{
|
||||
WiFiClient::_remove(this);
|
||||
if (_client)
|
||||
{
|
||||
_client->unref();
|
||||
}
|
||||
}
|
||||
|
||||
WiFiClient::WiFiClient(const WiFiClient& other)
|
||||
@ -106,19 +108,25 @@ WiFiClient::WiFiClient(const WiFiClient& other)
|
||||
_timeout = other._timeout;
|
||||
_localPort = other._localPort;
|
||||
if (_client)
|
||||
{
|
||||
_client->ref();
|
||||
}
|
||||
WiFiClient::_add(this);
|
||||
}
|
||||
|
||||
WiFiClient& WiFiClient::operator=(const WiFiClient& other)
|
||||
{
|
||||
if (_client)
|
||||
if (_client)
|
||||
{
|
||||
_client->unref();
|
||||
}
|
||||
_client = other._client;
|
||||
_timeout = other._timeout;
|
||||
_localPort = other._localPort;
|
||||
if (_client)
|
||||
{
|
||||
_client->ref();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -139,7 +147,8 @@ int WiFiClient::connect(const String& host, uint16_t port)
|
||||
|
||||
int WiFiClient::connect(IPAddress ip, uint16_t port)
|
||||
{
|
||||
if (_client) {
|
||||
if (_client)
|
||||
{
|
||||
stop();
|
||||
_client->unref();
|
||||
_client = nullptr;
|
||||
@ -150,7 +159,8 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
|
||||
// ever calling tcp_err
|
||||
// http://lists.gnu.org/archive/html/lwip-devel/2010-05/msg00001.html
|
||||
netif* interface = ip_route(ip);
|
||||
if (!interface) {
|
||||
if (!interface)
|
||||
{
|
||||
DEBUGV("no route to host\r\n");
|
||||
return 0;
|
||||
}
|
||||
@ -158,9 +168,12 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
|
||||
|
||||
tcp_pcb* pcb = tcp_new();
|
||||
if (!pcb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_localPort > 0) {
|
||||
if (_localPort > 0)
|
||||
{
|
||||
pcb->local_port = _localPort++;
|
||||
}
|
||||
|
||||
@ -168,7 +181,8 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
|
||||
_client->ref();
|
||||
_client->setTimeout(_timeout);
|
||||
int res = _client->connect(ip, port);
|
||||
if (res == 0) {
|
||||
if (res == 0)
|
||||
{
|
||||
_client->unref();
|
||||
_client = nullptr;
|
||||
return 0;
|
||||
@ -180,35 +194,45 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void WiFiClient::setNoDelay(bool nodelay) {
|
||||
void WiFiClient::setNoDelay(bool nodelay)
|
||||
{
|
||||
if (!_client)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_client->setNoDelay(nodelay);
|
||||
}
|
||||
|
||||
bool WiFiClient::getNoDelay() const {
|
||||
bool WiFiClient::getNoDelay() const
|
||||
{
|
||||
if (!_client)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return _client->getNoDelay();
|
||||
}
|
||||
|
||||
void WiFiClient::setSync(bool sync)
|
||||
{
|
||||
if (!_client)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_client->setSync(sync);
|
||||
}
|
||||
|
||||
bool WiFiClient::getSync() const
|
||||
{
|
||||
if (!_client)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return _client->getSync();
|
||||
}
|
||||
|
||||
size_t WiFiClient::availableForWrite ()
|
||||
size_t WiFiClient::availableForWrite()
|
||||
{
|
||||
return _client? _client->availableForWrite(): 0;
|
||||
return _client ? _client->availableForWrite() : 0;
|
||||
}
|
||||
|
||||
size_t WiFiClient::write(uint8_t b)
|
||||
@ -255,11 +279,14 @@ size_t WiFiClient::write_P(PGM_P buf, size_t size)
|
||||
int WiFiClient::available()
|
||||
{
|
||||
if (!_client)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int result = _client->getSize();
|
||||
|
||||
if (!result) {
|
||||
if (!result)
|
||||
{
|
||||
optimistic_yield(100);
|
||||
}
|
||||
return result;
|
||||
@ -268,7 +295,9 @@ int WiFiClient::available()
|
||||
int WiFiClient::read()
|
||||
{
|
||||
if (!available())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _client->read();
|
||||
}
|
||||
@ -282,26 +311,34 @@ int WiFiClient::read(uint8_t* buf, size_t size)
|
||||
int WiFiClient::peek()
|
||||
{
|
||||
if (!available())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _client->peek();
|
||||
}
|
||||
|
||||
size_t WiFiClient::peekBytes(uint8_t *buffer, size_t length) {
|
||||
size_t WiFiClient::peekBytes(uint8_t *buffer, size_t length)
|
||||
{
|
||||
size_t count = 0;
|
||||
|
||||
if(!_client) {
|
||||
if (!_client)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
_startMillis = millis();
|
||||
while((available() < (int) length) && ((millis() - _startMillis) < _timeout)) {
|
||||
while ((available() < (int) length) && ((millis() - _startMillis) < _timeout))
|
||||
{
|
||||
yield();
|
||||
}
|
||||
|
||||
if(available() < (int) length) {
|
||||
if (available() < (int) length)
|
||||
{
|
||||
count = available();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
count = length;
|
||||
}
|
||||
|
||||
@ -311,28 +348,38 @@ size_t WiFiClient::peekBytes(uint8_t *buffer, size_t length) {
|
||||
bool WiFiClient::flush(unsigned int maxWaitMs)
|
||||
{
|
||||
if (!_client)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (maxWaitMs == 0)
|
||||
{
|
||||
maxWaitMs = WIFICLIENT_MAX_FLUSH_WAIT_MS;
|
||||
}
|
||||
return _client->wait_until_sent(maxWaitMs);
|
||||
}
|
||||
|
||||
bool WiFiClient::stop(unsigned int maxWaitMs)
|
||||
{
|
||||
if (!_client)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ret = flush(maxWaitMs); // virtual, may be ssl's
|
||||
if (_client->close() != ERR_OK)
|
||||
{
|
||||
ret = false;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t WiFiClient::connected()
|
||||
{
|
||||
if (!_client || _client->state() == CLOSED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _client->state() == ESTABLISHED || available();
|
||||
}
|
||||
@ -340,7 +387,9 @@ uint8_t WiFiClient::connected()
|
||||
uint8_t WiFiClient::status()
|
||||
{
|
||||
if (!_client)
|
||||
{
|
||||
return CLOSED;
|
||||
}
|
||||
return _client->state();
|
||||
}
|
||||
|
||||
@ -352,7 +401,9 @@ WiFiClient::operator bool()
|
||||
IPAddress WiFiClient::remoteIP()
|
||||
{
|
||||
if (!_client || !_client->getRemoteAddress())
|
||||
{
|
||||
return IPAddress(0U);
|
||||
}
|
||||
|
||||
return _client->getRemoteAddress();
|
||||
}
|
||||
@ -360,7 +411,9 @@ IPAddress WiFiClient::remoteIP()
|
||||
uint16_t WiFiClient::remotePort()
|
||||
{
|
||||
if (!_client)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _client->getRemotePort();
|
||||
}
|
||||
@ -368,7 +421,9 @@ uint16_t WiFiClient::remotePort()
|
||||
IPAddress WiFiClient::localIP()
|
||||
{
|
||||
if (!_client)
|
||||
{
|
||||
return IPAddress(0U);
|
||||
}
|
||||
|
||||
return IPAddress(_client->getLocalAddress());
|
||||
}
|
||||
@ -376,50 +431,55 @@ IPAddress WiFiClient::localIP()
|
||||
uint16_t WiFiClient::localPort()
|
||||
{
|
||||
if (!_client)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _client->getLocalPort();
|
||||
}
|
||||
|
||||
void WiFiClient::stopAll()
|
||||
{
|
||||
for (WiFiClient* it = _s_first; it; it = it->_next) {
|
||||
for (WiFiClient* it = _s_first; it; it = it->_next)
|
||||
{
|
||||
it->stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WiFiClient::stopAllExcept(WiFiClient* except)
|
||||
void WiFiClient::stopAllExcept(WiFiClient* except)
|
||||
{
|
||||
for (WiFiClient* it = _s_first; it; it = it->_next) {
|
||||
if (it != except) {
|
||||
for (WiFiClient* it = _s_first; it; it = it->_next)
|
||||
{
|
||||
if (it != except)
|
||||
{
|
||||
it->stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WiFiClient::keepAlive (uint16_t idle_sec, uint16_t intv_sec, uint8_t count)
|
||||
void WiFiClient::keepAlive(uint16_t idle_sec, uint16_t intv_sec, uint8_t count)
|
||||
{
|
||||
_client->keepAlive(idle_sec, intv_sec, count);
|
||||
}
|
||||
|
||||
bool WiFiClient::isKeepAliveEnabled () const
|
||||
bool WiFiClient::isKeepAliveEnabled() const
|
||||
{
|
||||
return _client->isKeepAliveEnabled();
|
||||
}
|
||||
|
||||
uint16_t WiFiClient::getKeepAliveIdle () const
|
||||
uint16_t WiFiClient::getKeepAliveIdle() const
|
||||
{
|
||||
return _client->getKeepAliveIdle();
|
||||
}
|
||||
|
||||
uint16_t WiFiClient::getKeepAliveInterval () const
|
||||
uint16_t WiFiClient::getKeepAliveInterval() const
|
||||
{
|
||||
return _client->getKeepAliveInterval();
|
||||
}
|
||||
|
||||
uint8_t WiFiClient::getKeepAliveCount () const
|
||||
uint8_t WiFiClient::getKeepAliveCount() const
|
||||
{
|
||||
return _client->getKeepAliveCount();
|
||||
}
|
||||
|
@ -1,22 +1,22 @@
|
||||
/*
|
||||
WiFiClient.h - Library for Arduino Wifi shield.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
WiFiClient.h - Library for Arduino Wifi shield.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
|
||||
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 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.
|
||||
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
|
||||
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
|
||||
|
||||
Modified by Ivan Grokhotkov, December 2014 - esp8266 support
|
||||
Modified by Ivan Grokhotkov, December 2014 - esp8266 support
|
||||
*/
|
||||
|
||||
#ifndef wificlient_h
|
||||
@ -42,94 +42,108 @@
|
||||
class ClientContext;
|
||||
class WiFiServer;
|
||||
|
||||
class WiFiClient : public Client, public SList<WiFiClient> {
|
||||
class WiFiClient : public Client, public SList<WiFiClient>
|
||||
{
|
||||
protected:
|
||||
WiFiClient(ClientContext* client);
|
||||
WiFiClient(ClientContext* client);
|
||||
|
||||
public:
|
||||
WiFiClient();
|
||||
virtual ~WiFiClient();
|
||||
WiFiClient(const WiFiClient&);
|
||||
WiFiClient& operator=(const WiFiClient&);
|
||||
WiFiClient();
|
||||
virtual ~WiFiClient();
|
||||
WiFiClient(const WiFiClient&);
|
||||
WiFiClient& operator=(const WiFiClient&);
|
||||
|
||||
uint8_t status();
|
||||
virtual int connect(IPAddress ip, uint16_t port) override;
|
||||
virtual int connect(const char *host, uint16_t port) override;
|
||||
virtual int connect(const String& host, uint16_t port);
|
||||
virtual size_t write(uint8_t) override;
|
||||
virtual size_t write(const uint8_t *buf, size_t size) override;
|
||||
virtual size_t write_P(PGM_P buf, size_t size);
|
||||
size_t write(Stream& stream);
|
||||
uint8_t status();
|
||||
virtual int connect(IPAddress ip, uint16_t port) override;
|
||||
virtual int connect(const char *host, uint16_t port) override;
|
||||
virtual int connect(const String& host, uint16_t port);
|
||||
virtual size_t write(uint8_t) override;
|
||||
virtual size_t write(const uint8_t *buf, size_t size) override;
|
||||
virtual size_t write_P(PGM_P buf, size_t size);
|
||||
size_t write(Stream& stream);
|
||||
|
||||
// This one is deprecated, use write(Stream& instead)
|
||||
size_t write(Stream& stream, size_t unitSize) __attribute__ ((deprecated));
|
||||
// This one is deprecated, use write(Stream& instead)
|
||||
size_t write(Stream& stream, size_t unitSize) __attribute__((deprecated));
|
||||
|
||||
virtual int available() override;
|
||||
virtual int read() override;
|
||||
virtual int read(uint8_t *buf, size_t size) override;
|
||||
virtual int peek() override;
|
||||
virtual size_t peekBytes(uint8_t *buffer, size_t length);
|
||||
size_t peekBytes(char *buffer, size_t length) {
|
||||
return peekBytes((uint8_t *) buffer, length);
|
||||
}
|
||||
virtual void flush() override { (void)flush(0); }
|
||||
virtual void stop() override { (void)stop(0); }
|
||||
bool flush(unsigned int maxWaitMs);
|
||||
bool stop(unsigned int maxWaitMs);
|
||||
virtual uint8_t connected() override;
|
||||
virtual operator bool() override;
|
||||
virtual int available() override;
|
||||
virtual int read() override;
|
||||
virtual int read(uint8_t *buf, size_t size) override;
|
||||
virtual int peek() override;
|
||||
virtual size_t peekBytes(uint8_t *buffer, size_t length);
|
||||
size_t peekBytes(char *buffer, size_t length)
|
||||
{
|
||||
return peekBytes((uint8_t *) buffer, length);
|
||||
}
|
||||
virtual void flush() override
|
||||
{
|
||||
(void)flush(0);
|
||||
}
|
||||
virtual void stop() override
|
||||
{
|
||||
(void)stop(0);
|
||||
}
|
||||
bool flush(unsigned int maxWaitMs);
|
||||
bool stop(unsigned int maxWaitMs);
|
||||
virtual uint8_t connected() override;
|
||||
virtual operator bool() override;
|
||||
|
||||
IPAddress remoteIP();
|
||||
uint16_t remotePort();
|
||||
IPAddress localIP();
|
||||
uint16_t localPort();
|
||||
IPAddress remoteIP();
|
||||
uint16_t remotePort();
|
||||
IPAddress localIP();
|
||||
uint16_t localPort();
|
||||
|
||||
static void setLocalPortStart(uint16_t port) { _localPort = port; }
|
||||
static void setLocalPortStart(uint16_t port)
|
||||
{
|
||||
_localPort = port;
|
||||
}
|
||||
|
||||
size_t availableForWrite();
|
||||
size_t availableForWrite();
|
||||
|
||||
friend class WiFiServer;
|
||||
friend class WiFiServer;
|
||||
|
||||
using Print::write;
|
||||
using Print::write;
|
||||
|
||||
static void stopAll();
|
||||
static void stopAllExcept(WiFiClient * c);
|
||||
static void stopAll();
|
||||
static void stopAllExcept(WiFiClient * c);
|
||||
|
||||
void keepAlive (uint16_t idle_sec = TCP_DEFAULT_KEEPALIVE_IDLE_SEC, uint16_t intv_sec = TCP_DEFAULT_KEEPALIVE_INTERVAL_SEC, uint8_t count = TCP_DEFAULT_KEEPALIVE_COUNT);
|
||||
bool isKeepAliveEnabled () const;
|
||||
uint16_t getKeepAliveIdle () const;
|
||||
uint16_t getKeepAliveInterval () const;
|
||||
uint8_t getKeepAliveCount () const;
|
||||
void disableKeepAlive () { keepAlive(0, 0, 0); }
|
||||
void keepAlive(uint16_t idle_sec = TCP_DEFAULT_KEEPALIVE_IDLE_SEC, uint16_t intv_sec = TCP_DEFAULT_KEEPALIVE_INTERVAL_SEC, uint8_t count = TCP_DEFAULT_KEEPALIVE_COUNT);
|
||||
bool isKeepAliveEnabled() const;
|
||||
uint16_t getKeepAliveIdle() const;
|
||||
uint16_t getKeepAliveInterval() const;
|
||||
uint8_t getKeepAliveCount() const;
|
||||
void disableKeepAlive()
|
||||
{
|
||||
keepAlive(0, 0, 0);
|
||||
}
|
||||
|
||||
// default NoDelay=False (Nagle=True=!NoDelay)
|
||||
// Nagle is for shortly delaying outgoing data, to send less/bigger packets
|
||||
// Nagle should be disabled for telnet-like/interactive streams
|
||||
// Nagle is meaningless/ignored when Sync=true
|
||||
static void setDefaultNoDelay (bool noDelay);
|
||||
static bool getDefaultNoDelay ();
|
||||
bool getNoDelay() const;
|
||||
void setNoDelay(bool nodelay);
|
||||
// default NoDelay=False (Nagle=True=!NoDelay)
|
||||
// Nagle is for shortly delaying outgoing data, to send less/bigger packets
|
||||
// Nagle should be disabled for telnet-like/interactive streams
|
||||
// Nagle is meaningless/ignored when Sync=true
|
||||
static void setDefaultNoDelay(bool noDelay);
|
||||
static bool getDefaultNoDelay();
|
||||
bool getNoDelay() const;
|
||||
void setNoDelay(bool nodelay);
|
||||
|
||||
// default Sync=false
|
||||
// When sync is true, all writes are automatically flushed.
|
||||
// This is slower but also does not allocate
|
||||
// temporary memory for sending data
|
||||
static void setDefaultSync (bool sync);
|
||||
static bool getDefaultSync ();
|
||||
bool getSync() const;
|
||||
void setSync(bool sync);
|
||||
// default Sync=false
|
||||
// When sync is true, all writes are automatically flushed.
|
||||
// This is slower but also does not allocate
|
||||
// temporary memory for sending data
|
||||
static void setDefaultSync(bool sync);
|
||||
static bool getDefaultSync();
|
||||
bool getSync() const;
|
||||
void setSync(bool sync);
|
||||
|
||||
protected:
|
||||
|
||||
static int8_t _s_connected(void* arg, void* tpcb, int8_t err);
|
||||
static void _s_err(void* arg, int8_t err);
|
||||
static int8_t _s_connected(void* arg, void* tpcb, int8_t err);
|
||||
static void _s_err(void* arg, int8_t err);
|
||||
|
||||
int8_t _connected(void* tpcb, int8_t err);
|
||||
void _err(int8_t err);
|
||||
int8_t _connected(void* tpcb, int8_t err);
|
||||
void _err(int8_t err);
|
||||
|
||||
ClientContext* _client;
|
||||
static uint16_t _localPort;
|
||||
ClientContext* _client;
|
||||
static uint16_t _localPort;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,22 +1,22 @@
|
||||
/*
|
||||
WiFiClientSecure.h - Variant of WiFiClient with TLS support
|
||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
WiFiClientSecure.h - Variant of WiFiClient with TLS support
|
||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This library is 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.
|
||||
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
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
@ -24,18 +24,18 @@
|
||||
//using namespace axTLS;
|
||||
|
||||
/**********************************
|
||||
* !! Now BearSSL is the default !!
|
||||
*
|
||||
* While not advised,
|
||||
* Use legacy API without updating with:
|
||||
*
|
||||
#define USING_AXTLS
|
||||
#include <ESP8266WiFi.h>
|
||||
//#include <WiFiClientSecure.h>
|
||||
#include "WiFiClientSecureAxTLS.h"
|
||||
using namespace axTLS;
|
||||
*
|
||||
*
|
||||
!! Now BearSSL is the default !!
|
||||
|
||||
While not advised,
|
||||
Use legacy API without updating with:
|
||||
|
||||
#define USING_AXTLS
|
||||
#include <ESP8266WiFi.h>
|
||||
//#include <WiFiClientSecure.h>
|
||||
#include "WiFiClientSecureAxTLS.h"
|
||||
using namespace axTLS;
|
||||
|
||||
|
||||
**********************************/
|
||||
|
||||
#include "WiFiClientSecureBearSSL.h"
|
||||
|
@ -1,22 +1,22 @@
|
||||
/*
|
||||
WiFiClientSecure.cpp - Variant of WiFiClient with TLS support
|
||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
WiFiClientSecure.cpp - Variant of WiFiClient with TLS support
|
||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This library is 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.
|
||||
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
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
@ -42,7 +42,8 @@
|
||||
#include "include/SSLContext.h"
|
||||
#include "include/ClientContext.h"
|
||||
|
||||
namespace axTLS {
|
||||
namespace axTLS
|
||||
{
|
||||
|
||||
SSL_CTX* SSLContext::_ssl_client_ctx = nullptr;
|
||||
int SSLContext::_ssl_client_ctx_refcnt = 0;
|
||||
@ -57,7 +58,7 @@ WiFiClientSecure::WiFiClientSecure()
|
||||
|
||||
WiFiClientSecure::~WiFiClientSecure()
|
||||
{
|
||||
_ssl = nullptr;
|
||||
_ssl = nullptr;
|
||||
}
|
||||
|
||||
// Only called by the WifiServerSecure, need to get the keys/certs loaded before beginning
|
||||
@ -77,18 +78,25 @@ WiFiClientSecure::WiFiClientSecure(ClientContext* client, bool usePMEM,
|
||||
std::shared_ptr<SSLContext> _new_ssl_shared(_new_ssl);
|
||||
_ssl = _new_ssl_shared;
|
||||
|
||||
if (usePMEM) {
|
||||
if (rsakey && rsakeyLen) {
|
||||
if (usePMEM)
|
||||
{
|
||||
if (rsakey && rsakeyLen)
|
||||
{
|
||||
_ssl->loadObject_P(SSL_OBJ_RSA_KEY, rsakey, rsakeyLen);
|
||||
}
|
||||
if (cert && certLen) {
|
||||
if (cert && certLen)
|
||||
{
|
||||
_ssl->loadObject_P(SSL_OBJ_X509_CERT, cert, certLen);
|
||||
}
|
||||
} else {
|
||||
if (rsakey && rsakeyLen) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rsakey && rsakeyLen)
|
||||
{
|
||||
_ssl->loadObject(SSL_OBJ_RSA_KEY, rsakey, rsakeyLen);
|
||||
}
|
||||
if (cert && certLen) {
|
||||
if (cert && certLen)
|
||||
{
|
||||
_ssl->loadObject(SSL_OBJ_X509_CERT, cert, certLen);
|
||||
}
|
||||
}
|
||||
@ -97,7 +105,8 @@ WiFiClientSecure::WiFiClientSecure(ClientContext* client, bool usePMEM,
|
||||
|
||||
int WiFiClientSecure::connect(IPAddress ip, uint16_t port)
|
||||
{
|
||||
if (!WiFiClient::connect(ip, port)) {
|
||||
if (!WiFiClient::connect(ip, port))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -107,10 +116,12 @@ int WiFiClientSecure::connect(IPAddress ip, uint16_t port)
|
||||
int WiFiClientSecure::connect(const char* name, uint16_t port)
|
||||
{
|
||||
IPAddress remote_addr;
|
||||
if (!WiFi.hostByName(name, remote_addr)) {
|
||||
if (!WiFi.hostByName(name, remote_addr))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (!WiFiClient::connect(remote_addr, port)) {
|
||||
if (!WiFiClient::connect(remote_addr, port))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return _connectSSL(name);
|
||||
@ -123,13 +134,15 @@ int WiFiClientSecure::connect(const String& host, uint16_t port)
|
||||
|
||||
int WiFiClientSecure::_connectSSL(const char* hostName)
|
||||
{
|
||||
if (!_ssl) {
|
||||
if (!_ssl)
|
||||
{
|
||||
_ssl = std::make_shared<SSLContext>();
|
||||
}
|
||||
_ssl->connect(_client, hostName, _timeout);
|
||||
|
||||
auto status = ssl_handshake_status(*_ssl);
|
||||
if (status != SSL_OK) {
|
||||
if (status != SSL_OK)
|
||||
{
|
||||
_ssl = nullptr;
|
||||
return 0;
|
||||
}
|
||||
@ -139,16 +152,19 @@ int WiFiClientSecure::_connectSSL(const char* hostName)
|
||||
|
||||
size_t WiFiClientSecure::write(const uint8_t *buf, size_t size)
|
||||
{
|
||||
if (!_ssl) {
|
||||
if (!_ssl)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rc = _ssl->write(buf, size);
|
||||
if (rc >= 0) {
|
||||
if (rc >= 0)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc != SSL_CLOSE_NOTIFY) {
|
||||
if (rc != SSL_CLOSE_NOTIFY)
|
||||
{
|
||||
_ssl = nullptr;
|
||||
}
|
||||
|
||||
@ -174,22 +190,25 @@ size_t WiFiClientSecure::write(Stream& stream)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
do {
|
||||
do
|
||||
{
|
||||
uint8_t temp[256]; // Temporary chunk size same as ClientContext
|
||||
countSent = 0;
|
||||
countRead = stream.readBytes(temp, sizeof(temp));
|
||||
if (countRead) {
|
||||
if (countRead)
|
||||
{
|
||||
countSent = write(temp, countRead);
|
||||
totalSent += countSent;
|
||||
}
|
||||
yield(); // Feed the WDT
|
||||
} while ( (countSent == countRead) && (countSent > 0) );
|
||||
} while ((countSent == countRead) && (countSent > 0));
|
||||
return totalSent;
|
||||
}
|
||||
|
||||
int WiFiClientSecure::read(uint8_t *buf, size_t size)
|
||||
{
|
||||
if (!_ssl) {
|
||||
if (!_ssl)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -198,7 +217,8 @@ int WiFiClientSecure::read(uint8_t *buf, size_t size)
|
||||
|
||||
int WiFiClientSecure::read()
|
||||
{
|
||||
if (!_ssl) {
|
||||
if (!_ssl)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -207,7 +227,8 @@ int WiFiClientSecure::read()
|
||||
|
||||
int WiFiClientSecure::peek()
|
||||
{
|
||||
if (!_ssl) {
|
||||
if (!_ssl)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -218,22 +239,28 @@ size_t WiFiClientSecure::peekBytes(uint8_t *buffer, size_t length)
|
||||
{
|
||||
size_t count = 0;
|
||||
|
||||
if (!_ssl) {
|
||||
if (!_ssl)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
_startMillis = millis();
|
||||
while ((available() < (int) length) && ((millis() - _startMillis) < _timeout)) {
|
||||
while ((available() < (int) length) && ((millis() - _startMillis) < _timeout))
|
||||
{
|
||||
yield();
|
||||
}
|
||||
|
||||
if (!_ssl) {
|
||||
if (!_ssl)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (available() < (int) length) {
|
||||
if (available() < (int) length)
|
||||
{
|
||||
count = available();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
count = length;
|
||||
}
|
||||
|
||||
@ -242,7 +269,8 @@ size_t WiFiClientSecure::peekBytes(uint8_t *buffer, size_t length)
|
||||
|
||||
int WiFiClientSecure::available()
|
||||
{
|
||||
if (!_ssl) {
|
||||
if (!_ssl)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -251,20 +279,23 @@ int WiFiClientSecure::available()
|
||||
|
||||
|
||||
/*
|
||||
SSL TCP RX data connected
|
||||
null x x N
|
||||
!null x Y Y
|
||||
Y Y x Y
|
||||
x N N N
|
||||
err x N N
|
||||
SSL TCP RX data connected
|
||||
null x x N
|
||||
!null x Y Y
|
||||
Y Y x Y
|
||||
x N N N
|
||||
err x N N
|
||||
*/
|
||||
uint8_t WiFiClientSecure::connected()
|
||||
{
|
||||
if (_ssl) {
|
||||
if (_ssl->hasData()) {
|
||||
if (_ssl)
|
||||
{
|
||||
if (_ssl->hasData())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (_client && _client->state() == ESTABLISHED && _ssl->connected()) {
|
||||
if (_client && _client->state() == ESTABLISHED && _ssl->connected())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -273,7 +304,8 @@ uint8_t WiFiClientSecure::connected()
|
||||
|
||||
bool WiFiClientSecure::stop(unsigned int maxWaitMs)
|
||||
{
|
||||
if (_ssl) {
|
||||
if (_ssl)
|
||||
{
|
||||
_ssl->stop();
|
||||
}
|
||||
return WiFiClient::stop(maxWaitMs);
|
||||
@ -281,12 +313,17 @@ bool WiFiClientSecure::stop(unsigned int maxWaitMs)
|
||||
|
||||
static bool parseHexNibble(char pb, uint8_t* res)
|
||||
{
|
||||
if (pb >= '0' && pb <= '9') {
|
||||
*res = (uint8_t) (pb - '0'); return true;
|
||||
} else if (pb >= 'a' && pb <= 'f') {
|
||||
*res = (uint8_t) (pb - 'a' + 10); return true;
|
||||
} else if (pb >= 'A' && pb <= 'F') {
|
||||
*res = (uint8_t) (pb - 'A' + 10); return true;
|
||||
if (pb >= '0' && pb <= '9')
|
||||
{
|
||||
*res = (uint8_t)(pb - '0'); return true;
|
||||
}
|
||||
else if (pb >= 'a' && pb <= 'f')
|
||||
{
|
||||
*res = (uint8_t)(pb - 'a' + 10); return true;
|
||||
}
|
||||
else if (pb >= 'A' && pb <= 'F')
|
||||
{
|
||||
*res = (uint8_t)(pb - 'A' + 10); return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -295,23 +332,27 @@ static bool parseHexNibble(char pb, uint8_t* res)
|
||||
static bool matchName(const String& name, const String& domainName)
|
||||
{
|
||||
int wildcardPos = name.indexOf('*');
|
||||
if (wildcardPos == -1) {
|
||||
if (wildcardPos == -1)
|
||||
{
|
||||
// Not a wildcard, expect an exact match
|
||||
return name == domainName;
|
||||
}
|
||||
int firstDotPos = name.indexOf('.');
|
||||
if (wildcardPos > firstDotPos) {
|
||||
if (wildcardPos > firstDotPos)
|
||||
{
|
||||
// Wildcard is not part of leftmost component of domain name
|
||||
// Do not attempt to match (rfc6125 6.4.3.1)
|
||||
return false;
|
||||
}
|
||||
if (wildcardPos != 0 || firstDotPos != 1) {
|
||||
if (wildcardPos != 0 || firstDotPos != 1)
|
||||
{
|
||||
// Matching of wildcards such as baz*.example.com and b*z.example.com
|
||||
// is optional. Maybe implement this in the future?
|
||||
return false;
|
||||
}
|
||||
int domainNameFirstDotPos = domainName.indexOf('.');
|
||||
if (domainNameFirstDotPos < 0) {
|
||||
if (domainNameFirstDotPos < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return domainName.substring(domainNameFirstDotPos) == name.substring(firstDotPos);
|
||||
@ -319,30 +360,36 @@ static bool matchName(const String& name, const String& domainName)
|
||||
|
||||
bool WiFiClientSecure::verify(const char* fp, const char* domain_name)
|
||||
{
|
||||
if (!_ssl) {
|
||||
if (!_ssl)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t sha1[20];
|
||||
int len = strlen(fp);
|
||||
int pos = 0;
|
||||
for (size_t i = 0; i < sizeof(sha1); ++i) {
|
||||
while (pos < len && ((fp[pos] == ' ') || (fp[pos] == ':'))) {
|
||||
for (size_t i = 0; i < sizeof(sha1); ++i)
|
||||
{
|
||||
while (pos < len && ((fp[pos] == ' ') || (fp[pos] == ':')))
|
||||
{
|
||||
++pos;
|
||||
}
|
||||
if (pos > len - 2) {
|
||||
if (pos > len - 2)
|
||||
{
|
||||
DEBUGV("pos:%d len:%d fingerprint too short\r\n", pos, len);
|
||||
return false;
|
||||
}
|
||||
uint8_t high, low;
|
||||
if (!parseHexNibble(fp[pos], &high) || !parseHexNibble(fp[pos+1], &low)) {
|
||||
DEBUGV("pos:%d len:%d invalid hex sequence: %c%c\r\n", pos, len, fp[pos], fp[pos+1]);
|
||||
if (!parseHexNibble(fp[pos], &high) || !parseHexNibble(fp[pos + 1], &low))
|
||||
{
|
||||
DEBUGV("pos:%d len:%d invalid hex sequence: %c%c\r\n", pos, len, fp[pos], fp[pos + 1]);
|
||||
return false;
|
||||
}
|
||||
pos += 2;
|
||||
sha1[i] = low | (high << 4);
|
||||
}
|
||||
if (ssl_match_fingerprint(*_ssl, sha1) != 0) {
|
||||
if (ssl_match_fingerprint(*_ssl, sha1) != 0)
|
||||
{
|
||||
DEBUGV("fingerprint doesn't match\r\n");
|
||||
return false;
|
||||
}
|
||||
@ -352,16 +399,18 @@ bool WiFiClientSecure::verify(const char* fp, const char* domain_name)
|
||||
|
||||
bool WiFiClientSecure::_verifyDN(const char* domain_name)
|
||||
{
|
||||
DEBUGV("domain name: '%s'\r\n", (domain_name)?domain_name:"(null)");
|
||||
DEBUGV("domain name: '%s'\r\n", (domain_name) ? domain_name : "(null)");
|
||||
String domain_name_str(domain_name);
|
||||
domain_name_str.toLowerCase();
|
||||
|
||||
const char* san = nullptr;
|
||||
int i = 0;
|
||||
while ((san = ssl_get_cert_subject_alt_dnsname(*_ssl, i)) != nullptr) {
|
||||
while ((san = ssl_get_cert_subject_alt_dnsname(*_ssl, i)) != nullptr)
|
||||
{
|
||||
String san_str(san);
|
||||
san_str.toLowerCase();
|
||||
if (matchName(san_str, domain_name_str)) {
|
||||
if (matchName(san_str, domain_name_str))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
DEBUGV("SAN %d: '%s', no match\r\n", i, san);
|
||||
@ -370,20 +419,23 @@ bool WiFiClientSecure::_verifyDN(const char* domain_name)
|
||||
const char* common_name = ssl_get_cert_dn(*_ssl, SSL_X509_CERT_COMMON_NAME);
|
||||
String common_name_str(common_name);
|
||||
common_name_str.toLowerCase();
|
||||
if (common_name && matchName(common_name_str, domain_name_str)) {
|
||||
if (common_name && matchName(common_name_str, domain_name_str))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
DEBUGV("CN: '%s', no match\r\n", (common_name)?common_name:"(null)");
|
||||
DEBUGV("CN: '%s', no match\r\n", (common_name) ? common_name : "(null)");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WiFiClientSecure::verifyCertChain(const char* domain_name)
|
||||
{
|
||||
if (!_ssl) {
|
||||
if (!_ssl)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!_ssl->verifyCert()) {
|
||||
if (!_ssl->verifyCert())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return _verifyDN(domain_name);
|
||||
@ -391,7 +443,8 @@ bool WiFiClientSecure::verifyCertChain(const char* domain_name)
|
||||
|
||||
void WiFiClientSecure::_initSSLContext()
|
||||
{
|
||||
if (!_ssl) {
|
||||
if (!_ssl)
|
||||
{
|
||||
_ssl = std::make_shared<SSLContext>();
|
||||
}
|
||||
}
|
||||
@ -459,37 +512,42 @@ void WiFiClientSecure::allowSelfSignedCerts()
|
||||
extern "C" int __ax_port_read(int fd, uint8_t* buffer, size_t count)
|
||||
{
|
||||
ClientContext* _client = SSLContext::getIOContext(fd);
|
||||
if (!_client || (_client->state() != ESTABLISHED && !_client->getSize())) {
|
||||
if (!_client || (_client->state() != ESTABLISHED && !_client->getSize()))
|
||||
{
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
size_t cb = _client->read((char*) buffer, count);
|
||||
if (cb != count) {
|
||||
if (cb != count)
|
||||
{
|
||||
errno = EAGAIN;
|
||||
}
|
||||
if (cb == 0) {
|
||||
if (cb == 0)
|
||||
{
|
||||
optimistic_yield(100);
|
||||
return -1;
|
||||
}
|
||||
return cb;
|
||||
}
|
||||
extern "C" void ax_port_read() __attribute__ ((weak, alias("__ax_port_read")));
|
||||
extern "C" void ax_port_read() __attribute__((weak, alias("__ax_port_read")));
|
||||
|
||||
extern "C" int __ax_port_write(int fd, uint8_t* buffer, size_t count)
|
||||
{
|
||||
ClientContext* _client = SSLContext::getIOContext(fd);
|
||||
if (!_client || _client->state() != ESTABLISHED) {
|
||||
if (!_client || _client->state() != ESTABLISHED)
|
||||
{
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t cb = _client->write(buffer, count);
|
||||
if (cb != count) {
|
||||
if (cb != count)
|
||||
{
|
||||
errno = EAGAIN;
|
||||
}
|
||||
return cb;
|
||||
}
|
||||
extern "C" void ax_port_write() __attribute__ ((weak, alias("__ax_port_write")));
|
||||
extern "C" void ax_port_write() __attribute__((weak, alias("__ax_port_write")));
|
||||
|
||||
extern "C" int __ax_get_file(const char *filename, uint8_t **buf)
|
||||
{
|
||||
@ -497,12 +555,12 @@ extern "C" int __ax_get_file(const char *filename, uint8_t **buf)
|
||||
*buf = 0;
|
||||
return 0;
|
||||
}
|
||||
extern "C" void ax_get_file() __attribute__ ((weak, alias("__ax_get_file")));
|
||||
extern "C" void ax_get_file() __attribute__((weak, alias("__ax_get_file")));
|
||||
|
||||
extern "C" void __ax_wdt_feed()
|
||||
{
|
||||
optimistic_yield(10000);
|
||||
}
|
||||
extern "C" void ax_wdt_feed() __attribute__ ((weak, alias("__ax_wdt_feed")));
|
||||
extern "C" void ax_wdt_feed() __attribute__((weak, alias("__ax_wdt_feed")));
|
||||
|
||||
};
|
||||
|
@ -1,22 +1,22 @@
|
||||
/*
|
||||
WiFiClientSecure.h - Variant of WiFiClient with TLS support
|
||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
WiFiClientSecure.h - Variant of WiFiClient with TLS support
|
||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This library is 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.
|
||||
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
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
@ -26,67 +26,75 @@
|
||||
#include "include/ssl.h"
|
||||
|
||||
|
||||
namespace axTLS {
|
||||
namespace axTLS
|
||||
{
|
||||
|
||||
class SSLContext;
|
||||
|
||||
class WiFiClientSecure : public WiFiClient {
|
||||
class WiFiClientSecure : public WiFiClient
|
||||
{
|
||||
public:
|
||||
WiFiClientSecure() __attribute__((deprecated("Upgrade to BearSSL is advised, check https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/src/WiFiClientSecure.h#L25-L99")));
|
||||
~WiFiClientSecure() override;
|
||||
WiFiClientSecure() __attribute__((deprecated("Upgrade to BearSSL is advised, check https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/src/WiFiClientSecure.h#L25-L99")));
|
||||
~WiFiClientSecure() override;
|
||||
|
||||
int connect(IPAddress ip, uint16_t port) override;
|
||||
int connect(const String& host, uint16_t port) override;
|
||||
int connect(const char* name, uint16_t port) override;
|
||||
int connect(IPAddress ip, uint16_t port) override;
|
||||
int connect(const String& host, uint16_t port) override;
|
||||
int connect(const char* name, uint16_t port) override;
|
||||
|
||||
bool verify(const char* fingerprint, const char* domain_name);
|
||||
bool verifyCertChain(const char* domain_name);
|
||||
bool verify(const char* fingerprint, const char* domain_name);
|
||||
bool verifyCertChain(const char* domain_name);
|
||||
|
||||
uint8_t connected() override;
|
||||
size_t write(const uint8_t *buf, size_t size) override;
|
||||
size_t write_P(PGM_P buf, size_t size) override;
|
||||
size_t write(Stream& stream); // Note this is not virtual
|
||||
int read(uint8_t *buf, size_t size) override;
|
||||
int available() override;
|
||||
int read() override;
|
||||
int peek() override;
|
||||
size_t peekBytes(uint8_t *buffer, size_t length) override;
|
||||
void stop() override { (void)stop(0); }
|
||||
bool stop(unsigned int maxWaitMs);
|
||||
uint8_t connected() override;
|
||||
size_t write(const uint8_t *buf, size_t size) override;
|
||||
size_t write_P(PGM_P buf, size_t size) override;
|
||||
size_t write(Stream& stream); // Note this is not virtual
|
||||
int read(uint8_t *buf, size_t size) override;
|
||||
int available() override;
|
||||
int read() override;
|
||||
int peek() override;
|
||||
size_t peekBytes(uint8_t *buffer, size_t length) override;
|
||||
void stop() override
|
||||
{
|
||||
(void)stop(0);
|
||||
}
|
||||
bool stop(unsigned int maxWaitMs);
|
||||
|
||||
bool setCACert(const uint8_t* pk, size_t size);
|
||||
bool setCertificate(const uint8_t* pk, size_t size);
|
||||
bool setPrivateKey(const uint8_t* pk, size_t size);
|
||||
bool setCACert(const uint8_t* pk, size_t size);
|
||||
bool setCertificate(const uint8_t* pk, size_t size);
|
||||
bool setPrivateKey(const uint8_t* pk, size_t size);
|
||||
|
||||
bool setCACert_P(PGM_VOID_P pk, size_t size);
|
||||
bool setCertificate_P(PGM_VOID_P pk, size_t size);
|
||||
bool setPrivateKey_P(PGM_VOID_P pk, size_t size);
|
||||
bool setCACert_P(PGM_VOID_P pk, size_t size);
|
||||
bool setCertificate_P(PGM_VOID_P pk, size_t size);
|
||||
bool setPrivateKey_P(PGM_VOID_P pk, size_t size);
|
||||
|
||||
bool loadCACert(Stream& stream, size_t size);
|
||||
bool loadCertificate(Stream& stream, size_t size);
|
||||
bool loadPrivateKey(Stream& stream, size_t size);
|
||||
bool loadCACert(Stream& stream, size_t size);
|
||||
bool loadCertificate(Stream& stream, size_t size);
|
||||
bool loadPrivateKey(Stream& stream, size_t size);
|
||||
|
||||
void allowSelfSignedCerts();
|
||||
void allowSelfSignedCerts();
|
||||
|
||||
template<typename TFile>
|
||||
bool loadCertificate(TFile& file) {
|
||||
return loadCertificate(file, file.size());
|
||||
}
|
||||
template<typename TFile>
|
||||
bool loadCertificate(TFile& file)
|
||||
{
|
||||
return loadCertificate(file, file.size());
|
||||
}
|
||||
|
||||
template<typename TFile>
|
||||
bool loadPrivateKey(TFile& file) {
|
||||
return loadPrivateKey(file, file.size());
|
||||
}
|
||||
|
||||
template<typename TFile>
|
||||
bool loadCACert(TFile& file) {
|
||||
return loadCACert(file, file.size());
|
||||
}
|
||||
template<typename TFile>
|
||||
bool loadPrivateKey(TFile& file)
|
||||
{
|
||||
return loadPrivateKey(file, file.size());
|
||||
}
|
||||
|
||||
friend class WiFiServerSecure; // Needs access to custom constructor below
|
||||
template<typename TFile>
|
||||
bool loadCACert(TFile& file)
|
||||
{
|
||||
return loadCACert(file, file.size());
|
||||
}
|
||||
|
||||
friend class WiFiServerSecure; // Needs access to custom constructor below
|
||||
protected:
|
||||
// Only called by WiFiServerSecure
|
||||
WiFiClientSecure(ClientContext* client, bool usePMEM, const uint8_t *rsakey, int rsakeyLen, const uint8_t *cert, int certLen);
|
||||
// Only called by WiFiServerSecure
|
||||
WiFiClientSecure(ClientContext* client, bool usePMEM, const uint8_t *rsakey, int rsakeyLen, const uint8_t *cert, int certLen);
|
||||
|
||||
protected:
|
||||
void _initSSLContext();
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,23 +1,23 @@
|
||||
/*
|
||||
WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries
|
||||
- Mostly compatible with Arduino WiFi shield library and standard
|
||||
WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries
|
||||
- Mostly compatible with Arduino WiFi shield library and standard
|
||||
WiFiClient/ServerSecure (except for certificate handling).
|
||||
|
||||
Copyright (c) 2018 Earle F. Philhower, III
|
||||
Copyright (c) 2018 Earle F. Philhower, III
|
||||
|
||||
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 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.
|
||||
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
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
@ -29,10 +29,12 @@
|
||||
#include "BearSSLHelpers.h"
|
||||
#include "CertStoreBearSSL.h"
|
||||
|
||||
namespace BearSSL {
|
||||
namespace BearSSL
|
||||
{
|
||||
|
||||
class WiFiClientSecure : public WiFiClient {
|
||||
public:
|
||||
class WiFiClientSecure : public WiFiClient
|
||||
{
|
||||
public:
|
||||
WiFiClientSecure();
|
||||
WiFiClientSecure(const WiFiClientSecure &rhs);
|
||||
~WiFiClientSecure() override;
|
||||
@ -44,11 +46,13 @@ class WiFiClientSecure : public WiFiClient {
|
||||
uint8_t connected() override;
|
||||
size_t write(const uint8_t *buf, size_t size) override;
|
||||
size_t write_P(PGM_P buf, size_t size) override;
|
||||
size_t write(const char *buf) {
|
||||
return write((const uint8_t*)buf, strlen(buf));
|
||||
size_t write(const char *buf)
|
||||
{
|
||||
return write((const uint8_t*)buf, strlen(buf));
|
||||
}
|
||||
size_t write_P(const char *buf) {
|
||||
return write_P((PGM_P)buf, strlen_P(buf));
|
||||
size_t write_P(const char *buf)
|
||||
{
|
||||
return write_P((PGM_P)buf, strlen_P(buf));
|
||||
}
|
||||
size_t write(Stream& stream); // Note this is not virtual
|
||||
int read(uint8_t *buf, size_t size) override;
|
||||
@ -58,44 +62,59 @@ class WiFiClientSecure : public WiFiClient {
|
||||
size_t peekBytes(uint8_t *buffer, size_t length) override;
|
||||
bool flush(unsigned int maxWaitMs);
|
||||
bool stop(unsigned int maxWaitMs);
|
||||
void flush() override { (void)flush(0); }
|
||||
void stop() override { (void)stop(0); }
|
||||
void flush() override
|
||||
{
|
||||
(void)flush(0);
|
||||
}
|
||||
void stop() override
|
||||
{
|
||||
(void)stop(0);
|
||||
}
|
||||
|
||||
// Allow sessions to be saved/restored automatically to a memory area
|
||||
void setSession(Session *session) { _session = session; }
|
||||
void setSession(Session *session)
|
||||
{
|
||||
_session = session;
|
||||
}
|
||||
|
||||
// Don't validate the chain, just accept whatever is given. VERY INSECURE!
|
||||
void setInsecure() {
|
||||
_clearAuthenticationSettings();
|
||||
_use_insecure = true;
|
||||
void setInsecure()
|
||||
{
|
||||
_clearAuthenticationSettings();
|
||||
_use_insecure = true;
|
||||
}
|
||||
// Assume a given public key, don't validate or use cert info at all
|
||||
void setKnownKey(const PublicKey *pk, unsigned usages = BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN) {
|
||||
_clearAuthenticationSettings();
|
||||
_knownkey = pk;
|
||||
_knownkey_usages = usages;
|
||||
void setKnownKey(const PublicKey *pk, unsigned usages = BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN)
|
||||
{
|
||||
_clearAuthenticationSettings();
|
||||
_knownkey = pk;
|
||||
_knownkey_usages = usages;
|
||||
}
|
||||
// Only check SHA1 fingerprint of certificate
|
||||
bool setFingerprint(const uint8_t fingerprint[20]) {
|
||||
_clearAuthenticationSettings();
|
||||
_use_fingerprint = true;
|
||||
memcpy_P(_fingerprint, fingerprint, 20);
|
||||
return true;
|
||||
bool setFingerprint(const uint8_t fingerprint[20])
|
||||
{
|
||||
_clearAuthenticationSettings();
|
||||
_use_fingerprint = true;
|
||||
memcpy_P(_fingerprint, fingerprint, 20);
|
||||
return true;
|
||||
}
|
||||
bool setFingerprint(const char *fpStr);
|
||||
// Accept any certificate that's self-signed
|
||||
void allowSelfSignedCerts() {
|
||||
_clearAuthenticationSettings();
|
||||
_use_self_signed = true;
|
||||
void allowSelfSignedCerts()
|
||||
{
|
||||
_clearAuthenticationSettings();
|
||||
_use_self_signed = true;
|
||||
}
|
||||
// Install certificates of trusted CAs or specific site
|
||||
void setTrustAnchors(const X509List *ta) {
|
||||
_clearAuthenticationSettings();
|
||||
_ta = ta;
|
||||
void setTrustAnchors(const X509List *ta)
|
||||
{
|
||||
_clearAuthenticationSettings();
|
||||
_ta = ta;
|
||||
}
|
||||
// In cases when NTP is not used, app must set a time manually to check cert validity
|
||||
void setX509Time(time_t now) {
|
||||
_now = now;
|
||||
void setX509Time(time_t now)
|
||||
{
|
||||
_now = now;
|
||||
}
|
||||
// Install a client certificate for this connection, in case the server requires it (i.e. MQTT)
|
||||
void setClientRSACert(const X509List *cert, const PrivateKey *sk);
|
||||
@ -106,16 +125,18 @@ class WiFiClientSecure : public WiFiClient {
|
||||
void setBufferSizes(int recv, int xmit);
|
||||
|
||||
// Returns whether MFLN negotiation for the above buffer sizes succeeded (after connection)
|
||||
int getMFLNStatus() {
|
||||
return connected() && br_ssl_engine_get_mfln_negotiated(_eng);
|
||||
int getMFLNStatus()
|
||||
{
|
||||
return connected() && br_ssl_engine_get_mfln_negotiated(_eng);
|
||||
}
|
||||
|
||||
// Return an error code and possibly a text string in a passed-in buffer with last SSL failure
|
||||
int getLastSSLError(char *dest = NULL, size_t len = 0);
|
||||
|
||||
// Attach a preconfigured certificate store
|
||||
void setCertStore(CertStore *certStore) {
|
||||
_certStore = certStore;
|
||||
void setCertStore(CertStore *certStore)
|
||||
{
|
||||
_certStore = certStore;
|
||||
}
|
||||
|
||||
// Select specific ciphers (i.e. optimize for speed over security)
|
||||
@ -132,7 +153,7 @@ class WiFiClientSecure : public WiFiClient {
|
||||
////////////////////////////////////////////////////
|
||||
// AxTLS API deprecated warnings to help upgrading
|
||||
|
||||
#define AXTLS_DEPRECATED \
|
||||
#define AXTLS_DEPRECATED \
|
||||
__attribute__((deprecated( \
|
||||
"This is deprecated AxTLS API, " \
|
||||
"check https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/src/WiFiClientSecure.h#L25-L99")))
|
||||
@ -148,57 +169,66 @@ class WiFiClientSecure : public WiFiClient {
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
|
||||
bool setCACert_P(PGM_VOID_P pk, size_t size) AXTLS_DEPRECATED {
|
||||
return setCACert((const uint8_t *)pk, size);
|
||||
bool setCACert_P(PGM_VOID_P pk, size_t size) AXTLS_DEPRECATED
|
||||
{
|
||||
return setCACert((const uint8_t *)pk, size);
|
||||
}
|
||||
|
||||
bool setCertificate_P(PGM_VOID_P pk, size_t size) AXTLS_DEPRECATED {
|
||||
return setCertificate((const uint8_t *)pk, size);
|
||||
bool setCertificate_P(PGM_VOID_P pk, size_t size) AXTLS_DEPRECATED
|
||||
{
|
||||
return setCertificate((const uint8_t *)pk, size);
|
||||
}
|
||||
|
||||
bool setPrivateKey_P(PGM_VOID_P pk, size_t size) AXTLS_DEPRECATED {
|
||||
return setPrivateKey((const uint8_t *)pk, size);
|
||||
bool setPrivateKey_P(PGM_VOID_P pk, size_t size) AXTLS_DEPRECATED
|
||||
{
|
||||
return setPrivateKey((const uint8_t *)pk, size);
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
template<typename TFile>
|
||||
bool loadCertificate(TFile& file) {
|
||||
return loadCertificate(file, file.size());
|
||||
bool loadCertificate(TFile& file)
|
||||
{
|
||||
return loadCertificate(file, file.size());
|
||||
}
|
||||
|
||||
template<typename TFile>
|
||||
bool loadPrivateKey(TFile& file) {
|
||||
return loadPrivateKey(file, file.size());
|
||||
bool loadPrivateKey(TFile& file)
|
||||
{
|
||||
return loadPrivateKey(file, file.size());
|
||||
}
|
||||
|
||||
template<typename TFile>
|
||||
bool loadCACert(TFile& file) {
|
||||
return loadCACert(file, file.size());
|
||||
bool loadCACert(TFile& file)
|
||||
{
|
||||
return loadCACert(file, file.size());
|
||||
}
|
||||
|
||||
bool verify(const char* fingerprint, const char* domain_name) AXTLS_DEPRECATED {
|
||||
(void)fingerprint;
|
||||
(void)domain_name;
|
||||
return connected();
|
||||
bool verify(const char* fingerprint, const char* domain_name) AXTLS_DEPRECATED
|
||||
{
|
||||
(void)fingerprint;
|
||||
(void)domain_name;
|
||||
return connected();
|
||||
}
|
||||
|
||||
bool verifyCertChain(const char* domain_name) AXTLS_DEPRECATED {
|
||||
(void)domain_name;
|
||||
return connected();
|
||||
bool verifyCertChain(const char* domain_name) AXTLS_DEPRECATED
|
||||
{
|
||||
(void)domain_name;
|
||||
return connected();
|
||||
}
|
||||
|
||||
// AxTLS API deprecated section end
|
||||
/////////////////////////////////////
|
||||
|
||||
private:
|
||||
private:
|
||||
void _clear();
|
||||
void _clearAuthenticationSettings();
|
||||
// Only one of the following two should ever be != nullptr!
|
||||
std::shared_ptr<br_ssl_client_context> _sc;
|
||||
std::shared_ptr<br_ssl_server_context> _sc_svr;
|
||||
inline bool ctx_present() {
|
||||
return (_sc != nullptr) || (_sc_svr != nullptr);
|
||||
inline bool ctx_present()
|
||||
{
|
||||
return (_sc != nullptr) || (_sc_svr != nullptr);
|
||||
}
|
||||
br_ssl_engine_context *_eng; // &_sc->eng, to allow for client or server contexts
|
||||
std::shared_ptr<br_x509_minimal_context> _x509_minimal;
|
||||
@ -256,9 +286,9 @@ class WiFiClientSecure : public WiFiClient {
|
||||
// Methods for handling server.available() call which returns a client connection.
|
||||
friend class WiFiServerSecure; // Server needs to access these constructors
|
||||
WiFiClientSecure(ClientContext *client, const X509List *chain, unsigned cert_issuer_key_type,
|
||||
const PrivateKey *sk, int iobuf_in_size, int iobuf_out_size, const X509List *client_CA_ta);
|
||||
const PrivateKey *sk, int iobuf_in_size, int iobuf_out_size, const X509List *client_CA_ta);
|
||||
WiFiClientSecure(ClientContext* client, const X509List *chain, const PrivateKey *sk,
|
||||
int iobuf_in_size, int iobuf_out_size, const X509List *client_CA_ta);
|
||||
int iobuf_in_size, int iobuf_out_size, const X509List *client_CA_ta);
|
||||
|
||||
// RSA keyed server
|
||||
bool _connectSSLServerRSA(const X509List *chain, const PrivateKey *sk, const X509List *client_CA_ta);
|
||||
|
@ -1,31 +1,31 @@
|
||||
/*
|
||||
WiFiServer.cpp - TCP/IP server for esp8266, mostly compatible
|
||||
WiFiServer.cpp - TCP/IP server for esp8266, mostly compatible
|
||||
with Arduino WiFi shield library
|
||||
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This library is 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.
|
||||
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
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
#define LWIP_INTERNAL
|
||||
|
||||
extern "C" {
|
||||
#include "osapi.h"
|
||||
#include "ets_sys.h"
|
||||
#include "osapi.h"
|
||||
#include "ets_sys.h"
|
||||
}
|
||||
|
||||
#include "debug.h"
|
||||
@ -38,47 +38,53 @@ extern "C" {
|
||||
#include <include/ClientContext.h>
|
||||
|
||||
WiFiServer::WiFiServer(const IPAddress& addr, uint16_t port)
|
||||
: _port(port)
|
||||
, _addr(addr)
|
||||
, _pcb(nullptr)
|
||||
, _unclaimed(nullptr)
|
||||
, _discarded(nullptr)
|
||||
: _port(port)
|
||||
, _addr(addr)
|
||||
, _pcb(nullptr)
|
||||
, _unclaimed(nullptr)
|
||||
, _discarded(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
WiFiServer::WiFiServer(uint16_t port)
|
||||
: _port(port)
|
||||
, _addr(IP_ANY_TYPE)
|
||||
, _pcb(nullptr)
|
||||
, _unclaimed(nullptr)
|
||||
, _discarded(nullptr)
|
||||
: _port(port)
|
||||
, _addr(IP_ANY_TYPE)
|
||||
, _pcb(nullptr)
|
||||
, _unclaimed(nullptr)
|
||||
, _discarded(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void WiFiServer::begin() {
|
||||
begin(_port);
|
||||
void WiFiServer::begin()
|
||||
{
|
||||
begin(_port);
|
||||
}
|
||||
|
||||
void WiFiServer::begin(uint16_t port) {
|
||||
void WiFiServer::begin(uint16_t port)
|
||||
{
|
||||
close();
|
||||
_port = port;
|
||||
err_t err;
|
||||
tcp_pcb* pcb = tcp_new();
|
||||
if (!pcb)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pcb->so_options |= SOF_REUSEADDR;
|
||||
|
||||
// (IPAddress _addr) operator-converted to (const ip_addr_t*)
|
||||
err = tcp_bind(pcb, _addr, _port);
|
||||
|
||||
if (err != ERR_OK) {
|
||||
if (err != ERR_OK)
|
||||
{
|
||||
tcp_close(pcb);
|
||||
return;
|
||||
}
|
||||
|
||||
tcp_pcb* listen_pcb = tcp_listen(pcb);
|
||||
if (!listen_pcb) {
|
||||
if (!listen_pcb)
|
||||
{
|
||||
tcp_close(pcb);
|
||||
return;
|
||||
}
|
||||
@ -87,11 +93,13 @@ void WiFiServer::begin(uint16_t port) {
|
||||
tcp_arg(listen_pcb, (void*) this);
|
||||
}
|
||||
|
||||
void WiFiServer::setNoDelay(bool nodelay) {
|
||||
_noDelay = nodelay? _ndTrue: _ndFalse;
|
||||
void WiFiServer::setNoDelay(bool nodelay)
|
||||
{
|
||||
_noDelay = nodelay ? _ndTrue : _ndFalse;
|
||||
}
|
||||
|
||||
bool WiFiServer::getNoDelay() {
|
||||
bool WiFiServer::getNoDelay()
|
||||
{
|
||||
switch (_noDelay)
|
||||
{
|
||||
case _ndFalse: return false;
|
||||
@ -100,15 +108,20 @@ bool WiFiServer::getNoDelay() {
|
||||
}
|
||||
}
|
||||
|
||||
bool WiFiServer::hasClient() {
|
||||
bool WiFiServer::hasClient()
|
||||
{
|
||||
if (_unclaimed)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
WiFiClient WiFiServer::available(byte* status) {
|
||||
WiFiClient WiFiServer::available(byte* status)
|
||||
{
|
||||
(void) status;
|
||||
if (_unclaimed) {
|
||||
if (_unclaimed)
|
||||
{
|
||||
WiFiClient result(_unclaimed);
|
||||
_unclaimed = _unclaimed->next();
|
||||
result.setNoDelay(getNoDelay());
|
||||
@ -120,29 +133,37 @@ WiFiClient WiFiServer::available(byte* status) {
|
||||
return WiFiClient();
|
||||
}
|
||||
|
||||
uint8_t WiFiServer::status() {
|
||||
uint8_t WiFiServer::status()
|
||||
{
|
||||
if (!_pcb)
|
||||
{
|
||||
return CLOSED;
|
||||
}
|
||||
return _pcb->state;
|
||||
}
|
||||
|
||||
void WiFiServer::close() {
|
||||
if (!_pcb) {
|
||||
return;
|
||||
void WiFiServer::close()
|
||||
{
|
||||
if (!_pcb)
|
||||
{
|
||||
return;
|
||||
}
|
||||
tcp_close(_pcb);
|
||||
_pcb = nullptr;
|
||||
}
|
||||
|
||||
void WiFiServer::stop() {
|
||||
void WiFiServer::stop()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
size_t WiFiServer::write(uint8_t b) {
|
||||
size_t WiFiServer::write(uint8_t b)
|
||||
{
|
||||
return write(&b, 1);
|
||||
}
|
||||
|
||||
size_t WiFiServer::write(const uint8_t *buffer, size_t size) {
|
||||
size_t WiFiServer::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
// write to all clients
|
||||
// not implemented
|
||||
(void) buffer;
|
||||
@ -151,17 +172,23 @@ size_t WiFiServer::write(const uint8_t *buffer, size_t size) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* slist_append_tail(T* head, T* item) {
|
||||
T* slist_append_tail(T* head, T* item)
|
||||
{
|
||||
if (!head)
|
||||
{
|
||||
return item;
|
||||
}
|
||||
T* last = head;
|
||||
while(last->next())
|
||||
while (last->next())
|
||||
{
|
||||
last = last->next();
|
||||
}
|
||||
last->next(item);
|
||||
return head;
|
||||
}
|
||||
|
||||
long WiFiServer::_accept(tcp_pcb* apcb, long err) {
|
||||
long WiFiServer::_accept(tcp_pcb* apcb, long err)
|
||||
{
|
||||
(void) err;
|
||||
DEBUGV("WS:ac\r\n");
|
||||
ClientContext* client = new ClientContext(apcb, &WiFiServer::_s_discard, this);
|
||||
@ -170,16 +197,19 @@ long WiFiServer::_accept(tcp_pcb* apcb, long err) {
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void WiFiServer::_discard(ClientContext* client) {
|
||||
void WiFiServer::_discard(ClientContext* client)
|
||||
{
|
||||
(void) client;
|
||||
// _discarded = slist_append_tail(_discarded, client);
|
||||
DEBUGV("WS:dis\r\n");
|
||||
}
|
||||
|
||||
long WiFiServer::_s_accept(void *arg, tcp_pcb* newpcb, long err) {
|
||||
long WiFiServer::_s_accept(void *arg, tcp_pcb* newpcb, long err)
|
||||
{
|
||||
return reinterpret_cast<WiFiServer*>(arg)->_accept(newpcb, err);
|
||||
}
|
||||
|
||||
void WiFiServer::_s_discard(void* server, ClientContext* ctx) {
|
||||
void WiFiServer::_s_discard(void* server, ClientContext* ctx)
|
||||
{
|
||||
reinterpret_cast<WiFiServer*>(server)->_discard(ctx);
|
||||
}
|
||||
|
@ -1,31 +1,31 @@
|
||||
/*
|
||||
WiFiServer.h - Library for Arduino Wifi shield.
|
||||
Copyright (c) 2011-2014 Arduino LLC. All right reserved.
|
||||
WiFiServer.h - Library for Arduino Wifi shield.
|
||||
Copyright (c) 2011-2014 Arduino LLC. All right reserved.
|
||||
|
||||
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 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.
|
||||
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
|
||||
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
|
||||
|
||||
Modified by Ivan Grokhotkov, December 2014 - esp8266 support
|
||||
Modified by Ivan Grokhotkov, December 2014 - esp8266 support
|
||||
*/
|
||||
|
||||
#ifndef wifiserver_h
|
||||
#define wifiserver_h
|
||||
|
||||
extern "C" {
|
||||
#include "include/wl_definitions.h"
|
||||
#include "include/wl_definitions.h"
|
||||
|
||||
struct tcp_pcb;
|
||||
struct tcp_pcb;
|
||||
}
|
||||
|
||||
#include "Server.h"
|
||||
@ -34,41 +34,42 @@ extern "C" {
|
||||
class ClientContext;
|
||||
class WiFiClient;
|
||||
|
||||
class WiFiServer : public Server {
|
||||
// Secure server needs access to all the private entries here
|
||||
class WiFiServer : public Server
|
||||
{
|
||||
// Secure server needs access to all the private entries here
|
||||
protected:
|
||||
uint16_t _port;
|
||||
IPAddress _addr;
|
||||
tcp_pcb* _pcb;
|
||||
uint16_t _port;
|
||||
IPAddress _addr;
|
||||
tcp_pcb* _pcb;
|
||||
|
||||
ClientContext* _unclaimed;
|
||||
ClientContext* _discarded;
|
||||
enum { _ndDefault, _ndFalse, _ndTrue } _noDelay = _ndDefault;
|
||||
ClientContext* _unclaimed;
|
||||
ClientContext* _discarded;
|
||||
enum { _ndDefault, _ndFalse, _ndTrue } _noDelay = _ndDefault;
|
||||
|
||||
public:
|
||||
WiFiServer(const IPAddress& addr, uint16_t port);
|
||||
WiFiServer(uint16_t port);
|
||||
virtual ~WiFiServer() {}
|
||||
WiFiClient available(uint8_t* status = NULL);
|
||||
bool hasClient();
|
||||
void begin();
|
||||
void begin(uint16_t port);
|
||||
void setNoDelay(bool nodelay);
|
||||
bool getNoDelay();
|
||||
virtual size_t write(uint8_t);
|
||||
virtual size_t write(const uint8_t *buf, size_t size);
|
||||
uint8_t status();
|
||||
void close();
|
||||
void stop();
|
||||
WiFiServer(const IPAddress& addr, uint16_t port);
|
||||
WiFiServer(uint16_t port);
|
||||
virtual ~WiFiServer() {}
|
||||
WiFiClient available(uint8_t* status = NULL);
|
||||
bool hasClient();
|
||||
void begin();
|
||||
void begin(uint16_t port);
|
||||
void setNoDelay(bool nodelay);
|
||||
bool getNoDelay();
|
||||
virtual size_t write(uint8_t);
|
||||
virtual size_t write(const uint8_t *buf, size_t size);
|
||||
uint8_t status();
|
||||
void close();
|
||||
void stop();
|
||||
|
||||
using Print::write;
|
||||
using Print::write;
|
||||
|
||||
protected:
|
||||
long _accept(tcp_pcb* newpcb, long err);
|
||||
void _discard(ClientContext* client);
|
||||
long _accept(tcp_pcb* newpcb, long err);
|
||||
void _discard(ClientContext* client);
|
||||
|
||||
static long _s_accept(void *arg, tcp_pcb* newpcb, long err);
|
||||
static void _s_discard(void* server, ClientContext* ctx);
|
||||
static long _s_accept(void *arg, tcp_pcb* newpcb, long err);
|
||||
static void _s_discard(void* server, ClientContext* ctx);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,20 +1,20 @@
|
||||
/*
|
||||
WiFiServerSecure.h - Library for Arduino ESP8266
|
||||
Copyright (c) 2017 Earle F. Philhower, III
|
||||
WiFiServerSecure.h - Library for Arduino ESP8266
|
||||
Copyright (c) 2017 Earle F. Philhower, III
|
||||
|
||||
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 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.
|
||||
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
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <WiFiClientSecure.h>
|
||||
|
@ -1,29 +1,29 @@
|
||||
/*
|
||||
WiFiServerSecure.cpp - SSL server for esp8266, mostly compatible
|
||||
WiFiServerSecure.cpp - SSL server for esp8266, mostly compatible
|
||||
with Arduino WiFi shield library
|
||||
|
||||
Copyright (c) 2017 Earle F. Philhower, III
|
||||
Copyright (c) 2017 Earle F. Philhower, III
|
||||
|
||||
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 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.
|
||||
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
|
||||
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
|
||||
*/
|
||||
|
||||
#define LWIP_INTERNAL
|
||||
|
||||
extern "C" {
|
||||
#include "osapi.h"
|
||||
#include "ets_sys.h"
|
||||
#include "osapi.h"
|
||||
#include "ets_sys.h"
|
||||
}
|
||||
|
||||
#include "debug.h"
|
||||
@ -38,7 +38,8 @@ extern "C" {
|
||||
#include "WiFiServerSecureAxTLS.h"
|
||||
|
||||
|
||||
namespace axTLS {
|
||||
namespace axTLS
|
||||
{
|
||||
|
||||
WiFiServerSecure::WiFiServerSecure(IPAddress addr, uint16_t port) : WiFiServer(addr, port)
|
||||
{
|
||||
@ -69,7 +70,8 @@ void WiFiServerSecure::setServerKeyAndCert_P(const uint8_t *key, int keyLen, con
|
||||
WiFiClientSecure WiFiServerSecure::available(uint8_t* status)
|
||||
{
|
||||
(void) status; // Unused
|
||||
if (_unclaimed) {
|
||||
if (_unclaimed)
|
||||
{
|
||||
WiFiClientSecure result(_unclaimed, usePMEM, rsakey, rsakeyLen, cert, certLen);
|
||||
_unclaimed = _unclaimed->next();
|
||||
result.setNoDelay(_noDelay);
|
||||
|
@ -1,20 +1,20 @@
|
||||
/*
|
||||
WiFiServerSecure.h - Library for Arduino ESP8266
|
||||
Copyright (c) 2017 Earle F. Philhower, III
|
||||
WiFiServerSecure.h - Library for Arduino ESP8266
|
||||
Copyright (c) 2017 Earle F. Philhower, III
|
||||
|
||||
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 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.
|
||||
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
|
||||
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 wifiserversecure_h
|
||||
@ -22,24 +22,26 @@
|
||||
|
||||
#include "WiFiServer.h"
|
||||
|
||||
namespace axTLS {
|
||||
namespace axTLS
|
||||
{
|
||||
|
||||
class WiFiClientSecure;
|
||||
|
||||
class WiFiServerSecure : public WiFiServer {
|
||||
class WiFiServerSecure : public WiFiServer
|
||||
{
|
||||
public:
|
||||
WiFiServerSecure(IPAddress addr, uint16_t port);
|
||||
WiFiServerSecure(uint16_t port);
|
||||
void setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen);
|
||||
void setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen);
|
||||
virtual ~WiFiServerSecure() {}
|
||||
WiFiClientSecure available(uint8_t* status = NULL);
|
||||
WiFiServerSecure(IPAddress addr, uint16_t port);
|
||||
WiFiServerSecure(uint16_t port);
|
||||
void setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen);
|
||||
void setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen);
|
||||
virtual ~WiFiServerSecure() {}
|
||||
WiFiClientSecure available(uint8_t* status = NULL);
|
||||
private:
|
||||
bool usePMEM = false;
|
||||
const uint8_t *rsakey = nullptr;
|
||||
int rsakeyLen = 0;
|
||||
const uint8_t *cert = nullptr;
|
||||
int certLen = 0;
|
||||
bool usePMEM = false;
|
||||
const uint8_t *rsakey = nullptr;
|
||||
int rsakeyLen = 0;
|
||||
const uint8_t *cert = nullptr;
|
||||
int certLen = 0;
|
||||
};
|
||||
|
||||
};
|
||||
|
@ -1,22 +1,22 @@
|
||||
/*
|
||||
WiFiServerBearSSL.cpp - SSL server for esp8266, mostly compatible
|
||||
WiFiServerBearSSL.cpp - SSL server for esp8266, mostly compatible
|
||||
with Arduino WiFi shield library
|
||||
|
||||
Copyright (c) 2018 Earle F. Philhower, III
|
||||
Copyright (c) 2018 Earle F. Philhower, III
|
||||
|
||||
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 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.
|
||||
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
|
||||
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
|
||||
*/
|
||||
|
||||
#define LWIP_INTERNAL
|
||||
@ -37,83 +37,99 @@ extern "C" {
|
||||
#include <include/ClientContext.h>
|
||||
#include "WiFiServerSecureBearSSL.h"
|
||||
|
||||
namespace BearSSL {
|
||||
namespace BearSSL
|
||||
{
|
||||
|
||||
// Only need to call the standard server constructor
|
||||
WiFiServerSecure::WiFiServerSecure(IPAddress addr, uint16_t port) : WiFiServer(addr, port) {
|
||||
stack_thunk_add_ref();
|
||||
WiFiServerSecure::WiFiServerSecure(IPAddress addr, uint16_t port) : WiFiServer(addr, port)
|
||||
{
|
||||
stack_thunk_add_ref();
|
||||
}
|
||||
|
||||
// Only need to call the standard server constructor
|
||||
WiFiServerSecure::WiFiServerSecure(uint16_t port) : WiFiServer(port) {
|
||||
stack_thunk_add_ref();
|
||||
WiFiServerSecure::WiFiServerSecure(uint16_t port) : WiFiServer(port)
|
||||
{
|
||||
stack_thunk_add_ref();
|
||||
}
|
||||
|
||||
WiFiServerSecure::WiFiServerSecure(const WiFiServerSecure &rhs) : WiFiServer(rhs) {
|
||||
*this = rhs;
|
||||
stack_thunk_add_ref();
|
||||
WiFiServerSecure::WiFiServerSecure(const WiFiServerSecure &rhs) : WiFiServer(rhs)
|
||||
{
|
||||
*this = rhs;
|
||||
stack_thunk_add_ref();
|
||||
}
|
||||
|
||||
WiFiServerSecure::~WiFiServerSecure() {
|
||||
stack_thunk_del_ref();
|
||||
_axtls_chain = nullptr;
|
||||
_axtls_sk = nullptr;
|
||||
WiFiServerSecure::~WiFiServerSecure()
|
||||
{
|
||||
stack_thunk_del_ref();
|
||||
_axtls_chain = nullptr;
|
||||
_axtls_sk = nullptr;
|
||||
}
|
||||
|
||||
// Specify a RSA-signed certificate and key for the server. Only copies the pointer, the
|
||||
// caller needs to preserve this chain and key for the life of the object.
|
||||
void WiFiServerSecure::setRSACert(const X509List *chain, const PrivateKey *sk) {
|
||||
_chain = chain;
|
||||
_sk = sk;
|
||||
void WiFiServerSecure::setRSACert(const X509List *chain, const PrivateKey *sk)
|
||||
{
|
||||
_chain = chain;
|
||||
_sk = sk;
|
||||
}
|
||||
|
||||
// Specify a EC-signed certificate and key for the server. Only copies the pointer, the
|
||||
// caller needs to preserve this chain and key for the life of the object.
|
||||
void WiFiServerSecure::setECCert(const X509List *chain, unsigned cert_issuer_key_type, const PrivateKey *sk) {
|
||||
_chain = chain;
|
||||
_cert_issuer_key_type = cert_issuer_key_type;
|
||||
_sk = sk;
|
||||
void WiFiServerSecure::setECCert(const X509List *chain, unsigned cert_issuer_key_type, const PrivateKey *sk)
|
||||
{
|
||||
_chain = chain;
|
||||
_cert_issuer_key_type = cert_issuer_key_type;
|
||||
_sk = sk;
|
||||
}
|
||||
|
||||
// Return a client if there's an available connection waiting. If one is returned,
|
||||
// then any validation (i.e. client cert checking) will have succeeded.
|
||||
WiFiClientSecure WiFiServerSecure::available(uint8_t* status) {
|
||||
(void) status; // Unused
|
||||
if (_unclaimed) {
|
||||
if (_sk && _sk->isRSA()) {
|
||||
WiFiClientSecure result(_unclaimed, _chain, _sk, _iobuf_in_size, _iobuf_out_size, _client_CA_ta);
|
||||
_unclaimed = _unclaimed->next();
|
||||
result.setNoDelay(_noDelay);
|
||||
DEBUGV("WS:av\r\n");
|
||||
return result;
|
||||
} else if (_sk && _sk->isEC()) {
|
||||
WiFiClientSecure result(_unclaimed, _chain, _cert_issuer_key_type, _sk, _iobuf_in_size, _iobuf_out_size, _client_CA_ta);
|
||||
_unclaimed = _unclaimed->next();
|
||||
result.setNoDelay(_noDelay);
|
||||
DEBUGV("WS:av\r\n");
|
||||
return result;
|
||||
} else {
|
||||
// No key was defined, so we can't actually accept and attempt accept() and SSL handshake.
|
||||
DEBUGV("WS:nokey\r\n");
|
||||
WiFiClientSecure WiFiServerSecure::available(uint8_t* status)
|
||||
{
|
||||
(void) status; // Unused
|
||||
if (_unclaimed)
|
||||
{
|
||||
if (_sk && _sk->isRSA())
|
||||
{
|
||||
WiFiClientSecure result(_unclaimed, _chain, _sk, _iobuf_in_size, _iobuf_out_size, _client_CA_ta);
|
||||
_unclaimed = _unclaimed->next();
|
||||
result.setNoDelay(_noDelay);
|
||||
DEBUGV("WS:av\r\n");
|
||||
return result;
|
||||
}
|
||||
else if (_sk && _sk->isEC())
|
||||
{
|
||||
WiFiClientSecure result(_unclaimed, _chain, _cert_issuer_key_type, _sk, _iobuf_in_size, _iobuf_out_size, _client_CA_ta);
|
||||
_unclaimed = _unclaimed->next();
|
||||
result.setNoDelay(_noDelay);
|
||||
DEBUGV("WS:av\r\n");
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No key was defined, so we can't actually accept and attempt accept() and SSL handshake.
|
||||
DEBUGV("WS:nokey\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Something weird, return a no-op object
|
||||
optimistic_yield(1000);
|
||||
return WiFiClientSecure();
|
||||
// Something weird, return a no-op object
|
||||
optimistic_yield(1000);
|
||||
return WiFiClientSecure();
|
||||
}
|
||||
|
||||
|
||||
void WiFiServerSecure::setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen) {
|
||||
_axtls_chain = nullptr;
|
||||
_axtls_sk = nullptr;
|
||||
_axtls_chain = std::shared_ptr<X509List>(new X509List(cert, certLen));
|
||||
_axtls_sk = std::shared_ptr<PrivateKey>(new PrivateKey(key, keyLen));
|
||||
setRSACert(_axtls_chain.get(), _axtls_sk.get());
|
||||
void WiFiServerSecure::setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen)
|
||||
{
|
||||
_axtls_chain = nullptr;
|
||||
_axtls_sk = nullptr;
|
||||
_axtls_chain = std::shared_ptr<X509List>(new X509List(cert, certLen));
|
||||
_axtls_sk = std::shared_ptr<PrivateKey>(new PrivateKey(key, keyLen));
|
||||
setRSACert(_axtls_chain.get(), _axtls_sk.get());
|
||||
}
|
||||
|
||||
void WiFiServerSecure::setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen) {
|
||||
setServerKeyAndCert(key, keyLen, cert, certLen);
|
||||
void WiFiServerSecure::setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen)
|
||||
{
|
||||
setServerKeyAndCert(key, keyLen, cert, certLen);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,20 +1,20 @@
|
||||
/*
|
||||
WiFiServerBearSSL.h - Library for Arduino ESP8266
|
||||
Copyright (c) 2018 Earle F. Philhower, III
|
||||
WiFiServerBearSSL.h - Library for Arduino ESP8266
|
||||
Copyright (c) 2018 Earle F. Philhower, III
|
||||
|
||||
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 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.
|
||||
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
|
||||
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 wifiserverbearssl_h
|
||||
@ -25,21 +25,24 @@
|
||||
#include "BearSSLHelpers.h"
|
||||
#include <bearssl/bearssl.h>
|
||||
|
||||
namespace BearSSL {
|
||||
namespace BearSSL
|
||||
{
|
||||
|
||||
class WiFiClientSecure;
|
||||
|
||||
class WiFiServerSecure : public WiFiServer {
|
||||
public:
|
||||
class WiFiServerSecure : public WiFiServer
|
||||
{
|
||||
public:
|
||||
WiFiServerSecure(IPAddress addr, uint16_t port);
|
||||
WiFiServerSecure(uint16_t port);
|
||||
WiFiServerSecure(const WiFiServerSecure &rhs);
|
||||
virtual ~WiFiServerSecure();
|
||||
|
||||
// Override the default buffer sizes, if you know what you're doing...
|
||||
void setBufferSizes(int recv, int xmit) {
|
||||
_iobuf_in_size = recv;
|
||||
_iobuf_out_size = xmit;
|
||||
void setBufferSizes(int recv, int xmit)
|
||||
{
|
||||
_iobuf_in_size = recv;
|
||||
_iobuf_out_size = xmit;
|
||||
}
|
||||
|
||||
// Set the server's RSA key and x509 certificate (required, pick one).
|
||||
@ -51,8 +54,9 @@ class WiFiServerSecure : public WiFiServer {
|
||||
|
||||
// Require client certificates validated against the passed in x509 trust anchor
|
||||
// Caller needs to preserve the cert throughout the life of the server.
|
||||
void setClientTrustAnchor(const X509List *client_CA_ta) {
|
||||
_client_CA_ta = client_CA_ta;
|
||||
void setClientTrustAnchor(const X509List *client_CA_ta)
|
||||
{
|
||||
_client_CA_ta = client_CA_ta;
|
||||
}
|
||||
|
||||
// If awaiting connection available and authenticated (i.e. client cert), return it.
|
||||
@ -62,7 +66,7 @@ class WiFiServerSecure : public WiFiServer {
|
||||
void setServerKeyAndCert(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen);
|
||||
void setServerKeyAndCert_P(const uint8_t *key, int keyLen, const uint8_t *cert, int certLen);
|
||||
|
||||
private:
|
||||
private:
|
||||
const X509List *_chain = nullptr;
|
||||
unsigned _cert_issuer_key_type = 0;
|
||||
const PrivateKey *_sk = nullptr;
|
||||
|
@ -1,23 +1,23 @@
|
||||
/*
|
||||
WiFiUdp.cpp - UDP client/server for esp8266, mostly compatible
|
||||
WiFiUdp.cpp - UDP client/server for esp8266, mostly compatible
|
||||
with Arduino WiFi shield library
|
||||
|
||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This library is 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.
|
||||
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
|
||||
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
|
||||
*/
|
||||
|
||||
#define LWIP_INTERNAL
|
||||
@ -25,9 +25,9 @@
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "include/wl_definitions.h"
|
||||
#include "osapi.h"
|
||||
#include "ets_sys.h"
|
||||
#include "include/wl_definitions.h"
|
||||
#include "osapi.h"
|
||||
#include "ets_sys.h"
|
||||
}
|
||||
|
||||
#include "debug.h"
|
||||
@ -53,7 +53,9 @@ WiFiUDP::WiFiUDP(const WiFiUDP& other)
|
||||
{
|
||||
_ctx = other._ctx;
|
||||
if (_ctx)
|
||||
{
|
||||
_ctx->ref();
|
||||
}
|
||||
WiFiUDP::_add(this);
|
||||
}
|
||||
|
||||
@ -61,7 +63,9 @@ WiFiUDP& WiFiUDP::operator=(const WiFiUDP& rhs)
|
||||
{
|
||||
_ctx = rhs._ctx;
|
||||
if (_ctx)
|
||||
{
|
||||
_ctx->ref();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -69,13 +73,16 @@ WiFiUDP::~WiFiUDP()
|
||||
{
|
||||
WiFiUDP::_remove(this);
|
||||
if (_ctx)
|
||||
{
|
||||
_ctx->unref();
|
||||
}
|
||||
}
|
||||
|
||||
/* Start WiFiUDP socket, listening at local port */
|
||||
uint8_t WiFiUDP::begin(uint16_t port)
|
||||
{
|
||||
if (_ctx) {
|
||||
if (_ctx)
|
||||
{
|
||||
_ctx->unref();
|
||||
_ctx = 0;
|
||||
}
|
||||
@ -87,35 +94,41 @@ uint8_t WiFiUDP::begin(uint16_t port)
|
||||
|
||||
uint8_t WiFiUDP::beginMulticast(IPAddress interfaceAddr, IPAddress multicast, uint16_t port)
|
||||
{
|
||||
if (_ctx) {
|
||||
if (_ctx)
|
||||
{
|
||||
_ctx->unref();
|
||||
_ctx = 0;
|
||||
}
|
||||
|
||||
if (igmp_joingroup(interfaceAddr, multicast)!= ERR_OK) {
|
||||
if (igmp_joingroup(interfaceAddr, multicast) != ERR_OK)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
_ctx = new UdpContext;
|
||||
_ctx->ref();
|
||||
ip_addr_t addr = IPADDR4_INIT(INADDR_ANY);
|
||||
if (!_ctx->listen(&addr, port)) {
|
||||
if (!_ctx->listen(&addr, port))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* return number of bytes available in the current packet,
|
||||
will return zero if parsePacket hasn't been called yet */
|
||||
int WiFiUDP::available() {
|
||||
/* return number of bytes available in the current packet,
|
||||
will return zero if parsePacket hasn't been called yet */
|
||||
int WiFiUDP::available()
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (_ctx) {
|
||||
if (_ctx)
|
||||
{
|
||||
result = static_cast<int>(_ctx->getSize());
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
if (!result)
|
||||
{
|
||||
// yielding here will not make more data "available",
|
||||
// but it will prevent the system from going into WDT reset
|
||||
optimistic_yield(1000);
|
||||
@ -127,7 +140,8 @@ int WiFiUDP::available() {
|
||||
/* Release any resources being used by this WiFiUDP instance */
|
||||
void WiFiUDP::stop()
|
||||
{
|
||||
if (_ctx) {
|
||||
if (_ctx)
|
||||
{
|
||||
_ctx->disconnect();
|
||||
_ctx->unref();
|
||||
}
|
||||
@ -146,7 +160,8 @@ int WiFiUDP::beginPacket(const char *host, uint16_t port)
|
||||
|
||||
int WiFiUDP::beginPacket(IPAddress ip, uint16_t port)
|
||||
{
|
||||
if (!_ctx) {
|
||||
if (!_ctx)
|
||||
{
|
||||
_ctx = new UdpContext;
|
||||
_ctx->ref();
|
||||
}
|
||||
@ -154,13 +169,15 @@ int WiFiUDP::beginPacket(IPAddress ip, uint16_t port)
|
||||
}
|
||||
|
||||
int WiFiUDP::beginPacketMulticast(IPAddress multicastAddress, uint16_t port,
|
||||
IPAddress interfaceAddress, int ttl)
|
||||
IPAddress interfaceAddress, int ttl)
|
||||
{
|
||||
if (!_ctx) {
|
||||
if (!_ctx)
|
||||
{
|
||||
_ctx = new UdpContext;
|
||||
_ctx->ref();
|
||||
}
|
||||
if (!_ctx->connect(multicastAddress, port)) {
|
||||
if (!_ctx->connect(multicastAddress, port))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
_ctx->setMulticastInterface(interfaceAddress);
|
||||
@ -171,7 +188,9 @@ int WiFiUDP::beginPacketMulticast(IPAddress multicastAddress, uint16_t port,
|
||||
int WiFiUDP::endPacket()
|
||||
{
|
||||
if (!_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (_ctx->send()) ? 1 : 0;
|
||||
}
|
||||
@ -184,7 +203,9 @@ size_t WiFiUDP::write(uint8_t byte)
|
||||
size_t WiFiUDP::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
if (!_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _ctx->append(reinterpret_cast<const char*>(buffer), size);
|
||||
}
|
||||
@ -192,9 +213,12 @@ size_t WiFiUDP::write(const uint8_t *buffer, size_t size)
|
||||
int WiFiUDP::parsePacket()
|
||||
{
|
||||
if (!_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_ctx->next()) {
|
||||
if (!_ctx->next())
|
||||
{
|
||||
optimistic_yield(100);
|
||||
return 0;
|
||||
}
|
||||
@ -205,7 +229,9 @@ int WiFiUDP::parsePacket()
|
||||
int WiFiUDP::read()
|
||||
{
|
||||
if (!_ctx)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _ctx->read();
|
||||
}
|
||||
@ -213,7 +239,9 @@ int WiFiUDP::read()
|
||||
int WiFiUDP::read(unsigned char* buffer, size_t len)
|
||||
{
|
||||
if (!_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _ctx->read(reinterpret_cast<char*>(buffer), len);
|
||||
}
|
||||
@ -221,7 +249,9 @@ int WiFiUDP::read(unsigned char* buffer, size_t len)
|
||||
int WiFiUDP::peek()
|
||||
{
|
||||
if (!_ctx)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _ctx->peek();
|
||||
}
|
||||
@ -234,7 +264,9 @@ void WiFiUDP::flush()
|
||||
IPAddress WiFiUDP::remoteIP()
|
||||
{
|
||||
if (!_ctx)
|
||||
{
|
||||
return INADDR_ANY;
|
||||
}
|
||||
|
||||
return _ctx->getRemoteAddress();
|
||||
}
|
||||
@ -242,7 +274,9 @@ IPAddress WiFiUDP::remoteIP()
|
||||
uint16_t WiFiUDP::remotePort()
|
||||
{
|
||||
if (!_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _ctx->getRemotePort();
|
||||
}
|
||||
@ -250,7 +284,9 @@ uint16_t WiFiUDP::remotePort()
|
||||
IPAddress WiFiUDP::destinationIP() const
|
||||
{
|
||||
if (!_ctx)
|
||||
{
|
||||
return INADDR_ANY;
|
||||
}
|
||||
|
||||
return _ctx->getDestAddress();
|
||||
}
|
||||
@ -258,22 +294,28 @@ IPAddress WiFiUDP::destinationIP() const
|
||||
uint16_t WiFiUDP::localPort() const
|
||||
{
|
||||
if (!_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _ctx->getLocalPort();
|
||||
}
|
||||
|
||||
void WiFiUDP::stopAll()
|
||||
{
|
||||
for (WiFiUDP* it = _s_first; it; it = it->_next) {
|
||||
for (WiFiUDP* it = _s_first; it; it = it->_next)
|
||||
{
|
||||
DEBUGV("%s %p %p\n", __func__, it, _s_first);
|
||||
it->stop();
|
||||
}
|
||||
}
|
||||
|
||||
void WiFiUDP::stopAllExcept(WiFiUDP * exC) {
|
||||
for (WiFiUDP* it = _s_first; it; it = it->_next) {
|
||||
if (it->_ctx != exC->_ctx) {
|
||||
void WiFiUDP::stopAllExcept(WiFiUDP * exC)
|
||||
{
|
||||
for (WiFiUDP* it = _s_first; it; it = it->_next)
|
||||
{
|
||||
if (it->_ctx != exC->_ctx)
|
||||
{
|
||||
DEBUGV("%s %p %p\n", __func__, it, _s_first);
|
||||
it->stop();
|
||||
}
|
||||
|
@ -1,22 +1,22 @@
|
||||
/*
|
||||
WiFiUdp.h - Library for Arduino Wifi shield.
|
||||
Copyright (c) 2011-2014 Arduino LLC. All right reserved.
|
||||
WiFiUdp.h - Library for Arduino Wifi shield.
|
||||
Copyright (c) 2011-2014 Arduino LLC. All right reserved.
|
||||
|
||||
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 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.
|
||||
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
|
||||
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
|
||||
|
||||
Modified by Ivan Grokhotkov, January 2015 - esp8266 support
|
||||
Modified by Ivan Grokhotkov, January 2015 - esp8266 support
|
||||
*/
|
||||
|
||||
#ifndef WIFIUDP_H
|
||||
@ -29,83 +29,90 @@
|
||||
|
||||
class UdpContext;
|
||||
|
||||
class WiFiUDP : public UDP, public SList<WiFiUDP> {
|
||||
class WiFiUDP : public UDP, public SList<WiFiUDP>
|
||||
{
|
||||
private:
|
||||
UdpContext* _ctx;
|
||||
UdpContext* _ctx;
|
||||
|
||||
public:
|
||||
WiFiUDP(); // Constructor
|
||||
WiFiUDP(const WiFiUDP& other);
|
||||
WiFiUDP& operator=(const WiFiUDP& rhs);
|
||||
virtual ~WiFiUDP();
|
||||
WiFiUDP(); // Constructor
|
||||
WiFiUDP(const WiFiUDP& other);
|
||||
WiFiUDP& operator=(const WiFiUDP& rhs);
|
||||
virtual ~WiFiUDP();
|
||||
|
||||
operator bool() const { return _ctx != 0; }
|
||||
operator bool() const
|
||||
{
|
||||
return _ctx != 0;
|
||||
}
|
||||
|
||||
// initialize, start listening on specified port.
|
||||
// Returns 1 if successful, 0 if there are no sockets available to use
|
||||
uint8_t begin(uint16_t port) override;
|
||||
// Finish with the UDP connetion
|
||||
void stop() override;
|
||||
// join a multicast group and listen on the given port
|
||||
uint8_t beginMulticast(IPAddress interfaceAddr, IPAddress multicast, uint16_t port);
|
||||
// initialize, start listening on specified port.
|
||||
// Returns 1 if successful, 0 if there are no sockets available to use
|
||||
uint8_t begin(uint16_t port) override;
|
||||
// Finish with the UDP connetion
|
||||
void stop() override;
|
||||
// join a multicast group and listen on the given port
|
||||
uint8_t beginMulticast(IPAddress interfaceAddr, IPAddress multicast, uint16_t port);
|
||||
|
||||
// Sending UDP packets
|
||||
|
||||
// Start building up a packet to send to the remote host specific in ip and port
|
||||
// Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
|
||||
int beginPacket(IPAddress ip, uint16_t port) override;
|
||||
// Start building up a packet to send to the remote host specific in host and port
|
||||
// Returns 1 if successful, 0 if there was a problem resolving the hostname or port
|
||||
int beginPacket(const char *host, uint16_t port) override;
|
||||
// Start building up a packet to send to the multicast address
|
||||
// multicastAddress - muticast address to send to
|
||||
// interfaceAddress - the local IP address of the interface that should be used
|
||||
// use WiFi.localIP() or WiFi.softAPIP() depending on the interface you need
|
||||
// ttl - multicast packet TTL (default is 1)
|
||||
// Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
|
||||
virtual int beginPacketMulticast(IPAddress multicastAddress,
|
||||
uint16_t port,
|
||||
IPAddress interfaceAddress,
|
||||
int ttl = 1);
|
||||
// Finish off this packet and send it
|
||||
// Returns 1 if the packet was sent successfully, 0 if there was an error
|
||||
int endPacket() override;
|
||||
// Write a single byte into the packet
|
||||
size_t write(uint8_t) override;
|
||||
// Write size bytes from buffer into the packet
|
||||
size_t write(const uint8_t *buffer, size_t size) override;
|
||||
|
||||
using Print::write;
|
||||
// Sending UDP packets
|
||||
|
||||
// Start processing the next available incoming packet
|
||||
// Returns the size of the packet in bytes, or 0 if no packets are available
|
||||
int parsePacket() override;
|
||||
// Number of bytes remaining in the current packet
|
||||
int available() override;
|
||||
// Read a single byte from the current packet
|
||||
int read() override;
|
||||
// Read up to len bytes from the current packet and place them into buffer
|
||||
// Returns the number of bytes read, or 0 if none are available
|
||||
int read(unsigned char* buffer, size_t len) override;
|
||||
// Read up to len characters from the current packet and place them into buffer
|
||||
// Returns the number of characters read, or 0 if none are available
|
||||
int read(char* buffer, size_t len) override { return read((unsigned char*)buffer, len); };
|
||||
// Return the next byte from the current packet without moving on to the next byte
|
||||
int peek() override;
|
||||
void flush() override; // Finish reading the current packet
|
||||
// Start building up a packet to send to the remote host specific in ip and port
|
||||
// Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
|
||||
int beginPacket(IPAddress ip, uint16_t port) override;
|
||||
// Start building up a packet to send to the remote host specific in host and port
|
||||
// Returns 1 if successful, 0 if there was a problem resolving the hostname or port
|
||||
int beginPacket(const char *host, uint16_t port) override;
|
||||
// Start building up a packet to send to the multicast address
|
||||
// multicastAddress - muticast address to send to
|
||||
// interfaceAddress - the local IP address of the interface that should be used
|
||||
// use WiFi.localIP() or WiFi.softAPIP() depending on the interface you need
|
||||
// ttl - multicast packet TTL (default is 1)
|
||||
// Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
|
||||
virtual int beginPacketMulticast(IPAddress multicastAddress,
|
||||
uint16_t port,
|
||||
IPAddress interfaceAddress,
|
||||
int ttl = 1);
|
||||
// Finish off this packet and send it
|
||||
// Returns 1 if the packet was sent successfully, 0 if there was an error
|
||||
int endPacket() override;
|
||||
// Write a single byte into the packet
|
||||
size_t write(uint8_t) override;
|
||||
// Write size bytes from buffer into the packet
|
||||
size_t write(const uint8_t *buffer, size_t size) override;
|
||||
|
||||
// Return the IP address of the host who sent the current incoming packet
|
||||
IPAddress remoteIP() override;
|
||||
// Return the port of the host who sent the current incoming packet
|
||||
uint16_t remotePort() override;
|
||||
// Return the destination address for incoming packets,
|
||||
// useful to distinguish multicast and ordinary packets
|
||||
IPAddress destinationIP() const;
|
||||
// Return the local port for outgoing packets
|
||||
uint16_t localPort() const;
|
||||
using Print::write;
|
||||
|
||||
static void stopAll();
|
||||
static void stopAllExcept(WiFiUDP * exC);
|
||||
// Start processing the next available incoming packet
|
||||
// Returns the size of the packet in bytes, or 0 if no packets are available
|
||||
int parsePacket() override;
|
||||
// Number of bytes remaining in the current packet
|
||||
int available() override;
|
||||
// Read a single byte from the current packet
|
||||
int read() override;
|
||||
// Read up to len bytes from the current packet and place them into buffer
|
||||
// Returns the number of bytes read, or 0 if none are available
|
||||
int read(unsigned char* buffer, size_t len) override;
|
||||
// Read up to len characters from the current packet and place them into buffer
|
||||
// Returns the number of characters read, or 0 if none are available
|
||||
int read(char* buffer, size_t len) override
|
||||
{
|
||||
return read((unsigned char*)buffer, len);
|
||||
};
|
||||
// Return the next byte from the current packet without moving on to the next byte
|
||||
int peek() override;
|
||||
void flush() override; // Finish reading the current packet
|
||||
|
||||
// Return the IP address of the host who sent the current incoming packet
|
||||
IPAddress remoteIP() override;
|
||||
// Return the port of the host who sent the current incoming packet
|
||||
uint16_t remotePort() override;
|
||||
// Return the destination address for incoming packets,
|
||||
// useful to distinguish multicast and ordinary packets
|
||||
IPAddress destinationIP() const;
|
||||
// Return the local port for outgoing packets
|
||||
uint16_t localPort() const;
|
||||
|
||||
static void stopAll();
|
||||
static void stopAllExcept(WiFiUDP * exC);
|
||||
|
||||
};
|
||||
|
||||
|
@ -1,23 +1,23 @@
|
||||
/*
|
||||
ClientContext.h - TCP connection handling on top of lwIP
|
||||
ClientContext.h - TCP connection handling on top of lwIP
|
||||
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This library is 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.
|
||||
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
|
||||
*/
|
||||
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 CLIENTCONTEXT_H
|
||||
#define CLIENTCONTEXT_H
|
||||
|
||||
@ -31,7 +31,7 @@ extern "C" void esp_schedule();
|
||||
|
||||
#include "DataSource.h"
|
||||
|
||||
bool getDefaultPrivateGlobalSyncValue ();
|
||||
bool getDefaultPrivateGlobalSyncValue();
|
||||
|
||||
class ClientContext
|
||||
{
|
||||
@ -53,7 +53,8 @@ public:
|
||||
|
||||
err_t abort()
|
||||
{
|
||||
if(_pcb) {
|
||||
if (_pcb)
|
||||
{
|
||||
DEBUGV(":abort\r\n");
|
||||
tcp_arg(_pcb, NULL);
|
||||
tcp_sent(_pcb, NULL);
|
||||
@ -69,7 +70,8 @@ public:
|
||||
err_t close()
|
||||
{
|
||||
err_t err = ERR_OK;
|
||||
if(_pcb) {
|
||||
if (_pcb)
|
||||
{
|
||||
DEBUGV(":close\r\n");
|
||||
tcp_arg(_pcb, NULL);
|
||||
tcp_sent(_pcb, NULL);
|
||||
@ -77,7 +79,8 @@ public:
|
||||
tcp_err(_pcb, NULL);
|
||||
tcp_poll(_pcb, NULL, 0);
|
||||
err = tcp_close(_pcb);
|
||||
if(err != ERR_OK) {
|
||||
if (err != ERR_OK)
|
||||
{
|
||||
DEBUGV(":tc err %d\r\n", (int) err);
|
||||
tcp_abort(_pcb);
|
||||
err = ERR_ABRT;
|
||||
@ -111,10 +114,12 @@ public:
|
||||
void unref()
|
||||
{
|
||||
DEBUGV(":ur %d\r\n", _refcnt);
|
||||
if(--_refcnt == 0) {
|
||||
if (--_refcnt == 0)
|
||||
{
|
||||
discard_received();
|
||||
close();
|
||||
if(_discard_cb) {
|
||||
if (_discard_cb)
|
||||
{
|
||||
_discard_cb(_discard_cb_arg, this);
|
||||
}
|
||||
DEBUGV(":del\r\n");
|
||||
@ -125,7 +130,8 @@ public:
|
||||
int connect(CONST ip_addr_t* addr, uint16_t port)
|
||||
{
|
||||
err_t err = tcp_connect(_pcb, addr, port, &ClientContext::_s_connected);
|
||||
if (err != ERR_OK) {
|
||||
if (err != ERR_OK)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
_connect_pending = 1;
|
||||
@ -133,11 +139,13 @@ public:
|
||||
// This delay will be interrupted by esp_schedule in the connect callback
|
||||
delay(_timeout_ms);
|
||||
_connect_pending = 0;
|
||||
if (!_pcb) {
|
||||
if (!_pcb)
|
||||
{
|
||||
DEBUGV(":cabrt\r\n");
|
||||
return 0;
|
||||
}
|
||||
if (state() != ESTABLISHED) {
|
||||
if (state() != ESTABLISHED)
|
||||
{
|
||||
DEBUGV(":ctmo\r\n");
|
||||
abort();
|
||||
return 0;
|
||||
@ -147,24 +155,29 @@ public:
|
||||
|
||||
size_t availableForWrite() const
|
||||
{
|
||||
return _pcb? tcp_sndbuf(_pcb): 0;
|
||||
return _pcb ? tcp_sndbuf(_pcb) : 0;
|
||||
}
|
||||
|
||||
void setNoDelay(bool nodelay)
|
||||
{
|
||||
if(!_pcb) {
|
||||
if (!_pcb)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(nodelay) {
|
||||
if (nodelay)
|
||||
{
|
||||
tcp_nagle_disable(_pcb);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
tcp_nagle_enable(_pcb);
|
||||
}
|
||||
}
|
||||
|
||||
bool getNoDelay() const
|
||||
{
|
||||
if(!_pcb) {
|
||||
if (!_pcb)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return tcp_nagle_disabled(_pcb);
|
||||
@ -182,7 +195,8 @@ public:
|
||||
|
||||
const ip_addr_t* getRemoteAddress() const
|
||||
{
|
||||
if(!_pcb) {
|
||||
if (!_pcb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -191,7 +205,8 @@ public:
|
||||
|
||||
uint16_t getRemotePort() const
|
||||
{
|
||||
if(!_pcb) {
|
||||
if (!_pcb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -200,7 +215,8 @@ public:
|
||||
|
||||
const ip_addr_t* getLocalAddress() const
|
||||
{
|
||||
if(!_pcb) {
|
||||
if (!_pcb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -209,7 +225,8 @@ public:
|
||||
|
||||
uint16_t getLocalPort() const
|
||||
{
|
||||
if(!_pcb) {
|
||||
if (!_pcb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -218,7 +235,8 @@ public:
|
||||
|
||||
size_t getSize() const
|
||||
{
|
||||
if(!_rx_buf) {
|
||||
if (!_rx_buf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -227,7 +245,8 @@ public:
|
||||
|
||||
char read()
|
||||
{
|
||||
if(!_rx_buf) {
|
||||
if (!_rx_buf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -238,7 +257,8 @@ public:
|
||||
|
||||
size_t read(char* dst, size_t size)
|
||||
{
|
||||
if(!_rx_buf) {
|
||||
if (!_rx_buf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -247,7 +267,8 @@ public:
|
||||
|
||||
DEBUGV(":rd %d, %d, %d\r\n", size, _rx_buf->tot_len, _rx_buf_offset);
|
||||
size_t size_read = 0;
|
||||
while(size) {
|
||||
while (size)
|
||||
{
|
||||
size_t buf_size = _rx_buf->len - _rx_buf_offset;
|
||||
size_t copy_size = (size < buf_size) ? size : buf_size;
|
||||
DEBUGV(":rdi %d, %d\r\n", buf_size, copy_size);
|
||||
@ -262,7 +283,8 @@ public:
|
||||
|
||||
char peek() const
|
||||
{
|
||||
if(!_rx_buf) {
|
||||
if (!_rx_buf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -271,7 +293,8 @@ public:
|
||||
|
||||
size_t peekBytes(char *dst, size_t size) const
|
||||
{
|
||||
if(!_rx_buf) {
|
||||
if (!_rx_buf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -288,10 +311,12 @@ public:
|
||||
|
||||
void discard_received()
|
||||
{
|
||||
if(!_rx_buf) {
|
||||
if (!_rx_buf)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(_pcb) {
|
||||
if (_pcb)
|
||||
{
|
||||
tcp_recved(_pcb, (size_t) _rx_buf->tot_len);
|
||||
}
|
||||
pbuf_free(_rx_buf);
|
||||
@ -306,14 +331,18 @@ public:
|
||||
// option 2 / _write_some() not necessary since _datasource is always nullptr here
|
||||
|
||||
if (!_pcb)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int prevsndbuf = -1;
|
||||
|
||||
// wait for peer's acks to flush lwIP's output buffer
|
||||
uint32_t last_sent = millis();
|
||||
while (1) {
|
||||
if (millis() - last_sent > (uint32_t) max_wait_ms) {
|
||||
while (1)
|
||||
{
|
||||
if (millis() - last_sent > (uint32_t) max_wait_ms)
|
||||
{
|
||||
#ifdef DEBUGV
|
||||
// wait until sent: timeout
|
||||
DEBUGV(":wustmo\n");
|
||||
@ -326,7 +355,8 @@ public:
|
||||
tcp_output(_pcb);
|
||||
|
||||
int sndbuf = tcp_sndbuf(_pcb);
|
||||
if (sndbuf != prevsndbuf) {
|
||||
if (sndbuf != prevsndbuf)
|
||||
{
|
||||
// send buffer has changed (or first iteration)
|
||||
prevsndbuf = sndbuf;
|
||||
// We just sent a bit, move timeout forward
|
||||
@ -335,7 +365,8 @@ public:
|
||||
|
||||
delay(0); // from sys or os context
|
||||
|
||||
if ((state() != ESTABLISHED) || (sndbuf == TCP_SND_BUF)) {
|
||||
if ((state() != ESTABLISHED) || (sndbuf == TCP_SND_BUF))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -346,7 +377,8 @@ public:
|
||||
|
||||
uint8_t state() const
|
||||
{
|
||||
if(!_pcb) {
|
||||
if (!_pcb)
|
||||
{
|
||||
return CLOSED;
|
||||
}
|
||||
|
||||
@ -355,7 +387,8 @@ public:
|
||||
|
||||
size_t write(const uint8_t* data, size_t size)
|
||||
{
|
||||
if (!_pcb) {
|
||||
if (!_pcb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return _write_from_source(new BufferDataSource(data, size));
|
||||
@ -363,7 +396,8 @@ public:
|
||||
|
||||
size_t write(Stream& stream)
|
||||
{
|
||||
if (!_pcb) {
|
||||
if (!_pcb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return _write_from_source(new BufferedStreamDataSource<Stream>(stream, stream.available()));
|
||||
@ -371,51 +405,55 @@ public:
|
||||
|
||||
size_t write_P(PGM_P buf, size_t size)
|
||||
{
|
||||
if (!_pcb) {
|
||||
if (!_pcb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
ProgmemStream stream(buf, size);
|
||||
return _write_from_source(new BufferedStreamDataSource<ProgmemStream>(stream, size));
|
||||
}
|
||||
|
||||
void keepAlive (uint16_t idle_sec = TCP_DEFAULT_KEEPALIVE_IDLE_SEC, uint16_t intv_sec = TCP_DEFAULT_KEEPALIVE_INTERVAL_SEC, uint8_t count = TCP_DEFAULT_KEEPALIVE_COUNT)
|
||||
void keepAlive(uint16_t idle_sec = TCP_DEFAULT_KEEPALIVE_IDLE_SEC, uint16_t intv_sec = TCP_DEFAULT_KEEPALIVE_INTERVAL_SEC, uint8_t count = TCP_DEFAULT_KEEPALIVE_COUNT)
|
||||
{
|
||||
if (idle_sec && intv_sec && count) {
|
||||
if (idle_sec && intv_sec && count)
|
||||
{
|
||||
_pcb->so_options |= SOF_KEEPALIVE;
|
||||
_pcb->keep_idle = (uint32_t)1000 * idle_sec;
|
||||
_pcb->keep_intvl = (uint32_t)1000 * intv_sec;
|
||||
_pcb->keep_cnt = count;
|
||||
}
|
||||
else
|
||||
{
|
||||
_pcb->so_options &= ~SOF_KEEPALIVE;
|
||||
}
|
||||
}
|
||||
|
||||
bool isKeepAliveEnabled () const
|
||||
bool isKeepAliveEnabled() const
|
||||
{
|
||||
return !!(_pcb->so_options & SOF_KEEPALIVE);
|
||||
}
|
||||
|
||||
uint16_t getKeepAliveIdle () const
|
||||
uint16_t getKeepAliveIdle() const
|
||||
{
|
||||
return isKeepAliveEnabled()? (_pcb->keep_idle + 500) / 1000: 0;
|
||||
return isKeepAliveEnabled() ? (_pcb->keep_idle + 500) / 1000 : 0;
|
||||
}
|
||||
|
||||
uint16_t getKeepAliveInterval () const
|
||||
uint16_t getKeepAliveInterval() const
|
||||
{
|
||||
return isKeepAliveEnabled()? (_pcb->keep_intvl + 500) / 1000: 0;
|
||||
return isKeepAliveEnabled() ? (_pcb->keep_intvl + 500) / 1000 : 0;
|
||||
}
|
||||
|
||||
uint8_t getKeepAliveCount () const
|
||||
uint8_t getKeepAliveCount() const
|
||||
{
|
||||
return isKeepAliveEnabled()? _pcb->keep_cnt: 0;
|
||||
return isKeepAliveEnabled() ? _pcb->keep_cnt : 0;
|
||||
}
|
||||
|
||||
bool getSync () const
|
||||
bool getSync() const
|
||||
{
|
||||
return _sync;
|
||||
}
|
||||
|
||||
void setSync (bool sync)
|
||||
void setSync(bool sync)
|
||||
{
|
||||
_sync = sync;
|
||||
}
|
||||
@ -429,7 +467,8 @@ protected:
|
||||
|
||||
void _notify_error()
|
||||
{
|
||||
if (_connect_pending || _send_waiting) {
|
||||
if (_connect_pending || _send_waiting)
|
||||
{
|
||||
esp_schedule();
|
||||
}
|
||||
}
|
||||
@ -441,13 +480,17 @@ protected:
|
||||
_datasource = ds;
|
||||
_written = 0;
|
||||
_op_start_time = millis();
|
||||
do {
|
||||
if (_write_some()) {
|
||||
do
|
||||
{
|
||||
if (_write_some())
|
||||
{
|
||||
_op_start_time = millis();
|
||||
}
|
||||
|
||||
if (!_datasource->available() || _is_timeout() || state() == CLOSED) {
|
||||
if (_is_timeout()) {
|
||||
if (!_datasource->available() || _is_timeout() || state() == CLOSED)
|
||||
{
|
||||
if (_is_timeout())
|
||||
{
|
||||
DEBUGV(":wtmo\r\n");
|
||||
}
|
||||
delete _datasource;
|
||||
@ -457,18 +500,21 @@ protected:
|
||||
|
||||
++_send_waiting;
|
||||
esp_yield();
|
||||
} while(true);
|
||||
} while (true);
|
||||
_send_waiting = 0;
|
||||
|
||||
if (_sync)
|
||||
{
|
||||
wait_until_sent();
|
||||
}
|
||||
|
||||
return _written;
|
||||
}
|
||||
|
||||
bool _write_some()
|
||||
{
|
||||
if (!_datasource || !_pcb) {
|
||||
if (!_datasource || !_pcb)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -476,12 +522,17 @@ protected:
|
||||
|
||||
bool has_written = false;
|
||||
|
||||
while (_datasource) {
|
||||
while (_datasource)
|
||||
{
|
||||
if (state() == CLOSED)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
size_t next_chunk_size = std::min((size_t)tcp_sndbuf(_pcb), _datasource->available());
|
||||
if (!next_chunk_size)
|
||||
{
|
||||
break;
|
||||
}
|
||||
const uint8_t* buf = _datasource->get_buffer(next_chunk_size);
|
||||
|
||||
uint8_t flags = 0;
|
||||
@ -491,23 +542,30 @@ protected:
|
||||
// PUSH does not break Nagle
|
||||
// #5173: windows needs this flag
|
||||
// more info: https://lists.gnu.org/archive/html/lwip-users/2009-11/msg00018.html
|
||||
flags |= TCP_WRITE_FLAG_MORE; // do not tcp-PuSH (yet)
|
||||
{
|
||||
flags |= TCP_WRITE_FLAG_MORE; // do not tcp-PuSH (yet)
|
||||
}
|
||||
if (!_sync)
|
||||
// user data must be copied when data are sent but not yet acknowledged
|
||||
// (with sync, we wait for acknowledgment before returning to user)
|
||||
{
|
||||
flags |= TCP_WRITE_FLAG_COPY;
|
||||
}
|
||||
|
||||
err_t err = tcp_write(_pcb, buf, next_chunk_size, flags);
|
||||
|
||||
DEBUGV(":wrc %d %d %d\r\n", next_chunk_size, _datasource->available(), (int)err);
|
||||
|
||||
if (err == ERR_OK) {
|
||||
if (err == ERR_OK)
|
||||
{
|
||||
_datasource->release_buffer(buf, next_chunk_size);
|
||||
_written += next_chunk_size;
|
||||
has_written = true;
|
||||
} else {
|
||||
// ERR_MEM(-1) is a valid error meaning
|
||||
// "come back later". It leaves state() opened
|
||||
}
|
||||
else
|
||||
{
|
||||
// ERR_MEM(-1) is a valid error meaning
|
||||
// "come back later". It leaves state() opened
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -525,7 +583,8 @@ protected:
|
||||
|
||||
void _write_some_from_cb()
|
||||
{
|
||||
if (_send_waiting == 1) {
|
||||
if (_send_waiting == 1)
|
||||
{
|
||||
_send_waiting--;
|
||||
esp_schedule();
|
||||
}
|
||||
@ -542,17 +601,24 @@ protected:
|
||||
|
||||
void _consume(size_t size)
|
||||
{
|
||||
if(_pcb)
|
||||
if (_pcb)
|
||||
{
|
||||
tcp_recved(_pcb, size);
|
||||
}
|
||||
ptrdiff_t left = _rx_buf->len - _rx_buf_offset - size;
|
||||
if(left > 0) {
|
||||
if (left > 0)
|
||||
{
|
||||
_rx_buf_offset += size;
|
||||
} else if(!_rx_buf->next) {
|
||||
}
|
||||
else if (!_rx_buf->next)
|
||||
{
|
||||
DEBUGV(":c0 %d, %d\r\n", size, _rx_buf->tot_len);
|
||||
pbuf_free(_rx_buf);
|
||||
_rx_buf = 0;
|
||||
_rx_buf_offset = 0;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUGV(":c %d, %d, %d\r\n", size, _rx_buf->len, _rx_buf->tot_len);
|
||||
auto head = _rx_buf;
|
||||
_rx_buf = _rx_buf->next;
|
||||
@ -566,17 +632,21 @@ protected:
|
||||
{
|
||||
(void) pcb;
|
||||
(void) err;
|
||||
if(pb == 0) { // connection closed
|
||||
if (pb == 0) // connection closed
|
||||
{
|
||||
DEBUGV(":rcl\r\n");
|
||||
_notify_error();
|
||||
abort();
|
||||
return ERR_ABRT;
|
||||
}
|
||||
|
||||
if(_rx_buf) {
|
||||
if (_rx_buf)
|
||||
{
|
||||
DEBUGV(":rch %d, %d\r\n", _rx_buf->tot_len, pb->tot_len);
|
||||
pbuf_cat(_rx_buf, pb);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUGV(":rn %d\r\n", pb->tot_len);
|
||||
_rx_buf = pb;
|
||||
_rx_buf_offset = 0;
|
||||
|
@ -1,13 +1,14 @@
|
||||
/* DataSource.h - a read-only object similar to Stream, but with less methods
|
||||
* Copyright (c) 2016 Ivan Grokhotkov. All rights reserved.
|
||||
* This file is distributed under MIT license.
|
||||
*/
|
||||
/* DataSource.h - a read-only object similar to Stream, but with less methods
|
||||
Copyright (c) 2016 Ivan Grokhotkov. All rights reserved.
|
||||
This file is distributed under MIT license.
|
||||
*/
|
||||
#ifndef DATASOURCE_H
|
||||
#define DATASOURCE_H
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
class DataSource {
|
||||
class DataSource
|
||||
{
|
||||
public:
|
||||
virtual ~DataSource() {}
|
||||
virtual size_t available() = 0;
|
||||
@ -16,7 +17,8 @@ public:
|
||||
|
||||
};
|
||||
|
||||
class BufferDataSource : public DataSource {
|
||||
class BufferDataSource : public DataSource
|
||||
{
|
||||
public:
|
||||
BufferDataSource(const uint8_t* data, size_t size) :
|
||||
_data(data),
|
||||
@ -50,7 +52,8 @@ protected:
|
||||
};
|
||||
|
||||
template<typename TStream>
|
||||
class BufferedStreamDataSource : public DataSource {
|
||||
class BufferedStreamDataSource : public DataSource
|
||||
{
|
||||
public:
|
||||
BufferedStreamDataSource(TStream& stream, size_t size) :
|
||||
_stream(stream),
|
||||
@ -74,10 +77,12 @@ public:
|
||||
const size_t min_buffer_size = size > stream_read ? size : stream_read;
|
||||
|
||||
//Buffer too small?
|
||||
if (_bufferSize < min_buffer_size) {
|
||||
if (_bufferSize < min_buffer_size)
|
||||
{
|
||||
uint8_t *new_buffer = new uint8_t[min_buffer_size];
|
||||
//If stream reading is ahead, than some data is already in the old buffer and needs to be copied to new resized buffer
|
||||
if (_buffer && stream_read > 0) {
|
||||
if (_buffer && stream_read > 0)
|
||||
{
|
||||
memcpy(new_buffer, _buffer.get(), stream_read);
|
||||
}
|
||||
_buffer.reset(new_buffer);
|
||||
@ -86,7 +91,8 @@ public:
|
||||
|
||||
//Fetch remaining data from stream
|
||||
//If error in tcp_write in ClientContext::_write_some() occured earlier and therefore release_buffer was not called last time, than the requested stream data is already in the buffer.
|
||||
if (size > stream_read) {
|
||||
if (size > stream_read)
|
||||
{
|
||||
//Remaining bytes to read from stream
|
||||
const size_t stream_rem = size - stream_read;
|
||||
const size_t cb = _stream.readBytes(reinterpret_cast<char*>(_buffer.get() + stream_read), stream_rem);
|
||||
@ -100,18 +106,20 @@ public:
|
||||
|
||||
void release_buffer(const uint8_t* buffer, size_t size) override
|
||||
{
|
||||
if (size == 0) {
|
||||
if (size == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
(void)buffer;
|
||||
_pos += size;
|
||||
_pos += size;
|
||||
|
||||
//Cannot release more than acquired through get_buffer
|
||||
assert(_pos <= _streamPos);
|
||||
|
||||
//Release less than requested with get_buffer?
|
||||
if (_pos < _streamPos) {
|
||||
if (_pos < _streamPos)
|
||||
{
|
||||
// Move unreleased stream data in buffer to front
|
||||
assert(_buffer);
|
||||
memmove(_buffer.get(), _buffer.get() + size, _streamPos - _pos);
|
||||
|
@ -1,22 +1,22 @@
|
||||
/*
|
||||
SSLContext.h - Used by WiFiClientAxTLS
|
||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
SSLContext.h - Used by WiFiClientAxTLS
|
||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This library is 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.
|
||||
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
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
@ -41,16 +41,20 @@ extern "C"
|
||||
#include <WiFiClientSecureAxTLS.h>
|
||||
#include "c_types.h"
|
||||
|
||||
namespace axTLS {
|
||||
namespace axTLS
|
||||
{
|
||||
|
||||
typedef struct BufferItem
|
||||
{
|
||||
BufferItem(const uint8_t* data_, size_t size_)
|
||||
: size(size_), data(new uint8_t[size])
|
||||
: size(size_), data(new uint8_t[size])
|
||||
{
|
||||
if (data.get() != nullptr) {
|
||||
if (data.get() != nullptr)
|
||||
{
|
||||
memcpy(data.get(), data_, size);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUGV(":wcs alloc %d failed\r\n", size_);
|
||||
size = 0;
|
||||
}
|
||||
@ -68,13 +72,18 @@ public:
|
||||
SSLContext(bool isServer = false)
|
||||
{
|
||||
_isServer = isServer;
|
||||
if (!_isServer) {
|
||||
if (_ssl_client_ctx_refcnt == 0) {
|
||||
if (!_isServer)
|
||||
{
|
||||
if (_ssl_client_ctx_refcnt == 0)
|
||||
{
|
||||
_ssl_client_ctx = ssl_ctx_new(SSL_SERVER_VERIFY_LATER | SSL_DEBUG_OPTS | SSL_CONNECT_IN_PARTS | SSL_READ_BLOCKING | SSL_NO_DEFAULT_KEY, 0);
|
||||
}
|
||||
++_ssl_client_ctx_refcnt;
|
||||
} else {
|
||||
if (_ssl_svr_ctx_refcnt == 0) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_ssl_svr_ctx_refcnt == 0)
|
||||
{
|
||||
_ssl_svr_ctx = ssl_ctx_new(SSL_SERVER_VERIFY_LATER | SSL_DEBUG_OPTS | SSL_CONNECT_IN_PARTS | SSL_READ_BLOCKING | SSL_NO_DEFAULT_KEY, 0);
|
||||
}
|
||||
++_ssl_svr_ctx_refcnt;
|
||||
@ -83,20 +92,26 @@ public:
|
||||
|
||||
~SSLContext()
|
||||
{
|
||||
if (io_ctx) {
|
||||
if (io_ctx)
|
||||
{
|
||||
io_ctx->unref();
|
||||
io_ctx = nullptr;
|
||||
}
|
||||
_ssl = nullptr;
|
||||
if (!_isServer) {
|
||||
if (!_isServer)
|
||||
{
|
||||
--_ssl_client_ctx_refcnt;
|
||||
if (_ssl_client_ctx_refcnt == 0) {
|
||||
if (_ssl_client_ctx_refcnt == 0)
|
||||
{
|
||||
ssl_ctx_free(_ssl_client_ctx);
|
||||
_ssl_client_ctx = nullptr;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
--_ssl_svr_ctx_refcnt;
|
||||
if (_ssl_svr_ctx_refcnt == 0) {
|
||||
if (_ssl_svr_ctx_refcnt == 0)
|
||||
{
|
||||
ssl_ctx_free(_ssl_svr_ctx);
|
||||
_ssl_svr_ctx = nullptr;
|
||||
}
|
||||
@ -112,10 +127,11 @@ public:
|
||||
{
|
||||
SSL_EXTENSIONS* ext = ssl_ext_new();
|
||||
ssl_ext_set_host_name(ext, hostName);
|
||||
if (_ssl) {
|
||||
/* Creating a new TLS session on top of a new TCP connection.
|
||||
ssl_free will want to send a close notify alert, but the old TCP connection
|
||||
is already gone at this point, so reset io_ctx. */
|
||||
if (_ssl)
|
||||
{
|
||||
/* Creating a new TLS session on top of a new TCP connection.
|
||||
ssl_free will want to send a close notify alert, but the old TCP connection
|
||||
is already gone at this point, so reset io_ctx. */
|
||||
io_ctx = nullptr;
|
||||
_ssl = nullptr;
|
||||
_available = 0;
|
||||
@ -131,10 +147,12 @@ public:
|
||||
|
||||
uint32_t t = millis();
|
||||
|
||||
while (millis() - t < timeout_ms && ssl_handshake_status(_ssl.get()) != SSL_OK) {
|
||||
while (millis() - t < timeout_ms && ssl_handshake_status(_ssl.get()) != SSL_OK)
|
||||
{
|
||||
uint8_t* data;
|
||||
int rc = ssl_read(_ssl.get(), &data);
|
||||
if (rc < SSL_OK) {
|
||||
if (rc < SSL_OK)
|
||||
{
|
||||
ssl_display_error(rc);
|
||||
break;
|
||||
}
|
||||
@ -147,16 +165,18 @@ public:
|
||||
ctx->ref();
|
||||
|
||||
// Wrap the new SSL with a smart pointer, custom deleter to call ssl_free
|
||||
SSL *_new_ssl = ssl_server_new(_ssl_svr_ctx, reinterpret_cast<int>(this));
|
||||
SSL *_new_ssl = ssl_server_new(_ssl_svr_ctx, reinterpret_cast<int>(this));
|
||||
std::shared_ptr<SSL> _new_ssl_shared(_new_ssl, _delete_shared_SSL);
|
||||
_ssl = _new_ssl_shared;
|
||||
|
||||
uint32_t t = millis();
|
||||
|
||||
while (millis() - t < timeout_ms && ssl_handshake_status(_ssl.get()) != SSL_OK) {
|
||||
while (millis() - t < timeout_ms && ssl_handshake_status(_ssl.get()) != SSL_OK)
|
||||
{
|
||||
uint8_t* data;
|
||||
int rc = ssl_read(_ssl.get(), &data);
|
||||
if (rc < SSL_OK) {
|
||||
if (rc < SSL_OK)
|
||||
{
|
||||
ssl_display_error(rc);
|
||||
break;
|
||||
}
|
||||
@ -165,7 +185,8 @@ public:
|
||||
|
||||
void stop()
|
||||
{
|
||||
if (io_ctx) {
|
||||
if (io_ctx)
|
||||
{
|
||||
io_ctx->unref();
|
||||
}
|
||||
io_ctx = nullptr;
|
||||
@ -173,17 +194,22 @@ public:
|
||||
|
||||
bool connected()
|
||||
{
|
||||
if (_isServer) {
|
||||
if (_isServer)
|
||||
{
|
||||
return _ssl != nullptr;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return _ssl != nullptr && ssl_handshake_status(_ssl.get()) == SSL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
int read(uint8_t* dst, size_t size)
|
||||
{
|
||||
if (!_available) {
|
||||
if (!_readAll()) {
|
||||
if (!_available)
|
||||
{
|
||||
if (!_readAll())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -191,10 +217,12 @@ public:
|
||||
memcpy(dst, _read_ptr, will_copy);
|
||||
_read_ptr += will_copy;
|
||||
_available -= will_copy;
|
||||
if (_available == 0) {
|
||||
if (_available == 0)
|
||||
{
|
||||
_read_ptr = nullptr;
|
||||
/* Send pending outgoing data, if any */
|
||||
if (_hasWriteBuffers()) {
|
||||
if (_hasWriteBuffers())
|
||||
{
|
||||
_writeBuffersSend();
|
||||
}
|
||||
}
|
||||
@ -203,18 +231,22 @@ public:
|
||||
|
||||
int read()
|
||||
{
|
||||
if (!_available) {
|
||||
if (!_readAll()) {
|
||||
if (!_available)
|
||||
{
|
||||
if (!_readAll())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
int result = _read_ptr[0];
|
||||
++_read_ptr;
|
||||
--_available;
|
||||
if (_available == 0) {
|
||||
if (_available == 0)
|
||||
{
|
||||
_read_ptr = nullptr;
|
||||
/* Send pending outgoing data, if any */
|
||||
if (_hasWriteBuffers()) {
|
||||
if (_hasWriteBuffers())
|
||||
{
|
||||
_writeBuffersSend();
|
||||
}
|
||||
}
|
||||
@ -223,30 +255,37 @@ public:
|
||||
|
||||
int write(const uint8_t* src, size_t size)
|
||||
{
|
||||
if (_isServer) {
|
||||
if (_isServer)
|
||||
{
|
||||
return _write(src, size);
|
||||
} else if (!_available) {
|
||||
if (_hasWriteBuffers()) {
|
||||
}
|
||||
else if (!_available)
|
||||
{
|
||||
if (_hasWriteBuffers())
|
||||
{
|
||||
int rc = _writeBuffersSend();
|
||||
if (rc < 0) {
|
||||
if (rc < 0)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
return _write(src, size);
|
||||
}
|
||||
/* Some received data is still present in the axtls fragment buffer.
|
||||
We can't call ssl_write now, as that will overwrite the contents of
|
||||
the fragment buffer, corrupting the received data.
|
||||
Save a copy of the outgoing data, and call ssl_write when all
|
||||
recevied data has been consumed by the application.
|
||||
/* Some received data is still present in the axtls fragment buffer.
|
||||
We can't call ssl_write now, as that will overwrite the contents of
|
||||
the fragment buffer, corrupting the received data.
|
||||
Save a copy of the outgoing data, and call ssl_write when all
|
||||
recevied data has been consumed by the application.
|
||||
*/
|
||||
return _writeBufferAdd(src, size);
|
||||
}
|
||||
|
||||
int peek()
|
||||
{
|
||||
if (!_available) {
|
||||
if (!_readAll()) {
|
||||
if (!_available)
|
||||
{
|
||||
if (!_readAll())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -255,8 +294,10 @@ public:
|
||||
|
||||
size_t peekBytes(char *dst, size_t size)
|
||||
{
|
||||
if (!_available) {
|
||||
if (!_readAll()) {
|
||||
if (!_available)
|
||||
{
|
||||
if (!_readAll())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -269,9 +310,12 @@ public:
|
||||
int available()
|
||||
{
|
||||
auto cb = _available;
|
||||
if (cb == 0) {
|
||||
if (cb == 0)
|
||||
{
|
||||
cb = _readAll();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
optimistic_yield(100);
|
||||
}
|
||||
return cb;
|
||||
@ -286,13 +330,15 @@ public:
|
||||
bool loadObject(int type, Stream& stream, size_t size)
|
||||
{
|
||||
std::unique_ptr<uint8_t[]> buf(new uint8_t[size]);
|
||||
if (!buf.get()) {
|
||||
if (!buf.get())
|
||||
{
|
||||
DEBUGV("loadObject: failed to allocate memory\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t cb = stream.readBytes(buf.get(), size);
|
||||
if (cb != size) {
|
||||
if (cb != size)
|
||||
{
|
||||
DEBUGV("loadObject: reading %u bytes, got %u\n", size, cb);
|
||||
return false;
|
||||
}
|
||||
@ -303,14 +349,15 @@ public:
|
||||
bool loadObject_P(int type, PGM_VOID_P data, size_t size)
|
||||
{
|
||||
std::unique_ptr<uint8_t[]> buf(new uint8_t[size]);
|
||||
memcpy_P(buf.get(),data, size);
|
||||
memcpy_P(buf.get(), data, size);
|
||||
return loadObject(type, buf.get(), size);
|
||||
}
|
||||
|
||||
bool loadObject(int type, const uint8_t* data, size_t size)
|
||||
{
|
||||
int rc = ssl_obj_memory_load(_isServer?_ssl_svr_ctx:_ssl_client_ctx, type, data, static_cast<int>(size), nullptr);
|
||||
if (rc != SSL_OK) {
|
||||
int rc = ssl_obj_memory_load(_isServer ? _ssl_svr_ctx : _ssl_client_ctx, type, data, static_cast<int>(size), nullptr);
|
||||
if (rc != SSL_OK)
|
||||
{
|
||||
DEBUGV("loadObject: ssl_obj_memory_load returned %d\n", rc);
|
||||
return false;
|
||||
}
|
||||
@ -320,10 +367,13 @@ public:
|
||||
bool verifyCert()
|
||||
{
|
||||
int rc = ssl_verify_cert(_ssl.get());
|
||||
if (_allowSelfSignedCerts && rc == SSL_X509_ERROR(X509_VFY_ERROR_SELF_SIGNED)) {
|
||||
if (_allowSelfSignedCerts && rc == SSL_X509_ERROR(X509_VFY_ERROR_SELF_SIGNED))
|
||||
{
|
||||
DEBUGV("Allowing self-signed certificate\n");
|
||||
return true;
|
||||
} else if (rc != SSL_OK) {
|
||||
}
|
||||
else if (rc != SSL_OK)
|
||||
{
|
||||
DEBUGV("ssl_verify_cert returned %d\n", rc);
|
||||
ssl_display_error(rc);
|
||||
return false;
|
||||
@ -343,7 +393,8 @@ public:
|
||||
|
||||
static ClientContext* getIOContext(int fd)
|
||||
{
|
||||
if (fd) {
|
||||
if (fd)
|
||||
{
|
||||
SSLContext *thisSSL = reinterpret_cast<SSLContext*>(fd);
|
||||
return thisSSL->io_ctx;
|
||||
}
|
||||
@ -353,7 +404,8 @@ public:
|
||||
protected:
|
||||
int _readAll()
|
||||
{
|
||||
if (!_ssl) {
|
||||
if (!_ssl)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -361,8 +413,10 @@ protected:
|
||||
|
||||
uint8_t* data;
|
||||
int rc = ssl_read(_ssl.get(), &data);
|
||||
if (rc <= 0) {
|
||||
if (rc < SSL_OK && rc != SSL_CLOSE_NOTIFY && rc != SSL_ERROR_CONN_LOST) {
|
||||
if (rc <= 0)
|
||||
{
|
||||
if (rc < SSL_OK && rc != SSL_CLOSE_NOTIFY && rc != SSL_ERROR_CONN_LOST)
|
||||
{
|
||||
_ssl = nullptr;
|
||||
}
|
||||
return 0;
|
||||
@ -375,12 +429,14 @@ protected:
|
||||
|
||||
int _write(const uint8_t* src, size_t size)
|
||||
{
|
||||
if (!_ssl) {
|
||||
if (!_ssl)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rc = ssl_write(_ssl.get(), src, size);
|
||||
if (rc >= 0) {
|
||||
if (rc >= 0)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
DEBUGV(":wcs write rc=%d\r\n", rc);
|
||||
@ -389,12 +445,14 @@ protected:
|
||||
|
||||
int _writeBufferAdd(const uint8_t* data, size_t size)
|
||||
{
|
||||
if (!_ssl) {
|
||||
if (!_ssl)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
_writeBuffers.emplace_back(data, size);
|
||||
if (_writeBuffers.back().data.get() == nullptr) {
|
||||
if (_writeBuffers.back().data.get() == nullptr)
|
||||
{
|
||||
_writeBuffers.pop_back();
|
||||
return 0;
|
||||
}
|
||||
@ -403,12 +461,15 @@ protected:
|
||||
|
||||
int _writeBuffersSend()
|
||||
{
|
||||
while (!_writeBuffers.empty()) {
|
||||
while (!_writeBuffers.empty())
|
||||
{
|
||||
auto& first = _writeBuffers.front();
|
||||
int rc = _write(first.data.get(), first.size);
|
||||
_writeBuffers.pop_front();
|
||||
if (rc < 0) {
|
||||
if (_hasWriteBuffers()) {
|
||||
if (rc < 0)
|
||||
{
|
||||
if (_hasWriteBuffers())
|
||||
{
|
||||
DEBUGV(":wcs _writeBuffersSend dropping unsent data\r\n");
|
||||
_writeBuffers.clear();
|
||||
}
|
||||
|
@ -1,22 +1,22 @@
|
||||
/*
|
||||
UdpContext.h - UDP connection handling on top of lwIP
|
||||
UdpContext.h - UDP connection handling on top of lwIP
|
||||
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This library is 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.
|
||||
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
|
||||
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 UDPCONTEXT_H
|
||||
#define UDPCONTEXT_H
|
||||
@ -24,8 +24,8 @@
|
||||
class UdpContext;
|
||||
|
||||
extern "C" {
|
||||
void esp_yield();
|
||||
void esp_schedule();
|
||||
void esp_yield();
|
||||
void esp_schedule();
|
||||
#include "lwip/init.h" // LWIP_VERSION_
|
||||
#include <assert.h>
|
||||
}
|
||||
@ -42,14 +42,14 @@ public:
|
||||
typedef std::function<void(void)> rxhandler_t;
|
||||
|
||||
UdpContext()
|
||||
: _pcb(0)
|
||||
, _rx_buf(0)
|
||||
, _first_buf_taken(false)
|
||||
, _rx_buf_offset(0)
|
||||
, _refcnt(0)
|
||||
, _tx_buf_head(0)
|
||||
, _tx_buf_cur(0)
|
||||
, _tx_buf_offset(0)
|
||||
: _pcb(0)
|
||||
, _rx_buf(0)
|
||||
, _first_buf_taken(false)
|
||||
, _rx_buf_offset(0)
|
||||
, _refcnt(0)
|
||||
, _tx_buf_head(0)
|
||||
, _tx_buf_cur(0)
|
||||
, _tx_buf_offset(0)
|
||||
{
|
||||
_pcb = udp_new();
|
||||
#ifdef LWIP_MAYBE_XCC
|
||||
@ -83,9 +83,11 @@ public:
|
||||
|
||||
void unref()
|
||||
{
|
||||
if(this != 0) {
|
||||
if (this != 0)
|
||||
{
|
||||
DEBUGV(":ur %d\r\n", _refcnt);
|
||||
if(--_refcnt == 0) {
|
||||
if (--_refcnt == 0)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
@ -142,7 +144,7 @@ public:
|
||||
|
||||
if (!addr.isV4())
|
||||
{
|
||||
for (auto a: addrList)
|
||||
for (auto a : addrList)
|
||||
if (a.addr() == addr)
|
||||
{
|
||||
// found the IPv6 address,
|
||||
@ -179,14 +181,17 @@ public:
|
||||
|
||||
// warning: handler is called from tcp stack context
|
||||
// esp_yield and non-reentrant functions which depend on it will fail
|
||||
void onRx(rxhandler_t handler) {
|
||||
void onRx(rxhandler_t handler)
|
||||
{
|
||||
_on_rx = handler;
|
||||
}
|
||||
|
||||
size_t getSize() const
|
||||
{
|
||||
if (!_rx_buf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _rx_buf->len - _rx_buf_offset;
|
||||
}
|
||||
@ -202,7 +207,8 @@ public:
|
||||
_rx_buf_offset = pos;
|
||||
}
|
||||
|
||||
bool isValidOffset(const size_t pos) const {
|
||||
bool isValidOffset(const size_t pos) const
|
||||
{
|
||||
return (pos <= _rx_buf->len);
|
||||
}
|
||||
|
||||
@ -224,14 +230,18 @@ public:
|
||||
uint16_t getLocalPort() const
|
||||
{
|
||||
if (!_pcb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return _pcb->local_port;
|
||||
}
|
||||
|
||||
bool next()
|
||||
{
|
||||
if (!_rx_buf)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!_first_buf_taken)
|
||||
{
|
||||
_first_buf_taken = true;
|
||||
@ -272,7 +282,9 @@ public:
|
||||
int read()
|
||||
{
|
||||
if (!_rx_buf || _rx_buf_offset >= _rx_buf->len)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
char c = reinterpret_cast<char*>(_rx_buf->payload)[_rx_buf_offset];
|
||||
_consume(1);
|
||||
@ -282,7 +294,9 @@ public:
|
||||
size_t read(char* dst, size_t size)
|
||||
{
|
||||
if (!_rx_buf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t max_size = _rx_buf->len - _rx_buf_offset;
|
||||
size = (size < max_size) ? size : max_size;
|
||||
@ -297,7 +311,9 @@ public:
|
||||
int peek() const
|
||||
{
|
||||
if (!_rx_buf || _rx_buf_offset == _rx_buf->len)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return reinterpret_cast<char*>(_rx_buf->payload)[_rx_buf_offset];
|
||||
}
|
||||
@ -306,7 +322,9 @@ public:
|
||||
{
|
||||
//XXX this does not follow Arduino's flush definition
|
||||
if (!_rx_buf)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_consume(_rx_buf->len - _rx_buf_offset);
|
||||
}
|
||||
@ -324,7 +342,7 @@ public:
|
||||
}
|
||||
|
||||
size_t left_to_copy = size;
|
||||
while(left_to_copy)
|
||||
while (left_to_copy)
|
||||
{
|
||||
// size already used in current pbuf
|
||||
size_t used_cur = _tx_buf_offset - (_tx_buf_head->tot_len - _tx_buf_cur->tot_len);
|
||||
@ -347,12 +365,15 @@ public:
|
||||
{
|
||||
size_t data_size = _tx_buf_offset;
|
||||
pbuf* tx_copy = pbuf_alloc(PBUF_TRANSPORT, data_size, PBUF_RAM);
|
||||
if(!tx_copy){
|
||||
if (!tx_copy)
|
||||
{
|
||||
DEBUGV("failed pbuf_alloc");
|
||||
}
|
||||
else{
|
||||
else
|
||||
{
|
||||
uint8_t* dst = reinterpret_cast<uint8_t*>(tx_copy->payload);
|
||||
for (pbuf* p = _tx_buf_head; p; p = p->next) {
|
||||
for (pbuf* p = _tx_buf_head; p; p = p->next)
|
||||
{
|
||||
size_t will_copy = (data_size < p->len) ? data_size : p->len;
|
||||
memcpy(dst, p->payload, will_copy);
|
||||
dst += will_copy;
|
||||
@ -360,27 +381,33 @@ public:
|
||||
}
|
||||
}
|
||||
if (_tx_buf_head)
|
||||
{
|
||||
pbuf_free(_tx_buf_head);
|
||||
}
|
||||
_tx_buf_head = 0;
|
||||
_tx_buf_cur = 0;
|
||||
_tx_buf_offset = 0;
|
||||
if(!tx_copy){
|
||||
if (!tx_copy)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (!addr) {
|
||||
if (!addr)
|
||||
{
|
||||
addr = &_pcb->remote_ip;
|
||||
port = _pcb->remote_port;
|
||||
}
|
||||
#ifdef LWIP_MAYBE_XCC
|
||||
uint16_t old_ttl = _pcb->ttl;
|
||||
if (ip_addr_ismulticast(addr)) {
|
||||
if (ip_addr_ismulticast(addr))
|
||||
{
|
||||
_pcb->ttl = _mcast_ttl;
|
||||
}
|
||||
#endif
|
||||
err_t err = udp_sendto(_pcb, tx_copy, addr, port);
|
||||
if (err != ERR_OK) {
|
||||
if (err != ERR_OK)
|
||||
{
|
||||
DEBUGV(":ust rc=%d\r\n", (int) err);
|
||||
}
|
||||
#ifdef LWIP_MAYBE_XCC
|
||||
@ -408,11 +435,13 @@ private:
|
||||
|
||||
size_t cur_size = _tx_buf_head->tot_len;
|
||||
if (size < cur_size)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
size_t grow_size = size - cur_size;
|
||||
|
||||
while(grow_size)
|
||||
while (grow_size)
|
||||
{
|
||||
pbuf* pb = pbuf_alloc(PBUF_TRANSPORT, pbuf_unit_size, PBUF_RAM);
|
||||
if (!pb)
|
||||
@ -421,7 +450,9 @@ private:
|
||||
}
|
||||
pbuf_cat(_tx_buf_head, pb);
|
||||
if (grow_size < pbuf_unit_size)
|
||||
{
|
||||
return;
|
||||
}
|
||||
grow_size -= pbuf_unit_size;
|
||||
}
|
||||
}
|
||||
@ -429,20 +460,21 @@ private:
|
||||
void _consume(size_t size)
|
||||
{
|
||||
_rx_buf_offset += size;
|
||||
if (_rx_buf_offset > _rx_buf->len) {
|
||||
if (_rx_buf_offset > _rx_buf->len)
|
||||
{
|
||||
_rx_buf_offset = _rx_buf->len;
|
||||
}
|
||||
}
|
||||
|
||||
void _recv(udp_pcb *upcb, pbuf *pb,
|
||||
const ip_addr_t *srcaddr, u16_t srcport)
|
||||
const ip_addr_t *srcaddr, u16_t srcport)
|
||||
{
|
||||
(void) upcb;
|
||||
|
||||
#if LWIP_VERSION_MAJOR == 1
|
||||
#define TEMPDSTADDR (¤t_iphdr_dest)
|
||||
#define TEMPDSTADDR (¤t_iphdr_dest)
|
||||
#else
|
||||
#define TEMPDSTADDR (ip_current_dest_addr())
|
||||
#define TEMPDSTADDR (ip_current_dest_addr())
|
||||
#endif
|
||||
|
||||
// chain this helper pbuf first
|
||||
@ -470,7 +502,7 @@ private:
|
||||
return;
|
||||
}
|
||||
// construct in place
|
||||
new(PBUF_ALIGNER(pb_helper->payload)) AddrHelper(srcaddr, TEMPDSTADDR, srcport);
|
||||
new (PBUF_ALIGNER(pb_helper->payload)) AddrHelper(srcaddr, TEMPDSTADDR, srcport);
|
||||
// chain it
|
||||
pbuf_cat(_rx_buf, pb_helper);
|
||||
|
||||
@ -490,17 +522,18 @@ private:
|
||||
_rx_buf_offset = 0;
|
||||
}
|
||||
|
||||
if (_on_rx) {
|
||||
if (_on_rx)
|
||||
{
|
||||
_on_rx();
|
||||
}
|
||||
|
||||
#undef TEMPDSTADDR
|
||||
#undef TEMPDSTADDR
|
||||
|
||||
}
|
||||
|
||||
static void _s_recv(void *arg,
|
||||
udp_pcb *upcb, pbuf *p,
|
||||
CONST ip_addr_t *srcaddr, u16_t srcport)
|
||||
udp_pcb *upcb, pbuf *p,
|
||||
CONST ip_addr_t *srcaddr, u16_t srcport)
|
||||
{
|
||||
reinterpret_cast<UdpContext*>(arg)->_recv(upcb, p, srcaddr, srcport);
|
||||
}
|
||||
|
@ -2,36 +2,42 @@
|
||||
#define SLIST_H
|
||||
|
||||
template<typename T>
|
||||
class SList {
|
||||
class SList
|
||||
{
|
||||
public:
|
||||
SList() : _next(0) { }
|
||||
SList() : _next(0) { }
|
||||
|
||||
protected:
|
||||
|
||||
static void _add(T* self) {
|
||||
T* tmp = _s_first;
|
||||
_s_first = self;
|
||||
self->_next = tmp;
|
||||
}
|
||||
|
||||
static void _remove(T* self) {
|
||||
if (_s_first == self) {
|
||||
_s_first = self->_next;
|
||||
self->_next = 0;
|
||||
return;
|
||||
static void _add(T* self)
|
||||
{
|
||||
T* tmp = _s_first;
|
||||
_s_first = self;
|
||||
self->_next = tmp;
|
||||
}
|
||||
|
||||
for (T* prev = _s_first; prev->_next; prev = prev->_next) {
|
||||
if (prev->_next == self) {
|
||||
prev->_next = self->_next;
|
||||
self->_next = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void _remove(T* self)
|
||||
{
|
||||
if (_s_first == self)
|
||||
{
|
||||
_s_first = self->_next;
|
||||
self->_next = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
static T* _s_first;
|
||||
T* _next;
|
||||
for (T* prev = _s_first; prev->_next; prev = prev->_next)
|
||||
{
|
||||
if (prev->_next == self)
|
||||
{
|
||||
prev->_next = self->_next;
|
||||
self->_next = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static T* _s_first;
|
||||
T* _next;
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,65 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2016, Cameron Rich
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
Copyright (c) 2007-2016, Cameron Rich
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* * Neither the name of the axTLS project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @mainpage axTLS API
|
||||
*
|
||||
* @image html axolotl.jpg
|
||||
*
|
||||
* The axTLS library has features such as:
|
||||
* - The TLSv1 SSL client/server protocol
|
||||
* - No requirement to use any openssl libraries.
|
||||
* - A choice between AES block (128/256 bit) and RC4 (128 bit) stream ciphers.
|
||||
* - RSA encryption/decryption with variable sized keys (up to 4096 bits).
|
||||
* - Certificate chaining and peer authentication.
|
||||
* - Session resumption, session renegotiation.
|
||||
* - ASN.1, X.509, PKCS#8, PKCS#12 keys/certificates with DER/PEM encoding.
|
||||
* - Highly configurable compile time options.
|
||||
* - Portable across many platforms (written in ANSI C), and has language
|
||||
* bindings in C, C#, VB.NET, Java, Perl and Lua.
|
||||
* - Partial openssl API compatibility (via a wrapper).
|
||||
* - A very small footprint (around 50-60kB for the library in 'server-only'
|
||||
* mode).
|
||||
* - No dependencies on sockets - can use serial connections for example.
|
||||
* - A very simple API - ~ 20 functions/methods.
|
||||
*
|
||||
* A list of these functions/methods are described below.
|
||||
*
|
||||
* @ref c_api
|
||||
*
|
||||
* @ref bigint_api
|
||||
*
|
||||
* @ref csharp_api
|
||||
*
|
||||
* @ref java_api
|
||||
*/
|
||||
@mainpage axTLS API
|
||||
|
||||
@image html axolotl.jpg
|
||||
|
||||
The axTLS library has features such as:
|
||||
- The TLSv1 SSL client/server protocol
|
||||
- No requirement to use any openssl libraries.
|
||||
- A choice between AES block (128/256 bit) and RC4 (128 bit) stream ciphers.
|
||||
- RSA encryption/decryption with variable sized keys (up to 4096 bits).
|
||||
- Certificate chaining and peer authentication.
|
||||
- Session resumption, session renegotiation.
|
||||
- ASN.1, X.509, PKCS#8, PKCS#12 keys/certificates with DER/PEM encoding.
|
||||
- Highly configurable compile time options.
|
||||
- Portable across many platforms (written in ANSI C), and has language
|
||||
bindings in C, C#, VB.NET, Java, Perl and Lua.
|
||||
- Partial openssl API compatibility (via a wrapper).
|
||||
- A very small footprint (around 50-60kB for the library in 'server-only'
|
||||
mode).
|
||||
- No dependencies on sockets - can use serial connections for example.
|
||||
- A very simple API - ~ 20 functions/methods.
|
||||
|
||||
A list of these functions/methods are described below.
|
||||
|
||||
@ref c_api
|
||||
|
||||
@ref bigint_api
|
||||
|
||||
@ref csharp_api
|
||||
|
||||
@ref java_api
|
||||
*/
|
||||
#ifndef HEADER_SSL_H
|
||||
#define HEADER_SSL_H
|
||||
|
||||
@ -187,391 +187,391 @@ typedef struct SSL_EXTENSIONS_ SSL_EXTENSIONS;
|
||||
#define SSL_OBJ_PKCS12 5
|
||||
|
||||
/**
|
||||
* @defgroup c_api Standard C API
|
||||
* @brief The standard interface in C.
|
||||
* @{
|
||||
*/
|
||||
@defgroup c_api Standard C API
|
||||
@brief The standard interface in C.
|
||||
@{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Establish a new client/server context.
|
||||
*
|
||||
* This function is called before any client/server SSL connections are made.
|
||||
*
|
||||
* Each new connection will use the this context's private key and
|
||||
* certificate chain. If a different certificate chain is required, then a
|
||||
* different context needs to be be used.
|
||||
*
|
||||
* There are two threading models supported - a single thread with one
|
||||
* SSL_CTX can support any number of SSL connections - and multiple threads can
|
||||
* support one SSL_CTX object each (the default). But if a single SSL_CTX
|
||||
* object uses many SSL objects in individual threads, then the
|
||||
* CONFIG_SSL_CTX_MUTEXING option needs to be configured.
|
||||
*
|
||||
* @param options [in] Any particular options. At present the options
|
||||
* supported are:
|
||||
* - SSL_SERVER_VERIFY_LATER (client only): Don't stop a handshake if the server
|
||||
* authentication fails. The certificate can be authenticated later with a
|
||||
* call to ssl_verify_cert().
|
||||
* - SSL_CLIENT_AUTHENTICATION (server only): Enforce client authentication
|
||||
* i.e. each handshake will include a "certificate request" message from the
|
||||
* server. Only available if verification has been enabled.
|
||||
* - SSL_DISPLAY_BYTES (full mode build only): Display the byte sequences
|
||||
* during the handshake.
|
||||
* - SSL_DISPLAY_STATES (full mode build only): Display the state changes
|
||||
* during the handshake.
|
||||
* - SSL_DISPLAY_CERTS (full mode build only): Display the certificates that
|
||||
* are passed during a handshake.
|
||||
* - SSL_DISPLAY_RSA (full mode build only): Display the RSA key details that
|
||||
* are passed during a handshake.
|
||||
* - SSL_CONNECT_IN_PARTS (client only): To use a non-blocking version of
|
||||
* ssl_client_new().
|
||||
* @param num_sessions [in] The number of sessions to be used for session
|
||||
* caching. If this value is 0, then there is no session caching. This option
|
||||
* is not used in skeleton mode.
|
||||
* @return A client/server context.
|
||||
*/
|
||||
@brief Establish a new client/server context.
|
||||
|
||||
This function is called before any client/server SSL connections are made.
|
||||
|
||||
Each new connection will use the this context's private key and
|
||||
certificate chain. If a different certificate chain is required, then a
|
||||
different context needs to be be used.
|
||||
|
||||
There are two threading models supported - a single thread with one
|
||||
SSL_CTX can support any number of SSL connections - and multiple threads can
|
||||
support one SSL_CTX object each (the default). But if a single SSL_CTX
|
||||
object uses many SSL objects in individual threads, then the
|
||||
CONFIG_SSL_CTX_MUTEXING option needs to be configured.
|
||||
|
||||
@param options [in] Any particular options. At present the options
|
||||
supported are:
|
||||
- SSL_SERVER_VERIFY_LATER (client only): Don't stop a handshake if the server
|
||||
authentication fails. The certificate can be authenticated later with a
|
||||
call to ssl_verify_cert().
|
||||
- SSL_CLIENT_AUTHENTICATION (server only): Enforce client authentication
|
||||
i.e. each handshake will include a "certificate request" message from the
|
||||
server. Only available if verification has been enabled.
|
||||
- SSL_DISPLAY_BYTES (full mode build only): Display the byte sequences
|
||||
during the handshake.
|
||||
- SSL_DISPLAY_STATES (full mode build only): Display the state changes
|
||||
during the handshake.
|
||||
- SSL_DISPLAY_CERTS (full mode build only): Display the certificates that
|
||||
are passed during a handshake.
|
||||
- SSL_DISPLAY_RSA (full mode build only): Display the RSA key details that
|
||||
are passed during a handshake.
|
||||
- SSL_CONNECT_IN_PARTS (client only): To use a non-blocking version of
|
||||
ssl_client_new().
|
||||
@param num_sessions [in] The number of sessions to be used for session
|
||||
caching. If this value is 0, then there is no session caching. This option
|
||||
is not used in skeleton mode.
|
||||
@return A client/server context.
|
||||
*/
|
||||
EXP_FUNC SSL_CTX * STDCALL ssl_ctx_new(uint32_t options, int num_sessions);
|
||||
|
||||
/**
|
||||
* @brief Remove a client/server context.
|
||||
*
|
||||
* Frees any used resources used by this context. Each connection will be
|
||||
* sent a "Close Notify" alert (if possible).
|
||||
* @param ssl_ctx [in] The client/server context.
|
||||
*/
|
||||
@brief Remove a client/server context.
|
||||
|
||||
Frees any used resources used by this context. Each connection will be
|
||||
sent a "Close Notify" alert (if possible).
|
||||
@param ssl_ctx [in] The client/server context.
|
||||
*/
|
||||
EXP_FUNC void STDCALL ssl_ctx_free(SSL_CTX *ssl_ctx);
|
||||
|
||||
/**
|
||||
* @brief Allocates new SSL extensions structure and returns pointer to it
|
||||
*
|
||||
* @return ssl_ext Pointer to SSL_EXTENSIONS structure
|
||||
*
|
||||
*/
|
||||
@brief Allocates new SSL extensions structure and returns pointer to it
|
||||
|
||||
@return ssl_ext Pointer to SSL_EXTENSIONS structure
|
||||
|
||||
*/
|
||||
EXP_FUNC SSL_EXTENSIONS * STDCALL ssl_ext_new();
|
||||
|
||||
/**
|
||||
* @brief Set the host name for SNI extension
|
||||
* @param ssl_ext pointer returned by ssl_ext_new
|
||||
* @param host_name pointer to a zero-terminated string containing host name
|
||||
*/
|
||||
@brief Set the host name for SNI extension
|
||||
@param ssl_ext pointer returned by ssl_ext_new
|
||||
@param host_name pointer to a zero-terminated string containing host name
|
||||
*/
|
||||
EXP_FUNC void STDCALL ssl_ext_set_host_name(SSL_EXTENSIONS * ext, const char* host_name);
|
||||
|
||||
/**
|
||||
* @brief Set the maximum fragment size for the fragment size negotiation extension
|
||||
* @param ssl_ext pointer returned by ssl_ext_new
|
||||
* @param fragment_size fragment size, allowed values: 2^9, 2^10 ... 2^14
|
||||
*/
|
||||
@brief Set the maximum fragment size for the fragment size negotiation extension
|
||||
@param ssl_ext pointer returned by ssl_ext_new
|
||||
@param fragment_size fragment size, allowed values: 2^9, 2^10 ... 2^14
|
||||
*/
|
||||
EXP_FUNC void STDCALL ssl_ext_set_max_fragment_size(SSL_EXTENSIONS * ext, unsigned fragment_size);
|
||||
|
||||
/**
|
||||
* @brief Frees SSL extensions structure
|
||||
*
|
||||
* @param ssl_ext [in] Pointer to SSL_EXTENSION structure
|
||||
*
|
||||
*/
|
||||
@brief Frees SSL extensions structure
|
||||
|
||||
@param ssl_ext [in] Pointer to SSL_EXTENSION structure
|
||||
|
||||
*/
|
||||
EXP_FUNC void STDCALL ssl_ext_free(SSL_EXTENSIONS *ssl_ext);
|
||||
|
||||
/**
|
||||
* @brief (server only) Establish a new SSL connection to an SSL client.
|
||||
*
|
||||
* It is up to the application to establish the logical connection (whether it
|
||||
* is a socket, serial connection etc).
|
||||
* @param ssl_ctx [in] The server context.
|
||||
* @param client_fd [in] The client's file descriptor.
|
||||
* @return An SSL object reference.
|
||||
*/
|
||||
@brief (server only) Establish a new SSL connection to an SSL client.
|
||||
|
||||
It is up to the application to establish the logical connection (whether it
|
||||
is a socket, serial connection etc).
|
||||
@param ssl_ctx [in] The server context.
|
||||
@param client_fd [in] The client's file descriptor.
|
||||
@return An SSL object reference.
|
||||
*/
|
||||
EXP_FUNC SSL * STDCALL ssl_server_new(SSL_CTX *ssl_ctx, int client_fd);
|
||||
|
||||
/**
|
||||
* @brief (client only) Establish a new SSL connection to an SSL server.
|
||||
*
|
||||
* It is up to the application to establish the initial logical connection
|
||||
* (whether it is a socket, serial connection etc).
|
||||
*
|
||||
* This is a normally a blocking call - it will finish when the handshake is
|
||||
* complete (or has failed). To use in non-blocking mode, set
|
||||
* SSL_CONNECT_IN_PARTS in ssl_ctx_new().
|
||||
* @param ssl_ctx [in] The client context.
|
||||
* @param client_fd [in] The client's file descriptor.
|
||||
* @param session_id [in] A 32 byte session id for session resumption. This
|
||||
* can be null if no session resumption is being used or required. This option
|
||||
* is not used in skeleton mode.
|
||||
* @param sess_id_size The size of the session id (max 32)
|
||||
* @param ssl_ext pointer to a structure with the activated SSL extensions and their values
|
||||
* @return An SSL object reference. Use ssl_handshake_status() to check
|
||||
* if a handshake succeeded.
|
||||
*/
|
||||
@brief (client only) Establish a new SSL connection to an SSL server.
|
||||
|
||||
It is up to the application to establish the initial logical connection
|
||||
(whether it is a socket, serial connection etc).
|
||||
|
||||
This is a normally a blocking call - it will finish when the handshake is
|
||||
complete (or has failed). To use in non-blocking mode, set
|
||||
SSL_CONNECT_IN_PARTS in ssl_ctx_new().
|
||||
@param ssl_ctx [in] The client context.
|
||||
@param client_fd [in] The client's file descriptor.
|
||||
@param session_id [in] A 32 byte session id for session resumption. This
|
||||
can be null if no session resumption is being used or required. This option
|
||||
is not used in skeleton mode.
|
||||
@param sess_id_size The size of the session id (max 32)
|
||||
@param ssl_ext pointer to a structure with the activated SSL extensions and their values
|
||||
@return An SSL object reference. Use ssl_handshake_status() to check
|
||||
if a handshake succeeded.
|
||||
*/
|
||||
EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const uint8_t *session_id, uint8_t sess_id_size, SSL_EXTENSIONS* ssl_ext);
|
||||
|
||||
/**
|
||||
* @brief Free any used resources on this connection.
|
||||
@brief Free any used resources on this connection.
|
||||
|
||||
* A "Close Notify" message is sent on this connection (if possible). It is up
|
||||
* to the application to close the socket or file descriptor.
|
||||
* @param ssl [in] The ssl object reference.
|
||||
*/
|
||||
A "Close Notify" message is sent on this connection (if possible). It is up
|
||||
to the application to close the socket or file descriptor.
|
||||
@param ssl [in] The ssl object reference.
|
||||
*/
|
||||
EXP_FUNC void STDCALL ssl_free(SSL *ssl);
|
||||
|
||||
/**
|
||||
* @brief Read the SSL data stream.
|
||||
* If the socket is non-blocking and data is blocked then SSO_OK will be
|
||||
* returned.
|
||||
* @param ssl [in] An SSL object reference.
|
||||
* @param in_data [out] If the read was successful, a pointer to the read
|
||||
* buffer will be here. Do NOT ever free this memory as this buffer is used in
|
||||
* sucessive calls. If the call was unsuccessful, this value will be null.
|
||||
* @return The number of decrypted bytes:
|
||||
* - if > 0, then the handshaking is complete and we are returning the number
|
||||
* of decrypted bytes.
|
||||
* - SSL_OK if the handshaking stage is successful (but not yet complete).
|
||||
* - < 0 if an error.
|
||||
* @see ssl.h for the error code list.
|
||||
* @note Use in_data before doing any successive ssl calls.
|
||||
*/
|
||||
@brief Read the SSL data stream.
|
||||
If the socket is non-blocking and data is blocked then SSO_OK will be
|
||||
returned.
|
||||
@param ssl [in] An SSL object reference.
|
||||
@param in_data [out] If the read was successful, a pointer to the read
|
||||
buffer will be here. Do NOT ever free this memory as this buffer is used in
|
||||
sucessive calls. If the call was unsuccessful, this value will be null.
|
||||
@return The number of decrypted bytes:
|
||||
- if > 0, then the handshaking is complete and we are returning the number
|
||||
of decrypted bytes.
|
||||
- SSL_OK if the handshaking stage is successful (but not yet complete).
|
||||
- < 0 if an error.
|
||||
@see ssl.h for the error code list.
|
||||
@note Use in_data before doing any successive ssl calls.
|
||||
*/
|
||||
EXP_FUNC int STDCALL ssl_read(SSL *ssl, uint8_t **in_data);
|
||||
|
||||
/**
|
||||
* @brief Write to the SSL data stream.
|
||||
* if the socket is non-blocking and data is blocked then a check is made
|
||||
* to ensure that all data is sent (i.e. blocked mode is forced).
|
||||
* @param ssl [in] An SSL obect reference.
|
||||
* @param out_data [in] The data to be written
|
||||
* @param out_len [in] The number of bytes to be written.
|
||||
* @return The number of bytes sent, or if < 0 if an error.
|
||||
* @see ssl.h for the error code list.
|
||||
*/
|
||||
@brief Write to the SSL data stream.
|
||||
if the socket is non-blocking and data is blocked then a check is made
|
||||
to ensure that all data is sent (i.e. blocked mode is forced).
|
||||
@param ssl [in] An SSL obect reference.
|
||||
@param out_data [in] The data to be written
|
||||
@param out_len [in] The number of bytes to be written.
|
||||
@return The number of bytes sent, or if < 0 if an error.
|
||||
@see ssl.h for the error code list.
|
||||
*/
|
||||
EXP_FUNC int STDCALL ssl_write(SSL *ssl, const uint8_t *out_data, int out_len);
|
||||
|
||||
/**
|
||||
* @brief Calculate the size of the encrypted data from what you are about to send
|
||||
* @param ssl [in] An SSL obect reference.
|
||||
* @param out_len [in] The number of bytes to be written.
|
||||
* @return The number of bytes that will be sent, or if < 0 if an error.
|
||||
* @see ssl.h for the error code list.
|
||||
*/
|
||||
@brief Calculate the size of the encrypted data from what you are about to send
|
||||
@param ssl [in] An SSL obect reference.
|
||||
@param out_len [in] The number of bytes to be written.
|
||||
@return The number of bytes that will be sent, or if < 0 if an error.
|
||||
@see ssl.h for the error code list.
|
||||
*/
|
||||
EXP_FUNC int STDCALL ssl_calculate_write_length(SSL *ssl, int out_len);
|
||||
|
||||
/**
|
||||
* @brief Find an ssl object based on a file descriptor.
|
||||
*
|
||||
* Goes through the list of SSL objects maintained in a client/server context
|
||||
* to look for a file descriptor match.
|
||||
* @param ssl_ctx [in] The client/server context.
|
||||
* @param client_fd [in] The file descriptor.
|
||||
* @return A reference to the SSL object. Returns null if the object could not
|
||||
* be found.
|
||||
*/
|
||||
@brief Find an ssl object based on a file descriptor.
|
||||
|
||||
Goes through the list of SSL objects maintained in a client/server context
|
||||
to look for a file descriptor match.
|
||||
@param ssl_ctx [in] The client/server context.
|
||||
@param client_fd [in] The file descriptor.
|
||||
@return A reference to the SSL object. Returns null if the object could not
|
||||
be found.
|
||||
*/
|
||||
EXP_FUNC SSL * STDCALL ssl_find(SSL_CTX *ssl_ctx, int client_fd);
|
||||
|
||||
/**
|
||||
* @brief Get the session id for a handshake.
|
||||
*
|
||||
* This will be a 32 byte sequence and is available after the first
|
||||
* handshaking messages are sent.
|
||||
* @param ssl [in] An SSL object reference.
|
||||
* @return The session id as a 32 byte sequence.
|
||||
* @note A SSLv23 handshake may have only 16 valid bytes.
|
||||
*/
|
||||
@brief Get the session id for a handshake.
|
||||
|
||||
This will be a 32 byte sequence and is available after the first
|
||||
handshaking messages are sent.
|
||||
@param ssl [in] An SSL object reference.
|
||||
@return The session id as a 32 byte sequence.
|
||||
@note A SSLv23 handshake may have only 16 valid bytes.
|
||||
*/
|
||||
EXP_FUNC const uint8_t * STDCALL ssl_get_session_id(const SSL *ssl);
|
||||
|
||||
/**
|
||||
* @brief Get the session id size for a handshake.
|
||||
*
|
||||
* This will normally be 32 but could be 0 (no session id) or something else.
|
||||
* @param ssl [in] An SSL object reference.
|
||||
* @return The size of the session id.
|
||||
*/
|
||||
@brief Get the session id size for a handshake.
|
||||
|
||||
This will normally be 32 but could be 0 (no session id) or something else.
|
||||
@param ssl [in] An SSL object reference.
|
||||
@return The size of the session id.
|
||||
*/
|
||||
EXP_FUNC uint8_t STDCALL ssl_get_session_id_size(const SSL *ssl);
|
||||
|
||||
/**
|
||||
* @brief Return the cipher id (in the SSL form).
|
||||
* @param ssl [in] An SSL object reference.
|
||||
* @return The cipher id. This will be one of the following:
|
||||
* - SSL_AES128_SHA (0x2f)
|
||||
* - SSL_AES256_SHA (0x35)
|
||||
* - SSL_RC4_128_SHA (0x05)
|
||||
* - SSL_RC4_128_MD5 (0x04)
|
||||
*/
|
||||
@brief Return the cipher id (in the SSL form).
|
||||
@param ssl [in] An SSL object reference.
|
||||
@return The cipher id. This will be one of the following:
|
||||
- SSL_AES128_SHA (0x2f)
|
||||
- SSL_AES256_SHA (0x35)
|
||||
- SSL_RC4_128_SHA (0x05)
|
||||
- SSL_RC4_128_MD5 (0x04)
|
||||
*/
|
||||
EXP_FUNC uint8_t STDCALL ssl_get_cipher_id(const SSL *ssl);
|
||||
|
||||
/**
|
||||
* @brief Return the status of the handshake.
|
||||
* @param ssl [in] An SSL object reference.
|
||||
* @return SSL_OK if the handshake is complete and ok.
|
||||
* @see ssl.h for the error code list.
|
||||
*/
|
||||
@brief Return the status of the handshake.
|
||||
@param ssl [in] An SSL object reference.
|
||||
@return SSL_OK if the handshake is complete and ok.
|
||||
@see ssl.h for the error code list.
|
||||
*/
|
||||
EXP_FUNC int STDCALL ssl_handshake_status(const SSL *ssl);
|
||||
|
||||
/**
|
||||
* @brief Retrieve various parameters about the axTLS engine.
|
||||
* @param offset [in] The configuration offset. It will be one of the following:
|
||||
* - SSL_BUILD_MODE The build mode. This will be one of the following:
|
||||
* - SSL_BUILD_SERVER_ONLY (basic server mode)
|
||||
* - SSL_BUILD_ENABLE_VERIFICATION (server can do client authentication)
|
||||
* - SSL_BUILD_ENABLE_CLIENT (client/server capabilties)
|
||||
* - SSL_BUILD_FULL_MODE (client/server with diagnostics)
|
||||
* - SSL_BUILD_SKELETON_MODE (skeleton mode)
|
||||
* - SSL_MAX_CERT_CFG_OFFSET The maximum number of certificates allowed.
|
||||
* - SSL_MAX_CA_CERT_CFG_OFFSET The maximum number of CA certificates allowed.
|
||||
* - SSL_HAS_PEM 1 if supported
|
||||
* @return The value of the requested parameter.
|
||||
*/
|
||||
@brief Retrieve various parameters about the axTLS engine.
|
||||
@param offset [in] The configuration offset. It will be one of the following:
|
||||
- SSL_BUILD_MODE The build mode. This will be one of the following:
|
||||
- SSL_BUILD_SERVER_ONLY (basic server mode)
|
||||
- SSL_BUILD_ENABLE_VERIFICATION (server can do client authentication)
|
||||
- SSL_BUILD_ENABLE_CLIENT (client/server capabilties)
|
||||
- SSL_BUILD_FULL_MODE (client/server with diagnostics)
|
||||
- SSL_BUILD_SKELETON_MODE (skeleton mode)
|
||||
- SSL_MAX_CERT_CFG_OFFSET The maximum number of certificates allowed.
|
||||
- SSL_MAX_CA_CERT_CFG_OFFSET The maximum number of CA certificates allowed.
|
||||
- SSL_HAS_PEM 1 if supported
|
||||
@return The value of the requested parameter.
|
||||
*/
|
||||
EXP_FUNC int STDCALL ssl_get_config(int offset);
|
||||
|
||||
/**
|
||||
* @brief Display why the handshake failed.
|
||||
*
|
||||
* This call is only useful in a 'full mode' build. The output is to stdout.
|
||||
* @param error_code [in] An error code.
|
||||
* @see ssl.h for the error code list.
|
||||
*/
|
||||
@brief Display why the handshake failed.
|
||||
|
||||
This call is only useful in a 'full mode' build. The output is to stdout.
|
||||
@param error_code [in] An error code.
|
||||
@see ssl.h for the error code list.
|
||||
*/
|
||||
EXP_FUNC void STDCALL ssl_display_error(int error_code);
|
||||
|
||||
/**
|
||||
* @brief Authenticate a received certificate.
|
||||
*
|
||||
* This call is usually made by a client after a handshake is complete and the
|
||||
* context is in SSL_SERVER_VERIFY_LATER mode.
|
||||
* @param ssl [in] An SSL object reference.
|
||||
* @return SSL_OK if the certificate is verified.
|
||||
*/
|
||||
@brief Authenticate a received certificate.
|
||||
|
||||
This call is usually made by a client after a handshake is complete and the
|
||||
context is in SSL_SERVER_VERIFY_LATER mode.
|
||||
@param ssl [in] An SSL object reference.
|
||||
@return SSL_OK if the certificate is verified.
|
||||
*/
|
||||
EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl);
|
||||
|
||||
/**
|
||||
* @brief Check if certificate fingerprint (SHA1) matches the one given.
|
||||
*
|
||||
* @param ssl [in] An SSL object reference.
|
||||
* @param fp [in] SHA1 fingerprint to match against
|
||||
* @return SSL_OK if the certificate is verified.
|
||||
*/
|
||||
@brief Check if certificate fingerprint (SHA1) matches the one given.
|
||||
|
||||
@param ssl [in] An SSL object reference.
|
||||
@param fp [in] SHA1 fingerprint to match against
|
||||
@return SSL_OK if the certificate is verified.
|
||||
*/
|
||||
EXP_FUNC int STDCALL ssl_match_fingerprint(const SSL *ssl, const uint8_t* fp);
|
||||
|
||||
/**
|
||||
* @brief Check if SHA256 hash of Subject Public Key Info matches the one given.
|
||||
*
|
||||
* @param ssl [in] An SSL object reference.
|
||||
* @param fp [in] SHA256 hash to match against
|
||||
* @return SSL_OK if the certificate is verified.
|
||||
*/
|
||||
@brief Check if SHA256 hash of Subject Public Key Info matches the one given.
|
||||
|
||||
@param ssl [in] An SSL object reference.
|
||||
@param fp [in] SHA256 hash to match against
|
||||
@return SSL_OK if the certificate is verified.
|
||||
*/
|
||||
EXP_FUNC int STDCALL ssl_match_spki_sha256(const SSL *ssl, const uint8_t* hash);
|
||||
|
||||
/**
|
||||
* @brief Retrieve an X.509 distinguished name component.
|
||||
*
|
||||
* When a handshake is complete and a certificate has been exchanged, then the
|
||||
* details of the remote certificate can be retrieved.
|
||||
*
|
||||
* This will usually be used by a client to check that the server's common
|
||||
* name matches the URL.
|
||||
*
|
||||
* @param ssl [in] An SSL object reference.
|
||||
* @param component [in] one of:
|
||||
* - SSL_X509_CERT_COMMON_NAME
|
||||
* - SSL_X509_CERT_ORGANIZATION
|
||||
* - SSL_X509_CERT_ORGANIZATIONAL_NAME
|
||||
* - SSL_X509_CA_CERT_COMMON_NAME
|
||||
* - SSL_X509_CA_CERT_ORGANIZATION
|
||||
* - SSL_X509_CA_CERT_ORGANIZATIONAL_NAME
|
||||
* @return The appropriate string (or null if not defined)
|
||||
* @note Verification build mode must be enabled.
|
||||
*/
|
||||
@brief Retrieve an X.509 distinguished name component.
|
||||
|
||||
When a handshake is complete and a certificate has been exchanged, then the
|
||||
details of the remote certificate can be retrieved.
|
||||
|
||||
This will usually be used by a client to check that the server's common
|
||||
name matches the URL.
|
||||
|
||||
@param ssl [in] An SSL object reference.
|
||||
@param component [in] one of:
|
||||
- SSL_X509_CERT_COMMON_NAME
|
||||
- SSL_X509_CERT_ORGANIZATION
|
||||
- SSL_X509_CERT_ORGANIZATIONAL_NAME
|
||||
- SSL_X509_CA_CERT_COMMON_NAME
|
||||
- SSL_X509_CA_CERT_ORGANIZATION
|
||||
- SSL_X509_CA_CERT_ORGANIZATIONAL_NAME
|
||||
@return The appropriate string (or null if not defined)
|
||||
@note Verification build mode must be enabled.
|
||||
*/
|
||||
EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component);
|
||||
|
||||
/**
|
||||
* @brief Retrieve a Subject Alternative DNSName
|
||||
*
|
||||
* When a handshake is complete and a certificate has been exchanged, then the
|
||||
* details of the remote certificate can be retrieved.
|
||||
*
|
||||
* This will usually be used by a client to check that the server's DNS
|
||||
* name matches the URL.
|
||||
*
|
||||
* @param ssl [in] An SSL object reference.
|
||||
* @param dnsindex [in] The index of the DNS name to retrieve.
|
||||
* @return The appropriate string (or null if not defined)
|
||||
* @note Verification build mode must be enabled.
|
||||
*/
|
||||
@brief Retrieve a Subject Alternative DNSName
|
||||
|
||||
When a handshake is complete and a certificate has been exchanged, then the
|
||||
details of the remote certificate can be retrieved.
|
||||
|
||||
This will usually be used by a client to check that the server's DNS
|
||||
name matches the URL.
|
||||
|
||||
@param ssl [in] An SSL object reference.
|
||||
@param dnsindex [in] The index of the DNS name to retrieve.
|
||||
@return The appropriate string (or null if not defined)
|
||||
@note Verification build mode must be enabled.
|
||||
*/
|
||||
EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl, int dnsindex);
|
||||
|
||||
/**
|
||||
* @brief Force the client to perform its handshake again.
|
||||
*
|
||||
* For a client this involves sending another "client hello" message.
|
||||
* For the server is means sending a "hello request" message.
|
||||
*
|
||||
* This is a blocking call on the client (until the handshake completes).
|
||||
*
|
||||
* @param ssl [in] An SSL object reference.
|
||||
* @return SSL_OK if renegotiation instantiation was ok
|
||||
*/
|
||||
@brief Force the client to perform its handshake again.
|
||||
|
||||
For a client this involves sending another "client hello" message.
|
||||
For the server is means sending a "hello request" message.
|
||||
|
||||
This is a blocking call on the client (until the handshake completes).
|
||||
|
||||
@param ssl [in] An SSL object reference.
|
||||
@return SSL_OK if renegotiation instantiation was ok
|
||||
*/
|
||||
EXP_FUNC int STDCALL ssl_renegotiate(SSL *ssl);
|
||||
|
||||
/**
|
||||
* @brief Process a file that is in binary DER or ASCII PEM format.
|
||||
*
|
||||
* These are temporary objects that are used to load private keys,
|
||||
* certificates etc into memory.
|
||||
* @param ssl_ctx [in] The client/server context.
|
||||
* @param obj_type [in] The format of the file. Can be one of:
|
||||
* - SSL_OBJ_X509_CERT (no password required)
|
||||
* - SSL_OBJ_X509_CACERT (no password required)
|
||||
* - SSL_OBJ_RSA_KEY (AES128/AES256 PEM encryption supported)
|
||||
* - SSL_OBJ_PKCS8 (RC4-128 encrypted data supported)
|
||||
* - SSL_OBJ_PKCS12 (RC4-128 encrypted data supported)
|
||||
*
|
||||
* PEM files are automatically detected (if supported). The object type is
|
||||
* also detected, and so is not relevant for these types of files.
|
||||
* @param filename [in] The location of a file in DER/PEM format.
|
||||
* @param password [in] The password used. Can be null if not required.
|
||||
* @return SSL_OK if all ok
|
||||
* @note Not available in skeleton build mode.
|
||||
*/
|
||||
@brief Process a file that is in binary DER or ASCII PEM format.
|
||||
|
||||
These are temporary objects that are used to load private keys,
|
||||
certificates etc into memory.
|
||||
@param ssl_ctx [in] The client/server context.
|
||||
@param obj_type [in] The format of the file. Can be one of:
|
||||
- SSL_OBJ_X509_CERT (no password required)
|
||||
- SSL_OBJ_X509_CACERT (no password required)
|
||||
- SSL_OBJ_RSA_KEY (AES128/AES256 PEM encryption supported)
|
||||
- SSL_OBJ_PKCS8 (RC4-128 encrypted data supported)
|
||||
- SSL_OBJ_PKCS12 (RC4-128 encrypted data supported)
|
||||
|
||||
PEM files are automatically detected (if supported). The object type is
|
||||
also detected, and so is not relevant for these types of files.
|
||||
@param filename [in] The location of a file in DER/PEM format.
|
||||
@param password [in] The password used. Can be null if not required.
|
||||
@return SSL_OK if all ok
|
||||
@note Not available in skeleton build mode.
|
||||
*/
|
||||
EXP_FUNC int STDCALL ssl_obj_load(SSL_CTX *ssl_ctx, int obj_type, const char *filename, const char *password);
|
||||
|
||||
/**
|
||||
* @brief Process binary data.
|
||||
*
|
||||
* These are temporary objects that are used to load private keys,
|
||||
* certificates etc into memory.
|
||||
* @param ssl_ctx [in] The client/server context.
|
||||
* @param obj_type [in] The format of the memory data.
|
||||
* @param data [in] The binary data to be loaded.
|
||||
* @param len [in] The amount of data to be loaded.
|
||||
* @param password [in] The password used. Can be null if not required.
|
||||
* @return SSL_OK if all ok
|
||||
* @see ssl_obj_load for more details on obj_type.
|
||||
*/
|
||||
@brief Process binary data.
|
||||
|
||||
These are temporary objects that are used to load private keys,
|
||||
certificates etc into memory.
|
||||
@param ssl_ctx [in] The client/server context.
|
||||
@param obj_type [in] The format of the memory data.
|
||||
@param data [in] The binary data to be loaded.
|
||||
@param len [in] The amount of data to be loaded.
|
||||
@param password [in] The password used. Can be null if not required.
|
||||
@return SSL_OK if all ok
|
||||
@see ssl_obj_load for more details on obj_type.
|
||||
*/
|
||||
EXP_FUNC int STDCALL ssl_obj_memory_load(SSL_CTX *ssl_ctx, int obj_type, const uint8_t *data, int len, const char *password);
|
||||
|
||||
#ifdef CONFIG_SSL_GENERATE_X509_CERT
|
||||
/**
|
||||
* @brief Create an X.509 certificate.
|
||||
*
|
||||
* This certificate is a self-signed v1 cert with a fixed start/stop validity
|
||||
* times. It is signed with an internal private key in ssl_ctx.
|
||||
*
|
||||
* @param ssl_ctx [in] The client/server context.
|
||||
* @param options [in] Not used yet.
|
||||
* @param dn [in] An array of distinguished name strings. The array is defined
|
||||
* by:
|
||||
* - SSL_X509_CERT_COMMON_NAME (0)
|
||||
* - If SSL_X509_CERT_COMMON_NAME is empty or not defined, then the
|
||||
* hostname will be used.
|
||||
* - SSL_X509_CERT_ORGANIZATION (1)
|
||||
* - If SSL_X509_CERT_ORGANIZATION is empty or not defined, then $USERNAME
|
||||
* will be used.
|
||||
* - SSL_X509_CERT_ORGANIZATIONAL_NAME (2)
|
||||
* - SSL_X509_CERT_ORGANIZATIONAL_NAME is optional.
|
||||
* @param cert_data [out] The certificate as a sequence of bytes.
|
||||
* @return < 0 if an error, or the size of the certificate in bytes.
|
||||
* @note cert_data must be freed when there is no more need for it.
|
||||
*/
|
||||
@brief Create an X.509 certificate.
|
||||
|
||||
This certificate is a self-signed v1 cert with a fixed start/stop validity
|
||||
times. It is signed with an internal private key in ssl_ctx.
|
||||
|
||||
@param ssl_ctx [in] The client/server context.
|
||||
@param options [in] Not used yet.
|
||||
@param dn [in] An array of distinguished name strings. The array is defined
|
||||
by:
|
||||
- SSL_X509_CERT_COMMON_NAME (0)
|
||||
- If SSL_X509_CERT_COMMON_NAME is empty or not defined, then the
|
||||
hostname will be used.
|
||||
- SSL_X509_CERT_ORGANIZATION (1)
|
||||
- If SSL_X509_CERT_ORGANIZATION is empty or not defined, then $USERNAME
|
||||
will be used.
|
||||
- SSL_X509_CERT_ORGANIZATIONAL_NAME (2)
|
||||
- SSL_X509_CERT_ORGANIZATIONAL_NAME is optional.
|
||||
@param cert_data [out] The certificate as a sequence of bytes.
|
||||
@return < 0 if an error, or the size of the certificate in bytes.
|
||||
@note cert_data must be freed when there is no more need for it.
|
||||
*/
|
||||
EXP_FUNC int STDCALL ssl_x509_create(SSL_CTX *ssl_ctx, uint32_t options, const char * dn[], uint8_t **cert_data);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Return the axTLS library version as a string.
|
||||
*/
|
||||
@brief Return the axTLS library version as a string.
|
||||
*/
|
||||
EXP_FUNC const char * STDCALL ssl_version(void);
|
||||
|
||||
/** @} */
|
||||
|
@ -1,27 +1,27 @@
|
||||
/*
|
||||
wl_definitions.h - Library for Arduino Wifi shield.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
wl_definitions.h - Library for Arduino Wifi shield.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
|
||||
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 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.
|
||||
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
|
||||
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
|
||||
*/
|
||||
/*
|
||||
* wl_definitions.h
|
||||
*
|
||||
* Created on: Mar 6, 2011
|
||||
* Author: dlafauci
|
||||
*/
|
||||
wl_definitions.h
|
||||
|
||||
Created on: Mar 6, 2011
|
||||
Author: dlafauci
|
||||
*/
|
||||
|
||||
#ifndef WL_DEFINITIONS_H_
|
||||
#define WL_DEFINITIONS_H_
|
||||
@ -47,7 +47,8 @@
|
||||
//Maximum number of attempts to establish wifi connection
|
||||
#define WL_MAX_ATTEMPT_CONNECTION 10
|
||||
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
WL_NO_SHIELD = 255, // for compatibility with WiFi Shield library
|
||||
WL_IDLE_STATUS = 0,
|
||||
WL_NO_SSID_AVAIL = 1,
|
||||
@ -59,28 +60,30 @@ typedef enum {
|
||||
} wl_status_t;
|
||||
|
||||
/* Encryption modes */
|
||||
enum wl_enc_type { /* Values map to 802.11 encryption suites... */
|
||||
ENC_TYPE_WEP = 5,
|
||||
ENC_TYPE_TKIP = 2,
|
||||
ENC_TYPE_CCMP = 4,
|
||||
/* ... except these two, 7 and 8 are reserved in 802.11-2007 */
|
||||
ENC_TYPE_NONE = 7,
|
||||
ENC_TYPE_AUTO = 8
|
||||
enum wl_enc_type /* Values map to 802.11 encryption suites... */
|
||||
{
|
||||
ENC_TYPE_WEP = 5,
|
||||
ENC_TYPE_TKIP = 2,
|
||||
ENC_TYPE_CCMP = 4,
|
||||
/* ... except these two, 7 and 8 are reserved in 802.11-2007 */
|
||||
ENC_TYPE_NONE = 7,
|
||||
ENC_TYPE_AUTO = 8
|
||||
};
|
||||
|
||||
#if !defined(LWIP_INTERNAL) && !defined(__LWIP_TCP_H__)
|
||||
enum wl_tcp_state {
|
||||
CLOSED = 0,
|
||||
LISTEN = 1,
|
||||
SYN_SENT = 2,
|
||||
SYN_RCVD = 3,
|
||||
ESTABLISHED = 4,
|
||||
FIN_WAIT_1 = 5,
|
||||
FIN_WAIT_2 = 6,
|
||||
CLOSE_WAIT = 7,
|
||||
CLOSING = 8,
|
||||
LAST_ACK = 9,
|
||||
TIME_WAIT = 10
|
||||
enum wl_tcp_state
|
||||
{
|
||||
CLOSED = 0,
|
||||
LISTEN = 1,
|
||||
SYN_SENT = 2,
|
||||
SYN_RCVD = 3,
|
||||
ESTABLISHED = 4,
|
||||
FIN_WAIT_1 = 5,
|
||||
FIN_WAIT_2 = 6,
|
||||
CLOSE_WAIT = 7,
|
||||
CLOSING = 8,
|
||||
LAST_ACK = 9,
|
||||
TIME_WAIT = 10
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -1,22 +1,22 @@
|
||||
/*
|
||||
Old version of ESP8266WiFiMesh.cpp - Mesh network node
|
||||
Sets up a Mesh Node which acts as a router, creating a Mesh Network with other nodes. All information
|
||||
is passed in both directions, but it is up to the user what the data sent is and how it is dealt with.
|
||||
|
||||
Copyright (c) 2015 Julian Fell. All rights reserved.
|
||||
Updated 2018 by Anders Löfgren.
|
||||
|
||||
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
|
||||
Old version of ESP8266WiFiMesh.cpp - Mesh network node
|
||||
Sets up a Mesh Node which acts as a router, creating a Mesh Network with other nodes. All information
|
||||
is passed in both directions, but it is up to the user what the data sent is and how it is dealt with.
|
||||
|
||||
Copyright (c) 2015 Julian Fell. All rights reserved.
|
||||
Updated 2018 by Anders Löfgren.
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
@ -25,13 +25,13 @@
|
||||
|
||||
|
||||
/********************************************************************************************
|
||||
* NOTE!
|
||||
*
|
||||
* All method signatures in this file are deprecated and will be removed in core version 2.5.0.
|
||||
* If you are still using these methods, please consider migrating to the new API shown in
|
||||
* the ESP8266WiFiMesh.h source file.
|
||||
*
|
||||
* TODO: delete this file.
|
||||
NOTE!
|
||||
|
||||
All method signatures in this file are deprecated and will be removed in core version 2.5.0.
|
||||
If you are still using these methods, please consider migrating to the new API shown in
|
||||
the ESP8266WiFiMesh.h source file.
|
||||
|
||||
TODO: delete this file.
|
||||
********************************************************************************************/
|
||||
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <WiFiClient.h>
|
||||
#include <WiFiClient.h>
|
||||
#include <WiFiServer.h>
|
||||
|
||||
#include "ESP8266WiFiMesh.h"
|
||||
@ -51,131 +51,149 @@
|
||||
|
||||
// DEPRECATED!
|
||||
ESP8266WiFiMesh::ESP8266WiFiMesh(uint32_t chipID, ESP8266WiFiMesh::compatibilityLayerHandlerType handler)
|
||||
: _server(SERVER_PORT)
|
||||
: _server(SERVER_PORT)
|
||||
{
|
||||
_chipID = chipID;
|
||||
_SSID = String( String( SSID_PREFIX ) + String( _chipID ) );
|
||||
_ssidPrefix = String( SSID_PREFIX );
|
||||
_handler = handler;
|
||||
_chipID = chipID;
|
||||
_SSID = String(String(SSID_PREFIX) + String(_chipID));
|
||||
_ssidPrefix = String(SSID_PREFIX);
|
||||
_handler = handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for a WiFiClient to connect
|
||||
*
|
||||
* @returns: True if the client is ready, false otherwise.
|
||||
*
|
||||
*/
|
||||
Wait for a WiFiClient to connect
|
||||
|
||||
@returns: True if the client is ready, false otherwise.
|
||||
|
||||
*/
|
||||
// DEPRECATED!
|
||||
bool ESP8266WiFiMesh::waitForClient(WiFiClient &currClient, int maxWait)
|
||||
{
|
||||
int wait = maxWait;
|
||||
while(currClient.connected() && !currClient.available() && wait--)
|
||||
delay(3);
|
||||
int wait = maxWait;
|
||||
while (currClient.connected() && !currClient.available() && wait--)
|
||||
{
|
||||
delay(3);
|
||||
}
|
||||
|
||||
/* Return false if the client isn't ready to communicate */
|
||||
if (WiFi.status() == WL_DISCONNECTED || !currClient.connected())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
/* Return false if the client isn't ready to communicate */
|
||||
if (WiFi.status() == WL_DISCONNECTED || !currClient.connected())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the supplied message then read back the other node's response
|
||||
* and pass that to the user-supplied handler.
|
||||
*
|
||||
* @message The string to send to the node.
|
||||
* @returns: True if the exchange was a succes, false otherwise.
|
||||
*
|
||||
*/
|
||||
Send the supplied message then read back the other node's response
|
||||
and pass that to the user-supplied handler.
|
||||
|
||||
@message The string to send to the node.
|
||||
@returns: True if the exchange was a succes, false otherwise.
|
||||
|
||||
*/
|
||||
// DEPRECATED!
|
||||
bool ESP8266WiFiMesh::exchangeInfo(const char *message, WiFiClient &currClient)
|
||||
{
|
||||
currClient.println( message );
|
||||
currClient.println(message);
|
||||
|
||||
if (!waitForClient(currClient, 1000))
|
||||
return false;
|
||||
if (!waitForClient(currClient, 1000))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
String response = currClient.readStringUntil('\r');
|
||||
currClient.readStringUntil('\n');
|
||||
String response = currClient.readStringUntil('\r');
|
||||
currClient.readStringUntil('\n');
|
||||
|
||||
if (response.length() <= 2)
|
||||
return false;
|
||||
if (response.length() <= 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Pass data to user callback */
|
||||
_handler(response);
|
||||
return true;
|
||||
/* Pass data to user callback */
|
||||
_handler(response);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to the AP at ssid, send them a message then disconnect.
|
||||
*
|
||||
* @targetSSID The name of the AP the other node has set up.
|
||||
* @message The string to send to the node.
|
||||
*
|
||||
*/
|
||||
Connect to the AP at ssid, send them a message then disconnect.
|
||||
|
||||
@targetSSID The name of the AP the other node has set up.
|
||||
@message The string to send to the node.
|
||||
|
||||
*/
|
||||
// DEPRECATED!
|
||||
void ESP8266WiFiMesh::connectToNode(const String &targetSSID, const char *message)
|
||||
{
|
||||
WiFiClient currClient;
|
||||
WiFi.begin( targetSSID.c_str() );
|
||||
WiFiClient currClient;
|
||||
WiFi.begin(targetSSID.c_str());
|
||||
|
||||
int wait = 1500;
|
||||
while((WiFi.status() == WL_DISCONNECTED) && wait--)
|
||||
delay(3);
|
||||
int wait = 1500;
|
||||
while ((WiFi.status() == WL_DISCONNECTED) && wait--)
|
||||
{
|
||||
delay(3);
|
||||
}
|
||||
|
||||
/* If the connection timed out */
|
||||
if (WiFi.status() != 3)
|
||||
return;
|
||||
/* If the connection timed out */
|
||||
if (WiFi.status() != 3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Connect to the node's server */
|
||||
if (!currClient.connect(SERVER_IP_ADDR, SERVER_PORT))
|
||||
return;
|
||||
/* Connect to the node's server */
|
||||
if (!currClient.connect(SERVER_IP_ADDR, SERVER_PORT))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!exchangeInfo(message, currClient))
|
||||
return;
|
||||
if (!exchangeInfo(message, currClient))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
currClient.stop();
|
||||
WiFi.disconnect();
|
||||
currClient.stop();
|
||||
WiFi.disconnect();
|
||||
}
|
||||
|
||||
// DEPRECATED!
|
||||
void ESP8266WiFiMesh::attemptScanKernel(const char *message)
|
||||
{
|
||||
/* Scan for APs */
|
||||
int n = WiFi.scanNetworks();
|
||||
/* Scan for APs */
|
||||
int n = WiFi.scanNetworks();
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
String currentSSID = WiFi.SSID(i);
|
||||
int index = currentSSID.indexOf( _ssidPrefix );
|
||||
uint32_t targetChipID = (currentSSID.substring(index + _ssidPrefix.length())).toInt();
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
String currentSSID = WiFi.SSID(i);
|
||||
int index = currentSSID.indexOf(_ssidPrefix);
|
||||
uint32_t targetChipID = (currentSSID.substring(index + _ssidPrefix.length())).toInt();
|
||||
|
||||
/* Connect to any _suitable_ APs which contain _ssidPrefix */
|
||||
if (index >= 0 && (targetChipID < _chipID)) {
|
||||
/* Connect to any _suitable_ APs which contain _ssidPrefix */
|
||||
if (index >= 0 && (targetChipID < _chipID))
|
||||
{
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
delay(100);
|
||||
connectToNode(currentSSID, message);
|
||||
WiFi.mode(WIFI_AP_STA);
|
||||
delay(100);
|
||||
}
|
||||
}
|
||||
WiFi.mode(WIFI_STA);
|
||||
delay(100);
|
||||
connectToNode(currentSSID, message);
|
||||
WiFi.mode(WIFI_AP_STA);
|
||||
delay(100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DEPRECATED!
|
||||
void ESP8266WiFiMesh::attemptScan(const String &message)
|
||||
{
|
||||
attemptScanKernel(message.c_str());
|
||||
attemptScanKernel(message.c_str());
|
||||
}
|
||||
|
||||
// DEPRECATED!
|
||||
void ESP8266WiFiMesh::attemptScan(char *message)
|
||||
{
|
||||
attemptScanKernel(message);
|
||||
attemptScanKernel(message);
|
||||
}
|
||||
|
||||
// DEPRECATED!
|
||||
template<size_t Size>
|
||||
void ESP8266WiFiMesh::attemptScan(char (&message)[Size])
|
||||
{
|
||||
attemptScanKernel(message);
|
||||
attemptScanKernel(message);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,27 +1,27 @@
|
||||
/*
|
||||
ESP8266WiFiMesh.h - Mesh network node
|
||||
Sets up a Mesh Node which acts as a router, creating a Mesh Network with other nodes.
|
||||
|
||||
Copyright (c) 2015 Julian Fell. All rights reserved.
|
||||
Updated 2018 by Anders Löfgren.
|
||||
|
||||
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
|
||||
ESP8266WiFiMesh.h - Mesh network node
|
||||
Sets up a Mesh Node which acts as a router, creating a Mesh Network with other nodes.
|
||||
|
||||
Copyright (c) 2015 Julian Fell. All rights reserved.
|
||||
Updated 2018 by Anders Löfgren.
|
||||
|
||||
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 __WIFIMESH_H__
|
||||
#define __WIFIMESH_H__
|
||||
|
||||
#include <WiFiClient.h>
|
||||
#include <WiFiClient.h>
|
||||
#include <WiFiServer.h>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
@ -33,342 +33,343 @@
|
||||
|
||||
const String WIFI_MESH_EMPTY_STRING = "";
|
||||
|
||||
class ESP8266WiFiMesh {
|
||||
class ESP8266WiFiMesh
|
||||
{
|
||||
|
||||
private:
|
||||
String _SSID;
|
||||
String _meshName;
|
||||
String _nodeID;
|
||||
uint16_t _serverPort;
|
||||
String _meshPassword;
|
||||
uint8 _meshWiFiChannel;
|
||||
bool _verboseMode;
|
||||
WiFiServer _server;
|
||||
uint32_t _lwipVersion[3];
|
||||
static const uint32_t lwipVersion203Signature[3];
|
||||
String _message = WIFI_MESH_EMPTY_STRING;
|
||||
bool _scanHidden = false;
|
||||
bool _apHidden = false;
|
||||
uint8_t _maxAPStations = 4;
|
||||
int32_t _connectionAttemptTimeoutMs = 10000;
|
||||
int _stationModeTimeoutMs = 5000; // int is the type used in the Arduino core for this particular API, not uint32_t, which is why we use int here.
|
||||
uint32_t _apModeTimeoutMs = 4500;
|
||||
String _SSID;
|
||||
String _meshName;
|
||||
String _nodeID;
|
||||
uint16_t _serverPort;
|
||||
String _meshPassword;
|
||||
uint8 _meshWiFiChannel;
|
||||
bool _verboseMode;
|
||||
WiFiServer _server;
|
||||
uint32_t _lwipVersion[3];
|
||||
static const uint32_t lwipVersion203Signature[3];
|
||||
String _message = WIFI_MESH_EMPTY_STRING;
|
||||
bool _scanHidden = false;
|
||||
bool _apHidden = false;
|
||||
uint8_t _maxAPStations = 4;
|
||||
int32_t _connectionAttemptTimeoutMs = 10000;
|
||||
int _stationModeTimeoutMs = 5000; // int is the type used in the Arduino core for this particular API, not uint32_t, which is why we use int here.
|
||||
uint32_t _apModeTimeoutMs = 4500;
|
||||
|
||||
static String lastSSID;
|
||||
static bool staticIPActivated;
|
||||
static IPAddress staticIP;
|
||||
static IPAddress gateway;
|
||||
static IPAddress subnetMask;
|
||||
static ESP8266WiFiMesh *apController;
|
||||
static String lastSSID;
|
||||
static bool staticIPActivated;
|
||||
static IPAddress staticIP;
|
||||
static IPAddress gateway;
|
||||
static IPAddress subnetMask;
|
||||
static ESP8266WiFiMesh *apController;
|
||||
|
||||
typedef std::function<String(const String &, ESP8266WiFiMesh &)> requestHandlerType;
|
||||
typedef std::function<transmission_status_t(const String &, ESP8266WiFiMesh &)> responseHandlerType;
|
||||
typedef std::function<void(int, ESP8266WiFiMesh &)> networkFilterType;
|
||||
|
||||
requestHandlerType _requestHandler;
|
||||
responseHandlerType _responseHandler;
|
||||
networkFilterType _networkFilter;
|
||||
|
||||
void updateNetworkNames(const String &newMeshName = WIFI_MESH_EMPTY_STRING, const String &newNodeID = WIFI_MESH_EMPTY_STRING);
|
||||
void verboseModePrint(const String &stringToPrint, bool newline = true);
|
||||
void fullStop(WiFiClient &currClient);
|
||||
void initiateConnectionToAP(const String &targetSSID, int targetChannel = NETWORK_INFO_DEFAULT_INT, uint8_t *targetBSSID = NULL);
|
||||
transmission_status_t connectToNode(const String &targetSSID, int targetChannel = NETWORK_INFO_DEFAULT_INT, uint8_t *targetBSSID = NULL);
|
||||
transmission_status_t exchangeInfo(WiFiClient &currClient);
|
||||
bool waitForClientTransmission(WiFiClient &currClient, uint32_t maxWait);
|
||||
transmission_status_t attemptDataTransfer();
|
||||
transmission_status_t attemptDataTransferKernel();
|
||||
void storeLwipVersion();
|
||||
bool atLeastLwipVersion(const uint32_t minLwipVersion[3]);
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////<DEPRECATED> TODO: REMOVE IN 2.5.0////////////////////////////
|
||||
|
||||
typedef std::function<String(String)> compatibilityLayerHandlerType;
|
||||
|
||||
String _ssidPrefix;
|
||||
uint32_t _chipID;
|
||||
|
||||
compatibilityLayerHandlerType _handler = NULL;
|
||||
|
||||
WiFiClient _client;
|
||||
|
||||
void connectToNode(const String &targetSSID, const char *message);
|
||||
bool exchangeInfo(const char *message, WiFiClient &currClient);
|
||||
bool waitForClient(WiFiClient &currClient, int maxWait);
|
||||
void attemptScanKernel(const char *message);
|
||||
|
||||
////////////////////////////</DEPRECATED> TODO: REMOVE IN 2.5.0////////////////////////////
|
||||
|
||||
typedef std::function<String(const String &, ESP8266WiFiMesh &)> requestHandlerType;
|
||||
typedef std::function<transmission_status_t(const String &, ESP8266WiFiMesh &)> responseHandlerType;
|
||||
typedef std::function<void(int, ESP8266WiFiMesh &)> networkFilterType;
|
||||
|
||||
requestHandlerType _requestHandler;
|
||||
responseHandlerType _responseHandler;
|
||||
networkFilterType _networkFilter;
|
||||
|
||||
void updateNetworkNames(const String &newMeshName = WIFI_MESH_EMPTY_STRING, const String &newNodeID = WIFI_MESH_EMPTY_STRING);
|
||||
void verboseModePrint(const String &stringToPrint, bool newline = true);
|
||||
void fullStop(WiFiClient &currClient);
|
||||
void initiateConnectionToAP(const String &targetSSID, int targetChannel = NETWORK_INFO_DEFAULT_INT, uint8_t *targetBSSID = NULL);
|
||||
transmission_status_t connectToNode(const String &targetSSID, int targetChannel = NETWORK_INFO_DEFAULT_INT, uint8_t *targetBSSID = NULL);
|
||||
transmission_status_t exchangeInfo(WiFiClient &currClient);
|
||||
bool waitForClientTransmission(WiFiClient &currClient, uint32_t maxWait);
|
||||
transmission_status_t attemptDataTransfer();
|
||||
transmission_status_t attemptDataTransferKernel();
|
||||
void storeLwipVersion();
|
||||
bool atLeastLwipVersion(const uint32_t minLwipVersion[3]);
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////<DEPRECATED> TODO: REMOVE IN 2.5.0////////////////////////////
|
||||
|
||||
typedef std::function<String(String)> compatibilityLayerHandlerType;
|
||||
|
||||
String _ssidPrefix;
|
||||
uint32_t _chipID;
|
||||
|
||||
compatibilityLayerHandlerType _handler = NULL;
|
||||
|
||||
WiFiClient _client;
|
||||
|
||||
void connectToNode(const String &targetSSID, const char *message);
|
||||
bool exchangeInfo(const char *message, WiFiClient &currClient);
|
||||
bool waitForClient(WiFiClient &currClient, int maxWait);
|
||||
void attemptScanKernel(const char *message);
|
||||
|
||||
////////////////////////////</DEPRECATED> TODO: REMOVE IN 2.5.0////////////////////////////
|
||||
|
||||
|
||||
|
||||
public:
|
||||
|
||||
////////////////////////////<DEPRECATED> TODO: REMOVE IN 2.5.0////////////////////////////
|
||||
|
||||
/**
|
||||
* WiFiMesh Constructor method. Creates a WiFi Mesh Node, ready to be initialised.
|
||||
*
|
||||
* @chipID A unique identifier number for the node.
|
||||
* @handler The callback handler for dealing with received messages. Takes a string as an argument which
|
||||
* is the string received from another node and returns the string to send back.
|
||||
*
|
||||
*/
|
||||
ESP8266WiFiMesh(uint32_t chipID, compatibilityLayerHandlerType handler);
|
||||
////////////////////////////<DEPRECATED> TODO: REMOVE IN 2.5.0////////////////////////////
|
||||
|
||||
/**
|
||||
* Scan for other nodes, and exchange the chosen message with any that are found.
|
||||
*
|
||||
* @message The message to send to all other nodes.
|
||||
*
|
||||
*/
|
||||
void attemptScan(const String &message);
|
||||
void attemptScan(char *message);
|
||||
|
||||
template<size_t Size>
|
||||
void attemptScan(char (&message)[Size]);
|
||||
|
||||
////////////////////////////</DEPRECATED> TODO: REMOVE IN 2.5.0////////////////////////////
|
||||
/**
|
||||
WiFiMesh Constructor method. Creates a WiFi Mesh Node, ready to be initialised.
|
||||
|
||||
~ESP8266WiFiMesh();
|
||||
|
||||
/**
|
||||
* WiFiMesh Constructor method. Creates a WiFi Mesh Node, ready to be initialised.
|
||||
*
|
||||
* @param requestHandler The callback handler for dealing with received requests. Takes a string as an argument which
|
||||
* is the request string received from another node and returns the string to send back.
|
||||
* @param responseHandler The callback handler for dealing with received responses. Takes a string as an argument which
|
||||
* is the response string received from another node. Returns a transmission status code as a transmission_status_t.
|
||||
* @param networkFilter The callback handler for deciding which WiFi networks to connect to.
|
||||
* @param meshPassword The WiFi password for the mesh network.
|
||||
* @param meshName The name of the mesh network. Used as prefix for the node SSID and to find other network nodes in the example network filter function.
|
||||
* @param nodeID The id for this mesh node. Used as suffix for the node SSID. If set to "", the id will default to ESP.getChipId().
|
||||
* @param verboseMode Determines if we should print the events occurring in the library to Serial. Off by default.
|
||||
* @param meshWiFiChannel The WiFi channel used by the mesh network. Valid values are integers from 1 to 13. Defaults to 1.
|
||||
* WARNING: The ESP8266 has only one WiFi channel, and the the station/client mode is always prioritized for channel selection.
|
||||
* This can cause problems if several ESP8266WiFiMesh instances exist on the same ESP8266 and use different WiFi channels.
|
||||
* In such a case, whenever the station of one ESP8266WiFiMesh instance connects to an AP, it will silently force the
|
||||
* WiFi channel of any active AP on the ESP8266 to match that of the station. This will cause disconnects and possibly
|
||||
* make it impossible for other stations to detect the APs whose WiFi channels have changed.
|
||||
* @param serverPort The server port used by the AP of the ESP8266WiFiMesh instance. If multiple APs exist on a single ESP8266, each requires a separate server port.
|
||||
* If two AP:s on the same ESP8266 are using the same server port, they will not be able to have both server instances active at the same time.
|
||||
* This is managed automatically by the activateAP method.
|
||||
*
|
||||
*/
|
||||
ESP8266WiFiMesh(requestHandlerType requestHandler, responseHandlerType responseHandler, networkFilterType networkFilter,
|
||||
const String &meshPassword, const String &meshName = "MeshNode_", const String &nodeID = WIFI_MESH_EMPTY_STRING, bool verboseMode = false,
|
||||
uint8 meshWiFiChannel = 1, uint16_t serverPort = 4011);
|
||||
|
||||
/**
|
||||
* A vector that contains the NetworkInfo for each WiFi network to connect to.
|
||||
* The connectionQueue vector is cleared before each new scan and filled via the networkFilter callback function once the scan completes.
|
||||
* WiFi connections will start with connectionQueue[0] and then incrementally proceed to higher vector positions.
|
||||
* Note that old network indicies often are invalidated whenever a new WiFi network scan occurs.
|
||||
*/
|
||||
static std::vector<NetworkInfo> connectionQueue;
|
||||
@chipID A unique identifier number for the node.
|
||||
@handler The callback handler for dealing with received messages. Takes a string as an argument which
|
||||
is the string received from another node and returns the string to send back.
|
||||
|
||||
/**
|
||||
* A vector with the TransmissionResult for each AP to which a transmission was attempted during the latest attemptTransmission call.
|
||||
* The latestTransmissionOutcomes vector is cleared before each new transmission attempt.
|
||||
* Connection attempts are indexed in the same order they were attempted.
|
||||
* Note that old network indicies often are invalidated whenever a new WiFi network scan occurs.
|
||||
*/
|
||||
static std::vector<TransmissionResult> latestTransmissionOutcomes;
|
||||
*/
|
||||
ESP8266WiFiMesh(uint32_t chipID, compatibilityLayerHandlerType handler);
|
||||
|
||||
/**
|
||||
* @returns True if latest transmission was successful (i.e. latestTransmissionOutcomes is not empty and all entries have transmissionStatus TS_TRANSMISSION_COMPLETE). False otherwise.
|
||||
*/
|
||||
static bool latestTransmissionSuccessful();
|
||||
/**
|
||||
Scan for other nodes, and exchange the chosen message with any that are found.
|
||||
|
||||
/**
|
||||
* Initialises the node.
|
||||
*/
|
||||
void begin();
|
||||
@message The message to send to all other nodes.
|
||||
|
||||
/**
|
||||
* Each AP requires a separate server port. If two AP:s are using the same server port, they will not be able to have both server instances active at the same time.
|
||||
* This is managed automatically by the activateAP method.
|
||||
*/
|
||||
void activateAP();
|
||||
void deactivateAP();
|
||||
void restartAP();
|
||||
*/
|
||||
void attemptScan(const String &message);
|
||||
void attemptScan(char *message);
|
||||
|
||||
/**
|
||||
* Get the ESP8266WiFiMesh instance currently in control of the ESP8266 AP.
|
||||
* Note that the result will be nullptr when there is no active AP controller.
|
||||
* If another instance takes control over the AP after the pointer is created,
|
||||
* the created pointer will still point to the old AP instance.
|
||||
*
|
||||
* @returns A pointer to the ESP8266WiFiMesh instance currently in control of the ESP8266 AP,
|
||||
* or nullptr if there is no active AP controller.
|
||||
*/
|
||||
static ESP8266WiFiMesh * getAPController();
|
||||
|
||||
/**
|
||||
* Check if this ESP8266WiFiMesh instance is in control of the ESP8266 AP.
|
||||
*
|
||||
* @returns True if this ESP8266WiFiMesh instance is in control of the ESP8266 AP. False otherwise.
|
||||
*/
|
||||
bool isAPController();
|
||||
template<size_t Size>
|
||||
void attemptScan(char (&message)[Size]);
|
||||
|
||||
/**
|
||||
* Change the WiFi channel used by this ESP8266WiFiMesh instance.
|
||||
* Will also change the WiFi channel for the active AP if this ESP8266WiFiMesh instance is the current AP controller and it is possible to change channel.
|
||||
*
|
||||
* WARNING: The ESP8266 has only one WiFi channel, and the the station/client mode is always prioritized for channel selection.
|
||||
* This can cause problems if several ESP8266WiFiMesh instances exist on the same ESP8266 and use different WiFi channels.
|
||||
* In such a case, whenever the station of one ESP8266WiFiMesh instance connects to an AP, it will silently force the
|
||||
* WiFi channel of any active AP on the ESP8266 to match that of the station. This will cause disconnects and possibly
|
||||
* make it impossible for other stations to detect the APs whose WiFi channels have changed.
|
||||
*
|
||||
* @param newWiFiChannel The WiFi channel to change to. Valid values are integers from 1 to 13.
|
||||
*
|
||||
*/
|
||||
void setWiFiChannel(uint8 newWiFiChannel);
|
||||
uint8 getWiFiChannel();
|
||||
////////////////////////////</DEPRECATED> TODO: REMOVE IN 2.5.0////////////////////////////
|
||||
|
||||
/**
|
||||
* Change the mesh name used by this ESP8266WiFiMesh instance.
|
||||
* Will also change the mesh name (SSID prefix) for the active AP if this ESP8266WiFiMesh instance is the current AP controller.
|
||||
*
|
||||
* @param newMeshName The mesh name to change to.
|
||||
*/
|
||||
void setMeshName(const String &newMeshName);
|
||||
String getMeshName();
|
||||
|
||||
/**
|
||||
* Change the node id used by this ESP8266WiFiMesh instance.
|
||||
* Will also change the node id (SSID suffix) for the active AP if this ESP8266WiFiMesh instance is the current AP controller.
|
||||
*
|
||||
* @param newNodeID The node id to change to.
|
||||
*/
|
||||
void setNodeID(const String &newNodeID);
|
||||
String getNodeID();
|
||||
|
||||
/**
|
||||
* Change the SSID (mesh name + node id) used by this ESP8266WiFiMesh instance.
|
||||
* Will also change the SSID for the active AP if this ESP8266WiFiMesh instance is the current AP controller.
|
||||
*
|
||||
* @param newMeshName The mesh name to change to. Will be the SSID prefix.
|
||||
* @param newNodeID The node id to change to. Will be the SSID suffix.
|
||||
*/
|
||||
void setSSID(const String &newMeshName, const String &newNodeID);
|
||||
String getSSID();
|
||||
|
||||
/**
|
||||
* Set the message that will be sent to other nodes when calling attemptTransmission.
|
||||
*
|
||||
* @param newMessage The message to send.
|
||||
*/
|
||||
void setMessage(const String &newMessage);
|
||||
String getMessage();
|
||||
~ESP8266WiFiMesh();
|
||||
|
||||
/**
|
||||
* If AP connection already exists, and the initialDisconnect argument is set to false, send message only to the already connected AP.
|
||||
* Otherwise, scan for other networks, send the scan result to networkFilter and then transmit the message to the networks found in connectionQueue.
|
||||
*
|
||||
* @param message The message to send to other nodes. It will be stored in the class instance until replaced via attemptTransmission or setMessage.
|
||||
* @param concludingDisconnect Disconnect from AP once transmission is complete.
|
||||
* @param initialDisconnect Disconnect from any currently connected AP before attempting transmission.
|
||||
* @param noScan Do not scan for new networks and do not call networkFilter function. Will only use the data already in connectionQueue for the transmission.
|
||||
* @param scanAllWiFiChannels Scan all WiFi channels during a WiFi scan, instead of just the channel the ESP8266WiFiMesh instance is using.
|
||||
* Scanning all WiFi channels takes about 2100 ms, compared to just 60 ms if only channel 1 (standard) is scanned.
|
||||
* Note that if the ESP8266 has an active AP, that AP will switch WiFi channel to match that of any other AP the ESP8266 connects to.
|
||||
* This can make it impossible for other nodes to detect the AP if they are scanning the wrong WiFi channel.
|
||||
*/
|
||||
void attemptTransmission(const String &message, bool concludingDisconnect = true, bool initialDisconnect = false, bool noScan = false, bool scanAllWiFiChannels = false);
|
||||
/**
|
||||
WiFiMesh Constructor method. Creates a WiFi Mesh Node, ready to be initialised.
|
||||
|
||||
/**
|
||||
* If any clients are connected, accept their requests and call the requestHandler function for each one.
|
||||
*/
|
||||
void acceptRequest();
|
||||
@param requestHandler The callback handler for dealing with received requests. Takes a string as an argument which
|
||||
is the request string received from another node and returns the string to send back.
|
||||
@param responseHandler The callback handler for dealing with received responses. Takes a string as an argument which
|
||||
is the response string received from another node. Returns a transmission status code as a transmission_status_t.
|
||||
@param networkFilter The callback handler for deciding which WiFi networks to connect to.
|
||||
@param meshPassword The WiFi password for the mesh network.
|
||||
@param meshName The name of the mesh network. Used as prefix for the node SSID and to find other network nodes in the example network filter function.
|
||||
@param nodeID The id for this mesh node. Used as suffix for the node SSID. If set to "", the id will default to ESP.getChipId().
|
||||
@param verboseMode Determines if we should print the events occurring in the library to Serial. Off by default.
|
||||
@param meshWiFiChannel The WiFi channel used by the mesh network. Valid values are integers from 1 to 13. Defaults to 1.
|
||||
WARNING: The ESP8266 has only one WiFi channel, and the the station/client mode is always prioritized for channel selection.
|
||||
This can cause problems if several ESP8266WiFiMesh instances exist on the same ESP8266 and use different WiFi channels.
|
||||
In such a case, whenever the station of one ESP8266WiFiMesh instance connects to an AP, it will silently force the
|
||||
WiFi channel of any active AP on the ESP8266 to match that of the station. This will cause disconnects and possibly
|
||||
make it impossible for other stations to detect the APs whose WiFi channels have changed.
|
||||
@param serverPort The server port used by the AP of the ESP8266WiFiMesh instance. If multiple APs exist on a single ESP8266, each requires a separate server port.
|
||||
If two AP:s on the same ESP8266 are using the same server port, they will not be able to have both server instances active at the same time.
|
||||
This is managed automatically by the activateAP method.
|
||||
|
||||
/**
|
||||
* Set a static IP address for the ESP8266 and activate use of static IP.
|
||||
* The static IP needs to be at the same subnet as the server's gateway.
|
||||
*/
|
||||
void setStaticIP(const IPAddress &newIP);
|
||||
IPAddress getStaticIP();
|
||||
void disableStaticIP();
|
||||
*/
|
||||
ESP8266WiFiMesh(requestHandlerType requestHandler, responseHandlerType responseHandler, networkFilterType networkFilter,
|
||||
const String &meshPassword, const String &meshName = "MeshNode_", const String &nodeID = WIFI_MESH_EMPTY_STRING, bool verboseMode = false,
|
||||
uint8 meshWiFiChannel = 1, uint16_t serverPort = 4011);
|
||||
|
||||
/**
|
||||
* An empty IPAddress. Used as default when no IP is set.
|
||||
*/
|
||||
static const IPAddress emptyIP;
|
||||
/**
|
||||
A vector that contains the NetworkInfo for each WiFi network to connect to.
|
||||
The connectionQueue vector is cleared before each new scan and filled via the networkFilter callback function once the scan completes.
|
||||
WiFi connections will start with connectionQueue[0] and then incrementally proceed to higher vector positions.
|
||||
Note that old network indicies often are invalidated whenever a new WiFi network scan occurs.
|
||||
*/
|
||||
static std::vector<NetworkInfo> connectionQueue;
|
||||
|
||||
void setRequestHandler(requestHandlerType requestHandler);
|
||||
requestHandlerType getRequestHandler();
|
||||
|
||||
void setResponseHandler(responseHandlerType responseHandler);
|
||||
responseHandlerType getResponseHandler();
|
||||
|
||||
void setNetworkFilter(networkFilterType networkFilter);
|
||||
networkFilterType getNetworkFilter();
|
||||
/**
|
||||
A vector with the TransmissionResult for each AP to which a transmission was attempted during the latest attemptTransmission call.
|
||||
The latestTransmissionOutcomes vector is cleared before each new transmission attempt.
|
||||
Connection attempts are indexed in the same order they were attempted.
|
||||
Note that old network indicies often are invalidated whenever a new WiFi network scan occurs.
|
||||
*/
|
||||
static std::vector<TransmissionResult> latestTransmissionOutcomes;
|
||||
|
||||
/**
|
||||
* Set whether scan results from this ESP8266WiFiMesh instance will include WiFi networks with hidden SSIDs.
|
||||
* This is false by default.
|
||||
* The SSID field of a found hidden network will be blank in the scan results.
|
||||
* WiFi.isHidden(networkIndex) can be used to verify that a found network is hidden.
|
||||
*
|
||||
* @param scanHidden If true, WiFi networks with hidden SSIDs will be included in scan results.
|
||||
*/
|
||||
void setScanHidden(bool scanHidden);
|
||||
bool getScanHidden();
|
||||
/**
|
||||
@returns True if latest transmission was successful (i.e. latestTransmissionOutcomes is not empty and all entries have transmissionStatus TS_TRANSMISSION_COMPLETE). False otherwise.
|
||||
*/
|
||||
static bool latestTransmissionSuccessful();
|
||||
|
||||
/**
|
||||
* Set whether the AP controlled by this ESP8266WiFiMesh instance will have a WiFi network with hidden SSID.
|
||||
* This is false by default.
|
||||
* Will also change the setting for the active AP if this ESP8266WiFiMesh instance is the current AP controller.
|
||||
*
|
||||
* @param apHidden If true, the WiFi network created will have a hidden SSID.
|
||||
*/
|
||||
void setAPHidden(bool apHidden);
|
||||
bool getAPHidden();
|
||||
/**
|
||||
Initialises the node.
|
||||
*/
|
||||
void begin();
|
||||
|
||||
/**
|
||||
* Set the maximum number of stations that can simultaneously be connected to the AP controlled by this ESP8266WiFiMesh instance.
|
||||
* This number is 4 by default.
|
||||
* Once the max number has been reached, any other station that wants to connect will be forced to wait until an already connected station disconnects.
|
||||
* The more stations that are connected, the more memory is required.
|
||||
* Will also change the setting for the active AP if this ESP8266WiFiMesh instance is the current AP controller.
|
||||
*
|
||||
* @param maxAPStations The maximum number of simultaneous station connections allowed. Valid values are 0 to 8.
|
||||
*/
|
||||
void setMaxAPStations(uint8_t maxAPStations);
|
||||
bool getMaxAPStations();
|
||||
/**
|
||||
Each AP requires a separate server port. If two AP:s are using the same server port, they will not be able to have both server instances active at the same time.
|
||||
This is managed automatically by the activateAP method.
|
||||
*/
|
||||
void activateAP();
|
||||
void deactivateAP();
|
||||
void restartAP();
|
||||
|
||||
/**
|
||||
* Set the timeout for each attempt to connect to another AP that occurs through the attemptTransmission method by this ESP8266WiFiMesh instance.
|
||||
* The timeout is 10 000 ms by default.
|
||||
*
|
||||
* @param connectionAttemptTimeoutMs The timeout for each connection attempt, in milliseconds.
|
||||
*/
|
||||
void setConnectionAttemptTimeout(int32_t connectionAttemptTimeoutMs);
|
||||
int32_t getConnectionAttemptTimeout();
|
||||
/**
|
||||
Get the ESP8266WiFiMesh instance currently in control of the ESP8266 AP.
|
||||
Note that the result will be nullptr when there is no active AP controller.
|
||||
If another instance takes control over the AP after the pointer is created,
|
||||
the created pointer will still point to the old AP instance.
|
||||
|
||||
/**
|
||||
* Set the timeout to use for transmissions when this ESP8266WiFiMesh instance acts as a station (i.e. when connected to another AP).
|
||||
* This will affect the timeout of the attemptTransmission method once a connection to an AP has been established.
|
||||
* The timeout is 5 000 ms by default.
|
||||
*
|
||||
* @param stationModeTimeoutMs The timeout to use, in milliseconds.
|
||||
*/
|
||||
void setStationModeTimeout(int stationModeTimeoutMs);
|
||||
int getStationModeTimeout();
|
||||
@returns A pointer to the ESP8266WiFiMesh instance currently in control of the ESP8266 AP,
|
||||
or nullptr if there is no active AP controller.
|
||||
*/
|
||||
static ESP8266WiFiMesh * getAPController();
|
||||
|
||||
/**
|
||||
* Set the timeout to use for transmissions when this ESP8266WiFiMesh instance acts as an AP (i.e. when receiving connections from other stations).
|
||||
* This will affect the timeout of the acceptRequest method.
|
||||
* The timeout is 4 500 ms by default.
|
||||
* Will also change the setting for the active AP if this ESP8266WiFiMesh instance is the current AP controller.
|
||||
*
|
||||
* @param apModeTimeoutMs The timeout to use, in milliseconds.
|
||||
*/
|
||||
void setAPModeTimeout(uint32_t apModeTimeoutMs);
|
||||
uint32_t getAPModeTimeout();
|
||||
/**
|
||||
Check if this ESP8266WiFiMesh instance is in control of the ESP8266 AP.
|
||||
|
||||
@returns True if this ESP8266WiFiMesh instance is in control of the ESP8266 AP. False otherwise.
|
||||
*/
|
||||
bool isAPController();
|
||||
|
||||
/**
|
||||
Change the WiFi channel used by this ESP8266WiFiMesh instance.
|
||||
Will also change the WiFi channel for the active AP if this ESP8266WiFiMesh instance is the current AP controller and it is possible to change channel.
|
||||
|
||||
WARNING: The ESP8266 has only one WiFi channel, and the the station/client mode is always prioritized for channel selection.
|
||||
This can cause problems if several ESP8266WiFiMesh instances exist on the same ESP8266 and use different WiFi channels.
|
||||
In such a case, whenever the station of one ESP8266WiFiMesh instance connects to an AP, it will silently force the
|
||||
WiFi channel of any active AP on the ESP8266 to match that of the station. This will cause disconnects and possibly
|
||||
make it impossible for other stations to detect the APs whose WiFi channels have changed.
|
||||
|
||||
@param newWiFiChannel The WiFi channel to change to. Valid values are integers from 1 to 13.
|
||||
|
||||
*/
|
||||
void setWiFiChannel(uint8 newWiFiChannel);
|
||||
uint8 getWiFiChannel();
|
||||
|
||||
/**
|
||||
Change the mesh name used by this ESP8266WiFiMesh instance.
|
||||
Will also change the mesh name (SSID prefix) for the active AP if this ESP8266WiFiMesh instance is the current AP controller.
|
||||
|
||||
@param newMeshName The mesh name to change to.
|
||||
*/
|
||||
void setMeshName(const String &newMeshName);
|
||||
String getMeshName();
|
||||
|
||||
/**
|
||||
Change the node id used by this ESP8266WiFiMesh instance.
|
||||
Will also change the node id (SSID suffix) for the active AP if this ESP8266WiFiMesh instance is the current AP controller.
|
||||
|
||||
@param newNodeID The node id to change to.
|
||||
*/
|
||||
void setNodeID(const String &newNodeID);
|
||||
String getNodeID();
|
||||
|
||||
/**
|
||||
Change the SSID (mesh name + node id) used by this ESP8266WiFiMesh instance.
|
||||
Will also change the SSID for the active AP if this ESP8266WiFiMesh instance is the current AP controller.
|
||||
|
||||
@param newMeshName The mesh name to change to. Will be the SSID prefix.
|
||||
@param newNodeID The node id to change to. Will be the SSID suffix.
|
||||
*/
|
||||
void setSSID(const String &newMeshName, const String &newNodeID);
|
||||
String getSSID();
|
||||
|
||||
/**
|
||||
Set the message that will be sent to other nodes when calling attemptTransmission.
|
||||
|
||||
@param newMessage The message to send.
|
||||
*/
|
||||
void setMessage(const String &newMessage);
|
||||
String getMessage();
|
||||
|
||||
/**
|
||||
If AP connection already exists, and the initialDisconnect argument is set to false, send message only to the already connected AP.
|
||||
Otherwise, scan for other networks, send the scan result to networkFilter and then transmit the message to the networks found in connectionQueue.
|
||||
|
||||
@param message The message to send to other nodes. It will be stored in the class instance until replaced via attemptTransmission or setMessage.
|
||||
@param concludingDisconnect Disconnect from AP once transmission is complete.
|
||||
@param initialDisconnect Disconnect from any currently connected AP before attempting transmission.
|
||||
@param noScan Do not scan for new networks and do not call networkFilter function. Will only use the data already in connectionQueue for the transmission.
|
||||
@param scanAllWiFiChannels Scan all WiFi channels during a WiFi scan, instead of just the channel the ESP8266WiFiMesh instance is using.
|
||||
Scanning all WiFi channels takes about 2100 ms, compared to just 60 ms if only channel 1 (standard) is scanned.
|
||||
Note that if the ESP8266 has an active AP, that AP will switch WiFi channel to match that of any other AP the ESP8266 connects to.
|
||||
This can make it impossible for other nodes to detect the AP if they are scanning the wrong WiFi channel.
|
||||
*/
|
||||
void attemptTransmission(const String &message, bool concludingDisconnect = true, bool initialDisconnect = false, bool noScan = false, bool scanAllWiFiChannels = false);
|
||||
|
||||
/**
|
||||
If any clients are connected, accept their requests and call the requestHandler function for each one.
|
||||
*/
|
||||
void acceptRequest();
|
||||
|
||||
/**
|
||||
Set a static IP address for the ESP8266 and activate use of static IP.
|
||||
The static IP needs to be at the same subnet as the server's gateway.
|
||||
*/
|
||||
void setStaticIP(const IPAddress &newIP);
|
||||
IPAddress getStaticIP();
|
||||
void disableStaticIP();
|
||||
|
||||
/**
|
||||
An empty IPAddress. Used as default when no IP is set.
|
||||
*/
|
||||
static const IPAddress emptyIP;
|
||||
|
||||
void setRequestHandler(requestHandlerType requestHandler);
|
||||
requestHandlerType getRequestHandler();
|
||||
|
||||
void setResponseHandler(responseHandlerType responseHandler);
|
||||
responseHandlerType getResponseHandler();
|
||||
|
||||
void setNetworkFilter(networkFilterType networkFilter);
|
||||
networkFilterType getNetworkFilter();
|
||||
|
||||
/**
|
||||
Set whether scan results from this ESP8266WiFiMesh instance will include WiFi networks with hidden SSIDs.
|
||||
This is false by default.
|
||||
The SSID field of a found hidden network will be blank in the scan results.
|
||||
WiFi.isHidden(networkIndex) can be used to verify that a found network is hidden.
|
||||
|
||||
@param scanHidden If true, WiFi networks with hidden SSIDs will be included in scan results.
|
||||
*/
|
||||
void setScanHidden(bool scanHidden);
|
||||
bool getScanHidden();
|
||||
|
||||
/**
|
||||
Set whether the AP controlled by this ESP8266WiFiMesh instance will have a WiFi network with hidden SSID.
|
||||
This is false by default.
|
||||
Will also change the setting for the active AP if this ESP8266WiFiMesh instance is the current AP controller.
|
||||
|
||||
@param apHidden If true, the WiFi network created will have a hidden SSID.
|
||||
*/
|
||||
void setAPHidden(bool apHidden);
|
||||
bool getAPHidden();
|
||||
|
||||
/**
|
||||
Set the maximum number of stations that can simultaneously be connected to the AP controlled by this ESP8266WiFiMesh instance.
|
||||
This number is 4 by default.
|
||||
Once the max number has been reached, any other station that wants to connect will be forced to wait until an already connected station disconnects.
|
||||
The more stations that are connected, the more memory is required.
|
||||
Will also change the setting for the active AP if this ESP8266WiFiMesh instance is the current AP controller.
|
||||
|
||||
@param maxAPStations The maximum number of simultaneous station connections allowed. Valid values are 0 to 8.
|
||||
*/
|
||||
void setMaxAPStations(uint8_t maxAPStations);
|
||||
bool getMaxAPStations();
|
||||
|
||||
/**
|
||||
Set the timeout for each attempt to connect to another AP that occurs through the attemptTransmission method by this ESP8266WiFiMesh instance.
|
||||
The timeout is 10 000 ms by default.
|
||||
|
||||
@param connectionAttemptTimeoutMs The timeout for each connection attempt, in milliseconds.
|
||||
*/
|
||||
void setConnectionAttemptTimeout(int32_t connectionAttemptTimeoutMs);
|
||||
int32_t getConnectionAttemptTimeout();
|
||||
|
||||
/**
|
||||
Set the timeout to use for transmissions when this ESP8266WiFiMesh instance acts as a station (i.e. when connected to another AP).
|
||||
This will affect the timeout of the attemptTransmission method once a connection to an AP has been established.
|
||||
The timeout is 5 000 ms by default.
|
||||
|
||||
@param stationModeTimeoutMs The timeout to use, in milliseconds.
|
||||
*/
|
||||
void setStationModeTimeout(int stationModeTimeoutMs);
|
||||
int getStationModeTimeout();
|
||||
|
||||
/**
|
||||
Set the timeout to use for transmissions when this ESP8266WiFiMesh instance acts as an AP (i.e. when receiving connections from other stations).
|
||||
This will affect the timeout of the acceptRequest method.
|
||||
The timeout is 4 500 ms by default.
|
||||
Will also change the setting for the active AP if this ESP8266WiFiMesh instance is the current AP controller.
|
||||
|
||||
@param apModeTimeoutMs The timeout to use, in milliseconds.
|
||||
*/
|
||||
void setAPModeTimeout(uint32_t apModeTimeoutMs);
|
||||
uint32_t getAPModeTimeout();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,77 +1,77 @@
|
||||
/*
|
||||
* NetworkInfo
|
||||
* Copyright (C) 2018 Anders Löfgren
|
||||
*
|
||||
* License (MIT license):
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
NetworkInfo
|
||||
Copyright (C) 2018 Anders Löfgren
|
||||
|
||||
License (MIT license):
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "NetworkInfo.h"
|
||||
|
||||
void NetworkInfo::copyBSSID(uint8_t newBSSID[6])
|
||||
{
|
||||
if(newBSSID != NULL)
|
||||
{
|
||||
if(BSSID == NULL)
|
||||
if (newBSSID != NULL)
|
||||
{
|
||||
BSSID = _bssidArray;
|
||||
if (BSSID == NULL)
|
||||
{
|
||||
BSSID = _bssidArray;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
BSSID[i] = newBSSID[i];
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < 6; i++)
|
||||
else
|
||||
{
|
||||
BSSID[i] = newBSSID[i];
|
||||
BSSID = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BSSID = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
NetworkInfo::NetworkInfo(int newNetworkIndex, bool autofill) : networkIndex(newNetworkIndex)
|
||||
{
|
||||
if(autofill)
|
||||
{
|
||||
SSID = WiFi.SSID(newNetworkIndex);
|
||||
wifiChannel = WiFi.channel(newNetworkIndex);
|
||||
copyBSSID(WiFi.BSSID(newNetworkIndex));
|
||||
}
|
||||
{
|
||||
if (autofill)
|
||||
{
|
||||
SSID = WiFi.SSID(newNetworkIndex);
|
||||
wifiChannel = WiFi.channel(newNetworkIndex);
|
||||
copyBSSID(WiFi.BSSID(newNetworkIndex));
|
||||
}
|
||||
}
|
||||
|
||||
NetworkInfo::NetworkInfo(const String &newSSID, int newWiFiChannel, uint8_t newBSSID[6], int newNetworkIndex) :
|
||||
SSID(newSSID), wifiChannel(newWiFiChannel), networkIndex(newNetworkIndex)
|
||||
NetworkInfo::NetworkInfo(const String &newSSID, int newWiFiChannel, uint8_t newBSSID[6], int newNetworkIndex) :
|
||||
SSID(newSSID), wifiChannel(newWiFiChannel), networkIndex(newNetworkIndex)
|
||||
{
|
||||
copyBSSID(newBSSID);
|
||||
copyBSSID(newBSSID);
|
||||
}
|
||||
|
||||
NetworkInfo::NetworkInfo(const NetworkInfo &other) : SSID(other.SSID), wifiChannel(other.wifiChannel), networkIndex(other.networkIndex)
|
||||
{
|
||||
copyBSSID(other.BSSID);
|
||||
copyBSSID(other.BSSID);
|
||||
}
|
||||
|
||||
NetworkInfo & NetworkInfo::operator=(const NetworkInfo &other)
|
||||
{
|
||||
SSID = other.SSID;
|
||||
wifiChannel = other.wifiChannel;
|
||||
copyBSSID(other.BSSID);
|
||||
networkIndex = other.networkIndex;
|
||||
return *this;
|
||||
SSID = other.SSID;
|
||||
wifiChannel = other.wifiChannel;
|
||||
copyBSSID(other.BSSID);
|
||||
networkIndex = other.networkIndex;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1,27 +1,27 @@
|
||||
/*
|
||||
* NetworkInfo
|
||||
* Copyright (C) 2018 Anders Löfgren
|
||||
*
|
||||
* License (MIT license):
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
NetworkInfo
|
||||
Copyright (C) 2018 Anders Löfgren
|
||||
|
||||
License (MIT license):
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __NETWORKINFO_H__
|
||||
#define __NETWORKINFO_H__
|
||||
@ -30,40 +30,41 @@
|
||||
|
||||
const int NETWORK_INFO_DEFAULT_INT = -1;
|
||||
|
||||
class NetworkInfo {
|
||||
class NetworkInfo
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
uint8_t _bssidArray[6] {0};
|
||||
uint8_t _bssidArray[6] {0};
|
||||
|
||||
public:
|
||||
|
||||
String SSID = "";
|
||||
int wifiChannel = NETWORK_INFO_DEFAULT_INT;
|
||||
uint8_t *BSSID = NULL;
|
||||
int networkIndex = NETWORK_INFO_DEFAULT_INT;
|
||||
String SSID = "";
|
||||
int wifiChannel = NETWORK_INFO_DEFAULT_INT;
|
||||
uint8_t *BSSID = NULL;
|
||||
int networkIndex = NETWORK_INFO_DEFAULT_INT;
|
||||
|
||||
/**
|
||||
* @param autofill Automatically fill in the rest of the network info using newNetworkIndex and the WiFi scan results.
|
||||
*/
|
||||
NetworkInfo(int newNetworkIndex, bool autofill = true);
|
||||
/**
|
||||
@param autofill Automatically fill in the rest of the network info using newNetworkIndex and the WiFi scan results.
|
||||
*/
|
||||
NetworkInfo(int newNetworkIndex, bool autofill = true);
|
||||
|
||||
/**
|
||||
* Without giving channel and BSSID, connection time is longer.
|
||||
*/
|
||||
NetworkInfo(const String &newSSID, int newWiFiChannel = NETWORK_INFO_DEFAULT_INT, uint8_t newBSSID[6] = NULL, int newNetworkIndex = NETWORK_INFO_DEFAULT_INT);
|
||||
/**
|
||||
Without giving channel and BSSID, connection time is longer.
|
||||
*/
|
||||
NetworkInfo(const String &newSSID, int newWiFiChannel = NETWORK_INFO_DEFAULT_INT, uint8_t newBSSID[6] = NULL, int newNetworkIndex = NETWORK_INFO_DEFAULT_INT);
|
||||
|
||||
NetworkInfo(const NetworkInfo &other);
|
||||
NetworkInfo(const NetworkInfo &other);
|
||||
|
||||
NetworkInfo & operator=(const NetworkInfo &other);
|
||||
NetworkInfo & operator=(const NetworkInfo &other);
|
||||
|
||||
// No need for explicit destructor with current class design
|
||||
// No need for explicit destructor with current class design
|
||||
|
||||
/**
|
||||
* Copy newBSSID into BSSID.
|
||||
* Prefer this method for changing NetworkInfo BSSID, unless you actually want to change the BSSID pointer.
|
||||
*/
|
||||
void copyBSSID(uint8_t newBSSID[6]);
|
||||
/**
|
||||
Copy newBSSID into BSSID.
|
||||
Prefer this method for changing NetworkInfo BSSID, unless you actually want to change the BSSID pointer.
|
||||
*/
|
||||
void copyBSSID(uint8_t newBSSID[6]);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,42 +1,42 @@
|
||||
/*
|
||||
* TransmissionResult
|
||||
* Copyright (C) 2018 Anders Löfgren
|
||||
*
|
||||
* License (MIT license):
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
TransmissionResult
|
||||
Copyright (C) 2018 Anders Löfgren
|
||||
|
||||
License (MIT license):
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "TransmissionResult.h"
|
||||
|
||||
TransmissionResult::TransmissionResult(int newNetworkIndex, transmission_status_t newTransmissionStatus, bool autofill) :
|
||||
NetworkInfo(newNetworkIndex, autofill), transmissionStatus(newTransmissionStatus)
|
||||
TransmissionResult::TransmissionResult(int newNetworkIndex, transmission_status_t newTransmissionStatus, bool autofill) :
|
||||
NetworkInfo(newNetworkIndex, autofill), transmissionStatus(newTransmissionStatus)
|
||||
{ }
|
||||
|
||||
TransmissionResult::TransmissionResult(const String &newSSID, int newWiFiChannel, uint8_t newBSSID[6], transmission_status_t newTransmissionStatus) :
|
||||
NetworkInfo(newSSID, newWiFiChannel, newBSSID), transmissionStatus(newTransmissionStatus)
|
||||
TransmissionResult::TransmissionResult(const String &newSSID, int newWiFiChannel, uint8_t newBSSID[6], transmission_status_t newTransmissionStatus) :
|
||||
NetworkInfo(newSSID, newWiFiChannel, newBSSID), transmissionStatus(newTransmissionStatus)
|
||||
{ }
|
||||
|
||||
TransmissionResult::TransmissionResult(const String &newSSID, int newWiFiChannel, uint8_t newBSSID[6], int newNetworkIndex, transmission_status_t newTransmissionStatus) :
|
||||
NetworkInfo(newSSID, newWiFiChannel, newBSSID, newNetworkIndex), transmissionStatus(newTransmissionStatus)
|
||||
NetworkInfo(newSSID, newWiFiChannel, newBSSID, newNetworkIndex), transmissionStatus(newTransmissionStatus)
|
||||
{ }
|
||||
|
||||
TransmissionResult::TransmissionResult(const NetworkInfo& origin, transmission_status_t newTransmissionStatus) :
|
||||
NetworkInfo(origin), transmissionStatus(newTransmissionStatus)
|
||||
TransmissionResult::TransmissionResult(const NetworkInfo& origin, transmission_status_t newTransmissionStatus) :
|
||||
NetworkInfo(origin), transmissionStatus(newTransmissionStatus)
|
||||
{ }
|
||||
|
@ -1,27 +1,27 @@
|
||||
/*
|
||||
* TransmissionResult
|
||||
* Copyright (C) 2018 Anders Löfgren
|
||||
*
|
||||
* License (MIT license):
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
TransmissionResult
|
||||
Copyright (C) 2018 Anders Löfgren
|
||||
|
||||
License (MIT license):
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __TRANSMISSIONRESULT_H__
|
||||
#define __TRANSMISSIONRESULT_H__
|
||||
@ -29,29 +29,30 @@
|
||||
#include <ESP8266WiFi.h>
|
||||
#include "NetworkInfo.h"
|
||||
|
||||
typedef enum
|
||||
typedef enum
|
||||
{
|
||||
TS_CONNECTION_FAILED = -1,
|
||||
TS_TRANSMISSION_FAILED = 0,
|
||||
TS_TRANSMISSION_COMPLETE = 1
|
||||
} transmission_status_t;
|
||||
|
||||
class TransmissionResult : public NetworkInfo {
|
||||
class TransmissionResult : public NetworkInfo
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
transmission_status_t transmissionStatus;
|
||||
transmission_status_t transmissionStatus;
|
||||
|
||||
/**
|
||||
* @param autofill Automatically fill in the rest of the network info using newNetworkIndex and the WiFi scan results.
|
||||
*/
|
||||
TransmissionResult(int newNetworkIndex, transmission_status_t newTransmissionStatus, bool autofill = true);
|
||||
/**
|
||||
@param autofill Automatically fill in the rest of the network info using newNetworkIndex and the WiFi scan results.
|
||||
*/
|
||||
TransmissionResult(int newNetworkIndex, transmission_status_t newTransmissionStatus, bool autofill = true);
|
||||
|
||||
TransmissionResult(const String &newSSID, int newWiFiChannel, uint8_t newBSSID[6], transmission_status_t newTransmissionStatus);
|
||||
TransmissionResult(const String &newSSID, int newWiFiChannel, uint8_t newBSSID[6], transmission_status_t newTransmissionStatus);
|
||||
|
||||
TransmissionResult(const String &newSSID, int newWiFiChannel, uint8_t newBSSID[6], int newNetworkIndex, transmission_status_t newTransmissionStatus);
|
||||
TransmissionResult(const String &newSSID, int newWiFiChannel, uint8_t newBSSID[6], int newNetworkIndex, transmission_status_t newTransmissionStatus);
|
||||
|
||||
TransmissionResult(const NetworkInfo& origin, transmission_status_t newTransmissionStatus);
|
||||
TransmissionResult(const NetworkInfo& origin, transmission_status_t newTransmissionStatus);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,58 +1,58 @@
|
||||
/*
|
||||
* TypeConversionFunctions
|
||||
* Copyright (C) 2018 Anders Löfgren
|
||||
*
|
||||
* License (MIT license):
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
TypeConversionFunctions
|
||||
Copyright (C) 2018 Anders Löfgren
|
||||
|
||||
License (MIT license):
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "TypeConversionFunctions.h"
|
||||
|
||||
String uint64ToString(uint64_t number, byte base)
|
||||
{
|
||||
assert(2 <= base && base <= 36);
|
||||
|
||||
String result = "";
|
||||
assert(2 <= base && base <= 36);
|
||||
|
||||
while(number > 0)
|
||||
{
|
||||
result = String((uint32_t)(number % base), base) + result;
|
||||
number /= base;
|
||||
}
|
||||
|
||||
return (result == "" ? "0" : result);
|
||||
String result = "";
|
||||
|
||||
while (number > 0)
|
||||
{
|
||||
result = String((uint32_t)(number % base), base) + result;
|
||||
number /= base;
|
||||
}
|
||||
|
||||
return (result == "" ? "0" : result);
|
||||
}
|
||||
|
||||
uint64_t stringToUint64(const String &string, byte base)
|
||||
{
|
||||
assert(2 <= base && base <= 36);
|
||||
|
||||
uint64_t result = 0;
|
||||
assert(2 <= base && base <= 36);
|
||||
|
||||
char currentCharacter[1];
|
||||
for(uint32_t i = 0; i < string.length(); i++)
|
||||
{
|
||||
result *= base;
|
||||
currentCharacter[0] = string.charAt(i);
|
||||
result += strtoul(currentCharacter, NULL, base);
|
||||
}
|
||||
|
||||
return result;
|
||||
uint64_t result = 0;
|
||||
|
||||
char currentCharacter[1];
|
||||
for (uint32_t i = 0; i < string.length(); i++)
|
||||
{
|
||||
result *= base;
|
||||
currentCharacter[0] = string.charAt(i);
|
||||
result += strtoul(currentCharacter, NULL, base);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -1,27 +1,27 @@
|
||||
/*
|
||||
* TypeConversionFunctions
|
||||
* Copyright (C) 2018 Anders Löfgren
|
||||
*
|
||||
* License (MIT license):
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
TypeConversionFunctions
|
||||
Copyright (C) 2018 Anders Löfgren
|
||||
|
||||
License (MIT license):
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __TYPECONVERSIONFUNCTIONS_H__
|
||||
#define __TYPECONVERSIONFUNCTIONS_H__
|
||||
@ -30,21 +30,21 @@
|
||||
#include <assert.h>
|
||||
|
||||
/**
|
||||
* Note that using a base higher than 16 increases likelihood of randomly generating SSID strings containing controversial words.
|
||||
*
|
||||
* @param number The number to convert to a string with radix "base".
|
||||
* @param base The radix to convert "number" into. Must be between 2 and 36.
|
||||
* @returns A string of "number" encoded in radix "base".
|
||||
*/
|
||||
Note that using a base higher than 16 increases likelihood of randomly generating SSID strings containing controversial words.
|
||||
|
||||
@param number The number to convert to a string with radix "base".
|
||||
@param base The radix to convert "number" into. Must be between 2 and 36.
|
||||
@returns A string of "number" encoded in radix "base".
|
||||
*/
|
||||
String uint64ToString(uint64_t number, byte base = 16);
|
||||
|
||||
/**
|
||||
* Note that using a base higher than 16 increases likelihood of randomly generating SSID strings containing controversial words.
|
||||
*
|
||||
* @param string The string to convert to uint64_t. String must use radix "base".
|
||||
* @param base The radix of "string". Must be between 2 and 36.
|
||||
* @returns A uint64_t of the string, using radix "base" during decoding.
|
||||
*/
|
||||
Note that using a base higher than 16 increases likelihood of randomly generating SSID strings containing controversial words.
|
||||
|
||||
@param string The string to convert to uint64_t. String must use radix "base".
|
||||
@param base The radix of "string". Must be between 2 and 36.
|
||||
@returns A uint64_t of the string, using radix "base" during decoding.
|
||||
*/
|
||||
uint64_t stringToUint64(const String &string, byte base = 16);
|
||||
|
||||
#endif
|
||||
|
@ -1,81 +1,89 @@
|
||||
/*
|
||||
* TransmissionResult
|
||||
* Copyright (C) 2018 Anders Löfgren
|
||||
*
|
||||
* License (MIT license):
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
TransmissionResult
|
||||
Copyright (C) 2018 Anders Löfgren
|
||||
|
||||
License (MIT license):
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "TypeConversionFunctions.h"
|
||||
#include "ESP8266WiFiMesh.h"
|
||||
|
||||
void ESP8266WiFiMesh::verboseModePrint(const String &stringToPrint, bool newline)
|
||||
{
|
||||
if(_verboseMode)
|
||||
{
|
||||
if(newline)
|
||||
Serial.println(stringToPrint);
|
||||
else
|
||||
Serial.print(stringToPrint);
|
||||
}
|
||||
if (_verboseMode)
|
||||
{
|
||||
if (newline)
|
||||
{
|
||||
Serial.println(stringToPrint);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(stringToPrint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the current lwIP version number and store the numbers in the _lwipVersion array.
|
||||
* lwIP version can be changed in the "Tools" menu of Arduino IDE.
|
||||
*/
|
||||
Calculate the current lwIP version number and store the numbers in the _lwipVersion array.
|
||||
lwIP version can be changed in the "Tools" menu of Arduino IDE.
|
||||
*/
|
||||
void ESP8266WiFiMesh::storeLwipVersion()
|
||||
{
|
||||
// ESP.getFullVersion() looks something like:
|
||||
// SDK:2.2.1(cfd48f3)/Core:win-2.5.0-dev/lwIP:2.0.3(STABLE-2_0_3_RELEASE/glue:arduino-2.4.1-10-g0c0d8c2)/BearSSL:94e9704
|
||||
String fullVersion = ESP.getFullVersion();
|
||||
// ESP.getFullVersion() looks something like:
|
||||
// SDK:2.2.1(cfd48f3)/Core:win-2.5.0-dev/lwIP:2.0.3(STABLE-2_0_3_RELEASE/glue:arduino-2.4.1-10-g0c0d8c2)/BearSSL:94e9704
|
||||
String fullVersion = ESP.getFullVersion();
|
||||
|
||||
int i = fullVersion.indexOf("lwIP:") + 5;
|
||||
char currentChar = fullVersion.charAt(i);
|
||||
int i = fullVersion.indexOf("lwIP:") + 5;
|
||||
char currentChar = fullVersion.charAt(i);
|
||||
|
||||
for(int versionPart = 0; versionPart < 3; versionPart++)
|
||||
{
|
||||
while(!isdigit(currentChar))
|
||||
for (int versionPart = 0; versionPart < 3; versionPart++)
|
||||
{
|
||||
currentChar = fullVersion.charAt(++i);
|
||||
while (!isdigit(currentChar))
|
||||
{
|
||||
currentChar = fullVersion.charAt(++i);
|
||||
}
|
||||
while (isdigit(currentChar))
|
||||
{
|
||||
_lwipVersion[versionPart] = 10 * _lwipVersion[versionPart] + (currentChar - '0'); // Left shift and add digit value, in base 10.
|
||||
currentChar = fullVersion.charAt(++i);
|
||||
}
|
||||
}
|
||||
while(isdigit(currentChar))
|
||||
{
|
||||
_lwipVersion[versionPart] = 10 * _lwipVersion[versionPart] + (currentChar - '0'); // Left shift and add digit value, in base 10.
|
||||
currentChar = fullVersion.charAt(++i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the code is running on a version of lwIP that is at least minLwipVersion.
|
||||
*/
|
||||
Check if the code is running on a version of lwIP that is at least minLwipVersion.
|
||||
*/
|
||||
bool ESP8266WiFiMesh::atLeastLwipVersion(const uint32_t minLwipVersion[3])
|
||||
{
|
||||
for(int versionPart = 0; versionPart < 3; versionPart++)
|
||||
{
|
||||
if(_lwipVersion[versionPart] > minLwipVersion[versionPart])
|
||||
return true;
|
||||
else if(_lwipVersion[versionPart] < minLwipVersion[versionPart])
|
||||
return false;
|
||||
}
|
||||
{
|
||||
for (int versionPart = 0; versionPart < 3; versionPart++)
|
||||
{
|
||||
if (_lwipVersion[versionPart] > minLwipVersion[versionPart])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (_lwipVersion[versionPart] < minLwipVersion[versionPart])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
@ -1,27 +1,27 @@
|
||||
/**
|
||||
*
|
||||
* @file ESP8266HTTPUpdate.cpp
|
||||
* @date 21.06.2015
|
||||
* @author Markus Sattler
|
||||
*
|
||||
* Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||
* This file is part of the ESP8266 Http Updater.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
@file ESP8266HTTPUpdate.cpp
|
||||
@date 21.06.2015
|
||||
@author Markus Sattler
|
||||
|
||||
Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||
This file is part of the ESP8266 Http Updater.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "ESP8266httpUpdate.h"
|
||||
#include <StreamString.h>
|
||||
@ -30,12 +30,12 @@ extern "C" uint32_t _SPIFFS_start;
|
||||
extern "C" uint32_t _SPIFFS_end;
|
||||
|
||||
ESP8266HTTPUpdate::ESP8266HTTPUpdate(void)
|
||||
: _httpClientTimeout(8000), _followRedirects(false), _ledPin(-1)
|
||||
: _httpClientTimeout(8000), _followRedirects(false), _ledPin(-1)
|
||||
{
|
||||
}
|
||||
|
||||
ESP8266HTTPUpdate::ESP8266HTTPUpdate(int httpClientTimeout)
|
||||
: _httpClientTimeout(httpClientTimeout), _followRedirects(false), _ledPin(-1)
|
||||
: _httpClientTimeout(httpClientTimeout), _followRedirects(false), _ledPin(-1)
|
||||
{
|
||||
}
|
||||
|
||||
@ -139,11 +139,14 @@ HTTPUpdateResult ESP8266HTTPUpdate::update(const String& host, uint16_t port, co
|
||||
{
|
||||
(void)https;
|
||||
rebootOnUpdate(reboot);
|
||||
if (httpsFingerprint.length() == 0) {
|
||||
if (httpsFingerprint.length() == 0)
|
||||
{
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
return update(host, port, uri, currentVersion);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return update(host, port, uri, currentVersion, httpsFingerprint);
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
@ -192,27 +195,29 @@ HTTPUpdateResult ESP8266HTTPUpdate::update(WiFiClient& client, const String& hos
|
||||
}
|
||||
|
||||
/**
|
||||
* return error code as int
|
||||
* @return int error code
|
||||
*/
|
||||
return error code as int
|
||||
@return int error code
|
||||
*/
|
||||
int ESP8266HTTPUpdate::getLastError(void)
|
||||
{
|
||||
return _lastError;
|
||||
}
|
||||
|
||||
/**
|
||||
* return error code as String
|
||||
* @return String error
|
||||
*/
|
||||
return error code as String
|
||||
@return String error
|
||||
*/
|
||||
String ESP8266HTTPUpdate::getLastErrorString(void)
|
||||
{
|
||||
|
||||
if(_lastError == 0) {
|
||||
if (_lastError == 0)
|
||||
{
|
||||
return String(); // no error
|
||||
}
|
||||
|
||||
// error from Update class
|
||||
if(_lastError > 0) {
|
||||
if (_lastError > 0)
|
||||
{
|
||||
StreamString error;
|
||||
Update.printError(error);
|
||||
error.trim(); // remove line ending
|
||||
@ -220,11 +225,13 @@ String ESP8266HTTPUpdate::getLastErrorString(void)
|
||||
}
|
||||
|
||||
// error from http client
|
||||
if(_lastError > -100) {
|
||||
if (_lastError > -100)
|
||||
{
|
||||
return String(F("HTTP error: ")) + HTTPClient::errorToString(_lastError);
|
||||
}
|
||||
|
||||
switch(_lastError) {
|
||||
switch (_lastError)
|
||||
{
|
||||
case HTTP_UE_TOO_LESS_SPACE:
|
||||
return F("Not Enough space");
|
||||
case HTTP_UE_SERVER_NOT_REPORT_SIZE:
|
||||
@ -248,11 +255,11 @@ String ESP8266HTTPUpdate::getLastErrorString(void)
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param http HTTPClient *
|
||||
* @param currentVersion const char *
|
||||
* @return HTTPUpdateResult
|
||||
*/
|
||||
|
||||
@param http HTTPClient
|
||||
@param currentVersion const char
|
||||
@return HTTPUpdateResult
|
||||
*/
|
||||
HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String& currentVersion, bool spiffs)
|
||||
{
|
||||
|
||||
@ -271,13 +278,17 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String&
|
||||
http.addHeader(F("x-ESP8266-chip-size"), String(ESP.getFlashChipRealSize()));
|
||||
http.addHeader(F("x-ESP8266-sdk-version"), ESP.getSdkVersion());
|
||||
|
||||
if(spiffs) {
|
||||
if (spiffs)
|
||||
{
|
||||
http.addHeader(F("x-ESP8266-mode"), F("spiffs"));
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
http.addHeader(F("x-ESP8266-mode"), F("sketch"));
|
||||
}
|
||||
|
||||
if(currentVersion && currentVersion[0] != 0x00) {
|
||||
if (currentVersion && currentVersion[0] != 0x00)
|
||||
{
|
||||
http.addHeader(F("x-ESP8266-version"), currentVersion);
|
||||
}
|
||||
|
||||
@ -291,7 +302,8 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String&
|
||||
int code = http.GET();
|
||||
int len = http.getSize();
|
||||
|
||||
if(code <= 0) {
|
||||
if (code <= 0)
|
||||
{
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] HTTP error: %s\n", http.errorToString(code).c_str());
|
||||
_lastError = code;
|
||||
http.end();
|
||||
@ -304,7 +316,8 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String&
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] - code: %d\n", code);
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] - len: %d\n", len);
|
||||
|
||||
if(http.hasHeader("x-MD5")) {
|
||||
if (http.hasHeader("x-MD5"))
|
||||
{
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] - MD5: %s\n", http.header("x-MD5").c_str());
|
||||
}
|
||||
|
||||
@ -312,31 +325,42 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String&
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] - free Space: %d\n", ESP.getFreeSketchSpace());
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] - current Sketch Size: %d\n", ESP.getSketchSize());
|
||||
|
||||
if(currentVersion && currentVersion[0] != 0x00) {
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] - current version: %s\n", currentVersion.c_str() );
|
||||
if (currentVersion && currentVersion[0] != 0x00)
|
||||
{
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] - current version: %s\n", currentVersion.c_str());
|
||||
}
|
||||
|
||||
switch(code) {
|
||||
switch (code)
|
||||
{
|
||||
case HTTP_CODE_OK: ///< OK (Start Update)
|
||||
if(len > 0) {
|
||||
if (len > 0)
|
||||
{
|
||||
bool startUpdate = true;
|
||||
if(spiffs) {
|
||||
if (spiffs)
|
||||
{
|
||||
size_t spiffsSize = ((size_t) &_SPIFFS_end - (size_t) &_SPIFFS_start);
|
||||
if(len > (int) spiffsSize) {
|
||||
if (len > (int) spiffsSize)
|
||||
{
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] spiffsSize to low (%d) needed: %d\n", spiffsSize, len);
|
||||
startUpdate = false;
|
||||
}
|
||||
} else {
|
||||
if(len > (int) ESP.getFreeSketchSpace()) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (len > (int) ESP.getFreeSketchSpace())
|
||||
{
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] FreeSketchSpace to low (%d) needed: %d\n", ESP.getFreeSketchSpace(), len);
|
||||
startUpdate = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!startUpdate) {
|
||||
if (!startUpdate)
|
||||
{
|
||||
_lastError = HTTP_UE_TOO_LESS_SPACE;
|
||||
ret = HTTP_UPDATE_FAILED;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
WiFiClient * tcp = http.getStreamPtr();
|
||||
|
||||
@ -347,17 +371,22 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String&
|
||||
|
||||
int command;
|
||||
|
||||
if(spiffs) {
|
||||
if (spiffs)
|
||||
{
|
||||
command = U_SPIFFS;
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] runUpdate spiffs...\n");
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
command = U_FLASH;
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] runUpdate flash...\n");
|
||||
}
|
||||
|
||||
if(!spiffs) {
|
||||
if (!spiffs)
|
||||
{
|
||||
uint8_t buf[4];
|
||||
if(tcp->peekBytes(&buf[0], 4) != 4) {
|
||||
if (tcp->peekBytes(&buf[0], 4) != 4)
|
||||
{
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] peekBytes magic header failed\n");
|
||||
_lastError = HTTP_UE_BIN_VERIFY_HEADER_FAILED;
|
||||
http.end();
|
||||
@ -365,7 +394,8 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String&
|
||||
}
|
||||
|
||||
// check for valid first magic byte
|
||||
if(buf[0] != 0xE9) {
|
||||
if (buf[0] != 0xE9)
|
||||
{
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] Magic header does not start with 0xE9\n");
|
||||
_lastError = HTTP_UE_BIN_VERIFY_HEADER_FAILED;
|
||||
http.end();
|
||||
@ -376,28 +406,35 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String&
|
||||
uint32_t bin_flash_size = ESP.magicFlashChipSize((buf[3] & 0xf0) >> 4);
|
||||
|
||||
// check if new bin fits to SPI flash
|
||||
if(bin_flash_size > ESP.getFlashChipRealSize()) {
|
||||
if (bin_flash_size > ESP.getFlashChipRealSize())
|
||||
{
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] New binary does not fit SPI Flash size\n");
|
||||
_lastError = HTTP_UE_BIN_FOR_WRONG_FLASH;
|
||||
http.end();
|
||||
return HTTP_UPDATE_FAILED;
|
||||
}
|
||||
}
|
||||
if(runUpdate(*tcp, len, http.header("x-MD5"), command)) {
|
||||
if (runUpdate(*tcp, len, http.header("x-MD5"), command))
|
||||
{
|
||||
ret = HTTP_UPDATE_OK;
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] Update ok\n");
|
||||
http.end();
|
||||
|
||||
if(_rebootOnUpdate && !spiffs) {
|
||||
if (_rebootOnUpdate && !spiffs)
|
||||
{
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = HTTP_UPDATE_FAILED;
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] Update failed\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
_lastError = HTTP_UE_SERVER_NOT_REPORT_SIZE;
|
||||
ret = HTTP_UPDATE_FAILED;
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] Content-Length was 0 or wasn't set by Server?!\n");
|
||||
@ -428,18 +465,19 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String&
|
||||
}
|
||||
|
||||
/**
|
||||
* write Update to flash
|
||||
* @param in Stream&
|
||||
* @param size uint32_t
|
||||
* @param md5 String
|
||||
* @return true if Update ok
|
||||
*/
|
||||
write Update to flash
|
||||
@param in Stream&
|
||||
@param size uint32_t
|
||||
@param md5 String
|
||||
@return true if Update ok
|
||||
*/
|
||||
bool ESP8266HTTPUpdate::runUpdate(Stream& in, uint32_t size, String md5, int command)
|
||||
{
|
||||
|
||||
StreamString error;
|
||||
|
||||
if(!Update.begin(size, command, _ledPin, _ledOn)) {
|
||||
if (!Update.begin(size, command, _ledPin, _ledOn))
|
||||
{
|
||||
_lastError = Update.getError();
|
||||
Update.printError(error);
|
||||
error.trim(); // remove line ending
|
||||
@ -447,15 +485,18 @@ bool ESP8266HTTPUpdate::runUpdate(Stream& in, uint32_t size, String md5, int com
|
||||
return false;
|
||||
}
|
||||
|
||||
if(md5.length()) {
|
||||
if(!Update.setMD5(md5.c_str())) {
|
||||
if (md5.length())
|
||||
{
|
||||
if (!Update.setMD5(md5.c_str()))
|
||||
{
|
||||
_lastError = HTTP_UE_SERVER_FAULTY_MD5;
|
||||
DEBUG_HTTP_UPDATE("[httpUpdate] Update.setMD5 failed! (%s)\n", md5.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(Update.writeStream(in) != size) {
|
||||
if (Update.writeStream(in) != size)
|
||||
{
|
||||
_lastError = Update.getError();
|
||||
Update.printError(error);
|
||||
error.trim(); // remove line ending
|
||||
@ -463,7 +504,8 @@ bool ESP8266HTTPUpdate::runUpdate(Stream& in, uint32_t size, String md5, int com
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!Update.end()) {
|
||||
if (!Update.end())
|
||||
{
|
||||
_lastError = Update.getError();
|
||||
Update.printError(error);
|
||||
error.trim(); // remove line ending
|
||||
|
@ -1,27 +1,27 @@
|
||||
/**
|
||||
*
|
||||
* @file ESP8266HTTPUpdate.h
|
||||
* @date 21.06.2015
|
||||
* @author Markus Sattler
|
||||
*
|
||||
* Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||
* This file is part of the ESP8266 Http Updater.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
@file ESP8266HTTPUpdate.h
|
||||
@date 21.06.2015
|
||||
@author Markus Sattler
|
||||
|
||||
Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||
This file is part of the ESP8266 Http Updater.
|
||||
|
||||
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 ESP8266HTTPUPDATE_H_
|
||||
#define ESP8266HTTPUPDATE_H_
|
||||
@ -54,7 +54,8 @@
|
||||
#define HTTP_UE_BIN_VERIFY_HEADER_FAILED (-106)
|
||||
#define HTTP_UE_BIN_FOR_WRONG_FLASH (-107)
|
||||
|
||||
enum HTTPUpdateResult {
|
||||
enum HTTPUpdateResult
|
||||
{
|
||||
HTTP_UPDATE_FAILED,
|
||||
HTTP_UPDATE_NO_UPDATES,
|
||||
HTTP_UPDATE_OK
|
||||
|
@ -1,10 +1,10 @@
|
||||
#include <ESP8266mDNS.h>
|
||||
|
||||
/*
|
||||
* MDNS responder global instance
|
||||
*
|
||||
* Class type that is instantiated depends on the type mapping in ESP8266mDNS.h
|
||||
*/
|
||||
MDNS responder global instance
|
||||
|
||||
Class type that is instantiated depends on the type mapping in ESP8266mDNS.h
|
||||
*/
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS)
|
||||
MDNSResponder MDNS;
|
||||
#endif
|
||||
|
@ -1,44 +1,44 @@
|
||||
/*
|
||||
ESP8266mDNS.h - mDNSResponder for ESP8266 family
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
ESP8266mDNS.h - mDNSResponder for ESP8266 family
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
Legacy_ESP8266mDNS:
|
||||
The well known, thouroughly tested (yet no flawless) default mDNS library for the ESP8266 family
|
||||
Legacy_ESP8266mDNS:
|
||||
The well known, thouroughly tested (yet no flawless) default mDNS library for the ESP8266 family
|
||||
|
||||
LEA_ESP8266mDNS:
|
||||
An (currently) experimental mDNS implementation, that supports a lot more of mDNS features than Legacy_ESP8266mDNS, like:
|
||||
- Presenting a DNS-SD service to interested observers, eg. a http server by presenting _http._tcp service
|
||||
- Support for multi-level compressed names in input; in output only a very simple one-leven full-name compression is implemented
|
||||
- Probing host and service domains for uniqueness in the local network
|
||||
- Tiebreaking while probing is supportet in a very minimalistic way (the 'higher' IP address wins the tiebreak)
|
||||
- Announcing available services after successful probing
|
||||
- Using fixed service TXT items or
|
||||
- Using dynamic service TXT items for presented services (via callback)
|
||||
- Remove services (and un-announcing them to the observers by sending goodbye-messages)
|
||||
- Static queries for DNS-SD services (creating a fixed answer set after a certain timeout period)
|
||||
- Dynamic queries for DNS-SD services with cached and updated answers and user notifications
|
||||
- Support for multi-homed client host domains
|
||||
LEA_ESP8266mDNS:
|
||||
An (currently) experimental mDNS implementation, that supports a lot more of mDNS features than Legacy_ESP8266mDNS, like:
|
||||
- Presenting a DNS-SD service to interested observers, eg. a http server by presenting _http._tcp service
|
||||
- Support for multi-level compressed names in input; in output only a very simple one-leven full-name compression is implemented
|
||||
- Probing host and service domains for uniqueness in the local network
|
||||
- Tiebreaking while probing is supportet in a very minimalistic way (the 'higher' IP address wins the tiebreak)
|
||||
- Announcing available services after successful probing
|
||||
- Using fixed service TXT items or
|
||||
- Using dynamic service TXT items for presented services (via callback)
|
||||
- Remove services (and un-announcing them to the observers by sending goodbye-messages)
|
||||
- Static queries for DNS-SD services (creating a fixed answer set after a certain timeout period)
|
||||
- Dynamic queries for DNS-SD services with cached and updated answers and user notifications
|
||||
- Support for multi-homed client host domains
|
||||
|
||||
See 'LEA_ESP8266mDNS/EPS8266mDNS.h' for more implementation details and usage informations.
|
||||
See 'examples/mDNS_Clock' and 'examples/mDNS_ServiceMonitor' for implementation examples of the advanced features.
|
||||
See 'LEA_ESP8266mDNS/EPS8266mDNS.h' for more implementation details and usage informations.
|
||||
See 'examples/mDNS_Clock' and 'examples/mDNS_ServiceMonitor' for implementation examples of the advanced features.
|
||||
|
||||
LEA_ESP8266mDNS is (mostly) client source code compatible to 'Legacy_ESP8266mDNS', so it could be
|
||||
use as a 'drop-in' replacement in existing projects.
|
||||
LEA_ESP8266mDNS is (mostly) client source code compatible to 'Legacy_ESP8266mDNS', so it could be
|
||||
use as a 'drop-in' replacement in existing projects.
|
||||
|
||||
|
||||
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 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.
|
||||
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
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
@ -47,10 +47,10 @@
|
||||
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS)
|
||||
// Maps the implementation to use to the global namespace type
|
||||
//using MDNSResponder = Legacy_MDNSResponder::MDNSResponder; //legacy
|
||||
using MDNSResponder = esp8266::MDNSImplementation::MDNSResponder; //new
|
||||
|
||||
extern MDNSResponder MDNS;
|
||||
// Maps the implementation to use to the global namespace type
|
||||
//using MDNSResponder = Legacy_MDNSResponder::MDNSResponder; //legacy
|
||||
using MDNSResponder = esp8266::MDNSImplementation::MDNSResponder; //new
|
||||
|
||||
extern MDNSResponder MDNS;
|
||||
#endif
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,43 +1,43 @@
|
||||
/*
|
||||
ESP8266 Multicast DNS (port of CC3000 Multicast DNS library)
|
||||
Version 1.1
|
||||
Copyright (c) 2013 Tony DiCola (tony@tonydicola.com)
|
||||
ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com)
|
||||
Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com)
|
||||
ESP8266 Multicast DNS (port of CC3000 Multicast DNS library)
|
||||
Version 1.1
|
||||
Copyright (c) 2013 Tony DiCola (tony@tonydicola.com)
|
||||
ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com)
|
||||
Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com)
|
||||
|
||||
This is a simple implementation of multicast DNS query support for an Arduino
|
||||
running on ESP8266 chip. Only support for resolving address queries is currently
|
||||
implemented.
|
||||
This is a simple implementation of multicast DNS query support for an Arduino
|
||||
running on ESP8266 chip. Only support for resolving address queries is currently
|
||||
implemented.
|
||||
|
||||
Requirements:
|
||||
- ESP8266WiFi library
|
||||
Requirements:
|
||||
- ESP8266WiFi library
|
||||
|
||||
Usage:
|
||||
- Include the ESP8266 Multicast DNS library in the sketch.
|
||||
- Call the begin method in the sketch's setup and provide a domain name (without
|
||||
the '.local' suffix, i.e. just provide 'foo' to resolve 'foo.local'), and the
|
||||
Adafruit CC3000 class instance. Optionally provide a time to live (in seconds)
|
||||
for the DNS record--the default is 1 hour.
|
||||
- Call the update method in each iteration of the sketch's loop function.
|
||||
Usage:
|
||||
- Include the ESP8266 Multicast DNS library in the sketch.
|
||||
- Call the begin method in the sketch's setup and provide a domain name (without
|
||||
the '.local' suffix, i.e. just provide 'foo' to resolve 'foo.local'), and the
|
||||
Adafruit CC3000 class instance. Optionally provide a time to live (in seconds)
|
||||
for the DNS record--the default is 1 hour.
|
||||
- Call the update method in each iteration of the sketch's loop function.
|
||||
|
||||
License (MIT license):
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
License (MIT license):
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
#ifndef ESP8266MDNS_LEGACY_H
|
||||
@ -54,95 +54,108 @@ License (MIT license):
|
||||
class UdpContext;
|
||||
|
||||
|
||||
namespace Legacy_MDNSResponder {
|
||||
namespace Legacy_MDNSResponder
|
||||
{
|
||||
|
||||
|
||||
struct MDNSService;
|
||||
struct MDNSTxt;
|
||||
struct MDNSAnswer;
|
||||
|
||||
class MDNSResponder {
|
||||
class MDNSResponder
|
||||
{
|
||||
public:
|
||||
MDNSResponder();
|
||||
~MDNSResponder();
|
||||
bool begin(const char* hostName);
|
||||
bool begin(const String& hostName) {
|
||||
return begin(hostName.c_str());
|
||||
}
|
||||
//for compatibility
|
||||
bool begin(const char* hostName, IPAddress ip, uint32_t ttl=120){
|
||||
(void) ip;
|
||||
(void) ttl;
|
||||
return begin(hostName);
|
||||
}
|
||||
bool begin(const String& hostName, IPAddress ip, uint32_t ttl=120) {
|
||||
return begin(hostName.c_str(), ip, ttl);
|
||||
}
|
||||
/* Application should call this whenever AP is configured/disabled */
|
||||
void notifyAPChange();
|
||||
void update();
|
||||
MDNSResponder();
|
||||
~MDNSResponder();
|
||||
bool begin(const char* hostName);
|
||||
bool begin(const String& hostName)
|
||||
{
|
||||
return begin(hostName.c_str());
|
||||
}
|
||||
//for compatibility
|
||||
bool begin(const char* hostName, IPAddress ip, uint32_t ttl = 120)
|
||||
{
|
||||
(void) ip;
|
||||
(void) ttl;
|
||||
return begin(hostName);
|
||||
}
|
||||
bool begin(const String& hostName, IPAddress ip, uint32_t ttl = 120)
|
||||
{
|
||||
return begin(hostName.c_str(), ip, ttl);
|
||||
}
|
||||
/* Application should call this whenever AP is configured/disabled */
|
||||
void notifyAPChange();
|
||||
void update();
|
||||
|
||||
void addService(char *service, char *proto, uint16_t port);
|
||||
void addService(const char *service, const char *proto, uint16_t port){
|
||||
addService((char *)service, (char *)proto, port);
|
||||
}
|
||||
void addService(const String& service, const String& proto, uint16_t port){
|
||||
addService(service.c_str(), proto.c_str(), port);
|
||||
}
|
||||
|
||||
bool addServiceTxt(char *name, char *proto, char * key, char * value);
|
||||
bool addServiceTxt(const char *name, const char *proto, const char *key,const char * value){
|
||||
return addServiceTxt((char *)name, (char *)proto, (char *)key, (char *)value);
|
||||
}
|
||||
bool addServiceTxt(const String& name, const String& proto, const String& key, const String& value){
|
||||
return addServiceTxt(name.c_str(), proto.c_str(), key.c_str(), value.c_str());
|
||||
}
|
||||
|
||||
int queryService(char *service, char *proto);
|
||||
int queryService(const char *service, const char *proto){
|
||||
return queryService((char *)service, (char *)proto);
|
||||
}
|
||||
int queryService(const String& service, const String& proto){
|
||||
return queryService(service.c_str(), proto.c_str());
|
||||
}
|
||||
String hostname(int idx);
|
||||
IPAddress IP(int idx);
|
||||
uint16_t port(int idx);
|
||||
|
||||
void enableArduino(uint16_t port, bool auth=false);
|
||||
void addService(char *service, char *proto, uint16_t port);
|
||||
void addService(const char *service, const char *proto, uint16_t port)
|
||||
{
|
||||
addService((char *)service, (char *)proto, port);
|
||||
}
|
||||
void addService(const String& service, const String& proto, uint16_t port)
|
||||
{
|
||||
addService(service.c_str(), proto.c_str(), port);
|
||||
}
|
||||
|
||||
void setInstanceName(String name);
|
||||
void setInstanceName(const char * name){
|
||||
setInstanceName(String(name));
|
||||
}
|
||||
void setInstanceName(char * name){
|
||||
setInstanceName(String(name));
|
||||
}
|
||||
bool addServiceTxt(char *name, char *proto, char * key, char * value);
|
||||
bool addServiceTxt(const char *name, const char *proto, const char *key, const char * value)
|
||||
{
|
||||
return addServiceTxt((char *)name, (char *)proto, (char *)key, (char *)value);
|
||||
}
|
||||
bool addServiceTxt(const String& name, const String& proto, const String& key, const String& value)
|
||||
{
|
||||
return addServiceTxt(name.c_str(), proto.c_str(), key.c_str(), value.c_str());
|
||||
}
|
||||
|
||||
int queryService(char *service, char *proto);
|
||||
int queryService(const char *service, const char *proto)
|
||||
{
|
||||
return queryService((char *)service, (char *)proto);
|
||||
}
|
||||
int queryService(const String& service, const String& proto)
|
||||
{
|
||||
return queryService(service.c_str(), proto.c_str());
|
||||
}
|
||||
String hostname(int idx);
|
||||
IPAddress IP(int idx);
|
||||
uint16_t port(int idx);
|
||||
|
||||
void enableArduino(uint16_t port, bool auth = false);
|
||||
|
||||
void setInstanceName(String name);
|
||||
void setInstanceName(const char * name)
|
||||
{
|
||||
setInstanceName(String(name));
|
||||
}
|
||||
void setInstanceName(char * name)
|
||||
{
|
||||
setInstanceName(String(name));
|
||||
}
|
||||
|
||||
private:
|
||||
struct MDNSService * _services;
|
||||
UdpContext* _conn;
|
||||
String _hostName;
|
||||
String _instanceName;
|
||||
struct MDNSAnswer * _answers;
|
||||
struct MDNSQuery * _query;
|
||||
bool _newQuery;
|
||||
bool _waitingForAnswers;
|
||||
WiFiEventHandler _disconnectedHandler;
|
||||
WiFiEventHandler _gotIPHandler;
|
||||
|
||||
struct MDNSService * _services;
|
||||
UdpContext* _conn;
|
||||
String _hostName;
|
||||
String _instanceName;
|
||||
struct MDNSAnswer * _answers;
|
||||
struct MDNSQuery * _query;
|
||||
bool _newQuery;
|
||||
bool _waitingForAnswers;
|
||||
WiFiEventHandler _disconnectedHandler;
|
||||
WiFiEventHandler _gotIPHandler;
|
||||
|
||||
uint16_t _getServicePort(char *service, char *proto);
|
||||
MDNSTxt * _getServiceTxt(char *name, char *proto);
|
||||
uint16_t _getServiceTxtLen(char *name, char *proto);
|
||||
IPAddress _getRequestMulticastInterface();
|
||||
void _parsePacket();
|
||||
void _replyToTypeEnumRequest(IPAddress multicastInterface);
|
||||
void _replyToInstanceRequest(uint8_t questionMask, uint8_t responseMask, char * service, char *proto, uint16_t port, IPAddress multicastInterface);
|
||||
MDNSAnswer* _getAnswerFromIdx(int idx);
|
||||
int _getNumAnswers();
|
||||
bool _listen();
|
||||
void _restart();
|
||||
|
||||
uint16_t _getServicePort(char *service, char *proto);
|
||||
MDNSTxt * _getServiceTxt(char *name, char *proto);
|
||||
uint16_t _getServiceTxtLen(char *name, char *proto);
|
||||
IPAddress _getRequestMulticastInterface();
|
||||
void _parsePacket();
|
||||
void _replyToTypeEnumRequest(IPAddress multicastInterface);
|
||||
void _replyToInstanceRequest(uint8_t questionMask, uint8_t responseMask, char * service, char *proto, uint16_t port, IPAddress multicastInterface);
|
||||
MDNSAnswer* _getAnswerFromIdx(int idx);
|
||||
int _getNumAnswers();
|
||||
bool _listen();
|
||||
void _restart();
|
||||
};
|
||||
|
||||
} // namespace Legacy_MDNSResponder
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,177 +1,179 @@
|
||||
/*
|
||||
* LEAmDNS_Priv.h
|
||||
*
|
||||
* License (MIT license):
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MDNS_PRIV_H
|
||||
#define MDNS_PRIV_H
|
||||
|
||||
namespace esp8266 {
|
||||
|
||||
/*
|
||||
* LEAmDNS
|
||||
*/
|
||||
|
||||
namespace MDNSImplementation {
|
||||
|
||||
// Enable class debug functions
|
||||
#define ESP_8266_MDNS_INCLUDE
|
||||
//#define DEBUG_ESP_MDNS_RESPONDER
|
||||
|
||||
|
||||
#ifndef LWIP_OPEN_SRC
|
||||
#define LWIP_OPEN_SRC
|
||||
#endif
|
||||
|
||||
//
|
||||
// If ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE is defined, the mDNS responder ignores a successful probing
|
||||
// This allows to drive the responder in a environment, where 'update()' isn't called in the loop
|
||||
//#define ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE
|
||||
|
||||
// Enable/disable debug trace macros
|
||||
#ifdef DEBUG_ESP_MDNS_RESPONDER
|
||||
#define DEBUG_ESP_MDNS_INFO
|
||||
#define DEBUG_ESP_MDNS_ERR
|
||||
#define DEBUG_ESP_MDNS_TX
|
||||
#define DEBUG_ESP_MDNS_RX
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_ESP_MDNS_RESPONDER
|
||||
#ifdef DEBUG_ESP_MDNS_INFO
|
||||
#define DEBUG_EX_INFO(A) A
|
||||
#else
|
||||
#define DEBUG_EX_INFO(A)
|
||||
#endif
|
||||
#ifdef DEBUG_ESP_MDNS_ERR
|
||||
#define DEBUG_EX_ERR(A) A
|
||||
#else
|
||||
#define DEBUG_EX_ERR(A)
|
||||
#endif
|
||||
#ifdef DEBUG_ESP_MDNS_TX
|
||||
#define DEBUG_EX_TX(A) A
|
||||
#else
|
||||
#define DEBUG_EX_TX(A)
|
||||
#endif
|
||||
#ifdef DEBUG_ESP_MDNS_RX
|
||||
#define DEBUG_EX_RX(A) A
|
||||
#else
|
||||
#define DEBUG_EX_RX(A)
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_ESP_PORT
|
||||
#define DEBUG_OUTPUT DEBUG_ESP_PORT
|
||||
#else
|
||||
#define DEBUG_OUTPUT Serial
|
||||
#endif
|
||||
#else
|
||||
#define DEBUG_EX_INFO(A)
|
||||
#define DEBUG_EX_ERR(A)
|
||||
#define DEBUG_EX_TX(A)
|
||||
#define DEBUG_EX_RX(A)
|
||||
#endif
|
||||
|
||||
|
||||
/* Replaced by 'lwip/prot/dns.h' definitions
|
||||
#ifdef MDNS_IP4_SUPPORT
|
||||
#define MDNS_MULTICAST_ADDR_IP4 (IPAddress(224, 0, 0, 251)) // ip_addr_t v4group = DNS_MQUERY_IPV4_GROUP_INIT
|
||||
#endif
|
||||
#ifdef MDNS_IP6_SUPPORT
|
||||
#define MDNS_MULTICAST_ADDR_IP6 (IPAddress("FF02::FB")) // ip_addr_t v6group = DNS_MQUERY_IPV6_GROUP_INIT
|
||||
#endif*/
|
||||
//#define MDNS_MULTICAST_PORT 5353
|
||||
|
||||
/*
|
||||
* This is NOT the TTL (Time-To-Live) for MDNS records, but the
|
||||
* subnet level distance MDNS records should travel.
|
||||
* 1 sets the subnet distance to 'local', which is default for MDNS.
|
||||
* (Btw.: 255 would set it to 'as far as possible' -> internet)
|
||||
*
|
||||
* However, RFC 3171 seems to force 255 instead
|
||||
*/
|
||||
#define MDNS_MULTICAST_TTL 255/*1*/
|
||||
|
||||
/*
|
||||
* This is the MDNS record TTL
|
||||
* Host level records are set to 2min (120s)
|
||||
* service level records are set to 75min (4500s)
|
||||
*/
|
||||
#define MDNS_HOST_TTL 120
|
||||
#define MDNS_SERVICE_TTL 4500
|
||||
|
||||
/*
|
||||
* Compressed labels are flaged by the two topmost bits of the length byte being set
|
||||
*/
|
||||
#define MDNS_DOMAIN_COMPRESS_MARK 0xC0
|
||||
/*
|
||||
* Avoid endless recursion because of malformed compressed labels
|
||||
*/
|
||||
#define MDNS_DOMAIN_MAX_REDIRCTION 6
|
||||
|
||||
/*
|
||||
* Default service priority and weight in SRV answers
|
||||
*/
|
||||
#define MDNS_SRV_PRIORITY 0
|
||||
#define MDNS_SRV_WEIGHT 0
|
||||
|
||||
/*
|
||||
* Delay between and number of probes for host and service domains
|
||||
* Delay between and number of announces for host and service domains
|
||||
* Delay between and number of service queries; the delay is multiplied by the resent number in '_checkServiceQueryCache'
|
||||
*/
|
||||
#define MDNS_PROBE_DELAY 250
|
||||
#define MDNS_PROBE_COUNT 3
|
||||
#define MDNS_ANNOUNCE_DELAY 1000
|
||||
#define MDNS_ANNOUNCE_COUNT 8
|
||||
#define MDNS_DYNAMIC_QUERY_RESEND_COUNT 5
|
||||
#define MDNS_DYNAMIC_QUERY_RESEND_DELAY 5000
|
||||
|
||||
|
||||
/*
|
||||
* Force host domain to use only lowercase letters
|
||||
*/
|
||||
//#define MDNS_FORCE_LOWERCASE_HOSTNAME
|
||||
|
||||
/*
|
||||
* Enable/disable the usage of the F() macro in debug trace printf calls.
|
||||
* There needs to be an PGM comptible printf function to use this.
|
||||
*
|
||||
* USE_PGM_PRINTF and F
|
||||
*/
|
||||
#define USE_PGM_PRINTF
|
||||
|
||||
#ifdef USE_PGM_PRINTF
|
||||
#else
|
||||
#ifdef F
|
||||
#undef F
|
||||
#endif
|
||||
#define F(A) A
|
||||
#endif
|
||||
|
||||
} // namespace MDNSImplementation
|
||||
|
||||
} // namespace esp8266
|
||||
|
||||
// Include the main header, so the submodlues only need to include this header
|
||||
#include "LEAmDNS.h"
|
||||
|
||||
|
||||
#endif // MDNS_PRIV_H
|
||||
/*
|
||||
LEAmDNS_Priv.h
|
||||
|
||||
License (MIT license):
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef MDNS_PRIV_H
|
||||
#define MDNS_PRIV_H
|
||||
|
||||
namespace esp8266
|
||||
{
|
||||
|
||||
/*
|
||||
LEAmDNS
|
||||
*/
|
||||
|
||||
namespace MDNSImplementation
|
||||
{
|
||||
|
||||
// Enable class debug functions
|
||||
#define ESP_8266_MDNS_INCLUDE
|
||||
//#define DEBUG_ESP_MDNS_RESPONDER
|
||||
|
||||
|
||||
#ifndef LWIP_OPEN_SRC
|
||||
#define LWIP_OPEN_SRC
|
||||
#endif
|
||||
|
||||
//
|
||||
// If ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE is defined, the mDNS responder ignores a successful probing
|
||||
// This allows to drive the responder in a environment, where 'update()' isn't called in the loop
|
||||
//#define ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE
|
||||
|
||||
// Enable/disable debug trace macros
|
||||
#ifdef DEBUG_ESP_MDNS_RESPONDER
|
||||
#define DEBUG_ESP_MDNS_INFO
|
||||
#define DEBUG_ESP_MDNS_ERR
|
||||
#define DEBUG_ESP_MDNS_TX
|
||||
#define DEBUG_ESP_MDNS_RX
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_ESP_MDNS_RESPONDER
|
||||
#ifdef DEBUG_ESP_MDNS_INFO
|
||||
#define DEBUG_EX_INFO(A) A
|
||||
#else
|
||||
#define DEBUG_EX_INFO(A)
|
||||
#endif
|
||||
#ifdef DEBUG_ESP_MDNS_ERR
|
||||
#define DEBUG_EX_ERR(A) A
|
||||
#else
|
||||
#define DEBUG_EX_ERR(A)
|
||||
#endif
|
||||
#ifdef DEBUG_ESP_MDNS_TX
|
||||
#define DEBUG_EX_TX(A) A
|
||||
#else
|
||||
#define DEBUG_EX_TX(A)
|
||||
#endif
|
||||
#ifdef DEBUG_ESP_MDNS_RX
|
||||
#define DEBUG_EX_RX(A) A
|
||||
#else
|
||||
#define DEBUG_EX_RX(A)
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_ESP_PORT
|
||||
#define DEBUG_OUTPUT DEBUG_ESP_PORT
|
||||
#else
|
||||
#define DEBUG_OUTPUT Serial
|
||||
#endif
|
||||
#else
|
||||
#define DEBUG_EX_INFO(A)
|
||||
#define DEBUG_EX_ERR(A)
|
||||
#define DEBUG_EX_TX(A)
|
||||
#define DEBUG_EX_RX(A)
|
||||
#endif
|
||||
|
||||
|
||||
/* Replaced by 'lwip/prot/dns.h' definitions
|
||||
#ifdef MDNS_IP4_SUPPORT
|
||||
#define MDNS_MULTICAST_ADDR_IP4 (IPAddress(224, 0, 0, 251)) // ip_addr_t v4group = DNS_MQUERY_IPV4_GROUP_INIT
|
||||
#endif
|
||||
#ifdef MDNS_IP6_SUPPORT
|
||||
#define MDNS_MULTICAST_ADDR_IP6 (IPAddress("FF02::FB")) // ip_addr_t v6group = DNS_MQUERY_IPV6_GROUP_INIT
|
||||
#endif*/
|
||||
//#define MDNS_MULTICAST_PORT 5353
|
||||
|
||||
/*
|
||||
This is NOT the TTL (Time-To-Live) for MDNS records, but the
|
||||
subnet level distance MDNS records should travel.
|
||||
1 sets the subnet distance to 'local', which is default for MDNS.
|
||||
(Btw.: 255 would set it to 'as far as possible' -> internet)
|
||||
|
||||
However, RFC 3171 seems to force 255 instead
|
||||
*/
|
||||
#define MDNS_MULTICAST_TTL 255/*1*/
|
||||
|
||||
/*
|
||||
This is the MDNS record TTL
|
||||
Host level records are set to 2min (120s)
|
||||
service level records are set to 75min (4500s)
|
||||
*/
|
||||
#define MDNS_HOST_TTL 120
|
||||
#define MDNS_SERVICE_TTL 4500
|
||||
|
||||
/*
|
||||
Compressed labels are flaged by the two topmost bits of the length byte being set
|
||||
*/
|
||||
#define MDNS_DOMAIN_COMPRESS_MARK 0xC0
|
||||
/*
|
||||
Avoid endless recursion because of malformed compressed labels
|
||||
*/
|
||||
#define MDNS_DOMAIN_MAX_REDIRCTION 6
|
||||
|
||||
/*
|
||||
Default service priority and weight in SRV answers
|
||||
*/
|
||||
#define MDNS_SRV_PRIORITY 0
|
||||
#define MDNS_SRV_WEIGHT 0
|
||||
|
||||
/*
|
||||
Delay between and number of probes for host and service domains
|
||||
Delay between and number of announces for host and service domains
|
||||
Delay between and number of service queries; the delay is multiplied by the resent number in '_checkServiceQueryCache'
|
||||
*/
|
||||
#define MDNS_PROBE_DELAY 250
|
||||
#define MDNS_PROBE_COUNT 3
|
||||
#define MDNS_ANNOUNCE_DELAY 1000
|
||||
#define MDNS_ANNOUNCE_COUNT 8
|
||||
#define MDNS_DYNAMIC_QUERY_RESEND_COUNT 5
|
||||
#define MDNS_DYNAMIC_QUERY_RESEND_DELAY 5000
|
||||
|
||||
|
||||
/*
|
||||
Force host domain to use only lowercase letters
|
||||
*/
|
||||
//#define MDNS_FORCE_LOWERCASE_HOSTNAME
|
||||
|
||||
/*
|
||||
Enable/disable the usage of the F() macro in debug trace printf calls.
|
||||
There needs to be an PGM comptible printf function to use this.
|
||||
|
||||
USE_PGM_PRINTF and F
|
||||
*/
|
||||
#define USE_PGM_PRINTF
|
||||
|
||||
#ifdef USE_PGM_PRINTF
|
||||
#else
|
||||
#ifdef F
|
||||
#undef F
|
||||
#endif
|
||||
#define F(A) A
|
||||
#endif
|
||||
|
||||
} // namespace MDNSImplementation
|
||||
|
||||
} // namespace esp8266
|
||||
|
||||
// Include the main header, so the submodlues only need to include this header
|
||||
#include "LEAmDNS.h"
|
||||
|
||||
|
||||
#endif // MDNS_PRIV_H
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,26 +1,26 @@
|
||||
/*
|
||||
* LEAmDNS_Priv.h
|
||||
*
|
||||
* License (MIT license):
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
LEAmDNS_Priv.h
|
||||
|
||||
License (MIT license):
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef MDNS_LWIPDEFS_H
|
||||
#define MDNS_LWIPDEFS_H
|
||||
|
@ -1,50 +1,51 @@
|
||||
#ifndef RFC1305_H
|
||||
#define RFC1305_H
|
||||
/*
|
||||
* see https://www.eecis.udel.edu/~mills/database/rfc/rfc1305/rfc1305c.pdf
|
||||
* https://tools.ietf.org/html/rfc1305
|
||||
*/
|
||||
|
||||
#pragma pack(1)
|
||||
struct sRFC1305 {
|
||||
// NOTE all fields are BIG-ENDIAN so must be swapped on little endian machines
|
||||
uint8_t MODE:3;
|
||||
uint8_t VN:3;
|
||||
uint8_t LI:2;
|
||||
uint8_t stratum;
|
||||
uint8_t poll;
|
||||
uint8_t precision;
|
||||
int16_t rootdelay_main;
|
||||
uint16_t rootdelay_fraction;
|
||||
int16_t rootdispersion_main;
|
||||
uint16_t rootdispersion_fraction;
|
||||
uint8_t identifier[4];
|
||||
// 64 bit timestamps contain 32 bit whole part + 32 bit fractional part
|
||||
uint32_t referencetimestamp_main;
|
||||
uint32_t referencetimestamp_fraction;
|
||||
uint32_t origintimestamp_main;
|
||||
uint32_t origintimestamp_fraction;
|
||||
uint32_t receivetimestamp_main;
|
||||
uint32_t receivetimestamp_fraction;
|
||||
uint32_t transmittimestamp_main;
|
||||
uint32_t transmittimestamp_fraction;
|
||||
};
|
||||
#pragma pack(0)
|
||||
|
||||
#define LI_NOWARNING 0
|
||||
#define LI_61_SEC 1
|
||||
#define LI_59_SEC 2
|
||||
#define LI_ALARM 3
|
||||
|
||||
#define VERN 4
|
||||
|
||||
#define MODE_SYMMETRIC_ACTIVE 1
|
||||
#define MODE_SYMMETRIC_PASSIVE 2
|
||||
#define MODE_CLIENT 3
|
||||
#define MODE_SERVER 4
|
||||
#define MODE_BROADCAST 5
|
||||
|
||||
#define ENDIAN_SWAP_32(l) ((l>>24) |((l>>16)<<8)&0xff00 | ((l>>8)<<16)&0xff0000 | (l << 24))
|
||||
#define ENDIAN_SWAP_16(l) ((l>>8) | (l << 8))
|
||||
#endif
|
||||
|
||||
#ifndef RFC1305_H
|
||||
#define RFC1305_H
|
||||
/*
|
||||
see https://www.eecis.udel.edu/~mills/database/rfc/rfc1305/rfc1305c.pdf
|
||||
https://tools.ietf.org/html/rfc1305
|
||||
*/
|
||||
|
||||
#pragma pack(1)
|
||||
struct sRFC1305
|
||||
{
|
||||
// NOTE all fields are BIG-ENDIAN so must be swapped on little endian machines
|
||||
uint8_t MODE: 3;
|
||||
uint8_t VN: 3;
|
||||
uint8_t LI: 2;
|
||||
uint8_t stratum;
|
||||
uint8_t poll;
|
||||
uint8_t precision;
|
||||
int16_t rootdelay_main;
|
||||
uint16_t rootdelay_fraction;
|
||||
int16_t rootdispersion_main;
|
||||
uint16_t rootdispersion_fraction;
|
||||
uint8_t identifier[4];
|
||||
// 64 bit timestamps contain 32 bit whole part + 32 bit fractional part
|
||||
uint32_t referencetimestamp_main;
|
||||
uint32_t referencetimestamp_fraction;
|
||||
uint32_t origintimestamp_main;
|
||||
uint32_t origintimestamp_fraction;
|
||||
uint32_t receivetimestamp_main;
|
||||
uint32_t receivetimestamp_fraction;
|
||||
uint32_t transmittimestamp_main;
|
||||
uint32_t transmittimestamp_fraction;
|
||||
};
|
||||
#pragma pack(0)
|
||||
|
||||
#define LI_NOWARNING 0
|
||||
#define LI_61_SEC 1
|
||||
#define LI_59_SEC 2
|
||||
#define LI_ALARM 3
|
||||
|
||||
#define VERN 4
|
||||
|
||||
#define MODE_SYMMETRIC_ACTIVE 1
|
||||
#define MODE_SYMMETRIC_PASSIVE 2
|
||||
#define MODE_CLIENT 3
|
||||
#define MODE_SERVER 4
|
||||
#define MODE_BROADCAST 5
|
||||
|
||||
#define ENDIAN_SWAP_32(l) ((l>>24) |((l>>16)<<8)&0xff00 | ((l>>8)<<16)&0xff0000 | (l << 24))
|
||||
#define ENDIAN_SWAP_16(l) ((l>>8) | (l << 8))
|
||||
#endif
|
||||
|
||||
|
@ -1,481 +1,508 @@
|
||||
// DHCP Library v0.3 - April 25, 2009
|
||||
// Author: Jordan Terrell - blog.jordanterrell.com
|
||||
|
||||
#include "utility/w5100.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "Dhcp.h"
|
||||
#include "Arduino.h"
|
||||
#include "utility/util.h"
|
||||
|
||||
int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout)
|
||||
{
|
||||
_dhcpLeaseTime=0;
|
||||
_dhcpT1=0;
|
||||
_dhcpT2=0;
|
||||
_lastCheck=0;
|
||||
_timeout = timeout;
|
||||
_responseTimeout = responseTimeout;
|
||||
|
||||
// zero out _dhcpMacAddr
|
||||
memset(_dhcpMacAddr, 0, 6);
|
||||
reset_DHCP_lease();
|
||||
|
||||
memcpy((void*)_dhcpMacAddr, (void*)mac, 6);
|
||||
_dhcp_state = STATE_DHCP_START;
|
||||
return request_DHCP_lease();
|
||||
}
|
||||
|
||||
void DhcpClass::reset_DHCP_lease(){
|
||||
// zero out _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp
|
||||
memset(_dhcpLocalIp, 0, 20);
|
||||
}
|
||||
|
||||
//return:0 on error, 1 if request is sent and response is received
|
||||
int DhcpClass::request_DHCP_lease(){
|
||||
|
||||
uint8_t messageType = 0;
|
||||
|
||||
|
||||
|
||||
// Pick an initial transaction ID
|
||||
_dhcpTransactionId = random(1UL, 2000UL);
|
||||
_dhcpInitialTransactionId = _dhcpTransactionId;
|
||||
|
||||
_dhcpUdpSocket.stop();
|
||||
if (_dhcpUdpSocket.begin(DHCP_CLIENT_PORT) == 0)
|
||||
{
|
||||
// Couldn't get a socket
|
||||
return 0;
|
||||
}
|
||||
|
||||
presend_DHCP();
|
||||
|
||||
int result = 0;
|
||||
|
||||
unsigned long startTime = millis();
|
||||
|
||||
while(_dhcp_state != STATE_DHCP_LEASED)
|
||||
{
|
||||
if(_dhcp_state == STATE_DHCP_START)
|
||||
{
|
||||
_dhcpTransactionId++;
|
||||
|
||||
send_DHCP_MESSAGE(DHCP_DISCOVER, ((millis() - startTime) / 1000));
|
||||
_dhcp_state = STATE_DHCP_DISCOVER;
|
||||
}
|
||||
else if(_dhcp_state == STATE_DHCP_REREQUEST){
|
||||
_dhcpTransactionId++;
|
||||
send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime)/1000));
|
||||
_dhcp_state = STATE_DHCP_REQUEST;
|
||||
}
|
||||
else if(_dhcp_state == STATE_DHCP_DISCOVER)
|
||||
{
|
||||
uint32_t respId;
|
||||
messageType = parseDHCPResponse(_responseTimeout, respId);
|
||||
if(messageType == DHCP_OFFER)
|
||||
{
|
||||
// We'll use the transaction ID that the offer came with,
|
||||
// rather than the one we were up to
|
||||
_dhcpTransactionId = respId;
|
||||
send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime) / 1000));
|
||||
_dhcp_state = STATE_DHCP_REQUEST;
|
||||
}
|
||||
}
|
||||
else if(_dhcp_state == STATE_DHCP_REQUEST)
|
||||
{
|
||||
uint32_t respId;
|
||||
messageType = parseDHCPResponse(_responseTimeout, respId);
|
||||
if(messageType == DHCP_ACK)
|
||||
{
|
||||
_dhcp_state = STATE_DHCP_LEASED;
|
||||
result = 1;
|
||||
//use default lease time if we didn't get it
|
||||
if(_dhcpLeaseTime == 0){
|
||||
_dhcpLeaseTime = DEFAULT_LEASE;
|
||||
}
|
||||
//calculate T1 & T2 if we didn't get it
|
||||
if(_dhcpT1 == 0){
|
||||
//T1 should be 50% of _dhcpLeaseTime
|
||||
_dhcpT1 = _dhcpLeaseTime >> 1;
|
||||
}
|
||||
if(_dhcpT2 == 0){
|
||||
//T2 should be 87.5% (7/8ths) of _dhcpLeaseTime
|
||||
_dhcpT2 = _dhcpT1 << 1;
|
||||
}
|
||||
_renewInSec = _dhcpT1;
|
||||
_rebindInSec = _dhcpT2;
|
||||
}
|
||||
else if(messageType == DHCP_NAK)
|
||||
_dhcp_state = STATE_DHCP_START;
|
||||
}
|
||||
|
||||
if(messageType == 255)
|
||||
{
|
||||
messageType = 0;
|
||||
_dhcp_state = STATE_DHCP_START;
|
||||
}
|
||||
|
||||
if(result != 1 && ((millis() - startTime) > _timeout))
|
||||
break;
|
||||
}
|
||||
|
||||
// We're done with the socket now
|
||||
_dhcpUdpSocket.stop();
|
||||
_dhcpTransactionId++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void DhcpClass::presend_DHCP()
|
||||
{
|
||||
}
|
||||
|
||||
void DhcpClass::send_DHCP_MESSAGE(uint8_t messageType, uint16_t secondsElapsed)
|
||||
{
|
||||
uint8_t buffer[32];
|
||||
memset(buffer, 0, 32);
|
||||
IPAddress dest_addr( 255, 255, 255, 255 ); // Broadcast address
|
||||
|
||||
if (-1 == _dhcpUdpSocket.beginPacket(dest_addr, DHCP_SERVER_PORT))
|
||||
{
|
||||
// FIXME Need to return errors
|
||||
return;
|
||||
}
|
||||
|
||||
buffer[0] = DHCP_BOOTREQUEST; // op
|
||||
buffer[1] = DHCP_HTYPE10MB; // htype
|
||||
buffer[2] = DHCP_HLENETHERNET; // hlen
|
||||
buffer[3] = DHCP_HOPS; // hops
|
||||
|
||||
// xid
|
||||
unsigned long xid = htonl(_dhcpTransactionId);
|
||||
memcpy(buffer + 4, &(xid), 4);
|
||||
|
||||
// 8, 9 - seconds elapsed
|
||||
buffer[8] = ((secondsElapsed & 0xff00) >> 8);
|
||||
buffer[9] = (secondsElapsed & 0x00ff);
|
||||
|
||||
// flags
|
||||
unsigned short flags = htons(DHCP_FLAGSBROADCAST);
|
||||
memcpy(buffer + 10, &(flags), 2);
|
||||
|
||||
// ciaddr: already zeroed
|
||||
// yiaddr: already zeroed
|
||||
// siaddr: already zeroed
|
||||
// giaddr: already zeroed
|
||||
|
||||
//put data in W5100 transmit buffer
|
||||
_dhcpUdpSocket.write(buffer, 28);
|
||||
|
||||
memset(buffer, 0, 32); // clear local buffer
|
||||
|
||||
memcpy(buffer, _dhcpMacAddr, 6); // chaddr
|
||||
|
||||
//put data in W5100 transmit buffer
|
||||
_dhcpUdpSocket.write(buffer, 16);
|
||||
|
||||
memset(buffer, 0, 32); // clear local buffer
|
||||
|
||||
// leave zeroed out for sname && file
|
||||
// put in W5100 transmit buffer x 6 (192 bytes)
|
||||
|
||||
for(int i = 0; i < 6; i++) {
|
||||
_dhcpUdpSocket.write(buffer, 32);
|
||||
}
|
||||
|
||||
// OPT - Magic Cookie
|
||||
buffer[0] = (uint8_t)((MAGIC_COOKIE >> 24)& 0xFF);
|
||||
buffer[1] = (uint8_t)((MAGIC_COOKIE >> 16)& 0xFF);
|
||||
buffer[2] = (uint8_t)((MAGIC_COOKIE >> 8)& 0xFF);
|
||||
buffer[3] = (uint8_t)(MAGIC_COOKIE& 0xFF);
|
||||
|
||||
// OPT - message type
|
||||
buffer[4] = dhcpMessageType;
|
||||
buffer[5] = 0x01;
|
||||
buffer[6] = messageType; //DHCP_REQUEST;
|
||||
|
||||
// OPT - client identifier
|
||||
buffer[7] = dhcpClientIdentifier;
|
||||
buffer[8] = 0x07;
|
||||
buffer[9] = 0x01;
|
||||
memcpy(buffer + 10, _dhcpMacAddr, 6);
|
||||
|
||||
// OPT - host name
|
||||
buffer[16] = hostName;
|
||||
buffer[17] = strlen(HOST_NAME) + 6; // length of hostname + last 3 bytes of mac address
|
||||
strcpy((char*)&(buffer[18]), HOST_NAME);
|
||||
|
||||
printByte((char*)&(buffer[24]), _dhcpMacAddr[3]);
|
||||
printByte((char*)&(buffer[26]), _dhcpMacAddr[4]);
|
||||
printByte((char*)&(buffer[28]), _dhcpMacAddr[5]);
|
||||
|
||||
//put data in W5100 transmit buffer
|
||||
_dhcpUdpSocket.write(buffer, 30);
|
||||
|
||||
if(messageType == DHCP_REQUEST)
|
||||
{
|
||||
buffer[0] = dhcpRequestedIPaddr;
|
||||
buffer[1] = 0x04;
|
||||
buffer[2] = _dhcpLocalIp[0];
|
||||
buffer[3] = _dhcpLocalIp[1];
|
||||
buffer[4] = _dhcpLocalIp[2];
|
||||
buffer[5] = _dhcpLocalIp[3];
|
||||
|
||||
buffer[6] = dhcpServerIdentifier;
|
||||
buffer[7] = 0x04;
|
||||
buffer[8] = _dhcpDhcpServerIp[0];
|
||||
buffer[9] = _dhcpDhcpServerIp[1];
|
||||
buffer[10] = _dhcpDhcpServerIp[2];
|
||||
buffer[11] = _dhcpDhcpServerIp[3];
|
||||
|
||||
//put data in W5100 transmit buffer
|
||||
_dhcpUdpSocket.write(buffer, 12);
|
||||
}
|
||||
|
||||
buffer[0] = dhcpParamRequest;
|
||||
buffer[1] = 0x06;
|
||||
buffer[2] = subnetMask;
|
||||
buffer[3] = routersOnSubnet;
|
||||
buffer[4] = dns;
|
||||
buffer[5] = domainName;
|
||||
buffer[6] = dhcpT1value;
|
||||
buffer[7] = dhcpT2value;
|
||||
buffer[8] = endOption;
|
||||
|
||||
//put data in W5100 transmit buffer
|
||||
_dhcpUdpSocket.write(buffer, 9);
|
||||
|
||||
_dhcpUdpSocket.endPacket();
|
||||
}
|
||||
|
||||
uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId)
|
||||
{
|
||||
uint8_t type = 0;
|
||||
uint8_t opt_len = 0;
|
||||
|
||||
unsigned long startTime = millis();
|
||||
|
||||
while(_dhcpUdpSocket.parsePacket() <= 0)
|
||||
{
|
||||
if((millis() - startTime) > responseTimeout)
|
||||
{
|
||||
return 255;
|
||||
}
|
||||
delay(50);
|
||||
}
|
||||
// start reading in the packet
|
||||
RIP_MSG_FIXED fixedMsg;
|
||||
_dhcpUdpSocket.read((uint8_t*)&fixedMsg, sizeof(RIP_MSG_FIXED));
|
||||
|
||||
if(fixedMsg.op == DHCP_BOOTREPLY && _dhcpUdpSocket.remotePort() == DHCP_SERVER_PORT)
|
||||
{
|
||||
transactionId = ntohl(fixedMsg.xid);
|
||||
if(memcmp(fixedMsg.chaddr, _dhcpMacAddr, 6) != 0 || (transactionId < _dhcpInitialTransactionId) || (transactionId > _dhcpTransactionId))
|
||||
{
|
||||
// Need to read the rest of the packet here regardless
|
||||
_dhcpUdpSocket.flush();
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(_dhcpLocalIp, fixedMsg.yiaddr, 4);
|
||||
|
||||
// Skip to the option part
|
||||
// Doing this a byte at a time so we don't have to put a big buffer
|
||||
// on the stack (as we don't have lots of memory lying around)
|
||||
for (int i =0; i < (240 - (int)sizeof(RIP_MSG_FIXED)); i++)
|
||||
{
|
||||
_dhcpUdpSocket.read(); // we don't care about the returned byte
|
||||
}
|
||||
|
||||
while (_dhcpUdpSocket.available() > 0)
|
||||
{
|
||||
switch (_dhcpUdpSocket.read())
|
||||
{
|
||||
case endOption :
|
||||
break;
|
||||
|
||||
case padOption :
|
||||
break;
|
||||
|
||||
case dhcpMessageType :
|
||||
opt_len = _dhcpUdpSocket.read();
|
||||
type = _dhcpUdpSocket.read();
|
||||
break;
|
||||
|
||||
case subnetMask :
|
||||
opt_len = _dhcpUdpSocket.read();
|
||||
_dhcpUdpSocket.read(_dhcpSubnetMask, 4);
|
||||
break;
|
||||
|
||||
case routersOnSubnet :
|
||||
opt_len = _dhcpUdpSocket.read();
|
||||
_dhcpUdpSocket.read(_dhcpGatewayIp, 4);
|
||||
for (int i = 0; i < opt_len-4; i++)
|
||||
{
|
||||
_dhcpUdpSocket.read();
|
||||
}
|
||||
break;
|
||||
|
||||
case dns :
|
||||
opt_len = _dhcpUdpSocket.read();
|
||||
_dhcpUdpSocket.read(_dhcpDnsServerIp, 4);
|
||||
for (int i = 0; i < opt_len-4; i++)
|
||||
{
|
||||
_dhcpUdpSocket.read();
|
||||
}
|
||||
break;
|
||||
|
||||
case dhcpServerIdentifier :
|
||||
opt_len = _dhcpUdpSocket.read();
|
||||
if ((_dhcpDhcpServerIp[0] == 0 && _dhcpDhcpServerIp[1] == 0 &&
|
||||
_dhcpDhcpServerIp[2] == 0 && _dhcpDhcpServerIp[3] == 0) ||
|
||||
IPAddress(_dhcpDhcpServerIp) == _dhcpUdpSocket.remoteIP())
|
||||
{
|
||||
_dhcpUdpSocket.read(_dhcpDhcpServerIp, sizeof(_dhcpDhcpServerIp));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Skip over the rest of this option
|
||||
while (opt_len--)
|
||||
{
|
||||
_dhcpUdpSocket.read();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case dhcpT1value :
|
||||
opt_len = _dhcpUdpSocket.read();
|
||||
_dhcpUdpSocket.read((uint8_t*)&_dhcpT1, sizeof(_dhcpT1));
|
||||
_dhcpT1 = ntohl(_dhcpT1);
|
||||
break;
|
||||
|
||||
case dhcpT2value :
|
||||
opt_len = _dhcpUdpSocket.read();
|
||||
_dhcpUdpSocket.read((uint8_t*)&_dhcpT2, sizeof(_dhcpT2));
|
||||
_dhcpT2 = ntohl(_dhcpT2);
|
||||
break;
|
||||
|
||||
case dhcpIPaddrLeaseTime :
|
||||
opt_len = _dhcpUdpSocket.read();
|
||||
_dhcpUdpSocket.read((uint8_t*)&_dhcpLeaseTime, sizeof(_dhcpLeaseTime));
|
||||
_dhcpLeaseTime = ntohl(_dhcpLeaseTime);
|
||||
_renewInSec = _dhcpLeaseTime;
|
||||
break;
|
||||
|
||||
default :
|
||||
opt_len = _dhcpUdpSocket.read();
|
||||
// Skip over the rest of this option
|
||||
while (opt_len--)
|
||||
{
|
||||
_dhcpUdpSocket.read();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Need to skip to end of the packet regardless here
|
||||
_dhcpUdpSocket.flush();
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
returns:
|
||||
0/DHCP_CHECK_NONE: nothing happened
|
||||
1/DHCP_CHECK_RENEW_FAIL: renew failed
|
||||
2/DHCP_CHECK_RENEW_OK: renew success
|
||||
3/DHCP_CHECK_REBIND_FAIL: rebind fail
|
||||
4/DHCP_CHECK_REBIND_OK: rebind success
|
||||
*/
|
||||
int DhcpClass::checkLease(){
|
||||
//this uses a signed / unsigned trick to deal with millis overflow
|
||||
unsigned long now = millis();
|
||||
signed long snow = (long)now;
|
||||
int rc=DHCP_CHECK_NONE;
|
||||
if (_lastCheck != 0){
|
||||
signed long factor;
|
||||
//calc how many ms past the timeout we are
|
||||
factor = snow - (long)_secTimeout;
|
||||
//if on or passed the timeout, reduce the counters
|
||||
if ( factor >= 0 ){
|
||||
//next timeout should be now plus 1000 ms minus parts of second in factor
|
||||
_secTimeout = snow + 1000 - factor % 1000;
|
||||
//how many seconds late are we, minimum 1
|
||||
factor = factor / 1000 +1;
|
||||
|
||||
//reduce the counters by that mouch
|
||||
//if we can assume that the cycle time (factor) is fairly constant
|
||||
//and if the remainder is less than cycle time * 2
|
||||
//do it early instead of late
|
||||
if(_renewInSec < factor*2 )
|
||||
_renewInSec = 0;
|
||||
else
|
||||
_renewInSec -= factor;
|
||||
|
||||
if(_rebindInSec < factor*2 )
|
||||
_rebindInSec = 0;
|
||||
else
|
||||
_rebindInSec -= factor;
|
||||
}
|
||||
|
||||
//if we have a lease but should renew, do it
|
||||
if (_dhcp_state == STATE_DHCP_LEASED && _renewInSec <=0){
|
||||
_dhcp_state = STATE_DHCP_REREQUEST;
|
||||
rc = 1 + request_DHCP_lease();
|
||||
}
|
||||
|
||||
//if we have a lease or is renewing but should bind, do it
|
||||
if( (_dhcp_state == STATE_DHCP_LEASED || _dhcp_state == STATE_DHCP_START) && _rebindInSec <=0){
|
||||
//this should basically restart completely
|
||||
_dhcp_state = STATE_DHCP_START;
|
||||
reset_DHCP_lease();
|
||||
rc = 3 + request_DHCP_lease();
|
||||
}
|
||||
}
|
||||
else{
|
||||
_secTimeout = snow + 1000;
|
||||
}
|
||||
|
||||
_lastCheck = now;
|
||||
return rc;
|
||||
}
|
||||
|
||||
IPAddress DhcpClass::getLocalIp()
|
||||
{
|
||||
return IPAddress(_dhcpLocalIp);
|
||||
}
|
||||
|
||||
IPAddress DhcpClass::getSubnetMask()
|
||||
{
|
||||
return IPAddress(_dhcpSubnetMask);
|
||||
}
|
||||
|
||||
IPAddress DhcpClass::getGatewayIp()
|
||||
{
|
||||
return IPAddress(_dhcpGatewayIp);
|
||||
}
|
||||
|
||||
IPAddress DhcpClass::getDhcpServerIp()
|
||||
{
|
||||
return IPAddress(_dhcpDhcpServerIp);
|
||||
}
|
||||
|
||||
IPAddress DhcpClass::getDnsServerIp()
|
||||
{
|
||||
return IPAddress(_dhcpDnsServerIp);
|
||||
}
|
||||
|
||||
void DhcpClass::printByte(char * buf, uint8_t n ) {
|
||||
char *str = &buf[1];
|
||||
buf[0]='0';
|
||||
do {
|
||||
unsigned long m = n;
|
||||
n /= 16;
|
||||
char c = m - 16 * n;
|
||||
*str-- = c < 10 ? c + '0' : c + 'A' - 10;
|
||||
} while(n);
|
||||
}
|
||||
// DHCP Library v0.3 - April 25, 2009
|
||||
// Author: Jordan Terrell - blog.jordanterrell.com
|
||||
|
||||
#include "utility/w5100.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "Dhcp.h"
|
||||
#include "Arduino.h"
|
||||
#include "utility/util.h"
|
||||
|
||||
int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout)
|
||||
{
|
||||
_dhcpLeaseTime = 0;
|
||||
_dhcpT1 = 0;
|
||||
_dhcpT2 = 0;
|
||||
_lastCheck = 0;
|
||||
_timeout = timeout;
|
||||
_responseTimeout = responseTimeout;
|
||||
|
||||
// zero out _dhcpMacAddr
|
||||
memset(_dhcpMacAddr, 0, 6);
|
||||
reset_DHCP_lease();
|
||||
|
||||
memcpy((void*)_dhcpMacAddr, (void*)mac, 6);
|
||||
_dhcp_state = STATE_DHCP_START;
|
||||
return request_DHCP_lease();
|
||||
}
|
||||
|
||||
void DhcpClass::reset_DHCP_lease()
|
||||
{
|
||||
// zero out _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp
|
||||
memset(_dhcpLocalIp, 0, 20);
|
||||
}
|
||||
|
||||
//return:0 on error, 1 if request is sent and response is received
|
||||
int DhcpClass::request_DHCP_lease()
|
||||
{
|
||||
|
||||
uint8_t messageType = 0;
|
||||
|
||||
|
||||
|
||||
// Pick an initial transaction ID
|
||||
_dhcpTransactionId = random(1UL, 2000UL);
|
||||
_dhcpInitialTransactionId = _dhcpTransactionId;
|
||||
|
||||
_dhcpUdpSocket.stop();
|
||||
if (_dhcpUdpSocket.begin(DHCP_CLIENT_PORT) == 0)
|
||||
{
|
||||
// Couldn't get a socket
|
||||
return 0;
|
||||
}
|
||||
|
||||
presend_DHCP();
|
||||
|
||||
int result = 0;
|
||||
|
||||
unsigned long startTime = millis();
|
||||
|
||||
while (_dhcp_state != STATE_DHCP_LEASED)
|
||||
{
|
||||
if (_dhcp_state == STATE_DHCP_START)
|
||||
{
|
||||
_dhcpTransactionId++;
|
||||
|
||||
send_DHCP_MESSAGE(DHCP_DISCOVER, ((millis() - startTime) / 1000));
|
||||
_dhcp_state = STATE_DHCP_DISCOVER;
|
||||
}
|
||||
else if (_dhcp_state == STATE_DHCP_REREQUEST)
|
||||
{
|
||||
_dhcpTransactionId++;
|
||||
send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime) / 1000));
|
||||
_dhcp_state = STATE_DHCP_REQUEST;
|
||||
}
|
||||
else if (_dhcp_state == STATE_DHCP_DISCOVER)
|
||||
{
|
||||
uint32_t respId;
|
||||
messageType = parseDHCPResponse(_responseTimeout, respId);
|
||||
if (messageType == DHCP_OFFER)
|
||||
{
|
||||
// We'll use the transaction ID that the offer came with,
|
||||
// rather than the one we were up to
|
||||
_dhcpTransactionId = respId;
|
||||
send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime) / 1000));
|
||||
_dhcp_state = STATE_DHCP_REQUEST;
|
||||
}
|
||||
}
|
||||
else if (_dhcp_state == STATE_DHCP_REQUEST)
|
||||
{
|
||||
uint32_t respId;
|
||||
messageType = parseDHCPResponse(_responseTimeout, respId);
|
||||
if (messageType == DHCP_ACK)
|
||||
{
|
||||
_dhcp_state = STATE_DHCP_LEASED;
|
||||
result = 1;
|
||||
//use default lease time if we didn't get it
|
||||
if (_dhcpLeaseTime == 0)
|
||||
{
|
||||
_dhcpLeaseTime = DEFAULT_LEASE;
|
||||
}
|
||||
//calculate T1 & T2 if we didn't get it
|
||||
if (_dhcpT1 == 0)
|
||||
{
|
||||
//T1 should be 50% of _dhcpLeaseTime
|
||||
_dhcpT1 = _dhcpLeaseTime >> 1;
|
||||
}
|
||||
if (_dhcpT2 == 0)
|
||||
{
|
||||
//T2 should be 87.5% (7/8ths) of _dhcpLeaseTime
|
||||
_dhcpT2 = _dhcpT1 << 1;
|
||||
}
|
||||
_renewInSec = _dhcpT1;
|
||||
_rebindInSec = _dhcpT2;
|
||||
}
|
||||
else if (messageType == DHCP_NAK)
|
||||
{
|
||||
_dhcp_state = STATE_DHCP_START;
|
||||
}
|
||||
}
|
||||
|
||||
if (messageType == 255)
|
||||
{
|
||||
messageType = 0;
|
||||
_dhcp_state = STATE_DHCP_START;
|
||||
}
|
||||
|
||||
if (result != 1 && ((millis() - startTime) > _timeout))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We're done with the socket now
|
||||
_dhcpUdpSocket.stop();
|
||||
_dhcpTransactionId++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void DhcpClass::presend_DHCP()
|
||||
{
|
||||
}
|
||||
|
||||
void DhcpClass::send_DHCP_MESSAGE(uint8_t messageType, uint16_t secondsElapsed)
|
||||
{
|
||||
uint8_t buffer[32];
|
||||
memset(buffer, 0, 32);
|
||||
IPAddress dest_addr(255, 255, 255, 255); // Broadcast address
|
||||
|
||||
if (-1 == _dhcpUdpSocket.beginPacket(dest_addr, DHCP_SERVER_PORT))
|
||||
{
|
||||
// FIXME Need to return errors
|
||||
return;
|
||||
}
|
||||
|
||||
buffer[0] = DHCP_BOOTREQUEST; // op
|
||||
buffer[1] = DHCP_HTYPE10MB; // htype
|
||||
buffer[2] = DHCP_HLENETHERNET; // hlen
|
||||
buffer[3] = DHCP_HOPS; // hops
|
||||
|
||||
// xid
|
||||
unsigned long xid = htonl(_dhcpTransactionId);
|
||||
memcpy(buffer + 4, &(xid), 4);
|
||||
|
||||
// 8, 9 - seconds elapsed
|
||||
buffer[8] = ((secondsElapsed & 0xff00) >> 8);
|
||||
buffer[9] = (secondsElapsed & 0x00ff);
|
||||
|
||||
// flags
|
||||
unsigned short flags = htons(DHCP_FLAGSBROADCAST);
|
||||
memcpy(buffer + 10, &(flags), 2);
|
||||
|
||||
// ciaddr: already zeroed
|
||||
// yiaddr: already zeroed
|
||||
// siaddr: already zeroed
|
||||
// giaddr: already zeroed
|
||||
|
||||
//put data in W5100 transmit buffer
|
||||
_dhcpUdpSocket.write(buffer, 28);
|
||||
|
||||
memset(buffer, 0, 32); // clear local buffer
|
||||
|
||||
memcpy(buffer, _dhcpMacAddr, 6); // chaddr
|
||||
|
||||
//put data in W5100 transmit buffer
|
||||
_dhcpUdpSocket.write(buffer, 16);
|
||||
|
||||
memset(buffer, 0, 32); // clear local buffer
|
||||
|
||||
// leave zeroed out for sname && file
|
||||
// put in W5100 transmit buffer x 6 (192 bytes)
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
_dhcpUdpSocket.write(buffer, 32);
|
||||
}
|
||||
|
||||
// OPT - Magic Cookie
|
||||
buffer[0] = (uint8_t)((MAGIC_COOKIE >> 24) & 0xFF);
|
||||
buffer[1] = (uint8_t)((MAGIC_COOKIE >> 16) & 0xFF);
|
||||
buffer[2] = (uint8_t)((MAGIC_COOKIE >> 8) & 0xFF);
|
||||
buffer[3] = (uint8_t)(MAGIC_COOKIE & 0xFF);
|
||||
|
||||
// OPT - message type
|
||||
buffer[4] = dhcpMessageType;
|
||||
buffer[5] = 0x01;
|
||||
buffer[6] = messageType; //DHCP_REQUEST;
|
||||
|
||||
// OPT - client identifier
|
||||
buffer[7] = dhcpClientIdentifier;
|
||||
buffer[8] = 0x07;
|
||||
buffer[9] = 0x01;
|
||||
memcpy(buffer + 10, _dhcpMacAddr, 6);
|
||||
|
||||
// OPT - host name
|
||||
buffer[16] = hostName;
|
||||
buffer[17] = strlen(HOST_NAME) + 6; // length of hostname + last 3 bytes of mac address
|
||||
strcpy((char*) & (buffer[18]), HOST_NAME);
|
||||
|
||||
printByte((char*) & (buffer[24]), _dhcpMacAddr[3]);
|
||||
printByte((char*) & (buffer[26]), _dhcpMacAddr[4]);
|
||||
printByte((char*) & (buffer[28]), _dhcpMacAddr[5]);
|
||||
|
||||
//put data in W5100 transmit buffer
|
||||
_dhcpUdpSocket.write(buffer, 30);
|
||||
|
||||
if (messageType == DHCP_REQUEST)
|
||||
{
|
||||
buffer[0] = dhcpRequestedIPaddr;
|
||||
buffer[1] = 0x04;
|
||||
buffer[2] = _dhcpLocalIp[0];
|
||||
buffer[3] = _dhcpLocalIp[1];
|
||||
buffer[4] = _dhcpLocalIp[2];
|
||||
buffer[5] = _dhcpLocalIp[3];
|
||||
|
||||
buffer[6] = dhcpServerIdentifier;
|
||||
buffer[7] = 0x04;
|
||||
buffer[8] = _dhcpDhcpServerIp[0];
|
||||
buffer[9] = _dhcpDhcpServerIp[1];
|
||||
buffer[10] = _dhcpDhcpServerIp[2];
|
||||
buffer[11] = _dhcpDhcpServerIp[3];
|
||||
|
||||
//put data in W5100 transmit buffer
|
||||
_dhcpUdpSocket.write(buffer, 12);
|
||||
}
|
||||
|
||||
buffer[0] = dhcpParamRequest;
|
||||
buffer[1] = 0x06;
|
||||
buffer[2] = subnetMask;
|
||||
buffer[3] = routersOnSubnet;
|
||||
buffer[4] = dns;
|
||||
buffer[5] = domainName;
|
||||
buffer[6] = dhcpT1value;
|
||||
buffer[7] = dhcpT2value;
|
||||
buffer[8] = endOption;
|
||||
|
||||
//put data in W5100 transmit buffer
|
||||
_dhcpUdpSocket.write(buffer, 9);
|
||||
|
||||
_dhcpUdpSocket.endPacket();
|
||||
}
|
||||
|
||||
uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId)
|
||||
{
|
||||
uint8_t type = 0;
|
||||
uint8_t opt_len = 0;
|
||||
|
||||
unsigned long startTime = millis();
|
||||
|
||||
while (_dhcpUdpSocket.parsePacket() <= 0)
|
||||
{
|
||||
if ((millis() - startTime) > responseTimeout)
|
||||
{
|
||||
return 255;
|
||||
}
|
||||
delay(50);
|
||||
}
|
||||
// start reading in the packet
|
||||
RIP_MSG_FIXED fixedMsg;
|
||||
_dhcpUdpSocket.read((uint8_t*)&fixedMsg, sizeof(RIP_MSG_FIXED));
|
||||
|
||||
if (fixedMsg.op == DHCP_BOOTREPLY && _dhcpUdpSocket.remotePort() == DHCP_SERVER_PORT)
|
||||
{
|
||||
transactionId = ntohl(fixedMsg.xid);
|
||||
if (memcmp(fixedMsg.chaddr, _dhcpMacAddr, 6) != 0 || (transactionId < _dhcpInitialTransactionId) || (transactionId > _dhcpTransactionId))
|
||||
{
|
||||
// Need to read the rest of the packet here regardless
|
||||
_dhcpUdpSocket.flush();
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(_dhcpLocalIp, fixedMsg.yiaddr, 4);
|
||||
|
||||
// Skip to the option part
|
||||
// Doing this a byte at a time so we don't have to put a big buffer
|
||||
// on the stack (as we don't have lots of memory lying around)
|
||||
for (int i = 0; i < (240 - (int)sizeof(RIP_MSG_FIXED)); i++)
|
||||
{
|
||||
_dhcpUdpSocket.read(); // we don't care about the returned byte
|
||||
}
|
||||
|
||||
while (_dhcpUdpSocket.available() > 0)
|
||||
{
|
||||
switch (_dhcpUdpSocket.read())
|
||||
{
|
||||
case endOption :
|
||||
break;
|
||||
|
||||
case padOption :
|
||||
break;
|
||||
|
||||
case dhcpMessageType :
|
||||
opt_len = _dhcpUdpSocket.read();
|
||||
type = _dhcpUdpSocket.read();
|
||||
break;
|
||||
|
||||
case subnetMask :
|
||||
opt_len = _dhcpUdpSocket.read();
|
||||
_dhcpUdpSocket.read(_dhcpSubnetMask, 4);
|
||||
break;
|
||||
|
||||
case routersOnSubnet :
|
||||
opt_len = _dhcpUdpSocket.read();
|
||||
_dhcpUdpSocket.read(_dhcpGatewayIp, 4);
|
||||
for (int i = 0; i < opt_len - 4; i++)
|
||||
{
|
||||
_dhcpUdpSocket.read();
|
||||
}
|
||||
break;
|
||||
|
||||
case dns :
|
||||
opt_len = _dhcpUdpSocket.read();
|
||||
_dhcpUdpSocket.read(_dhcpDnsServerIp, 4);
|
||||
for (int i = 0; i < opt_len - 4; i++)
|
||||
{
|
||||
_dhcpUdpSocket.read();
|
||||
}
|
||||
break;
|
||||
|
||||
case dhcpServerIdentifier :
|
||||
opt_len = _dhcpUdpSocket.read();
|
||||
if ((_dhcpDhcpServerIp[0] == 0 && _dhcpDhcpServerIp[1] == 0 &&
|
||||
_dhcpDhcpServerIp[2] == 0 && _dhcpDhcpServerIp[3] == 0) ||
|
||||
IPAddress(_dhcpDhcpServerIp) == _dhcpUdpSocket.remoteIP())
|
||||
{
|
||||
_dhcpUdpSocket.read(_dhcpDhcpServerIp, sizeof(_dhcpDhcpServerIp));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Skip over the rest of this option
|
||||
while (opt_len--)
|
||||
{
|
||||
_dhcpUdpSocket.read();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case dhcpT1value :
|
||||
opt_len = _dhcpUdpSocket.read();
|
||||
_dhcpUdpSocket.read((uint8_t*)&_dhcpT1, sizeof(_dhcpT1));
|
||||
_dhcpT1 = ntohl(_dhcpT1);
|
||||
break;
|
||||
|
||||
case dhcpT2value :
|
||||
opt_len = _dhcpUdpSocket.read();
|
||||
_dhcpUdpSocket.read((uint8_t*)&_dhcpT2, sizeof(_dhcpT2));
|
||||
_dhcpT2 = ntohl(_dhcpT2);
|
||||
break;
|
||||
|
||||
case dhcpIPaddrLeaseTime :
|
||||
opt_len = _dhcpUdpSocket.read();
|
||||
_dhcpUdpSocket.read((uint8_t*)&_dhcpLeaseTime, sizeof(_dhcpLeaseTime));
|
||||
_dhcpLeaseTime = ntohl(_dhcpLeaseTime);
|
||||
_renewInSec = _dhcpLeaseTime;
|
||||
break;
|
||||
|
||||
default :
|
||||
opt_len = _dhcpUdpSocket.read();
|
||||
// Skip over the rest of this option
|
||||
while (opt_len--)
|
||||
{
|
||||
_dhcpUdpSocket.read();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Need to skip to end of the packet regardless here
|
||||
_dhcpUdpSocket.flush();
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
returns:
|
||||
0/DHCP_CHECK_NONE: nothing happened
|
||||
1/DHCP_CHECK_RENEW_FAIL: renew failed
|
||||
2/DHCP_CHECK_RENEW_OK: renew success
|
||||
3/DHCP_CHECK_REBIND_FAIL: rebind fail
|
||||
4/DHCP_CHECK_REBIND_OK: rebind success
|
||||
*/
|
||||
int DhcpClass::checkLease()
|
||||
{
|
||||
//this uses a signed / unsigned trick to deal with millis overflow
|
||||
unsigned long now = millis();
|
||||
signed long snow = (long)now;
|
||||
int rc = DHCP_CHECK_NONE;
|
||||
if (_lastCheck != 0)
|
||||
{
|
||||
signed long factor;
|
||||
//calc how many ms past the timeout we are
|
||||
factor = snow - (long)_secTimeout;
|
||||
//if on or passed the timeout, reduce the counters
|
||||
if (factor >= 0)
|
||||
{
|
||||
//next timeout should be now plus 1000 ms minus parts of second in factor
|
||||
_secTimeout = snow + 1000 - factor % 1000;
|
||||
//how many seconds late are we, minimum 1
|
||||
factor = factor / 1000 + 1;
|
||||
|
||||
//reduce the counters by that mouch
|
||||
//if we can assume that the cycle time (factor) is fairly constant
|
||||
//and if the remainder is less than cycle time * 2
|
||||
//do it early instead of late
|
||||
if (_renewInSec < factor * 2)
|
||||
{
|
||||
_renewInSec = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_renewInSec -= factor;
|
||||
}
|
||||
|
||||
if (_rebindInSec < factor * 2)
|
||||
{
|
||||
_rebindInSec = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_rebindInSec -= factor;
|
||||
}
|
||||
}
|
||||
|
||||
//if we have a lease but should renew, do it
|
||||
if (_dhcp_state == STATE_DHCP_LEASED && _renewInSec <= 0)
|
||||
{
|
||||
_dhcp_state = STATE_DHCP_REREQUEST;
|
||||
rc = 1 + request_DHCP_lease();
|
||||
}
|
||||
|
||||
//if we have a lease or is renewing but should bind, do it
|
||||
if ((_dhcp_state == STATE_DHCP_LEASED || _dhcp_state == STATE_DHCP_START) && _rebindInSec <= 0)
|
||||
{
|
||||
//this should basically restart completely
|
||||
_dhcp_state = STATE_DHCP_START;
|
||||
reset_DHCP_lease();
|
||||
rc = 3 + request_DHCP_lease();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_secTimeout = snow + 1000;
|
||||
}
|
||||
|
||||
_lastCheck = now;
|
||||
return rc;
|
||||
}
|
||||
|
||||
IPAddress DhcpClass::getLocalIp()
|
||||
{
|
||||
return IPAddress(_dhcpLocalIp);
|
||||
}
|
||||
|
||||
IPAddress DhcpClass::getSubnetMask()
|
||||
{
|
||||
return IPAddress(_dhcpSubnetMask);
|
||||
}
|
||||
|
||||
IPAddress DhcpClass::getGatewayIp()
|
||||
{
|
||||
return IPAddress(_dhcpGatewayIp);
|
||||
}
|
||||
|
||||
IPAddress DhcpClass::getDhcpServerIp()
|
||||
{
|
||||
return IPAddress(_dhcpDhcpServerIp);
|
||||
}
|
||||
|
||||
IPAddress DhcpClass::getDnsServerIp()
|
||||
{
|
||||
return IPAddress(_dhcpDnsServerIp);
|
||||
}
|
||||
|
||||
void DhcpClass::printByte(char * buf, uint8_t n)
|
||||
{
|
||||
char *str = &buf[1];
|
||||
buf[0] = '0';
|
||||
do
|
||||
{
|
||||
unsigned long m = n;
|
||||
n /= 16;
|
||||
char c = m - 16 * n;
|
||||
*str-- = c < 10 ? c + '0' : c + 'A' - 10;
|
||||
} while (n);
|
||||
}
|
||||
|
@ -1,178 +1,179 @@
|
||||
// DHCP Library v0.3 - April 25, 2009
|
||||
// Author: Jordan Terrell - blog.jordanterrell.com
|
||||
|
||||
#ifndef Dhcp_h
|
||||
#define Dhcp_h
|
||||
|
||||
#include "EthernetUdp.h"
|
||||
|
||||
/* DHCP state machine. */
|
||||
#define STATE_DHCP_START 0
|
||||
#define STATE_DHCP_DISCOVER 1
|
||||
#define STATE_DHCP_REQUEST 2
|
||||
#define STATE_DHCP_LEASED 3
|
||||
#define STATE_DHCP_REREQUEST 4
|
||||
#define STATE_DHCP_RELEASE 5
|
||||
|
||||
#define DHCP_FLAGSBROADCAST 0x8000
|
||||
|
||||
/* UDP port numbers for DHCP */
|
||||
#define DHCP_SERVER_PORT 67 /* from server to client */
|
||||
#define DHCP_CLIENT_PORT 68 /* from client to server */
|
||||
|
||||
/* DHCP message OP code */
|
||||
#define DHCP_BOOTREQUEST 1
|
||||
#define DHCP_BOOTREPLY 2
|
||||
|
||||
/* DHCP message type */
|
||||
#define DHCP_DISCOVER 1
|
||||
#define DHCP_OFFER 2
|
||||
#define DHCP_REQUEST 3
|
||||
#define DHCP_DECLINE 4
|
||||
#define DHCP_ACK 5
|
||||
#define DHCP_NAK 6
|
||||
#define DHCP_RELEASE 7
|
||||
#define DHCP_INFORM 8
|
||||
|
||||
#define DHCP_HTYPE10MB 1
|
||||
#define DHCP_HTYPE100MB 2
|
||||
|
||||
#define DHCP_HLENETHERNET 6
|
||||
#define DHCP_HOPS 0
|
||||
#define DHCP_SECS 0
|
||||
|
||||
#define MAGIC_COOKIE 0x63825363
|
||||
#define MAX_DHCP_OPT 16
|
||||
|
||||
#define HOST_NAME "WIZnet"
|
||||
#define DEFAULT_LEASE (900) //default lease time in seconds
|
||||
|
||||
#define DHCP_CHECK_NONE (0)
|
||||
#define DHCP_CHECK_RENEW_FAIL (1)
|
||||
#define DHCP_CHECK_RENEW_OK (2)
|
||||
#define DHCP_CHECK_REBIND_FAIL (3)
|
||||
#define DHCP_CHECK_REBIND_OK (4)
|
||||
|
||||
enum
|
||||
{
|
||||
padOption = 0,
|
||||
subnetMask = 1,
|
||||
timerOffset = 2,
|
||||
routersOnSubnet = 3,
|
||||
/* timeServer = 4,
|
||||
nameServer = 5,*/
|
||||
dns = 6,
|
||||
/*logServer = 7,
|
||||
cookieServer = 8,
|
||||
lprServer = 9,
|
||||
impressServer = 10,
|
||||
resourceLocationServer = 11,*/
|
||||
hostName = 12,
|
||||
/*bootFileSize = 13,
|
||||
meritDumpFile = 14,*/
|
||||
domainName = 15,
|
||||
/*swapServer = 16,
|
||||
rootPath = 17,
|
||||
extentionsPath = 18,
|
||||
IPforwarding = 19,
|
||||
nonLocalSourceRouting = 20,
|
||||
policyFilter = 21,
|
||||
maxDgramReasmSize = 22,
|
||||
defaultIPTTL = 23,
|
||||
pathMTUagingTimeout = 24,
|
||||
pathMTUplateauTable = 25,
|
||||
ifMTU = 26,
|
||||
allSubnetsLocal = 27,
|
||||
broadcastAddr = 28,
|
||||
performMaskDiscovery = 29,
|
||||
maskSupplier = 30,
|
||||
performRouterDiscovery = 31,
|
||||
routerSolicitationAddr = 32,
|
||||
staticRoute = 33,
|
||||
trailerEncapsulation = 34,
|
||||
arpCacheTimeout = 35,
|
||||
ethernetEncapsulation = 36,
|
||||
tcpDefaultTTL = 37,
|
||||
tcpKeepaliveInterval = 38,
|
||||
tcpKeepaliveGarbage = 39,
|
||||
nisDomainName = 40,
|
||||
nisServers = 41,
|
||||
ntpServers = 42,
|
||||
vendorSpecificInfo = 43,
|
||||
netBIOSnameServer = 44,
|
||||
netBIOSdgramDistServer = 45,
|
||||
netBIOSnodeType = 46,
|
||||
netBIOSscope = 47,
|
||||
xFontServer = 48,
|
||||
xDisplayManager = 49,*/
|
||||
dhcpRequestedIPaddr = 50,
|
||||
dhcpIPaddrLeaseTime = 51,
|
||||
/*dhcpOptionOverload = 52,*/
|
||||
dhcpMessageType = 53,
|
||||
dhcpServerIdentifier = 54,
|
||||
dhcpParamRequest = 55,
|
||||
/*dhcpMsg = 56,
|
||||
dhcpMaxMsgSize = 57,*/
|
||||
dhcpT1value = 58,
|
||||
dhcpT2value = 59,
|
||||
/*dhcpClassIdentifier = 60,*/
|
||||
dhcpClientIdentifier = 61,
|
||||
endOption = 255
|
||||
};
|
||||
|
||||
typedef struct __attribute__((packed)) _RIP_MSG_FIXED
|
||||
{
|
||||
uint8_t op;
|
||||
uint8_t htype;
|
||||
uint8_t hlen;
|
||||
uint8_t hops;
|
||||
uint32_t xid;
|
||||
uint16_t secs;
|
||||
uint16_t flags;
|
||||
uint8_t ciaddr[4];
|
||||
uint8_t yiaddr[4];
|
||||
uint8_t siaddr[4];
|
||||
uint8_t giaddr[4];
|
||||
uint8_t chaddr[6];
|
||||
}RIP_MSG_FIXED;
|
||||
|
||||
class DhcpClass {
|
||||
private:
|
||||
uint32_t _dhcpInitialTransactionId;
|
||||
uint32_t _dhcpTransactionId;
|
||||
uint8_t _dhcpMacAddr[6];
|
||||
uint8_t _dhcpLocalIp[4];
|
||||
uint8_t _dhcpSubnetMask[4];
|
||||
uint8_t _dhcpGatewayIp[4];
|
||||
uint8_t _dhcpDhcpServerIp[4];
|
||||
uint8_t _dhcpDnsServerIp[4];
|
||||
uint32_t _dhcpLeaseTime;
|
||||
uint32_t _dhcpT1, _dhcpT2;
|
||||
signed long _renewInSec;
|
||||
signed long _rebindInSec;
|
||||
signed long _lastCheck;
|
||||
unsigned long _timeout;
|
||||
unsigned long _responseTimeout;
|
||||
unsigned long _secTimeout;
|
||||
uint8_t _dhcp_state;
|
||||
EthernetUDP _dhcpUdpSocket;
|
||||
|
||||
int request_DHCP_lease();
|
||||
void reset_DHCP_lease();
|
||||
void presend_DHCP();
|
||||
void send_DHCP_MESSAGE(uint8_t, uint16_t);
|
||||
void printByte(char *, uint8_t);
|
||||
|
||||
uint8_t parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId);
|
||||
public:
|
||||
IPAddress getLocalIp();
|
||||
IPAddress getSubnetMask();
|
||||
IPAddress getGatewayIp();
|
||||
IPAddress getDhcpServerIp();
|
||||
IPAddress getDnsServerIp();
|
||||
|
||||
int beginWithDHCP(uint8_t *, unsigned long timeout = 60000, unsigned long responseTimeout = 4000);
|
||||
int checkLease();
|
||||
};
|
||||
|
||||
#endif
|
||||
// DHCP Library v0.3 - April 25, 2009
|
||||
// Author: Jordan Terrell - blog.jordanterrell.com
|
||||
|
||||
#ifndef Dhcp_h
|
||||
#define Dhcp_h
|
||||
|
||||
#include "EthernetUdp.h"
|
||||
|
||||
/* DHCP state machine. */
|
||||
#define STATE_DHCP_START 0
|
||||
#define STATE_DHCP_DISCOVER 1
|
||||
#define STATE_DHCP_REQUEST 2
|
||||
#define STATE_DHCP_LEASED 3
|
||||
#define STATE_DHCP_REREQUEST 4
|
||||
#define STATE_DHCP_RELEASE 5
|
||||
|
||||
#define DHCP_FLAGSBROADCAST 0x8000
|
||||
|
||||
/* UDP port numbers for DHCP */
|
||||
#define DHCP_SERVER_PORT 67 /* from server to client */
|
||||
#define DHCP_CLIENT_PORT 68 /* from client to server */
|
||||
|
||||
/* DHCP message OP code */
|
||||
#define DHCP_BOOTREQUEST 1
|
||||
#define DHCP_BOOTREPLY 2
|
||||
|
||||
/* DHCP message type */
|
||||
#define DHCP_DISCOVER 1
|
||||
#define DHCP_OFFER 2
|
||||
#define DHCP_REQUEST 3
|
||||
#define DHCP_DECLINE 4
|
||||
#define DHCP_ACK 5
|
||||
#define DHCP_NAK 6
|
||||
#define DHCP_RELEASE 7
|
||||
#define DHCP_INFORM 8
|
||||
|
||||
#define DHCP_HTYPE10MB 1
|
||||
#define DHCP_HTYPE100MB 2
|
||||
|
||||
#define DHCP_HLENETHERNET 6
|
||||
#define DHCP_HOPS 0
|
||||
#define DHCP_SECS 0
|
||||
|
||||
#define MAGIC_COOKIE 0x63825363
|
||||
#define MAX_DHCP_OPT 16
|
||||
|
||||
#define HOST_NAME "WIZnet"
|
||||
#define DEFAULT_LEASE (900) //default lease time in seconds
|
||||
|
||||
#define DHCP_CHECK_NONE (0)
|
||||
#define DHCP_CHECK_RENEW_FAIL (1)
|
||||
#define DHCP_CHECK_RENEW_OK (2)
|
||||
#define DHCP_CHECK_REBIND_FAIL (3)
|
||||
#define DHCP_CHECK_REBIND_OK (4)
|
||||
|
||||
enum
|
||||
{
|
||||
padOption = 0,
|
||||
subnetMask = 1,
|
||||
timerOffset = 2,
|
||||
routersOnSubnet = 3,
|
||||
/* timeServer = 4,
|
||||
nameServer = 5,*/
|
||||
dns = 6,
|
||||
/* logServer = 7,
|
||||
cookieServer = 8,
|
||||
lprServer = 9,
|
||||
impressServer = 10,
|
||||
resourceLocationServer = 11,*/
|
||||
hostName = 12,
|
||||
/* bootFileSize = 13,
|
||||
meritDumpFile = 14,*/
|
||||
domainName = 15,
|
||||
/* swapServer = 16,
|
||||
rootPath = 17,
|
||||
extentionsPath = 18,
|
||||
IPforwarding = 19,
|
||||
nonLocalSourceRouting = 20,
|
||||
policyFilter = 21,
|
||||
maxDgramReasmSize = 22,
|
||||
defaultIPTTL = 23,
|
||||
pathMTUagingTimeout = 24,
|
||||
pathMTUplateauTable = 25,
|
||||
ifMTU = 26,
|
||||
allSubnetsLocal = 27,
|
||||
broadcastAddr = 28,
|
||||
performMaskDiscovery = 29,
|
||||
maskSupplier = 30,
|
||||
performRouterDiscovery = 31,
|
||||
routerSolicitationAddr = 32,
|
||||
staticRoute = 33,
|
||||
trailerEncapsulation = 34,
|
||||
arpCacheTimeout = 35,
|
||||
ethernetEncapsulation = 36,
|
||||
tcpDefaultTTL = 37,
|
||||
tcpKeepaliveInterval = 38,
|
||||
tcpKeepaliveGarbage = 39,
|
||||
nisDomainName = 40,
|
||||
nisServers = 41,
|
||||
ntpServers = 42,
|
||||
vendorSpecificInfo = 43,
|
||||
netBIOSnameServer = 44,
|
||||
netBIOSdgramDistServer = 45,
|
||||
netBIOSnodeType = 46,
|
||||
netBIOSscope = 47,
|
||||
xFontServer = 48,
|
||||
xDisplayManager = 49,*/
|
||||
dhcpRequestedIPaddr = 50,
|
||||
dhcpIPaddrLeaseTime = 51,
|
||||
/*dhcpOptionOverload = 52,*/
|
||||
dhcpMessageType = 53,
|
||||
dhcpServerIdentifier = 54,
|
||||
dhcpParamRequest = 55,
|
||||
/* dhcpMsg = 56,
|
||||
dhcpMaxMsgSize = 57,*/
|
||||
dhcpT1value = 58,
|
||||
dhcpT2value = 59,
|
||||
/*dhcpClassIdentifier = 60,*/
|
||||
dhcpClientIdentifier = 61,
|
||||
endOption = 255
|
||||
};
|
||||
|
||||
typedef struct __attribute__((packed)) _RIP_MSG_FIXED
|
||||
{
|
||||
uint8_t op;
|
||||
uint8_t htype;
|
||||
uint8_t hlen;
|
||||
uint8_t hops;
|
||||
uint32_t xid;
|
||||
uint16_t secs;
|
||||
uint16_t flags;
|
||||
uint8_t ciaddr[4];
|
||||
uint8_t yiaddr[4];
|
||||
uint8_t siaddr[4];
|
||||
uint8_t giaddr[4];
|
||||
uint8_t chaddr[6];
|
||||
} RIP_MSG_FIXED;
|
||||
|
||||
class DhcpClass
|
||||
{
|
||||
private:
|
||||
uint32_t _dhcpInitialTransactionId;
|
||||
uint32_t _dhcpTransactionId;
|
||||
uint8_t _dhcpMacAddr[6];
|
||||
uint8_t _dhcpLocalIp[4];
|
||||
uint8_t _dhcpSubnetMask[4];
|
||||
uint8_t _dhcpGatewayIp[4];
|
||||
uint8_t _dhcpDhcpServerIp[4];
|
||||
uint8_t _dhcpDnsServerIp[4];
|
||||
uint32_t _dhcpLeaseTime;
|
||||
uint32_t _dhcpT1, _dhcpT2;
|
||||
signed long _renewInSec;
|
||||
signed long _rebindInSec;
|
||||
signed long _lastCheck;
|
||||
unsigned long _timeout;
|
||||
unsigned long _responseTimeout;
|
||||
unsigned long _secTimeout;
|
||||
uint8_t _dhcp_state;
|
||||
EthernetUDP _dhcpUdpSocket;
|
||||
|
||||
int request_DHCP_lease();
|
||||
void reset_DHCP_lease();
|
||||
void presend_DHCP();
|
||||
void send_DHCP_MESSAGE(uint8_t, uint16_t);
|
||||
void printByte(char *, uint8_t);
|
||||
|
||||
uint8_t parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId);
|
||||
public:
|
||||
IPAddress getLocalIp();
|
||||
IPAddress getSubnetMask();
|
||||
IPAddress getGatewayIp();
|
||||
IPAddress getDhcpServerIp();
|
||||
IPAddress getDnsServerIp();
|
||||
|
||||
int beginWithDHCP(uint8_t *, unsigned long timeout = 60000, unsigned long responseTimeout = 4000);
|
||||
int checkLease();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -58,9 +58,9 @@ void DNSClient::begin(const IPAddress& aDNSServer)
|
||||
int DNSClient::inet_aton_ethlib(const char* aIPAddrString, IPAddress& aResult)
|
||||
{
|
||||
// See if we've been given a valid IP address
|
||||
const char* p =aIPAddrString;
|
||||
const char* p = aIPAddrString;
|
||||
while (*p &&
|
||||
( (*p == '.') || (*p >= '0') || (*p <= '9') ))
|
||||
((*p == '.') || (*p >= '0') || (*p <= '9')))
|
||||
{
|
||||
p++;
|
||||
}
|
||||
@ -69,8 +69,8 @@ int DNSClient::inet_aton_ethlib(const char* aIPAddrString, IPAddress& aResult)
|
||||
{
|
||||
// It's looking promising, we haven't found any invalid characters
|
||||
p = aIPAddrString;
|
||||
int segment =0;
|
||||
int segmentValue =0;
|
||||
int segment = 0;
|
||||
int segmentValue = 0;
|
||||
while (*p && (segment < 4))
|
||||
{
|
||||
if (*p == '.')
|
||||
@ -91,7 +91,7 @@ int DNSClient::inet_aton_ethlib(const char* aIPAddrString, IPAddress& aResult)
|
||||
else
|
||||
{
|
||||
// Next digit
|
||||
segmentValue = (segmentValue*10)+(*p - '0');
|
||||
segmentValue = (segmentValue * 10) + (*p - '0');
|
||||
}
|
||||
p++;
|
||||
}
|
||||
@ -117,7 +117,7 @@ int DNSClient::inet_aton_ethlib(const char* aIPAddrString, IPAddress& aResult)
|
||||
|
||||
int DNSClient::getHostByName(const char* aHostname, IPAddress& aResult)
|
||||
{
|
||||
int ret =0;
|
||||
int ret = 0;
|
||||
|
||||
// See if it's a numeric IP address
|
||||
if (inet_aton_ethlib(aHostname, aResult))
|
||||
@ -131,13 +131,13 @@ int DNSClient::getHostByName(const char* aHostname, IPAddress& aResult)
|
||||
{
|
||||
return INVALID_SERVER;
|
||||
}
|
||||
|
||||
|
||||
// Find a socket to use
|
||||
if (iUdp.begin(1024+(millis() & 0xF)) == 1)
|
||||
if (iUdp.begin(1024 + (millis() & 0xF)) == 1)
|
||||
{
|
||||
// Try up to three times
|
||||
int retries = 0;
|
||||
// while ((retries < 3) && (ret <= 0))
|
||||
// while ((retries < 3) && (ret <= 0))
|
||||
{
|
||||
// Send DNS request
|
||||
ret = iUdp.beginPacket(iDNSServer, DNS_PORT);
|
||||
@ -213,28 +213,28 @@ uint16_t DNSClient::BuildRequest(const char* aName)
|
||||
iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer));
|
||||
|
||||
// Build question
|
||||
const char* start =aName;
|
||||
const char* end =start;
|
||||
const char* start = aName;
|
||||
const char* end = start;
|
||||
uint8_t len;
|
||||
// Run through the name being requested
|
||||
while (*end)
|
||||
{
|
||||
// Find out how long this section of the name is
|
||||
end = start;
|
||||
while (*end && (*end != '.') )
|
||||
while (*end && (*end != '.'))
|
||||
{
|
||||
end++;
|
||||
}
|
||||
|
||||
if (end-start > 0)
|
||||
if (end - start > 0)
|
||||
{
|
||||
// Write out the size of this section
|
||||
len = end-start;
|
||||
len = end - start;
|
||||
iUdp.write(&len, sizeof(len));
|
||||
// And then write out the section
|
||||
iUdp.write((uint8_t*)start, end-start);
|
||||
iUdp.write((uint8_t*)start, end - start);
|
||||
}
|
||||
start = end+1;
|
||||
start = end + 1;
|
||||
}
|
||||
|
||||
// We've got to the end of the question name, so
|
||||
@ -257,10 +257,12 @@ uint16_t DNSClient::ProcessResponse(uint16_t aTimeout, IPAddress& aAddress)
|
||||
uint32_t startTime = millis();
|
||||
|
||||
// Wait for a response packet
|
||||
while(iUdp.parsePacket() <= 0)
|
||||
while (iUdp.parsePacket() <= 0)
|
||||
{
|
||||
if((millis() - startTime) > aTimeout)
|
||||
if ((millis() - startTime) > aTimeout)
|
||||
{
|
||||
return TIMED_OUT;
|
||||
}
|
||||
delay(50);
|
||||
}
|
||||
|
||||
@ -268,8 +270,8 @@ uint16_t DNSClient::ProcessResponse(uint16_t aTimeout, IPAddress& aAddress)
|
||||
// Read the UDP header
|
||||
uint8_t header[DNS_HEADER_SIZE]; // Enough space to reuse for the DNS header
|
||||
// Check that it's a response from the right server and the right port
|
||||
if ( (iDNSServer != iUdp.remoteIP()) ||
|
||||
(iUdp.remotePort() != DNS_PORT) )
|
||||
if ((iDNSServer != iUdp.remoteIP()) ||
|
||||
(iUdp.remotePort() != DNS_PORT))
|
||||
{
|
||||
// It's not from who we expected
|
||||
return INVALID_SERVER;
|
||||
@ -287,8 +289,8 @@ uint16_t DNSClient::ProcessResponse(uint16_t aTimeout, IPAddress& aAddress)
|
||||
uint16_t header_flags = htons(staging);
|
||||
memcpy(&staging, &header[0], sizeof(uint16_t));
|
||||
// Check that it's a response to this request
|
||||
if ( ( iRequestId != staging ) ||
|
||||
((header_flags & QUERY_RESPONSE_MASK) != (uint16_t)RESPONSE_FLAG) )
|
||||
if ((iRequestId != staging) ||
|
||||
((header_flags & QUERY_RESPONSE_MASK) != (uint16_t)RESPONSE_FLAG))
|
||||
{
|
||||
// Mark the entire packet as read
|
||||
iUdp.flush();
|
||||
@ -296,7 +298,7 @@ uint16_t DNSClient::ProcessResponse(uint16_t aTimeout, IPAddress& aAddress)
|
||||
}
|
||||
// Check for any errors in the response (or in our request)
|
||||
// although we don't do anything to get round these
|
||||
if ( (header_flags & TRUNCATION_FLAG) || (header_flags & RESP_MASK) )
|
||||
if ((header_flags & TRUNCATION_FLAG) || (header_flags & RESP_MASK))
|
||||
{
|
||||
// Mark the entire packet as read
|
||||
iUdp.flush();
|
||||
@ -306,7 +308,7 @@ uint16_t DNSClient::ProcessResponse(uint16_t aTimeout, IPAddress& aAddress)
|
||||
// And make sure we've got (at least) one answer
|
||||
memcpy(&staging, &header[6], sizeof(uint16_t));
|
||||
uint16_t answerCount = htons(staging);
|
||||
if (answerCount == 0 )
|
||||
if (answerCount == 0)
|
||||
{
|
||||
// Mark the entire packet as read
|
||||
iUdp.flush();
|
||||
@ -315,7 +317,7 @@ uint16_t DNSClient::ProcessResponse(uint16_t aTimeout, IPAddress& aAddress)
|
||||
|
||||
// Skip over any questions
|
||||
memcpy(&staging, &header[4], sizeof(uint16_t));
|
||||
for (uint16_t i =0; i < htons(staging); i++)
|
||||
for (uint16_t i = 0; i < htons(staging); i++)
|
||||
{
|
||||
// Skip over the name
|
||||
uint8_t len;
|
||||
@ -326,7 +328,7 @@ uint16_t DNSClient::ProcessResponse(uint16_t aTimeout, IPAddress& aAddress)
|
||||
{
|
||||
// Don't need to actually read the data out for the string, just
|
||||
// advance ptr to beyond it
|
||||
while(len--)
|
||||
while (len--)
|
||||
{
|
||||
iUdp.read(); // we don't care about the returned byte
|
||||
}
|
||||
@ -334,7 +336,7 @@ uint16_t DNSClient::ProcessResponse(uint16_t aTimeout, IPAddress& aAddress)
|
||||
} while (len != 0);
|
||||
|
||||
// Now jump over the type and class
|
||||
for (int i =0; i < 4; i++)
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
iUdp.read(); // we don't care about the returned byte
|
||||
}
|
||||
@ -345,7 +347,7 @@ uint16_t DNSClient::ProcessResponse(uint16_t aTimeout, IPAddress& aAddress)
|
||||
// type A answer) and some authority and additional resource records but
|
||||
// we're going to ignore all of them.
|
||||
|
||||
for (uint16_t i =0; i < answerCount; i++)
|
||||
for (uint16_t i = 0; i < answerCount; i++)
|
||||
{
|
||||
// Skip the name
|
||||
uint8_t len;
|
||||
@ -360,7 +362,7 @@ uint16_t DNSClient::ProcessResponse(uint16_t aTimeout, IPAddress& aAddress)
|
||||
// And it's got a length
|
||||
// Don't need to actually read the data out for the string,
|
||||
// just advance ptr to beyond it
|
||||
while(len--)
|
||||
while (len--)
|
||||
{
|
||||
iUdp.read(); // we don't care about the returned byte
|
||||
}
|
||||
@ -388,7 +390,7 @@ uint16_t DNSClient::ProcessResponse(uint16_t aTimeout, IPAddress& aAddress)
|
||||
iUdp.read((uint8_t*)&answerClass, sizeof(answerClass));
|
||||
|
||||
// Ignore the Time-To-Live as we don't do any caching
|
||||
for (int i =0; i < TTL_SIZE; i++)
|
||||
for (int i = 0; i < TTL_SIZE; i++)
|
||||
{
|
||||
iUdp.read(); // we don't care about the returned byte
|
||||
}
|
||||
@ -397,7 +399,7 @@ uint16_t DNSClient::ProcessResponse(uint16_t aTimeout, IPAddress& aAddress)
|
||||
// Don't need header_flags anymore, so we can reuse it here
|
||||
iUdp.read((uint8_t*)&header_flags, sizeof(header_flags));
|
||||
|
||||
if ( (htons(answerType) == TYPE_A) && (htons(answerClass) == CLASS_IN) )
|
||||
if ((htons(answerType) == TYPE_A) && (htons(answerClass) == CLASS_IN))
|
||||
{
|
||||
if (htons(header_flags) != 4)
|
||||
{
|
||||
@ -412,7 +414,7 @@ uint16_t DNSClient::ProcessResponse(uint16_t aTimeout, IPAddress& aAddress)
|
||||
else
|
||||
{
|
||||
// This isn't an answer type we're after, move onto the next one
|
||||
for (uint16_t i =0; i < htons(header_flags); i++)
|
||||
for (uint16_t i = 0; i < htons(header_flags); i++)
|
||||
{
|
||||
iUdp.read(); // we don't care about the returned byte
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user