1 /*
2 * atheme-services: A collection of minimalist IRC services
3 * servers.c: Server and network state tracking.
4 *
5 * Copyright (c) 2005-2007 Atheme Project (http://www.atheme.org)
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
12 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
13 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
14 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
15 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
16 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
17 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
18 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
19 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
20 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
21 * POSSIBILITY OF SUCH DAMAGE.
22 */
23
24 #include "atheme.h"
25
26 mowgli_patricia_t *sidlist;
27 mowgli_patricia_t *servlist;
28 mowgli_list_t tldlist;
29
30 mowgli_heap_t *serv_heap;
31 mowgli_heap_t *tld_heap;
32
33 static void server_delete_serv(server_t *s);
34
35 /*
36 * init_servers()
37 *
38 * Initializes the server heap and server/sid DTree structures.
39 *
40 * Inputs:
41 * - nothing
42 *
43 * Outputs:
44 * - nothing
45 *
46 * Side Effects:
47 * - if the heap or dtrees fail to initialize, the program
48 * will abort.
49 */
init_servers(void)50 void init_servers(void)
51 {
52 serv_heap = sharedheap_get(sizeof(server_t));
53 tld_heap = sharedheap_get(sizeof(tld_t));
54
55 if (serv_heap == NULL || tld_heap == NULL)
56 {
57 slog(LG_INFO, "init_servers(): block allocator failure.");
58 exit(EXIT_FAILURE);
59 }
60
61 servlist = mowgli_patricia_create(irccasecanon);
62 sidlist = mowgli_patricia_create(noopcanon);
63 }
64
65 /*
66 * server_add(const char *name, unsigned int hops, const char *uplink,
67 * const char *id, const char *desc)
68 *
69 * Server object factory.
70 *
71 * Inputs:
72 * - name of server object to create or NULL if it's a masked server
73 * - amount of hops server has from services
74 * - name of server's uplink or NULL if it's us
75 * - SID of uplink if applicable otherwise NULL
76 * - server's description
77 *
78 * Outputs:
79 * - on success, a new server object
80 *
81 * Side Effects:
82 * - the new server object is added to the server and sid DTree.
83 */
server_add(const char * name,unsigned int hops,server_t * uplink,const char * id,const char * desc)84 server_t *server_add(const char *name, unsigned int hops, server_t *uplink, const char *id, const char *desc)
85 {
86 server_t *s;
87 const char *tld;
88
89 /* Masked servers must have a SID */
90 return_val_if_fail(name != NULL || id != NULL, NULL);
91 /* Masked servers must be behind something else */
92 return_val_if_fail(name != NULL || uplink != NULL, NULL);
93
94 if (uplink)
95 {
96 if (name == NULL)
97 slog(LG_NETWORK, "server_add(): %s (%s), masked", uplink->name, id);
98 else if (id != NULL)
99 slog(LG_NETWORK, "server_add(): %s (%s), uplink %s", name, id, uplink->name);
100 else
101 slog(LG_NETWORK, "server_add(): %s, uplink %s", name, uplink->name);
102 }
103 else
104 slog(LG_DEBUG, "server_add(): %s, root", name);
105
106 s = mowgli_heap_alloc(serv_heap);
107
108 if (id != NULL)
109 {
110 s->sid = sstrdup(id);
111 mowgli_patricia_add(sidlist, s->sid, s);
112 }
113
114 /* check to see if it's hidden */
115 if (!strncmp(desc, "(H)", 3))
116 {
117 s->flags |= SF_HIDE;
118 desc += 3;
119 if (*desc == ' ')
120 desc++;
121 }
122
123 s->name = sstrdup(name != NULL ? name : uplink->name);
124 s->desc = sstrdup(desc);
125 s->hops = hops;
126 s->connected_since = CURRTIME;
127
128 if (name != NULL)
129 mowgli_patricia_add(servlist, s->name, s);
130 else
131 s->flags |= SF_MASKED;
132
133 if (uplink)
134 {
135 s->uplink = uplink;
136 mowgli_node_add(s, mowgli_node_create(), &uplink->children);
137 }
138
139 /* tld list for global noticer */
140 tld = strrchr(s->name, '.');
141
142 if (tld != NULL)
143 {
144 if (!tld_find(tld))
145 tld_add(tld);
146 }
147
148 cnt.server++;
149
150 hook_call_server_add(s);
151
152 return s;
153 }
154
155 /*
156 * server_delete(const char *name)
157 *
158 * Finds and recursively destroys a server object.
159 *
160 * Inputs:
161 * - name of server to find and destroy
162 *
163 * Outputs:
164 * - nothing
165 *
166 * Side Effects:
167 * - all users and servers attached to the target are recursively deleted
168 */
server_delete(const char * name)169 void server_delete(const char *name)
170 {
171 server_t *s = server_find(name);
172
173 if (!s)
174 {
175 slog(LG_DEBUG, "server_delete(): called for nonexistant server: %s", name);
176
177 return;
178 }
179 server_delete_serv(s);
180 }
181
server_delete_serv(server_t * s)182 static void server_delete_serv(server_t *s)
183 {
184 server_t *child;
185 user_t *u;
186 mowgli_node_t *n, *tn;
187
188 if (s == me.me)
189 {
190 /* Deleting this would cause confusion, so let's not do it.
191 * Some ircds send SQUIT <myname> when atheme is squitted.
192 * -- jilles
193 */
194 slog(LG_DEBUG, "server_delete(): tried to delete myself");
195 return;
196 }
197
198 if (s->sid)
199 slog(me.connected ? LG_NETWORK : LG_DEBUG, "server_delete(): %s (%s), uplink %s (%d users)",
200 s->name, s->sid,
201 s->uplink != NULL ? s->uplink->name : "<none>",
202 s->users);
203 else
204 slog(me.connected ? LG_NETWORK : LG_DEBUG, "server_delete(): %s, uplink %s (%d users)",
205 s->name, s->uplink != NULL ? s->uplink->name : "<none>",
206 s->users);
207
208 hook_call_server_delete((&(hook_server_delete_t){ .s = s }));
209
210 /* first go through it's users and kill all of them */
211 MOWGLI_ITER_FOREACH_SAFE(n, tn, s->userlist.head)
212 {
213 u = (user_t *)n->data;
214 /* This user split, allow bursted logins for the account.
215 * XXX should we do this here?
216 * -- jilles */
217 if (u->myuser != NULL)
218 u->myuser->flags &= ~MU_NOBURSTLOGIN;
219 user_delete(u, "*.net *.split");
220 }
221
222 MOWGLI_ITER_FOREACH_SAFE(n, tn, s->children.head)
223 {
224 child = n->data;
225 server_delete_serv(child);
226 }
227
228 /* now remove the server */
229 if (!(s->flags & SF_MASKED))
230 mowgli_patricia_delete(servlist, s->name);
231
232 if (s->sid)
233 mowgli_patricia_delete(sidlist, s->sid);
234
235 if (s->uplink)
236 {
237 n = mowgli_node_find(s, &s->uplink->children);
238 mowgli_node_delete(n, &s->uplink->children);
239 mowgli_node_free(n);
240 }
241
242 /* If unconnect semantics SQUIT was confirmed, introduce the jupe
243 * now. This must be after removing the server from the dtrees.
244 * -- jilles */
245 if (s->flags & SF_JUPE_PENDING)
246 jupe(s->name, "Juped");
247
248 free(s->name);
249 free(s->desc);
250 if (s->sid)
251 free(s->sid);
252
253 mowgli_heap_free(serv_heap, s);
254
255 cnt.server--;
256 }
257
258 /*
259 * server_find(const char *name)
260 *
261 * Finds a server object.
262 *
263 * Inputs:
264 * - name of server to find
265 *
266 * Outputs:
267 * - on success, the server object
268 * - on failure, NULL.
269 *
270 * Side Effects:
271 * - none
272 */
server_find(const char * name)273 server_t *server_find(const char *name)
274 {
275 server_t *s;
276
277 s = mowgli_patricia_retrieve(sidlist, name);
278 if (s != NULL)
279 return s;
280
281 return mowgli_patricia_retrieve(servlist, name);
282 }
283
284 /*
285 * tld_add(const char *name)
286 *
287 * TLD object factory.
288 *
289 * Inputs:
290 * - name of TLD to cache as an object
291 *
292 * Outputs:
293 * - on success, a TLD object
294 * - on failure, NULL
295 *
296 * Side Effects:
297 * - the TLD object is registered with the TLD list.
298 */
tld_add(const char * name)299 tld_t *tld_add(const char *name)
300 {
301 tld_t *tld;
302 mowgli_node_t *n = mowgli_node_create();
303
304 slog(LG_DEBUG, "tld_add(): %s", name);
305
306 tld = mowgli_heap_alloc(tld_heap);
307
308 mowgli_node_add(tld, n, &tldlist);
309
310 tld->name = sstrdup(name);
311
312 cnt.tld++;
313
314 return tld;
315 }
316
317 /*
318 * tld_delete(const char *name)
319 *
320 * Destroys a TLD object.
321 *
322 * Inputs:
323 * - name of TLD object to destroy
324 *
325 * Outputs:
326 * - nothing
327 *
328 * Side Effects:
329 * - the TLD object is removed and deregistered from the TLD list.
330 */
tld_delete(const char * name)331 void tld_delete(const char *name)
332 {
333 tld_t *tld = tld_find(name);
334 mowgli_node_t *n;
335
336 if (!tld)
337 {
338 slog(LG_DEBUG, "tld_delete(): called for nonexistant tld: %s", name);
339
340 return;
341 }
342
343 slog(LG_DEBUG, "tld_delete(): %s", tld->name);
344
345 n = mowgli_node_find(tld, &tldlist);
346 mowgli_node_delete(n, &tldlist);
347 mowgli_node_free(n);
348
349 free(tld->name);
350 mowgli_heap_free(tld_heap, tld);
351
352 cnt.tld--;
353 }
354
355 /*
356 * tld_find(const char *name)
357 *
358 * Looks up a TLD object.
359 *
360 * Inputs:
361 * - name of TLD object to look up
362 *
363 * Outputs:
364 * - on success, the TLD object
365 * - on failure, NULL
366 *
367 * Side Effects:
368 * - none
369 */
tld_find(const char * name)370 tld_t *tld_find(const char *name)
371 {
372 tld_t *tld;
373 mowgli_node_t *n;
374
375 if (name == NULL)
376 return NULL;
377
378 MOWGLI_ITER_FOREACH(n, tldlist.head)
379 {
380 tld = (tld_t *)n->data;
381
382 if (!strcasecmp(name, tld->name))
383 return tld;
384 }
385
386 return NULL;
387 }
388
389 /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
390 * vim:ts=8
391 * vim:sw=8
392 * vim:noexpandtab
393 */
394