issiauskinau kad checksum yra nahuj reikalingas ir kad onConnect turejo buti uzkomentuotas. Reikia issiaiskinti kodel luzta onLogin clientas. Kitus failus reikia perziureti ir isvalyti siuksles

This commit is contained in:
ErikasKontenis 2019-11-10 19:45:03 +02:00
parent f0e103a475
commit 3d05566759
17 changed files with 233 additions and 232 deletions

View File

@ -52,7 +52,7 @@ timeBetweenExActions = 1000
-- Map
-- NOTE: set mapName WITHOUT .otbm at the end
mapName = "map"
mapName = "mymap"
mapAuthor = "CipSoft"
-- MySQL

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<houses/>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<spawns/>

BIN
data/world/mymap.otbm Normal file

Binary file not shown.

View File

@ -74,6 +74,7 @@ bool ConfigManager::load()
boolean[FREE_PREMIUM] = getGlobalBoolean(L, "freePremium", false);
boolean[REPLACE_KICK_ON_LOGIN] = getGlobalBoolean(L, "replaceKickOnLogin", true);
boolean[ALLOW_CLONES] = getGlobalBoolean(L, "allowClones", false);
boolean[STAMINA_SYSTEM] = getGlobalBoolean(L, "staminaSystem", true);
boolean[WARN_UNSAFE_SCRIPTS] = getGlobalBoolean(L, "warnUnsafeScripts", true);
boolean[CONVERT_UNSAFE_SCRIPTS] = getGlobalBoolean(L, "convertUnsafeScripts", true);
boolean[TELEPORT_NEWBIES] = getGlobalBoolean(L, "teleportNewbies", true);

View File

@ -37,6 +37,7 @@ class ConfigManager
ALLOW_CLONES,
BIND_ONLY_GLOBAL_ADDRESS,
OPTIMIZE_DATABASE,
STAMINA_SYSTEM,
WARN_UNSAFE_SCRIPTS,
CONVERT_UNSAFE_SCRIPTS,
TELEPORT_NEWBIES,

View File

