219 lines
6.3 KiB
C++
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
|