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