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