This repository has been archived on 2023-10-10. You can view files and clone it, but cannot push or open issues/pull-requests.
umcs/src/Server.cpp

131 lines
3.7 KiB
C++

#include "Server.h"
using namespace umcs;
#include "config.h"
CServer::CServer(short Port = 25565)
{
m_GamePort = Port;
m_GameSocket = socket(AF_INET, SOCK_STREAM, 0);
if (m_GameSocket == -1)
{
LOG("Could not create game socket.\n", 0);
return;
}
}
TSocket CServer::Select(unsigned int TimeoutMicro)
{
FD_ZERO(&m_RSockets);
FD_SET(m_GameSocket, &m_RSockets);
for (auto Iterator = m_ClientConnections.begin(); Iterator != m_ClientConnections.end(); Iterator++)
FD_SET((*Iterator)->GetSocket(), &m_RSockets);
struct timeval Timeout;
Timeout.tv_sec = 0;
Timeout.tv_usec = TimeoutMicro;
return select(FD_SETSIZE, &m_RSockets, (fd_set *)0, (fd_set *)0, &Timeout);
}
int CServer::MakeSocketNonBlocking(TSocket Socket)
{
int Options = fcntl(Socket, F_GETFL);
if (Options < 0)
{
LOG("Could not get socket options...\n", 0);
return -1;
}
Options |= O_NONBLOCK;
if (fcntl(Socket, F_SETFL, Options) < 0)
{
LOG("Could not set socket options...\n", 0);
return -1;
}
return 0;
}
int CServer::Run(void)
{
if (m_GameSocket == -1)
return -1;
// reuse socket
int ReuseAddress = 1;
setsockopt(m_GameSocket, SOL_SOCKET, SO_REUSEADDR, &ReuseAddress, sizeof(ReuseAddress));
// make it non-blocking
if (MakeSocketNonBlocking(m_GameSocket) < 0)
{
LOG("Could not make socket non-blocking...\n", 0);
return -1;
}
// bind to inaddr_any and specified port
struct sockaddr_in Address;
Address.sin_family = AF_INET;
Address.sin_addr.s_addr = INADDR_ANY;
Address.sin_port = htons(m_GamePort);
if (bind(m_GameSocket, (struct sockaddr *)&Address, sizeof(Address)) == -1)
{
LOG("Cold not bind to port...\n", 0);
return -2;
}
if (listen(m_GameSocket, 100) == -1)
{
LOG("Could not listen on socket...\n", 0);
return -3;
}
LOG("Starting select() loop...\n", 0);
bool Continue = true;
while (Continue)
{
int Result = Select(100000);
if (FD_ISSET(m_GameSocket, &m_RSockets))
{
LOG("New connection!\n", 0);
// accept the new connection
TSocket Socket = accept(m_GameSocket, 0, 0);
if (Socket < 0)
LOG("...but we couldn't accept it.\n", 0);
else
{
MakeSocketNonBlocking(Socket);
auto Connection = new CClientConnection(Socket);
m_ClientConnections.push_back(Connection);
}
}
for (auto Iterator = m_ClientConnections.begin(); Iterator != m_ClientConnections.end(); Iterator++)
{
// has this client sent any data?
auto Client = (*Iterator);
if (FD_ISSET(Client->GetSocket(), &m_RSockets))
{
unsigned char *Buffer = new unsigned char[256];
int BytesReceived = recv(Client->GetSocket(), Buffer, 256, 0);
if (BytesReceived < 0)
// todo: what client?
LOG("Did not receive bytes from client. Wat.\n", 0);
else if (BytesReceived != 0)
{
Client->FillReadBuffer(Buffer, BytesReceived);
if (Client->Communicate() < 0)
{
// todo: what client?
LOG("Fatal error occured for client. Disconnecting.\n", 0);
close(Client->GetSocket());
delete Client;
m_ClientConnections.erase(Iterator);
break;
}
}
delete[] Buffer;
}
}
}
return 0;
}