188 lines
5.1 KiB
C++
188 lines
5.1 KiB
C++
#include "GwSocketServer.h"
|
|
#include <ESPmDNS.h>
|
|
#include <lwip/sockets.h>
|
|
#include "GwBuffer.h"
|
|
#include "GwSocketConnection.h"
|
|
#include "GwSocketHelper.h"
|
|
|
|
GwSocketServer::GwSocketServer(const GwConfigHandler *config, GwLog *logger, int minId)
|
|
{
|
|
this->config = config;
|
|
this->logger = logger;
|
|
this->minId = minId;
|
|
maxClients = 1;
|
|
allowReceive = false;
|
|
}
|
|
bool GwSocketServer::createListener()
|
|
{
|
|
struct sockaddr_in server;
|
|
listener = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (listener < 0)
|
|
{
|
|
return false;
|
|
}
|
|
int enable = 1;
|
|
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));
|
|
server.sin_family = AF_INET;
|
|
server.sin_addr.s_addr = INADDR_ANY;
|
|
server.sin_port = htons(listenerPort);
|
|
if (bind(listener, (struct sockaddr *)&server, sizeof(server)) < 0)
|
|
return false;
|
|
if (listen(listener, maxClients) < 0)
|
|
return false;
|
|
fcntl(listener, F_SETFL, O_NONBLOCK);
|
|
return true;
|
|
}
|
|
void GwSocketServer::begin()
|
|
{
|
|
maxClients = config->getInt(config->maxClients);
|
|
allowReceive = config->getBool(config->readTCP);
|
|
listenerPort=config->getInt(config->serverPort);
|
|
clients = new GwSocketConnection*[maxClients];
|
|
for (int i = 0; i < maxClients; i++)
|
|
{
|
|
clients[i] = new GwSocketConnection(logger, i, allowReceive);
|
|
}
|
|
if (! createListener()){
|
|
listener=-1;
|
|
LOG_DEBUG(GwLog::ERROR,"Unable to create listener");
|
|
return;
|
|
}
|
|
LOG_DEBUG(GwLog::LOG, "Socket server created, port=%d",
|
|
config->getInt(config->serverPort));
|
|
MDNS.addService("_nmea-0183", "_tcp", config->getInt(config->serverPort));
|
|
}
|
|
int GwSocketServer::available()
|
|
{
|
|
if (listener < 0)
|
|
return -1;
|
|
int client_sock;
|
|
struct sockaddr_in _client;
|
|
int cs = sizeof(struct sockaddr_in);
|
|
client_sock = accept(listener, (struct sockaddr *)&_client, (socklen_t *)&cs);
|
|
if (client_sock >= 0)
|
|
{
|
|
int val = 1;
|
|
if (! GwSocketHelper::setKeepAlive(client_sock,true)){
|
|
LOG_DEBUG(GwLog::ERROR,"unable to set keepalive, nodelay on socket");
|
|
}
|
|
else
|
|
{
|
|
fcntl(client_sock, F_SETFL, O_NONBLOCK);
|
|
return client_sock;
|
|
}
|
|
close(client_sock);
|
|
}
|
|
return -1;
|
|
}
|
|
void GwSocketServer::loop(bool handleRead, bool handleWrite)
|
|
{
|
|
if (!clients)
|
|
return;
|
|
int client = available(); // listen for incoming clients
|
|
if (client >= 0)
|
|
{
|
|
LOG_DEBUG(GwLog::LOG, "new client connected from %s",
|
|
GwSocketConnection::remoteIP(client).toString().c_str());
|
|
bool canHandle = false;
|
|
for (int i = 0; i < maxClients; i++)
|
|
{
|
|
if (!clients[i]->hasClient())
|
|
{
|
|
clients[i]->setClient(client);
|
|
LOG_DEBUG(GwLog::LOG, "set client as number %d", i);
|
|
canHandle = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!canHandle)
|
|
{
|
|
logger->logDebug(GwLog::ERROR, "no space to store client, disconnect");
|
|
close(client);
|
|
}
|
|
}
|
|
if (handleWrite)
|
|
{
|
|
//sending
|
|
for (int i = 0; i < maxClients; i++)
|
|
{
|
|
GwSocketConnection *client = clients[i];
|
|
if (!client->hasClient())
|
|
continue;
|
|
GwBuffer::WriteStatus rt = client->write();
|
|
if (rt == GwBuffer::ERROR)
|
|
{
|
|
LOG_DEBUG(GwLog::ERROR, "write error on %s, closing", client->remoteIpAddress.c_str());
|
|
client->stop();
|
|
}
|
|
}
|
|
}
|
|
for (int i = 0; i < maxClients; i++)
|
|
{
|
|
GwSocketConnection *client = clients[i];
|
|
if (!client->hasClient())
|
|
continue;
|
|
|
|
if (!client->connected())
|
|
{
|
|
LOG_DEBUG(GwLog::LOG, "client %d disconnect %s", i, client->remoteIpAddress.c_str());
|
|
client->stop();
|
|
}
|
|
else
|
|
{
|
|
if (handleRead)
|
|
client->read();
|
|
}
|
|
}
|
|
}
|
|
|
|
void GwSocketServer::readMessages(GwMessageFetcher *writer)
|
|
{
|
|
if (!allowReceive || !clients)
|
|
return;
|
|
for (int i = 0; i < maxClients; i++)
|
|
{
|
|
writer->id = minId + i;
|
|
if (!clients[i]->hasClient())
|
|
continue;
|
|
clients[i]->messagesFromBuffer(writer);
|
|
}
|
|
return;
|
|
}
|
|
size_t GwSocketServer::sendToClients(const char *buf, int source,bool partial)
|
|
{
|
|
if (!clients)
|
|
return 0;
|
|
bool hasSend=false;
|
|
int len = strlen(buf);
|
|
int sourceIndex = source - minId;
|
|
for (int i = 0; i < maxClients; i++)
|
|
{
|
|
if (i == sourceIndex)
|
|
continue; //never send out to the source we received from
|
|
GwSocketConnection *client = clients[i];
|
|
if (!client->hasClient())
|
|
continue;
|
|
if (client->connected())
|
|
{
|
|
if(client->enqueue((uint8_t *)buf, len)) hasSend=true;
|
|
}
|
|
}
|
|
return hasSend?len:0;
|
|
}
|
|
|
|
int GwSocketServer::numClients()
|
|
{
|
|
if (!clients)
|
|
return 0;
|
|
int num = 0;
|
|
for (int i = 0; i < maxClients; i++)
|
|
{
|
|
if (clients[i]->hasClient())
|
|
num++;
|
|
}
|
|
return num;
|
|
}
|
|
GwSocketServer::~GwSocketServer()
|
|
{
|
|
} |