#ifndef TCPSERVER_H #define TCPSERVER_H #include #include "List.h" #include "TCPClient.h" #define MAX_CLIENT 0 //#define DEBUG_TCPS template 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 _clientList; private: }; #endif //TCPSERVER_H