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