diff --git a/examples/IPv6-IPv4-separate/IPv6-IPv4-separate.ino b/examples/IPv6-IPv4-separate/IPv6-IPv4-separate.ino new file mode 100644 index 0000000..6f00f37 --- /dev/null +++ b/examples/IPv6-IPv4-separate/IPv6-IPv4-separate.ino @@ -0,0 +1,191 @@ +/** + * Example for the ESP32 HTTP(S) Webserver + * + * IMPORTANT NOTE: + * To run this script, your need to + * 1) Enter your WiFi SSID and PSK below this comment + * 2) Make sure to have certificate data available. You will find a + * shell script and instructions to do so in the library folder + * under extras/ + * + * This script will install an HTTP Server on port 80 and an HTTPS server + * on port 443 of your ESP32 with the following functionalities: + * - Show simple page on web server root + * - 404 for everything else + * + * The comments in this script focus on making both protocols available, + * for setting up the server itself, see Static-Page. + */ + +// TODO: Configure your WiFi here +#define WIFI_SSID "" +#define WIFI_PSK "" + +// Include certificate data (see note above) +#include "cert.h" +#include "private_key.h" + +// We will use wifi +#include + +// Includes for the server +#include +#include +#include +#include + +// The HTTPS Server comes in a separate namespace. For easier use, include it here. +using namespace httpsserver; + +// Create an SSL certificate object from the files included above +SSLCert cert = SSLCert( + example_crt_DER, example_crt_DER_len, + example_key_DER, example_key_DER_len +); + +// First, we create an IPv4 HTTPSServer with the certificate created above +HTTPSServer ipv4Server = HTTPSServer(&cert); + +// Additionally, we create an HTTPSServer for IPv6 +// We need to manually specify all the parameters +// But the important ones are the address to bind to +// And the flag to only accept IPv6 connections +// - This makes sure the two servers don't interfere +HTTPSServer ipv6Server = HTTPSServer(&cert, (uint16_t)443U, (uint8_t)'\004', in6addr_any.s6_addr, true); + +// Declare some handler functions for the various URLs on the server +void handleRootIPv4(HTTPRequest * req, HTTPResponse * res); +void handleRootIPv6(HTTPRequest * req, HTTPResponse * res); +void handle404(HTTPRequest * req, HTTPResponse * res); + +void WiFiEvent(WiFiEvent_t event); + +void setup() { + // For logging + Serial.begin(115200); + + // Connect to WiFi + Serial.println("Setting up WiFi"); + // Handle WiFi events, see WifiEvent() + WiFi.onEvent(WiFiEvent); + WiFi.begin(WIFI_SSID, WIFI_PSK); + while (WiFi.status() != WL_CONNECTED) { + Serial.print("."); + delay(500); + } + + Serial.print("Connected. IPv4="); + Serial.println(WiFi.localIP()); + + // For every resource available on the server, we need to create a ResourceNode + // The ResourceNode links URL and HTTP method to a handler function + ResourceNode * nodeRootIPv4 = new ResourceNode("/", "GET", &handleRootIPv4); + ResourceNode * nodeRootIPv6 = new ResourceNode("/", "GET", &handleRootIPv6); + ResourceNode * node404 = new ResourceNode("", "GET", &handle404); + + // Add the root node to the servers. We can use the same ResourceNode on multiple + // servers (you could also run multiple HTTPS servers) + ipv4Server.registerNode(nodeRootIPv4); + ipv6Server.registerNode(nodeRootIPv6); + + // We do the same for the default Node + ipv4Server.setDefaultNode(node404); + ipv6Server.setDefaultNode(node404); + + Serial.println("Starting IPv4 server..."); + ipv4Server.start(); + Serial.println("Starting IPv6 server..."); + ipv6Server.start(); + if (ipv4Server.isRunning() && ipv6Server.isRunning()) { + Serial.println("Servers ready."); + } +} + +void loop() { + // We need to call both loop functions here + ipv4Server.loop(); + ipv6Server.loop(); + + // Other code would go here... + delay(1); +} + +// We serve different content on the IPv4 and IPv6 servers +// Therefore we create two different handlers + +void handleRootIPv4(HTTPRequest * req, HTTPResponse * res) { + res->setHeader("Content-Type", "text/html"); + + res->println(""); + res->println(""); + res->println("Hello World!"); + res->println(""); + res->println("

