131 lines
3.7 KiB
C++
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;
|
|
} |