#include "GwSocketServer.h" #include #include #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() { }