mirror of
https://github.com/esp8266/Arduino.git
synced 2025-06-06 05:21:22 +03:00
lwIP on ethernet: examples (#8395)
* ethernet: examples * remove duplicate * styling * fix comment restyle + comment eth.setdefault() * comment and add comments about eth.setDefault() * update comments when using interface::setDefault() * repair bad merge * fix default interface case * factorize * change comment
This commit is contained in:
parent
f5ef02d643
commit
5f2af1945b
@ -59,7 +59,17 @@ public:
|
|||||||
return IPAddress(ip4_addr_get_u32(ip_2_ip4(&_netif.gw)));
|
return IPAddress(ip4_addr_get_u32(ip_2_ip4(&_netif.gw)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDefault();
|
// 1. Currently when no default is set, esp8266-Arduino uses the first
|
||||||
|
// DHCP client interface receiving a valid address and gateway to
|
||||||
|
// become the new lwIP default interface.
|
||||||
|
// 2. Otherwise - when using static addresses - lwIP for every packets by
|
||||||
|
// defaults selects automatically the best suited output interface
|
||||||
|
// matching the destination address. If several interfaces match,
|
||||||
|
// the first one is picked. On esp8266/Arduno: WiFi interfaces are
|
||||||
|
// checked first.
|
||||||
|
// 3. Or, use `::setDefault(true)` to force using this interface's gateway
|
||||||
|
// as default router.
|
||||||
|
void setDefault(bool deflt = true);
|
||||||
|
|
||||||
// true if interface has a valid IPv4 address
|
// true if interface has a valid IPv4 address
|
||||||
bool connected()
|
bool connected()
|
||||||
@ -67,12 +77,18 @@ public:
|
|||||||
return !!ip4_addr_get_u32(ip_2_ip4(&_netif.ip_addr));
|
return !!ip4_addr_get_u32(ip_2_ip4(&_netif.ip_addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool routable()
|
||||||
|
{
|
||||||
|
return !ip_addr_isany(&_netif.gw);
|
||||||
|
}
|
||||||
|
|
||||||
// ESP8266WiFi API compatibility
|
// ESP8266WiFi API compatibility
|
||||||
|
|
||||||
wl_status_t status();
|
wl_status_t status();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
err_t netif_init();
|
err_t netif_init();
|
||||||
|
void check_route();
|
||||||
void netif_status_callback();
|
void netif_status_callback();
|
||||||
|
|
||||||
static err_t netif_init_s(netif* netif);
|
static err_t netif_init_s(netif* netif);
|
||||||
@ -184,10 +200,10 @@ boolean LwipIntfDev<RawDev>::begin(const uint8_t* macAddress, const uint16_t mtu
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_netif.flags |= NETIF_FLAG_UP;
|
|
||||||
|
|
||||||
if (localIP().v4() == 0)
|
if (localIP().v4() == 0)
|
||||||
{
|
{
|
||||||
|
// IP not set, starting DHCP
|
||||||
|
_netif.flags |= NETIF_FLAG_UP;
|
||||||
switch (dhcp_start(&_netif))
|
switch (dhcp_start(&_netif))
|
||||||
{
|
{
|
||||||
case ERR_OK:
|
case ERR_OK:
|
||||||
@ -201,6 +217,12 @@ boolean LwipIntfDev<RawDev>::begin(const uint8_t* macAddress, const uint16_t mtu
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// IP is set, static config
|
||||||
|
netif_set_link_up(&_netif);
|
||||||
|
netif_set_up(&_netif);
|
||||||
|
}
|
||||||
|
|
||||||
_started = true;
|
_started = true;
|
||||||
|
|
||||||
@ -301,17 +323,26 @@ err_t LwipIntfDev<RawDev>::netif_init()
|
|||||||
template<class RawDev>
|
template<class RawDev>
|
||||||
void LwipIntfDev<RawDev>::netif_status_callback()
|
void LwipIntfDev<RawDev>::netif_status_callback()
|
||||||
{
|
{
|
||||||
|
check_route();
|
||||||
if (connected())
|
if (connected())
|
||||||
{
|
{
|
||||||
if (_default || (netif_default == nullptr && !ip_addr_isany(&_netif.gw)))
|
|
||||||
{
|
|
||||||
// on user request,
|
|
||||||
// or if there is no current default interface, but a gateway is valid
|
|
||||||
netif_set_default(&_netif);
|
|
||||||
}
|
|
||||||
sntp_stop();
|
sntp_stop();
|
||||||
sntp_init();
|
sntp_init();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class RawDev>
|
||||||
|
void LwipIntfDev<RawDev>::check_route()
|
||||||
|
{
|
||||||
|
if (connected())
|
||||||
|
{
|
||||||
|
if (_default || (netif_default == nullptr && routable()))
|
||||||
|
{
|
||||||
|
// on user request,
|
||||||
|
// or if there is no current default interface, but our gateway is valid
|
||||||
|
netif_set_default(&_netif);
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (netif_default == &_netif)
|
else if (netif_default == &_netif)
|
||||||
{
|
{
|
||||||
netif_set_default(nullptr);
|
netif_set_default(nullptr);
|
||||||
@ -386,13 +417,10 @@ err_t LwipIntfDev<RawDev>::handlePackets()
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class RawDev>
|
template<class RawDev>
|
||||||
void LwipIntfDev<RawDev>::setDefault()
|
void LwipIntfDev<RawDev>::setDefault(bool deflt)
|
||||||
{
|
{
|
||||||
_default = true;
|
_default = deflt;
|
||||||
if (connected())
|
check_route();
|
||||||
{
|
|
||||||
netif_set_default(&_netif);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // _LWIPINTFDEV_H
|
#endif // _LWIPINTFDEV_H
|
||||||
|
@ -1766,11 +1766,13 @@ namespace MDNSImplementation
|
|||||||
stcMDNS_RRAttributes attributes(DNS_RRTYPE_AAAA,
|
stcMDNS_RRAttributes attributes(DNS_RRTYPE_AAAA,
|
||||||
((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0)
|
((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0)
|
||||||
| DNS_RRCLASS_IN)); // Cache flush? & INternet
|
| DNS_RRCLASS_IN)); // Cache flush? & INternet
|
||||||
bool bResult = ((_writeMDNSHostDomain(m_pcHostname, false, p_rSendParameter)) && // esp8266.local
|
bool bResult
|
||||||
(_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS
|
= ((_writeMDNSHostDomain(m_pcHostname, false, p_rSendParameter)) && // esp8266.local
|
||||||
(_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter)) && // TTL
|
(_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS
|
||||||
(_write16(MDNS_IP6_SIZE, p_rSendParameter)) && // RDLength
|
(_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter))
|
||||||
(false /*TODO: IP6 version of: _udpAppendBuffer((uint32_t)p_IPAddress, MDNS_IP4_SIZE)*/)); // RData
|
&& // TTL
|
||||||
|
(_write16(MDNS_IP6_SIZE, p_rSendParameter)) && // RDLength
|
||||||
|
(false /*TODO: IP6 version of: _udpAppendBuffer((uint32_t)p_IPAddress, MDNS_IP4_SIZE)*/)); // RData
|
||||||
|
|
||||||
DEBUG_EX_ERR(if (!bResult) {
|
DEBUG_EX_ERR(if (!bResult) {
|
||||||
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_AAAA: FAILED!\n"));
|
DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_AAAA: FAILED!\n"));
|
||||||
@ -1855,7 +1857,7 @@ namespace MDNSImplementation
|
|||||||
p_rSendParameter.m_u16Offset))
|
p_rSendParameter.m_u16Offset))
|
||||||
&& (_writeMDNSRRDomain(hostDomain,
|
&& (_writeMDNSRRDomain(hostDomain,
|
||||||
p_rSendParameter))) // Host, eg. esp8266.local
|
p_rSendParameter))) // Host, eg. esp8266.local
|
||||||
// Cache available for domain
|
// Cache available for domain
|
||||||
: ((MDNS_DOMAIN_COMPRESS_MARK
|
: ((MDNS_DOMAIN_COMPRESS_MARK
|
||||||
> ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK))
|
> ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK))
|
||||||
&& // Valid offset
|
&& // Valid offset
|
||||||
|
89
libraries/lwIP_Ethernet/examples/EthClient/EthClient.ino
Normal file
89
libraries/lwIP_Ethernet/examples/EthClient/EthClient.ino
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
This sketch establishes a TCP connection to a "quote of the day" service.
|
||||||
|
It sends a "hello" message, and then prints received data.
|
||||||
|
|
||||||
|
This is Ethernet version of:
|
||||||
|
https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <LwipEthernet.h>
|
||||||
|
|
||||||
|
Wiznet5500lwIP eth(/*SS*/ 16); // <== adapt to your hardware
|
||||||
|
|
||||||
|
const char* host = "djxmmx.net";
|
||||||
|
const uint16_t port = 17;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
Serial.println("\nEthernet\n");
|
||||||
|
|
||||||
|
// 1. Currently when no default is set, esp8266-Arduino uses the first
|
||||||
|
// DHCP client interface receiving a valid address and gateway to
|
||||||
|
// become the new lwIP default interface.
|
||||||
|
// 2. Otherwise - when using static addresses - lwIP for every packets by
|
||||||
|
// defaults selects automatically the best suited output interface
|
||||||
|
// matching the destination address. If several interfaces match,
|
||||||
|
// the first one is picked. On esp8266/Arduno: WiFi interfaces are
|
||||||
|
// checked first.
|
||||||
|
// 3. Or, use `::setDefault()` to force routing through this interface.
|
||||||
|
// eth.setDefault(); // default route set through this interface
|
||||||
|
|
||||||
|
if (!ethInitDHCP(eth)) {
|
||||||
|
Serial.printf("no hardware found\n");
|
||||||
|
while (1) {
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!eth.connected()) {
|
||||||
|
Serial.printf(".");
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.printf("Ethernet: IP Address: %s\n",
|
||||||
|
eth.localIP().toString().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
Serial.print("connecting to ");
|
||||||
|
Serial.print(host);
|
||||||
|
Serial.print(':');
|
||||||
|
Serial.println(port);
|
||||||
|
|
||||||
|
// Use WiFiClient class to create TCP connections
|
||||||
|
// (this class could have been named TCPClient)
|
||||||
|
WiFiClient client;
|
||||||
|
if (!client.connect(host, port)) {
|
||||||
|
Serial.println("connection failed");
|
||||||
|
delay(5000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will send a string to the server
|
||||||
|
Serial.println("sending data to server");
|
||||||
|
if (client.connected()) { client.println("hello from ESP8266"); }
|
||||||
|
|
||||||
|
// wait for data to be available
|
||||||
|
unsigned long timeout = millis();
|
||||||
|
while (client.available() == 0) {
|
||||||
|
if (millis() - timeout > 5000) {
|
||||||
|
Serial.println(">>> Client Timeout !");
|
||||||
|
client.stop();
|
||||||
|
delay(60000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read all the lines of the reply from server and print them to Serial
|
||||||
|
Serial.println("receiving from remote server");
|
||||||
|
client.sendAll(Serial); // this peer closes once all data are sent
|
||||||
|
|
||||||
|
// Close the connection
|
||||||
|
Serial.println();
|
||||||
|
Serial.println("closing connection");
|
||||||
|
client.stop();
|
||||||
|
|
||||||
|
delay(300000); // execute once every 5 minutes, don't flood remote service
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
This sketch establishes a TCP connection to a "quote of the day" service.
|
||||||
|
It sends a "hello" message, and then prints received data.
|
||||||
|
|
||||||
|
This is Ethernet version of:
|
||||||
|
https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <LwipEthernet.h>
|
||||||
|
|
||||||
|
#define LOCAL_IP IPAddress(192, 168, 0, 233)
|
||||||
|
#define LOCAL_GW IPAddress(192, 168, 0, 254) // <== adapt to your network
|
||||||
|
#define LOCAL_MASK IPAddress(255, 255, 255, 0)
|
||||||
|
#define DNS IPAddress(8, 8, 8, 8)
|
||||||
|
|
||||||
|
Wiznet5500lwIP eth(/*SS*/ 16); // <== adapt to your hardware
|
||||||
|
|
||||||
|
const char* host = "djxmmx.net";
|
||||||
|
const uint16_t port = 17;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
Serial.println("\nEthernet\n");
|
||||||
|
|
||||||
|
// 1. Currently when no default is set, esp8266-Arduino uses the first
|
||||||
|
// DHCP client interface receiving a valid address and gateway to
|
||||||
|
// become the new lwIP default interface.
|
||||||
|
// 2. Otherwise - when using static addresses - lwIP for every packets by
|
||||||
|
// defaults selects automatically the best suited output interface
|
||||||
|
// matching the destination address. If several interfaces match,
|
||||||
|
// the first one is picked. On esp8266/Arduno: WiFi interfaces are
|
||||||
|
// checked first.
|
||||||
|
// 3. Or, use `::setDefault()` to force routing through this interface.
|
||||||
|
// eth.setDefault(true); // default route set through this interface
|
||||||
|
|
||||||
|
if (!ethInitStatic(eth, LOCAL_IP, LOCAL_GW, LOCAL_MASK, DNS)) {
|
||||||
|
// enabling debug message will show the real cause
|
||||||
|
Serial.printf("no hardware found or bad network configuration\n");
|
||||||
|
while (1) {
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.printf("Ethernet: IP Address: %s\n",
|
||||||
|
eth.localIP().toString().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
Serial.print("connecting to ");
|
||||||
|
Serial.print(host);
|
||||||
|
Serial.print(':');
|
||||||
|
Serial.println(port);
|
||||||
|
|
||||||
|
// Use WiFiClient class to create TCP connections
|
||||||
|
// (this class could have been named TCPClient)
|
||||||
|
WiFiClient client;
|
||||||
|
if (!client.connect(host, port)) {
|
||||||
|
Serial.println("connection failed");
|
||||||
|
delay(5000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will send a string to the server
|
||||||
|
Serial.println("sending data to server");
|
||||||
|
if (client.connected()) {
|
||||||
|
client.println("hello from ESP8266");
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for data to be available
|
||||||
|
unsigned long timeout = millis();
|
||||||
|
while (client.available() == 0) {
|
||||||
|
if (millis() - timeout > 5000) {
|
||||||
|
Serial.println(">>> Client Timeout !");
|
||||||
|
client.stop();
|
||||||
|
delay(60000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read all the lines of the reply from server and print them to Serial
|
||||||
|
Serial.println("receiving from remote server");
|
||||||
|
client.sendAll(Serial); // this peer closes once all data are sent
|
||||||
|
|
||||||
|
// Close the connection
|
||||||
|
Serial.println();
|
||||||
|
Serial.println("closing connection");
|
||||||
|
client.stop();
|
||||||
|
|
||||||
|
delay(600000); // execute once every 10 minutes, don't flood remote service
|
||||||
|
}
|
@ -0,0 +1,238 @@
|
|||||||
|
// Example of the different modes of the X.509 validation options
|
||||||
|
// in the WiFiClientBearSSL object
|
||||||
|
//
|
||||||
|
// Mar 2018 by Earle F. Philhower, III
|
||||||
|
// Released to the public domain
|
||||||
|
//
|
||||||
|
// This is Ethernet version of:
|
||||||
|
// https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/examples/BearSSL_Validation/BearSSL_Validation.ino
|
||||||
|
|
||||||
|
#include <LwipEthernet.h>
|
||||||
|
|
||||||
|
Wiznet5500lwIP eth(/*SS*/ 16); // <== adapt to your hardware
|
||||||
|
|
||||||
|
#include <WiFiClientSecure.h>
|
||||||
|
#include <StackThunk.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "certs.h"
|
||||||
|
|
||||||
|
const char *path = "/";
|
||||||
|
|
||||||
|
// Set time via NTP, as required for x.509 validation
|
||||||
|
void setClock() {
|
||||||
|
configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov");
|
||||||
|
|
||||||
|
Serial.print("Waiting for NTP time sync: ");
|
||||||
|
time_t now = time(nullptr);
|
||||||
|
while (now < 8 * 3600 * 2) {
|
||||||
|
delay(500);
|
||||||
|
Serial.print(".");
|
||||||
|
now = time(nullptr);
|
||||||
|
}
|
||||||
|
Serial.println("");
|
||||||
|
struct tm timeinfo;
|
||||||
|
gmtime_r(&now, &timeinfo);
|
||||||
|
Serial.print("Current time: ");
|
||||||
|
Serial.print(asctime(&timeinfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try and connect using a WiFiClientBearSSL to specified host:port and dump HTTP response
|
||||||
|
void fetchURL(BearSSL::WiFiClientSecure *client, const char *host, const uint16_t port, const char *path) {
|
||||||
|
if (!path) {
|
||||||
|
path = "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP.resetFreeContStack();
|
||||||
|
uint32_t freeStackStart = ESP.getFreeContStack();
|
||||||
|
Serial.printf("Trying: %s:443...", host);
|
||||||
|
client->connect(host, port);
|
||||||
|
if (!client->connected()) {
|
||||||
|
Serial.printf("*** Can't connect. ***\n-------\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Serial.printf("Connected!\n-------\n");
|
||||||
|
client->write("GET ");
|
||||||
|
client->write(path);
|
||||||
|
client->write(" HTTP/1.0\r\nHost: ");
|
||||||
|
client->write(host);
|
||||||
|
client->write("\r\nUser-Agent: ESP8266\r\n");
|
||||||
|
client->write("\r\n");
|
||||||
|
uint32_t to = millis() + 5000;
|
||||||
|
if (client->connected()) {
|
||||||
|
do {
|
||||||
|
char tmp[32];
|
||||||
|
memset(tmp, 0, 32);
|
||||||
|
int rlen = client->read((uint8_t *)tmp, sizeof(tmp) - 1);
|
||||||
|
yield();
|
||||||
|
if (rlen < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Only print out first line up to \r, then abort connection
|
||||||
|
char *nl = strchr(tmp, '\r');
|
||||||
|
if (nl) {
|
||||||
|
*nl = 0;
|
||||||
|
Serial.print(tmp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Serial.print(tmp);
|
||||||
|
} while (millis() < to);
|
||||||
|
}
|
||||||
|
client->stop();
|
||||||
|
uint32_t freeStackEnd = ESP.getFreeContStack();
|
||||||
|
Serial.printf("\nCONT stack used: %d\n", freeStackStart - freeStackEnd);
|
||||||
|
Serial.printf("BSSL stack used: %d\n-------\n\n", stack_thunk_get_max_usage());
|
||||||
|
}
|
||||||
|
|
||||||
|
void fetchNoConfig() {
|
||||||
|
Serial.printf(R"EOF(
|
||||||
|
If there are no CAs or insecure options specified, BearSSL will not connect.
|
||||||
|
Expect the following call to fail as none have been configured.
|
||||||
|
)EOF");
|
||||||
|
BearSSL::WiFiClientSecure client;
|
||||||
|
fetchURL(&client, gitlab_host, gitlab_port, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fetchInsecure() {
|
||||||
|
Serial.printf(R"EOF(
|
||||||
|
This is absolutely *insecure*, but you can tell BearSSL not to check the
|
||||||
|
certificate of the server. In this mode it will accept ANY certificate,
|
||||||
|
which is subject to man-in-the-middle (MITM) attacks.
|
||||||
|
)EOF");
|
||||||
|
BearSSL::WiFiClientSecure client;
|
||||||
|
client.setInsecure();
|
||||||
|
fetchURL(&client, gitlab_host, gitlab_port, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fetchFingerprint() {
|
||||||
|
Serial.printf(R"EOF(
|
||||||
|
The SHA-1 fingerprint of an X.509 certificate can be used to validate it
|
||||||
|
instead of the while certificate. This is not nearly as secure as real
|
||||||
|
X.509 validation, but is better than nothing. Also be aware that these
|
||||||
|
fingerprints will change if anything changes in the certificate chain
|
||||||
|
(i.e. re-generating the certificate for a new end date, any updates to
|
||||||
|
the root authorities, etc.).
|
||||||
|
)EOF");
|
||||||
|
BearSSL::WiFiClientSecure client;
|
||||||
|
client.setFingerprint(fingerprint_gitlab_com);
|
||||||
|
fetchURL(&client, gitlab_host, gitlab_port, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fetchSelfSigned() {
|
||||||
|
Serial.printf(R"EOF(
|
||||||
|
It is also possible to accept *any* self-signed certificate. This is
|
||||||
|
absolutely insecure as anyone can make a self-signed certificate.
|
||||||
|
)EOF");
|
||||||
|
BearSSL::WiFiClientSecure client;
|
||||||
|
Serial.printf("First, try and connect to a badssl.com self-signed website (will fail):\n");
|
||||||
|
fetchURL(&client, "self-signed.badssl.com", 443, "/");
|
||||||
|
Serial.printf("Now we'll enable self-signed certs (will pass)\n");
|
||||||
|
client.allowSelfSignedCerts();
|
||||||
|
fetchURL(&client, "self-signed.badssl.com", 443, "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
void fetchKnownKey() {
|
||||||
|
Serial.printf(R"EOF(
|
||||||
|
The server certificate can be completely ignored and its public key
|
||||||
|
hardcoded in your application. This should be secure as the public key
|
||||||
|
needs to be paired with the private key of the site, which is obviously
|
||||||
|
private and not shared. A MITM without the private key would not be
|
||||||
|
able to establish communications.
|
||||||
|
)EOF");
|
||||||
|
BearSSL::WiFiClientSecure client;
|
||||||
|
BearSSL::PublicKey key(pubkey_gitlab_com);
|
||||||
|
client.setKnownKey(&key);
|
||||||
|
fetchURL(&client, gitlab_host, gitlab_port, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fetchCertAuthority() {
|
||||||
|
Serial.printf(R"EOF(
|
||||||
|
A specific certification authority can be passed in and used to validate
|
||||||
|
a chain of certificates from a given server. These will be validated
|
||||||
|
using BearSSL's rules, which do NOT include certificate revocation lists.
|
||||||
|
A specific server's certificate, or your own self-signed root certificate
|
||||||
|
can also be used. ESP8266 time needs to be valid for checks to pass as
|
||||||
|
BearSSL does verify the notValidBefore/After fields.
|
||||||
|
)EOF");
|
||||||
|
|
||||||
|
BearSSL::WiFiClientSecure client;
|
||||||
|
BearSSL::X509List cert(cert_USERTrust_RSA_Certification_Authority);
|
||||||
|
client.setTrustAnchors(&cert);
|
||||||
|
Serial.printf("Try validating without setting the time (should fail)\n");
|
||||||
|
fetchURL(&client, gitlab_host, gitlab_port, path);
|
||||||
|
|
||||||
|
Serial.printf("Try again after setting NTP time (should pass)\n");
|
||||||
|
setClock();
|
||||||
|
fetchURL(&client, gitlab_host, gitlab_port, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fetchFaster() {
|
||||||
|
Serial.printf(R"EOF(
|
||||||
|
The ciphers used to set up the SSL connection can be configured to
|
||||||
|
only support faster but less secure ciphers. If you care about security
|
||||||
|
you won't want to do this. If you need to maximize battery life, these
|
||||||
|
may make sense
|
||||||
|
)EOF");
|
||||||
|
BearSSL::WiFiClientSecure client;
|
||||||
|
client.setInsecure();
|
||||||
|
uint32_t now = millis();
|
||||||
|
fetchURL(&client, gitlab_host, gitlab_port, path);
|
||||||
|
uint32_t delta = millis() - now;
|
||||||
|
client.setInsecure();
|
||||||
|
client.setCiphersLessSecure();
|
||||||
|
now = millis();
|
||||||
|
fetchURL(&client, gitlab_host, gitlab_port, path);
|
||||||
|
uint32_t delta2 = millis() - now;
|
||||||
|
std::vector<uint16_t> myCustomList = { BR_TLS_RSA_WITH_AES_256_CBC_SHA256, BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA };
|
||||||
|
client.setInsecure();
|
||||||
|
client.setCiphers(myCustomList);
|
||||||
|
now = millis();
|
||||||
|
fetchURL(&client, gitlab_host, gitlab_port, path);
|
||||||
|
uint32_t delta3 = millis() - now;
|
||||||
|
Serial.printf("Using more secure: %dms\nUsing less secure ciphers: %dms\nUsing custom cipher list: %dms\n", delta, delta2, delta3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println();
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
Serial.println("\nEthernet\n");
|
||||||
|
|
||||||
|
// 1. Currently when no default is set, esp8266-Arduino uses the first
|
||||||
|
// DHCP client interface receiving a valid address and gateway to
|
||||||
|
// become the new lwIP default interface.
|
||||||
|
// 2. Otherwise - when using static addresses - lwIP for every packets by
|
||||||
|
// defaults selects automatically the best suited output interface
|
||||||
|
// matching the destination address. If several interfaces match,
|
||||||
|
// the first one is picked. On esp8266/Arduno: WiFi interfaces are
|
||||||
|
// checked first.
|
||||||
|
// 3. Or, use `::setDefault()` to force routing through this interface.
|
||||||
|
// eth.setDefault(true); // default route set through this interface
|
||||||
|
|
||||||
|
if (!ethInitDHCP(eth)) {
|
||||||
|
Serial.printf("no hardware found\n");
|
||||||
|
while (1)
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!eth.connected()) {
|
||||||
|
Serial.printf(".");
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.printf("Ethernet: IP Address: %s\n",
|
||||||
|
eth.localIP().toString().c_str());
|
||||||
|
|
||||||
|
fetchNoConfig();
|
||||||
|
fetchInsecure();
|
||||||
|
fetchFingerprint();
|
||||||
|
fetchSelfSigned();
|
||||||
|
fetchKnownKey();
|
||||||
|
fetchCertAuthority();
|
||||||
|
fetchFaster();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// Nothing to do here
|
||||||
|
}
|
2
libraries/lwIP_Ethernet/examples/EthSSLValidation/certUpdate
Executable file
2
libraries/lwIP_Ethernet/examples/EthSSLValidation/certUpdate
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
cd ${0%/*} 2>/dev/null
|
||||||
|
python3 ../../../../tools/cert.py -s www.gitlab.com -n gitlab > certs.h
|
114
libraries/lwIP_Ethernet/examples/EthSSLValidation/certs.h
Normal file
114
libraries/lwIP_Ethernet/examples/EthSSLValidation/certs.h
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
|
||||||
|
// this file is autogenerated - any modification will be overwritten
|
||||||
|
// unused symbols will not be linked in the final binary
|
||||||
|
// generated on 2021-11-30 02:13:11
|
||||||
|
// by ['../../../../tools/cert.py', '-s', 'www.gitlab.com', '-n', 'gitlab']
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// certificate chain for www.gitlab.com:443
|
||||||
|
|
||||||
|
const char* gitlab_host = "www.gitlab.com";
|
||||||
|
const uint16_t gitlab_port = 443;
|
||||||
|
|
||||||
|
// CN: gitlab.com => name: gitlab_com
|
||||||
|
// not valid before: 2021-04-12 00:00:00
|
||||||
|
// not valid after: 2022-05-11 23:59:59
|
||||||
|
const char fingerprint_gitlab_com[] PROGMEM
|
||||||
|
= "71:55:5e:29:68:99:43:98:c8:85:35:bd:4c:10:4c:f5:cf:17:09:e6";
|
||||||
|
const char pubkey_gitlab_com[] PROGMEM = R"PUBKEY(
|
||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1eeFy86Xbz3ygyCVprHp
|
||||||
|
sPP3zyg0yldkIfqwjsXPH0b+KwQ85s3pzI/5+MVrR2/BGY4ed6mTZ6hvNwQJ2B0E
|
||||||
|
sJrsTb2nuUsXQ0UVO4hvnZ7Dnx8r/bT1cndqa+Mn+bms8/TS4etP72+TLaORBRCz
|
||||||
|
O4L1Hi8r61+zZLnP3DqqHeHAgl5wKHNYpx7yFFl2I71LuLH/pk2ICDBjaHwCIbRW
|
||||||
|
u484no9s1c4VROxqMrQQ/wDMl80MiO9YeNQ5rBHfnabh4rFe9eb2Sd0H/DWBj3SO
|
||||||
|
YBD0kiLI6b5CWYfA76pBSlZg7G3ledvQ+n9FEcS3EOCPKBBZqMDCzEahvHqwJ/r6
|
||||||
|
pwIDAQAB
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
|
)PUBKEY";
|
||||||
|
|
||||||
|
// http://crt.sectigo.com/SectigoRSADomainValidationSecureServerCA.crt
|
||||||
|
// CN: Sectigo RSA Domain Validation Secure Server CA => name: Sectigo_RSA_Domain_Validation_Secure_Server_CA
|
||||||
|
// not valid before: 2018-11-02 00:00:00
|
||||||
|
// not valid after: 2030-12-31 23:59:59
|
||||||
|
const char cert_Sectigo_RSA_Domain_Validation_Secure_Server_CA[] PROGMEM = R"CERT(
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCB
|
||||||
|
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
|
||||||
|
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
|
||||||
|
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx
|
||||||
|
MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBjzELMAkGA1UEBhMCR0IxGzAZBgNV
|
||||||
|
BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE
|
||||||
|
ChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIFJTQSBEb21haW4g
|
||||||
|
VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
||||||
|
AQ8AMIIBCgKCAQEA1nMz1tc8INAA0hdFuNY+B6I/x0HuMjDJsGz99J/LEpgPLT+N
|
||||||
|
TQEMgg8Xf2Iu6bhIefsWg06t1zIlk7cHv7lQP6lMw0Aq6Tn/2YHKHxYyQdqAJrkj
|
||||||
|
eocgHuP/IJo8lURvh3UGkEC0MpMWCRAIIz7S3YcPb11RFGoKacVPAXJpz9OTTG0E
|
||||||
|
oKMbgn6xmrntxZ7FN3ifmgg0+1YuWMQJDgZkW7w33PGfKGioVrCSo1yfu4iYCBsk
|
||||||
|
Haswha6vsC6eep3BwEIc4gLw6uBK0u+QDrTBQBbwb4VCSmT3pDCg/r8uoydajotY
|
||||||
|
uK3DGReEY+1vVv2Dy2A0xHS+5p3b4eTlygxfFQIDAQABo4IBbjCCAWowHwYDVR0j
|
||||||
|
BBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFI2MXsRUrYrhd+mb
|
||||||
|
+ZsF4bgBjWHhMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G
|
||||||
|
A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYGBFUdIAAw
|
||||||
|
CAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0
|
||||||
|
LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2Bggr
|
||||||
|
BgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNv
|
||||||
|
bS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDov
|
||||||
|
L29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAMr9hvQ5Iw0/H
|
||||||
|
ukdN+Jx4GQHcEx2Ab/zDcLRSmjEzmldS+zGea6TvVKqJjUAXaPgREHzSyrHxVYbH
|
||||||
|
7rM2kYb2OVG/Rr8PoLq0935JxCo2F57kaDl6r5ROVm+yezu/Coa9zcV3HAO4OLGi
|
||||||
|
H19+24rcRki2aArPsrW04jTkZ6k4Zgle0rj8nSg6F0AnwnJOKf0hPHzPE/uWLMUx
|
||||||
|
RP0T7dWbqWlod3zu4f+k+TY4CFM5ooQ0nBnzvg6s1SQ36yOoeNDT5++SR2RiOSLv
|
||||||
|
xvcRviKFxmZEJCaOEDKNyJOuB56DPi/Z+fVGjmO+wea03KbNIaiGCpXZLoUmGv38
|
||||||
|
sbZXQm2V0TP2ORQGgkE49Y9Y3IBbpNV9lXj9p5v//cWoaasm56ekBYdbqbe4oyAL
|
||||||
|
l6lFhd2zi+WJN44pDfwGF/Y4QA5C5BIG+3vzxhFoYt/jmPQT2BVPi7Fp2RBgvGQq
|
||||||
|
6jG35LWjOhSbJuMLe/0CjraZwTiXWTb2qHSihrZe68Zk6s+go/lunrotEbaGmAhY
|
||||||
|
LcmsJWTyXnW0OMGuf1pGg+pRyrbxmRE1a6Vqe8YAsOf4vmSyrcjC8azjUeqkk+B5
|
||||||
|
yOGBQMkKW+ESPMFgKuOXwIlCypTPRpgSabuY0MLTDXJLR27lk8QyKGOHQ+SwMj4K
|
||||||
|
00u/I5sUKUErmgQfky3xxzlIPK1aEn8=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
)CERT";
|
||||||
|
|
||||||
|
// http://crt.usertrust.com/USERTrustRSAAddTrustCA.crt
|
||||||
|
// CN: USERTrust RSA Certification Authority => name: USERTrust_RSA_Certification_Authority
|
||||||
|
// not valid before: 2019-03-12 00:00:00
|
||||||
|
// not valid after: 2028-12-31 23:59:59
|
||||||
|
const char cert_USERTrust_RSA_Certification_Authority[] PROGMEM = R"CERT(
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFgTCCBGmgAwIBAgIQOXJEOvkit1HX02wQ3TE1lTANBgkqhkiG9w0BAQwFADB7
|
||||||
|
MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD
|
||||||
|
VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE
|
||||||
|
AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTE5MDMxMjAwMDAwMFoXDTI4
|
||||||
|
MTIzMTIzNTk1OVowgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5
|
||||||
|
MRQwEgYDVQQHEwtKZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBO
|
||||||
|
ZXR3b3JrMS4wLAYDVQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0
|
||||||
|
aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAgBJlFzYOw9sI
|
||||||
|
s9CsVw127c0n00ytUINh4qogTQktZAnczomfzD2p7PbPwdzx07HWezcoEStH2jnG
|
||||||
|
vDoZtF+mvX2do2NCtnbyqTsrkfjib9DsFiCQCT7i6HTJGLSR1GJk23+jBvGIGGqQ
|
||||||
|
Ijy8/hPwhxR79uQfjtTkUcYRZ0YIUcuGFFQ/vDP+fmyc/xadGL1RjjWmp2bIcmfb
|
||||||
|
IWax1Jt4A8BQOujM8Ny8nkz+rwWWNR9XWrf/zvk9tyy29lTdyOcSOk2uTIq3XJq0
|
||||||
|
tyA9yn8iNK5+O2hmAUTnAU5GU5szYPeUvlM3kHND8zLDU+/bqv50TmnHa4xgk97E
|
||||||
|
xwzf4TKuzJM7UXiVZ4vuPVb+DNBpDxsP8yUmazNt925H+nND5X4OpWaxKXwyhGNV
|
||||||
|
icQNwZNUMBkTrNN9N6frXTpsNVzbQdcS2qlJC9/YgIoJk2KOtWbPJYjNhLixP6Q5
|
||||||
|
D9kCnusSTJV882sFqV4Wg8y4Z+LoE53MW4LTTLPtW//e5XOsIzstAL81VXQJSdhJ
|
||||||
|
WBp/kjbmUZIO8yZ9HE0XvMnsQybQv0FfQKlERPSZ51eHnlAfV1SoPv10Yy+xUGUJ
|
||||||
|
5lhCLkMaTLTwJUdZ+gQek9QmRkpQgbLevni3/GcV4clXhB4PY9bpYrrWX1Uu6lzG
|
||||||
|
KAgEJTm4Diup8kyXHAc/DVL17e8vgg8CAwEAAaOB8jCB7zAfBgNVHSMEGDAWgBSg
|
||||||
|
EQojPpbxB+zirynvgqV/0DCktDAdBgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rID
|
||||||
|
ZsswDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAG
|
||||||
|
BgRVHSAAMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29t
|
||||||
|
L0FBQUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggr
|
||||||
|
BgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBDAUA
|
||||||
|
A4IBAQAYh1HcdCE9nIrgJ7cz0C7M7PDmy14R3iJvm3WOnnL+5Nb+qh+cli3vA0p+
|
||||||
|
rvSNb3I8QzvAP+u431yqqcau8vzY7qN7Q/aGNnwU4M309z/+3ri0ivCRlv79Q2R+
|
||||||
|
/czSAaF9ffgZGclCKxO/WIu6pKJmBHaIkU4MiRTOok3JMrO66BQavHHxW/BBC5gA
|
||||||
|
CiIDEOUMsfnNkjcZ7Tvx5Dq2+UUTJnWvu6rvP3t3O9LEApE9GQDTF1w52z97GA1F
|
||||||
|
zZOFli9d31kWTz9RvdVFGD/tSo7oBmF0Ixa1DVBzJ0RHfxBdiSprhTEUxOipakyA
|
||||||
|
vGp4z7h/jnZymQyd/teRCBaho1+V
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
)CERT";
|
||||||
|
|
||||||
|
// end of certificate chain for www.gitlab.com:443
|
||||||
|
////////////////////////////////////////////////////////////
|
@ -0,0 +1,282 @@
|
|||||||
|
/*
|
||||||
|
ESP8266 mDNS responder clock
|
||||||
|
|
||||||
|
This example demonstrates two features of the LEA MDNSResponder:
|
||||||
|
1. The host and service domain negotiation process that ensures
|
||||||
|
the uniqueness of the finally chosen host and service domain name.
|
||||||
|
2. The dynamic MDNS service TXT feature
|
||||||
|
|
||||||
|
A 'clock' service in announced via the MDNS responder and the current
|
||||||
|
time is set as a TXT item (eg. 'curtime=Mon Oct 15 19:54:35 2018').
|
||||||
|
The time value is updated every second!
|
||||||
|
|
||||||
|
The ESP is initially announced to clients as 'esp8266.local', if this host domain
|
||||||
|
is already used in the local network, another host domain is negotiated. Keep an
|
||||||
|
eye to the serial output to learn the final host domain for the clock service.
|
||||||
|
The service itself is is announced as 'host domain'._espclk._tcp.local.
|
||||||
|
As the service uses port 80, a very simple HTTP server is installed also to deliver
|
||||||
|
a small web page containing a greeting and the current time (not updated).
|
||||||
|
The web server code is taken nearly 1:1 from the 'mDNS_Web_Server.ino' example.
|
||||||
|
Point your browser to 'host domain'.local to see this web page.
|
||||||
|
|
||||||
|
Instructions:
|
||||||
|
- Flash the sketch to the ESP8266 board
|
||||||
|
- Install host software:
|
||||||
|
- For Linux, install Avahi (http://avahi.org/).
|
||||||
|
- For Windows, install Bonjour (http://www.apple.com/support/bonjour/).
|
||||||
|
- For Mac OSX and iOS support is built in through Bonjour already.
|
||||||
|
- Use a MDNS/Bonjour browser like 'Discovery' to find the clock service in your local
|
||||||
|
network and see the current time updates.
|
||||||
|
|
||||||
|
This is the Ethernet version of:
|
||||||
|
https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_Clock
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <WiFiClient.h>
|
||||||
|
#include <ESP8266WebServer.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <PolledTimeout.h>
|
||||||
|
#include <ESP8266mDNS.h>
|
||||||
|
#include <LwipEthernet.h>
|
||||||
|
|
||||||
|
Wiznet5500lwIP eth(/*SS*/ 16); // <== adapt to your hardware
|
||||||
|
|
||||||
|
/*
|
||||||
|
Global defines and vars
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define TIMEZONE_OFFSET 1 // CET
|
||||||
|
#define DST_OFFSET 1 // CEST
|
||||||
|
#define UPDATE_CYCLE (1 * 1000) // every second
|
||||||
|
|
||||||
|
#define SERVICE_PORT 80 // HTTP port
|
||||||
|
|
||||||
|
#ifndef STASSID
|
||||||
|
#define STASSID "your-ssid"
|
||||||
|
#define STAPSK "your-password"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char* ssid = STASSID;
|
||||||
|
const char* password = STAPSK;
|
||||||
|
|
||||||
|
char* pcHostDomain = 0; // Negotiated host domain
|
||||||
|
bool bHostDomainConfirmed = false; // Flags the confirmation of the host domain
|
||||||
|
MDNSResponder::hMDNSService hMDNSService = 0; // The handle of the clock service in the MDNS responder
|
||||||
|
|
||||||
|
// HTTP server at port 'SERVICE_PORT' will respond to HTTP requests
|
||||||
|
ESP8266WebServer server(SERVICE_PORT);
|
||||||
|
|
||||||
|
/*
|
||||||
|
getTimeString
|
||||||
|
*/
|
||||||
|
const char* getTimeString(void) {
|
||||||
|
|
||||||
|
static char acTimeString[32];
|
||||||
|
time_t now = time(nullptr);
|
||||||
|
ctime_r(&now, acTimeString);
|
||||||
|
size_t stLength;
|
||||||
|
while (((stLength = strlen(acTimeString))) && ('\n' == acTimeString[stLength - 1])) {
|
||||||
|
acTimeString[stLength - 1] = 0; // Remove trailing line break...
|
||||||
|
}
|
||||||
|
return acTimeString;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
setClock
|
||||||
|
|
||||||
|
Set time via NTP
|
||||||
|
*/
|
||||||
|
void setClock(void) {
|
||||||
|
configTime((TIMEZONE_OFFSET * 3600), (DST_OFFSET * 3600), "pool.ntp.org", "time.nist.gov", "time.windows.com");
|
||||||
|
|
||||||
|
Serial.print("Waiting for NTP time sync: ");
|
||||||
|
time_t now = time(nullptr); // Secs since 01.01.1970 (when uninitialized starts with (8 * 3600 = 28800)
|
||||||
|
while (now < 8 * 3600 * 2) { // Wait for realistic value
|
||||||
|
delay(500);
|
||||||
|
Serial.print(".");
|
||||||
|
now = time(nullptr);
|
||||||
|
}
|
||||||
|
Serial.println("");
|
||||||
|
Serial.printf("Current time: %s\n", getTimeString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
setStationHostname
|
||||||
|
*/
|
||||||
|
bool setStationHostname(const char* p_pcHostname) {
|
||||||
|
|
||||||
|
if (p_pcHostname) {
|
||||||
|
WiFi.hostname(p_pcHostname);
|
||||||
|
Serial.printf("setDeviceHostname: Station hostname is set to '%s'\n", p_pcHostname);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
MDNSDynamicServiceTxtCallback
|
||||||
|
|
||||||
|
Add a dynamic MDNS TXT item 'ct' to the clock service.
|
||||||
|
The callback function is called every time, the TXT items for the clock service
|
||||||
|
are needed.
|
||||||
|
This can be triggered by calling MDNS.announce().
|
||||||
|
|
||||||
|
*/
|
||||||
|
void MDNSDynamicServiceTxtCallback(const MDNSResponder::hMDNSService p_hService) {
|
||||||
|
Serial.println("MDNSDynamicServiceTxtCallback");
|
||||||
|
|
||||||
|
if (hMDNSService == p_hService) {
|
||||||
|
Serial.printf("Updating curtime TXT item to: %s\n", getTimeString());
|
||||||
|
MDNS.addDynamicServiceTxt(p_hService, "curtime", getTimeString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
MDNSProbeResultCallback
|
||||||
|
|
||||||
|
Probe result callback for the host domain.
|
||||||
|
If the domain is free, the host domain is set and the clock service is
|
||||||
|
added.
|
||||||
|
If the domain is already used, a new name is created and the probing is
|
||||||
|
restarted via p_pMDNSResponder->setHostname().
|
||||||
|
|
||||||
|
*/
|
||||||
|
void hostProbeResult(String p_pcDomainName, bool p_bProbeResult) {
|
||||||
|
|
||||||
|
Serial.println("MDNSProbeResultCallback");
|
||||||
|
Serial.printf("MDNSProbeResultCallback: Host domain '%s.local' is %s\n", p_pcDomainName.c_str(), (p_bProbeResult ? "free" : "already USED!"));
|
||||||
|
if (true == p_bProbeResult) {
|
||||||
|
// Set station hostname
|
||||||
|
setStationHostname(pcHostDomain);
|
||||||
|
|
||||||
|
if (!bHostDomainConfirmed) {
|
||||||
|
// Hostname free -> setup clock service
|
||||||
|
bHostDomainConfirmed = true;
|
||||||
|
|
||||||
|
if (!hMDNSService) {
|
||||||
|
// Add a 'clock.tcp' service to port 'SERVICE_PORT', using the host domain as instance domain
|
||||||
|
hMDNSService = MDNS.addService(0, "espclk", "tcp", SERVICE_PORT);
|
||||||
|
if (hMDNSService) {
|
||||||
|
// Add a simple static MDNS service TXT item
|
||||||
|
MDNS.addServiceTxt(hMDNSService, "port#", SERVICE_PORT);
|
||||||
|
// Set the callback function for dynamic service TXTs
|
||||||
|
MDNS.setDynamicServiceTxtCallback(MDNSDynamicServiceTxtCallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Change hostname, use '-' as divider between base name and index
|
||||||
|
if (MDNSResponder::indexDomain(pcHostDomain, "-", 0)) {
|
||||||
|
MDNS.setHostname(pcHostDomain);
|
||||||
|
} else {
|
||||||
|
Serial.println("MDNSProbeResultCallback: FAILED to update hostname!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
handleHTTPClient
|
||||||
|
*/
|
||||||
|
|
||||||
|
void handleHTTPRequest() {
|
||||||
|
Serial.println("");
|
||||||
|
Serial.println("HTTP Request");
|
||||||
|
|
||||||
|
// Get current time
|
||||||
|
time_t now = time(nullptr);
|
||||||
|
struct tm timeinfo;
|
||||||
|
gmtime_r(&now, &timeinfo);
|
||||||
|
|
||||||
|
String s;
|
||||||
|
|
||||||
|
s = "<!DOCTYPE HTML>\r\n<html>Hello from ";
|
||||||
|
s += WiFi.hostname() + " at " + WiFi.localIP().toString();
|
||||||
|
// Simple addition of the current time
|
||||||
|
s += "\r\nCurrent time is: ";
|
||||||
|
s += getTimeString();
|
||||||
|
// done :-)
|
||||||
|
s += "</html>\r\n\r\n";
|
||||||
|
Serial.println("Sending 200");
|
||||||
|
server.send(200, "text/html", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
setup
|
||||||
|
*/
|
||||||
|
void setup(void) {
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
Serial.println("\nEthernet\n");
|
||||||
|
|
||||||
|
// 1. Currently when no default is set, esp8266-Arduino uses the first
|
||||||
|
// DHCP client interface receiving a valid address and gateway to
|
||||||
|
// become the new lwIP default interface.
|
||||||
|
// 2. Otherwise - when using static addresses - lwIP for every packets by
|
||||||
|
// defaults selects automatically the best suited output interface
|
||||||
|
// matching the destination address. If several interfaces match,
|
||||||
|
// the first one is picked. On esp8266/Arduno: WiFi interfaces are
|
||||||
|
// checked first.
|
||||||
|
// 3. Or, use `::setDefault()` to force routing through this interface.
|
||||||
|
// eth.setDefault(); // default route set through this interface
|
||||||
|
|
||||||
|
if (!ethInitDHCP(eth)) {
|
||||||
|
Serial.printf("no hardware found\n");
|
||||||
|
while (1) {
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!eth.connected()) {
|
||||||
|
Serial.printf(".");
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.printf("Ethernet: IP Address: %s\n",
|
||||||
|
eth.localIP().toString().c_str());
|
||||||
|
|
||||||
|
// Sync clock
|
||||||
|
setClock();
|
||||||
|
|
||||||
|
// Setup MDNS responder
|
||||||
|
MDNS.setHostProbeResultCallback(hostProbeResult);
|
||||||
|
// Init the (currently empty) host domain string with 'esp8266'
|
||||||
|
if ((!MDNSResponder::indexDomain(pcHostDomain, 0, "esp8266")) || (!MDNS.begin(pcHostDomain))) {
|
||||||
|
Serial.println("Error setting up MDNS responder!");
|
||||||
|
while (1) { // STOP
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Serial.println("MDNS responder started");
|
||||||
|
|
||||||
|
// Setup HTTP server
|
||||||
|
server.on("/", handleHTTPRequest);
|
||||||
|
server.begin();
|
||||||
|
Serial.println("HTTP server started");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
loop
|
||||||
|
*/
|
||||||
|
void loop(void) {
|
||||||
|
|
||||||
|
// Check if a request has come in
|
||||||
|
server.handleClient();
|
||||||
|
// Allow MDNS processing
|
||||||
|
MDNS.update();
|
||||||
|
|
||||||
|
static esp8266::polledTimeout::periodicMs timeout(UPDATE_CYCLE);
|
||||||
|
if (timeout.expired()) {
|
||||||
|
|
||||||
|
if (hMDNSService) {
|
||||||
|
// Just trigger a new MDNS announcement, this will lead to a call to
|
||||||
|
// 'MDNSDynamicServiceTxtCallback', which will update the time TXT item
|
||||||
|
MDNS.announce();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
libraries/lwIP_Ethernet/library.properties
Normal file
10
libraries/lwIP_Ethernet/library.properties
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
name=lwIP-Ethernet
|
||||||
|
version=1
|
||||||
|
author=esp8266/Arduino
|
||||||
|
maintainer=esp8266/Arduino
|
||||||
|
sentence=Helper for ethernet drivers
|
||||||
|
paragraph=Example repository for Ethernet drivers
|
||||||
|
category=Communication
|
||||||
|
url=https://github.com/esp8266/Arduino
|
||||||
|
architectures=esp8266
|
||||||
|
dot_a_linkage=true
|
15
libraries/lwIP_Ethernet/src/LwipEthernet.cpp
Normal file
15
libraries/lwIP_Ethernet/src/LwipEthernet.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
#include <LwipEthernet.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
|
||||||
|
#ifndef ETHERNET_SPI_CLOCK_DIV
|
||||||
|
#define ETHERNET_SPI_CLOCK_DIV SPI_CLOCK_DIV4 // 4MHz (SPI.h)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void SPI4EthInit()
|
||||||
|
{
|
||||||
|
SPI.begin();
|
||||||
|
SPI.setClockDivider(ETHERNET_SPI_CLOCK_DIV);
|
||||||
|
SPI.setBitOrder(MSBFIRST);
|
||||||
|
SPI.setDataMode(SPI_MODE0);
|
||||||
|
}
|
53
libraries/lwIP_Ethernet/src/LwipEthernet.h
Normal file
53
libraries/lwIP_Ethernet/src/LwipEthernet.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
|
||||||
|
#include <ESP8266WiFi.h> // tcp API
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <W5100lwIP.h>
|
||||||
|
#include <W5500lwIP.h>
|
||||||
|
#include <ENC28J60lwIP.h>
|
||||||
|
|
||||||
|
// One of them is to be declared in the main sketch
|
||||||
|
// and passed to ethInitDHCP() or ethInitStatic():
|
||||||
|
// Wiznet5500lwIP eth(CSPIN);
|
||||||
|
// Wiznet5100lwIP eth(CSPIN);
|
||||||
|
// ENC28J60lwIP eth(CSPIN);
|
||||||
|
|
||||||
|
void SPI4EthInit();
|
||||||
|
|
||||||
|
template<class EthImpl>
|
||||||
|
bool ethInitDHCP(EthImpl& eth)
|
||||||
|
{
|
||||||
|
SPI4EthInit();
|
||||||
|
|
||||||
|
if (!eth.begin())
|
||||||
|
{
|
||||||
|
// hardware not responding
|
||||||
|
DEBUGV("ethInitDHCP: hardware not responding\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class EthImpl>
|
||||||
|
bool ethInitStatic(EthImpl& eth, IPAddress IP, IPAddress gateway, IPAddress netmask, IPAddress dns1,
|
||||||
|
IPAddress dns2 = IPADDR_NONE)
|
||||||
|
{
|
||||||
|
SPI4EthInit();
|
||||||
|
|
||||||
|
if (!eth.config(IP, gateway, netmask, dns1, dns2))
|
||||||
|
{
|
||||||
|
// invalid arguments
|
||||||
|
DEBUGV("ethInitStatic: invalid arguments\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!eth.begin())
|
||||||
|
{
|
||||||
|
// hardware not responding
|
||||||
|
DEBUGV("ethInitStatic: hardware not responding\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
@ -1,91 +0,0 @@
|
|||||||
/*
|
|
||||||
This sketch establishes a TCP connection to a "quote of the day" service.
|
|
||||||
It sends a "hello" message, and then prints received data.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <SPI.h>
|
|
||||||
#include <W5500lwIP.h>
|
|
||||||
// or #include <W5100lwIP.h>
|
|
||||||
// or #include <ENC28J60lwIP.h>
|
|
||||||
|
|
||||||
#include <WiFiClient.h> // WiFiClient (-> TCPClient)
|
|
||||||
|
|
||||||
const char* host = "djxmmx.net";
|
|
||||||
const uint16_t port = 17;
|
|
||||||
|
|
||||||
using TCPClient = WiFiClient;
|
|
||||||
|
|
||||||
#define CSPIN 16 // wemos/lolin/nodemcu D0
|
|
||||||
Wiznet5500lwIP eth(CSPIN);
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(115200);
|
|
||||||
|
|
||||||
SPI.begin();
|
|
||||||
SPI.setClockDivider(SPI_CLOCK_DIV4); // 4 MHz?
|
|
||||||
SPI.setBitOrder(MSBFIRST);
|
|
||||||
SPI.setDataMode(SPI_MODE0);
|
|
||||||
eth.setDefault(); // use ethernet for default route
|
|
||||||
if (!eth.begin()) {
|
|
||||||
Serial.println("ethernet hardware not found ... sleeping");
|
|
||||||
while (1) { delay(1000); }
|
|
||||||
} else {
|
|
||||||
Serial.print("connecting ethernet");
|
|
||||||
while (!eth.connected()) {
|
|
||||||
Serial.print(".");
|
|
||||||
delay(1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Serial.println();
|
|
||||||
Serial.print("ethernet IP address: ");
|
|
||||||
Serial.println(eth.localIP());
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
static bool wait = false;
|
|
||||||
|
|
||||||
Serial.print("connecting to ");
|
|
||||||
Serial.print(host);
|
|
||||||
Serial.print(':');
|
|
||||||
Serial.println(port);
|
|
||||||
|
|
||||||
TCPClient client;
|
|
||||||
if (!client.connect(host, port)) {
|
|
||||||
Serial.println("connection failed");
|
|
||||||
delay(5000);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This will send a string to the server
|
|
||||||
Serial.println("sending data to server");
|
|
||||||
if (client.connected()) { client.println("hello from ESP8266"); }
|
|
||||||
|
|
||||||
// wait for data to be available
|
|
||||||
unsigned long timeout = millis();
|
|
||||||
while (client.available() == 0) {
|
|
||||||
if (millis() - timeout > 5000) {
|
|
||||||
Serial.println(">>> Client Timeout !");
|
|
||||||
client.stop();
|
|
||||||
delay(60000);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read all the lines of the reply from server and print them to Serial
|
|
||||||
Serial.println("receiving from remote server");
|
|
||||||
// not testing 'client.connected()' since we do not need to send data here
|
|
||||||
while (client.available()) {
|
|
||||||
char ch = static_cast<char>(client.read());
|
|
||||||
Serial.print(ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close the connection
|
|
||||||
Serial.println();
|
|
||||||
Serial.println("closing connection");
|
|
||||||
client.stop();
|
|
||||||
|
|
||||||
if (wait) {
|
|
||||||
delay(300000); // execute once every 5 minutes, don't flood remote service
|
|
||||||
}
|
|
||||||
wait = true;
|
|
||||||
}
|
|
@ -27,3 +27,4 @@ NamespaceIndentation: Inner
|
|||||||
BreakBeforeBraces: Allman
|
BreakBeforeBraces: Allman
|
||||||
IndentWidth: 4
|
IndentWidth: 4
|
||||||
IndentCaseLabels: false
|
IndentCaseLabels: false
|
||||||
|
ReflowComments: false
|
||||||
|
Loading…
x
Reference in New Issue
Block a user