mirror of
https://github.com/thooge/esp32-nmea2000-obp60.git
synced 2025-12-13 05:53:06 +01:00
use async send for tcp connections
This commit is contained in:
@@ -1,5 +1,95 @@
|
||||
#include "GwSocketServer.h"
|
||||
#include <ESPmDNS.h>
|
||||
#include <lwip/sockets.h>
|
||||
#include "GwBuffer.h"
|
||||
|
||||
class Writer : public GwBufferWriter{
|
||||
public:
|
||||
wiFiClientPtr client;
|
||||
bool writeError=false;
|
||||
bool timeOut=false;
|
||||
unsigned long writeTimeout;
|
||||
unsigned long lastWrite;
|
||||
bool pending;
|
||||
Writer(wiFiClientPtr client, unsigned long writeTimeout=10000){
|
||||
this->client=client;
|
||||
pending=false;
|
||||
this->writeTimeout=writeTimeout;
|
||||
}
|
||||
virtual ~Writer(){}
|
||||
virtual int write(const uint8_t *buffer,size_t len){
|
||||
int res = send(client->fd(), (void*) buffer, len, MSG_DONTWAIT);
|
||||
if (res < 0){
|
||||
if (errno != EAGAIN){
|
||||
writeError=true;
|
||||
return res;
|
||||
}
|
||||
res=0;
|
||||
}
|
||||
if (res >= len){
|
||||
pending=false;
|
||||
}
|
||||
else{
|
||||
if (!pending){
|
||||
lastWrite=millis();
|
||||
pending=true;
|
||||
}
|
||||
else{
|
||||
//we need to check if we have still not been able
|
||||
//to write until timeout
|
||||
if (millis() >= (lastWrite+writeTimeout)){
|
||||
timeOut=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
class GwClient{
|
||||
public:
|
||||
wiFiClientPtr client;
|
||||
GwBuffer *buffer;
|
||||
GwLog *logger;
|
||||
int overflows;
|
||||
private:
|
||||
Writer *writer;
|
||||
public:
|
||||
GwClient(wiFiClientPtr client,GwLog *logger){
|
||||
this->client=client;
|
||||
this->logger=logger;
|
||||
buffer=new GwBuffer(logger);
|
||||
overflows=0;
|
||||
writer=new Writer(client);
|
||||
}
|
||||
~GwClient(){
|
||||
delete writer;
|
||||
}
|
||||
bool enqueue(uint8_t *data, size_t len){
|
||||
if (len == 0) return true;
|
||||
size_t rt=buffer->addData(data,len);
|
||||
if (rt < len){
|
||||
LOG_DEBUG(GwLog::LOG,"overflow on %s",client->remoteIP().toString().c_str());
|
||||
overflows++;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool hasData(){
|
||||
return buffer->usedSpace() > 0;
|
||||
}
|
||||
GwBuffer::WriteStatus write(){
|
||||
GwBuffer::WriteStatus rt=buffer->fetchData(writer,false);
|
||||
if (rt != GwBuffer::OK){
|
||||
LOG_DEBUG(GwLog::DEBUG+1,"write returns %d on %s",rt,client->remoteIP().toString().c_str());
|
||||
}
|
||||
if (writer->timeOut ){
|
||||
LOG_DEBUG(GwLog::LOG,"timeout on %s",client->remoteIP().toString().c_str());
|
||||
return GwBuffer::ERROR;
|
||||
}
|
||||
return rt;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
GwSocketServer::GwSocketServer(const GwConfigHandler *config,GwLog *logger){
|
||||
this->config=config;
|
||||
@@ -20,23 +110,33 @@ void GwSocketServer::loop()
|
||||
if (client){
|
||||
logger->logString("new client connected from %s",
|
||||
client.remoteIP().toString().c_str());
|
||||
clients.push_back(wiFiClientPtr(new WiFiClient(client)));
|
||||
fcntl(client.fd(), F_SETFL, O_NONBLOCK);
|
||||
gwClientPtr newClient(new GwClient(wiFiClientPtr(new WiFiClient(client)),logger));
|
||||
clients.push_back(newClient);
|
||||
}
|
||||
//sending
|
||||
for (auto it = clients.begin(); it != clients.end();it++){
|
||||
GwBuffer::WriteStatus rt=(*it)->write();
|
||||
if (rt == GwBuffer::ERROR){
|
||||
LOG_DEBUG(GwLog::ERROR,"write error on %s, closing",(*it)->client->remoteIP().toString().c_str());
|
||||
(*it)->client->stop();
|
||||
}
|
||||
}
|
||||
for (auto it = clients.begin(); it != clients.end();it++)
|
||||
{
|
||||
if ((*it) != NULL)
|
||||
{
|
||||
if (!(*it)->connected())
|
||||
if (!(*it)->client->connected())
|
||||
{
|
||||
logger->logString("client disconnect ");
|
||||
(*it)->stop();
|
||||
logger->logString("client disconnect");
|
||||
(*it)->client->stop();
|
||||
clients.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((*it)->available())
|
||||
while ((*it)->client->available())
|
||||
{
|
||||
char c = (*it)->read();
|
||||
char c = (*it)->client->read();
|
||||
//TODO: read data
|
||||
}
|
||||
}
|
||||
@@ -48,9 +148,20 @@ void GwSocketServer::loop()
|
||||
}
|
||||
}
|
||||
void GwSocketServer::sendToClients(const char *buf){
|
||||
int len=strlen(buf);
|
||||
char buffer[len+2];
|
||||
memcpy(buffer,buf,len);
|
||||
buffer[len]=0x0d;
|
||||
len++;
|
||||
buffer[len]=0x0a;
|
||||
len++;
|
||||
for (auto it = clients.begin() ; it != clients.end(); it++) {
|
||||
if ( (*it) != NULL && (*it)->connected() ) {
|
||||
(*it)->println(buf);
|
||||
if ( (*it) != NULL && (*it)->client->connected() ) {
|
||||
bool rt=(*it)->enqueue((uint8_t*)buffer,len);
|
||||
if (!rt){
|
||||
LOG_DEBUG(GwLog::DEBUG,"overflow in send to %s",(*it)->client->remoteIP().toString().c_str());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,13 @@
|
||||
#include <WiFi.h>
|
||||
|
||||
using wiFiClientPtr = std::shared_ptr<WiFiClient>;
|
||||
class GwClient;
|
||||
using gwClientPtr = std::shared_ptr<GwClient>;
|
||||
class GwSocketServer{
|
||||
private:
|
||||
const GwConfigHandler *config;
|
||||
GwLog *logger;
|
||||
std::list<wiFiClientPtr> clients;
|
||||
std::list<gwClientPtr> clients;
|
||||
WiFiServer *server=NULL;
|
||||
public:
|
||||
GwSocketServer(const GwConfigHandler *config,GwLog *logger);
|
||||
|
||||
Reference in New Issue
Block a user