summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGuillaume Melquiond <guillaume.melquiond@gmail.com>2006-05-19 06:00:30 +0000
committerGuillaume Melquiond <guillaume.melquiond@gmail.com>2006-05-19 06:00:30 +0000
commit149efe91e50bf0e298761bb941e20ce4d8362314 (patch)
tree33b35c8374c919332622d98a8bac66096c8b5fe3 /src
parentede341d0d121a842ad6ec8060931863cdc8021c1 (diff)
downloadmanaserv-149efe91e50bf0e298761bb941e20ce4d8362314.tar.gz
manaserv-149efe91e50bf0e298761bb941e20ce4d8362314.tar.bz2
manaserv-149efe91e50bf0e298761bb941e20ce4d8362314.tar.xz
manaserv-149efe91e50bf0e298761bb941e20ce4d8362314.zip
Switched to a monothreaded server. Fixed segfaults after disconnect.
Removed netsession.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/connectionhandler.cpp203
-rw-r--r--src/connectionhandler.h28
-rw-r--r--src/main.cpp70
-rw-r--r--src/netsession.cpp168
-rw-r--r--src/netsession.h102
6 files changed, 131 insertions, 442 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 070d6f00..8d745a77 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -47,8 +47,6 @@ tmwserv_SOURCES = main.cpp \
messageout.cpp \
netcomputer.h \
netcomputer.cpp \
- netsession.h \
- netsession.cpp \
packet.h \
packet.cpp \
skill.h \
diff --git a/src/connectionhandler.cpp b/src/connectionhandler.cpp
index e7ef6b9f..1da0b830 100644
--- a/src/connectionhandler.cpp
+++ b/src/connectionhandler.cpp
@@ -27,7 +27,6 @@
#include "messagein.h"
#include "messageout.h"
#include "netcomputer.h"
-#include "netsession.h"
#include "packet.h"
#include "utils/logger.h"
@@ -93,121 +92,129 @@ ClientData::ClientData():
{
}
-ConnectionHandler::ConnectionHandler()
+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 << "...", 0);
+ host = enet_host_create(&address /* the address to bind the server host to */,
+ MAX_CLIENTS /* allow up to MAX_CLIENTS clients and/or outgoing connections */,
+ 0 /* assume any amount of incoming bandwidth */,
+ 0 /* assume any amount of outgoing bandwidth */);
+
+ return host;
}
void
-ConnectionHandler::startListen(ListenThreadData *ltd)
+ConnectionHandler::stopListen()
{
- while (ltd->running)
- {
- ENetEvent event;
-
- // Wait up to 1000 milliseconds for an event.
- while (enet_host_service(ltd->host, &event, 1000) > 0)
- {
- switch (event.type)
- {
- case ENET_EVENT_TYPE_CONNECT:
- {
- LOG_INFO("A new client connected from " <<
- ip4ToString(event.peer->address.host) << ":" <<
- event.peer->address.port, 0);
- NetComputer *comp = new NetComputer(this, event.peer);
- clients.push_back(comp);
- computerConnected(comp);
- /*LOG_INFO(ltd->host->peerCount <<
- " client(s) connected", 0);*/
-
- // Store any relevant client information here.
- event.peer->data = (void *)comp;
- } break;
-
- case ENET_EVENT_TYPE_RECEIVE:
- {
- LOG_INFO("A packet of length " << event.packet->dataLength
- << " was received from " << event.peer->address.host,
- 2);
-
- NetComputer *comp = (NetComputer *)event.peer->data;
-
-#ifdef SCRIPT_SUPPORT
- // This could be good if you wanted to extend the
- // server protocol using a scripting language. This
- // could be attained by using allowing scripts to
- // "hook" certain messages.
-
- //script->message(buffer);
-#endif
-
- // If the scripting subsystem didn't hook the message
- // it will be handled by the default message handler.
-
- // Convert the client IP address to string
- // representation
- std::string ipaddr = ip4ToString(event.peer->address.host);
-
- // Make sure that the packet is big enough (> short)
- if (event.packet->dataLength >= 2)
- {
- Packet *packet = new Packet((char *)event.packet->data,
- event.packet->dataLength);
- MessageIn msg(packet); // (MessageIn frees packet)
-
- short messageId = msg.getId();
-
- if (handlers.find(messageId) != handlers.end())
- {
- // send message to appropriate handler
- handlers[messageId]->receiveMessage(*comp, msg);
- }
- else {
- // bad message (no registered handler)
- LOG_ERROR("Unhandled message (" << messageId
- << ") received from " << ipaddr, 0);
- }
- }
- else {
- LOG_ERROR("Message too short from " << ipaddr, 0);
- }
-
- /* Clean up the packet now that we're done using it. */
- enet_packet_destroy(event.packet);
- } break;
-
- case ENET_EVENT_TYPE_DISCONNECT:
- {
- NetComputer *comp = (NetComputer *)event.peer->data;
- /*LOG_INFO(event.peer->address.host
- << " disconected.", 0);*/
- // Reset the peer's client information.
- computerDisconnected(comp);
- delete comp;
- event.peer->data = NULL;
- } break;
-
- default: break;
- }
- }
- }
-
// - Disconnect all clients (close sockets)
// TODO: probably there's a better way.
ENetPeer *currentPeer;
- for (currentPeer = ltd->host->peers;
- currentPeer < &ltd->host->peers[ltd->host->peerCount];
+ 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(ltd->host);
+ enet_host_flush(host);
enet_peer_reset(currentPeer);
}
}
+ enet_host_destroy(host);
+}
+
+void
+ConnectionHandler::process()
+{
+ ENetEvent event;
+ // Process Enet events and do not block.
+ while (enet_host_service(host, &event, 0) > 0) {
+ switch (event.type) {
+ case ENET_EVENT_TYPE_CONNECT:
+ {
+ LOG_INFO("A new client connected from " <<
+ ip4ToString(event.peer->address.host) << ":" <<
+ event.peer->address.port, 0);
+ NetComputer *comp = new NetComputer(this, event.peer);
+ clients.push_back(comp);
+ computerConnected(comp);
+ /*LOG_INFO(ltd->host->peerCount <<
+ " client(s) connected", 0);*/
+
+ // Store any relevant client information here.
+ event.peer->data = (void *)comp;
+ } break;
+
+ case ENET_EVENT_TYPE_RECEIVE:
+ {
+ LOG_INFO("A packet of length " << event.packet->dataLength <<
+ " was received from " << event.peer->address.host, 2);
+
+ NetComputer *comp = (NetComputer *)event.peer->data;
+
+#ifdef SCRIPT_SUPPORT
+ // This could be good if you wanted to extend the
+ // server protocol using a scripting language. This
+ // could be attained by using allowing scripts to
+ // "hook" certain messages.
+
+ //script->message(buffer);
+#endif
+
+ // If the scripting subsystem didn't hook the message
+ // it will be handled by the default message handler.
+
+ // Convert the client IP address to string
+ // representation
+ std::string ipaddr = ip4ToString(event.peer->address.host);
+
+ // Make sure that the packet is big enough (> short)
+ if (event.packet->dataLength >= 2) {
+ Packet *packet = new Packet((char *)event.packet->data,
+ event.packet->dataLength);
+ MessageIn msg(packet); // (MessageIn frees packet)
+
+ short messageId = msg.getId();
+
+ HandlerMap::iterator it = handlers.find(messageId);
+ if (it != handlers.end()) {
+ // send message to appropriate handler
+ it->second->receiveMessage(*comp, msg);
+ } else {
+ // bad message (no registered handler)
+ LOG_ERROR("Unhandled message (" << messageId
+ << ") received from " << ipaddr, 0);
+ }
+ } else {
+ LOG_ERROR("Message too short from " << ipaddr, 0);
+ }
+
+ /* Clean up the packet now that we're done using it. */
+ enet_packet_destroy(event.packet);
+ } break;
+
+ case ENET_EVENT_TYPE_DISCONNECT:
+ {
+ NetComputer *comp = (NetComputer *)event.peer->data;
+ /*LOG_INFO(event.peer->address.host
+ << " disconected.", 0);*/
+ // Reset the peer's client information.
+ computerDisconnected(comp);
+ delete comp;
+ clients.erase(std::find(clients.begin(), clients.end(), comp));
+ event.peer->data = NULL;
+ } break;
+
+ default: break;
+ }
+ }
}
void ConnectionHandler::computerConnected(NetComputer *comp)
diff --git a/src/connectionhandler.h b/src/connectionhandler.h
index dd6cf207..d56fc09d 100644
--- a/src/connectionhandler.h
+++ b/src/connectionhandler.h
@@ -26,6 +26,7 @@
#include <list>
#include <map>
+#include <enet/enet.h>
#include "being.h"
@@ -35,9 +36,6 @@ class MessageHandler;
class MessageOut;
class NetComputer;
-// Forward declaration
-class ListenThreadData;
-
/**
* Data related to a connected client. This includes the buffer for incoming
* messages and the related socket.
@@ -61,19 +59,22 @@ class ClientData
class ConnectionHandler
{
public:
- typedef std::list<NetComputer*> NetComputers;
/**
- * Constructor.
+ * Open the server socket.
*/
- ConnectionHandler();
+ bool startListen(enet_uint16 port);
/**
- * Starts listening to the server socket. It accepts new connections
- * and receives data from connected clients. All computers are
- * disconnected when listening stops.
+ * Disconnect all the clients and close the server socket.
*/
- void startListen(ListenThreadData *ltd);
+ void stopListen();
+
+ /**
+ * Process outgoing messages and listen to the server socket for
+ * incoming messages and new connections.
+ */
+ void process();
/**
* Called when a computer connects to a network session.
@@ -146,8 +147,13 @@ class ConnectionHandler
const char eventId);
private:
- std::map<unsigned int, MessageHandler*> handlers;
+ ENetAddress address; /**< Includes the port to listen to. */
+ ENetHost *host; /**< The host that listen for connections. */
+
+ typedef std::map< unsigned int, MessageHandler * > HandlerMap;
+ HandlerMap handlers;
+ typedef std::list<NetComputer*> NetComputers;
NetComputers clients;
};
diff --git a/src/main.cpp b/src/main.cpp
index db594c76..e7c599cb 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -41,7 +41,6 @@
#include "connectionhandler.h"
#include "gamehandler.h"
#include "messageout.h"
-#include "netsession.h"
#include "resourcemanager.h"
#include "skill.h"
#include "state.h"
@@ -278,7 +277,7 @@ void parseOptions(int argc, char *argv[])
{ "help", no_argument, 0, 'h' },
{ "verbosity", required_argument, 0, 'v' },
{ "port", required_argument, 0, 'p' },
- 0
+ { 0 }
};
while (optind < argc) {
@@ -328,13 +327,9 @@ int main(int argc, char *argv[])
// General Initialization
initialize();
- // Ready for server work...
- std::auto_ptr<NetSession> session(new NetSession());
-
// Note: This is just an idea, we could also pass the connection handler
- // to the constructor of the account handler, upon which is would register
+ // to the constructor of the account handler, upon which it would register
// itself for the messages it handles.
- //
// Register message handlers
connectionHandler->registerHandler(CMSG_LOGIN, accountHandler);
@@ -362,10 +357,10 @@ int main(int argc, char *argv[])
connectionHandler->registerHandler(CMSG_REQ_TRADE, gameHandler);
connectionHandler->registerHandler(CMSG_EQUIP, gameHandler);
- session->startListen(connectionHandler, int(config.getValue("ListenOnPort",
- DEFAULT_SERVER_PORT)));
- LOG_INFO("Listening on port " <<
- config.getValue("ListenOnPort", DEFAULT_SERVER_PORT) << "...", 0)
+ if (!connectionHandler->startListen(int(config.getValue("ListenOnPort", DEFAULT_SERVER_PORT)))) {
+ LOG_ERROR("Unable to create an ENet server host.", 0);
+ return 3;
+ }
using namespace tmwserv;
@@ -400,61 +395,14 @@ int main(int argc, char *argv[])
// - Handle all messages that are in the message queue
// - Update all active objects/beings
+ connectionHandler->process();
state.update(*connectionHandler);
+ connectionHandler->process();
}
worldTimer.sleep();
-
- /*ENetEvent netEvent;
-
- while (enet_host_service(server, &netEvent, 3000) > 0)
- {
- switch (netEvent.type)
- {
- case ENET_EVENT_TYPE_CONNECT:
- printf("A new client connected from %x:%u.\n",
- netEvent.peer->address.host,
- netEvent.peer->address.port);
-
- netEvent.peer->data = (void *)"Client information";
- break;
-
- case ENET_EVENT_TYPE_RECEIVE:
- {
- printf("A packet of length %u containing %s was received from %s on channel %u.\n",
- netEvent.packet->dataLength,
- netEvent.packet->data,
- netEvent.peer->data,
- netEvent.channelID);
-
- MessageOut msg;
- msg.writeShort(SMSG_REGISTER_RESPONSE);
- msg.writeByte(REGISTER_OK);
- ENetPacket *packet = enet_packet_create(msg.getData(),
- msg.getDataSize() + 1,
- ENET_PACKET_FLAG_RELIABLE);
- // Send the packet to the peer over channel id 0.
- enet_peer_send(netEvent.peer, 0, packet);
- // Clean up the packet now that we're done using it.
- enet_packet_destroy(netEvent.packet);
- }
- break;
-
- case ENET_EVENT_TYPE_DISCONNECT:
- printf("%s disconected.\n", netEvent.peer->data);
-
- netEvent.peer->data = NULL;
- break;
-
- default:
- printf("Unhandled enet event\n");
- break;
- }
- }*/
}
LOG_INFO("Received: Quit signal, closing down...", 0)
- session->stopListen(int(config.getValue("ListenOnPort",
- DEFAULT_SERVER_PORT)));
-
+ connectionHandler->stopListen();
deinitialize();
}
diff --git a/src/netsession.cpp b/src/netsession.cpp
deleted file mode 100644
index 8ce5c8ad..00000000
--- a/src/netsession.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * 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
- *
- * $Id$
- */
-
-#include "netsession.h"
-
-#include "connectionhandler.h"
-
-#include "utils/logger.h"
-
-/**
- * This function is the new thread created to listen to a server socket. It
- * immediately passes control over to the connection handler instance that will
- * deal with incoming connections and data.
- */
-void *startListenThread(void *data)
-{
- ListenThreadData *ltd = (ListenThreadData*)data;
- ltd->handler->startListen(ltd);
- pthread_exit(NULL);
-}
-
-
-NetSession::NetSession()
-{
-}
-
-NetSession::~NetSession()
-{
- // Stop listening to any ports
-}
-
-void NetSession::startListen(ConnectionHandler *handler, enet_uint16 port)
-{
- // Here we will probably need the creation of a listening thread, which
- // will call connect/disconnect events on the given ConnectionHandler and
- // will cut incoming data into Packets and send them there too.
-
- ListenThreadData *data = new ListenThreadData();
-
- data->handler = handler;
- data->running = true;
-
- ENetHost *server;
-
- // Bind the server to the default localhost.
- data->address.host = ENET_HOST_ANY;
- data->address.port = port;
-
- server = enet_host_create(&data->address /* the address to bind the server host to */,
- MAX_CLIENTS /* allow up to MAX_CLIENTS clients and/or outgoing connections */,
- 0 /* assume any amount of incoming bandwidth */,
- 0 /* assume any amount of outgoing bandwidth */);
- if (server == NULL)
- {
- LOG_ERROR("Unable to create an ENet server host.", 0);
- exit(3);
- }
-
- data->host = server;
-
- // Start the listening thread
- int rc = pthread_create(&data->thread, NULL,
- startListenThread, (void *)data);
- if (rc) {
- LOG_ERROR("pthread_create: " << rc, 0);
- exit(4);
- }
-
- listeners[port] = data;
-}
-
-void NetSession::stopListen(enet_uint16 port)
-{
- std::map<enet_uint16, ListenThreadData*>::iterator threadDataI;
- threadDataI = listeners.find(port);
-
- if (threadDataI != listeners.end())
- {
- ListenThreadData *data = (*threadDataI).second;
-
- // Tell listen thread to stop running
- data->running = false;
-
- // Wait for listen thread to stop and close socket
- // Note: Somewhere in this process the ConnectionHandler should receive
- // disconnect notifications about all the connected clients.
- enet_host_destroy(data->host);
- delete data;
- listeners.erase(threadDataI);
- }
- else
- {
- LOG_WARN("NetSession::stopListen() not listening to port %d!\n", port);
- }
-}
-
-NetComputer *NetSession::connect(const std::string &host, enet_uint16 port)
-{
- // Try to connect to given host:port, and return NetComputer objects that
- // can be used to send messages that way, or NULL when failing to connect.
- //
- // An asynchroneous wrapper could be created around this method.
-
- ENetHost *client;
-
- client = enet_host_create(NULL, 1, 0, 0);
-
- if (client == NULL)
- {
- LOG_ERROR("Unable to create an ENet client host.", 0);
- exit(3);
- }
-
- ENetAddress address;
- ENetEvent event;
- ENetPeer *peer;
-
- // Connect to host:port.
- enet_address_set_host(&address, host.c_str());
- address.port = port;
-
- // Initiate the connection, allocating the channel 0.
- peer = enet_host_connect(client, &address, 1);
-
- if (peer == NULL)
- {
- LOG_ERROR("No available peer for initiating an ENet connection.", 0);
- exit(4);
- }
-
- // Wait up to 5 seconds for the connection attempt to succeed.
- if (enet_host_service (client, &event, 5000) > 0 &&
- event.type == ENET_EVENT_TYPE_CONNECT)
- {
- LOG_INFO("Connection succeeded.", 0);
- }
- else
- {
- /* Either the 5 seconds are up or a disconnect event was */
- /* received. Reset the peer in the event the 5 seconds */
- /* had run out without any significant event. */
- enet_peer_reset(peer);
- LOG_ERROR("Connection failed.", 0);
- exit(5);
- }
-
- return NULL;
-}
diff --git a/src/netsession.h b/src/netsession.h
deleted file mode 100644
index fe893055..00000000
--- a/src/netsession.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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
- *
- * $Id$
- */
-
-#ifndef _TMWSERV_NETSESSION_H_
-#define _TMWSERV_NETSESSION_H_
-
-#include <map>
-#include <pthread.h>
-
-#include <enet/enet.h>
-
-class ConnectionHandler;
-class NetComputer;
-
-/**
- * Data communicated to a new listen thread. The <code>running</code> member is
- * set to <code>false</code> to tell the thread to stop listening.
- */
-struct ListenThreadData
-{
- ENetAddress address; /**< Includes the port to listen to. */
- ENetHost *host; /**< The host that listen for connections. */
- pthread_t thread; /**< The thread, ignored by thread itself. */
- ConnectionHandler *handler; /**< Handler for events. */
- bool running; /**< Wether to keep listening. */
-};
-
-/**
- * This class represents a network session. It implements listening for
- * connections from and connecting to other computers.
- */
-class NetSession
-{
- public:
- /**
- * Constructor.
- */
- NetSession();
-
- /**
- * Destructor.
- */
- ~NetSession();
-
- /**
- * Start listening for connections and notify the given connection
- * handler about events.
- *
- * This method opens a socket on the given port and starts a new thread
- * that will handle listening for new connections and incoming data
- * over this port. The connection handler will need to be thread safe.
- */
- void startListen(ConnectionHandler *handler, enet_uint16 port);
-
- /**
- * Stop listening for connections and disconnect any connected clients.
- * This is done by signalling the listening thread to stop running, and
- * closing the socket when it stopped.
- */
- void stopListen(unsigned short port);
-
- /**
- * Connect to another network session.
- */
- NetComputer *connect(const std::string &ip, unsigned short port);
-
- private:
- /**
- * The list of ports we're listening to and their associated thread
- * data, including the connection handler and wether to keep listening.
- */
- std::map<unsigned short, ListenThreadData*> listeners;
-
- // Other information we need to keep:
- //
- // - The list of clients that connected and their associated net
- // computers.
- // - The list of servers we connected to and their associated net
- // computers.
-};
-
-#endif