1
0
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:
Allman-astyler
2019-05-13 16:41:34 +02:00
committed by david gauchard
parent 625c3a62c4
commit 98125f8860
255 changed files with 51238 additions and 42984 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
};

View File

@ -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)

View File

@ -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)

View File

@ -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);
}
}
}
}

View File

@ -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;

View File

@ -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

View File

@ -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;
};

View File

@ -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();
}

View File

@ -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;

View File

@ -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)

View File

@ -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();

View File

@ -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 = &current_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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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
};

View File

@ -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>

View File

@ -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();
}
};

View File

@ -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;
};
};

View File

@ -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);
}
};

View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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" }
};
}

View File

@ -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

View File

@ -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);
};
};

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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("): ");

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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

View File

@ -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_ */

View File

@ -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();
}

View File

@ -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_ */

View File

@ -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

View File

@ -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_ */

View File

@ -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;
}

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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();
}

View File

@ -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

View File

@ -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"

View File

@ -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")));
};

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -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>

View File

@ -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);

View File

@ -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;
};
};

View File

@ -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);
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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);
};

View File

@ -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;

View File

@ -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);

View File

@ -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();
}

View File

@ -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 (&current_iphdr_dest)
#define TEMPDSTADDR (&current_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);
}

View File

@ -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;
};

View File

@ -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);
/** @} */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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)
{ }

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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