]> git.ipfire.org Git - thirdparty/squid.git/blame - src/client_db.cc
Fix diskd debugging to print the correct unlink function name, either
[thirdparty/squid.git] / src / client_db.cc
CommitLineData
8eb58c9c 1
516350ca 2/*
6a702e8d 3 * $Id: client_db.cc,v 1.64 2005/09/03 10:05:46 serassio Exp $
516350ca 4 *
f43e2ec2 5 * DEBUG: section 0 Client Database
516350ca 6 * AUTHOR: Duane Wessels
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 9 * ----------------------------------------------------------
516350ca 10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
516350ca 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 33 *
516350ca 34 */
35
c41d4b6d 36#include "squid.h"
e6ccf245 37#include "Store.h"
38
c41d4b6d 39
365e5b34 40static hash_table *client_table = NULL;
62e76326 41
ddfcbc22 42static ClientInfo *clientdbAdd(struct IN_ADDR addr);
ec878047 43static FREE clientdbFreeItem;
a0eba6bc 44static void clientdbStartGC(void);
45static void clientdbScheduledGC(void *);
46
47static int max_clients = 32;
48static int cleanup_running = 0;
49static int cleanup_scheduled = 0;
50static int cleanup_removed;
51
52#define CLIENT_DB_HASH_SIZE 467
c41d4b6d 53
54static ClientInfo *
62e76326 55
ddfcbc22 56clientdbAdd(struct IN_ADDR addr)
c41d4b6d 57{
58 ClientInfo *c;
e6ccf245 59 c = (ClientInfo *)memAllocate(MEM_CLIENT_INFO);
186477c1 60 c->hash.key = xstrdup(inet_ntoa(addr));
c41d4b6d 61 c->addr = addr;
186477c1 62 hash_join(client_table, &c->hash);
83704487 63 statCounter.client_http.clients++;
a0eba6bc 64
85ca7218 65 if ((statCounter.client_http.clients > max_clients) && !cleanup_running && cleanup_scheduled < 2)
a0eba6bc 66 {
67 cleanup_scheduled++;
68 eventAdd("client_db garbage collector", clientdbScheduledGC, NULL, 90, 0);
69 }
70
c41d4b6d 71 return c;
72}
73
74void
75clientdbInit(void)
76{
19054954 77 if (client_table)
62e76326 78 return;
79
a0eba6bc 80 client_table = hash_create((HASHCMP *) strcmp, CLIENT_DB_HASH_SIZE, hash_string);
62e76326 81
22f3fd98 82 cachemgrRegister("client_list",
62e76326 83 "Cache Client List",
84 clientdbDump,
85 0, 1);
c41d4b6d 86}
87
88void
62e76326 89
ddfcbc22 90clientdbUpdate(struct IN_ADDR addr, log_type ltype, protocol_t p, size_t size)
c41d4b6d 91{
429fdbec 92 char *key;
93 ClientInfo *c;
62e76326 94
17a0a4ee 95 if (!Config.onoff.client_db)
62e76326 96 return;
97
429fdbec 98 key = inet_ntoa(addr);
62e76326 99
429fdbec 100 c = (ClientInfo *) hash_lookup(client_table, key);
62e76326 101
c41d4b6d 102 if (c == NULL)
62e76326 103 c = clientdbAdd(addr);
104
c41d4b6d 105 if (c == NULL)
62e76326 106 debug_trap("clientdbUpdate: Failed to add entry");
107
108 if (p == PROTO_HTTP)
109 {
110 c->Http.n_requests++;
111 c->Http.result_hist[ltype]++;
112 kb_incr(&c->Http.kbytes_out, size);
113
114 if (logTypeIsATcpHit(ltype))
115 kb_incr(&c->Http.hit_kbytes_out, size);
116 } else if (p == PROTO_ICP)
117 {
118 c->Icp.n_requests++;
119 c->Icp.result_hist[ltype]++;
120 kb_incr(&c->Icp.kbytes_out, size);
121
122 if (LOG_UDP_HIT == ltype)
123 kb_incr(&c->Icp.hit_kbytes_out, size);
81d0c856 124 }
a0eba6bc 125
126 c->last_seen = squid_curtime;
c41d4b6d 127}
128
9bc73deb 129/*
130 * clientdbEstablished()
131 * This function tracks the number of currently established connections
132 * for a client IP address. When a connection is accepted, call this
133 * with delta = 1. When the connection is closed, call with delta =
134 * -1. To get the current value, simply call with delta = 0.
135 */
136int
62e76326 137
ddfcbc22 138clientdbEstablished(struct IN_ADDR addr, int delta)
9bc73deb 139{
140 char *key;
141 ClientInfo *c;
62e76326 142
9bc73deb 143 if (!Config.onoff.client_db)
62e76326 144 return 0;
145
9bc73deb 146 key = inet_ntoa(addr);
62e76326 147
9bc73deb 148 c = (ClientInfo *) hash_lookup(client_table, key);
62e76326 149
9bc73deb 150 if (c == NULL)
62e76326 151 c = clientdbAdd(addr);
152
9bc73deb 153 if (c == NULL)
62e76326 154 debug_trap("clientdbUpdate: Failed to add entry");
155
9bc73deb 156 c->n_established += delta;
62e76326 157
9bc73deb 158 return c->n_established;
159}
160
e711a2ff 161#define CUTOFF_SECONDS 3600
c41d4b6d 162int
62e76326 163
ddfcbc22 164clientdbCutoffDenied(struct IN_ADDR addr)
c41d4b6d 165{
429fdbec 166 char *key;
e711a2ff 167 int NR;
168 int ND;
169 double p;
429fdbec 170 ClientInfo *c;
62e76326 171
59c4d35b 172 if (!Config.onoff.client_db)
62e76326 173 return 0;
174
429fdbec 175 key = inet_ntoa(addr);
62e76326 176
429fdbec 177 c = (ClientInfo *) hash_lookup(client_table, key);
62e76326 178
c41d4b6d 179 if (c == NULL)
62e76326 180 return 0;
181
e711a2ff 182 /*
183 * If we are in a cutoff window, we don't send a reply
184 */
185 if (squid_curtime - c->cutoff.time < CUTOFF_SECONDS)
62e76326 186 return 1;
187
e711a2ff 188 /*
189 * Calculate the percent of DENIED replies since the last
190 * cutoff time.
191 */
192 NR = c->Icp.n_requests - c->cutoff.n_req;
62e76326 193
e711a2ff 194 if (NR < 150)
62e76326 195 NR = 150;
196
e711a2ff 197 ND = c->Icp.result_hist[LOG_UDP_DENIED] - c->cutoff.n_denied;
62e76326 198
e711a2ff 199 p = 100.0 * ND / NR;
62e76326 200
e711a2ff 201 if (p < 95.0)
62e76326 202 return 0;
203
59c4d35b 204 debug(1, 0) ("WARNING: Probable misconfigured neighbor at %s\n", key);
62e76326 205
59c4d35b 206 debug(1, 0) ("WARNING: %d of the last %d ICP replies are DENIED\n", ND, NR);
62e76326 207
59c4d35b 208 debug(1, 0) ("WARNING: No replies will be sent for the next %d seconds\n",
62e76326 209 CUTOFF_SECONDS);
210
e711a2ff 211 c->cutoff.time = squid_curtime;
62e76326 212
e711a2ff 213 c->cutoff.n_req = c->Icp.n_requests;
62e76326 214
e711a2ff 215 c->cutoff.n_denied = c->Icp.result_hist[LOG_UDP_DENIED];
62e76326 216
e711a2ff 217 return 1;
c41d4b6d 218}
219
e6ccf245 220log_type &operator++ (log_type &aLogType)
221{
1f1ae50a 222 int tmp = (int)aLogType;
223 aLogType = (log_type)(++tmp);
e6ccf245 224 return aLogType;
225}
226
e711a2ff 227
8eb58c9c 228void
c41d4b6d 229clientdbDump(StoreEntry * sentry)
230{
231 ClientInfo *c;
232 log_type l;
ac0963ac 233 int icp_total = 0;
234 int icp_hits = 0;
235 int http_total = 0;
236 int http_hits = 0;
15576b6a 237 storeAppendPrintf(sentry, "Cache Clients:\n");
0f6bebac 238 hash_first(client_table);
62e76326 239
0f6bebac 240 while ((c = (ClientInfo *) hash_next(client_table))) {
62e76326 241 storeAppendPrintf(sentry, "Address: %s\n", hashKeyStr(&c->hash));
242 storeAppendPrintf(sentry, "Name: %s\n", fqdnFromAddr(c->addr));
243 storeAppendPrintf(sentry, "Currently established connections: %d\n",
244 c->n_established);
245 storeAppendPrintf(sentry, " ICP Requests %d\n",
246 c->Icp.n_requests);
247
248 for (l = LOG_TAG_NONE; l < LOG_TYPE_MAX; ++l) {
249 if (c->Icp.result_hist[l] == 0)
250 continue;
251
252 icp_total += c->Icp.result_hist[l];
253
254 if (LOG_UDP_HIT == l)
255 icp_hits += c->Icp.result_hist[l];
256
257 storeAppendPrintf(sentry,
258 " %-20.20s %7d %3d%%\n",
259 log_tags[l],
260 c->Icp.result_hist[l],
261 percent(c->Icp.result_hist[l], c->Icp.n_requests));
262 }
263
264 storeAppendPrintf(sentry, " HTTP Requests %d\n",
265 c->Http.n_requests);
266
267 for (l = LOG_TAG_NONE; l < LOG_TYPE_MAX; ++l) {
268 if (c->Http.result_hist[l] == 0)
269 continue;
270
271 http_total += c->Http.result_hist[l];
272
273 if (logTypeIsATcpHit(l))
274 http_hits += c->Http.result_hist[l];
275
276 storeAppendPrintf(sentry,
277 " %-20.20s %7d %3d%%\n",
278 log_tags[l],
279 c->Http.result_hist[l],
280 percent(c->Http.result_hist[l], c->Http.n_requests));
281 }
282
283 storeAppendPrintf(sentry, "\n");
c41d4b6d 284 }
62e76326 285
ac0963ac 286 storeAppendPrintf(sentry, "TOTALS\n");
287 storeAppendPrintf(sentry, "ICP : %d Queries, %d Hits (%3d%%)\n",
62e76326 288 icp_total, icp_hits, percent(icp_hits, icp_total));
ac0963ac 289 storeAppendPrintf(sentry, "HTTP: %d Requests, %d Hits (%3d%%)\n",
62e76326 290 http_total, http_hits, percent(http_hits, http_total));
c41d4b6d 291}
83394596 292
ec878047 293static void
294clientdbFreeItem(void *data)
295{
e6ccf245 296 ClientInfo *c = (ClientInfo *)data;
186477c1 297 safe_free(c->hash.key);
db1cd23c 298 memFree(c, MEM_CLIENT_INFO);
ec878047 299}
300
83394596 301void
302clientdbFreeMemory(void)
303{
ec878047 304 hashFreeItems(client_table, clientdbFreeItem);
83394596 305 hashFreeMemory(client_table);
306 client_table = NULL;
307}
81d0c856 308
a0eba6bc 309static void
310clientdbScheduledGC(void *unused)
311{
312 cleanup_scheduled = 0;
313 clientdbStartGC();
314}
315
316static void
317clientdbGC(void *unused)
318{
319 static int bucket = 0;
320 hash_link *link_next;
321
322 link_next = hash_get_bucket(client_table, bucket++);
323
324 while (link_next != NULL) {
325 ClientInfo *c = (ClientInfo *)link_next;
326 int age = squid_curtime - c->last_seen;
327 link_next = link_next->next;
328
329 if (c->n_established)
330 continue;
331
332 if (age < 24 * 3600 && c->Http.n_requests > 100)
333 continue;
334
335 if (age < 4 * 3600 && (c->Http.n_requests > 10 || c->Icp.n_requests > 10))
336 continue;
337
338 if (age < 5 * 60 && (c->Http.n_requests > 1 || c->Icp.n_requests > 1))
339 continue;
340
341 if (age < 60)
342 continue;
343
344 hash_remove_link(client_table, &c->hash);
345
346 clientdbFreeItem(c);
347
348 statCounter.client_http.clients--;
349
350 cleanup_removed++;
351 }
352
353 if (bucket < CLIENT_DB_HASH_SIZE)
354 eventAdd("client_db garbage collector", clientdbGC, NULL, 0.15, 0);
355 else {
356 bucket = 0;
357 cleanup_running = 0;
358 max_clients = statCounter.client_http.clients * 3 / 2;
359
360 if (!cleanup_scheduled) {
361 cleanup_scheduled = 1;
362 eventAdd("client_db garbage collector", clientdbScheduledGC, NULL, 6 * 3600, 0);
363 }
364
365 debug(49, 2) ("clientdbGC: Removed %d entries\n", cleanup_removed);
366 }
367}
368
369static void
370clientdbStartGC(void)
371{
372 max_clients = statCounter.client_http.clients;
373 cleanup_running = 1;
374 cleanup_removed = 0;
375 clientdbGC(NULL);
376}
377
81d0c856 378#if SQUID_SNMP
62e76326 379
ddfcbc22 380struct IN_ADDR *
62e76326 381
ddfcbc22 382 client_entry(struct IN_ADDR *current)
81d0c856 383{
6f47fbc7 384 ClientInfo *c = NULL;
b6a2f15e 385 char *key;
62e76326 386
387 if (current)
388 {
389 key = inet_ntoa(*current);
390 hash_first(client_table);
391
392 while ((c = (ClientInfo *) hash_next(client_table))) {
393 if (!strcmp(key, hashKeyStr(&c->hash)))
394 break;
395 }
396
397 c = (ClientInfo *) hash_next(client_table);
398 } else
399 {
400 hash_first(client_table);
401 c = (ClientInfo *) hash_next(client_table);
6f47fbc7 402 }
62e76326 403
b6a2f15e 404 hash_last(client_table);
62e76326 405
b6a2f15e 406 if (c)
62e76326 407 return (&c->addr);
b6a2f15e 408 else
62e76326 409 return (NULL);
81d0c856 410
b6a2f15e 411}
81d0c856 412
413variable_list *
6f47fbc7 414snmp_meshCtblFn(variable_list * Var, snint * ErrP)
81d0c856 415{
736eb6ad 416 variable_list *Answer = NULL;
6a702e8d 417 static char key[16];
81d0c856 418 ClientInfo *c = NULL;
6f47fbc7 419 int aggr = 0;
cc4621e5 420 log_type l;
81d0c856 421 *ErrP = SNMP_ERR_NOERROR;
b6a2f15e 422 debug(49, 6) ("snmp_meshCtblFn: Current : \n");
423 snmpDebugOid(6, Var->name, Var->name_length);
1388e4a7 424 snprintf(key, sizeof(key), "%d.%d.%d.%d", Var->name[LEN_SQ_NET + 3], Var->name[LEN_SQ_NET + 4],
62e76326 425 Var->name[LEN_SQ_NET + 5], Var->name[LEN_SQ_NET + 6]);
81d0c856 426 debug(49, 5) ("snmp_meshCtblFn: [%s] requested!\n", key);
427 c = (ClientInfo *) hash_lookup(client_table, key);
62e76326 428
81d0c856 429 if (c == NULL) {
62e76326 430 debug(49, 5) ("snmp_meshCtblFn: not found.\n");
431 *ErrP = SNMP_ERR_NOSUCHNAME;
432 return NULL;
81d0c856 433 }
62e76326 434
135171fe 435 switch (Var->name[LEN_SQ_NET + 2]) {
62e76326 436
81d0c856 437 case MESH_CTBL_ADDR:
62e76326 438 Answer = snmp_var_new_integer(Var->name, Var->name_length,
439 (snint) c->addr.s_addr,
440 SMI_IPADDRESS);
441 break;
442
81d0c856 443 case MESH_CTBL_HTBYTES:
62e76326 444 Answer = snmp_var_new_integer(Var->name, Var->name_length,
445 (snint) c->Http.kbytes_out.kb,
446 SMI_COUNTER32);
447 break;
448
81d0c856 449 case MESH_CTBL_HTREQ:
62e76326 450 Answer = snmp_var_new_integer(Var->name, Var->name_length,
451 (snint) c->Http.n_requests,
452 SMI_COUNTER32);
453 break;
454
81d0c856 455 case MESH_CTBL_HTHITS:
62e76326 456 aggr = 0;
457
458 for (l = LOG_TAG_NONE; l < LOG_TYPE_MAX; ++l) {
459 if (logTypeIsATcpHit(l))
460 aggr += c->Http.result_hist[l];
461 }
462
463 Answer = snmp_var_new_integer(Var->name, Var->name_length,
464 (snint) aggr,
465 SMI_COUNTER32);
466 break;
467
81d0c856 468 case MESH_CTBL_HTHITBYTES:
62e76326 469 Answer = snmp_var_new_integer(Var->name, Var->name_length,
470 (snint) c->Http.hit_kbytes_out.kb,
471 SMI_COUNTER32);
472 break;
473
81d0c856 474 case MESH_CTBL_ICPBYTES:
62e76326 475 Answer = snmp_var_new_integer(Var->name, Var->name_length,
476 (snint) c->Icp.kbytes_out.kb,
477 SMI_COUNTER32);
478 break;
479
81d0c856 480 case MESH_CTBL_ICPREQ:
62e76326 481 Answer = snmp_var_new_integer(Var->name, Var->name_length,
482 (snint) c->Icp.n_requests,
483 SMI_COUNTER32);
484 break;
485
81d0c856 486 case MESH_CTBL_ICPHITS:
62e76326 487 aggr = c->Icp.result_hist[LOG_UDP_HIT];
488 Answer = snmp_var_new_integer(Var->name, Var->name_length,
489 (snint) aggr,
490 SMI_COUNTER32);
491 break;
492
81d0c856 493 case MESH_CTBL_ICPHITBYTES:
62e76326 494 Answer = snmp_var_new_integer(Var->name, Var->name_length,
495 (snint) c->Icp.hit_kbytes_out.kb,
496 SMI_COUNTER32);
497 break;
498
81d0c856 499 default:
62e76326 500 *ErrP = SNMP_ERR_NOSUCHNAME;
501 debug(49, 5) ("snmp_meshCtblFn: illegal column.\n");
502 break;
81d0c856 503 }
62e76326 504
81d0c856 505 return Answer;
506}
507
135171fe 508#endif /*SQUID_SNMP */