@ -187,29 +187,13 @@ void Connection::parsePacket(const boost::system::error_code& error)
return;
}
//Check packet checksum
uint32_t checksum;
int32_t len = msg.getLength() - msg.getBufferPosition() - NetworkMessage::CHECKSUM_LENGTH;
if (len > 0) {
checksum = adlerChecksum(msg.getBuffer() + msg.getBufferPosition() + NetworkMessage::CHECKSUM_LENGTH, len);
}
else {
checksum = 0;
}
uint32_t recvChecksum = msg.get<uint32_t>();
if (recvChecksum != checksum) {
// it might not have been the checksum, step back
msg.skipBytes(-NetworkMessage::CHECKSUM_LENGTH);
}
if (!receivedFirst) {
// First message received
receivedFirst = true;
if (!protocol) {
// Game protocol has already been created at this point
protocol = service_port->make_protocol(recvChecksum == checksum, msg, shared_from_this());
protocol = service_port->make_protocol(msg, shared_from_this());
if (!protocol) {
close(FORCE_CLOSE);
return;
@ -242,6 +226,7 @@ void Connection::parsePacket(const boost::system::error_code& error)
}
void Connection::send(const OutputMessage_ptr& msg)
{
std::lock_guard<std::recursive_mutex> lockClass(connectionLock);

View File

@ -188,7 +188,7 @@ bool IOLoginData::preloadPlayer(Player* player, const std::string& name)
bool IOLoginData::loadPlayerById(Player* player, uint32_t id)
{
std::ostringstream query;
query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `id` = " << id;
query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `id` = " << id;
return loadPlayer(player, Database::getInstance()->storeQuery(query.str()));
}
@ -196,7 +196,7 @@ bool IOLoginData::loadPlayerByName(Player* player, const std::string& name)
{
Database* db = Database::getInstance();
std::ostringstream query;
query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `name` = " << db->escapeString(name);
query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `name` = " << db->escapeString(name);
return loadPlayer(player, db->storeQuery(query.str()));
}
@ -296,6 +296,7 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
player->defaultOutfit.lookBody = result->getNumber<uint16_t>("lookbody");
player->defaultOutfit.lookLegs = result->getNumber<uint16_t>("looklegs");
player->defaultOutfit.lookFeet = result->getNumber<uint16_t>("lookfeet");
player->defaultOutfit.lookAddons = result->getNumber<uint16_t>("lookaddons");
player->currentOutfit = player->defaultOutfit;
if (g_game.getWorldType() != WORLD_TYPE_PVP_ENFORCED) {
@ -331,6 +332,8 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
player->loginPosition = player->getTemplePosition();
}
player->staminaMinutes = result->getNumber<uint16_t>("stamina");
static const std::string skillNames[] = {"skill_fist", "skill_club", "skill_sword", "skill_axe", "skill_dist", "skill_shielding", "skill_fishing"};
static const std::string skillNameTries[] = {"skill_fist_tries", "skill_club_tries", "skill_sword_tries", "skill_axe_tries", "skill_dist_tries", "skill_shielding_tries", "skill_fishing_tries"};
static constexpr size_t size = sizeof(skillNames) / sizeof(std::string);
@ -616,6 +619,7 @@ bool IOLoginData::savePlayer(Player* player)
query << "`lookhead` = " << static_cast<uint32_t>(player->defaultOutfit.lookHead) << ',';
query << "`looklegs` = " << static_cast<uint32_t>(player->defaultOutfit.lookLegs) << ',';
query << "`looktype` = " << player->defaultOutfit.lookType << ',';
query << "`lookaddons` = " << static_cast<uint32_t>(player->defaultOutfit.lookAddons) << ',';
query << "`maglevel` = " << player->magLevel << ',';
query << "`mana` = " << player->mana << ',';
query << "`manamax` = " << player->manaMax << ',';
@ -654,6 +658,7 @@ bool IOLoginData::savePlayer(Player* player)
query << "`lastlogout` = " << player->getLastLogout() << ',';
query << "`balance` = " << player->bankBalance << ',';
query << "`stamina` = " << player->getStaminaMinutes() << ',';
query << "`skill_fist` = " << player->skills[SKILL_FIST].level << ',';
query << "`skill_fist_tries` = " << player->skills[SKILL_FIST].tries << ',';

View File

@ -730,6 +730,8 @@ Position LuaScriptInterface::getPosition(lua_State* L, int32_t arg)
Outfit_t LuaScriptInterface::getOutfit(lua_State* L, int32_t arg)
{
Outfit_t outfit;
outfit.lookAddons = getField<uint8_t>(L, arg, "lookAddons");
outfit.lookFeet = getField<uint8_t>(L, arg, "lookFeet");
outfit.lookLegs = getField<uint8_t>(L, arg, "lookLegs");
outfit.lookBody = getField<uint8_t>(L, arg, "lookBody");
@ -882,6 +884,7 @@ void LuaScriptInterface::pushOutfit(lua_State* L, const Outfit_t& outfit)
setField(L, "lookBody", outfit.lookBody);
setField(L, "lookLegs", outfit.lookLegs);
setField(L, "lookFeet", outfit.lookFeet);
setField(L, "lookAddons", outfit.lookAddons);
}
#define registerEnum(value) { std::string enumName = #value; registerGlobalVariable(enumName.substr(enumName.find_last_of(':') + 1), value); }
@ -1607,6 +1610,7 @@ void LuaScriptInterface::registerFunctions()
registerEnumIn("configKeys", ConfigManager::ALLOW_CLONES)
registerEnumIn("configKeys", ConfigManager::BIND_ONLY_GLOBAL_ADDRESS)
registerEnumIn("configKeys", ConfigManager::OPTIMIZE_DATABASE)
registerEnumIn("configKeys", ConfigManager::STAMINA_SYSTEM)
registerEnumIn("configKeys", ConfigManager::WARN_UNSAFE_SCRIPTS)
registerEnumIn("configKeys", ConfigManager::CONVERT_UNSAFE_SCRIPTS)
registerEnumIn("configKeys", ConfigManager::TELEPORT_NEWBIES)
@ -2008,6 +2012,9 @@ void LuaScriptInterface::registerFunctions()
registerMethod("Player", "getGroup", LuaScriptInterface::luaPlayerGetGroup);
registerMethod("Player", "setGroup", LuaScriptInterface::luaPlayerSetGroup);
registerMethod("Player", "getStamina", LuaScriptInterface::luaPlayerGetStamina);
registerMethod("Player", "setStamina", LuaScriptInterface::luaPlayerSetStamina);
registerMethod("Player", "getSoul", LuaScriptInterface::luaPlayerGetSoul);
registerMethod("Player", "addSoul", LuaScriptInterface::luaPlayerAddSoul);
registerMethod("Player", "getMaxSoul", LuaScriptInterface::luaPlayerGetMaxSoul);
@ -7757,6 +7764,35 @@ int LuaScriptInterface::luaPlayerSetGroup(lua_State* L)
return 1;
}
int LuaScriptInterface::luaPlayerGetStamina(lua_State* L)
{
// player:getStamina()
Player* player = getUserdata<Player>(L, 1);
if (player) {
lua_pushnumber(L, player->getStaminaMinutes());
}
else {
lua_pushnil(L);
}
return 1;
}
int LuaScriptInterface::luaPlayerSetStamina(lua_State* L)
{
// player:setStamina(stamina)
uint16_t stamina = getNumber<uint16_t>(L, 2);
Player* player = getUserdata<Player>(L, 1);
if (player) {
player->staminaMinutes = std::min<uint16_t>(2520, stamina);
player->sendStats();
pushBoolean(L, true);
}
else {
lua_pushnil(L);
}
return 1;
}
int LuaScriptInterface::luaPlayerGetSoul(lua_State* L)
{
// player:getSoul()
@ -10616,11 +10652,12 @@ int LuaScriptInterface::luaConditionSetSpeedDelta(lua_State* L)
int LuaScriptInterface::luaConditionSetOutfit(lua_State* L)
{
// condition:setOutfit(outfit)
// condition:setOutfit(lookTypeEx, lookType, lookHead, lookBody, lookLegs, lookFeet)
// condition:setOutfit(lookTypeEx, lookType, lookHead, lookBody, lookLegs, lookFeet[, lookAddons])
Outfit_t outfit;
if (isTable(L, 2)) {
outfit = getOutfit(L, 2);
} else {
outfit.lookAddons = getNumber<uint8_t>(L, 8, outfit.lookAddons);
outfit.lookFeet = getNumber<uint8_t>(L, 7);
outfit.lookLegs = getNumber<uint8_t>(L, 6);
outfit.lookBody = getNumber<uint8_t>(L, 5);

View File

@ -849,6 +849,9 @@ class LuaScriptInterface
static int luaPlayerGetGroup(lua_State* L);
static int luaPlayerSetGroup(lua_State* L);
static int luaPlayerGetStamina(lua_State* L);
static int luaPlayerSetStamina(lua_State* L);
static int luaPlayerGetSoul(lua_State* L);
static int luaPlayerAddSoul(lua_State* L);
static int luaPlayerGetMaxSoul(lua_State* L);

View File

@ -759,6 +759,10 @@ bool Monsters::loadMonster(const std::string& file, const std::string& monsterNa
if ((attr = node.attribute("feet"))) {
mType->info.outfit.lookFeet = pugi::cast<uint16_t>(attr.value());
}
if ((attr = node.attribute("addons"))) {
mType->info.outfit.lookAddons = pugi::cast<uint16_t>(attr.value());
}
} else if ((attr = node.attribute("typeex"))) {
mType->info.outfit.lookTypeEx = pugi::cast<uint16_t>(attr.value());
} else {

View File

@ -28,80 +28,76 @@ class Protocol;
class OutputMessage : public NetworkMessage
{
public:
OutputMessage() = default;
public:
OutputMessage() = default;
// non-copyable
OutputMessage(const OutputMessage&) = delete;
OutputMessage& operator=(const OutputMessage&) = delete;
// non-copyable
OutputMessage(const OutputMessage&) = delete;
OutputMessage& operator=(const OutputMessage&) = delete;
uint8_t* getOutputBuffer() {
return buffer + outputBufferStart;
}
uint8_t* getOutputBuffer() {
return buffer + outputBufferStart;
}
void writeMessageLength() {
add_header(info.length);
}
void writeMessageLength() {
add_header(info.length);
}
void addCryptoHeader(bool addChecksum) {
if (addChecksum) {
add_header(adlerChecksum(buffer + outputBufferStart, info.length));
}
void addCryptoHeader(bool addChecksum) {
writeMessageLength();
}
writeMessageLength();
}
inline void append(const NetworkMessage& msg) {
auto msgLen = msg.getLength();
memcpy(buffer + info.position, msg.getBuffer() + 4, msgLen);
info.length += msgLen;
info.position += msgLen;
}
inline void append(const NetworkMessage& msg) {
auto msgLen = msg.getLength();
memcpy(buffer + info.position, msg.getBuffer() + 4, msgLen);
info.length += msgLen;
info.position += msgLen;
}
inline void append(const OutputMessage_ptr& msg) {
auto msgLen = msg->getLength();
memcpy(buffer + info.position, msg->getBuffer() + 4, msgLen);
info.length += msgLen;
info.position += msgLen;
}
inline void append(const OutputMessage_ptr& msg) {
auto msgLen = msg->getLength();
memcpy(buffer + info.position, msg->getBuffer() + 4, msgLen);
info.length += msgLen;
info.position += msgLen;
}
protected:
template <typename T>
inline void add_header(T add) {
assert(outputBufferStart >= sizeof(T));
outputBufferStart -= sizeof(T);
memcpy(buffer + outputBufferStart, &add, sizeof(T));
//added header size to the message size
info.length += sizeof(T);
}
protected:
template <typename T>
inline void add_header(T add) {
assert(outputBufferStart >= sizeof(T));
outputBufferStart -= sizeof(T);
memcpy(buffer + outputBufferStart, &add, sizeof(T));
//added header size to the message size
info.length += sizeof(T);
}
MsgSize_t outputBufferStart = INITIAL_BUFFER_POSITION;
MsgSize_t outputBufferStart = INITIAL_BUFFER_POSITION;
};
class OutputMessagePool
{
public:
// non-copyable
OutputMessagePool(const OutputMessagePool&) = delete;
OutputMessagePool& operator=(const OutputMessagePool&) = delete;
public:
// non-copyable
OutputMessagePool(const OutputMessagePool&) = delete;
OutputMessagePool& operator=(const OutputMessagePool&) = delete;
static OutputMessagePool& getInstance() {
static OutputMessagePool instance;
return instance;
}
static OutputMessagePool& getInstance() {
static OutputMessagePool instance;
return instance;
}
void sendAll();
void scheduleSendAll();
void sendAll();
void scheduleSendAll();
static OutputMessage_ptr getOutputMessage();
static OutputMessage_ptr getOutputMessage();
void addProtocolToAutosend(Protocol_ptr protocol);
void removeProtocolFromAutosend(const Protocol_ptr& protocol);
private:
OutputMessagePool() = default;
//NOTE: A vector is used here because this container is mostly read
//and relatively rarely modified (only when a client connects/disconnects)
std::vector<Protocol_ptr> bufferedProtocols;
void addProtocolToAutosend(Protocol_ptr protocol);
void removeProtocolFromAutosend(const Protocol_ptr& protocol);
private:
OutputMessagePool() = default;
//NOTE: A vector is used here because this container is mostly read
//and relatively rarely modified (only when a client connects/disconnects)
std::vector<Protocol_ptr> bufferedProtocols;
};

View File

@ -242,8 +242,6 @@ void ProtocolGame::onRecvFirstMessage(NetworkMessage& msg)
OperatingSystem_t operatingSystem = static_cast<OperatingSystem_t>(msg.get<uint16_t>());
version = msg.get<uint16_t>();
msg.skipBytes(7); // U32 client version, U8 client type, U16 dat revision
if (!Protocol::RSA_decrypt(msg)) {
disconnect();
return;
@ -304,45 +302,24 @@ void ProtocolGame::onRecvFirstMessage(NetworkMessage& msg)
disconnectClient("Account number or password is not correct.");
return;
}
Account account;
if (!IOLoginData::loginserverAuthentication(accountNumber, password, account)) {
disconnectClient("Account number or password is not correct.");
return;
}
//Update premium days
Game::updatePremium(account);
g_dispatcher.addTask(createTask(std::bind(&ProtocolGame::login, getThis(), characterName, accountId, operatingSystem)));
}
void ProtocolGame::onConnect()
{
auto output = OutputMessagePool::getOutputMessage();
static std::random_device rd;
static std::ranlux24 generator(rd());
static std::uniform_int_distribution<uint16_t> randNumber(0x00, 0xFF);
// Skip checksum
output->skipBytes(sizeof(uint32_t));
// Packet length & type
output->add<uint16_t>(0x0006);
output->addByte(0x1F);
// Add timestamp & random number
challengeTimestamp = static_cast<uint32_t>(time(nullptr));
output->add<uint32_t>(challengeTimestamp);
challengeRandom = randNumber(generator);
output->addByte(challengeRandom);
// Go back and write checksum
output->skipBytes(-12);
output->add<uint32_t>(adlerChecksum(output->getOutputBuffer() + sizeof(uint32_t), 8));
send(output);
}
void ProtocolGame::disconnectClient(const std::string& message) const
@ -464,12 +441,15 @@ void ProtocolGame::parsePacket(NetworkMessage& msg)
void ProtocolGame::GetTileDescription(const Tile* tile, NetworkMessage& msg)
{
msg.add<uint16_t>(0x00); //environmental effects
int32_t count;
Item* ground = tile->getGround();
if (ground) {
msg.addItem(ground);
count = 1;
} else {
}
else {
count = 0;
}
@ -478,7 +458,11 @@ void ProtocolGame::GetTileDescription(const Tile* tile, NetworkMessage& msg)
for (auto it = items->getBeginTopItem(), end = items->getEndTopItem(); it != end; ++it) {
msg.addItem(*it);
if (++count == 10) {
count++;
if (count == 9 && tile->getPosition() == player->getPosition()) {
break;
}
else if (count == 10) {
return;
}
}
@ -486,11 +470,20 @@ void ProtocolGame::GetTileDescription(const Tile* tile, NetworkMessage& msg)
const CreatureVector* creatures = tile->getCreatures();
if (creatures) {
bool playerAdded = false;
for (const Creature* creature : boost::adaptors::reverse(*creatures)) {
if (!player->canSeeCreature(creature)) {
continue;
}
if (tile->getPosition() == player->getPosition() && count == 9 && !playerAdded) {
creature = player;
}
if (creature->getID() == player->getID()) {
playerAdded = true;
}
bool known;
uint32_t removedKnown;
checkCreatureAsKnown(creature->getID(), known, removedKnown);
@ -1864,12 +1857,18 @@ void ProtocolGame::AddPlayerStats(NetworkMessage& msg)
msg.add<uint16_t>(std::min<int32_t>(player->getMaxMana(), std::numeric_limits<uint16_t>::max()));
msg.addByte(std::min<uint32_t>(player->getMagicLevel(), std::numeric_limits<uint8_t>::max()));
msg.addByte(std::min<uint32_t>(player->getBaseMagicLevel(), std::numeric_limits<uint8_t>::max()));
msg.addByte(player->getMagicLevelPercent());
msg.addByte(player->getSoul());
msg.add<uint16_t>(player->getStaminaMinutes());
msg.add<uint16_t>(player->getBaseSpeed() / 2);
Condition* condition = player->getCondition(CONDITION_REGENERATION);
msg.add<uint16_t>(condition ? condition->getTicks() / 1000 : 0x00);
msg.add<uint16_t>(0); // xp boost time (seconds)
}

View File

@ -43,7 +43,7 @@ void ProtocolLogin::disconnectClient(const std::string& message, uint16_t versio
disconnect();
}
void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string& password, const std::string& token, uint16_t version)
void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string& password, uint16_t version)
{
Account account;
if (!IOLoginData::loginserverAuthentication(accountNumber, password, account)) {
@ -51,20 +51,7 @@ void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string&
return;
}
uint32_t ticks = time(nullptr) / AUTHENTICATOR_PERIOD;
auto output = OutputMessagePool::getOutputMessage();
if (!std::to_string(accountNumber).empty()) {
if (token.empty() || !(token == generateToken(std::to_string(accountNumber), ticks) || token == generateToken(std::to_string(accountNumber), ticks - 1) || token == generateToken(std::to_string(accountNumber), ticks + 1))) {
output->addByte(0x0D);
output->addByte(0);
send(output);
disconnect();
return;
}
output->addByte(0x0C);
output->addByte(0);
}
//Update premium days
Game::updatePremium(account);
@ -79,38 +66,24 @@ void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string&
output->addString(ss.str());
}
//Add session key
output->addByte(0x28);
output->addString(std::to_string(accountNumber) + "\n" + password + "\n" + token + "\n" + std::to_string(ticks));
//Add char list
output->addByte(0x64);
output->addByte(1); // number of worlds
output->addByte(0); // world id
output->addString(g_config.getString(ConfigManager::SERVER_NAME));
output->addString(g_config.getString(ConfigManager::IP));
output->add<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT));
output->addByte(0);
uint8_t size = std::min<size_t>(std::numeric_limits<uint8_t>::max(), account.characters.size());
output->addByte(size);
for (uint8_t i = 0; i < size; i++) {
output->addByte(0);
output->addString(account.characters[i]);
output->addString(g_config.getString(ConfigManager::SERVER_NAME));
output->add<uint32_t>(inet_addr(g_config.getString(ConfigManager::IP).c_str()));
output->add<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT));
}
//Add premium days
output->addByte(0);
if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) {
output->addByte(1);
output->add<uint32_t>(0);
output->add<uint16_t>(0xFFFF);
}
else {
output->addByte(account.premiumDays > 0 ? 1 : 0);
output->add<uint32_t>(time(nullptr) + (account.premiumDays * 86400));
output->add<uint16_t>(account.premiumDays);
}
send(output);
@ -118,6 +91,7 @@ void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string&
disconnect();
}
void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg)
{
if (g_game.getGameState() == GAME_STATE_SHUTDOWN) {
@ -208,15 +182,6 @@ void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg)
return;
}
// read authenticator token and stay logged in flag from last 128 bytes
msg.skipBytes((msg.getLength() - 128) - msg.getBufferPosition());
if (!Protocol::RSA_decrypt(msg)) {
disconnectClient("Invalid authentification token.", version);
return;
}
std::string authToken = msg.getString();
auto thisPtr = std::static_pointer_cast<ProtocolLogin>(shared_from_this());
g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, thisPtr, accountNumber, password, authToken, version)));
g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, thisPtr, accountNumber, password, version)));
}

