|
@@ -1,5 +1,9 @@
|
|
#include <iostream>
|
|
#include <iostream>
|
|
#include <cstring>
|
|
#include <cstring>
|
|
|
|
+#include <vector>
|
|
|
|
+#include <atomic>
|
|
|
|
+#include <thread>
|
|
|
|
+#include <mutex>
|
|
|
|
|
|
#include <sys/socket.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/in.h>
|
|
@@ -8,174 +12,178 @@
|
|
|
|
|
|
#include "server/network/Server.h"
|
|
#include "server/network/Server.h"
|
|
|
|
|
|
-
|
|
+static void printError(const char* message)
|
|
-Server::ConnectedClient::ConnectedClient() : th([]() {}), socket(-1)
|
|
|
|
{
|
|
{
|
|
|
|
+ std::cout << message << ": " << strerror(errno) << "\n";
|
|
}
|
|
}
|
|
|
|
|
|
-Server::Server(uint16_t port, uint16_t maxClients, const IServerListener& listener) :
|
|
+struct ConnectedClient
|
|
- shouldRun(false), port(port), maxClients(maxClients), serverListener(listener),
|
|
|
|
- listenerSocket(-1), clientAmount(0), clients(nullptr)
|
|
|
|
{
|
|
{
|
|
-
|
|
+ ~ConnectedClient()
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- listenerSocket = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
- if(listenerSocket == -1)
|
|
|
|
{
|
|
{
|
|
- printError("cannot create listener socket");
|
|
+ if(socket != -1)
|
|
- return;
|
|
+ {
|
|
- }
|
|
+ if(shutdown(socket, SHUT_RDWR))
|
|
-
|
|
+ {
|
|
-
|
|
+ printError("cannot shutdown client socket");
|
|
-
|
|
+ }
|
|
- struct linger sl;
|
|
+ if(close(socket) == -1)
|
|
- sl.l_onoff = 1;
|
|
+ {
|
|
- sl.l_linger = 0;
|
|
+ printError("cannot close client socket");
|
|
-
|
|
+ }
|
|
-
|
|
+ }
|
|
-
|
|
+ if(th.joinable())
|
|
- if(setsockopt(listenerSocket, SOL_SOCKET, SO_LINGER, &sl, sizeof(struct linger)) == -1)
|
|
+ {
|
|
- {
|
|
+ th.join();
|
|
- printError("cannot set non lingering");
|
|
+ }
|
|
- return;
|
|
+ else
|
|
- }
|
|
+ {
|
|
-
|
|
+ std::cout << "cannot join client connection thread\n";
|
|
-
|
|
+ }
|
|
- struct sockaddr_in connectSocketData;
|
|
|
|
-
|
|
|
|
- memset(&connectSocketData, 0, sizeof(struct sockaddr_in));
|
|
|
|
-
|
|
|
|
- connectSocketData.sin_family = AF_INET;
|
|
|
|
-
|
|
|
|
- connectSocketData.sin_port = htons(port);
|
|
|
|
-
|
|
|
|
- connectSocketData.sin_addr.s_addr = htons(INADDR_ANY);
|
|
|
|
-
|
|
|
|
- if(bind(listenerSocket, (struct sockaddr*) &connectSocketData, sizeof(struct sockaddr_in)) == -1)
|
|
|
|
- {
|
|
|
|
- printError("cannot bind listener socket");
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- if(listen(listenerSocket, 5) == -1)
|
|
|
|
- {
|
|
|
|
- printError("cannot start listening on socket");
|
|
|
|
- return;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- shouldRun = true;
|
|
+ std::thread th = std::thread([]() {});
|
|
- listenerThread = std::thread(&Server::listenForClients, this);
|
|
+ int socket = -1;
|
|
-
|
|
+};
|
|
- clients = new ConnectedClient[maxClients];
|
|
|
|
-}
|
|
|
|
|
|
|
|
-Server::~Server()
|
|
+struct InternServer final
|
|
{
|
|
{
|
|
- shouldRun = false;
|
|
+ InternServer() : listenerSocket(-1), shouldRun(true), clients(nullptr)
|
|
- listenerThread.join();
|
|
|
|
-
|
|
|
|
- if(listenerSocket != -1)
|
|
|
|
{
|
|
{
|
|
- if(close(listenerSocket) == -1)
|
|
|
|
- {
|
|
|
|
- printError("cannot close listener socket");
|
|
|
|
- }
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- if(clients != nullptr)
|
|
+ ~InternServer()
|
|
{
|
|
{
|
|
- for(uint16_t i = 0; i < maxClients; i++)
|
|
+ shouldRun = false;
|
|
|
|
+ listenerThread.join();
|
|
|
|
+
|
|
|
|
+ if(listenerSocket != -1)
|
|
{
|
|
{
|
|
- if(clients[i].socket != -1)
|
|
+ if(close(listenerSocket) == -1)
|
|
- {
|
|
|
|
- if(shutdown(clients[i].socket, SHUT_RDWR))
|
|
|
|
- {
|
|
|
|
- printError("cannot shutdown client socket");
|
|
|
|
- }
|
|
|
|
- if(close(clients[i].socket) == -1)
|
|
|
|
- {
|
|
|
|
- printError("cannot close client socket");
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if(clients[i].th.joinable())
|
|
|
|
{
|
|
{
|
|
- clients[i].th.join();
|
|
+ printError("cannot close listener socket");
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- std::cout << "cannot join client connection thread " << std::endl;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- delete[] clients;
|
|
+ if(clients != nullptr)
|
|
|
|
+ {
|
|
|
|
+ delete[] clients;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ int listenerSocket;
|
|
|
|
+ std::thread listenerThread;
|
|
|
|
+ std::atomic_bool shouldRun;
|
|
|
|
+ ConnectedClient* clients;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static InternServer server;
|
|
|
|
+
|
|
|
|
+static void defaultFullServerClientConnect(int)
|
|
|
|
+{
|
|
|
|
+ std::cout << "default onFullServerClientConnectFunction\n";
|
|
}
|
|
}
|
|
|
|
|
|
-bool Server::isRunning() const
|
|
+static void defaultClientConnect(int)
|
|
{
|
|
{
|
|
- return shouldRun;
|
|
+ std::cout << "default onClientConnectFunction\n";
|
|
}
|
|
}
|
|
|
|
|
|
-void Server::printError(const char* message) const
|
|
+static void defaultClientPackage(int, Stream&)
|
|
{
|
|
{
|
|
- std::cout << message << ": " << strerror(errno) << std::endl;
|
|
+ std::cout << "default onClientPackageFunction\n";
|
|
}
|
|
}
|
|
|
|
|
|
-void Server::listenForClients()
|
|
+static void defaultClientDisconnect(int)
|
|
{
|
|
{
|
|
- while(shouldRun)
|
|
+ std::cout << "default onClientDisconnectFunction\n";
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static std::mutex clientMutex;
|
|
|
|
+static u16 clientAmount = 0;
|
|
|
|
+static u16 maxClients = 0;
|
|
|
|
+static Server::FullServerClientConnectFunction onFullServerClientConnect = defaultFullServerClientConnect;
|
|
|
|
+static Server::ClientConnectFunction onClientConnect = defaultClientConnect;
|
|
|
|
+static Server::ClientPackageFunction onClientPackage = defaultClientPackage;
|
|
|
|
+static Server::ClientDisconnectFunction onClientDisconnect = defaultClientDisconnect;
|
|
|
|
+
|
|
|
|
+void Server::setFullServerClientConnectFunction(Server::FullServerClientConnectFunction f)
|
|
|
|
+{
|
|
|
|
+ onFullServerClientConnect = f;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void Server::setClientConnectFunction(Server::ClientConnectFunction f)
|
|
|
|
+{
|
|
|
|
+ onClientConnect = f;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void Server::setClientPackageFunction(Server::ClientPackageFunction f)
|
|
|
|
+{
|
|
|
|
+ onClientPackage = f;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void Server::setClientDisconnectFunction(Server::ClientDisconnectFunction f)
|
|
|
|
+{
|
|
|
|
+ onClientDisconnect = f;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void listenOnClient(ConnectedClient& cc)
|
|
|
|
+{
|
|
|
|
+
|
|
|
|
+ struct pollfd fds;
|
|
|
|
+ fds.fd = cc.socket;
|
|
|
|
+ fds.events = POLLIN;
|
|
|
|
+ fds.revents = 0;
|
|
|
|
+
|
|
|
|
+ onClientConnect(cc.socket);
|
|
|
|
+
|
|
|
|
+ Stream st;
|
|
|
|
+ while(server.shouldRun)
|
|
{
|
|
{
|
|
-
|
|
|
|
-
|
|
|
|
- struct pollfd fds;
|
|
|
|
- fds.fd = listenerSocket;
|
|
|
|
- fds.events = POLLIN;
|
|
|
|
- fds.revents = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int pollData = poll(&fds, 1, 100);
|
|
int pollData = poll(&fds, 1, 100);
|
|
if(pollData > 0)
|
|
if(pollData > 0)
|
|
{
|
|
{
|
|
- struct sockaddr_in clientSocketData;
|
|
+ st.readSocket(cc.socket);
|
|
-
|
|
+ if(st.hasData())
|
|
-
|
|
|
|
- socklen_t addrlen = sizeof(struct sockaddr_in);
|
|
|
|
- int clientSocket = accept(listenerSocket, (struct sockaddr*) &clientSocketData, &addrlen);
|
|
|
|
- if(clientSocket >= 0)
|
|
|
|
{
|
|
{
|
|
-
|
|
+ onClientPackage(cc.socket, st);
|
|
- if(addClient(clientSocket))
|
|
|
|
- {
|
|
|
|
- if(close(clientSocket) == -1)
|
|
|
|
- {
|
|
|
|
- printError("cannot close client socket");
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
- printError("accept error");
|
|
+
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(pollData == -1)
|
|
else if(pollData == -1)
|
|
{
|
|
{
|
|
- printError("poll error");
|
|
+ printError("cannot poll from client");
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ onClientDisconnect(cc.socket);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ if(server.shouldRun)
|
|
|
|
+ {
|
|
|
|
+ std::lock_guard<std::mutex> lg(clientMutex);
|
|
|
|
+ if(close(cc.socket) == -1)
|
|
|
|
+ {
|
|
|
|
+ printError("cannot close socket of client");
|
|
|
|
+ }
|
|
|
|
+ cc.socket = -1;
|
|
|
|
+ clientAmount--;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
-bool Server::addClient(int clientSocket)
|
|
+static bool addClient(int clientSocket)
|
|
{
|
|
{
|
|
std::lock_guard<std::mutex> lg(clientMutex);
|
|
std::lock_guard<std::mutex> lg(clientMutex);
|
|
if(clientAmount >= maxClients)
|
|
if(clientAmount >= maxClients)
|
|
{
|
|
{
|
|
- serverListener.onFullServerClientConnect(clientSocket);
|
|
+ onFullServerClientConnect(clientSocket);
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
else
|
|
@@ -184,7 +192,7 @@ bool Server::addClient(int clientSocket)
|
|
uint16_t index = 0;
|
|
uint16_t index = 0;
|
|
while(index < maxClients)
|
|
while(index < maxClients)
|
|
{
|
|
{
|
|
- if(clients[index].socket == -1)
|
|
+ if(server.clients[index].socket == -1)
|
|
{
|
|
{
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -193,20 +201,20 @@ bool Server::addClient(int clientSocket)
|
|
|
|
|
|
if(index >= maxClients)
|
|
if(index >= maxClients)
|
|
{
|
|
{
|
|
- std::cout << "cannot find free slot - even if there should be one" << std::endl;
|
|
+ std::cout << "cannot find free slot - even if there should be one\n";
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
- if(!clients[index].th.joinable())
|
|
+ if(!server.clients[index].th.joinable())
|
|
{
|
|
{
|
|
- std::cout << "cannot join thread of non used client connection" << std::endl;
|
|
+ std::cout << "cannot join thread of non used client connection\n";
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
- clients[index].th.join();
|
|
+ server.clients[index].th.join();
|
|
|
|
|
|
- clients[index].socket = clientSocket;
|
|
+ server.clients[index].socket = clientSocket;
|
|
- clients[index].th = std::thread(&Server::listenOnClient, this, std::ref(clients[index]));
|
|
+ server.clients[index].th = std::thread(listenOnClient, std::ref(server.clients[index]));
|
|
|
|
|
|
clientAmount++;
|
|
clientAmount++;
|
|
|
|
|
|
@@ -214,54 +222,107 @@ bool Server::addClient(int clientSocket)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-void Server::listenOnClient(ConnectedClient& cc)
|
|
+static void listenForClients()
|
|
{
|
|
{
|
|
-
|
|
+ while(server.shouldRun)
|
|
- struct pollfd fds;
|
|
|
|
- fds.fd = cc.socket;
|
|
|
|
- fds.events = POLLIN;
|
|
|
|
- fds.revents = 0;
|
|
|
|
-
|
|
|
|
- serverListener.onClientConnect(cc.socket);
|
|
|
|
-
|
|
|
|
- Stream st;
|
|
|
|
- while(shouldRun)
|
|
|
|
{
|
|
{
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ struct pollfd fds;
|
|
|
|
+ fds.fd = server.listenerSocket;
|
|
|
|
+ fds.events = POLLIN;
|
|
|
|
+ fds.revents = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int pollData = poll(&fds, 1, 100);
|
|
int pollData = poll(&fds, 1, 100);
|
|
if(pollData > 0)
|
|
if(pollData > 0)
|
|
{
|
|
{
|
|
- st.readSocket(cc.socket);
|
|
+ struct sockaddr_in clientSocketData;
|
|
- if(st.hasData())
|
|
+
|
|
|
|
+
|
|
|
|
+ socklen_t addrlen = sizeof(struct sockaddr_in);
|
|
|
|
+ int clientSocket = accept(server.listenerSocket, (struct sockaddr*) &clientSocketData, &addrlen);
|
|
|
|
+ if(clientSocket >= 0)
|
|
{
|
|
{
|
|
- serverListener.onClientPackage(cc.socket, st);
|
|
+ if(addClient(clientSocket))
|
|
|
|
+ {
|
|
|
|
+ if(close(clientSocket) == -1)
|
|
|
|
+ {
|
|
|
|
+ printError("cannot close client socket");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
-
|
|
+ printError("accept error");
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(pollData == -1)
|
|
else if(pollData == -1)
|
|
{
|
|
{
|
|
- printError("cannot poll from client");
|
|
+ printError("poll error");
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool Server::start(u16 port, u16 inMaxClients)
|
|
|
|
+{
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ server.listenerSocket = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
+ if(server.listenerSocket == -1)
|
|
|
|
+ {
|
|
|
|
+ printError("cannot create listener socket");
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
|
|
- serverListener.onClientDisconnect(cc.socket);
|
|
+
|
|
|
|
+
|
|
|
|
+ struct linger sl;
|
|
|
|
+ sl.l_onoff = 1;
|
|
|
|
+ sl.l_linger = 0;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ if(setsockopt(server.listenerSocket, SOL_SOCKET, SO_LINGER, &sl, sizeof(struct linger)) == -1)
|
|
|
|
+ {
|
|
|
|
+ printError("cannot set non lingering");
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
|
|
-
|
|
+
|
|
- if(shouldRun)
|
|
+ struct sockaddr_in connectSocketData;
|
|
|
|
+
|
|
|
|
+ memset(&connectSocketData, 0, sizeof(struct sockaddr_in));
|
|
|
|
+
|
|
|
|
+ connectSocketData.sin_family = AF_INET;
|
|
|
|
+
|
|
|
|
+ connectSocketData.sin_port = htons(port);
|
|
|
|
+
|
|
|
|
+ connectSocketData.sin_addr.s_addr = htons(INADDR_ANY);
|
|
|
|
+
|
|
|
|
+ if(bind(server.listenerSocket, (struct sockaddr*) &connectSocketData, sizeof(struct sockaddr_in)) == -1)
|
|
{
|
|
{
|
|
- std::lock_guard<std::mutex> lg(clientMutex);
|
|
+ printError("cannot bind listener socket");
|
|
- if(close(cc.socket) == -1)
|
|
+ return false;
|
|
- {
|
|
|
|
- printError("cannot close socket of client");
|
|
|
|
- }
|
|
|
|
- cc.socket = -1;
|
|
|
|
- clientAmount--;
|
|
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ if(listen(server.listenerSocket, 5) == -1)
|
|
|
|
+ {
|
|
|
|
+ printError("cannot start listening on socket");
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ server.shouldRun = true;
|
|
|
|
+
|
|
|
|
+ maxClients = inMaxClients;
|
|
|
|
+ server.clients = new ConnectedClient[inMaxClients];
|
|
|
|
+ server.listenerThread = std::thread(listenForClients);
|
|
|
|
+ return true;
|
|
}
|
|
}
|