mirror of
https://github.com/rajkosto/mxoemu
synced 2026-08-14 02:26:05 -04:00
188 lines
4.5 KiB
C++
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);
|
|
}
|
|
|
|
}
|
|
}
|