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