Hello World!

"); + + res->print("

Your server is running for "); + res->print((int)(millis()/1000), DEC); + res->println(" seconds.

"); + res->println(""); + res->println(""); + + res->println("

You are connected to the IPv4 server.

"); + res->print("

Your IP address is "); + res->print(req->getClientIP()); + res->println(".

"); + + res->println(""); + res->println(""); +} + +void handleRootIPv6(HTTPRequest * req, HTTPResponse * res) { + res->setHeader("Content-Type", "text/html"); + + res->println(""); + res->println(""); + res->println("Hello World!"); + res->println(""); + res->println("

Hello World!

"); + + res->print("

Your server is running for "); + res->print((int)(millis()/1000), DEC); + res->println(" seconds.

"); + res->println(""); + res->println(""); + + res->println("

You are connected to the IPv6 server.

"); + res->print("

Your IP address is "); + res->print(req->getClientIPv6()); + res->println(".

"); + + res->println(""); + res->println(""); +} + +void handle404(HTTPRequest * req, HTTPResponse * res) { + req->discardRequestBody(); + res->setStatusCode(404); + res->setStatusText("Not Found"); + res->setHeader("Content-Type", "text/html"); + res->println(""); + res->println(""); + res->println("Not Found"); + res->println("

404 Not Found

The requested resource was not found on this server.

"); + res->println(""); +} + +// We need to enable IPv6 on the wifi client AFTER we are connected +// When we get an IPv6 address, we print it +void WiFiEvent(WiFiEvent_t event){ + switch(event) { + case SYSTEM_EVENT_STA_CONNECTED: + // Enable IPv6 + WiFi.enableIpV6(); + break; + case SYSTEM_EVENT_AP_STA_GOT_IP6: + Serial.print("Connected. IPv6="); + Serial.println(WiFi.localIPv6()); + break; + default: + break; + } +} diff --git a/examples/IPv6-dual-stack/IPv6-dual-stack.ino b/examples/IPv6-dual-stack/IPv6-dual-stack.ino new file mode 100644 index 0000000..f062588 --- /dev/null +++ b/examples/IPv6-dual-stack/IPv6-dual-stack.ino @@ -0,0 +1,159 @@ +/** + * Example for the ESP32 HTTP(S) Webserver + * + * IMPORTANT NOTE: + * To run this script, your need to + * 1) Enter your WiFi SSID and PSK below this comment + * 2) Make sure to have certificate data available. You will find a + * shell script and instructions to do so in the library folder + * under extras/ + * + * This script will install an HTTP Server on port 80 and an HTTPS server + * on port 443 of your ESP32 with the following functionalities: + * - Show simple page on web server root + * - 404 for everything else + * + * The comments in this script focus on making both protocols available, + * for setting up the server itself, see Static-Page. + */ + +// TODO: Configure your WiFi here +#define WIFI_SSID "" +#define WIFI_PSK "" + +// Include certificate data (see note above) +#include "cert.h" +#include "private_key.h" + +// We will use wifi +#include + +// Includes for the server +#include +#include +#include +#include + +// The HTTPS Server comes in a separate namespace. For easier use, include it here. +using namespace httpsserver; + +// Create an SSL certificate object from the files included above +SSLCert cert = SSLCert( + example_crt_DER, example_crt_DER_len, + example_key_DER, example_key_DER_len +); + +// First, we create an IPv6 HTTPSServer with the certificate created above + +// We need to manually specify all the parameters +// But the important ones are the address to bind to (if set to an IPv6 address it enables IPv6 on the server) +// and the flag to only accept IPv6 connections (set to false since we want dual stack) +HTTPSServer secureServer = HTTPSServer(&cert, (uint16_t)443U, (uint8_t)'\004', in6addr_any.s6_addr, false); + +// Declare some handler functions for the various URLs on the server +void handleRoot(HTTPRequest * req, HTTPResponse * res); +void handle404(HTTPRequest * req, HTTPResponse * res); + +void WiFiEvent(WiFiEvent_t event); + +void setup() { + // For logging + Serial.begin(115200); + + // Connect to WiFi + Serial.println("Setting up WiFi"); + // Handle WiFi events, see WifiEvent() + WiFi.onEvent(WiFiEvent); + WiFi.begin(WIFI_SSID, WIFI_PSK); + while (WiFi.status() != WL_CONNECTED) { + Serial.print("."); + delay(500); + } + + Serial.print("Connected. IPv4="); + Serial.println(WiFi.localIP()); + + // For every resource available on the server, we need to create a ResourceNode + // The ResourceNode links URL and HTTP method to a handler function + ResourceNode * nodeRoot = new ResourceNode("/", "GET", &handleRoot); + ResourceNode * node404 = new ResourceNode("", "GET", &handle404); + + // Add the root node to the server. + secureServer.registerNode(nodeRoot); + + secureServer.setDefaultNode(node404); + + Serial.println("Starting server..."); + secureServer.start(); + if (secureServer.isRunning()) { + Serial.println("Server ready."); + } +} + +void loop() { + // We need to call the loop function here + secureServer.loop(); + + // Other code would go here... + delay(1); +} + +// Create the handlers + +void handleRoot(HTTPRequest * req, HTTPResponse * res) { + res->setHeader("Content-Type", "text/html"); + + res->println(""); + res->println(""); + res->println("Hello World!"); + res->println(""); + res->println("