View File

@ -43,7 +43,7 @@ class ProtocolLogin : public Protocol
private:
void disconnectClient(const std::string& message, uint16_t version);
void getCharacterList(uint32_t accountNumber, const std::string& password, const std::string& token, uint16_t version);
void getCharacterList(uint32_t accountNumber, const std::string& password, uint16_t version);
};
#endif

View File

@ -56,7 +56,8 @@ void ServiceManager::stop()
for (auto& servicePortIt : acceptors) {
try {
io_service.post(std::bind(&ServicePort::onStopServer, servicePortIt.second));
} catch (boost::system::system_error& e) {
}
catch (boost::system::system_error& e) {
std::cout << "[ServiceManager::stop] Network Error: " << e.what() << std::endl;
}
}
@ -114,25 +115,28 @@ void ServicePort::onAccept(Connection_ptr connection, const boost::system::error
Service_ptr service = services.front();
if (service->is_single_socket()) {
connection->accept(service->make_protocol(connection));
} else {
}
else {
connection->accept();
}
} else {
}
else {
connection->close(Connection::FORCE_CLOSE);
}
accept();
} else if (error != boost::asio::error::operation_aborted) {
}
else if (error != boost::asio::error::operation_aborted) {
if (!pendingStart) {
close();
pendingStart = true;
g_scheduler.addEvent(createSchedulerTask(15000,
std::bind(&ServicePort::openAcceptor, std::weak_ptr<ServicePort>(shared_from_this()), serverPort)));
std::bind(&ServicePort::openAcceptor, std::weak_ptr<ServicePort>(shared_from_this()), serverPort)));
}
}
}
Protocol_ptr ServicePort::make_protocol(bool checksummed, NetworkMessage& msg, const Connection_ptr& connection) const
Protocol_ptr ServicePort::make_protocol(NetworkMessage& msg, const Connection_ptr& connection) const
{
uint8_t protocolID = msg.getByte();
for (auto& service : services) {
@ -140,9 +144,7 @@ Protocol_ptr ServicePort::make_protocol(bool checksummed, NetworkMessage& msg, c
continue;
}
if ((checksummed && service->is_checksummed()) || !service->is_checksummed()) {
return service->make_protocol(connection);
}
return service->make_protocol(connection);
}
return nullptr;
}
@ -169,21 +171,23 @@ void ServicePort::open(uint16_t port)
try {
if (g_config.getBoolean(ConfigManager::BIND_ONLY_GLOBAL_ADDRESS)) {
acceptor.reset(new boost::asio::ip::tcp::acceptor(io_service, boost::asio::ip::tcp::endpoint(
boost::asio::ip::address(boost::asio::ip::address_v4::from_string(g_config.getString(ConfigManager::IP))), serverPort)));
} else {
boost::asio::ip::address(boost::asio::ip::address_v4::from_string(g_config.getString(ConfigManager::IP))), serverPort)));
}
else {
acceptor.reset(new boost::asio::ip::tcp::acceptor(io_service, boost::asio::ip::tcp::endpoint(
boost::asio::ip::address(boost::asio::ip::address_v4(INADDR_ANY)), serverPort)));
boost::asio::ip::address(boost::asio::ip::address_v4(INADDR_ANY)), serverPort)));
}
acceptor->set_option(boost::asio::ip::tcp::no_delay(true));
accept();
} catch (boost::system::system_error& e) {
}
catch (boost::system::system_error& e) {
std::cout << "[ServicePort::open] Error: " << e.what() << std::endl;
pendingStart = true;
g_scheduler.addEvent(createSchedulerTask(15000,
std::bind(&ServicePort::openAcceptor, std::weak_ptr<ServicePort>(shared_from_this()), port)));
std::bind(&ServicePort::openAcceptor, std::weak_ptr<ServicePort>(shared_from_this()), port)));
}
}
@ -197,7 +201,7 @@ void ServicePort::close()
bool ServicePort::add_service(const Service_ptr& new_svc)
{
if (std::any_of(services.begin(), services.end(), [](const Service_ptr& svc) {return svc->is_single_socket();})) {
if (std::any_of(services.begin(), services.end(), [](const Service_ptr& svc) {return svc->is_single_socket(); })) {
return false;
}

View File

@ -27,98 +27,94 @@ class Protocol;
class ServiceBase
{
public:
virtual bool is_single_socket() const = 0;
virtual bool is_checksummed() const = 0;
virtual uint8_t get_protocol_identifier() const = 0;
virtual const char* get_protocol_name() const = 0;
public:
virtual bool is_single_socket() const = 0;
virtual uint8_t get_protocol_identifier() const = 0;
virtual const char* get_protocol_name() const = 0;
virtual Protocol_ptr make_protocol(const Connection_ptr& c) const = 0;
virtual Protocol_ptr make_protocol(const Connection_ptr& c) const = 0;
};
template <typename ProtocolType>
class Service final : public ServiceBase
{
public:
bool is_single_socket() const override {
return ProtocolType::server_sends_first;
}
bool is_checksummed() const override {
return ProtocolType::use_checksum;
}
uint8_t get_protocol_identifier() const override {
return ProtocolType::protocol_identifier;
}
const char* get_protocol_name() const override {
return ProtocolType::protocol_name();
}
public:
bool is_single_socket() const final {
return ProtocolType::server_sends_first;
}
uint8_t get_protocol_identifier() const final {
return ProtocolType::protocol_identifier;
}
const char* get_protocol_name() const final {
return ProtocolType::protocol_name();
}
Protocol_ptr make_protocol(const Connection_ptr& c) const override {
return std::make_shared<ProtocolType>(c);
}
Protocol_ptr make_protocol(const Connection_ptr& c) const final {
return std::make_shared<ProtocolType>(c);
}
};
class ServicePort : public std::enable_shared_from_this<ServicePort>
{
public:
explicit ServicePort(boost::asio::io_service& io_service) : io_service(io_service) {}
~ServicePort();
public:
explicit ServicePort(boost::asio::io_service& io_service) : io_service(io_service) {}
~ServicePort();
// non-copyable
ServicePort(const ServicePort&) = delete;
ServicePort& operator=(const ServicePort&) = delete;
// non-copyable
ServicePort(const ServicePort&) = delete;
ServicePort& operator=(const ServicePort&) = delete;
static void openAcceptor(std::weak_ptr<ServicePort> weak_service, uint16_t port);
void open(uint16_t port);
void close();
bool is_single_socket() const;
std::string get_protocol_names() const;
static void openAcceptor(std::weak_ptr<ServicePort> weak_service, uint16_t port);
void open(uint16_t port);
void close();
bool is_single_socket() const;
std::string get_protocol_names() const;
bool add_service(const Service_ptr& new_svc);
Protocol_ptr make_protocol(bool checksummed, NetworkMessage& msg, const Connection_ptr& connection) const;
bool add_service(const Service_ptr& new_svc);
Protocol_ptr make_protocol(NetworkMessage& msg, const Connection_ptr& connection) const;
void onStopServer();
void onAccept(Connection_ptr connection, const boost::system::error_code& error);
void onStopServer();
void onAccept(Connection_ptr connection, const boost::system::error_code& error);
protected:
void accept();
protected:
void accept();
boost::asio::io_service& io_service;
std::unique_ptr<boost::asio::ip::tcp::acceptor> acceptor;
std::vector<Service_ptr> services;
boost::asio::io_service& io_service;
std::unique_ptr<boost::asio::ip::tcp::acceptor> acceptor;
std::vector<Service_ptr> services;
uint16_t serverPort = 0;
bool pendingStart = false;
uint16_t serverPort = 0;
bool pendingStart = false;
};
class ServiceManager
{
public:
ServiceManager() = default;
~ServiceManager();
public:
ServiceManager() = default;
~ServiceManager();
// non-copyable
ServiceManager(const ServiceManager&) = delete;
ServiceManager& operator=(const ServiceManager&) = delete;
// non-copyable
ServiceManager(const ServiceManager&) = delete;
ServiceManager& operator=(const ServiceManager&) = delete;
void run();
void stop();
void run();
void stop();
template <typename ProtocolType>
bool add(uint16_t port);
template <typename ProtocolType>
bool add(uint16_t port);
bool is_running() const {
return acceptors.empty() == false;
}
bool is_running() const {
return acceptors.empty() == false;
}
protected:
void die();
protected:
void die();
std::unordered_map<uint16_t, ServicePort_ptr> acceptors;
std::unordered_map<uint16_t, ServicePort_ptr> acceptors;
boost::asio::io_service io_service;
boost::asio::deadline_timer death_timer { io_service };
bool running = false;
boost::asio::io_service io_service;
boost::asio::deadline_timer death_timer{ io_service };
bool running = false;
};
template <typename ProtocolType>
@ -137,13 +133,14 @@ bool ServiceManager::add(uint16_t port)
service_port = std::make_shared<ServicePort>(io_service);
service_port->open(port);
acceptors[port] = service_port;
} else {
}
else {
service_port = foundServicePort->second;
if (service_port->is_single_socket() || ProtocolType::server_sends_first) {
std::cout << "ERROR: " << ProtocolType::protocol_name() <<
" and " << service_port->get_protocol_names() <<
" cannot use the same port " << port << '.' << std::endl;
" and " << service_port->get_protocol_names() <<
" cannot use the same port " << port << '.' << std::endl;
return false;
}
}