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