ESP8266_swiss_army_board/src/app/TCPServer.h
2022-10-04 08:27:21 +02:00

219 lines
6.3 KiB
C++

#ifndef TCPSERVER_H
#define TCPSERVER_H
#include <ESP8266WiFi.h>
#include "List.h"
#include "TCPClient.h"
#define MAX_CLIENT 0
//#define DEBUG_TCPS
template <typename T>
class TCPServer
{
public:
TCPServer(uint16_t port = 80, uint8_t maxClient = MAX_CLIENT, uint16_t clientDataBufferSize = 256) : _maxClient(maxClient), _clientDataBufferSize(clientDataBufferSize), _wifiServer(port)
{
}
virtual ~TCPServer()
{
_clientList.dispose();
}
uint8_t getMaxClient()
{
return _maxClient;
}
uint16_t getPort() const
{
return _wifiServer.port();
}
uint8_t getConnectedClientsCount()
{
return _clientList.count();
}
virtual void run()
{
handleNewClients();
getClientData();
}
virtual void start(uint16_t port = 0, uint8_t backlog = 5)
{
if(!_serverStarted)
{
!port ? _wifiServer.begin(getPort()) : _wifiServer.begin(port, backlog) ;
_serverStarted = true;
}
}
virtual void stop()
{
if(_serverStarted)
{
_wifiServer.stop();
_clientList.dispose();
_serverStarted = false;
}
}
virtual void enableTCPKeepAlive(uint16_t timeBetween2KATransmitions = TCP_DEFAULT_KEEPALIVE_IDLE_SEC,
uint16_t timeBetweenFailedKARetransmissions = TCP_DEFAULT_KEEPALIVE_INTERVAL_SEC,
uint8_t retriesBeforeDrop = TCP_DEFAULT_KEEPALIVE_COUNT)
{
_TKAIdleSec = timeBetween2KATransmitions;
_TKAIntvSec = timeBetweenFailedKARetransmissions;
_TKACount = retriesBeforeDrop;
}
virtual void disableTCPKeepAlive(){ _TKAIdleSec = 0;_TKAIntvSec = 0;_TKACount = 0; }
protected:
virtual T* createNewClient(WiFiClient wc)
{
return new T(wc, freeClientId(), _clientDataBufferSize);
}
virtual void handleNewClients()
{
WiFiClient wc;
if(!_maxClient || _maxClient > _clientList.count())
{
wc = _wifiServer.available();
}
if(wc && wc.connected())
{
T *clientPointer = createNewClient(wc);
//Serial.printf("Addr : %lu\n", clientPointer);
//We activate the TKA : (The check is internally done in the
//ClientContext.h class : ie if one of the provided parameters is 0, then TKA is disabled)
(clientPointer->_client).keepAlive(_TKAIdleSec, _TKAIntvSec, _TKACount);
_clientList.addFirst(clientPointer);
#ifdef DEBUG_TCPS
Serial.printf("TCPServer : New client accepted. Id : %u , Number of clients : %u, local port : %u, remote port : %u\n",clientPointer->_id, _clientList.count(),clientPointer->_client.localPort(),clientPointer->_client.remotePort());
if(_TKAIdleSec && _TKAIntvSec && _TKACount)
Serial.printf("TCPKeepAlive enabled for client id : %u\n", clientPointer->_id);
#endif
greetClient(clientPointer);
}
_currentClient = _clientList.removeLastRef();//We pick a client in the list to process it's request
if(_currentClient != nullptr)
{
if(_currentClient->_error != TCPClient::OK)
{
_currentClient->closeConnection();
delete _currentClient; _currentClient = nullptr;
}
}
}
virtual void greetClient(T *client)
{
client->_client.printf_P(PSTR("Successfully connected at %lu !\r\nYour are client with id : %u\r\n"), millis(), client->_id);
}
virtual void getClientData()
{
if(_currentClient == nullptr)
{
return;
}
if((_currentClient->_client).available())
{
fillDataBuffer(_currentClient);
}
else if(!(_currentClient->_client).connected())
{
#ifdef DEBUG_TCPS
Serial.printf("TCPServer : Client disconnected and can be discarded : %u\n", _currentClient->_id);
#endif
_currentClient->_clientState = TCPClient::DISCARDED;
}
else //Strange
{
#ifdef DEBUG_TCPS
Serial.printf("Client(%u/%u) id : %u, with TCP status : %u and available : %u, Is keepAlive enabled : %d\n", _clientList.count()+1, _maxClient, _currentClient->_id, (_currentClient->_client).status(), (_currentClient->_client).available(), (_currentClient->_client).isKeepAliveEnabled());
#endif
}
processClientData(_currentClient);//We process the actual data
_currentClient->_newDataAvailable = false;
if(_currentClient->_clientState == TCPClient::ClientState::DISCARDED)
{
_currentClient->closeConnection();
#ifdef DEBUG_TCPS
Serial.printf("TCPServer : Client was discarded : %u\n", _currentClient->_id);
#endif
delete _currentClient;
_currentClient = nullptr;
return;
}
_clientList.addFirst(_currentClient);
}
virtual void processClientData(T *client)
{
if(client->_dataSize > 0 && ((char) client->_data[0] != '\r' && (char) client->_data[0] != '\n'))
{
Serial.printf("Client --> %u : #%s#\r\n", client->_id, (char *)client->_data);
}
client->freeDataBuffer(client->_dataSize);
}
virtual void fillDataBuffer(T *client)
{
uint16_t freeSpace = (client->_dataBufferSize-1/*for \0*/ - client->_dataSize);
if(freeSpace > 0)
{
uint32_t bytesAvailable(client->_client.available());
int amountToBeRead = bytesAvailable < freeSpace ? bytesAvailable : freeSpace;
(client->_client).read(client->_data + client->_dataSize, amountToBeRead);
client->_dataSize += amountToBeRead;
client->_data[_currentClient->_dataSize] = '\0';
client->_newDataAvailable = true;
}
}
uint8_t freeClientId()
{
int listCounter(_clientList.count());
int freeId(0);
for(int i(0); i < listCounter; i++)
{
if(_clientList.getRef(i)->_id == freeId)
{
freeId++;
i = -1; //We start from 0 again
}
}
return freeId;
}
boolean _serverStarted = false;
uint8_t _maxClient, _TKACount = 0;
uint16_t _clientDataBufferSize, _TKAIdleSec = 0, _TKAIntvSec = 0;
WiFiServer _wifiServer;
T *_currentClient = nullptr; //current client to be processed
List<T> _clientList;
private:
};
#endif //TCPSERVER_H