From 3247705c36c5f112ffd14269e3f50781d92bd8f8 Mon Sep 17 00:00:00 2001 From: bbourdel Date: Wed, 8 Nov 2017 15:05:51 +0100 Subject: [PATCH 1/6] Add method to stop HttpSever Have to be improved to free all RAM (heap) taken when HTTP server is created. --- Sming/SmingCore/Network/HttpServer.cpp | 21 ++++++++++++++++++++- Sming/SmingCore/Network/HttpServer.h | 5 ++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Sming/SmingCore/Network/HttpServer.cpp b/Sming/SmingCore/Network/HttpServer.cpp index fa2e2b8ae5..61b6308c30 100644 --- a/Sming/SmingCore/Network/HttpServer.cpp +++ b/Sming/SmingCore/Network/HttpServer.cpp @@ -17,12 +17,14 @@ HttpServer::HttpServer() { + active = true; settings.keepAliveSeconds = 0; configure(settings); } HttpServer::HttpServer(HttpServerSettings settings) { + active = true; configure(settings); } @@ -44,6 +46,7 @@ void HttpServer::configure(HttpServerSettings settings) { HttpServer::~HttpServer() { + active = true; for(int i=0; i< resourceTree.count(); i++) { if(resourceTree.valueAt(i) != NULL) { delete resourceTree.valueAt(i); @@ -99,7 +102,23 @@ void HttpServer::setDefaultResource(HttpResource* resource) { addPath("*", resource); } +void HttpServer::close() { + active = false; + if(totalConnections==0){ + debugf("Closing server"); + delete this; + } + else{ + debugf("Wait end connection before closing server"); + } +} + + void HttpServer::onConnectionClose(TcpClient& connection, bool success) { totalConnections--; + if(totalConnections==0 && !active){ + debugf("Closing server"); + delete this; + } debugf("Closing connection. Total connections: %d", totalConnections); -} +} \ No newline at end of file diff --git a/Sming/SmingCore/Network/HttpServer.h b/Sming/SmingCore/Network/HttpServer.h index 02f6c00c4a..53253bb5db 100644 --- a/Sming/SmingCore/Network/HttpServer.h +++ b/Sming/SmingCore/Network/HttpServer.h @@ -77,6 +77,8 @@ class HttpServer: public TcpServer void setDefaultHandler(const HttpPathDelegate& callback); void setDefaultResource(HttpResource* resource); + void close(); + protected: virtual TcpConnection* createClient(tcp_pcb *clientTcp); @@ -91,7 +93,8 @@ class HttpServer: public TcpServer HttpServerSettings settings; ResourceTree resourceTree; BodyParsers bodyParsers; + bool active = true; }; /** @} */ -#endif /* _SMING_CORE_HTTPSERVER_H_ */ +#endif /* _SMING_CORE_HTTPSERVER_H_ */ \ No newline at end of file From 603d2680c92bf6ffaa1d1e14d8a29f6b241fba9c Mon Sep 17 00:00:00 2001 From: Slavey Karadzhov Date: Wed, 8 Nov 2017 18:25:59 +0100 Subject: [PATCH 2/6] Stop accepting new connection when the server is shutting down. Force-close all connections. --- Sming/SmingCore/Network/HttpServer.cpp | 55 +++++++++++++++----------- Sming/SmingCore/Network/HttpServer.h | 7 ++-- 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/Sming/SmingCore/Network/HttpServer.cpp b/Sming/SmingCore/Network/HttpServer.cpp index 61b6308c30..be78396272 100644 --- a/Sming/SmingCore/Network/HttpServer.cpp +++ b/Sming/SmingCore/Network/HttpServer.cpp @@ -15,20 +15,19 @@ #include "TcpClient.h" #include "../Wiring/WString.h" -HttpServer::HttpServer() +HttpServer::HttpServer(): active(true) { - active = true; settings.keepAliveSeconds = 0; configure(settings); } -HttpServer::HttpServer(HttpServerSettings settings) +HttpServer::HttpServer(HttpServerSettings settings): active(true) { - active = true; configure(settings); } -void HttpServer::configure(HttpServerSettings settings) { +void HttpServer::configure(HttpServerSettings settings) +{ this->settings = settings; if(settings.minHeapSize != -1 && settings.minHeapSize > -1) { minHeapSize = settings.minHeapSize; @@ -61,12 +60,18 @@ void HttpServer::setBodyParser(const String& contentType, HttpBodyParserDelegate TcpConnection* HttpServer::createClient(tcp_pcb *clientTcp) { + if(!active) { + debugf("Refusing new connections. The server is shutting down"); + return NULL; + } + HttpServerConnection* con = new HttpServerConnection(clientTcp); con->setResourceTree(&resourceTree); con->setBodyParsers(&bodyParsers); con->setCompleteDelegate(TcpClientCompleteDelegate(&HttpServer::onConnectionClose, this)); - totalConnections++; + connections.add(con); + totalConnections = connections.count(); debugf("Opening connection. Total connections: %d", totalConnections); return con; @@ -88,37 +93,43 @@ void HttpServer::setDefaultHandler(const HttpPathDelegate& callback) addPath("*", callback); } -void HttpServer::addPath(const String& path, const HttpResourceDelegate& onRequestComplete) { +void HttpServer::addPath(const String& path, const HttpResourceDelegate& onRequestComplete) +{ HttpResource* resource = new HttpResource; resource->onRequestComplete = onRequestComplete; resourceTree[path] = resource; } -void HttpServer::addPath(const String& path, HttpResource* resource) { +void HttpServer::addPath(const String& path, HttpResource* resource) +{ resourceTree[path] = resource; } -void HttpServer::setDefaultResource(HttpResource* resource) { +void HttpServer::setDefaultResource(HttpResource* resource) +{ addPath("*", resource); } -void HttpServer::close() { +void HttpServer::shutdown() +{ active = false; - if(totalConnections==0){ - debugf("Closing server"); - delete this; - } - else{ - debugf("Wait end connection before closing server"); + for(int i; i < connections.count(); i++) { + HttpServerConnection* connection = connections[i]; + if(connection == NULL) { + continue; + } + + connection->close(); } } - -void HttpServer::onConnectionClose(TcpClient& connection, bool success) { - totalConnections--; - if(totalConnections==0 && !active){ - debugf("Closing server"); +void HttpServer::onConnectionClose(TcpClient& connection, bool success) +{ + connections.removeElement((HttpServerConnection*)&connection); + totalConnections = connections.count(); + if(totalConnections == 0 && !active){ + debugf("Shutting down the Http Server"); delete this; } debugf("Closing connection. Total connections: %d", totalConnections); -} \ No newline at end of file +} diff --git a/Sming/SmingCore/Network/HttpServer.h b/Sming/SmingCore/Network/HttpServer.h index 53253bb5db..c24f2d00a4 100644 --- a/Sming/SmingCore/Network/HttpServer.h +++ b/Sming/SmingCore/Network/HttpServer.h @@ -77,8 +77,7 @@ class HttpServer: public TcpServer void setDefaultHandler(const HttpPathDelegate& callback); void setDefaultResource(HttpResource* resource); - void close(); - + void shutdown(); protected: virtual TcpConnection* createClient(tcp_pcb *clientTcp); @@ -94,7 +93,9 @@ class HttpServer: public TcpServer ResourceTree resourceTree; BodyParsers bodyParsers; bool active = true; + + Vector connections; }; /** @} */ -#endif /* _SMING_CORE_HTTPSERVER_H_ */ \ No newline at end of file +#endif /* _SMING_CORE_HTTPSERVER_H_ */ From 09ee2b4f51a733793af731c21062a79293a31bf2 Mon Sep 17 00:00:00 2001 From: Slavey Karadzhov Date: Wed, 8 Nov 2017 19:08:20 +0100 Subject: [PATCH 3/6] Only listening tcp's should be polled. Fixes segfault with HttpServer::shutdown(); --- Sming/SmingCore/Network/HttpServer.cpp | 2 +- Sming/SmingCore/Network/TcpConnection.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Sming/SmingCore/Network/HttpServer.cpp b/Sming/SmingCore/Network/HttpServer.cpp index be78396272..1808a91244 100644 --- a/Sming/SmingCore/Network/HttpServer.cpp +++ b/Sming/SmingCore/Network/HttpServer.cpp @@ -113,7 +113,7 @@ void HttpServer::setDefaultResource(HttpResource* resource) void HttpServer::shutdown() { active = false; - for(int i; i < connections.count(); i++) { + for(int i=0; i < connections.count(); i++) { HttpServerConnection* connection = connections[i]; if(connection == NULL) { continue; diff --git a/Sming/SmingCore/Network/TcpConnection.cpp b/Sming/SmingCore/Network/TcpConnection.cpp index f29399a53e..0f1b6b0874 100644 --- a/Sming/SmingCore/Network/TcpConnection.cpp +++ b/Sming/SmingCore/Network/TcpConnection.cpp @@ -309,7 +309,9 @@ void TcpConnection::close() axl_free(tcp); #endif - tcp_poll(tcp, staticOnPoll, 1); + if(tcp->state == LISTEN) { + tcp_poll(tcp, staticOnPoll, 1); + } tcp_arg(tcp, NULL); // reset pointer to close connection on next callback tcp = NULL; From 15ffb5ee5d0004e1aec69f9a257e6671bda10964 Mon Sep 17 00:00:00 2001 From: Slavey Karadzhov Date: Thu, 9 Nov 2017 15:02:55 +0100 Subject: [PATCH 4/6] Delete the server only after all connections are closed and deleted. --- .../Network/Http/HttpServerConnection.cpp | 9 +++++++ .../Network/Http/HttpServerConnection.h | 11 ++++++++ Sming/SmingCore/Network/HttpServer.cpp | 25 +++++++++++++++++-- Sming/SmingCore/Network/HttpServer.h | 1 + Sming/SmingCore/Network/TcpConnection.cpp | 4 +-- 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/Sming/SmingCore/Network/Http/HttpServerConnection.cpp b/Sming/SmingCore/Network/Http/HttpServerConnection.cpp index 3baa6afdf9..209e06c4c6 100644 --- a/Sming/SmingCore/Network/Http/HttpServerConnection.cpp +++ b/Sming/SmingCore/Network/Http/HttpServerConnection.cpp @@ -49,6 +49,10 @@ HttpServerConnection::~HttpServerConnection() if(this->resource) { this->resource->shutdown(*this); } + + if(destroyedDelegate) { + destroyedDelegate(); + } } void HttpServerConnection::setResourceTree(ResourceTree* resourceTree) @@ -543,3 +547,8 @@ void HttpServerConnection::sendError(const char* message /* = NULL*/, enum http_ send(); } + +void HttpServerConnection::setDestroyedDelegate(HttpServerConnectionDestroyedDelegate destroyedDelegate) +{ + this->destroyedDelegate = destroyedDelegate; +} diff --git a/Sming/SmingCore/Network/Http/HttpServerConnection.h b/Sming/SmingCore/Network/Http/HttpServerConnection.h index 534df786d5..afc74ba90e 100644 --- a/Sming/SmingCore/Network/Http/HttpServerConnection.h +++ b/Sming/SmingCore/Network/Http/HttpServerConnection.h @@ -33,6 +33,8 @@ class HttpServerConnection; typedef Delegate HttpServerConnectionDelegate; +typedef Delegate HttpServerConnectionDestroyedDelegate; + class HttpServerConnection: public TcpClient { @@ -47,6 +49,13 @@ class HttpServerConnection: public TcpClient using TcpClient::send; + /** + * Sets a callback to be called when the object instance is destroyed + * + * @param HttpServerConnectionDestroyedDelegate destroyedDelegate - callback + */ + void setDestroyedDelegate(HttpServerConnectionDestroyedDelegate destroyedDelegate); + protected: virtual err_t onReceive(pbuf *buf); virtual void onReadyToSendData(TcpConnectionEvent sourceEvent); @@ -94,6 +103,8 @@ class HttpServerConnection: public TcpClient BodyParsers* bodyParsers = NULL; HttpBodyParserDelegate bodyParser; + + HttpServerConnectionDestroyedDelegate destroyedDelegate = 0; }; #endif /* _SMING_CORE_HTTPSERVERCONNECTION_H_ */ diff --git a/Sming/SmingCore/Network/HttpServer.cpp b/Sming/SmingCore/Network/HttpServer.cpp index 1808a91244..57d3996a4f 100644 --- a/Sming/SmingCore/Network/HttpServer.cpp +++ b/Sming/SmingCore/Network/HttpServer.cpp @@ -69,6 +69,7 @@ TcpConnection* HttpServer::createClient(tcp_pcb *clientTcp) con->setResourceTree(&resourceTree); con->setBodyParsers(&bodyParsers); con->setCompleteDelegate(TcpClientCompleteDelegate(&HttpServer::onConnectionClose, this)); + con->setDestroyedDelegate(HttpServerConnectionDestroyedDelegate(&HttpServer::onClientDestroy, this)); connections.add(con); totalConnections = connections.count(); @@ -113,6 +114,15 @@ void HttpServer::setDefaultResource(HttpResource* resource) void HttpServer::shutdown() { active = false; + + if(tcp) { + tcp_arg(tcp, NULL); + tcp_accept(tcp, NULL); + tcp_close(tcp); + + tcp = NULL; + } + for(int i=0; i < connections.count(); i++) { HttpServerConnection* connection = connections[i]; if(connection == NULL) { @@ -123,13 +133,24 @@ void HttpServer::shutdown() } } +void HttpServer::onClientDestroy() +{ + if(active) { + return; + } + + if(connections.count() == 0) { + debugf("Http Server will be destroyed."); + delete this; + } +} + void HttpServer::onConnectionClose(TcpClient& connection, bool success) { connections.removeElement((HttpServerConnection*)&connection); totalConnections = connections.count(); if(totalConnections == 0 && !active){ - debugf("Shutting down the Http Server"); - delete this; + debugf("Shutting down the Http Server ..."); } debugf("Closing connection. Total connections: %d", totalConnections); } diff --git a/Sming/SmingCore/Network/HttpServer.h b/Sming/SmingCore/Network/HttpServer.h index c24f2d00a4..b3aca483d0 100644 --- a/Sming/SmingCore/Network/HttpServer.h +++ b/Sming/SmingCore/Network/HttpServer.h @@ -82,6 +82,7 @@ class HttpServer: public TcpServer protected: virtual TcpConnection* createClient(tcp_pcb *clientTcp); virtual void onConnectionClose(TcpClient& connection, bool success); + virtual void onClientDestroy(); protected: #ifdef ENABLE_SSL diff --git a/Sming/SmingCore/Network/TcpConnection.cpp b/Sming/SmingCore/Network/TcpConnection.cpp index 0f1b6b0874..f29399a53e 100644 --- a/Sming/SmingCore/Network/TcpConnection.cpp +++ b/Sming/SmingCore/Network/TcpConnection.cpp @@ -309,9 +309,7 @@ void TcpConnection::close() axl_free(tcp); #endif - if(tcp->state == LISTEN) { - tcp_poll(tcp, staticOnPoll, 1); - } + tcp_poll(tcp, staticOnPoll, 1); tcp_arg(tcp, NULL); // reset pointer to close connection on next callback tcp = NULL; From 1f0257ad2a5c0697704ae8c775a7f02e000e932f Mon Sep 17 00:00:00 2001 From: Slavey Karadzhov Date: Thu, 9 Nov 2017 16:06:58 +0100 Subject: [PATCH 5/6] Added command to test remotely server shutdown. The shutdown uses timeouts to "gracefully" close the client connections. --- Sming/SmingCore/Network/HttpServer.cpp | 2 +- samples/HttpServer_WebSockets/app/application.cpp | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Sming/SmingCore/Network/HttpServer.cpp b/Sming/SmingCore/Network/HttpServer.cpp index 57d3996a4f..2dd589e854 100644 --- a/Sming/SmingCore/Network/HttpServer.cpp +++ b/Sming/SmingCore/Network/HttpServer.cpp @@ -129,7 +129,7 @@ void HttpServer::shutdown() continue; } - connection->close(); + connection->setTimeOut(1); } } diff --git a/samples/HttpServer_WebSockets/app/application.cpp b/samples/HttpServer_WebSockets/app/application.cpp index 24876d8b7a..3ed79853f5 100644 --- a/samples/HttpServer_WebSockets/app/application.cpp +++ b/samples/HttpServer_WebSockets/app/application.cpp @@ -52,6 +52,14 @@ void wsConnected(WebSocketConnection& socket) void wsMessageReceived(WebSocketConnection& socket, const String& message) { Serial.printf("WebSocket message received:\r\n%s\r\n", message.c_str()); + + if(message == "shutdown") { + String message = "The server is shutting down..."; + socket.broadcast(message.c_str(), message.length()); + server.shutdown(); + return; + } + String response = "Echo: " + message; socket.sendString(response); From 26ed09808b57442914bfa2e560117d8bbdbd2d0e Mon Sep 17 00:00:00 2001 From: Slavey Karadzhov Date: Thu, 9 Nov 2017 17:48:32 +0100 Subject: [PATCH 6/6] Moved the general server code from HttpServer to TcpServer. It should be possible to shut down cleanly all servers that inherit from TcpServer. --- .../Network/Http/HttpServerConnection.cpp | 9 --- .../Network/Http/HttpServerConnection.h | 11 ---- Sming/SmingCore/Network/HttpServer.cpp | 60 +------------------ Sming/SmingCore/Network/HttpServer.h | 7 --- Sming/SmingCore/Network/TcpConnection.cpp | 30 +++++++--- Sming/SmingCore/Network/TcpConnection.h | 13 ++++ Sming/SmingCore/Network/TcpServer.cpp | 55 ++++++++++++++++- Sming/SmingCore/Network/TcpServer.h | 8 ++- 8 files changed, 98 insertions(+), 95 deletions(-) diff --git a/Sming/SmingCore/Network/Http/HttpServerConnection.cpp b/Sming/SmingCore/Network/Http/HttpServerConnection.cpp index 209e06c4c6..3baa6afdf9 100644 --- a/Sming/SmingCore/Network/Http/HttpServerConnection.cpp +++ b/Sming/SmingCore/Network/Http/HttpServerConnection.cpp @@ -49,10 +49,6 @@ HttpServerConnection::~HttpServerConnection() if(this->resource) { this->resource->shutdown(*this); } - - if(destroyedDelegate) { - destroyedDelegate(); - } } void HttpServerConnection::setResourceTree(ResourceTree* resourceTree) @@ -547,8 +543,3 @@ void HttpServerConnection::sendError(const char* message /* = NULL*/, enum http_ send(); } - -void HttpServerConnection::setDestroyedDelegate(HttpServerConnectionDestroyedDelegate destroyedDelegate) -{ - this->destroyedDelegate = destroyedDelegate; -} diff --git a/Sming/SmingCore/Network/Http/HttpServerConnection.h b/Sming/SmingCore/Network/Http/HttpServerConnection.h index afc74ba90e..534df786d5 100644 --- a/Sming/SmingCore/Network/Http/HttpServerConnection.h +++ b/Sming/SmingCore/Network/Http/HttpServerConnection.h @@ -33,8 +33,6 @@ class HttpServerConnection; typedef Delegate HttpServerConnectionDelegate; -typedef Delegate HttpServerConnectionDestroyedDelegate; - class HttpServerConnection: public TcpClient { @@ -49,13 +47,6 @@ class HttpServerConnection: public TcpClient using TcpClient::send; - /** - * Sets a callback to be called when the object instance is destroyed - * - * @param HttpServerConnectionDestroyedDelegate destroyedDelegate - callback - */ - void setDestroyedDelegate(HttpServerConnectionDestroyedDelegate destroyedDelegate); - protected: virtual err_t onReceive(pbuf *buf); virtual void onReadyToSendData(TcpConnectionEvent sourceEvent); @@ -103,8 +94,6 @@ class HttpServerConnection: public TcpClient BodyParsers* bodyParsers = NULL; HttpBodyParserDelegate bodyParser; - - HttpServerConnectionDestroyedDelegate destroyedDelegate = 0; }; #endif /* _SMING_CORE_HTTPSERVERCONNECTION_H_ */ diff --git a/Sming/SmingCore/Network/HttpServer.cpp b/Sming/SmingCore/Network/HttpServer.cpp index 2dd589e854..9ad31c89ee 100644 --- a/Sming/SmingCore/Network/HttpServer.cpp +++ b/Sming/SmingCore/Network/HttpServer.cpp @@ -15,13 +15,13 @@ #include "TcpClient.h" #include "../Wiring/WString.h" -HttpServer::HttpServer(): active(true) +HttpServer::HttpServer() { settings.keepAliveSeconds = 0; configure(settings); } -HttpServer::HttpServer(HttpServerSettings settings): active(true) +HttpServer::HttpServer(HttpServerSettings settings) { configure(settings); } @@ -45,7 +45,6 @@ void HttpServer::configure(HttpServerSettings settings) HttpServer::~HttpServer() { - active = true; for(int i=0; i< resourceTree.count(); i++) { if(resourceTree.valueAt(i) != NULL) { delete resourceTree.valueAt(i); @@ -60,20 +59,9 @@ void HttpServer::setBodyParser(const String& contentType, HttpBodyParserDelegate TcpConnection* HttpServer::createClient(tcp_pcb *clientTcp) { - if(!active) { - debugf("Refusing new connections. The server is shutting down"); - return NULL; - } - HttpServerConnection* con = new HttpServerConnection(clientTcp); con->setResourceTree(&resourceTree); con->setBodyParsers(&bodyParsers); - con->setCompleteDelegate(TcpClientCompleteDelegate(&HttpServer::onConnectionClose, this)); - con->setDestroyedDelegate(HttpServerConnectionDestroyedDelegate(&HttpServer::onClientDestroy, this)); - - connections.add(con); - totalConnections = connections.count(); - debugf("Opening connection. Total connections: %d", totalConnections); return con; } @@ -110,47 +98,3 @@ void HttpServer::setDefaultResource(HttpResource* resource) { addPath("*", resource); } - -void HttpServer::shutdown() -{ - active = false; - - if(tcp) { - tcp_arg(tcp, NULL); - tcp_accept(tcp, NULL); - tcp_close(tcp); - - tcp = NULL; - } - - for(int i=0; i < connections.count(); i++) { - HttpServerConnection* connection = connections[i]; - if(connection == NULL) { - continue; - } - - connection->setTimeOut(1); - } -} - -void HttpServer::onClientDestroy() -{ - if(active) { - return; - } - - if(connections.count() == 0) { - debugf("Http Server will be destroyed."); - delete this; - } -} - -void HttpServer::onConnectionClose(TcpClient& connection, bool success) -{ - connections.removeElement((HttpServerConnection*)&connection); - totalConnections = connections.count(); - if(totalConnections == 0 && !active){ - debugf("Shutting down the Http Server ..."); - } - debugf("Closing connection. Total connections: %d", totalConnections); -} diff --git a/Sming/SmingCore/Network/HttpServer.h b/Sming/SmingCore/Network/HttpServer.h index b3aca483d0..f688aa80ec 100644 --- a/Sming/SmingCore/Network/HttpServer.h +++ b/Sming/SmingCore/Network/HttpServer.h @@ -77,12 +77,8 @@ class HttpServer: public TcpServer void setDefaultHandler(const HttpPathDelegate& callback); void setDefaultResource(HttpResource* resource); - void shutdown(); - protected: virtual TcpConnection* createClient(tcp_pcb *clientTcp); - virtual void onConnectionClose(TcpClient& connection, bool success); - virtual void onClientDestroy(); protected: #ifdef ENABLE_SSL @@ -93,9 +89,6 @@ class HttpServer: public TcpServer HttpServerSettings settings; ResourceTree resourceTree; BodyParsers bodyParsers; - bool active = true; - - Vector connections; }; /** @} */ diff --git a/Sming/SmingCore/Network/TcpConnection.cpp b/Sming/SmingCore/Network/TcpConnection.cpp index f29399a53e..aa9d342ba9 100644 --- a/Sming/SmingCore/Network/TcpConnection.cpp +++ b/Sming/SmingCore/Network/TcpConnection.cpp @@ -38,6 +38,10 @@ TcpConnection::~TcpConnection() freeSslClientKeyCert(); #endif debugf("~TCP connection"); + + if(destroyedDelegate) { + destroyedDelegate(*this); + } } bool TcpConnection::connect(String server, int port, bool useSsl /* = false */, uint32_t sslOptions /* = 0 */) @@ -698,12 +702,19 @@ void TcpConnection::staticDnsResponse(const char *name, ip_addr_t *ipaddr, void delete dlook; } +void TcpConnection::setDestroyedDelegate(TcpConnectionDestroyedDelegate destroyedDelegate) +{ + this->destroyedDelegate = destroyedDelegate; +} + #ifdef ENABLE_SSL -void TcpConnection::addSslOptions(uint32_t sslOptions) { +void TcpConnection::addSslOptions(uint32_t sslOptions) +{ this->sslOptions |= sslOptions; } -bool TcpConnection::pinCertificate(const uint8_t *fingerprint, SslFingerprintType type, bool freeAfterHandshake /* = false */) { +bool TcpConnection::pinCertificate(const uint8_t *fingerprint, SslFingerprintType type, bool freeAfterHandshake /* = false */) +{ int length = 0; uint8_t *localStore; @@ -749,7 +760,8 @@ bool TcpConnection::pinCertificate(const uint8_t *fingerprint, SslFingerprintTyp return true; } -bool TcpConnection::pinCertificate(SSLFingerprints fingerprints, bool freeAfterHandshake /* = false */) { +bool TcpConnection::pinCertificate(SSLFingerprints fingerprints, bool freeAfterHandshake /* = false */) +{ sslFingerprint = fingerprints; freeFingerprints = freeAfterHandshake; return true; @@ -757,7 +769,8 @@ bool TcpConnection::pinCertificate(SSLFingerprints fingerprints, bool freeAfterH bool TcpConnection::setSslClientKeyCert(const uint8_t *key, int keyLength, const uint8_t *certificate, int certificateLength, - const char *keyPassword /* = NULL */, bool freeAfterHandshake /* = false */) { + const char *keyPassword /* = NULL */, bool freeAfterHandshake /* = false */) +{ clientKeyCert.key = new uint8_t[keyLength]; @@ -785,14 +798,16 @@ bool TcpConnection::setSslClientKeyCert(const uint8_t *key, int keyLength, return true; } -bool TcpConnection::setSslClientKeyCert(SSLKeyCertPair clientKeyCert, bool freeAfterHandshake /* = false */) { +bool TcpConnection::setSslClientKeyCert(SSLKeyCertPair clientKeyCert, bool freeAfterHandshake /* = false */) +{ this->clientKeyCert = clientKeyCert; freeClientKeyCert = freeAfterHandshake; return true; } -void TcpConnection::freeSslClientKeyCert() { +void TcpConnection::freeSslClientKeyCert() +{ if(clientKeyCert.key) { delete[] clientKeyCert.key; clientKeyCert.key = NULL; @@ -812,7 +827,8 @@ void TcpConnection::freeSslClientKeyCert() { clientKeyCert.certificateLength = 0; } -void TcpConnection::freeSslFingerprints() { +void TcpConnection::freeSslFingerprints() +{ if(sslFingerprint.certSha1) { delete[] sslFingerprint.certSha1; sslFingerprint.certSha1 = NULL; diff --git a/Sming/SmingCore/Network/TcpConnection.h b/Sming/SmingCore/Network/TcpConnection.h index a902e3b55a..932e4dc7fe 100644 --- a/Sming/SmingCore/Network/TcpConnection.h +++ b/Sming/SmingCore/Network/TcpConnection.h @@ -20,6 +20,7 @@ #include "../Wiring/WiringFrameworkDependencies.h" #include "IPAddress.h" +#include "../Delegate.h" #define NETWORK_DEBUG @@ -71,6 +72,9 @@ class String; class IDataSourceStream; class IPAddress; class TcpServer; +class TcpConnection; + +typedef Delegate TcpConnectionDestroyedDelegate; class TcpConnection { @@ -99,6 +103,12 @@ class TcpConnection IPAddress getRemoteIp() { return (tcp == NULL) ? INADDR_NONE : IPAddress(tcp->remote_ip);}; uint16_t getRemotePort() { return (tcp == NULL) ? 0 : tcp->remote_port; }; + /** + * @brief Sets a callback to be called when the object instance is destroyed + * @param TcpServerConnectionDestroyedDelegate destroyedDelegate - callback + */ + void setDestroyedDelegate(TcpConnectionDestroyedDelegate destroyedDelegate); + #ifdef ENABLE_SSL void addSslOptions(uint32_t sslOptions); @@ -234,6 +244,9 @@ class TcpConnection SSLSessionId* sslSessionId = NULL; #endif bool useSsl = false; + +private: + TcpConnectionDestroyedDelegate destroyedDelegate = 0; }; /** @} */ diff --git a/Sming/SmingCore/Network/TcpServer.cpp b/Sming/SmingCore/Network/TcpServer.cpp index 828d725563..32362f2d70 100644 --- a/Sming/SmingCore/Network/TcpServer.cpp +++ b/Sming/SmingCore/Network/TcpServer.cpp @@ -63,6 +63,11 @@ TcpConnection* TcpServer::createClient(tcp_pcb *clientTcp) debugf("TCP Server createClient not NULL"); } + if(!active) { + debugf("Refusing new connections. The server is shutting down"); + return NULL; + } + TcpConnection* con = new TcpClient(clientTcp, TcpClientDataDelegate(&TcpServer::onClientReceive,this), TcpClientCompleteDelegate(&TcpServer::onClientComplete,this)); @@ -83,7 +88,8 @@ void TcpServer::setTimeOut(uint16_t waitTimeOut) } #ifdef ENABLE_SSL -void TcpServer::setServerKeyCert(SSLKeyCertPair serverKeyCert) { +void TcpServer::setServerKeyCert(SSLKeyCertPair serverKeyCert) +{ clientKeyCert = serverKeyCert; } #endif @@ -148,7 +154,7 @@ err_t TcpServer::onAccept(tcp_pcb *clientTcp, err_t err) } #ifdef NETWORK_DEBUG - debugf("onAccept state: %d K=%d", err, totalConnections); + debugf("onAccept state: %d K=%d", err, connections.count()); list_mem(); #endif @@ -177,6 +183,11 @@ err_t TcpServer::onAccept(tcp_pcb *clientTcp, err_t err) } #endif + client->setDestroyedDelegate(TcpConnectionDestroyedDelegate(&TcpServer::onClientDestroy, this)); + + connections.add(client); + debugf("Opening connection. Total connections: %d", connections.count()); + onClient((TcpClient*)client); return ERR_OK; @@ -231,3 +242,43 @@ err_t TcpServer::staticAccept(void *arg, tcp_pcb *new_tcp, err_t err) err_t res = con->onAccept(new_tcp, err); return res; } + + +void TcpServer::shutdown() +{ + active = false; + + debugf("Shutting down the server ..."); + + if(tcp) { + tcp_arg(tcp, NULL); + tcp_accept(tcp, NULL); + tcp_close(tcp); + + tcp = NULL; + } + + for(int i=0; i < connections.count(); i++) { + TcpConnection* connection = connections[i]; + if(connection == NULL) { + continue; + } + + connection->setTimeOut(1); + } +} + +void TcpServer::onClientDestroy(TcpConnection& connection) +{ + connections.removeElement((TcpConnection*)&connection); + debugf("Destroying connection. Total connections: %d", connections.count()); + + if(active) { + return; + } + + if(connections.count() == 0) { + debugf("Server is destroyed."); + delete this; + } +} diff --git a/Sming/SmingCore/Network/TcpServer.h b/Sming/SmingCore/Network/TcpServer.h index f70d69b171..39e88d36a4 100644 --- a/Sming/SmingCore/Network/TcpServer.h +++ b/Sming/SmingCore/Network/TcpServer.h @@ -33,6 +33,8 @@ class TcpServer: public TcpConnection { virtual bool listen(int port, bool useSsl = false); void setTimeOut(uint16_t waitTimeOut); + void shutdown(); + #ifdef ENABLE_SSL /** * @brief Adds SSL support and specifies the server certificate and private key. @@ -46,8 +48,9 @@ class TcpServer: public TcpConnection { virtual err_t onAccept(tcp_pcb *clientTcp, err_t err); virtual void onClient(TcpClient *client); - virtual void onClientComplete(TcpClient& client, bool succesfull); virtual bool onClientReceive (TcpClient& client, char *data, int size); + virtual void onClientComplete(TcpClient& client, bool succesfull); + virtual void onClientDestroy(TcpConnection& connection); static err_t staticAccept(void *arg, tcp_pcb *new_tcp, err_t err); @@ -62,6 +65,9 @@ class TcpServer: public TcpConnection { int sslSessionCacheSize = 50; #endif + bool active = true; + Vector connections; + private: uint16_t timeOut; TcpClientDataDelegate clientReceiveDelegate = NULL;