1
0
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:
david gauchard 2022-06-02 14:03:38 +02:00 committed by GitHub
parent f5ef02d643
commit 5f2af1945b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 947 additions and 112 deletions

View File

@ -59,7 +59,17 @@ public:
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
bool connected()
@ -67,12 +77,18 @@ public:
return !!ip4_addr_get_u32(ip_2_ip4(&_netif.ip_addr));
}
bool routable()
{
return !ip_addr_isany(&_netif.gw);
}
// ESP8266WiFi API compatibility
wl_status_t status();
protected:
err_t netif_init();
void check_route();
void netif_status_callback();
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;
}
_netif.flags |= NETIF_FLAG_UP;
if (localIP().v4() == 0)
{
// IP not set, starting DHCP
_netif.flags |= NETIF_FLAG_UP;
switch (dhcp_start(&_netif))
{
case ERR_OK:
@ -201,6 +217,12 @@ boolean LwipIntfDev<RawDev>::begin(const uint8_t* macAddress, const uint16_t mtu
return false;
}
}
else
{
// IP is set, static config
netif_set_link_up(&_netif);
netif_set_up(&_netif);
}
_started = true;
@ -301,17 +323,26 @@ err_t LwipIntfDev<RawDev>::netif_init()
template<class RawDev>
void LwipIntfDev<RawDev>::netif_status_callback()
{
check_route();
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_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)
{
netif_set_default(nullptr);
@ -386,13 +417,10 @@ err_t LwipIntfDev<RawDev>::handlePackets()
}
template<class RawDev>
void LwipIntfDev<RawDev>::setDefault()
void LwipIntfDev<RawDev>::setDefault(bool deflt)
{
_default = true;
if (connected())
{
netif_set_default(&_netif);
}
_default = deflt;
check_route();
}
#endif // _LWIPINTFDEV_H

View File

@ -1766,11 +1766,13 @@ namespace MDNSImplementation
stcMDNS_RRAttributes attributes(DNS_RRTYPE_AAAA,
((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0)
| DNS_RRCLASS_IN)); // Cache flush? & INternet
bool bResult = ((_writeMDNSHostDomain(m_pcHostname, false, p_rSendParameter)) && // esp8266.local
(_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS
(_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter)) && // TTL
(_write16(MDNS_IP6_SIZE, p_rSendParameter)) && // RDLength
(false /*TODO: IP6 version of: _udpAppendBuffer((uint32_t)p_IPAddress, MDNS_IP4_SIZE)*/)); // RData
bool bResult
= ((_writeMDNSHostDomain(m_pcHostname, false, p_rSendParameter)) && // esp8266.local
(_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS
(_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter))
&& // 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_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_AAAA: FAILED!\n"));
@ -1855,7 +1857,7 @@ namespace MDNSImplementation
p_rSendParameter.m_u16Offset))
&& (_writeMDNSRRDomain(hostDomain,
p_rSendParameter))) // Host, eg. esp8266.local
// Cache available for domain
// Cache available for domain
: ((MDNS_DOMAIN_COMPRESS_MARK
> ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK))
&& // Valid offset

View 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
}

View File

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

View File

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

View File

@ -0,0 +1,2 @@
cd ${0%/*} 2>/dev/null
python3 ../../../../tools/cert.py -s www.gitlab.com -n gitlab > certs.h

View 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
////////////////////////////////////////////////////////////

View File

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

View 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

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

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

View File

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

View File

@ -27,3 +27,4 @@ NamespaceIndentation: Inner
BreakBeforeBraces: Allman
IndentWidth: 4
IndentCaseLabels: false
ReflowComments: false