X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fcoremods%2Fcore_reloadmodule.cpp;h=34eaeae186ee04f378dbda557967c52583157dfc;hb=28fef58b882e34369c935d56cb4ac50429cba8c7;hp=9684c8c139d01d3fba8a795f414e56c8caee94e7;hpb=91e0af0fc4889f20d2f63426f8fe379674fc0393;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/coremods/core_reloadmodule.cpp b/src/coremods/core_reloadmodule.cpp index 9684c8c13..34eaeae18 100644 --- a/src/coremods/core_reloadmodule.cpp +++ b/src/coremods/core_reloadmodule.cpp @@ -1,9 +1,12 @@ /* * InspIRCd -- Internet Relay Chat Daemon * - * Copyright (C) 2015 Attila Molnar + * Copyright (C) 2017-2019 Sadie Powell + * Copyright (C) 2014-2016, 2018 Attila Molnar + * Copyright (C) 2012 Robby * Copyright (C) 2009 Daniel De Graaf - * Copyright (C) 2007 Robin Burchell + * Copyright (C) 2007, 2010 Craig Edwards + * Copyright (C) 2007 Dennis Friis * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public @@ -24,18 +27,42 @@ #include "modules/reload.h" static Events::ModuleEventProvider* reloadevprov; +static ClientProtocol::Serializer* dummyserializer; + +class DummySerializer : public ClientProtocol::Serializer +{ + bool Parse(LocalUser* user, const std::string& line, ClientProtocol::ParseOutput& parseoutput) CXX11_OVERRIDE + { + return false; + } + + ClientProtocol::SerializedMessage Serialize(const ClientProtocol::Message& msg, const ClientProtocol::TagSelection& tagwl) const CXX11_OVERRIDE + { + return ClientProtocol::SerializedMessage(); + } + + public: + DummySerializer(Module* mod) + : ClientProtocol::Serializer(mod, "dummy") + { + } +}; class CommandReloadmodule : public Command { Events::ModuleEventProvider evprov; + DummySerializer dummyser; + public: /** Constructor for reloadmodule. */ CommandReloadmodule(Module* parent) : Command(parent, "RELOADMODULE", 1) , evprov(parent, "event/reloadmodule") + , dummyser(parent) { reloadevprov = &evprov; + dummyserializer = &dummyser; flags_needed = 'o'; syntax = ""; } @@ -45,7 +72,7 @@ class CommandReloadmodule : public Command * @param user The user issuing the command * @return A value from CmdResult to indicate command success or failure. */ - CmdResult Handle(const std::vector& parameters, User* user) CXX11_OVERRIDE; + CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; namespace ReloadModule @@ -62,6 +89,7 @@ class DataKeeper { ModeHandler* mh; ExtensionItem* extitem; + ClientProtocol::Serializer* serializer; }; ProviderInfo(ModeHandler* mode) @@ -75,6 +103,12 @@ class DataKeeper , extitem(ei) { } + + ProviderInfo(ClientProtocol::Serializer* ser) + : itemname(ser->name) + , serializer(ser) + { + } }; struct InstanceData @@ -143,7 +177,17 @@ class DataKeeper }; // Data saved for each user - typedef OwnedModesExts UserData; + struct UserData : public OwnedModesExts + { + static const size_t UNUSED_INDEX = (size_t)-1; + size_t serializerindex; + + UserData(User* user, size_t serializeridx) + : OwnedModesExts(user->uuid) + , serializerindex(serializeridx) + { + } + }; /** Module being reloaded */ @@ -157,6 +201,10 @@ class DataKeeper */ std::vector handledexts; + /** Stores all serializers provided by the module + */ + std::vector handledserializers; + /** Stores all of the module data related to users */ std::vector userdatalist; @@ -172,6 +220,14 @@ class DataKeeper void SaveExtensions(Extensible* extensible, std::vector& extdatalist); void SaveMemberData(Channel* chan, std::vector& memberdatalist); static void SaveListModes(Channel* chan, ListModeBase* lm, size_t index, ModesExts& currdata); + size_t SaveSerializer(User* user); + + /** Get the index of a ProviderInfo representing the serializer in the handledserializers list. + * If the serializer is not already in the list it is added. + * @param serializer Serializer to get an index to. + * @return Index of the ProviderInfo representing the serializer. + */ + size_t GetSerializerIndex(ClientProtocol::Serializer* serializer); void CreateModeList(ModeType modetype); void DoSaveUsers(); @@ -186,6 +242,10 @@ class DataKeeper */ void LinkModes(ModeType modetype); + /** Link previously saved serializer names to currently available Serializers + */ + void LinkSerializers(); + void DoRestoreUsers(); void DoRestoreChans(); void DoRestoreModules(); @@ -213,6 +273,15 @@ class DataKeeper */ void RestoreModes(const std::vector& list, ModeType modetype, Modes::ChangeList& modechange); + /** Restore previously saved serializer on a User. + * Quit the user if the serializer cannot be restored. + * @param serializerindex Saved serializer index to restore. + * @param user User whose serializer to restore. If not local then calling this method is a no-op. + * @return True if the serializer didn't need restoring or was restored successfully. + * False if the serializer should have been restored but the required serializer is unavailable and the user was quit. + */ + bool RestoreSerializer(size_t serializerindex, User* user); + /** Restore all modes and extensions of all members on a channel * @param chan Channel whose members are being restored * @param memberdata Data to restore @@ -262,16 +331,44 @@ void DataKeeper::DoSaveUsers() // Serialize all extensions attached to the User SaveExtensions(user, currdata.extlist); + // Save serializer name if applicable and get an index to it + size_t serializerindex = SaveSerializer(user); + // Add to list if the user has any modes or extensions set that we are interested in, otherwise we don't // have to do anything with this user when restoring - if (!currdata.empty()) + if ((!currdata.empty()) || (serializerindex != UserData::UNUSED_INDEX)) { - userdatalist.push_back(UserData(user->uuid)); + userdatalist.push_back(UserData(user, serializerindex)); userdatalist.back().swap(currdata); } } } +size_t DataKeeper::GetSerializerIndex(ClientProtocol::Serializer* serializer) +{ + for (size_t i = 0; i < handledserializers.size(); i++) + { + if (handledserializers[i].serializer == serializer) + return i; + } + + handledserializers.push_back(ProviderInfo(serializer)); + return handledserializers.size()-1; +} + +size_t DataKeeper::SaveSerializer(User* user) +{ + LocalUser* const localuser = IS_LOCAL(user); + if ((!localuser) || (!localuser->serializer)) + return UserData::UNUSED_INDEX; + if (localuser->serializer->creator != mod) + return UserData::UNUSED_INDEX; + + const size_t serializerindex = GetSerializerIndex(localuser->serializer); + localuser->serializer = dummyserializer; + return serializerindex; +} + void DataKeeper::SaveExtensions(Extensible* extensible, std::vector& extdata) { const Extensible::ExtensibleStore& setexts = extensible->GetExtList(); @@ -285,7 +382,7 @@ void DataKeeper::SaveExtensions(Extensible* extensible, std::vectorserialize(FORMAT_INTERNAL, extensible, it->second); + std::string value = item->ToInternal(extensible, it->second); // If the serialized value is empty the extension won't be saved and restored if (!value.empty()) extdata.push_back(InstanceData(index, value)); @@ -456,6 +553,16 @@ void DataKeeper::LinkExtensions() } } +void DataKeeper::LinkSerializers() +{ + for (std::vector::iterator i = handledserializers.begin(); i != handledserializers.end(); ++i) + { + ProviderInfo& item = *i; + item.serializer = ServerInstance->Modules.FindDataService(item.itemname); + VerifyServiceProvider(item.serializer, "Serializer"); + } +} + void DataKeeper::Restore(Module* newmod) { this->mod = newmod; @@ -464,6 +571,7 @@ void DataKeeper::Restore(Module* newmod) LinkExtensions(); LinkModes(MODETYPE_USER); LinkModes(MODETYPE_CHANNEL); + LinkSerializers(); // Restore DoRestoreUsers(); @@ -492,7 +600,7 @@ void DataKeeper::RestoreExtensions(const std::vector& list, Extens for (std::vector::const_iterator i = list.begin(); i != list.end(); ++i) { const InstanceData& id = *i; - handledexts[id.index].extitem->unserialize(FORMAT_INTERNAL, extensible, id.serialized); + handledexts[id.index].extitem->FromInternal(extensible, id.serialized); } } @@ -505,6 +613,30 @@ void DataKeeper::RestoreModes(const std::vector& list, ModeType mo } } +bool DataKeeper::RestoreSerializer(size_t serializerindex, User* user) +{ + if (serializerindex == UserData::UNUSED_INDEX) + return true; + + // The following checks are redundant + LocalUser* const localuser = IS_LOCAL(user); + if (!localuser) + return true; + if (localuser->serializer != dummyserializer) + return true; + + const ProviderInfo& provinfo = handledserializers[serializerindex]; + if (!provinfo.serializer) + { + // Users cannot exist without a serializer + ServerInstance->Users.QuitUser(user, "Serializer lost in reload"); + return false; + } + + localuser->serializer = provinfo.serializer; + return true; +} + void DataKeeper::DoRestoreUsers() { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restoring user data"); @@ -520,6 +652,10 @@ void DataKeeper::DoRestoreUsers() continue; } + // Attempt to restore serializer first, if it fails it's a fatal error and RestoreSerializer() quits them + if (!RestoreSerializer(userdata.serializerindex, user)) + continue; + RestoreObj(userdata, user, MODETYPE_USER, modechange); ServerInstance->Modes.Process(ServerInstance->FakeClient, NULL, user, modechange, ModeParser::MODE_LOCALONLY); modechange.clear(); @@ -565,7 +701,7 @@ void DataKeeper::DoRestoreModules() } // namespace ReloadModule -class ReloadAction : public HandlerBase0 +class ReloadAction : public ActionBase { Module* const mod; const std::string uuid; @@ -584,11 +720,9 @@ class ReloadAction : public HandlerBase0 ReloadModule::DataKeeper datakeeper; datakeeper.Save(mod); - DLLManager* dll = mod->ModuleDLLManager; std::string name = mod->ModuleSourceFile; ServerInstance->Modules->DoSafeUnload(mod); ServerInstance->GlobalCulls.Apply(); - delete dll; bool result = ServerInstance->Modules->Load(name); if (result) @@ -602,18 +736,21 @@ class ReloadAction : public HandlerBase0 ServerInstance->SNO->WriteGlobalSno('a', "RELOAD MODULE: %s %ssuccessfully reloaded", passedname.c_str(), result ? "" : "un"); User* user = ServerInstance->FindUUID(uuid); if (user) - user->WriteNumeric(RPL_LOADEDMODULE, passedname, InspIRCd::Format("Module %ssuccessfully reloaded.", (result ? "" : "un"))); + { + int numeric = result ? RPL_LOADEDMODULE : ERR_CANTUNLOADMODULE; + user->WriteNumeric(numeric, passedname, InspIRCd::Format("Module %ssuccessfully reloaded.", (result ? "" : "un"))); + } ServerInstance->GlobalCulls.AddItem(this); } }; -CmdResult CommandReloadmodule::Handle (const std::vector& parameters, User *user) +CmdResult CommandReloadmodule::Handle(User* user, const Params& parameters) { Module* m = ServerInstance->Modules->Find(parameters[0]); if (m == creator) { - user->WriteNumeric(RPL_LOADEDMODULE, parameters[0], "You cannot reload core_reloadmodule (unload and load it)"); + user->WriteNumeric(ERR_CANTUNLOADMODULE, parameters[0], "You cannot reload core_reloadmodule (unload and load it)"); return CMD_FAILURE; } @@ -627,9 +764,26 @@ CmdResult CommandReloadmodule::Handle (const std::vector& parameter } else { - user->WriteNumeric(RPL_LOADEDMODULE, parameters[0], "Could not find module by that name"); + user->WriteNumeric(ERR_CANTUNLOADMODULE, parameters[0], "Could not find module by that name"); return CMD_FAILURE; } } -COMMAND_INIT(CommandReloadmodule) +class CoreModReloadmodule : public Module +{ + private: + CommandReloadmodule cmd; + + public: + CoreModReloadmodule() + : cmd(this) + { + } + + Version GetVersion() CXX11_OVERRIDE + { + return Version("Provides the RELOADMODULE command", VF_CORE | VF_VENDOR); + } +}; + +MODULE_INIT(CoreModReloadmodule)