]>
Commit | Line | Data |
---|---|---|
212380e3 AC |
1 | /* |
2 | * ircd-ratbox: A slightly useful ircd. | |
3 | * whowas.c: WHOWAS user cache. | |
4 | * | |
5 | * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center | |
6 | * Copyright (C) 1996-2002 Hybrid Development Team | |
b47f8a4f AC |
7 | * Copyright (C) 2002-2012 ircd-ratbox development team |
8 | * Copyright (C) 2016 William Pitcock <nenolod@dereferenced.org> | |
212380e3 AC |
9 | * |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License as published by | |
12 | * the Free Software Foundation; either version 2 of the License, or | |
13 | * (at your option) any later version. | |
14 | * | |
15 | * This program is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | * GNU General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU General Public License | |
21 | * along with this program; if not, write to the Free Software | |
b47f8a4f | 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 |
212380e3 | 23 | * USA |
212380e3 AC |
24 | */ |
25 | ||
26 | #include "stdinc.h" | |
212380e3 | 27 | #include "hash.h" |
b47f8a4f | 28 | #include "whowas.h" |
4562c604 | 29 | #include "match.h" |
212380e3 | 30 | #include "ircd.h" |
212380e3 | 31 | #include "numeric.h" |
b47f8a4f | 32 | #include "s_assert.h" |
212380e3 AC |
33 | #include "s_serv.h" |
34 | #include "s_user.h" | |
35 | #include "send.h" | |
36 | #include "s_conf.h" | |
b47f8a4f AC |
37 | #include "client.h" |
38 | #include "send.h" | |
39 | #include "logger.h" | |
c88cdb00 | 40 | #include "scache.h" |
a4bf26dd | 41 | #include "rb_radixtree.h" |
212380e3 | 42 | |
b47f8a4f AC |
43 | struct whowas_top |
44 | { | |
45 | char *name; | |
46 | rb_dlink_list wwlist; | |
47 | }; | |
212380e3 | 48 | |
2fc6772e | 49 | static rb_radixtree *whowas_tree = NULL; |
b47f8a4f AC |
50 | static rb_dlink_list whowas_list = {NULL, NULL, 0}; |
51 | static unsigned int whowas_list_length = NICKNAMEHISTORYLENGTH; | |
52 | static void whowas_trim(void *unused); | |
212380e3 | 53 | |
b47f8a4f AC |
54 | static void |
55 | whowas_free_wtop(struct whowas_top *wtop) | |
56 | { | |
57 | if(rb_dlink_list_length(&wtop->wwlist) == 0) | |
58 | { | |
a4bf26dd | 59 | rb_radixtree_delete(whowas_tree, wtop->name); |
b47f8a4f AC |
60 | rb_free(wtop->name); |
61 | rb_free(wtop); | |
62 | } | |
63 | } | |
212380e3 | 64 | |
b47f8a4f AC |
65 | static struct whowas_top * |
66 | whowas_get_top(const char *name) | |
212380e3 | 67 | { |
b47f8a4f AC |
68 | struct whowas_top *wtop; |
69 | ||
a4bf26dd | 70 | wtop = rb_radixtree_retrieve(whowas_tree, name); |
b47f8a4f AC |
71 | if (wtop != NULL) |
72 | return wtop; | |
73 | ||
74 | wtop = rb_malloc(sizeof(struct whowas_top)); | |
75 | wtop->name = rb_strdup(name); | |
a4bf26dd | 76 | rb_radixtree_add(whowas_tree, wtop->name, wtop); |
b47f8a4f AC |
77 | |
78 | return wtop; | |
212380e3 AC |
79 | } |
80 | ||
b47f8a4f AC |
81 | rb_dlink_list * |
82 | whowas_get_list(const char *name) | |
212380e3 | 83 | { |
b47f8a4f | 84 | struct whowas_top *wtop; |
a4bf26dd | 85 | wtop = rb_radixtree_retrieve(whowas_tree, name); |
b47f8a4f AC |
86 | if(wtop == NULL) |
87 | return NULL; | |
88 | return &wtop->wwlist; | |
89 | } | |
212380e3 | 90 | |
b47f8a4f AC |
91 | void |
92 | whowas_add_history(struct Client *client_p, int online) | |
93 | { | |
94 | struct whowas_top *wtop; | |
95 | struct Whowas *who; | |
212380e3 AC |
96 | s_assert(NULL != client_p); |
97 | ||
98 | if(client_p == NULL) | |
99 | return; | |
100 | ||
b47f8a4f AC |
101 | /* trim some of the entries if we're getting well over our history length */ |
102 | if(rb_dlink_list_length(&whowas_list) > whowas_list_length + 100) | |
103 | whowas_trim(NULL); | |
104 | ||
105 | wtop = whowas_get_top(client_p->name); | |
106 | who = rb_malloc(sizeof(struct Whowas)); | |
107 | who->wtop = wtop; | |
e3354945 | 108 | who->logoff = rb_current_time(); |
b47f8a4f | 109 | |
f427c8b0 | 110 | rb_strlcpy(who->name, client_p->name, sizeof(who->name)); |
b47f8a4f AC |
111 | rb_strlcpy(who->username, client_p->username, sizeof(who->username)); |
112 | rb_strlcpy(who->hostname, client_p->host, sizeof(who->hostname)); | |
113 | rb_strlcpy(who->realname, client_p->info, sizeof(who->realname)); | |
114 | rb_strlcpy(who->sockhost, client_p->sockhost, sizeof(who->sockhost)); | |
115 | ||
364e59f8 JT |
116 | who->flags = (IsIPSpoof(client_p) ? WHOWAS_IP_SPOOFING : 0) | |
117 | (IsDynSpoof(client_p) ? WHOWAS_DYNSPOOF : 0); | |
212380e3 | 118 | |
b47f8a4f | 119 | /* this is safe do to with the servername cache */ |
994544c2 | 120 | who->servername = scache_get_name(client_p->servptr->serv->nameinfo); |
212380e3 AC |
121 | |
122 | if(online) | |
123 | { | |
124 | who->online = client_p; | |
b47f8a4f | 125 | rb_dlinkAdd(who, &who->cnode, &client_p->whowas_clist); |
212380e3 AC |
126 | } |
127 | else | |
128 | who->online = NULL; | |
b47f8a4f AC |
129 | |
130 | rb_dlinkAdd(who, &who->wnode, &wtop->wwlist); | |
131 | rb_dlinkAdd(who, &who->whowas_node, &whowas_list); | |
212380e3 AC |
132 | } |
133 | ||
b47f8a4f AC |
134 | |
135 | void | |
136 | whowas_off_history(struct Client *client_p) | |
212380e3 | 137 | { |
b47f8a4f | 138 | rb_dlink_node *ptr, *next; |
212380e3 | 139 | |
b47f8a4f | 140 | RB_DLINK_FOREACH_SAFE(ptr, next, client_p->whowas_clist.head) |
212380e3 | 141 | { |
b47f8a4f AC |
142 | struct Whowas *who = ptr->data; |
143 | who->online = NULL; | |
144 | rb_dlinkDelete(&who->cnode, &client_p->whowas_clist); | |
212380e3 AC |
145 | } |
146 | } | |
147 | ||
b47f8a4f AC |
148 | struct Client * |
149 | whowas_get_history(const char *nick, time_t timelimit) | |
212380e3 | 150 | { |
b47f8a4f AC |
151 | struct whowas_top *wtop; |
152 | rb_dlink_node *ptr; | |
153 | ||
a4bf26dd | 154 | wtop = rb_radixtree_retrieve(whowas_tree, nick); |
b47f8a4f AC |
155 | if(wtop == NULL) |
156 | return NULL; | |
212380e3 | 157 | |
e3354945 | 158 | timelimit = rb_current_time() - timelimit; |
b47f8a4f AC |
159 | |
160 | RB_DLINK_FOREACH_PREV(ptr, wtop->wwlist.tail) | |
212380e3 | 161 | { |
b47f8a4f AC |
162 | struct Whowas *who = ptr->data; |
163 | if(who->logoff >= timelimit) | |
164 | { | |
165 | return who->online; | |
166 | } | |
212380e3 | 167 | } |
b47f8a4f | 168 | |
212380e3 AC |
169 | return NULL; |
170 | } | |
171 | ||
b47f8a4f AC |
172 | static void |
173 | whowas_trim(void *unused) | |
212380e3 | 174 | { |
b47f8a4f | 175 | long over; |
212380e3 | 176 | |
b47f8a4f AC |
177 | if(rb_dlink_list_length(&whowas_list) < whowas_list_length) |
178 | return; | |
179 | over = rb_dlink_list_length(&whowas_list) - whowas_list_length; | |
212380e3 | 180 | |
b47f8a4f AC |
181 | /* remove whowas entries over the configured length */ |
182 | for(long i = 0; i < over; i++) | |
212380e3 | 183 | { |
b47f8a4f AC |
184 | if(whowas_list.tail != NULL && whowas_list.tail->data != NULL) |
185 | { | |
186 | struct Whowas *twho = whowas_list.tail->data; | |
187 | if(twho->online != NULL) | |
188 | rb_dlinkDelete(&twho->cnode, &twho->online->whowas_clist); | |
189 | rb_dlinkDelete(&twho->wnode, &twho->wtop->wwlist); | |
190 | rb_dlinkDelete(&twho->whowas_node, &whowas_list); | |
191 | whowas_free_wtop(twho->wtop); | |
192 | rb_free(twho); | |
193 | } | |
212380e3 | 194 | } |
212380e3 AC |
195 | } |
196 | ||
b47f8a4f AC |
197 | void |
198 | whowas_init(void) | |
212380e3 | 199 | { |
a4bf26dd | 200 | whowas_tree = rb_radixtree_create("whowas", irccasecanon); |
b47f8a4f AC |
201 | if(whowas_list_length == 0) |
202 | { | |
203 | whowas_list_length = NICKNAMEHISTORYLENGTH; | |
204 | } | |
205 | rb_event_add("whowas_trim", whowas_trim, NULL, 10); | |
212380e3 AC |
206 | } |
207 | ||
b47f8a4f AC |
208 | void |
209 | whowas_set_size(int len) | |
212380e3 | 210 | { |
b47f8a4f AC |
211 | whowas_list_length = len; |
212 | whowas_trim(NULL); | |
212380e3 AC |
213 | } |
214 | ||
b47f8a4f AC |
215 | void |
216 | whowas_memory_usage(size_t * count, size_t * memused) | |
212380e3 | 217 | { |
b47f8a4f AC |
218 | *count = rb_dlink_list_length(&whowas_list); |
219 | *memused += *count * sizeof(struct Whowas); | |
a4bf26dd | 220 | *memused += sizeof(struct whowas_top) * rb_radixtree_size(whowas_tree); |
212380e3 | 221 | } |