2 * InspIRCd -- Internet Relay Chat Daemon
4 * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com>
5 * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
6 * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
8 * This file is part of InspIRCd. InspIRCd is free software: you can
9 * redistribute it and/or modify it under the terms of the GNU General Public
10 * License as published by the Free Software Foundation, version 2.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "modules/reload.h"
26 static Events::ModuleEventProvider* reloadevprov;
27 static ClientProtocol::Serializer* dummyserializer;
29 class DummySerializer : public ClientProtocol::Serializer
31 bool Parse(LocalUser* user, const std::string& line, ClientProtocol::ParseOutput& parseoutput) CXX11_OVERRIDE
36 ClientProtocol::SerializedMessage Serialize(const ClientProtocol::Message& msg, const ClientProtocol::TagSelection& tagwl) const CXX11_OVERRIDE
38 return ClientProtocol::SerializedMessage();
42 DummySerializer(Module* mod)
43 : ClientProtocol::Serializer(mod, "dummy")
48 class CommandReloadmodule : public Command
50 Events::ModuleEventProvider evprov;
51 DummySerializer dummyser;
54 /** Constructor for reloadmodule.
56 CommandReloadmodule(Module* parent)
57 : Command(parent, "RELOADMODULE", 1)
58 , evprov(parent, "event/reloadmodule")
61 reloadevprov = &evprov;
62 dummyserializer = &dummyser;
64 syntax = "<modulename>";
68 * @param parameters The parameters to the command
69 * @param user The user issuing the command
70 * @return A value from CmdResult to indicate command success or failure.
72 CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE;
75 namespace ReloadModule
80 /** Data we save for each mode and extension provided by the module
88 ExtensionItem* extitem;
89 ClientProtocol::Serializer* serializer;
92 ProviderInfo(ModeHandler* mode)
93 : itemname(mode->name)
98 ProviderInfo(ExtensionItem* ei)
104 ProviderInfo(ClientProtocol::Serializer* ser)
105 : itemname(ser->name)
113 /** Position of the ModeHandler or ExtensionItem that the serialized data belongs to
119 std::string serialized;
121 InstanceData(size_t Index, const std::string& Serialized)
123 , serialized(Serialized)
130 /** Mode data for the object, one entry per mode set by the module being reloaded
132 std::vector<InstanceData> modelist;
134 /** Extensions for the object, one entry per extension set by the module being reloaded
136 std::vector<InstanceData> extlist;
138 bool empty() const { return ((modelist.empty()) && (extlist.empty())); }
140 void swap(ModesExts& other)
142 modelist.swap(other.modelist);
143 extlist.swap(other.extlist);
147 struct OwnedModesExts : public ModesExts
149 /** User uuid or channel name
153 OwnedModesExts(const std::string& Owner)
159 // Data saved for each channel
160 struct ChanData : public OwnedModesExts
162 /** Type of data stored for each member who has any affected modes or extensions set
164 typedef OwnedModesExts MemberData;
166 /** List of data (modes and extensions) about each member
168 std::vector<MemberData> memberdatalist;
170 ChanData(Channel* chan)
171 : OwnedModesExts(chan->name)
176 // Data saved for each user
177 struct UserData : public OwnedModesExts
179 static const size_t UNUSED_INDEX = (size_t)-1;
180 size_t serializerindex;
182 UserData(User* user, size_t serializeridx)
183 : OwnedModesExts(user->uuid)
184 , serializerindex(serializeridx)
189 /** Module being reloaded
193 /** Stores all user and channel modes provided by the module
195 std::vector<ProviderInfo> handledmodes[2];
197 /** Stores all extensions provided by the module
199 std::vector<ProviderInfo> handledexts;
201 /** Stores all serializers provided by the module
203 std::vector<ProviderInfo> handledserializers;
205 /** Stores all of the module data related to users
207 std::vector<UserData> userdatalist;
209 /** Stores all of the module data related to channels and memberships
211 std::vector<ChanData> chandatalist;
213 /** Data attached by modules
215 ReloadModule::CustomData moddata;
217 void SaveExtensions(Extensible* extensible, std::vector<InstanceData>& extdatalist);
218 void SaveMemberData(Channel* chan, std::vector<ChanData::MemberData>& memberdatalist);
219 static void SaveListModes(Channel* chan, ListModeBase* lm, size_t index, ModesExts& currdata);
220 size_t SaveSerializer(User* user);
222 /** Get the index of a ProviderInfo representing the serializer in the handledserializers list.
223 * If the serializer is not already in the list it is added.
224 * @param serializer Serializer to get an index to.
225 * @return Index of the ProviderInfo representing the serializer.
227 size_t GetSerializerIndex(ClientProtocol::Serializer* serializer);
229 void CreateModeList(ModeType modetype);
233 /** Link previously saved extension names to currently available ExtensionItems
235 void LinkExtensions();
237 /** Link previously saved mode names to currently available ModeHandlers
238 * @param modetype Type of the modes to look for
240 void LinkModes(ModeType modetype);
242 /** Link previously saved serializer names to currently available Serializers
244 void LinkSerializers();
246 void DoRestoreUsers();
247 void DoRestoreChans();
248 void DoRestoreModules();
250 /** Restore previously saved modes and extensions on an Extensible.
251 * The extensions are set directly on the extensible, the modes are added into the provided mode change list.
252 * @param data Data to unserialize from
253 * @param extensible Object to restore
254 * @param modetype MODETYPE_USER if the object being restored is a User, MODETYPE_CHANNEL otherwise
255 * (for Channels and Memberships).
256 * @param modechange Mode change to populate with the modes
258 void RestoreObj(const OwnedModesExts& data, Extensible* extensible, ModeType modetype, Modes::ChangeList& modechange);
260 /** Restore all previously saved extensions on an Extensible
261 * @param list List of extensions and their serialized data to restore
262 * @param extensible Target Extensible
264 void RestoreExtensions(const std::vector<InstanceData>& list, Extensible* extensible);
266 /** Restore all previously saved modes on a User, Channel or Membership
267 * @param list List of modes to restore
268 * @param modetype MODETYPE_USER if the object being restored is a User, MODETYPE_CHANNEL otherwise
269 * @param modechange Mode change to populate with the modes
271 void RestoreModes(const std::vector<InstanceData>& list, ModeType modetype, Modes::ChangeList& modechange);
273 /** Restore previously saved serializer on a User.
274 * Quit the user if the serializer cannot be restored.
275 * @param serializerindex Saved serializer index to restore.
276 * @param user User whose serializer to restore. If not local then calling this method is a no-op.
277 * @return True if the serializer didn't need restoring or was restored successfully.
278 * False if the serializer should have been restored but the required serializer is unavailable and the user was quit.
280 bool RestoreSerializer(size_t serializerindex, User* user);
282 /** Restore all modes and extensions of all members on a channel
283 * @param chan Channel whose members are being restored
284 * @param memberdata Data to restore
285 * @param modechange Mode change to populate with prefix modes
287 void RestoreMemberData(Channel* chan, const std::vector<ChanData::MemberData>& memberdatalist, Modes::ChangeList& modechange);
289 /** Verify that a service which had its data saved is available and owned by the module that owned it previously
290 * @param service Service descriptor
291 * @param type Human-readable type of the service for log messages
293 void VerifyServiceProvider(const ProviderInfo& service, const char* type);
296 /** Save module state
297 * @param currmod Module whose data to save
299 void Save(Module* currmod);
301 /** Restore module state
302 * @param newmod Newly loaded instance of the module which had its data saved
304 void Restore(Module* newmod);
306 /** Handle reload failure
311 void DataKeeper::DoSaveUsers()
315 const user_hash& users = ServerInstance->Users->GetUsers();
316 for (user_hash::const_iterator i = users.begin(); i != users.end(); ++i)
318 User* const user = i->second;
320 // Serialize user modes
321 for (size_t j = 0; j < handledmodes[MODETYPE_USER].size(); j++)
323 ModeHandler* mh = handledmodes[MODETYPE_USER][j].mh;
324 if (user->IsModeSet(mh))
325 currdata.modelist.push_back(InstanceData(j, mh->GetUserParameter(user)));
328 // Serialize all extensions attached to the User
329 SaveExtensions(user, currdata.extlist);
331 // Save serializer name if applicable and get an index to it
332 size_t serializerindex = SaveSerializer(user);
334 // Add to list if the user has any modes or extensions set that we are interested in, otherwise we don't
335 // have to do anything with this user when restoring
336 if ((!currdata.empty()) || (serializerindex != UserData::UNUSED_INDEX))
338 userdatalist.push_back(UserData(user, serializerindex));
339 userdatalist.back().swap(currdata);
344 size_t DataKeeper::GetSerializerIndex(ClientProtocol::Serializer* serializer)
346 for (size_t i = 0; i < handledserializers.size(); i++)
348 if (handledserializers[i].serializer == serializer)
352 handledserializers.push_back(ProviderInfo(serializer));
353 return handledserializers.size()-1;
356 size_t DataKeeper::SaveSerializer(User* user)
358 LocalUser* const localuser = IS_LOCAL(user);
359 if ((!localuser) || (!localuser->serializer))
360 return UserData::UNUSED_INDEX;
361 if (localuser->serializer->creator != mod)
362 return UserData::UNUSED_INDEX;
364 const size_t serializerindex = GetSerializerIndex(localuser->serializer);
365 localuser->serializer = dummyserializer;
366 return serializerindex;
369 void DataKeeper::SaveExtensions(Extensible* extensible, std::vector<InstanceData>& extdata)
371 const Extensible::ExtensibleStore& setexts = extensible->GetExtList();
373 // Position of the extension saved in the handledexts list
375 for (std::vector<ProviderInfo>::const_iterator i = handledexts.begin(); i != handledexts.end(); ++i, index++)
377 ExtensionItem* const item = i->extitem;
378 Extensible::ExtensibleStore::const_iterator it = setexts.find(item);
379 if (it == setexts.end())
382 std::string value = item->ToInternal(extensible, it->second);
383 // If the serialized value is empty the extension won't be saved and restored
385 extdata.push_back(InstanceData(index, value));
389 void DataKeeper::SaveListModes(Channel* chan, ListModeBase* lm, size_t index, ModesExts& currdata)
391 const ListModeBase::ModeList* list = lm->GetList(chan);
395 for (ListModeBase::ModeList::const_iterator i = list->begin(); i != list->end(); ++i)
397 const ListModeBase::ListItem& listitem = *i;
398 currdata.modelist.push_back(InstanceData(index, listitem.mask));
402 void DataKeeper::DoSaveChans()
405 std::vector<OwnedModesExts> currmemberdata;
407 const chan_hash& chans = ServerInstance->GetChans();
408 for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ++i)
410 Channel* const chan = i->second;
412 // Serialize channel modes
413 for (size_t j = 0; j < handledmodes[MODETYPE_CHANNEL].size(); j++)
415 ModeHandler* mh = handledmodes[MODETYPE_CHANNEL][j].mh;
416 ListModeBase* lm = mh->IsListModeBase();
418 SaveListModes(chan, lm, j, currdata);
419 else if (chan->IsModeSet(mh))
420 currdata.modelist.push_back(InstanceData(j, chan->GetModeParameter(mh)));
423 // Serialize all extensions attached to the Channel
424 SaveExtensions(chan, currdata.extlist);
426 // Serialize all extensions attached to and all modes set on all members of the channel
427 SaveMemberData(chan, currmemberdata);
429 // Same logic as in DoSaveUsers() plus we consider the modes and extensions of all members
430 if ((!currdata.empty()) || (!currmemberdata.empty()))
432 chandatalist.push_back(ChanData(chan));
433 chandatalist.back().swap(currdata);
434 chandatalist.back().memberdatalist.swap(currmemberdata);
439 void DataKeeper::SaveMemberData(Channel* chan, std::vector<OwnedModesExts>& memberdatalist)
442 const Channel::MemberMap& users = chan->GetUsers();
443 for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i)
445 Membership* const memb = i->second;
447 for (size_t j = 0; j < handledmodes[MODETYPE_CHANNEL].size(); j++)
449 ModeHandler* mh = handledmodes[MODETYPE_CHANNEL][j].mh;
450 const PrefixMode* const pm = mh->IsPrefixMode();
451 if ((pm) && (memb->HasMode(pm)))
452 currdata.modelist.push_back(InstanceData(j, memb->user->uuid)); // Need to pass the user's uuid to the mode parser to set the mode later
455 SaveExtensions(memb, currdata.extlist);
457 // Same logic as in DoSaveUsers()
458 if (!currdata.empty())
460 memberdatalist.push_back(OwnedModesExts(memb->user->uuid));
461 memberdatalist.back().swap(currdata);
466 void DataKeeper::RestoreMemberData(Channel* chan, const std::vector<ChanData::MemberData>& memberdatalist, Modes::ChangeList& modechange)
468 for (std::vector<ChanData::MemberData>::const_iterator i = memberdatalist.begin(); i != memberdatalist.end(); ++i)
470 const ChanData::MemberData& md = *i;
471 User* const user = ServerInstance->FindUUID(md.owner);
474 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "User %s is gone (while processing %s)", md.owner.c_str(), chan->name.c_str());
478 Membership* const memb = chan->GetUser(user);
481 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Member %s is no longer on channel %s", md.owner.c_str(), chan->name.c_str());
485 RestoreObj(md, memb, MODETYPE_CHANNEL, modechange);
489 void DataKeeper::CreateModeList(ModeType modetype)
491 const ModeParser::ModeHandlerMap& modes = ServerInstance->Modes->GetModes(modetype);
492 for (ModeParser::ModeHandlerMap::const_iterator i = modes.begin(); i != modes.end(); ++i)
494 ModeHandler* mh = i->second;
495 if (mh->creator == mod)
496 handledmodes[modetype].push_back(ProviderInfo(mh));
500 void DataKeeper::Save(Module* currmod)
504 const ExtensionManager::ExtMap& allexts = ServerInstance->Extensions.GetExts();
505 for (ExtensionManager::ExtMap::const_iterator i = allexts.begin(); i != allexts.end(); ++i)
507 ExtensionItem* ext = i->second;
508 if (ext->creator == mod)
509 handledexts.push_back(ProviderInfo(ext));
512 CreateModeList(MODETYPE_USER);
515 CreateModeList(MODETYPE_CHANNEL);
518 FOREACH_MOD_CUSTOM(*reloadevprov, ReloadModule::EventListener, OnReloadModuleSave, (mod, this->moddata));
520 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Saved data about %lu users %lu chans %lu modules", (unsigned long)userdatalist.size(), (unsigned long)chandatalist.size(), (unsigned long)moddata.list.size());
523 void DataKeeper::VerifyServiceProvider(const ProviderInfo& service, const char* type)
525 const ServiceProvider* sp = service.extitem;
527 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "%s \"%s\" is no longer available", type, service.itemname.c_str());
528 else if (sp->creator != mod)
529 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "%s \"%s\" is now handled by %s", type, service.itemname.c_str(), (sp->creator ? sp->creator->ModuleSourceFile.c_str() : "<core>"));
532 void DataKeeper::LinkModes(ModeType modetype)
534 std::vector<ProviderInfo>& list = handledmodes[modetype];
535 for (std::vector<ProviderInfo>::iterator i = list.begin(); i != list.end(); ++i)
537 ProviderInfo& item = *i;
538 item.mh = ServerInstance->Modes->FindMode(item.itemname, modetype);
539 VerifyServiceProvider(item, (modetype == MODETYPE_USER ? "User mode" : "Channel mode"));
543 void DataKeeper::LinkExtensions()
545 for (std::vector<ProviderInfo>::iterator i = handledexts.begin(); i != handledexts.end(); ++i)
547 ProviderInfo& item = *i;
548 item.extitem = ServerInstance->Extensions.GetItem(item.itemname);
549 VerifyServiceProvider(item.extitem, "Extension");
553 void DataKeeper::LinkSerializers()
555 for (std::vector<ProviderInfo>::iterator i = handledserializers.begin(); i != handledserializers.end(); ++i)
557 ProviderInfo& item = *i;
558 item.serializer = ServerInstance->Modules.FindDataService<ClientProtocol::Serializer>(item.itemname);
559 VerifyServiceProvider(item.serializer, "Serializer");
563 void DataKeeper::Restore(Module* newmod)
567 // Find the new extension items
569 LinkModes(MODETYPE_USER);
570 LinkModes(MODETYPE_CHANNEL);
578 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restore finished");
581 void DataKeeper::Fail()
585 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restore failed, notifying modules");
589 void DataKeeper::RestoreObj(const OwnedModesExts& data, Extensible* extensible, ModeType modetype, Modes::ChangeList& modechange)
591 RestoreExtensions(data.extlist, extensible);
592 RestoreModes(data.modelist, modetype, modechange);
595 void DataKeeper::RestoreExtensions(const std::vector<InstanceData>& list, Extensible* extensible)
597 for (std::vector<InstanceData>::const_iterator i = list.begin(); i != list.end(); ++i)
599 const InstanceData& id = *i;
600 handledexts[id.index].extitem->FromInternal(extensible, id.serialized);
604 void DataKeeper::RestoreModes(const std::vector<InstanceData>& list, ModeType modetype, Modes::ChangeList& modechange)
606 for (std::vector<InstanceData>::const_iterator i = list.begin(); i != list.end(); ++i)
608 const InstanceData& id = *i;
609 modechange.push_add(handledmodes[modetype][id.index].mh, id.serialized);
613 bool DataKeeper::RestoreSerializer(size_t serializerindex, User* user)
615 if (serializerindex == UserData::UNUSED_INDEX)
618 // The following checks are redundant
619 LocalUser* const localuser = IS_LOCAL(user);
622 if (localuser->serializer != dummyserializer)
625 const ProviderInfo& provinfo = handledserializers[serializerindex];
626 if (!provinfo.serializer)
628 // Users cannot exist without a serializer
629 ServerInstance->Users.QuitUser(user, "Serializer lost in reload");
633 localuser->serializer = provinfo.serializer;
637 void DataKeeper::DoRestoreUsers()
639 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restoring user data");
640 Modes::ChangeList modechange;
642 for (std::vector<UserData>::const_iterator i = userdatalist.begin(); i != userdatalist.end(); ++i)
644 const UserData& userdata = *i;
645 User* const user = ServerInstance->FindUUID(userdata.owner);
648 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "User %s is gone", userdata.owner.c_str());
652 // Attempt to restore serializer first, if it fails it's a fatal error and RestoreSerializer() quits them
653 if (!RestoreSerializer(userdata.serializerindex, user))
656 RestoreObj(userdata, user, MODETYPE_USER, modechange);
657 ServerInstance->Modes.Process(ServerInstance->FakeClient, NULL, user, modechange, ModeParser::MODE_LOCALONLY);
662 void DataKeeper::DoRestoreChans()
664 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restoring channel data");
665 Modes::ChangeList modechange;
667 for (std::vector<ChanData>::const_iterator i = chandatalist.begin(); i != chandatalist.end(); ++i)
669 const ChanData& chandata = *i;
670 Channel* const chan = ServerInstance->FindChan(chandata.owner);
673 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Channel %s not found", chandata.owner.c_str());
677 RestoreObj(chandata, chan, MODETYPE_CHANNEL, modechange);
678 // Process the mode change before applying any prefix modes
679 ServerInstance->Modes.Process(ServerInstance->FakeClient, chan, NULL, modechange, ModeParser::MODE_LOCALONLY);
682 // Restore all member data
683 RestoreMemberData(chan, chandata.memberdatalist, modechange);
684 ServerInstance->Modes.Process(ServerInstance->FakeClient, chan, NULL, modechange, ModeParser::MODE_LOCALONLY);
689 void DataKeeper::DoRestoreModules()
691 for (ReloadModule::CustomData::List::iterator i = moddata.list.begin(); i != moddata.list.end(); ++i)
693 ReloadModule::CustomData::Data& data = *i;
694 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Calling module data handler %p", (void*)data.handler);
695 data.handler->OnReloadModuleRestore(mod, data.data);
699 } // namespace ReloadModule
701 class ReloadAction : public ActionBase
704 const std::string uuid;
705 const std::string passedname;
708 ReloadAction(Module* m, const std::string& uid, const std::string& passedmodname)
711 , passedname(passedmodname)
715 void Call() CXX11_OVERRIDE
717 ReloadModule::DataKeeper datakeeper;
718 datakeeper.Save(mod);
720 DLLManager* dll = mod->ModuleDLLManager;
721 std::string name = mod->ModuleSourceFile;
722 ServerInstance->Modules->DoSafeUnload(mod);
723 ServerInstance->GlobalCulls.Apply();
725 bool result = ServerInstance->Modules->Load(name);
729 Module* newmod = ServerInstance->Modules->Find(name);
730 datakeeper.Restore(newmod);
735 ServerInstance->SNO->WriteGlobalSno('a', "RELOAD MODULE: %s %ssuccessfully reloaded", passedname.c_str(), result ? "" : "un");
736 User* user = ServerInstance->FindUUID(uuid);
738 user->WriteNumeric(RPL_LOADEDMODULE, passedname, InspIRCd::Format("Module %ssuccessfully reloaded.", (result ? "" : "un")));
740 ServerInstance->GlobalCulls.AddItem(this);
744 CmdResult CommandReloadmodule::Handle(User* user, const Params& parameters)
746 Module* m = ServerInstance->Modules->Find(parameters[0]);
749 user->WriteNumeric(RPL_LOADEDMODULE, parameters[0], "You cannot reload core_reloadmodule (unload and load it)");
756 if ((m) && (ServerInstance->Modules.CanUnload(m)))
758 ServerInstance->AtomicActions.AddAction(new ReloadAction(m, user->uuid, parameters[0]));
763 user->WriteNumeric(RPL_LOADEDMODULE, parameters[0], "Could not find module by that name");
768 class CoreModReloadmodule : public Module
771 CommandReloadmodule cmd;
774 CoreModReloadmodule()
779 Version GetVersion() CXX11_OVERRIDE
781 return Version("Provides the RELOADMODULE command", VF_CORE | VF_VENDOR);
785 MODULE_INIT(CoreModReloadmodule)