summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
m---------libs/uWebSockets0
-rw-r--r--src/CMakeLists.txt11
-rw-r--r--src/account-server/accountclient.h1
-rw-r--r--src/account-server/accounthandler.cpp186
-rw-r--r--src/account-server/accounthandler.h10
-rw-r--r--src/account-server/main-account.cpp131
-rw-r--r--src/account-server/serverhandler.cpp5
-rw-r--r--src/account-server/serverhandler.h5
-rw-r--r--src/common/manaserv_protocol.h2
-rw-r--r--src/net/connectionhandler.cpp21
-rw-r--r--src/net/connectionhandler.h23
12 files changed, 326 insertions, 72 deletions
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 00000000..6c4cf6d0
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "libs/uWebSockets"]
+ path = libs/uWebSockets
+ url = https://github.com/uNetworking/uWebSockets.git
diff --git a/libs/uWebSockets b/libs/uWebSockets
new file mode 160000
+Subproject 67ed81b9f43832acab5d7f75a8cc38cdfd25c03
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index b7e7c48a..26658271 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -2,6 +2,7 @@ find_package(LibXml2 REQUIRED)
find_package(PhysFS REQUIRED)
find_package(ZLIB REQUIRED)
find_package(SigC++ REQUIRED)
+find_package(RapidJSON REQUIRED)
if(CMAKE_COMPILER_IS_GNUCXX)
# Help getting compilation warnings
@@ -46,7 +47,7 @@ set(FLAGS "${FLAGS} -DPACKAGE_VERSION=\\\"${VERSION}\\\"")
set(FLAGS "${FLAGS} -DPKG_DATADIR=\\\"${PKG_DATADIR}/\\\"")
set(FLAGS "${FLAGS} -DLOCALEDIR=\\\"${LOCALEDIR}/\\\"")
-set(FLAGS "${FLAGS} -std=c++0x")
+set(FLAGS "${FLAGS} -std=c++17")
set(FLAGS "${FLAGS} -Woverloaded-virtual")
# Prevent clashes with icu namespace
@@ -312,6 +313,14 @@ set(PROGRAMS manaserv-account manaserv-game)
add_executable(manaserv-game WIN32 ${SRCS} ${SRCS_MANASERVGAME})
add_executable(manaserv-account WIN32 ${SRCS} ${SRCS_MANASERVACCOUNT})
+target_include_directories(manaserv-account SYSTEM PRIVATE
+ ${CMAKE_SOURCE_DIR}/libs/uWebSockets/src
+ ${CMAKE_SOURCE_DIR}/libs/uWebSockets/uSockets/src
+ ${RAPIDJSON_INCLUDE_DIRS})
+
+target_link_libraries(manaserv-account
+ ${CMAKE_SOURCE_DIR}/libs/uWebSockets/uSockets/uSockets.a)
+
foreach(program ${PROGRAMS})
target_link_libraries(
${program}
diff --git a/src/account-server/accountclient.h b/src/account-server/accountclient.h
index 3973d60b..5ccb0f1d 100644
--- a/src/account-server/accountclient.h
+++ b/src/account-server/accountclient.h
@@ -51,6 +51,7 @@ class AccountClient : public NetComputer
AccountClientStatus status;
int version;
+ std::string stellarToken;
private:
std::unique_ptr<Account> mAccount;
diff --git a/src/account-server/accounthandler.cpp b/src/account-server/accounthandler.cpp
index 2275e015..b13b4580 100644
--- a/src/account-server/accounthandler.cpp
+++ b/src/account-server/accounthandler.cpp
@@ -40,7 +40,6 @@
#include "utils/tokencollector.h"
#include "utils/tokendispenser.h"
#include "utils/sha256.h"
-#include "utils/string.h"
#include "utils/xml.h"
using namespace ManaServ;
@@ -68,6 +67,10 @@ public:
void deletePendingConnect(int) {}
/**
+ */
+ void handleStellarLogin(const std::string &token, const std::string &pubKey);
+
+ /**
* Token collector for connecting a client coming from a game server
* without having to provide username and password a second time.
*/
@@ -85,6 +88,7 @@ protected:
private:
void handleLoginRandTriggerMessage(AccountClient &client, MessageIn &msg);
+ void handleStellarLoginMessage(AccountClient &client, MessageIn &msg);
void handleLoginMessage(AccountClient &client, MessageIn &msg);
void handleLogoutMessage(AccountClient &client);
void handleReconnectMessage(AccountClient &client, MessageIn &msg);
@@ -97,7 +101,10 @@ private:
void handleCharacterSelectMessage(AccountClient &client, MessageIn &msg);
void handleCharacterDeleteMessage(AccountClient &client, MessageIn &msg);
- void addServerInfo(MessageOut *msg);
+ std::unique_ptr<Account> createAccount(const std::string &username,
+ const std::string &password,
+ const std::string &email);
+ void addServerInfo(MessageOut &msg);
/** List of all accounts which requested a random seed, but are not logged
* yet. This list will be regularly remove (after timeout) old accounts
@@ -239,9 +246,9 @@ void AccountClientHandler::deinitialize()
accountHandler = nullptr;
}
-void AccountClientHandler::process()
+ConnectionHandler *AccountClientHandler::getConnectionHandler()
{
- accountHandler->process(50);
+ return accountHandler;
}
void AccountClientHandler::prepareReconnect(const std::string &token, int id)
@@ -249,6 +256,12 @@ void AccountClientHandler::prepareReconnect(const std::string &token, int id)
accountHandler->mTokenCollector.addPendingConnect(token, id);
}
+void AccountClientHandler::handleStellarLogin(const std::string &token, const std::string &pubKey)
+{
+ accountHandler->handleStellarLogin(token, pubKey);
+}
+
+
NetComputer *AccountHandler::computerConnected(ENetPeer *peer)
{
return new AccountClient(peer);
@@ -306,7 +319,7 @@ static void sendFullCharacterData(AccountClient *client,
client->send(msg);
}
-static std::string getRandomString(int length)
+static std::string getRandomData(int length)
{
std::string s;
s.resize(length);
@@ -318,9 +331,31 @@ static std::string getRandomString(int length)
return s;
}
+/**
+ * Generates a random string containing lowercase and uppercase characters as
+ * well as numbers.
+ */
+static std::string getRandomString(int length)
+{
+ std::string s;
+ s.resize(length);
+ for (int i = 0; i < length; ++i)
+ {
+ int r = rand() % 62;
+ if (r < 10)
+ s[i] = '0' + r;
+ else if (r < 36)
+ s[i] = 'a' + r - 10;
+ else
+ s[i] = 'A' + r - 36;
+ }
+
+ return s;
+}
+
void AccountHandler::handleLoginRandTriggerMessage(AccountClient &client, MessageIn &msg)
{
- std::string salt = getRandomString(4);
+ std::string salt = getRandomData(4);
std::string username = msg.readString();
if (auto acc = storage->getAccount(username))
@@ -333,6 +368,34 @@ void AccountHandler::handleLoginRandTriggerMessage(AccountClient &client, Messag
client.send(reply);
}
+void AccountHandler::handleStellarLoginMessage(AccountClient &client, MessageIn &msg)
+{
+ client.version = msg.readInt32();
+
+ MessageOut reply(APMSG_STELLAR_LOGIN_RESPONSE);
+
+ if (client.status != CLIENT_LOGIN)
+ {
+ reply.writeInt8(ERRMSG_FAILURE);
+ client.send(reply);
+ return;
+ }
+
+ if (client.version < MIN_PROTOCOL_VERSION)
+ {
+ reply.writeInt8(LOGIN_INVALID_VERSION);
+ client.send(reply);
+ return;
+ }
+
+ client.stellarToken = getRandomString(8);
+
+ reply.writeInt8(ERRMSG_OK);
+ reply.writeString(client.stellarToken);
+
+ client.send(reply);
+}
+
void AccountHandler::handleLoginMessage(AccountClient &client, MessageIn &msg)
{
MessageOut reply(APMSG_LOGIN_RESPONSE);
@@ -425,7 +488,7 @@ void AccountHandler::handleLoginMessage(AccountClient &client, MessageIn &msg)
storage->updateLastLogin(*acc);
reply.writeInt8(ERRMSG_OK);
- addServerInfo(&reply);
+ addServerInfo(reply);
const Characters &chars = acc->getCharacters();
@@ -534,24 +597,14 @@ void AccountHandler::handleRegisterMessage(AccountClient &client,
}
else
{
- std::unique_ptr<Account> acc { new Account };
- acc->setName(username);
- acc->setPassword(sha256(password));
- // We hash email server-side for additional privacy
- // we ask for it again when we need it and verify it
- // through comparing it with the hash.
- acc->setEmail(sha256(email));
- acc->setLevel(AL_PLAYER);
-
- // Set the date and time of the account registration, and the last login
- time_t regdate;
- time(&regdate);
- acc->setRegistrationDate(regdate);
- acc->setLastLogin(regdate);
-
- storage->addAccount(*acc);
+ // We hash email server-side for additional privacy we ask for it again
+ // when we need it and verify it through comparing it with the hash.
+ std::unique_ptr<Account> acc = createAccount(username,
+ sha256(password),
+ sha256(email));
+
reply.writeInt8(ERRMSG_OK);
- addServerInfo(&reply);
+ addServerInfo(reply);
// Associate account with connection
client.setAccount(std::move(acc));
@@ -960,6 +1013,26 @@ void AccountHandler::handleCharacterDeleteMessage(AccountClient &client,
client.send(reply);
}
+std::unique_ptr<Account> AccountHandler::createAccount(const std::string &username,
+ const std::string &password,
+ const std::string &email)
+{
+ std::unique_ptr<Account> acc { new Account };
+ acc->setName(username);
+ acc->setPassword(password);
+ acc->setEmail(email);
+ acc->setLevel(AL_PLAYER);
+
+ // Set the date and time of the account registration, and the last login
+ time_t regdate;
+ time(&regdate);
+ acc->setRegistrationDate(regdate);
+ acc->setLastLogin(regdate);
+
+ storage->addAccount(*acc);
+ return acc;
+}
+
/**
* Adds server specific info to the current message
*
@@ -968,11 +1041,11 @@ void AccountHandler::handleCharacterDeleteMessage(AccountClient &client,
* (String) Client Data URL (or "")
* (Byte) Number of maximum character slots (empty or not)
*/
-void AccountHandler::addServerInfo(MessageOut *msg)
+void AccountHandler::addServerInfo(MessageOut &msg)
{
- msg->writeString(mUpdateHost);
- msg->writeString(mDataUrl);
- msg->writeInt8(mMaxCharacters);
+ msg.writeString(mUpdateHost);
+ msg.writeString(mDataUrl);
+ msg.writeInt8(mMaxCharacters);
}
void AccountHandler::tokenMatched(AccountClient *client, int accountID)
@@ -1001,6 +1074,58 @@ void AccountHandler::deletePendingClient(AccountClient *client)
// The client will be deleted when the disconnect event is processed
}
+void AccountHandler::handleStellarLogin(const std::string &token, const std::string &pubKey)
+{
+ auto it = std::find_if(clients.begin(), clients.end(),
+ [token](NetComputer *client) -> bool
+ {
+ auto c = static_cast<AccountClient *>(client);
+ return c->stellarToken == token;
+ });
+
+ if (it == clients.end())
+ {
+ LOG_DEBUG("Stellar login: No client with token " << token);
+ return;
+ }
+
+ auto client = static_cast<AccountClient*>(*it);
+ auto acc = storage->getAccount(pubKey);
+ if (acc)
+ {
+ // Set lastLogin date of the account.
+ time_t login;
+ time(&login);
+ acc->setLastLogin(login);
+ storage->updateLastLogin(*acc);
+ }
+ else if (!mRegistrationAllowed)
+ {
+ MessageOut reply(APMSG_REGISTER_RESPONSE);
+ reply.writeInt8(ERRMSG_FAILURE);
+ client->send(reply);
+ return;
+ }
+ else
+ {
+ // On-demand account creation for public keys
+ acc = createAccount(pubKey, std::string(), std::string());
+ }
+
+ MessageOut reply(APMSG_LOGIN_RESPONSE);
+ reply.writeInt8(ERRMSG_OK);
+ addServerInfo(reply);
+
+ for (auto &charIt : acc->getCharacters())
+ sendCharacterData(reply, charIt.second);
+
+ client->send(reply);
+
+ // Associate account with connection.
+ client->setAccount(std::move(acc));
+ client->status = CLIENT_CONNECTED;
+}
+
void AccountHandler::processMessage(NetComputer *comp, MessageIn &message)
{
AccountClient &client = *static_cast< AccountClient * >(comp);
@@ -1017,6 +1142,11 @@ void AccountHandler::processMessage(NetComputer *comp, MessageIn &message)
handleLoginMessage(client, message);
break;
+ case PAMSG_STELLAR_LOGIN:
+ LOG_DEBUG("Received msg ... PAMSG_STELLAR_LOGIN");
+ handleStellarLoginMessage(client, message);
+ break;
+
case PAMSG_LOGOUT:
LOG_DEBUG("Received msg ... PAMSG_LOGOUT");
handleLogoutMessage(client);
diff --git a/src/account-server/accounthandler.h b/src/account-server/accounthandler.h
index f1ffcfe2..c27b00ed 100644
--- a/src/account-server/accounthandler.h
+++ b/src/account-server/accounthandler.h
@@ -23,6 +23,8 @@
#include <string>
+class ConnectionHandler;
+
namespace AccountClientHandler
{
/**
@@ -37,14 +39,18 @@ namespace AccountClientHandler
void deinitialize();
/**
+ * Returns the connection handler.
+ */
+ ConnectionHandler *getConnectionHandler();
+
+ /**
* Prepares a connection for a client coming from a game server.
*/
void prepareReconnect(const std::string &token, int accountID);
/**
- * Processes messages received by the connection handler.
*/
- void process();
+ void handleStellarLogin(const std::string &token, const std::string &pubKey);
}
#endif // ACCOUNTHANDLER_H
diff --git a/src/account-server/main-account.cpp b/src/account-server/main-account.cpp
index 73382f23..4d5bf02a 100644
--- a/src/account-server/main-account.cpp
+++ b/src/account-server/main-account.cpp
@@ -45,7 +45,6 @@
#include "utils/processorutils.h"
#include "utils/stringfilter.h"
#include "utils/time.h"
-#include "utils/timer.h"
#include <cstdlib>
#include <getopt.h>
@@ -54,6 +53,8 @@
#include <fstream>
#include <physfs.h>
#include <enet/enet.h>
+#include <rapidjson/document.h>
+#include <App.h>
using utils::Logger;
@@ -185,20 +186,26 @@ static void deinitializeServer()
/**
* Dumps statistics.
*/
-static void dumpStatistics(std::string accountAddress, int accountClientPort,
- int accountGamePort, int chatClientPort)
+static void dumpStatistics()
{
- std::ofstream os(statisticsFile.c_str());
+ std::ofstream os(statisticsFile);
+
os << "<statistics>\n";
+
// Print last heartbeat
os << "<heartbeat=\"" << utils::getCurrentDate() << "_"
- << utils::getCurrentTime() << "\" />\n";
+ << utils::getCurrentTime() << "\" />\n";
+
// Add account server information
- os << "<accountserver address=\"" << accountAddress << "\" clientport=\""
- << accountClientPort << "\" gameport=\"" << accountGamePort
- << "\" chatclientport=\"" << chatClientPort << "\" />\n";
+ auto accountHandler = AccountClientHandler::getConnectionHandler();
+ auto gameHandler = GameServerHandler::getConnectionHandler();
+ os << "<accountserver address=\"" << accountHandler->getHostname() << "\" clientport=\""
+ << accountHandler->getPort() << "\" gameport=\"" << gameHandler->getPort()
+ << "\" chatclientport=\"" << chatHandler->getPort() << "\" />\n";
+
// Add game servers information
GameServerHandler::dumpStatistics(os);
+
os << "</statistics>\n";
}
@@ -333,6 +340,8 @@ int main(int argc, char *argv[])
"localhost");
std::string accountListenToGameHost = Configuration::getValue("net_accountListenToGameHost",
accountHost);
+ std::string accountListenToStellarBridgeHost = Configuration::getValue("net_accountListenToStellarBridgeHost",
+ accountListenToGameHost);
// We separate the chat host as the chat server will be separated out
// from the account server.
@@ -350,6 +359,8 @@ int main(int argc, char *argv[])
options.port + 1);
int chatClientPort = Configuration::getValue("net_chatListenToClientPort",
options.port + 2);
+ int accountStellarBridgePort = Configuration::getValue("net_accountListenToStellarBridgePort",
+ options.port + 4);
bool debugNetwork = Configuration::getBoolValue("net_debugMode", false);
MessageOut::setDebugModeEnabled(debugNetwork);
@@ -363,13 +374,78 @@ int main(int argc, char *argv[])
return EXIT_NET_EXCEPTION;
}
- // Dump statistics every 10 seconds.
- utils::Timer statTimer(10000);
- // Check for expired bans every 30 seconds
- utils::Timer banTimer(30000);
-
- statTimer.start();
- banTimer.start();
+ struct us_loop_t *loop = (struct us_loop_t *) uWS::Loop::get();
+ struct us_timer_t *processTimer = us_create_timer(loop, 0, 0);
+ struct us_timer_t *statTimer = us_create_timer(loop, 0, 0);
+ struct us_timer_t *banTimer = us_create_timer(loop, 0, 0);
+
+ constexpr int processTimerIntervalMs = 1000 / 20; // 20 times per second
+ constexpr int statTimerIntervalMs = 10 * 1000; // dump statistics every 10 seconds
+ constexpr int banTimerIntervalMs = 30 * 1000; // check bans every 30 seconds
+
+ us_timer_set(processTimer, [](struct us_timer_t *) {
+ AccountClientHandler::getConnectionHandler()->process();
+ GameServerHandler::getConnectionHandler()->process();
+ chatHandler->process();
+ }, processTimerIntervalMs, processTimerIntervalMs);
+
+ us_timer_set(statTimer, [](struct us_timer_t *) {
+ dumpStatistics();
+ }, statTimerIntervalMs, statTimerIntervalMs);
+
+ us_timer_set(banTimer, [](struct us_timer_t *) {
+ storage->checkBannedAccounts();
+ }, banTimerIntervalMs, banTimerIntervalMs);
+
+ uWS::App wsApp;
+
+ struct PerSocketData {};
+ wsApp.ws<PerSocketData>("/stellar-auth", {
+ .maxPayloadLength = 1024, // we only expect small messages
+ .open = [](auto *ws) {
+ std::cout << "WebSocket opened " << ws->getRemoteAddressAsText() << std::endl;
+ },
+ .message = [](auto *ws, std::string_view message, uWS::OpCode /*opCode*/) {
+ rapidjson::Document d;
+ d.Parse(message.data(), message.size());
+ if (d.HasParseError()) {
+ LOG_ERROR("WebSocket: received JSON parse error");
+ return;
+ }
+ if (!d.IsObject()) {
+ std::cout << "not an object" << std::endl;
+ LOG_ERROR("WebSocket: received JSON not an object");
+ return;
+ }
+
+ const auto pubkeyMember = d.FindMember("pubkey");
+ const auto tokenMember = d.FindMember("token");
+
+ if (pubkeyMember == d.MemberEnd() || tokenMember == d.MemberEnd()) {
+ LOG_ERROR("WebSocket: received JSON missing pubkey or token");
+ return;
+ }
+ if (!pubkeyMember->value.IsString() || !tokenMember->value.IsString()) {
+ LOG_ERROR("WebSocket: received JSON pubkey or token not a string");
+ return;
+ }
+
+ const std::string pubkey = pubkeyMember->value.GetString();
+ const std::string token = tokenMember->value.GetString();
+
+ AccountClientHandler::handleStellarLogin(token, pubkey);
+ },
+ .close = [](auto *ws, int code, std::string_view message) {
+ std::cout << "WebSocket closed " << ws->getRemoteAddressAsText() << " with code " << code << ": " << message << std::endl;
+ }
+ }).listen(accountListenToStellarBridgeHost, accountStellarBridgePort, [](us_listen_socket_t *listen_socket) {
+ if (listen_socket) {
+ /* Note that us_listen_socket_t is castable to us_socket_t */
+ std::cout << "WebSocket: Thread " << std::this_thread::get_id() << " listening on port " << us_socket_local_port(1, (struct us_socket_t *) listen_socket) << std::endl;
+ } else {
+ std::cout << "WebSocket: Thread " << std::this_thread::get_id() << " failed to listen on port 3000" << std::endl;
+ }
+ });
// Write startup time to database as system world state variable
std::stringstream timestamp;
@@ -377,19 +453,22 @@ int main(int argc, char *argv[])
storage->setWorldStateVar("accountserver_startup", timestamp.str(),
Storage::SystemMap);
- while (running)
- {
- AccountClientHandler::process();
- GameServerHandler::process();
- chatHandler->process(50);
+ // Start a thread to close the sockets and timers when running is set to false
+ std::thread([&wsApp,processTimer,statTimer,banTimer] {
+ while (running) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ }
- if (statTimer.poll())
- dumpStatistics(accountHost, options.port, accountGamePort,
- chatClientPort);
+ LOG_INFO("Closing uWebSockets app...");
+ wsApp.close();
- if (banTimer.poll())
- storage->checkBannedAccounts();
- }
+ LOG_INFO("Closing uSockets timers...");
+ us_timer_close(processTimer);
+ us_timer_close(statTimer);
+ us_timer_close(banTimer);
+ }).detach();
+
+ wsApp.run();
LOG_INFO("Received: Quit signal, closing down...");
chatHandler->stopListen();
diff --git a/src/account-server/serverhandler.cpp b/src/account-server/serverhandler.cpp
index cc53eace..54754546 100644
--- a/src/account-server/serverhandler.cpp
+++ b/src/account-server/serverhandler.cpp
@@ -109,11 +109,12 @@ void GameServerHandler::deinitialize()
{
serverHandler->stopListen();
delete serverHandler;
+ serverHandler = nullptr;
}
-void GameServerHandler::process()
+ConnectionHandler *GameServerHandler::getConnectionHandler()
{
- serverHandler->process(50);
+ return serverHandler;
}
NetComputer *ServerHandler::computerConnected(ENetPeer *peer)
diff --git a/src/account-server/serverhandler.h b/src/account-server/serverhandler.h
index 6f4c61fe..916a0224 100644
--- a/src/account-server/serverhandler.h
+++ b/src/account-server/serverhandler.h
@@ -27,6 +27,7 @@
#include "net/messagein.h"
class CharacterData;
+class ConnectionHandler;
namespace GameServerHandler
{
@@ -57,9 +58,9 @@ namespace GameServerHandler
void dumpStatistics(std::ostream &);
/**
- * Processes messages received by the connection handler.
+ * Returns the connection handler.
*/
- void process();
+ ConnectionHandler *getConnectionHandler();
/**
* Sends chat party information
diff --git a/src/common/manaserv_protocol.h b/src/common/manaserv_protocol.h
index ce41c723..77b8e5ac 100644
--- a/src/common/manaserv_protocol.h
+++ b/src/common/manaserv_protocol.h
@@ -79,6 +79,8 @@ enum {
APMSG_LOGOUT_RESPONSE = 0x0014, // B error
PAMSG_LOGIN_RNDTRGR = 0x0015, // S username
APMSG_LOGIN_RNDTRGR_RESPONSE = 0x0016, // S random seed
+ PAMSG_STELLAR_LOGIN = 0x0017, // D version
+ APMSG_STELLAR_LOGIN_RESPONSE = 0x0018, // B error, S token
PAMSG_CHAR_CREATE = 0x0020, // S name, B hair style, B hair color, B gender, B slot, {W stats}*
APMSG_CHAR_CREATE_RESPONSE = 0x0021, // B error, on success: B slot, S name, B gender, B hair style, B hair color,
// W character points, W correction points, B amount of items equipped,
diff --git a/src/net/connectionhandler.cpp b/src/net/connectionhandler.cpp
index 4edb1fd2..ee98a18b 100644
--- a/src/net/connectionhandler.cpp
+++ b/src/net/connectionhandler.cpp
@@ -36,16 +36,20 @@
#endif
bool ConnectionHandler::startListen(enet_uint16 port,
- const std::string &listenHost)
+ const std::string &hostname)
{
+ // Remember unresolved host for debugging purposes.
+ this->hostname = hostname;
+
// Bind the server to the default localhost.
+ ENetAddress address;
address.host = ENET_HOST_ANY;
address.port = port;
- if (!listenHost.empty())
- enet_address_set_host(&address, listenHost.c_str());
+ if (!hostname.empty())
+ enet_address_set_host(&address, hostname.c_str());
- LOG_INFO("Listening on " << listenHost << ":" << port << "...");
+ LOG_INFO("Listening on " << hostname << ":" << port << "...");
#if defined(ENET_VERSION) && ENET_VERSION >= ENET_CUTOFF
host = enet_host_create(
&address /* the address to bind the server host to */,
@@ -86,6 +90,11 @@ void ConnectionHandler::stopListen()
// FIXME: memory leak on NetComputers
}
+enet_uint16 ConnectionHandler::getPort() const
+{
+ return host ? host->address.port : 0;
+}
+
void ConnectionHandler::flush()
{
enet_host_flush(host);
@@ -93,9 +102,11 @@ void ConnectionHandler::flush()
void ConnectionHandler::process(enet_uint32 timeout)
{
+ enet_host_service(host, nullptr, timeout);
+
ENetEvent event;
// Process Enet events and do not block.
- while (enet_host_service(host, &event, timeout) > 0) {
+ while (enet_host_check_events(host, &event) > 0) {
switch (event.type) {
case ENET_EVENT_TYPE_CONNECT:
{
diff --git a/src/net/connectionhandler.h b/src/net/connectionhandler.h
index e49d49a9..2d0a2a6a 100644
--- a/src/net/connectionhandler.h
+++ b/src/net/connectionhandler.h
@@ -41,11 +41,12 @@ class ConnectionHandler
/**
* Open the server socket.
- * @param port the port to listen to
- * @host the host IP to listen on, defaults to the default localhost
+ *
+ * @param port the port to listen to
+ * @param hostname the host IP to listen on, defaults to the default localhost
*/
bool startListen(enet_uint16 port,
- const std::string &host = std::string());
+ const std::string &hostname = std::string());
/**
* Disconnect all the clients and close the server socket.
@@ -53,13 +54,23 @@ class ConnectionHandler
void stopListen();
/**
+ * Return the port the handler is listening on, or 0 if not listening.
+ */
+ enet_uint16 getPort() const;
+
+ /**
+ * Return the host the handler was asked to listen on.
+ */
+ const std::string &getHostname() const { return hostname; }
+
+ /**
* Process outgoing messages and listen to the server socket for
* incoming messages and new connections.
*
* @timeout an optional timeout in milliseconds to wait for something
* to happen when there is nothing to do
*/
- virtual void process(enet_uint32 timeout = 0);
+ void process(enet_uint32 timeout = 0);
/**
* Process outgoing messages.
@@ -82,8 +93,8 @@ class ConnectionHandler
unsigned getClientCount() const;
private:
- ENetAddress address; /**< Includes the port to listen to. */
- ENetHost *host; /**< The host that listen for connections. */
+ std::string hostname; /**< The unresolved host the handler was asked to listen on. */
+ ENetHost *host; /**< The ENet host that listen for connections. */
protected:
/**