]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_spanningtree/treeserver.cpp
Merge pull request #1162 from SaberUK/insp20+fix-deinstall
[user/henk/code/inspircd.git] / src / modules / m_spanningtree / treeserver.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
5  *   Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc>
6  *   Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net>
7  *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
8  *
9  * This file is part of InspIRCd.  InspIRCd is free software: you can
10  * redistribute it and/or modify it under the terms of the GNU General Public
11  * License as published by the Free Software Foundation, version 2.
12  *
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22
23 #include "inspircd.h"
24 #include "socket.h"
25 #include "xline.h"
26 #include "main.h"
27 #include "../spanningtree.h"
28
29 #include "utils.h"
30 #include "treeserver.h"
31
32 /* $ModDep: m_spanningtree/utils.h m_spanningtree/treeserver.h */
33
34 /** We use this constructor only to create the 'root' item, Utils->TreeRoot, which
35  * represents our own server. Therefore, it has no route, no parent, and
36  * no socket associated with it. Its version string is our own local version.
37  */
38 TreeServer::TreeServer(SpanningTreeUtilities* Util, std::string Name, std::string Desc, const std::string &id)
39         : ServerName(Name.c_str()), ServerDesc(Desc), Utils(Util), ServerUser(ServerInstance->FakeClient)
40 {
41         age = ServerInstance->Time();
42         bursting = false;
43         Parent = NULL;
44         VersionString.clear();
45         ServerUserCount = ServerOperCount = 0;
46         VersionString = ServerInstance->GetVersionString();
47         Route = NULL;
48         Socket = NULL; /* Fix by brain */
49         StartBurst = rtt = 0;
50         Warned = Hidden = false;
51         AddHashEntry();
52         SetID(id);
53 }
54
55 /** When we create a new server, we call this constructor to initialize it.
56  * This constructor initializes the server's Route and Parent, and sets up
57  * its ping counters so that it will be pinged one minute from now.
58  */
59 TreeServer::TreeServer(SpanningTreeUtilities* Util, std::string Name, std::string Desc, const std::string &id, TreeServer* Above, TreeSocket* Sock, bool Hide)
60         : Parent(Above), ServerName(Name.c_str()), ServerDesc(Desc), Socket(Sock), Utils(Util), ServerUser(new FakeUser(id, Name)), Hidden(Hide)
61 {
62         age = ServerInstance->Time();
63         bursting = true;
64         VersionString.clear();
65         ServerUserCount = ServerOperCount = 0;
66         SetNextPingTime(ServerInstance->Time() + Utils->PingFreq);
67         SetPingFlag();
68         Warned = false;
69         rtt = 0;
70
71         long ts = ServerInstance->Time() * 1000 + (ServerInstance->Time_ns() / 1000000);
72         this->StartBurst = ts;
73         ServerInstance->Logs->Log("m_spanningtree",DEBUG, "Started bursting at time %lu", ts);
74
75         /* find the 'route' for this server (e.g. the one directly connected
76          * to the local server, which we can use to reach it)
77          *
78          * In the following example, consider we have just added a TreeServer
79          * class for server G on our network, of which we are server A.
80          * To route traffic to G (marked with a *) we must send the data to
81          * B (marked with a +) so this algorithm initializes the 'Route'
82          * value to point at whichever server traffic must be routed through
83          * to get here. If we were to try this algorithm with server B,
84          * the Route pointer would point at its own object ('this').
85          *
86          *            A
87          *           / \
88          *        + B   C
89          *         / \   \
90          *        D   E   F
91          *       /         \
92          *    * G           H
93          *
94          * We only run this algorithm when a server is created, as
95          * the routes remain constant while ever the server exists, and
96          * do not need to be re-calculated.
97          */
98
99         Route = Above;
100         if (Route == Utils->TreeRoot)
101         {
102                 Route = this;
103         }
104         else
105         {
106                 while (this->Route->GetParent() != Utils->TreeRoot)
107                 {
108                         this->Route = Route->GetParent();
109                 }
110         }
111
112         /* Because recursive code is slow and takes a lot of resources,
113          * we store two representations of the server tree. The first
114          * is a recursive structure where each server references its
115          * children and its parent, which is used for netbursts and
116          * netsplits to dump the whole dataset to the other server,
117          * and the second is used for very fast lookups when routing
118          * messages and is instead a hash_map, where each item can
119          * be referenced by its server name. The AddHashEntry()
120          * call below automatically inserts each TreeServer class
121          * into the hash_map as it is created. There is a similar
122          * maintainance call in the destructor to tidy up deleted
123          * servers.
124          */
125
126         this->AddHashEntry();
127
128         SetID(id);
129 }
130
131 const std::string& TreeServer::GetID()
132 {
133         return sid;
134 }
135
136 void TreeServer::FinishBurstInternal()
137 {
138         this->bursting = false;
139         SetNextPingTime(ServerInstance->Time() + Utils->PingFreq);
140         SetPingFlag();
141         for(unsigned int q=0; q < ChildCount(); q++)
142         {
143                 TreeServer* child = GetChild(q);
144                 child->FinishBurstInternal();
145         }
146 }
147
148 void TreeServer::FinishBurst()
149 {
150         FinishBurstInternal();
151         ServerInstance->XLines->ApplyLines();
152         long ts = ServerInstance->Time() * 1000 + (ServerInstance->Time_ns() / 1000000);
153         unsigned long bursttime = ts - this->StartBurst;
154         ServerInstance->SNO->WriteToSnoMask(Parent == Utils->TreeRoot ? 'l' : 'L', "Received end of netburst from \2%s\2 (burst time: %lu %s)",
155                 ServerName.c_str(), (bursttime > 10000 ? bursttime / 1000 : bursttime), (bursttime > 10000 ? "secs" : "msecs"));
156         AddServerEvent(Utils->Creator, ServerName.c_str());
157 }
158
159 void TreeServer::SetID(const std::string &id)
160 {
161         ServerInstance->Logs->Log("m_spanningtree",DEBUG, "Setting SID to " + id);
162         sid = id;
163         Utils->sidlist[sid] = this;
164 }
165
166 int TreeServer::QuitUsers(const std::string &reason)
167 {
168         const char* reason_s = reason.c_str();
169         std::vector<User*> time_to_die;
170         for (user_hash::iterator n = ServerInstance->Users->clientlist->begin(); n != ServerInstance->Users->clientlist->end(); n++)
171         {
172                 if (n->second->server == ServerName)
173                 {
174                         time_to_die.push_back(n->second);
175                 }
176         }
177         for (std::vector<User*>::iterator n = time_to_die.begin(); n != time_to_die.end(); n++)
178         {
179                 User* a = (User*)*n;
180                 if (!IS_LOCAL(a))
181                 {
182                         if (this->Utils->quiet_bursts)
183                                 a->quietquit = true;
184
185                         if (ServerInstance->Config->HideSplits)
186                                 ServerInstance->Users->QuitUser(a, "*.net *.split", reason_s);
187                         else
188                                 ServerInstance->Users->QuitUser(a, reason_s);
189                 }
190         }
191         return time_to_die.size();
192 }
193
194 /** This method is used to add the structure to the
195  * hash_map for linear searches. It is only called
196  * by the constructors.
197  */
198 void TreeServer::AddHashEntry()
199 {
200         server_hash::iterator iter = Utils->serverlist.find(this->ServerName.c_str());
201         if (iter == Utils->serverlist.end())
202                 Utils->serverlist[this->ServerName.c_str()] = this;
203 }
204
205 /** This method removes the reference to this object
206  * from the hash_map which is used for linear searches.
207  * It is only called by the default destructor.
208  */
209 void TreeServer::DelHashEntry()
210 {
211         server_hash::iterator iter = Utils->serverlist.find(this->ServerName.c_str());
212         if (iter != Utils->serverlist.end())
213                 Utils->serverlist.erase(iter);
214 }
215
216 /** These accessors etc should be pretty self-
217  * explanitory.
218  */
219 TreeServer* TreeServer::GetRoute()
220 {
221         return Route;
222 }
223
224 std::string TreeServer::GetName()
225 {
226         return ServerName.c_str();
227 }
228
229 const std::string& TreeServer::GetDesc()
230 {
231         return ServerDesc;
232 }
233
234 const std::string& TreeServer::GetVersion()
235 {
236         return VersionString;
237 }
238
239 void TreeServer::SetNextPingTime(time_t t)
240 {
241         this->NextPing = t;
242         LastPingWasGood = false;
243 }
244
245 time_t TreeServer::NextPingTime()
246 {
247         return NextPing;
248 }
249
250 bool TreeServer::AnsweredLastPing()
251 {
252         return LastPingWasGood;
253 }
254
255 void TreeServer::SetPingFlag()
256 {
257         LastPingWasGood = true;
258 }
259
260 unsigned int TreeServer::GetUserCount()
261 {
262         return ServerUserCount;
263 }
264
265 void TreeServer::SetUserCount(int diff)
266 {
267         ServerUserCount += diff;
268 }
269
270 void TreeServer::SetOperCount(int diff)
271 {
272         ServerOperCount += diff;
273 }
274
275 unsigned int TreeServer::GetOperCount()
276 {
277         return ServerOperCount;
278 }
279
280 TreeSocket* TreeServer::GetSocket()
281 {
282         return Socket;
283 }
284
285 TreeServer* TreeServer::GetParent()
286 {
287         return Parent;
288 }
289
290 void TreeServer::SetVersion(const std::string &Version)
291 {
292         VersionString = Version;
293 }
294
295 unsigned int TreeServer::ChildCount()
296 {
297         return Children.size();
298 }
299
300 TreeServer* TreeServer::GetChild(unsigned int n)
301 {
302         if (n < Children.size())
303         {
304                 /* Make sure they  cant request
305                  * an out-of-range object. After
306                  * all we know what these programmer
307                  * types are like *grin*.
308                  */
309                 return Children[n];
310         }
311         else
312         {
313                 return NULL;
314         }
315 }
316
317 void TreeServer::AddChild(TreeServer* Child)
318 {
319         Children.push_back(Child);
320 }
321
322 bool TreeServer::DelChild(TreeServer* Child)
323 {
324         std::vector<TreeServer*>::iterator it = std::find(Children.begin(), Children.end(), Child);
325         if (it != Children.end())
326         {
327                 Children.erase(it);
328                 return true;
329         }
330         return false;
331 }
332
333 /** Removes child nodes of this node, and of that node, etc etc.
334  * This is used during netsplits to automatically tidy up the
335  * server tree. It is slow, we don't use it for much else.
336  */
337 bool TreeServer::Tidy()
338 {
339         while (1)
340         {
341                 std::vector<TreeServer*>::iterator a = Children.begin();
342                 if (a == Children.end())
343                         return true;
344                 TreeServer* s = *a;
345                 s->Tidy();
346                 s->cull();
347                 Children.erase(a);
348                 delete s;
349         }
350 }
351
352 CullResult TreeServer::cull()
353 {
354         if (ServerUser != ServerInstance->FakeClient)
355                 ServerUser->cull();
356         return classbase::cull();
357 }
358
359 TreeServer::~TreeServer()
360 {
361         /* We'd better tidy up after ourselves, eh? */
362         this->DelHashEntry();
363         if (ServerUser != ServerInstance->FakeClient)
364                 delete ServerUser;
365
366         server_hash::iterator iter = Utils->sidlist.find(GetID());
367         if (iter != Utils->sidlist.end())
368                 Utils->sidlist.erase(iter);
369 }