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