]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/coremods/core_reloadmodule.cpp
0d01d9e856519a44c7fb9bd5c7fab2cfc33545a9
[user/henk/code/inspircd.git] / src / coremods / core_reloadmodule.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
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>
7  *
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.
11  *
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
15  * details.
16  *
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/>.
19  */
20
21
22 #include "inspircd.h"
23 #include "listmode.h"
24 #include "modules/reload.h"
25
26 static Events::ModuleEventProvider* reloadevprov;
27
28 class CommandReloadmodule : public Command
29 {
30         Events::ModuleEventProvider evprov;
31  public:
32         /** Constructor for reloadmodule.
33          */
34         CommandReloadmodule(Module* parent)
35                 : Command(parent, "RELOADMODULE", 1)
36                 , evprov(parent, "event/reloadmodule")
37         {
38                 reloadevprov = &evprov;
39                 flags_needed = 'o';
40                 syntax = "<modulename>";
41         }
42
43         /** Handle command.
44          * @param parameters The parameters to the command
45          * @param user The user issuing the command
46          * @return A value from CmdResult to indicate command success or failure.
47          */
48         CmdResult Handle(const std::vector<std::string>& parameters, User *user);
49 };
50
51 namespace ReloadModule
52 {
53
54 class DataKeeper
55 {
56         /** Data we save for each mode and extension provided by the module
57          */
58         struct ProviderInfo
59         {
60                 std::string itemname;
61                 union
62                 {
63                         ModeHandler* mh;
64                         ExtensionItem* extitem;
65                 };
66
67                 ProviderInfo(ModeHandler* mode)
68                         : itemname(mode->name)
69                         , mh(mode)
70                 {
71                 }
72
73                 ProviderInfo(ExtensionItem* ei)
74                         : itemname(ei->name)
75                         , extitem(ei)
76                 {
77                 }
78         };
79
80         struct InstanceData
81         {
82                 /** Position of the ModeHandler or ExtensionItem that the serialized data belongs to
83                  */
84                 size_t index;
85
86                 /** Serialized data
87                  */
88                 std::string serialized;
89
90                 InstanceData(size_t Index, const std::string& Serialized)
91                         : index(Index)
92                         , serialized(Serialized)
93                 {
94                 }
95         };
96
97         struct ModesExts
98         {
99                 /** Mode data for the object, one entry per mode set by the module being reloaded
100                  */
101                 std::vector<InstanceData> modelist;
102
103                 /** Extensions for the object, one entry per extension set by the module being reloaded
104                  */
105                 std::vector<InstanceData> extlist;
106
107                 bool empty() const { return ((modelist.empty()) && (extlist.empty())); }
108
109                 void swap(ModesExts& other)
110                 {
111                         modelist.swap(other.modelist);
112                         extlist.swap(other.extlist);
113                 }
114         };
115
116         struct OwnedModesExts : public ModesExts
117         {
118                 /** User uuid or channel name
119                  */
120                 std::string owner;
121
122                 OwnedModesExts(const std::string& Owner)
123                         : owner(Owner)
124                 {
125                 }
126         };
127
128         // Data saved for each channel
129         struct ChanData : public OwnedModesExts
130         {
131                 /** Type of data stored for each member who has any affected modes or extensions set
132                  */
133                 typedef OwnedModesExts MemberData;
134
135                 /** List of data (modes and extensions) about each member
136                  */
137                 std::vector<MemberData> memberdatalist;
138
139                 ChanData(Channel* chan)
140                         : OwnedModesExts(chan->name)
141                 {
142                 }
143         };
144
145         // Data saved for each user
146         typedef OwnedModesExts UserData;
147
148         /** Module being reloaded
149          */
150         Module* mod;
151
152         /** Stores all user and channel modes provided by the module
153          */
154         std::vector<ProviderInfo> handledmodes[2];
155
156         /** Stores all extensions provided by the module
157          */
158         std::vector<ProviderInfo> handledexts;
159
160         /** Stores all of the module data related to users
161          */
162         std::vector<UserData> userdatalist;
163
164         /** Stores all of the module data related to channels and memberships
165          */
166         std::vector<ChanData> chandatalist;
167
168         /** Data attached by modules
169          */
170         ReloadModule::CustomData moddata;
171
172         void SaveExtensions(Extensible* extensible, std::vector<InstanceData>& extdatalist);
173         void SaveMemberData(Channel* chan, std::vector<ChanData::MemberData>& memberdatalist);
174         static void SaveListModes(Channel* chan, ListModeBase* lm, size_t index, ModesExts& currdata);
175
176         void CreateModeList(ModeType modetype);
177         void DoSaveUsers();
178         void DoSaveChans();
179
180         /** Link previously saved extension names to currently available ExtensionItems
181          */
182         void LinkExtensions();
183
184         /** Link previously saved mode names to currently available ModeHandlers
185          * @param modetype Type of the modes to look for
186          */
187         void LinkModes(ModeType modetype);
188
189         void DoRestoreUsers();
190         void DoRestoreChans();
191         void DoRestoreModules();
192
193         /** Restore previously saved modes and extensions on an Extensible.
194          * The extensions are set directly on the extensible, the modes are added into the provided mode change list.
195          * @param data Data to unserialize from
196          * @param extensible Object to restore
197          * @param modetype MODETYPE_USER if the object being restored is a User, MODETYPE_CHANNEL otherwise
198          * (for Channels and Memberships).
199          * @param modechange Mode change to populate with the modes
200          */
201         void RestoreObj(const OwnedModesExts& data, Extensible* extensible, ModeType modetype, Modes::ChangeList& modechange);
202
203         /** Restore all previously saved extensions on an Extensible
204          * @param list List of extensions and their serialized data to restore
205          * @param extensible Target Extensible
206          */
207         void RestoreExtensions(const std::vector<InstanceData>& list, Extensible* extensible);
208
209         /** Restore all previously saved modes on a User, Channel or Membership
210          * @param list List of modes to restore
211          * @param modetype MODETYPE_USER if the object being restored is a User, MODETYPE_CHANNEL otherwise
212          * @param modechange Mode change to populate with the modes
213          */
214         void RestoreModes(const std::vector<InstanceData>& list, ModeType modetype, Modes::ChangeList& modechange);
215
216         /** Restore all modes and extensions of all members on a channel
217          * @param chan Channel whose members are being restored
218          * @param memberdata Data to restore
219          * @param modechange Mode change to populate with prefix modes
220          */
221         void RestoreMemberData(Channel* chan, const std::vector<ChanData::MemberData>& memberdatalist, Modes::ChangeList& modechange);
222
223         /** Verify that a service which had its data saved is available and owned by the module that owned it previously
224          * @param service Service descriptor
225          * @param type Human-readable type of the service for log messages
226          */
227         void VerifyServiceProvider(const ProviderInfo& service, const char* type);
228
229  public:
230         /** Save module state
231          * @param currmod Module whose data to save
232          */
233         void Save(Module* currmod);
234
235         /** Restore module state
236          * @param newmod Newly loaded instance of the module which had its data saved
237          */
238         void Restore(Module* newmod);
239
240         /** Handle reload failure
241          */
242         void Fail();
243 };
244
245 void DataKeeper::DoSaveUsers()
246 {
247         ModesExts currdata;
248
249         const user_hash& users = ServerInstance->Users->GetUsers();
250         for (user_hash::const_iterator i = users.begin(); i != users.end(); ++i)
251         {
252                 User* const user = i->second;
253
254                 // Serialize user modes
255                 for (size_t j = 0; j < handledmodes[MODETYPE_USER].size(); j++)
256                 {
257                         ModeHandler* mh = handledmodes[MODETYPE_USER][j].mh;
258                         if (user->IsModeSet(mh))
259                                 currdata.modelist.push_back(InstanceData(j, mh->GetUserParameter(user)));
260                 }
261
262                 // Serialize all extensions attached to the User
263                 SaveExtensions(user, currdata.extlist);
264
265                 // Add to list if the user has any modes or extensions set that we are interested in, otherwise we don't
266                 // have to do anything with this user when restoring
267                 if (!currdata.empty())
268                 {
269                         userdatalist.push_back(UserData(user->uuid));
270                         userdatalist.back().swap(currdata);
271                 }
272         }
273 }
274
275 void DataKeeper::SaveExtensions(Extensible* extensible, std::vector<InstanceData>& extdata)
276 {
277         const Extensible::ExtensibleStore& setexts = extensible->GetExtList();
278
279         // Position of the extension saved in the handledexts list
280         size_t index = 0;
281         for (std::vector<ProviderInfo>::const_iterator i = handledexts.begin(); i != handledexts.end(); ++i, index++)
282         {
283                 ExtensionItem* const item = i->extitem;
284                 Extensible::ExtensibleStore::const_iterator it = setexts.find(item);
285                 if (it == setexts.end())
286                         continue;
287
288                 std::string value = item->serialize(FORMAT_INTERNAL, extensible, it->second);
289                 // If the serialized value is empty the extension won't be saved and restored
290                 if (!value.empty())
291                         extdata.push_back(InstanceData(index, value));
292         }
293 }
294
295 void DataKeeper::SaveListModes(Channel* chan, ListModeBase* lm, size_t index, ModesExts& currdata)
296 {
297         const ListModeBase::ModeList* list = lm->GetList(chan);
298         if (!list)
299                 return;
300
301         for (ListModeBase::ModeList::const_iterator i = list->begin(); i != list->end(); ++i)
302         {
303                 const ListModeBase::ListItem& listitem = *i;
304                 currdata.modelist.push_back(InstanceData(index, listitem.mask));
305         }
306 }
307
308 void DataKeeper::DoSaveChans()
309 {
310         ModesExts currdata;
311         std::vector<OwnedModesExts> currmemberdata;
312
313         const chan_hash& chans = ServerInstance->GetChans();
314         for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ++i)
315         {
316                 Channel* const chan = i->second;
317
318                 // Serialize channel modes
319                 for (size_t j = 0; j < handledmodes[MODETYPE_CHANNEL].size(); j++)
320                 {
321                         ModeHandler* mh = handledmodes[MODETYPE_CHANNEL][j].mh;
322                         ListModeBase* lm = mh->IsListModeBase();
323                         if (lm)
324                                 SaveListModes(chan, lm, j, currdata);
325                         else if (chan->IsModeSet(mh))
326                                 currdata.modelist.push_back(InstanceData(j, chan->GetModeParameter(mh)));
327                 }
328
329                 // Serialize all extensions attached to the Channel
330                 SaveExtensions(chan, currdata.extlist);
331
332                 // Serialize all extensions attached to and all modes set on all members of the channel
333                 SaveMemberData(chan, currmemberdata);
334
335                 // Same logic as in DoSaveUsers() plus we consider the modes and extensions of all members
336                 if ((!currdata.empty()) || (!currmemberdata.empty()))
337                 {
338                         chandatalist.push_back(ChanData(chan));
339                         chandatalist.back().swap(currdata);
340                         chandatalist.back().memberdatalist.swap(currmemberdata);
341                 }
342         }
343 }
344
345 void DataKeeper::SaveMemberData(Channel* chan, std::vector<OwnedModesExts>& memberdatalist)
346 {
347         ModesExts currdata;
348         const Channel::MemberMap& users = chan->GetUsers();
349         for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i)
350         {
351                 Membership* const memb = i->second;
352
353                 for (size_t j = 0; j < handledmodes[MODETYPE_CHANNEL].size(); j++)
354                 {
355                         ModeHandler* mh = handledmodes[MODETYPE_CHANNEL][j].mh;
356                         if ((mh->IsPrefixMode()) && (memb->hasMode(mh->GetModeChar())))
357                                 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
358                 }
359
360                 SaveExtensions(memb, currdata.extlist);
361
362                 // Same logic as in DoSaveUsers()
363                 if (!currdata.empty())
364                 {
365                         memberdatalist.push_back(OwnedModesExts(memb->user->uuid));
366                         memberdatalist.back().swap(currdata);
367                 }
368         }
369 }
370
371 void DataKeeper::RestoreMemberData(Channel* chan, const std::vector<ChanData::MemberData>& memberdatalist, Modes::ChangeList& modechange)
372 {
373         for (std::vector<ChanData::MemberData>::const_iterator i = memberdatalist.begin(); i != memberdatalist.end(); ++i)
374         {
375                 const ChanData::MemberData& md = *i;
376                 User* const user = ServerInstance->FindUUID(md.owner);
377                 if (!user)
378                 {
379                         ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "User %s is gone (while processing %s)", md.owner.c_str(), chan->name.c_str());
380                         continue;
381                 }
382
383                 Membership* const memb = chan->GetUser(user);
384                 if (!memb)
385                 {
386                         ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Member %s is no longer on channel %s", md.owner.c_str(), chan->name.c_str());
387                         continue;
388                 }
389
390                 RestoreObj(md, memb, MODETYPE_CHANNEL, modechange);
391         }
392 }
393
394 void DataKeeper::CreateModeList(ModeType modetype)
395 {
396         const ModeParser::ModeHandlerMap& modes = ServerInstance->Modes->GetModes(modetype);
397         for (ModeParser::ModeHandlerMap::const_iterator i = modes.begin(); i != modes.end(); ++i)
398         {
399                 ModeHandler* mh = i->second;
400                 if (mh->creator == mod)
401                         handledmodes[modetype].push_back(ProviderInfo(mh));
402         }
403 }
404
405 void DataKeeper::Save(Module* currmod)
406 {
407         this->mod = currmod;
408
409         const ExtensionManager::ExtMap& allexts = ServerInstance->Extensions.GetExts();
410         for (ExtensionManager::ExtMap::const_iterator i = allexts.begin(); i != allexts.end(); ++i)
411         {
412                 ExtensionItem* ext = i->second;
413                 if (ext->creator == mod)
414                         handledexts.push_back(ProviderInfo(ext));
415         }
416
417         CreateModeList(MODETYPE_USER);
418         DoSaveUsers();
419
420         CreateModeList(MODETYPE_CHANNEL);
421         DoSaveChans();
422
423         FOREACH_MOD_CUSTOM(*reloadevprov, ReloadModule::EventListener, OnReloadModuleSave, (mod, this->moddata));
424
425         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());
426 }
427
428 void DataKeeper::VerifyServiceProvider(const ProviderInfo& service, const char* type)
429 {
430         const ServiceProvider* sp = service.extitem;
431         if (!sp)
432                 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "%s \"%s\" is no longer available", type, service.itemname.c_str());
433         else if (sp->creator != mod)
434                 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>"));
435 }
436
437 void DataKeeper::LinkModes(ModeType modetype)
438 {
439         std::vector<ProviderInfo>& list = handledmodes[modetype];
440         for (std::vector<ProviderInfo>::iterator i = list.begin(); i != list.end(); ++i)
441         {
442                 ProviderInfo& item = *i;
443                 item.mh = ServerInstance->Modes->FindMode(item.itemname, modetype);
444                 VerifyServiceProvider(item, (modetype == MODETYPE_USER ? "User mode" : "Channel mode"));
445         }
446 }
447
448 void DataKeeper::LinkExtensions()
449 {
450         for (std::vector<ProviderInfo>::iterator i = handledexts.begin(); i != handledexts.end(); ++i)
451         {
452                 ProviderInfo& item = *i;
453                 item.extitem = ServerInstance->Extensions.GetItem(item.itemname);
454                 VerifyServiceProvider(item.extitem, "Extension");
455         }
456 }
457
458 void DataKeeper::Restore(Module* newmod)
459 {
460         this->mod = newmod;
461
462         // Find the new extension items
463         LinkExtensions();
464         LinkModes(MODETYPE_USER);
465         LinkModes(MODETYPE_CHANNEL);
466
467         // Restore
468         DoRestoreUsers();
469         DoRestoreChans();
470         DoRestoreModules();
471
472         ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restore finished");
473 }
474
475 void DataKeeper::Fail()
476 {
477         this->mod = NULL;
478
479         ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restore failed, notifying modules");
480         DoRestoreModules();
481 }
482
483 void DataKeeper::RestoreObj(const OwnedModesExts& data, Extensible* extensible, ModeType modetype, Modes::ChangeList& modechange)
484 {
485         RestoreExtensions(data.extlist, extensible);
486         RestoreModes(data.modelist, modetype, modechange);
487 }
488
489 void DataKeeper::RestoreExtensions(const std::vector<InstanceData>& list, Extensible* extensible)
490 {
491         for (std::vector<InstanceData>::const_iterator i = list.begin(); i != list.end(); ++i)
492         {
493                 const InstanceData& id = *i;
494                 handledexts[id.index].extitem->unserialize(FORMAT_INTERNAL, extensible, id.serialized);
495         }
496 }
497
498 void DataKeeper::RestoreModes(const std::vector<InstanceData>& list, ModeType modetype, Modes::ChangeList& modechange)
499 {
500         for (std::vector<InstanceData>::const_iterator i = list.begin(); i != list.end(); ++i)
501         {
502                 const InstanceData& id = *i;
503                 modechange.push_add(handledmodes[modetype][id.index].mh, id.serialized);
504         }
505 }
506
507 void DataKeeper::DoRestoreUsers()
508 {
509         ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restoring user data");
510         Modes::ChangeList modechange;
511
512         for (std::vector<UserData>::const_iterator i = userdatalist.begin(); i != userdatalist.end(); ++i)
513         {
514                 const UserData& userdata = *i;
515                 User* const user = ServerInstance->FindUUID(userdata.owner);
516                 if (!user)
517                 {
518                         ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "User %s is gone", userdata.owner.c_str());
519                         continue;
520                 }
521
522                 RestoreObj(userdata, user, MODETYPE_USER, modechange);
523                 ServerInstance->Modes.Process(ServerInstance->FakeClient, NULL, user, modechange, ModeParser::MODE_LOCALONLY);
524                 modechange.clear();
525         }
526 }
527
528 void DataKeeper::DoRestoreChans()
529 {
530         ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Restoring channel data");
531         Modes::ChangeList modechange;
532
533         for (std::vector<ChanData>::const_iterator i = chandatalist.begin(); i != chandatalist.end(); ++i)
534         {
535                 const ChanData& chandata = *i;
536                 Channel* const chan = ServerInstance->FindChan(chandata.owner);
537                 if (!chan)
538                 {
539                         ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Channel %s not found", chandata.owner.c_str());
540                         continue;
541                 }
542
543                 RestoreObj(chandata, chan, MODETYPE_CHANNEL, modechange);
544                 // Process the mode change before applying any prefix modes
545                 ServerInstance->Modes.Process(ServerInstance->FakeClient, chan, NULL, modechange, ModeParser::MODE_LOCALONLY);
546                 modechange.clear();
547
548                 // Restore all member data
549                 RestoreMemberData(chan, chandata.memberdatalist, modechange);
550                 ServerInstance->Modes.Process(ServerInstance->FakeClient, chan, NULL, modechange, ModeParser::MODE_LOCALONLY);
551                 modechange.clear();
552         }
553 }
554
555 void DataKeeper::DoRestoreModules()
556 {
557         for (ReloadModule::CustomData::List::iterator i = moddata.list.begin(); i != moddata.list.end(); ++i)
558         {
559                 ReloadModule::CustomData::Data& data = *i;
560                 ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Calling module data handler %p", (void*)data.handler);
561                 data.handler->OnReloadModuleRestore(mod, data.data);
562         }
563 }
564
565 } // namespace ReloadModule
566
567 class ReloadAction : public HandlerBase0<void>
568 {
569         Module* const mod;
570         const std::string uuid;
571         const std::string passedname;
572
573  public:
574         ReloadAction(Module* m, const std::string& uid, const std::string& passedmodname)
575                 : mod(m)
576                 , uuid(uid)
577                 , passedname(passedmodname)
578         {
579         }
580
581         void Call()
582         {
583                 ReloadModule::DataKeeper datakeeper;
584                 datakeeper.Save(mod);
585
586                 DLLManager* dll = mod->ModuleDLLManager;
587                 std::string name = mod->ModuleSourceFile;
588                 ServerInstance->Modules->DoSafeUnload(mod);
589                 ServerInstance->GlobalCulls.Apply();
590                 delete dll;
591                 bool result = ServerInstance->Modules->Load(name);
592
593                 if (result)
594                 {
595                         Module* newmod = ServerInstance->Modules->Find(name);
596                         datakeeper.Restore(newmod);
597                 }
598                 else
599                         datakeeper.Fail();
600
601                 ServerInstance->SNO->WriteGlobalSno('a', "RELOAD MODULE: %s %ssuccessfully reloaded", passedname.c_str(), result ? "" : "un");
602                 User* user = ServerInstance->FindUUID(uuid);
603                 if (user)
604                         user->WriteNumeric(RPL_LOADEDMODULE, "%s :Module %ssuccessfully reloaded.", passedname.c_str(), result ? "" : "un");
605
606                 ServerInstance->GlobalCulls.AddItem(this);
607         }
608 };
609
610 CmdResult CommandReloadmodule::Handle (const std::vector<std::string>& parameters, User *user)
611 {
612         Module* m = ServerInstance->Modules->Find(parameters[0]);
613         if (m == creator)
614         {
615                 user->WriteNumeric(RPL_LOADEDMODULE, "%s :You cannot reload core_reloadmodule.so (unload and load it)",
616                         parameters[0].c_str());
617                 return CMD_FAILURE;
618         }
619
620         if (creator->dying)
621                 return CMD_FAILURE;
622
623         if ((m) && (ServerInstance->Modules.CanUnload(m)))
624         {
625                 ServerInstance->AtomicActions.AddAction(new ReloadAction(m, user->uuid, parameters[0]));
626                 return CMD_SUCCESS;
627         }
628         else
629         {
630                 user->WriteNumeric(RPL_LOADEDMODULE, "%s :Could not find module by that name", parameters[0].c_str());
631                 return CMD_FAILURE;
632         }
633 }
634
635 COMMAND_INIT(CommandReloadmodule)