From 291ad04d5b5c4ab08d85eadde116f968cd579b77 Mon Sep 17 00:00:00 2001 From: Guillaume Melquiond <guillaume.melquiond@gmail.com> Date: Fri, 29 Dec 2006 13:43:24 +0000 Subject: Physically split the server into one tmwserv-acount program (account + chat + database) and multiple tmwserv-game programs (selected with respect to the maps). Cleaned the repository by moving server-specific source files into dedicated directories. --- src/net/connection.cpp | 110 ++++++++++++++++++++++++++++ src/net/connection.hpp | 80 ++++++++++++++++++++ src/net/connectionhandler.cpp | 166 ++++++++++++++++++++++++++++++++++++++++++ src/net/connectionhandler.hpp | 123 +++++++++++++++++++++++++++++++ src/net/messagein.cpp | 100 +++++++++++++++++++++++++ src/net/messagein.hpp | 77 ++++++++++++++++++++ src/net/messageout.cpp | 135 ++++++++++++++++++++++++++++++++++ src/net/messageout.hpp | 96 ++++++++++++++++++++++++ src/net/netcomputer.cpp | 94 ++++++++++++++++++++++++ src/net/netcomputer.hpp | 97 ++++++++++++++++++++++++ 10 files changed, 1078 insertions(+) create mode 100644 src/net/connection.cpp create mode 100644 src/net/connection.hpp create mode 100644 src/net/connectionhandler.cpp create mode 100644 src/net/connectionhandler.hpp create mode 100644 src/net/messagein.cpp create mode 100644 src/net/messagein.hpp create mode 100644 src/net/messageout.cpp create mode 100644 src/net/messageout.hpp create mode 100644 src/net/netcomputer.cpp create mode 100644 src/net/netcomputer.hpp (limited to 'src/net') diff --git a/src/net/connection.cpp b/src/net/connection.cpp new file mode 100644 index 00000000..8a5c8d0e --- /dev/null +++ b/src/net/connection.cpp @@ -0,0 +1,110 @@ +/* + * The Mana World Server + * Copyright 2006 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 "net/connection.hpp" +#include "net/messagein.hpp" +#include "net/messageout.hpp" +#include "utils/logger.h" + +bool Connection::start(std::string const &address, int port) +{ + ENetAddress enetAddress; + enet_address_set_host(&enetAddress, address.c_str()); + enetAddress.port = port; + + mLocal = enet_host_create(NULL /* create a client host */, + 1 /* allow one outgoing connection */, + 0 /* assume any amount of incoming bandwidth */, + 0 /* assume any amount of outgoing bandwidth */); + + if (!mLocal) return false; + + // Initiate the connection, allocating channel 0. + mRemote = enet_host_connect(mLocal, &enetAddress, 1); + + ENetEvent event; + if (enet_host_service(mLocal, &event, 10000) <= 0 || + event.type != ENET_EVENT_TYPE_CONNECT) + { + stop(); + return false; + } + return mRemote; +} + +void Connection::stop() +{ + enet_peer_disconnect(mRemote, 0); + enet_host_flush(mLocal); + enet_peer_reset(mRemote); + enet_host_destroy(mLocal); + mRemote = NULL; +} + +bool Connection::isConnected() const +{ + return mRemote && mRemote->state == ENET_PEER_STATE_CONNECTED; +} + +void Connection::send(MessageOut const &msg, bool reliable, unsigned channel) +{ + ENetPacket *packet; + packet = enet_packet_create(msg.getData(), + msg.getLength(), + reliable ? ENET_PACKET_FLAG_RELIABLE : 0); + + if (packet) + { + enet_peer_send(mRemote, channel, packet); + } + else + { + LOG_WARN("Failure to create packet!", 0); + } +} + +void Connection::process() +{ + ENetEvent event; + // Process Enet events and do not block. + while (enet_host_service(mLocal, &event, 0) > 0) + { + switch (event.type) + { + case ENET_EVENT_TYPE_RECEIVE: + if (event.packet->dataLength >= 2) { + MessageIn msg((char *)event.packet->data, + event.packet->dataLength); + processMessage(msg); + } else { + LOG_ERROR("Message too short.", 0); + } + // Clean up the packet now that we are done using it. + enet_packet_destroy(event.packet); + break; + + default: + break; + } + } +} diff --git a/src/net/connection.hpp b/src/net/connection.hpp new file mode 100644 index 00000000..0cdb1fc0 --- /dev/null +++ b/src/net/connection.hpp @@ -0,0 +1,80 @@ +/* + * The Mana World Server + * Copyright 2006 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_CONNECTION_H_ +#define _TMWSERV_CONNECTION_H_ + +#include <string> +#include <enet/enet.h> + +class MessageIn; +class MessageOut; + +/** + * A point-to-point connection to a remote host. The remote host can use a + * ConnectionHandler to handle this incoming connection. + */ +class Connection +{ + public: + Connection(): mRemote(NULL) {} + virtual ~Connection() {} + + /** + * Connects to the given host/port and waits until the connection is + * established. Returns false if it fails to connect. + */ + bool start(std::string const &, int); + + /** + * Disconnects. + */ + void stop(); + + /** + * Returns whether the connection is established or not. + */ + bool isConnected() const; + + /** + * Sends a message to the remote host. + */ + void send(MessageOut const &msg, bool reliable = true, unsigned channel = 0); + + /** + * Dispatches received messages to processMessage. + */ + void process(); + + protected: + /** + * Processes a single message from the remote host. + */ + virtual void processMessage(MessageIn &) = 0; + + private: + ENetPeer *mRemote; + ENetHost *mLocal; +}; + +#endif diff --git a/src/net/connectionhandler.cpp b/src/net/connectionhandler.cpp new file mode 100644 index 00000000..7782a74a --- /dev/null +++ b/src/net/connectionhandler.cpp @@ -0,0 +1,166 @@ +/* + * 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 "defines.h" +#include "net/connectionhandler.hpp" +#include "net/messagein.hpp" +#include "net/messageout.hpp" +#include "net/netcomputer.hpp" +#include "utils/logger.h" + +#ifdef SCRIPT_SUPPORT +#include "script.h" +#endif + + +std::string +ip4ToString(unsigned int ip4addr) +{ + std::stringstream ss; + ss << (ip4addr & 0x000000ff) << "." + << ((ip4addr & 0x0000ff00) >> 8) << "." + << ((ip4addr & 0x00ff0000) >> 16) << "." + << ((ip4addr & 0xff000000) >> 24); + return ss.str(); +} + +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::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() +{ + 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 << " to port " << + host->address.port, 0); + NetComputer *comp = computerConnected(event.peer); + clients.push_back(comp); + + // Store any relevant client information here. + event.peer->data = (void *)comp; + } break; + + case ENET_EVENT_TYPE_RECEIVE: + { + 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. + + // Make sure that the packet is big enough (> short) + if (event.packet->dataLength >= 2) { + MessageIn msg((char *)event.packet->data, + event.packet->dataLength); + LOG_INFO("Received message " << msg.getId() << " (" + << event.packet->dataLength << " B) from " + << *comp, 2); + + processMessage(comp, msg); + } else { + LOG_ERROR("Message too short from " << *comp, 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(ip4ToString(event.peer->address.host) << " disconnected.", 0); + // 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(); +} diff --git a/src/net/connectionhandler.hpp b/src/net/connectionhandler.hpp new file mode 100644 index 00000000..df22aacc --- /dev/null +++ b/src/net/connectionhandler.hpp @@ -0,0 +1,123 @@ +/* + * 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_CONNECTIONHANDLER_H_ +#define _TMWSERV_CONNECTIONHANDLER_H_ + +#include <list> +#include <enet/enet.h> + +class MessageIn; +class MessageOut; +class NetComputer; + +/** + * Convert a IP4 address into its string representation + */ +std::string +ip4ToString(unsigned int ip4addr); + +/** + * This class represents the connection handler interface. The connection + * handler will respond to connect/reconnect/disconnect events and handle + * incoming messages, passing them on to registered message handlers. + */ +class ConnectionHandler +{ + public: + virtual ~ConnectionHandler() {} + + /** + * Open the server socket. + */ + bool startListen(enet_uint16 port); + + /** + * Disconnect all the clients and close the server socket. + */ + void stopListen(); + + /** + * Process outgoing messages and listen to the server socket for + * incoming messages and new connections. + */ + virtual void process(); + + /** + * Process outgoing messages. + */ + void flush(); + + /** + * Called when a computer sends a packet to the network session. + */ + //void receivePacket(NetComputer *computer, Packet *packet); + + /** + * Send packet to every client, used for announcements. + */ + void sendToEveryone(const MessageOut &msg); + + /** + * Return the number of connected clients. + */ + unsigned int getClientNumber(); + + private: + ENetAddress address; /**< Includes the port to listen to. */ + ENetHost *host; /**< The host that listen for connections. */ + + protected: + /** + * Called when a computer connects to the server. Initialize + * an object derived of NetComputer. + */ + virtual NetComputer *computerConnected(ENetPeer *peer) = 0; + + /** + * Called when a computer reconnects to the server. + */ + //virtual NetComputer *computerReconnected(ENetPeer *) = 0; + + /** + * Called when a computer disconnects from the server. + * + * <b>Note:</b> After returning from this method the NetComputer + * reference is no longer guaranteed to be valid. + */ + virtual void computerDisconnected(NetComputer *) = 0; + + /** + * Called when a message is received. + */ + virtual void processMessage(NetComputer *, MessageIn &) = 0; + + typedef std::list<NetComputer*> NetComputers; + /** + * A list of pointers to the client structures created by + * computerConnected. + */ + NetComputers clients; +}; + +#endif diff --git a/src/net/messagein.cpp b/src/net/messagein.cpp new file mode 100644 index 00000000..8da02550 --- /dev/null +++ b/src/net/messagein.cpp @@ -0,0 +1,100 @@ +/* + * 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 <string> +#include <enet/enet.h> + +#include "net/messagein.hpp" + +MessageIn::MessageIn(const char *data, int length): + mData(data), + mLength(length), + mPos(0) +{ + // Read the message ID + mId = readShort(); +} + +MessageIn::~MessageIn() +{ +} + +char MessageIn::readByte() +{ + char value = -1; + if (mPos < mLength) + { + value = mData[mPos]; + } + mPos += 1; + return value; +} + +short MessageIn::readShort() +{ + short value = -1; + if (mPos + 2 <= mLength) + { + uint16_t t; + memcpy(&t, mData + mPos, 2); + value = ENET_NET_TO_HOST_16(t); + } + mPos += 2; + return value; +} + +long MessageIn::readLong() +{ + long value = -1; + if (mPos + 4 <= mLength) + { + uint32_t t; + memcpy(&t, mData + mPos, 4); + value = ENET_NET_TO_HOST_32(t); + } + mPos += 4; + return value; +} + +std::string MessageIn::readString(int length) +{ + // Get string length + if (length < 0) { + length = readShort(); + } + + // Make sure the string isn't erroneous + if (length < 0 || mPos + length > mLength) { + mPos = mLength + 1; + return ""; + } + + // Read the string + char const *stringBeg = mData + mPos; + char const *stringEnd = (char const *)memchr(stringBeg, '\0', length); + std::string readString(stringBeg, + stringEnd ? stringEnd - stringBeg : length); + mPos += length; + + return readString; +} diff --git a/src/net/messagein.hpp b/src/net/messagein.hpp new file mode 100644 index 00000000..c582d056 --- /dev/null +++ b/src/net/messagein.hpp @@ -0,0 +1,77 @@ +/* + * 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_MESSAGEIN_H_ +#define _TMWSERV_MESSAGEIN_H_ + +#include <iosfwd> + +class Packet; + +/** + * Used for parsing an incoming message. + */ +class MessageIn +{ + public: + /** + * Constructor. + */ + MessageIn(const char *data, int length); + + /** + * Destructor. + */ + ~MessageIn(); + + short getId() { return mId; } /**< Returns the message ID. */ + + char readByte(); /**< Reads a byte. */ + short readShort(); /**< Reads a short. */ + long readLong(); /**< Reads a long. */ + + /** + * Reads a string. If a length is not given (-1), it is assumed + * that the length of the string is stored in a short at the + * start of the string. + */ + std::string readString(int length = -1); + + /** + * Returns the length of unread data. + */ + unsigned getUnreadLength() { return mLength - mPos; } + + private: + const char *mData; /**< Packet data */ + unsigned int mLength; /**< Length of data in bytes */ + short mId; /**< The message ID. */ + + /** + * Actual position in the packet. From 0 to packet->length. A value + * bigger than packet->length means EOP was reached when reading it. + */ + unsigned int mPos; +}; + +#endif diff --git a/src/net/messageout.cpp b/src/net/messageout.cpp new file mode 100644 index 00000000..34655e4c --- /dev/null +++ b/src/net/messageout.cpp @@ -0,0 +1,135 @@ +/* + * 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 <cstdlib> +#include <iosfwd> +#include <string> +#include <enet/enet.h> + +#include "net/messageout.hpp" + +/** Initial amount of bytes allocated for the messageout data buffer. */ +const unsigned int INITIAL_DATA_CAPACITY = 16; + +/** Factor by which the messageout data buffer is increased when too small. */ +const unsigned int CAPACITY_GROW_FACTOR = 2; + +MessageOut::MessageOut(): + mPos(0) +{ + mData = (char*) malloc(INITIAL_DATA_CAPACITY); + mDataSize = INITIAL_DATA_CAPACITY; +} + +MessageOut::MessageOut(short id): + mPos(0) +{ + mData = (char*) malloc(INITIAL_DATA_CAPACITY); + mDataSize = INITIAL_DATA_CAPACITY; + + writeShort(id); +} + +MessageOut::~MessageOut() +{ + free(mData); +} + +void +MessageOut::expand(size_t bytes) +{ + if (bytes > mDataSize) + { + do + { + mDataSize *= CAPACITY_GROW_FACTOR; + } + while (bytes > mDataSize); + + mData = (char*) realloc(mData, mDataSize); + } +} + +void +MessageOut::writeByte(char value) +{ + expand(mPos + 1); + mData[mPos] = value; + mPos += 1; +} + +void +MessageOut::writeShort(short value) +{ + expand(mPos + 2); + uint16_t t = ENET_HOST_TO_NET_16(value); + memcpy(mData + mPos, &t, 2); + mPos += 2; +} + +void +MessageOut::writeLong(long value) +{ + expand(mPos + 4); + uint32_t t = ENET_HOST_TO_NET_32(value); + memcpy(mData + mPos, &t, 4); + mPos += 4; +} + +void MessageOut::writeCoordinates(int x, int y) +{ + expand(mPos + 3); + char *p = mData + mPos; + p[0] = x & 0x00FF; + p[1] = ((x & 0x0700) >> 8) | ((y & 0x001F) << 3); + p[2] = (y & 0x07E0) >> 5; + mPos += 3; +} + +void +MessageOut::writeString(const std::string &string, int length) +{ + int stringLength = string.length(); + if (length < 0) + { + // Write the length at the start if not fixed + writeShort(stringLength); + length = stringLength; + } + else if (length < stringLength) + { + // Make sure the length of the string is no longer than specified + stringLength = length; + } + expand(mPos + length); + + // Write the actual string + memcpy(mData + mPos, string.c_str(), stringLength); + + if (length > stringLength) + { + // Pad remaining space with zeros + memset(mData + mPos + stringLength, '\0', length - stringLength); + } + mPos += length; +} diff --git a/src/net/messageout.hpp b/src/net/messageout.hpp new file mode 100644 index 00000000..8ec6b171 --- /dev/null +++ b/src/net/messageout.hpp @@ -0,0 +1,96 @@ +/* + * 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_MESSAGEOUT_H_ +#define _TMWSERV_MESSAGEOUT_H_ + +#include <iosfwd> + +/** + * Used for building an outgoing message. + */ +class MessageOut +{ + public: + /** + * Constructor. + */ + MessageOut(); + + /** + * Constructor that takes a message ID. + */ + MessageOut(short id); + + /** + * Destructor. + */ + ~MessageOut(); + + void + writeByte(char value); /**< Writes a byte. */ + + void + writeShort(short value); /**< Writes a short. */ + + void + writeLong(long value); /**< Writes a long. */ + + /** + * Writes a 3-byte block containing tile-based coordinates. + */ + void writeCoordinates(int x, int y); + + /** + * Writes a string. If a fixed length is not given (-1), it is stored + * as a short at the start of the string. + */ + void + writeString(const std::string &string, int length = -1); + + /** + * Returns the content of the message. + */ + char* + getData() const { return mData; } + + /** + * Returns the length of the data. + */ + unsigned int + getLength() const { return mPos; } + + private: + /** + * Ensures the capacity of the data buffer is large enough to hold the + * given amount of bytes. + */ + void + expand(size_t size); + + char *mData; /**< Data building up. */ + unsigned int mPos; /**< Position in the data. */ + unsigned int mDataSize; /**< Allocated datasize. */ +}; + +#endif //_TMWSERV_MESSAGEOUT_H_ diff --git a/src/net/netcomputer.cpp b/src/net/netcomputer.cpp new file mode 100644 index 00000000..f963db55 --- /dev/null +++ b/src/net/netcomputer.cpp @@ -0,0 +1,94 @@ +/* + * 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 <iosfwd> +#include <queue> +#include <enet/enet.h> + +#include "defines.h" +#include "net/messageout.hpp" +#include "net/netcomputer.hpp" +#include "utils/logger.h" + +NetComputer::NetComputer(ENetPeer *peer): + mPeer(peer) +{ +} + +bool +NetComputer::isConnected() +{ + return (mPeer->state == ENET_PEER_STATE_CONNECTED); +} + +void +NetComputer::disconnect(const MessageOut &msg) +{ + if (isConnected()) + { + /* ChannelID 0xFF is the channel used by enet_peer_disconnect. + * If a reliable packet is send over this channel ENet guaranties + * that the message is recieved before the disconnect request. + */ + send(msg, ENET_PACKET_FLAG_RELIABLE, 0xFF); + + /* ENet generates a disconnect event + * (notifying the connection handler). + */ + enet_peer_disconnect(mPeer, 0); + } +} + +void +NetComputer::send(const MessageOut &msg, bool reliable, + unsigned int channel) +{ + LOG_INFO("Sending packet of length " << msg.getLength() << " to " + << *this, 2); + + ENetPacket *packet; + packet = enet_packet_create(msg.getData(), + msg.getLength(), + reliable ? ENET_PACKET_FLAG_RELIABLE : 0); + + if (packet) + { + enet_peer_send(mPeer, channel, packet); + } + else + { + LOG_WARN("Failure to create packet!", 0); + } +} + +std::ostream& +operator <<(std::ostream &os, const NetComputer &comp) +{ + // address.host contains the ip-address in network-byte-order + + os << ((comp.mPeer->address.host & 0xff000000) >> 24) << "." + << ((comp.mPeer->address.host & 0x00ff0000) >> 16) << "." + << ((comp.mPeer->address.host & 0x0000ff00) >> 8) << "." + << ((comp.mPeer->address.host & 0x000000ff) >> 0); + return os; +} diff --git a/src/net/netcomputer.hpp b/src/net/netcomputer.hpp new file mode 100644 index 00000000..0b8dab3d --- /dev/null +++ b/src/net/netcomputer.hpp @@ -0,0 +1,97 @@ +/* + * 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_NETCOMPUTER_H_ +#define _TMWSERV_NETCOMPUTER_H_ + +#include <iostream> +#include <enet/enet.h> + +class MessageOut; + +/** + * This class represents a known computer on the network. For example a + * connected client or a server we're connected to. + */ +class NetComputer +{ + public: + /** + * Constructor. + */ + NetComputer(ENetPeer *peer); + + /** + * Destructor. + */ + virtual ~NetComputer() {} + + /** + * Returns <code>true</code> if this computer is connected. + */ + bool + isConnected(); + + /** + * Disconnects the computer from the server, after sending a message. + * + * The caller of this method should prepare the message, because + * NetComputer does not know which handler is sending it + * (could have been chat/game/account) + */ + void + disconnect(const MessageOut &msg); + + /** + * Queues a message for sending to a client. + * + * Reliable packets always arrive, if the client stays connected. + * Unreliable packets may not arrive, and may not even be sent. + * + * Channels are used to ensure that unrelated reliable packets do not + * hold each other up. In essence, each channel represents a different + * queue. + * + * @param msg The message to be sent. + * @param reliable Defines if a reliable or an unreliable packet + * should be sent. + * @param channel The channel number of which the packet should + * be sent. + */ + void + send(const MessageOut &msg, bool reliable = true, + unsigned int channel = 0); + + private: + ENetPeer *mPeer; /**< Client peer */ + + /** + * Converts the ip-address of the peer to a stringstream. + * Example: + * <code> std::cout << comp </code> + */ + friend std::ostream& operator <<(std::ostream &os, + const NetComputer &comp); +}; + +#endif // _TMWSERV_NETCOMPUTER_H_ -- cgit v1.2.3-70-g09d2