2 * InspIRCd -- Internet Relay Chat Daemon
4 * Copyright (C) 2017-2019 Sadie Powell <sadie@witchery.services>
5 * Copyright (C) 2014-2016, 2018 Attila Molnar <attilamolnar@hush.com>
6 * Copyright (C) 2012 Robby <robby@chatbelgie.be>
7 * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
8 * Copyright (C) 2007, 2010 Craig Edwards <brain@inspircd.org>
9 * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
11 * This file is part of InspIRCd. InspIRCd is free software: you can
12 * redistribute it and/or modify it under the terms of the GNU General Public
13 * License as published by the Free Software Foundation, version 2.
15 * This program is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include "modules/reload.h"
29 static Events::ModuleEventProvider* reloadevprov;
30 static ClientProtocol::Serializer* dummyserializer;
32 class DummySerializer : public ClientProtocol::Serializer
34 bool Parse(LocalUser* user, const std::string& line, ClientProtocol::ParseOutput& parseoutput) CXX11_OVERRIDE
39 ClientProtocol::SerializedMessage Serialize(const ClientProtocol::Message& msg, const ClientProtocol::TagSelection& tagwl) const CXX11_OVERRIDE
41 return ClientProtocol::SerializedMessage();
45 DummySerializer(Module* mod)
46 : ClientProtocol::Serializer(mod, "dummy")
51 class CommandReloadmodule : public Command
53 Events::ModuleEventProvider evprov;
54 DummySerializer dummyser;
57 /** Constructor for reloadmodule.
59 CommandReloadmodule(Module* parent)
60 : Command(parent, "RELOADMODULE", 1)
61 , evprov(parent, "event/reloadmodule")
64 reloadevprov = &evprov;
65 dummyserializer = &dummyser;
67 syntax = "<modulename>";
71 * @param parameters The parameters to the command
72 * @param user The user issuing the command
73 * @return A value from CmdResult to indicate command success or failure.
75 CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE;
78 namespace ReloadModule
83 /** Data we save for each mode and extension provided by the module
91 ExtensionItem* extitem;
92 ClientProtocol::Serializer* serializer;
95 ProviderInfo(ModeHandler* mode)
96 : itemname(mode->name)
101 ProviderInfo(ExtensionItem* ei)
107 ProviderInfo(ClientProtocol::Serializer* ser)
108 : itemname(ser->name)
116 /** Position of the ModeHandler or ExtensionItem that the serialized data belongs to
122 std::string serialized;
124 InstanceData(size_t Index, const std::string& Serialized)
126 , serialized(Serialized)
133 /** Mode data for the object, one entry per mode set by the module being reloaded
135 std::vector<InstanceData> modelist;
137 /** Extensions for the object, one entry per extension set by the module being reloaded
139 std::vector<InstanceData> extlist;
141 bool empty() const { return ((modelist.empty()) && (extlist.empty())); }
143 void swap(ModesExts& other)
145 modelist.swap(other.modelist);
146 extlist.swap(other.extlist);
150 struct OwnedModesExts : public ModesExts
152 /** User uuid or channel name
156 OwnedModesExts(const std::string& Owner)
162 // Data saved for each channel
163 struct ChanData : public OwnedModesExts
165 /** Type of data stored for each member who has any affected modes or extensions set
167 typedef OwnedModesExts MemberData;
169 /** List of data (modes and extensions) about each member
171 std::vector<MemberData> memberdatalist;
173 ChanData(Channel* chan)
174 : OwnedModesExts(chan->name)
179 // Data saved for each user
180 struct UserData : public OwnedModesExts
182 static const size_t UNUSED_INDEX = (size_t)-1;
183 size_t serializerindex;
185 UserData(User* user, size_t serializeridx)
186 : OwnedModesExts(user->uuid)
187 , serializerindex(serializeridx)
192 /** Module being reloaded
196 /** Stores all user and channel modes provided by the module
198 std::vector<ProviderInfo> handledmodes[2];
200 /** Stores all extensions provided by the module
202 std::vector<ProviderInfo> handledexts;
204 /** Stores all serializers provided by the module
206 std::vector<ProviderInfo> handledserializers;
208 /** Stores all of the module data related to users
210 std::vector<UserData> userdatalist;
212 /** Stores all of the module data related to channels and memberships
214 std::vector<ChanData> chandatalist;
216 /** Data attached by modules
218 ReloadModule::CustomData moddata;
220 void SaveExtensions(Extensible* extensible, std::vector<InstanceData>& extdatalist);
221 void SaveMemberData(Channel* chan, std::vector<ChanData::MemberData>& memberdatalist);
222 static void SaveListModes(Channel* chan, ListModeBase* lm, size_t index, ModesExts& currdata);
223 size_t SaveSerializer(User* user);
225 /** Get the index of a ProviderInfo representing the serializer in the handledserializers list.
226 * If the serializer is not already in the list it is added.
227 * @param serializer Serializer to get an index to.
228 * @return Index of the ProviderInfo representing the serializer.
230 size_t GetSerializerIndex(ClientProtocol::Serializer* serializer);
232 void CreateModeList(ModeType modetype);
236 /** Link previously saved extension names to currently available ExtensionItems
238 void LinkExtensions();
240 /** Link previously saved mode names to currently available ModeHandlers
241 * @param modetype Type of the modes to look for
243 void LinkModes(ModeType modetype);
245 /** Link previously saved serializer names to currently available Serializers
247 void LinkSerializers();
249 void DoRestoreUsers();
250 void DoRestoreChans();
251 void DoRestoreModules();
253 /** Restore previously saved modes and extensions on an Extensible.
254 * The extensions are set directly on the extensible, the modes are added into the provided mode change list.
255 * @param data Data to unserialize from
256 * @param extensible Object to restore
257 * @param modetype MODETYPE_USER if the object being restored is a User, MODETYPE_CHANNEL otherwise
258 * (for Channels and Memberships).
259 * @param modechange Mode change to populate with the modes
261 void RestoreObj(const OwnedModesExts& data, Extensible* extensible, ModeType modetype, Modes::ChangeList& modechange);
263 /** Restore all previously saved extensions on an Extensible
264 * @param list List of extensions and their serialized data to restore
265 * @param extensible Target Extensible
267 void RestoreExtensions(const std::vector<InstanceData>& list, Extensible* extensible);
269 /** Restore all previously saved modes on a User, Channel or Membership
270 * @param list List of modes to restore
271 * @param modetype MODETYPE_USER if the object being restored is a User, MODETYPE_CHANNEL otherwise
272 * @param modechange Mode change to populate with the modes
274 void RestoreModes(const std::vector<InstanceData>& list, ModeType modetype, Modes::ChangeList& modechange);
276 /** Restore previously saved serializer on a User.
277 * Quit the user if the serializer cannot be restored.
278 * @param serializerindex Saved serializer index to restore.
279 * @param user User whose serializer to restore. If not local then calling this method is a no-op.
280 * @return True if the serializer didn't need restoring or was restored successfully.
281 * False if the serializer should have been restored but the required serializer is unavailable and the user was quit.
283 bool RestoreSerializer(size_t serializerindex, User* user);
285 /** Restore all modes and extensions of all members on a channel
286 * @param chan Channel whose members are being restored
287 * @param memberdata Data to restore
288 * @param modechange Mode change to populate with prefix modes
290 void RestoreMemberData(Channel* chan, const std::vector<ChanData::MemberData>& memberdatalist, Modes::ChangeList& modechange);
292 /** Verify that a service which had its data saved is available and owned by the module that owned it previously
293 * @param service Service descriptor
294 * @param type Human-readable type of the service for log messages
296 void VerifyServiceProvider(const ProviderInfo& service, const char* type);
299 /** Save module state
300 * @param currmod Module whose data to save
302 void Save(Module* currmod);
304 /** Restore module state
305 * @param newmod Newly loaded instance of the module which had its data saved
307 void Restore(Module* newmod);
309 /** Handle reload failure
314 void DataKeeper::DoSaveUsers()
318 const user_hash& users = ServerInstance->Users->GetUsers();
319 for (user_hash::const_iterator i = users.begin(); i != users.end(); ++i)
321 User* const user = i->second;
323 // Serialize user modes
324 for (size_t j = 0; j < handledmodes[MODETYPE_USER].size(); j++)
326 ModeHandler* mh = handledmodes[MODETYPE_USER][j].mh;
327 if (user->IsModeSet(mh))
328 currdata.modelist.push_back(InstanceData(j, mh->GetUserParameter(user)));
331 // Serialize all extensions attached to the User
332 SaveExtensions(user, currdata.extlist);
334 // Save serializer name if applicable and get an index to it
335 size_t serializerindex = SaveSerializer(user);
337 // Add to list if the user has any modes or extensions set that we are interested in, otherwise we don't
338 // have to do anything with this user when restoring
339 if ((!currdata.empty()) || (serializerindex != UserData::UNUSED_INDEX))
341 userdatalist.push_back(UserData(user, serializerindex));
342 userdatalist.back().swap(currdata);
347 size_t DataKeeper::GetSerializerIndex(ClientProtocol::Serializer* serializer)
349 for (size_t i = 0; i < handledserializers.size(); i++)
351 if (handledserializers[i].serializer == serializer)
355 handledserializers.push_back(ProviderInfo(serializer));
356 return handledserializers.size()-1;
359 size_t DataKeeper::SaveSerializer(User* user)
361 LocalUser* const localuser = IS_LOCAL(user);
362 if ((!localuser) || (!localuser->serializer))
363 return UserData::UNUSED_INDEX;
364 if (localuser->serializer->creator != mod)
365 return UserData::UNUSED_INDEX;
367 const size_t serializerindex = GetSerializerIndex(localuser->serializer);
368 localuser->serializer = dummyserializer;
369 return serializerindex;
372 void DataKeeper::SaveExtensions(Extensible* extensible, std::vector<InstanceData>& extdata)
374 const Extensible::ExtensibleStore& setexts = extensible->GetExtList();
376 // Position of the extension saved in the handledexts list
378 for (std::vector<ProviderInfo>::const_iterator i = handledexts.begin(); i != handledexts.end(); ++i, index++)
380 ExtensionItem* const item = i->extitem;
381 Extensible::ExtensibleStore::const_iterator it = setexts.find(item);
382 if (it == setexts.end())
385 std::string value = item->ToInternal(extensible, it->second);
386 // If the serialized value is empty the extension won't be saved and restored
388 extdata.push_back(InstanceData(index, value));
392 void DataKeeper::SaveListModes(Channel* chan, ListModeBase* lm, size_t index, ModesExts& currdata)
394 const ListModeBase::ModeList* list = lm->GetList(chan);
398 for (ListModeBase::ModeList::const_iterator i = list->begin(); i != list->end(); ++i)
400 const ListModeBase::ListItem& listitem = *i;
401 currdata.modelist.push_back(InstanceData(index, listitem.mask));
405 void DataKeeper::DoSaveChans()
408 std::vector<OwnedModesExts> currmemberdata;
410 const chan_hash& chans = ServerInstance->GetChans();
411 for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ++i)
413 Channel* const chan = i->second;
415 // Serialize channel modes
416 for (size_t j = 0; j < handledmodes[MODETYPE_CHANNEL].size(); j++)
418 ModeHandler* mh = handledmodes[MODETYPE_CHANNEL][j].mh;
419 ListModeBase* lm = mh->IsListModeBase();
421 SaveListModes(chan, lm, j, currdata);
422 else if (chan->IsModeSet(mh))
423 currdata.modelist.push_back(InstanceData(j, chan->GetModeParameter(mh)));
426 // Serialize all extensions attached to the Channel
427 SaveExtensions(chan, currdata.extlist);
429 // Serialize all extensions attached to and all modes set on all members of the channel
430 SaveMemberData(chan, currmemberdata);
432 // Same logic as in DoSaveUsers() plus we consider the modes and extensions of all members
433 if ((!currdata.empty()) || (!currmemberdata.empty()))
435 chandatalist.push_back(ChanData(chan));
436 chandatalist.back().swap(currdata);
437 chandatalist.back().memberdatalist.swap(currmemberdata);
442 void DataKeeper::SaveMemberData(Channel* chan, std::vector<OwnedModesExts>& memberdatalist)
445 const Channel::MemberMap& users = chan->GetUsers();
446 for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i)
448 Membership* const memb = i->second;
450 for (size_t j = 0; j < handledmodes[MODETYPE_CHANNEL].size(); j++)
452 ModeHandler* mh = handledmodes[MODETYPE_CHANNEL][j].mh;
453 const PrefixMode* const pm = mh->IsPrefixMode();
454 if ((pm) && (memb->HasMode(pm)))
455 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
458 SaveExtensions(memb, currdata.extlist);
460 // Same logic as in DoSaveUsers()
461 if (!currdata.empty())
463 memberdatalist.push_back(OwnedModesExts(memb->user->uuid));
464 memberdatalist.back().swap(currdata);
469 void DataKeeper::RestoreMemberData(Channel* chan, const std::vector<ChanData::MemberData>& memberdatalist, Modes::ChangeList& modechange)
471 for (std::vector<ChanData::MemberData>::const_iterator i = memberdatalist.begin(); i != memberdatalist.end(); ++i)
473 const ChanData::MemberData& md = *i;
474 User* const user = ServerInstance->FindUUID(md.owner);
477 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "User %s is gone (while processing %s)", md.owner.c_str(), chan->name.c_str());
481 Membership* const memb = chan->GetUser(user);
484 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Member %s is no longer on channel %s", md.owner.c_str(), chan->name.c_str());
488 RestoreObj(md, memb, MODETYPE_CHANNEL, modechange);
492 void DataKeeper::CreateModeList(ModeType modetype)
494 const ModeParser::ModeHandlerMap& modes = ServerInstance->Modes->GetModes(modetype);
495 for (ModeParser::ModeHandlerMap::const_iterator i = modes.begin(); i != modes.end(); ++i)
497 ModeHandler* mh = i->second;
498 if (mh->creator == mod)
499 handledmodes[modetype].push_back(ProviderInfo(mh));
503 void DataKeeper::Save(Module* currmod)
507 const ExtensionManager::ExtMap& allexts = ServerInstance->Extensions.GetExts();
508 for (ExtensionManager::ExtMap::const_iterator i = allexts.begin(); i != allexts.end(); ++i)
510 ExtensionItem* ext = i->second;
511 if (ext->creator == mod)
512 handledexts.push_back(ProviderInfo(ext));
515 CreateModeList(MODETYPE_USER);
518 CreateModeList(MODETYPE_CHANNEL);
521 FOREACH_MOD_CUSTOM(*reloadevprov, ReloadModule::EventListener, OnReloadModuleSave, (mod, this->moddata));
523 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());
526 void DataKeeper::VerifyServiceProvider(const ProviderInfo& service, const char* type)
528 const ServiceProvider* sp = service.extitem;
530 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "%s \"%s\" is no longer available", type, service.itemname.c_str());
531 else if (sp->creator != mod)
532 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>"));
535 void DataKeeper::LinkModes(ModeType modetype)
537 std::vector<ProviderInfo>& list = handledmodes[modetype];
538 for (std::vector<ProviderInfo>::iterator i = list.begin(); i != list.end(); ++i)
540 ProviderInfo& item = *i;
541 item.mh = ServerInstance->Modes->FindMode(item.itemname, modetype);
542 VerifyServiceProvider(item, (modetype == MODETYPE_USER ? "User mode" : "Channel mode"));
546 void DataKeeper::LinkExtensions()
548 for (std::vector<ProviderInfo>::iterator i = handledexts.begin(); i != handledexts.end(); ++i)
550 ProviderInfo& item = *i;
551 item.extitem = ServerInstance->Extensions.GetItem(item.itemname);
552 VerifyServiceProvider(item.extitem, "Extension");
556 void DataKeeper::LinkSerializers()
558 for (std::vector<ProviderInfo>::iterator i = handledserializers.begin(); i != handledserializers.end(); ++i)
560 ProviderInfo& item = *i;
561 item.serializer = ServerInstance->Modules.FindDataService<ClientProtocol::Serializer>(item.itemname);
562 VerifyServiceProvider(item.serializer, "Serializer");
566 void DataKeeper::Restore(Module* newmod)
570 // Find the new extension items
572 LinkModes(MODETYPE_USER);
573 LinkModes(MODETYPE_CHANNEL);
581 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restore finished");
584 void DataKeeper::Fail()
588 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restore failed, notifying modules");
592 void DataKeeper::RestoreObj(const OwnedModesExts& data, Extensible* extensible, ModeType modetype, Modes::ChangeList& modechange)
594 RestoreExtensions(data.extlist, extensible);
595 RestoreModes(data.modelist, modetype, modechange);
598 void DataKeeper::RestoreExtensions(const std::vector<InstanceData>& list, Extensible* extensible)
600 for (std::vector<InstanceData>::const_iterator i = list.begin(); i != list.end(); ++i)
602 const InstanceData& id = *i;
603 handledexts[id.index].extitem->FromInternal(extensible, id.serialized);
607 void DataKeeper::RestoreModes(const std::vector<InstanceData>& list, ModeType modetype, Modes::ChangeList& modechange)
609 for (std::vector<InstanceData>::const_iterator i = list.begin(); i != list.end(); ++i)
611 const InstanceData& id = *i;
612 modechange.push_add(handledmodes[modetype][id.index].mh, id.serialized);
616 bool DataKeeper::RestoreSerializer(size_t serializerindex, User* user)
618 if (serializerindex == UserData::UNUSED_INDEX)
621 // The following checks are redundant
622 LocalUser* const localuser = IS_LOCAL(user);
625 if (localuser->serializer != dummyserializer)
628 const ProviderInfo& provinfo = handledserializers[serializerindex];
629 if (!provinfo.serializer)
631 // Users cannot exist without a serializer
632 ServerInstance->Users.QuitUser(user, "Serializer lost in reload");
636 localuser->serializer = provinfo.serializer;
640 void DataKeeper::DoRestoreUsers()
642 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restoring user data");
643 Modes::ChangeList modechange;
645 for (std::vector<UserData>::const_iterator i = userdatalist.begin(); i != userdatalist.end(); ++i)
647 const UserData& userdata = *i;
648 User* const user = ServerInstance->FindUUID(userdata.owner);
651 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "User %s is gone", userdata.owner.c_str());
655 // Attempt to restore serializer first, if it fails it's a fatal error and RestoreSerializer() quits them
656 if (!RestoreSerializer(userdata.serializerindex, user))
659 RestoreObj(userdata, user, MODETYPE_USER, modechange);
660 ServerInstance->Modes.Process(ServerInstance->FakeClient, NULL, user, modechange, ModeParser::MODE_LOCALONLY);
665 void DataKeeper::DoRestoreChans()
667 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restoring channel data");
668 Modes::ChangeList modechange;
670 for (std::vector<ChanData>::const_iterator i = chandatalist.begin(); i != chandatalist.end(); ++i)
672 const ChanData& chandata = *i;
673 Channel* const chan = ServerInstance->FindChan(chandata.owner);
676 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Channel %s not found", chandata.owner.c_str());
680 RestoreObj(chandata, chan, MODETYPE_CHANNEL, modechange);
681 // Process the mode change before applying any prefix modes
682 ServerInstance->Modes.Process(ServerInstance->FakeClient, chan, NULL, modechange, ModeParser::MODE_LOCALONLY);
685 // Restore all member data
686 RestoreMemberData(chan, chandata.memberdatalist, modechange);
687 ServerInstance->Modes.Process(ServerInstance->FakeClient, chan, NULL, modechange, ModeParser::MODE_LOCALONLY);
692 void DataKeeper::DoRestoreModules()
694 for (ReloadModule::CustomData::List::iterator i = moddata.list.begin(); i != moddata.list.end(); ++i)
696 ReloadModule::CustomData::Data& data = *i;
697 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Calling module data handler %p", (void*)data.handler);
698 data.handler->OnReloadModuleRestore(mod, data.data);
702 } // namespace ReloadModule
704 class ReloadAction : public ActionBase
707 const std::string uuid;
708 const std::string passedname;
711 ReloadAction(Module* m, const std::string& uid, const std::string& passedmodname)
714 , passedname(passedmodname)
718 void Call() CXX11_OVERRIDE
720 ReloadModule::DataKeeper datakeeper;
721 datakeeper.Save(mod);
723 std::string name = mod->ModuleSourceFile;
724 ServerInstance->Modules->DoSafeUnload(mod);
725 ServerInstance->GlobalCulls.Apply();
726 bool result = ServerInstance->Modules->Load(name);
730 Module* newmod = ServerInstance->Modules->Find(name);
731 datakeeper.Restore(newmod);
736 ServerInstance->SNO->WriteGlobalSno('a', "RELOAD MODULE: %s %ssuccessfully reloaded", passedname.c_str(), result ? "" : "un");
737 User* user = ServerInstance->FindUUID(uuid);
739 user->WriteNumeric(RPL_LOADEDMODULE, passedname, InspIRCd::Format("Module %ssuccessfully reloaded.", (result ? "" : "un")));
741 ServerInstance->GlobalCulls.AddItem(this);
745 CmdResult CommandReloadmodule::Handle(User* user, const Params& parameters)
747 Module* m = ServerInstance->Modules->Find(parameters[0]);
750 user->WriteNumeric(RPL_LOADEDMODULE, parameters[0], "You cannot reload core_reloadmodule (unload and load it)");
757 if ((m) && (ServerInstance->Modules.CanUnload(m)))
759 ServerInstance->AtomicActions.AddAction(new ReloadAction(m, user->uuid, parameters[0]));
764 user->WriteNumeric(RPL_LOADEDMODULE, parameters[0], "Could not find module by that name");
769 class CoreModReloadmodule : public Module
772 CommandReloadmodule cmd;
775 CoreModReloadmodule()
780 Version GetVersion() CXX11_OVERRIDE
782 return Version("Provides the RELOADMODULE command", VF_CORE | VF_VENDOR);
786 MODULE_INIT(CoreModReloadmodule)