123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- #include "Server.h"
- #include <iostream>
- #include <sys/socket.h>
- #include <cstdio>
- #include <cstring>
- #include <stdexcept>
- #include <netinet/in.h>
- #include <unistd.h>
- #include <arpa/inet.h>
- #include <poll.h>
- #include <time.h>
- #include <signal.h>
- #include "../stream/Stream.h"
- using namespace std;
- Server::Server(unsigned short port, unsigned short maxClients) : port(port), maxClients(maxClients)
- {
- try
- {
- // create socket for incoming connections
- listenerSocket = socket(AF_INET, SOCK_STREAM, 0);
- if(listenerSocket == -1)
- {
- throw runtime_error(string("cannot create socket: ") + strerror(errno));
- }
- // prevents clients from blocking the port if the server exits
- struct linger sl;
- sl.l_onoff = 1;
- sl.l_linger = 0;
- if(setsockopt(listenerSocket, SOL_SOCKET, SO_LINGER, &sl, sizeof(struct linger)) == -1)
- {
- throw runtime_error(string("cannot set non lingering: ") + strerror(errno));
- }
- // specifies data of the port ...
- struct sockaddr_in connectSocketData;
- memset(&connectSocketData, 0, sizeof(struct sockaddr_in));
- connectSocketData.sin_family = AF_INET;
- connectSocketData.sin_addr.s_addr = INADDR_ANY;
- connectSocketData.sin_port = htons(port);
- // ... and binds it
- if(bind(listenerSocket, (struct sockaddr*) &connectSocketData, sizeof(struct sockaddr_in)) == -1)
- {
- throw runtime_error(string("cannot bind socket: ") + strerror(errno));
- }
- // mark this socket as handler for connection requests
- if(listen(listenerSocket, 5) != 0)
- {
- throw runtime_error(string("cannot start listening: ") + strerror(errno));
- }
-
- // array for client connections, pointer to pointer to change placement
- clients = new ConnectedClient*[maxClients];
- for(int i = 0; i < maxClients; i++)
- {
- clients[i] = nullptr;
- }
- }
- catch(runtime_error& err)
- {
- clean();
- throw err;
- }
- }
- Server::~Server()
- {
- clean();
- }
- void Server::clean()
- {
- if(listenerSocket != -1)
- {
- // ignore error
- close(listenerSocket);
- }
- if(clients != nullptr)
- {
- for(int i = 0; i < maxClients; i++)
- {
- if(clients[i] != nullptr)
- {
- if(clients[i]->socket != -1)
- {
- close(clients[i]->socket);
- }
- delete clients[i];
- }
- }
- delete[] clients;
- }
- }
- void Server::start(IServerListener* listener)
- {
- serverListener = listener;
- shouldRun = true;
- listenerThread = thread(&Server::listenForClients, this);
- }
- void Server::stop()
- {
- shouldRun = false;
-
- listenerThread.join();
- for(int i = 0; i < maxClients; i++)
- {
- if(clients[i] != nullptr)
- {
- clients[i]->th.join();
- }
- }
- }
- void Server::listenForClients()
- {
- while(shouldRun)
- {
- struct pollfd fds;
- fds.fd = listenerSocket;
- fds.events = POLLIN;
- fds.revents = 0;
- int pollData = poll(&fds, 1, 100);
- if(pollData > 0)
- {
- struct sockaddr_in clientSocketData;
- socklen_t addrlen = sizeof(struct sockaddr_in);
- int clientSocket = accept(listenerSocket, (struct sockaddr*) &clientSocketData, &addrlen);
- if(clientSocket >= 0)
- {
- //cout << "Client connected from " << inet_ntoa(clientSocketData.sin_addr) << ":" << (int) ntohs(clientSocketData.sin_port) << endl;
-
- clientMutex.lock();
- addClient(clientSocket);
- clientMutex.unlock();
- }
- else
- {
- break;
- }
- }
- else if(pollData == -1)
- {
- cerr << "poll error: " << strerror(errno) << endl;
- }
- }
- }
- void Server::addClient(int clientSocket)
- {
- if(clientIndex >= maxClients)
- {
- serverListener->onFullServerClientConnect(clientSocket);
- close(clientSocket);
- }
- else
- {
- if(clients[clientIndex] == nullptr)
- {
- clients[clientIndex] = new ConnectedClient();
- }
- else
- {
- //ensure old thread has ended
- if(!clients[clientIndex]->th.joinable())
- {
- cerr << "cannot join thread of non used client connection" << endl;
- close(clientSocket);
- return;
- }
- clients[clientIndex]->th.join();
- }
-
- clients[clientIndex]->index = clientIndex;
- clients[clientIndex]->socket = clientSocket;
- clients[clientIndex]->th = thread(&Server::listenOnClient, this, clients[clientIndex]);
- clientIndex++;
- }
- }
- void Server::listenOnClient(ConnectedClient* cc)
- {
- struct pollfd fds;
- fds.fd = cc->socket;
- fds.events = POLLIN;
- fds.revents = 0;
-
- serverListener->onClientConnect(cc->socket);
-
- Stream st;
-
- while(shouldRun)
- {
- int pollData = poll(&fds, 1, 100);
- if(pollData > 0)
- {
- st.readSocket(cc->socket);
- if(st.hasData())
- {
- serverListener->onClientPackage(cc->socket, st);
- }
- else
- {
- // client closed connection
- break;
- }
- }
- else if(pollData == -1)
- {
- cout << "poll error: " << strerror(errno) << endl;
- }
- }
-
- serverListener->onClientDisconnect(cc->socket);
-
- // do not swap on server shutdown
- if(!shouldRun)
- {
- return;
- }
-
- // remove client from list, move last client to empty slot
- clientMutex.lock();
-
- clientIndex--;
- if(cc->index != clientIndex) // client is not the last connected client
- {
- // move last element to empty slot
- ConnectedClient* tmp = clients[clientIndex];
- clients[clientIndex] = clients[cc->index];
- clients[cc->index] = tmp;
- // set indices
- int i = cc->index;
- clients[i]->index = i;
- clients[clientIndex]->index = clientIndex;
- }
-
- if(close(cc->socket) == -1)
- {
- cerr << "cannot close socket of client: " << strerror(errno) << endl;
- }
- cc->socket = -1;
-
- clientMutex.unlock();
- }
|