Skip to content

Commit

Permalink
Allow shutting down of TcpServers (#1284)
Browse files Browse the repository at this point in the history
* Delete the server only after all connections are closed and deleted.
* Added command to test remotely server shutdown.
* It should be possible to shut down cleanly all servers that inherit from TcpServer.
  • Loading branch information
slaff authored Nov 11, 2017
1 parent 89ac9a7 commit 30e7d6b
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 25 deletions.
21 changes: 8 additions & 13 deletions Sming/SmingCore/Network/HttpServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ HttpServer::HttpServer(HttpServerSettings settings)
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;
Expand Down Expand Up @@ -61,10 +62,6 @@ TcpConnection* HttpServer::createClient(tcp_pcb *clientTcp)
HttpServerConnection* con = new HttpServerConnection(clientTcp);
con->setResourceTree(&resourceTree);
con->setBodyParsers(&bodyParsers);
con->setCompleteDelegate(TcpClientCompleteDelegate(&HttpServer::onConnectionClose, this));

totalConnections++;
debugf("Opening connection. Total connections: %d", totalConnections);

return con;
}
Expand All @@ -85,21 +82,19 @@ 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::onConnectionClose(TcpClient& connection, bool success) {
totalConnections--;
debugf("Closing connection. Total connections: %d", totalConnections);
}
2 changes: 0 additions & 2 deletions Sming/SmingCore/Network/HttpServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,8 @@ class HttpServer: public TcpServer
void setDefaultHandler(const HttpPathDelegate& callback);
void setDefaultResource(HttpResource* resource);


protected:
virtual TcpConnection* createClient(tcp_pcb *clientTcp);
virtual void onConnectionClose(TcpClient& connection, bool success);

protected:
#ifdef ENABLE_SSL
Expand Down
30 changes: 23 additions & 7 deletions Sming/SmingCore/Network/TcpConnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 */)
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -749,15 +760,17 @@ 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;
}

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];
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
13 changes: 13 additions & 0 deletions Sming/SmingCore/Network/TcpConnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include "../Wiring/WiringFrameworkDependencies.h"
#include "IPAddress.h"
#include "../Delegate.h"


#define NETWORK_DEBUG
Expand Down Expand Up @@ -71,6 +72,9 @@ class String;
class IDataSourceStream;
class IPAddress;
class TcpServer;
class TcpConnection;

typedef Delegate<void(TcpConnection&)> TcpConnectionDestroyedDelegate;

class TcpConnection
{
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -234,6 +244,9 @@ class TcpConnection
SSLSessionId* sslSessionId = NULL;
#endif
bool useSsl = false;

private:
TcpConnectionDestroyedDelegate destroyedDelegate = 0;
};

/** @} */
Expand Down
55 changes: 53 additions & 2 deletions Sming/SmingCore/Network/TcpServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
}
8 changes: 7 additions & 1 deletion Sming/SmingCore/Network/TcpServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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);

Expand All @@ -62,6 +65,9 @@ class TcpServer: public TcpConnection {
int sslSessionCacheSize = 50;
#endif

bool active = true;
Vector<TcpConnection*> connections;

private:
uint16_t timeOut;
TcpClientDataDelegate clientReceiveDelegate = NULL;
Expand Down
8 changes: 8 additions & 0 deletions samples/HttpServer_WebSockets/app/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit 30e7d6b

Please sign in to comment.