/*
* The Mana World Server
* Copyright 2004 The Mana World Development Team
*
* This file is part of The Mana World.
*
* The Mana World is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or any later version.
*
* The Mana World 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 General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with The Mana World; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <algorithm>
#include "net/connectionhandler.hpp"
#include "defines.h"
#include "common/configuration.hpp"
#include "net/bandwidth.hpp"
#include "net/messagein.hpp"
#include "net/messageout.hpp"
#include "net/netcomputer.hpp"
#include "utils/logger.h"
bool ConnectionHandler::startListen(enet_uint16 port)
{
// Bind the server to the default localhost.
address.host = ENET_HOST_ANY;
address.port = port;
LOG_INFO("Listening on port " << port << "...");
host = enet_host_create(
&address /* the address to bind the server host to */,
Configuration::getValue("net_maxClients", 1000) /* allowed connections */,
0 /* assume any amount of incoming bandwidth */,
0 /* assume any amount of outgoing bandwidth */);
return host;
}
void ConnectionHandler::stopListen()
{
// - Disconnect all clients (close sockets)
// TODO: probably there's a better way.
ENetPeer *currentPeer;
for (currentPeer = host->peers;
currentPeer < &host->peers[host->peerCount];
++currentPeer)
{
if (currentPeer->state == ENET_PEER_STATE_CONNECTED)
{
enet_peer_disconnect(currentPeer, 0);
enet_host_flush(host);
enet_peer_reset(currentPeer);
}
}
enet_host_destroy(host);
// FIXME: memory leak on NetComputers
}
void ConnectionHandler::flush()
{
enet_host_flush(host);
}
void ConnectionHandler::process(enet_uint32 timeout)
{
ENetEvent event;
// Process Enet events and do not block.
while (enet_host_service(host, &event, timeout) > 0) {
switch (event.type) {
case ENET_EVENT_TYPE_CONNECT:
{
NetComputer *comp = computerConnected(event.peer);
clients.push_back(comp);
LOG_INFO("A new client connected from " << *comp << ":"
<< event.peer->address.port << " to port "
<< host->address.port);
// Store any relevant client information here.
event.peer->data = (void *)comp;
} break;
case ENET_EVENT_TYPE_RECEIVE:
{
NetComputer *comp =
static_cast<NetComputer*>(event.peer->data);
// If the scripting subsystem didn't hook the message
// it will be handled by the default message handler.
// Make sure that the packet is big enough (> short)
if (event.packet->dataLength >= 2) {
MessageIn msg((char *)event.packet->data,
event.packet->dataLength);
LOG_DEBUG("Received message " << msg << " from "
<< *comp);
gBandwidth->increaseClientInput(comp, event.packet->dataLength);
processMessage(comp, msg);
} else {
LOG_ERROR("Message too short from " << *comp);
}
/* Clean up the packet now that we're done using it. */
enet_packet_destroy(event.packet);
} break;
case ENET_EVENT_TYPE_DISCONNECT:
{
NetComputer *comp =
static_cast<NetComputer*>(event.peer->data);
LOG_INFO("" << *comp << " disconnected.");
// Reset the peer's client information.
computerDisconnected(comp);
clients.erase(std::find(clients.begin(), clients.end(), comp));
event.peer->data = NULL;
} break;
default: break;
}
}
}
void ConnectionHandler::sendToEveryone(const MessageOut &msg)
{
for (NetComputers::iterator i = clients.begin(), i_end = clients.end();
i != i_end; ++i)
{
(*i)->send(msg);
}
}
unsigned int ConnectionHandler::getClientNumber()
{
return clients.size();
}