Hello World!

"); + + res->print("

Your server is running for "); + res->print((int)(millis()/1000), DEC); + res->println(" seconds.

"); + res->println(""); + res->println(""); + + // Since we handle both IPv4 and IPv6 clients, we will check which protocl they're using + // Then we will print the IP address + res->print("

Your IP address is "); + if (req->isIPv6()) { + res->print(req->getClientIPv6()); + } else { + res->print(req->getClientIP()); + } + res->println(".

"); + + res->println(""); + res->println(""); +} + +void handle404(HTTPRequest * req, HTTPResponse * res) { + req->discardRequestBody(); + res->setStatusCode(404); + res->setStatusText("Not Found"); + res->setHeader("Content-Type", "text/html"); + res->println(""); + res->println(""); + res->println("Not Found"); + res->println("

404 Not Found

The requested resource was not found on this server.

"); + res->println(""); +} + +// We need to enable IPv6 on the wifi client AFTER we are connected +// When we get an IPv6 address, we print it +void WiFiEvent(WiFiEvent_t event){ + switch(event) { + case SYSTEM_EVENT_STA_CONNECTED: + // Enable IPv6 + WiFi.enableIpV6(); + break; + case SYSTEM_EVENT_AP_STA_GOT_IP6: + Serial.print("Connected. IPv6="); + Serial.println(WiFi.localIPv6()); + break; + default: + break; + } +} diff --git a/examples/IPv6-only/IPv6-only.ino b/examples/IPv6-only/IPv6-only.ino new file mode 100644 index 0000000..9703629 --- /dev/null +++ b/examples/IPv6-only/IPv6-only.ino @@ -0,0 +1,155 @@ +/** + * Example for the ESP32 HTTP(S) Webserver + * + * IMPORTANT NOTE: + * To run this script, your need to + * 1) Enter your WiFi SSID and PSK below this comment + * 2) Make sure to have certificate data available. You will find a + * shell script and instructions to do so in the library folder + * under extras/ + * + * This script will install an HTTP Server on port 80 and an HTTPS server + * on port 443 of your ESP32 with the following functionalities: + * - Show simple page on web server root + * - 404 for everything else + * + * The comments in this script focus on making both protocols available, + * for setting up the server itself, see Static-Page. + */ + +// TODO: Configure your WiFi here +#define WIFI_SSID "" +#define WIFI_PSK "" + +// Include certificate data (see note above) +#include "cert.h" +#include "private_key.h" + +// We will use wifi +#include + +// Includes for the server +#include +#include +#include +#include + +// The HTTPS Server comes in a separate namespace. For easier use, include it here. +using namespace httpsserver; + +// Create an SSL certificate object from the files included above +SSLCert cert = SSLCert( + example_crt_DER, example_crt_DER_len, + example_key_DER, example_key_DER_len +); + +// First, we create an IPv6 HTTPSServer with the certificate created above + +// We need to manually specify all the parameters +// But the important ones are the address to bind to +// And the flag to only accept IPv6 connections +// - This makes sure the two servers don't interfere +HTTPSServer ipv6Server = HTTPSServer(&cert, (uint16_t)443U, (uint8_t)'\004', in6addr_any.s6_addr, true); + +// Declare some handler functions for the various URLs on the server +void handleRoot(HTTPRequest * req, HTTPResponse * res); +void handle404(HTTPRequest * req, HTTPResponse * res); + +void WiFiEvent(WiFiEvent_t event); + +void setup() { + // For logging + Serial.begin(115200); + + // Connect to WiFi + Serial.println("Setting up WiFi"); + // Handle WiFi events, see WifiEvent() + WiFi.onEvent(WiFiEvent); + WiFi.begin(WIFI_SSID, WIFI_PSK); + while (WiFi.status() != WL_CONNECTED) { + Serial.print("."); + delay(500); + } + + Serial.print("Connected. IPv4="); + Serial.println(WiFi.localIP()); + + // For every resource available on the server, we need to create a ResourceNode + // The ResourceNode links URL and HTTP method to a handler function + ResourceNode * nodeRoot = new ResourceNode("/", "GET", &handleRoot); + ResourceNode * node404 = new ResourceNode("", "GET", &handle404); + + // Add the root node to the server. + ipv6Server.registerNode(nodeRoot); + + ipv6Server.setDefaultNode(node404); + + Serial.println("Starting server..."); + ipv6Server.start(); + if (ipv6Server.isRunning()) { + Serial.println("Server ready."); + } +} + +void loop() { + // We need to call the loop function here + ipv6Server.loop(); + + // Other code would go here... + delay(1); +} + +// Create the handlers + +void handleRoot(HTTPRequest * req, HTTPResponse * res) { + res->setHeader("Content-Type", "text/html"); + + res->println(""); + res->println(""); + res->println("Hello World!"); + res->println(""); + res->println("

