mxoemu/Reality/Source/GameServer.cpp
2009-08-12 19:55:32 +00:00

188 lines
4.5 KiB
C++

// *************************************************************************************************
// --------------------------------------
// Copyright (C) 2006-2010 Rajko Stojadinovic
//
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
// *************************************************************************************************
#include "Common.h"
#include "GameServer.h"
#include "Log.h"
#include "Timer.h"
#include "Config.h"
#include "Sockets.h"
initialiseSingleton( GameServer );
bool GameServer::Start()
{
int Port;
Port = sConfig.GetIntDefault("GameServer.Port", 10000);
INFO_LOG("Starting Game server on port %d", Port);
#if PLATFORM == PLATFORM_WIN32
// Winsock Startup
WSADATA wsa;
memset(&wsa, 0x0, sizeof(WSADATA));
if( WSAStartup( MAKEWORD(2,0), &wsa ) != 0x0 )
{
CRITICAL_LOG("Unable to initialize WinSock2!");
return false;
}
#endif
Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (Socket == INVALID_SOCKET)
{
CRITICAL_LOG("Unable to create socket!");
return false;
}
// 0 = Blocking sockets - 1 = Non-blocking
unsigned long mode = 1;
#if PLATFORM == PLATFORM_WIN32
int ret = ioctlsocket(Socket, FIONBIO, &mode );
#else
int ret = ioctl(Socket, FIONBIO, &mode);
#endif
if (ret < 0)
{
CRITICAL_LOG("Unable to set socket to non blocking!");
Socket = INVALID_SOCKET;
return false;
}
memset(&listen_addr, 0, sizeof(listen_addr));
listen_addr.sin_family = AF_INET;
listen_addr.sin_addr.s_addr = INADDR_ANY;
listen_addr.sin_port = htons(Port);
if (::bind(Socket, (struct sockaddr *) &listen_addr, sizeof(listen_addr)) < 0)
{
CRITICAL_LOG("Unable to bind socket!");
Socket = INVALID_SOCKET;
return false;
}
lastCleanupTime = getTime();
return true;
}
void GameServer::Stop()
{
INFO_LOG("Game Server shutdown");
#if PLATFORM == PLATFORM_WIN32
closesocket(Socket);
WSACleanup();
#else
close(Socket);
#endif
Socket = INVALID_SOCKET;
}
void GameServer::Loop(void)
{
FD_ZERO(&Readable);
FD_SET(Socket, &Readable);
timeout.tv_sec = 0;
timeout.tv_usec = 100;
if (select(0, &Readable, NULL, NULL, &timeout) == SOCKET_ERROR)
{
CRITICAL_LOG("Select() Failed, Shutting down World server");
Stop();
}
if (FD_ISSET(Socket, &Readable))
{
Handle_Incoming();
}
CurTime = getTime();
if ((CurTime - lastCleanupTime) >= 5)
{
// Do client cleanup
GClientList::iterator i = Clients.begin();
for (;;)
{
if (i == Clients.end())
break;
GameClient *Client = (*i).second;
if (Client->IsValid() == false || (CurTime
- Client->LastActive()) >= 30)
{
DEBUG_LOG("Routine dead client removal [%s]",
Client->Address());
Clients.erase(i++);
delete Client;
}
else
++i;
}
lastCleanupTime = CurTime;
}
}
void GameServer::Handle_Incoming()
{
char Buffer[RECV_BUFFER_SIZE];
socklen_t addr_len = sizeof(inc_addr);
uint16 len = 0;
std::stringstream IP;
len = recvfrom(Socket, Buffer, RECV_BUFFER_SIZE, 0,
(struct sockaddr*) &inc_addr, &addr_len);
if ((len > 0 && len <= RECV_BUFFER_SIZE && errno != EWOULDBLOCK) ||
(len > 0 && len <= RECV_BUFFER_SIZE))
{
IP << inet_ntoa(inc_addr.sin_addr) << ":" << inc_addr.sin_port;
GClientList::iterator i = Clients.find(IP.str());
if (i != Clients.end())
{
if (Clients[IP.str()]->IsValid() == false)
{
DEBUG_LOG("Removing dead client [%s]", IP.str().c_str());
delete Clients[IP.str()];
Clients.erase(Clients.find(IP.str()));
}
else
{
Clients[IP.str()]->HandlePacket(Buffer, len);
}
}
else
{
Clients[IP.str()] = new GameClient(inc_addr, &Socket);
DEBUG_LOG("Client connected [%s], now have [%d] clients",
IP.str().c_str(), Clients_Connected());
Clients[IP.str()]->HandlePacket(Buffer, len);
}
}
}