Hello World!

"); + + res->print("

Your server is running for "); + res->print((int)(millis()/1000), DEC); + res->println(" seconds.

"); + res->println(""); + res->println(""); + + // Print the IP(v6) address + res->print("

Your IP address is "); + res->print(req->getClientIPv6()); + res->println(".

"); + + res->println(""); + res->println(""); +} + +void handle404(HTTPRequest * req, HTTPResponse * res) { + req->discardRequestBody(); + res->setStatusCode(404); + res->setStatusText("Not Found"); + res->setHeader("Content-Type", "text/html"); + res->println(""); + res->println(""); + res->println("Not Found"); + res->println("

404 Not Found

The requested resource was not found on this server.

"); + res->println(""); +} + +// We need to enable IPv6 on the wifi client AFTER we are connected +// When we get an IPv6 address, we print it +void WiFiEvent(WiFiEvent_t event){ + switch(event) { + case SYSTEM_EVENT_STA_CONNECTED: + // Enable IPv6 + WiFi.enableIpV6(); + break; + case SYSTEM_EVENT_AP_STA_GOT_IP6: + Serial.print("Connected. IPv6="); + Serial.println(WiFi.localIPv6()); + break; + default: + break; + } +} diff --git a/src/ConnectionContext.hpp b/src/ConnectionContext.hpp index da88964..392c1e4 100644 --- a/src/ConnectionContext.hpp +++ b/src/ConnectionContext.hpp @@ -3,6 +3,7 @@ #include #include +#include // Required for SSL #include "openssl/ssl.h" @@ -30,8 +31,10 @@ class ConnectionContext { virtual size_t writeBuffer(byte* buffer, size_t length) = 0; virtual bool isSecure() = 0; + virtual bool isIPv6() = 0; virtual void setWebsocketHandler(WebsocketHandler *wsHandler); virtual IPAddress getClientIP() = 0; + virtual IPv6Address getClientIPv6() = 0; WebsocketHandler * _wsHandler; }; diff --git a/src/HTTPConnection.cpp b/src/HTTPConnection.cpp index 0ab739c..a64f059 100644 --- a/src/HTTPConnection.cpp +++ b/src/HTTPConnection.cpp @@ -63,13 +63,25 @@ int HTTPConnection::initialize(int serverSocketID, HTTPHeaders *defaultHeaders) * Returns the client's IPv4 */ IPAddress HTTPConnection::getClientIP() { - if (_addrLen > 0 && _sockAddr.sa_family == AF_INET) { + if (_addrLen > 0 && _sockAddr.ss_family == AF_INET) { struct sockaddr_in *sockAddrIn = (struct sockaddr_in *)(&_sockAddr); return IPAddress(sockAddrIn->sin_addr.s_addr); } return IPAddress(0, 0, 0, 0); } +/** + * Returns the client's IPv6 + */ +IPv6Address HTTPConnection::getClientIPv6() { + if (_addrLen > 0 && _sockAddr.ss_family == AF_INET6) { + struct sockaddr_in6 *sockAddrIn6 = (struct sockaddr_in6 *)(&_sockAddr); + return IPv6Address(sockAddrIn6->sin6_addr.s6_addr); + } + const in6_addr address = { 0 }; + return IPv6Address(address.s6_addr); +} + /** * True if the connection is timed out. * @@ -104,6 +116,20 @@ bool HTTPConnection::isSecure() { return false; } +/** + * Returns true if the connection is using IPv6 + */ +bool HTTPConnection::isIPv6() { + if (_addrLen > 0 && _sockAddr.ss_family == AF_INET6) { + // Using IPv6 + return true; + } else if (_addrLen > 0 && _sockAddr.ss_family == AF_INET) { + // Using IPv4 + return false; + } + return false; +} + void HTTPConnection::closeConnection() { // TODO: Call an event handler here, maybe? diff --git a/src/HTTPConnection.hpp b/src/HTTPConnection.hpp index fb15d7a..1757b54 100644 --- a/src/HTTPConnection.hpp +++ b/src/HTTPConnection.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -43,7 +44,9 @@ class HTTPConnection : private ConnectionContext { virtual int initialize(int serverSocketID, HTTPHeaders *defaultHeaders); virtual void closeConnection(); virtual bool isSecure(); + virtual bool isIPv6(); virtual IPAddress getClientIP(); + virtual IPv6Address getClientIPv6(); void loop(); bool isClosed(); @@ -133,7 +136,7 @@ class HTTPConnection : private ConnectionContext { int _bufferUnusedIdx; // Socket address, length etc for the connection - struct sockaddr _sockAddr; + struct sockaddr_storage _sockAddr; socklen_t _addrLen; int _socket; diff --git a/src/HTTPRequest.cpp b/src/HTTPRequest.cpp index 2a83a09..72e41a5 100644 --- a/src/HTTPRequest.cpp +++ b/src/HTTPRequest.cpp @@ -61,6 +61,10 @@ IPAddress HTTPRequest::getClientIP() { return _con->getClientIP(); } +IPv6Address HTTPRequest::getClientIPv6() { + return _con->getClientIPv6(); +} + size_t HTTPRequest::readBytes(byte * buffer, size_t length) { // Limit reading to content length @@ -177,6 +181,9 @@ bool HTTPRequest::isSecure() { return _con->isSecure(); } +bool HTTPRequest::isIPv6() { + return _con->isIPv6(); +} void HTTPRequest::setWebsocketHandler(WebsocketHandler *wsHandler) { _con->setWebsocketHandler(wsHandler); diff --git a/src/HTTPRequest.hpp b/src/HTTPRequest.hpp index 7184180..0c33a8e 100644 --- a/src/HTTPRequest.hpp +++ b/src/HTTPRequest.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -31,6 +32,7 @@ class HTTPRequest { std::string getMethod(); std::string getTag(); IPAddress getClientIP(); + IPv6Address getClientIPv6(); size_t readChars(char * buffer, size_t length); size_t readBytes(byte * buffer, size_t length); @@ -42,6 +44,7 @@ class HTTPRequest { std::string getBasicAuthUser(); std::string getBasicAuthPassword(); bool isSecure(); + bool isIPv6(); void setWebsocketHandler(WebsocketHandler *wsHandler); private: diff --git a/src/HTTPSServer.cpp b/src/HTTPSServer.cpp index 4d8352d..70089a1 100644 --- a/src/HTTPSServer.cpp +++ b/src/HTTPSServer.cpp @@ -3,6 +3,7 @@ namespace httpsserver { +// IPv4 HTTPSServer::HTTPSServer(SSLCert * cert, const uint16_t port, const uint8_t maxConnections, const in_addr_t bindAddress): HTTPServer(port, maxConnections, bindAddress), _cert(cert) { @@ -11,6 +12,15 @@ HTTPSServer::HTTPSServer(SSLCert * cert, const uint16_t port, const uint8_t maxC _sslctx = NULL; } +// IPv6 +HTTPSServer::HTTPSServer(SSLCert * cert, const uint16_t port, const uint8_t maxConnections, const uint8_t bindAddress[16], const bool ipv6Only): + HTTPServer(port, maxConnections, bindAddress, ipv6Only), + _cert(cert) { + + // Configure runtime data + _sslctx = NULL; +} + HTTPSServer::~HTTPSServer() { } diff --git a/src/HTTPSServer.hpp b/src/HTTPSServer.hpp index 68596bf..2438d02 100644 --- a/src/HTTPSServer.hpp +++ b/src/HTTPSServer.hpp @@ -29,7 +29,8 @@ namespace httpsserver { */ class HTTPSServer : public HTTPServer { public: - HTTPSServer(SSLCert * cert, const uint16_t portHTTPS = 443, const uint8_t maxConnections = 4, const in_addr_t bindAddress = 0); + HTTPSServer(SSLCert * cert, const uint16_t portHTTPS = 443, const uint8_t maxConnections = 4, const in_addr_t bindAddress = INADDR_ANY); + HTTPSServer(SSLCert * cert, const uint16_t portHTTPS, const uint8_t maxConnections, const uint8_t bindAddress[16], const bool ipv6Only); virtual ~HTTPSServer(); private: diff --git a/src/HTTPServer.cpp b/src/HTTPServer.cpp index 9705e0c..b66d1f8 100644 --- a/src/HTTPServer.cpp +++ b/src/HTTPServer.cpp @@ -3,10 +3,33 @@ namespace httpsserver { +// IPv4 HTTPServer::HTTPServer(const uint16_t port, const uint8_t maxConnections, const in_addr_t bindAddress): _port(port), _maxConnections(maxConnections), - _bindAddress(bindAddress) { + _useIPv6(false), + _useIPv6Only(false) { + + _bindAddress.ipv4bindAddress.s_addr = bindAddress; + + // Create space for the connections + _connections = new HTTPConnection*[maxConnections]; + for(uint8_t i = 0; i < maxConnections; i++) _connections[i] = NULL; + + // Configure runtime data + _socket = -1; + _running = false; +} + +// IPv6 with bindAddress +HTTPServer::HTTPServer(const uint16_t port, const uint8_t maxConnections, const uint8_t bindAddress[16], const bool ipv6Only): + _port(port), + _maxConnections(maxConnections), + //Enable Ipv6 + _useIPv6(true), + _useIPv6Only(ipv6Only) { + + memcpy(_bindAddress.ipv6bindAddress.s6_addr, bindAddress, 16); // Create space for the connections _connections = new HTTPConnection*[maxConnections]; @@ -168,18 +191,47 @@ int HTTPServer::createConnection(int idx) { * This method prepares the tcp server socket */ uint8_t HTTPServer::setupSocket() { - // (AF_INET = IPv4, SOCK_STREAM = TCP) - _socket = socket(AF_INET, SOCK_STREAM, 0); + // Initialize socket + if (_useIPv6) { + // (AF_INET = IPv6, SOCK_STREAM = TCP) + _socket = socket(AF_INET6, SOCK_STREAM, 0); + + if (_useIPv6Only) { + // Set the correct flag on the socket + int on = 1; + if (setsockopt(_socket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on)) == -1) { + // Return error if we couldn't set the socket option + return 0; + } + } + } else { + // (AF_INET6 = IPv4, SOCK_STREAM = TCP) + _socket = socket(AF_INET, SOCK_STREAM, 0); + } + // Initialize socket address if (_socket>=0) { - _sock_addr.sin_family = AF_INET; - // Listen on all interfaces - _sock_addr.sin_addr.s_addr = _bindAddress; - // Set the server port - _sock_addr.sin_port = htons(_port); + if (_useIPv6) { + // Not used but should be set to 0 according to spec + ((struct sockaddr_in6 *)&_sock_addr)->sin6_flowinfo = 0; + // I could't find any codumentation about "sin6_scope_id" actually being implemented in lwIP + // The parameter "sin6_len" shouldn't be needed either + + ((struct sockaddr_in6 *)&_sock_addr)->sin6_family = AF_INET6; + // Listen on all interfaces + ((struct sockaddr_in6 *)&_sock_addr)->sin6_addr = _bindAddress.ipv6bindAddress; + // Set the server port + ((struct sockaddr_in6 *)&_sock_addr)->sin6_port = htons(_port); + } else { + ((struct sockaddr_in *)&_sock_addr)->sin_family = AF_INET; + // Listen on all interfaces + ((struct sockaddr_in *)&_sock_addr)->sin_addr = _bindAddress.ipv4bindAddress; + // Set the server port + ((struct sockaddr_in *)&_sock_addr)->sin_port = htons(_port); + } // Now bind the TCP socket we did create above to the socket address we specified - // (The TCP-socket now listens on 0.0.0.0:port) + // (The TCP-socket now listens on bindAddress:port) int err = bind(_socket, (struct sockaddr* )&_sock_addr, sizeof(_sock_addr)); if(!err) { err = listen(_socket, _maxConnections); diff --git a/src/HTTPServer.hpp b/src/HTTPServer.hpp index 47746c1..3891a2f 100644 --- a/src/HTTPServer.hpp +++ b/src/HTTPServer.hpp @@ -29,7 +29,8 @@ namespace httpsserver { */ class HTTPServer : public ResourceResolver { public: - HTTPServer(const uint16_t portHTTPS = 80, const uint8_t maxConnections = 8, const in_addr_t bindAddress = 0); + HTTPServer(const uint16_t portHTTPS = 80, const uint8_t maxConnections = 8, const in_addr_t bindAddress = INADDR_ANY); + HTTPServer(const uint16_t portHTTPS, const uint8_t maxConnections, const uint8_t bindAddress[16], const bool ipv6Only); virtual ~HTTPServer(); uint8_t start(); @@ -47,8 +48,15 @@ class HTTPServer : public ResourceResolver { // Max parallel connections that the server will accept const uint8_t _maxConnections; - // Address to bind to (0 = all interfaces) - const in_addr_t _bindAddress; + // Address to bind to (INADDR_ANY or IN6ADDR_ANY_INIT = all interfaces) + union bindAddressv4v6 { + struct in_addr ipv4bindAddress; + struct in6_addr ipv6bindAddress; + }; + bindAddressv4v6 _bindAddress; + // Internal flags for IPv6 support + const bool _useIPv6; + const bool _useIPv6Only; //// Runtime data ============================================ // The array of connections that are currently active @@ -59,7 +67,7 @@ class HTTPServer : public ResourceResolver { int _socket; // The server socket address, that our service is bound to - sockaddr_in _sock_addr; + sockaddr_storage _sock_addr; // Headers that are included in every response HTTPHeaders _defaultHeaders;