]>
Commit | Line | Data |
---|---|---|
87801fcb | 1 | |
516350ca | 2 | /* |
4a56ee8d | 3 | * $Id: net_db.cc,v 1.181 2006/01/23 20:04:24 wessels Exp $ |
516350ca | 4 | * |
67f46679 | 5 | * DEBUG: section 38 Network Measurement 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 | ||
add2192d | 36 | /* |
37 | * XXX XXX XXX | |
38 | * | |
39 | * This code may be slightly broken now. If you're getting consistent | |
40 | * (sometimes working) corrupt data exchanges, please contact adrian | |
41 | * (adrian@squid-cache.org) to sort them out. | |
42 | */ | |
43 | ||
87801fcb | 44 | #include "squid.h" |
e6ccf245 | 45 | #include "Store.h" |
53525d53 | 46 | #include "SwapDir.h" |
528b2c61 | 47 | #include "HttpRequest.h" |
48 | #include "HttpReply.h" | |
49 | #include "MemObject.h" | |
50 | #include "fde.h" | |
21ea7560 | 51 | #include "forward.h" |
87801fcb | 52 | |
a97cfa48 | 53 | #if USE_ICMP |
4b725156 | 54 | #include "StoreClient.h" |
55 | ||
add2192d | 56 | #define NETDB_REQBUF_SZ 4096 |
57 | ||
58 | typedef enum { | |
fa80a8ef | 59 | STATE_NONE, |
60 | STATE_HEADER, | |
61 | STATE_BODY | |
add2192d | 62 | } netdb_conn_state_t; |
8b833697 | 63 | |
62e76326 | 64 | typedef struct |
65 | { | |
a74c5601 | 66 | peer *p; |
67 | StoreEntry *e; | |
06d2839d | 68 | store_client *sc; |
190154cf | 69 | HttpRequest *r; |
a74c5601 | 70 | off_t used; |
71 | size_t buf_sz; | |
add2192d | 72 | char buf[NETDB_REQBUF_SZ]; |
73 | int buf_ofs; | |
74 | netdb_conn_state_t connstate; | |
62e76326 | 75 | } |
76 | ||
77 | netdbExchangeState; | |
9ad1cbca | 78 | |
ce75f381 | 79 | static hash_table *addr_table = NULL; |
365e5b34 | 80 | static hash_table *host_table = NULL; |
87801fcb | 81 | |
ddfcbc22 | 82 | static struct IN_ADDR networkFromInaddr(struct IN_ADDR a); |
f5b8bbc4 | 83 | static void netdbRelease(netdbEntry * n); |
62e76326 | 84 | |
ddfcbc22 | 85 | static void netdbHashInsert(netdbEntry * n, struct IN_ADDR addr); |
f5b8bbc4 | 86 | static void netdbHashDelete(const char *key); |
587d8445 | 87 | static void netdbHostInsert(netdbEntry * n, const char *hostname); |
88 | static void netdbHostDelete(const net_db_name * x); | |
f5b8bbc4 | 89 | static void netdbPurgeLRU(void); |
23d92c64 | 90 | static netdbEntry *netdbLookupHost(const char *key); |
f5b8bbc4 | 91 | static net_db_peer *netdbPeerByName(const netdbEntry * n, const char *); |
92 | static net_db_peer *netdbPeerAdd(netdbEntry * n, peer * e); | |
858783c9 | 93 | static const char *netdbPeerName(const char *name); |
b69f7771 | 94 | static IPH netdbSendPing; |
79d39a72 | 95 | static QS sortPeerByRtt; |
96 | static QS sortByRtt; | |
97 | static QS netdbLRU; | |
ec878047 | 98 | static FREE netdbFreeNameEntry; |
99 | static FREE netdbFreeNetdbEntry; | |
9ad1cbca | 100 | static STCB netdbExchangeHandleReply; |
45c54bdc | 101 | static void netdbExchangeDone(void *); |
429fdbec | 102 | |
103 | /* We have to keep a local list of peer names. The Peers structure | |
104 | * gets freed during a reconfigure. We want this database to | |
105 | * remain persisitent, so _net_db_peer->peername points into this | |
106 | * linked list */ | |
107 | static wordlist *peer_names = NULL; | |
67508012 | 108 | |
87801fcb | 109 | static void |
62e76326 | 110 | |
ddfcbc22 | 111 | netdbHashInsert(netdbEntry * n, struct IN_ADDR addr) |
87801fcb | 112 | { |
f2052513 | 113 | xstrncpy(n->network, inet_ntoa(networkFromInaddr(addr)), 16); |
186477c1 | 114 | n->hash.key = n->network; |
587d8445 | 115 | assert(hash_lookup(addr_table, n->network) == NULL); |
186477c1 | 116 | hash_join(addr_table, &n->hash); |
87801fcb | 117 | } |
118 | ||
119 | static void | |
0ee4272b | 120 | netdbHashDelete(const char *key) |
87801fcb | 121 | { |
e6ccf245 | 122 | hash_link *hptr = (hash_link *)hash_lookup(addr_table, key); |
62e76326 | 123 | |
87801fcb | 124 | if (hptr == NULL) { |
62e76326 | 125 | debug_trap("netdbHashDelete: key not found"); |
126 | return; | |
87801fcb | 127 | } |
62e76326 | 128 | |
e0b1c6aa | 129 | hash_remove_link(addr_table, hptr); |
67508012 | 130 | } |
131 | ||
132 | static void | |
587d8445 | 133 | netdbHostInsert(netdbEntry * n, const char *hostname) |
67508012 | 134 | { |
e6ccf245 | 135 | net_db_name *x = (net_db_name *)memAllocate(MEM_NET_DB_NAME); |
186477c1 | 136 | x->hash.key = xstrdup(hostname); |
67508012 | 137 | x->next = n->hosts; |
138 | n->hosts = x; | |
587d8445 | 139 | x->net_db_entry = n; |
140 | assert(hash_lookup(host_table, hostname) == NULL); | |
186477c1 | 141 | hash_join(host_table, &x->hash); |
67508012 | 142 | n->link_count++; |
143 | } | |
144 | ||
145 | static void | |
587d8445 | 146 | netdbHostDelete(const net_db_name * x) |
67508012 | 147 | { |
148 | netdbEntry *n; | |
b19361fd | 149 | net_db_name **X; |
b19361fd | 150 | assert(x != NULL); |
587d8445 | 151 | assert(x->net_db_entry != NULL); |
152 | n = x->net_db_entry; | |
b19361fd | 153 | n->link_count--; |
62e76326 | 154 | |
587d8445 | 155 | for (X = &n->hosts; *X; X = &(*X)->next) { |
62e76326 | 156 | if (*X == x) { |
157 | *X = x->next; | |
158 | break; | |
159 | } | |
587d8445 | 160 | } |
62e76326 | 161 | |
587d8445 | 162 | hash_remove_link(host_table, (hash_link *) x); |
186477c1 | 163 | xfree(x->hash.key); |
db1cd23c | 164 | memFree((void *) x, MEM_NET_DB_NAME); |
87801fcb | 165 | } |
166 | ||
167 | static netdbEntry * | |
0ee4272b | 168 | netdbLookupHost(const char *key) |
87801fcb | 169 | { |
587d8445 | 170 | net_db_name *x = (net_db_name *) hash_lookup(host_table, key); |
171 | return x ? x->net_db_entry : NULL; | |
87801fcb | 172 | } |
173 | ||
c907000b | 174 | static void |
175 | netdbRelease(netdbEntry * n) | |
176 | { | |
429fdbec | 177 | net_db_name *x; |
587d8445 | 178 | net_db_name *next; |
62e76326 | 179 | |
c907000b | 180 | for (x = n->hosts; x; x = next) { |
62e76326 | 181 | next = x->next; |
182 | netdbHostDelete(x); | |
c907000b | 183 | } |
62e76326 | 184 | |
c907000b | 185 | n->hosts = NULL; |
429fdbec | 186 | safe_free(n->peers); |
429fdbec | 187 | n->peers = NULL; |
188 | n->n_peers = 0; | |
189 | n->n_peers_alloc = 0; | |
62e76326 | 190 | |
c907000b | 191 | if (n->link_count == 0) { |
62e76326 | 192 | netdbHashDelete(n->network); |
193 | memFree(n, MEM_NETDBENTRY); | |
c907000b | 194 | } |
195 | } | |
196 | ||
197 | static int | |
79d39a72 | 198 | netdbLRU(const void *A, const void *B) |
c907000b | 199 | { |
e6ccf245 | 200 | const netdbEntry *const *n1 = (const netdbEntry *const *)A; |
201 | const netdbEntry *const *n2 = (const netdbEntry *const *)B; | |
62e76326 | 202 | |
c907000b | 203 | if ((*n1)->last_use_time > (*n2)->last_use_time) |
62e76326 | 204 | return (1); |
205 | ||
c907000b | 206 | if ((*n1)->last_use_time < (*n2)->last_use_time) |
62e76326 | 207 | return (-1); |
208 | ||
c907000b | 209 | return (0); |
210 | } | |
211 | ||
c907000b | 212 | static void |
213 | netdbPurgeLRU(void) | |
214 | { | |
215 | netdbEntry *n; | |
216 | netdbEntry **list; | |
217 | int k = 0; | |
218 | int list_count = 0; | |
219 | int removed = 0; | |
e6ccf245 | 220 | list = (netdbEntry **)xcalloc(memInUse(MEM_NETDBENTRY), sizeof(netdbEntry *)); |
0f6bebac | 221 | hash_first(addr_table); |
62e76326 | 222 | |
0f6bebac | 223 | while ((n = (netdbEntry *) hash_next(addr_table))) { |
62e76326 | 224 | assert(list_count < memInUse(MEM_NETDBENTRY)); |
225 | *(list + list_count) = n; | |
226 | list_count++; | |
c907000b | 227 | } |
62e76326 | 228 | |
c907000b | 229 | qsort((char *) list, |
62e76326 | 230 | list_count, |
231 | sizeof(netdbEntry *), | |
232 | netdbLRU); | |
233 | ||
c907000b | 234 | for (k = 0; k < list_count; k++) { |
62e76326 | 235 | if (memInUse(MEM_NETDBENTRY) < Config.Netdb.low) |
236 | break; | |
237 | ||
238 | netdbRelease(*(list + k)); | |
239 | ||
240 | removed++; | |
c907000b | 241 | } |
62e76326 | 242 | |
c907000b | 243 | xfree(list); |
244 | } | |
245 | ||
67508012 | 246 | static netdbEntry * |
62e76326 | 247 | |
ddfcbc22 | 248 | netdbLookupAddr(struct IN_ADDR addr) |
87801fcb | 249 | { |
587d8445 | 250 | netdbEntry *n; |
67508012 | 251 | char *key = inet_ntoa(networkFromInaddr(addr)); |
587d8445 | 252 | n = (netdbEntry *) hash_lookup(addr_table, key); |
253 | return n; | |
87801fcb | 254 | } |
255 | ||
67508012 | 256 | static netdbEntry * |
62e76326 | 257 | |
ddfcbc22 | 258 | netdbAdd(struct IN_ADDR addr) |
87801fcb | 259 | { |
260 | netdbEntry *n; | |
62e76326 | 261 | |
587d8445 | 262 | if (memInUse(MEM_NETDBENTRY) > Config.Netdb.high) |
62e76326 | 263 | netdbPurgeLRU(); |
264 | ||
265 | if ((n = netdbLookupAddr(addr)) == NULL) | |
266 | { | |
267 | n = (netdbEntry *)memAllocate(MEM_NETDBENTRY); | |
268 | netdbHashInsert(n, addr); | |
87801fcb | 269 | } |
62e76326 | 270 | |
67508012 | 271 | return n; |
87801fcb | 272 | } |
273 | ||
274 | static void | |
82691c78 | 275 | netdbSendPing(const ipcache_addrs * ia, void *data) |
87801fcb | 276 | { |
62e76326 | 277 | |
ddfcbc22 | 278 | struct IN_ADDR addr; |
e6ccf245 | 279 | char *hostname = (char *)((generic_cbdata *) data)->data; |
87801fcb | 280 | netdbEntry *n; |
b19361fd | 281 | netdbEntry *na; |
587d8445 | 282 | net_db_name *x; |
283 | net_db_name **X; | |
28c60158 | 284 | cbdataFree(data); |
62e76326 | 285 | |
e5f6c5c2 | 286 | if (ia == NULL) { |
62e76326 | 287 | xfree(hostname); |
288 | return; | |
cb190ed7 | 289 | } |
62e76326 | 290 | |
e5f6c5c2 | 291 | addr = ia->in_addrs[ia->cur]; |
62e76326 | 292 | |
b19361fd | 293 | if ((n = netdbLookupHost(hostname)) == NULL) { |
62e76326 | 294 | n = netdbAdd(addr); |
295 | netdbHostInsert(n, hostname); | |
b19361fd | 296 | } else if ((na = netdbLookupAddr(addr)) != n) { |
62e76326 | 297 | /* |
298 | *hostname moved from 'network n' to 'network na'! | |
299 | */ | |
300 | ||
301 | if (na == NULL) | |
302 | na = netdbAdd(addr); | |
303 | ||
304 | debug(38, 3) ("netdbSendPing: %s moved from %s to %s\n", | |
305 | hostname, n->network, na->network); | |
306 | ||
307 | x = (net_db_name *) hash_lookup(host_table, hostname); | |
308 | ||
309 | if (x == NULL) { | |
310 | debug(38, 1) ("netdbSendPing: net_db_name list bug: %s not found", hostname); | |
311 | xfree(hostname); | |
312 | return; | |
313 | } | |
314 | ||
315 | /* remove net_db_name from 'network n' linked list */ | |
316 | for (X = &n->hosts; *X; X = &(*X)->next) { | |
317 | if (*X == x) { | |
318 | *X = x->next; | |
319 | break; | |
320 | } | |
321 | } | |
322 | ||
323 | n->link_count--; | |
324 | /* point to 'network na' from host entry */ | |
325 | x->net_db_entry = na; | |
326 | /* link net_db_name to 'network na' */ | |
327 | x->next = na->hosts; | |
328 | na->hosts = x; | |
329 | na->link_count++; | |
330 | n = na; | |
b19361fd | 331 | } |
62e76326 | 332 | |
674ac814 | 333 | if (n->next_ping_time <= squid_curtime) { |
62e76326 | 334 | debug(38, 3) ("netdbSendPing: pinging %s\n", hostname); |
335 | icmpDomainPing(addr, hostname); | |
336 | n->pings_sent++; | |
337 | n->next_ping_time = squid_curtime + Config.Netdb.period; | |
338 | n->last_use_time = squid_curtime; | |
674ac814 | 339 | } |
62e76326 | 340 | |
28c60158 | 341 | xfree(hostname); |
67508012 | 342 | } |
343 | ||
ddfcbc22 | 344 | static struct IN_ADDR |
62e76326 | 345 | |
ddfcbc22 | 346 | networkFromInaddr(struct IN_ADDR a) |
67508012 | 347 | { |
62e76326 | 348 | |
ddfcbc22 | 349 | struct IN_ADDR b; |
a9778d11 | 350 | b.s_addr = ntohl(a.s_addr); |
429fdbec | 351 | #if USE_CLASSFUL |
62e76326 | 352 | |
67508012 | 353 | if (IN_CLASSC(b.s_addr)) |
62e76326 | 354 | b.s_addr &= IN_CLASSC_NET; |
67508012 | 355 | else if (IN_CLASSB(b.s_addr)) |
62e76326 | 356 | b.s_addr &= IN_CLASSB_NET; |
67508012 | 357 | else if (IN_CLASSA(b.s_addr)) |
62e76326 | 358 | b.s_addr &= IN_CLASSA_NET; |
359 | ||
429fdbec | 360 | #else |
361 | /* use /24 for everything */ | |
362 | b.s_addr &= IN_CLASSC_NET; | |
62e76326 | 363 | |
429fdbec | 364 | #endif |
62e76326 | 365 | |
a9778d11 | 366 | b.s_addr = htonl(b.s_addr); |
62e76326 | 367 | |
67508012 | 368 | return b; |
369 | } | |
370 | ||
371 | static int | |
79d39a72 | 372 | sortByRtt(const void *A, const void *B) |
67508012 | 373 | { |
e6ccf245 | 374 | const netdbEntry *const *n1 = (const netdbEntry *const *)A; |
375 | const netdbEntry *const *n2 = (const netdbEntry *const *)B; | |
62e76326 | 376 | |
429fdbec | 377 | if ((*n1)->rtt > (*n2)->rtt) |
62e76326 | 378 | return 1; |
429fdbec | 379 | else if ((*n1)->rtt < (*n2)->rtt) |
62e76326 | 380 | return -1; |
67508012 | 381 | else |
62e76326 | 382 | return 0; |
67508012 | 383 | } |
384 | ||
429fdbec | 385 | static net_db_peer * |
386 | netdbPeerByName(const netdbEntry * n, const char *peername) | |
387 | { | |
388 | int i; | |
389 | net_db_peer *p = n->peers; | |
62e76326 | 390 | |
429fdbec | 391 | for (i = 0; i < n->n_peers; i++, p++) { |
62e76326 | 392 | if (!strcmp(p->peername, peername)) |
393 | return p; | |
429fdbec | 394 | } |
62e76326 | 395 | |
429fdbec | 396 | return NULL; |
397 | } | |
398 | ||
399 | static net_db_peer * | |
400 | netdbPeerAdd(netdbEntry * n, peer * e) | |
401 | { | |
402 | net_db_peer *p; | |
403 | net_db_peer *o; | |
404 | int osize; | |
405 | int i; | |
62e76326 | 406 | |
429fdbec | 407 | if (n->n_peers == n->n_peers_alloc) { |
62e76326 | 408 | o = n->peers; |
409 | osize = n->n_peers_alloc; | |
410 | ||
411 | if (n->n_peers_alloc == 0) | |
412 | n->n_peers_alloc = 2; | |
413 | else | |
414 | n->n_peers_alloc <<= 1; | |
415 | ||
416 | debug(38, 3) ("netdbPeerAdd: Growing peer list for '%s' to %d\n", | |
417 | n->network, n->n_peers_alloc); | |
418 | ||
419 | n->peers = (net_db_peer *)xcalloc(n->n_peers_alloc, sizeof(net_db_peer)); | |
420 | ||
421 | for (i = 0; i < osize; i++) | |
422 | *(n->peers + i) = *(o + i); | |
423 | ||
424 | if (osize) { | |
425 | safe_free(o); | |
426 | } | |
429fdbec | 427 | } |
62e76326 | 428 | |
429fdbec | 429 | p = n->peers + n->n_peers; |
430 | p->peername = netdbPeerName(e->host); | |
431 | n->n_peers++; | |
432 | return p; | |
433 | } | |
434 | ||
435 | static int | |
79d39a72 | 436 | sortPeerByRtt(const void *A, const void *B) |
429fdbec | 437 | { |
e6ccf245 | 438 | const net_db_peer *p1 = (net_db_peer *)A; |
439 | const net_db_peer *p2 = (net_db_peer *)B; | |
62e76326 | 440 | |
429fdbec | 441 | if (p1->rtt > p2->rtt) |
62e76326 | 442 | return 1; |
429fdbec | 443 | else if (p1->rtt < p2->rtt) |
62e76326 | 444 | return -1; |
429fdbec | 445 | else |
62e76326 | 446 | return 0; |
429fdbec | 447 | } |
448 | ||
c8f4eac4 | 449 | static void |
450 | netdbPath(char *path) | |
451 | { | |
452 | /* this is completely wrong. the netdb location should be memoised | |
453 | * separately from the cache dirs, and also be settable in | |
454 | * squid.conf RBC 20041225 | |
455 | */ | |
53525d53 | 456 | snprintf(path, SQUID_MAXPATHLEN, "%s/netdb_state", dynamic_cast<SwapDir *>(Config.cacheSwap.swapDirs[0].getRaw())->path); |
c8f4eac4 | 457 | } |
458 | ||
429fdbec | 459 | static void |
460 | netdbSaveState(void *foo) | |
461 | { | |
462 | LOCAL_ARRAY(char, path, SQUID_MAXPATHLEN); | |
08e8e020 | 463 | Logfile *lf; |
429fdbec | 464 | netdbEntry *n; |
429fdbec | 465 | net_db_name *x; |
62e76326 | 466 | |
429fdbec | 467 | struct timeval start = current_time; |
468 | int count = 0; | |
c8f4eac4 | 469 | netdbPath(path); |
111b16cf | 470 | /* |
471 | * This was nicer when we were using stdio, but thanks to | |
472 | * Solaris bugs, its a bad idea. fopen can fail if more than | |
473 | * 256 FDs are open. | |
474 | */ | |
e3732f4f | 475 | /* |
476 | * unlink() is here because there is currently no way to make | |
477 | * logfileOpen() use O_TRUNC. | |
478 | */ | |
479 | unlink(path); | |
08e8e020 | 480 | lf = logfileOpen(path, 4096, 0); |
62e76326 | 481 | |
08e8e020 | 482 | if (NULL == lf) { |
62e76326 | 483 | debug(50, 1) ("netdbSaveState: %s: %s\n", path, xstrerror()); |
484 | return; | |
429fdbec | 485 | } |
62e76326 | 486 | |
0f6bebac | 487 | hash_first(addr_table); |
62e76326 | 488 | |
0f6bebac | 489 | while ((n = (netdbEntry *) hash_next(addr_table))) { |
62e76326 | 490 | if (n->pings_recv == 0) |
491 | continue; | |
492 | ||
493 | logfilePrintf(lf, "%s %d %d %10.5f %10.5f %d %d", | |
494 | n->network, | |
495 | n->pings_sent, | |
496 | n->pings_recv, | |
497 | n->hops, | |
498 | n->rtt, | |
499 | (int) n->next_ping_time, | |
500 | (int) n->last_use_time); | |
501 | ||
502 | for (x = n->hosts; x; x = x->next) | |
503 | logfilePrintf(lf, " %s", hashKeyStr(&x->hash)); | |
504 | ||
505 | logfilePrintf(lf, "\n"); | |
506 | ||
507 | count++; | |
508 | ||
111b16cf | 509 | #undef RBUF_SZ |
62e76326 | 510 | |
429fdbec | 511 | } |
62e76326 | 512 | |
08e8e020 | 513 | logfileClose(lf); |
587d8445 | 514 | getCurrentTime(); |
67f46679 | 515 | debug(38, 1) ("NETDB state saved; %d entries, %d msec\n", |
62e76326 | 516 | count, tvSubMsec(start, current_time)); |
52040193 | 517 | eventAddIsh("netdbSaveState", netdbSaveState, NULL, 3600.0, 1); |
429fdbec | 518 | } |
519 | ||
520 | static void | |
521 | netdbReloadState(void) | |
522 | { | |
523 | LOCAL_ARRAY(char, path, SQUID_MAXPATHLEN); | |
111b16cf | 524 | char *s; |
525 | int fd; | |
526 | int l; | |
62e76326 | 527 | |
111b16cf | 528 | struct stat sb; |
429fdbec | 529 | netdbEntry *n; |
530 | netdbEntry N; | |
62e76326 | 531 | |
ddfcbc22 | 532 | struct IN_ADDR addr; |
429fdbec | 533 | int count = 0; |
62e76326 | 534 | |
429fdbec | 535 | struct timeval start = current_time; |
c8f4eac4 | 536 | netdbPath(path); |
111b16cf | 537 | /* |
538 | * This was nicer when we were using stdio, but thanks to | |
539 | * Solaris bugs, its a bad idea. fopen can fail if more than | |
540 | * 256 FDs are open. | |
541 | */ | |
a50bfe93 | 542 | fd = file_open(path, O_RDONLY | O_BINARY); |
62e76326 | 543 | |
111b16cf | 544 | if (fd < 0) |
62e76326 | 545 | return; |
546 | ||
053ea9f4 | 547 | if (fstat(fd, &sb) < 0) { |
62e76326 | 548 | file_close(fd); |
549 | return; | |
053ea9f4 | 550 | } |
62e76326 | 551 | |
e0bbe966 | 552 | char *t; |
553 | char *buf = (char *)xcalloc(1, sb.st_size + 1); | |
554 | t = buf; | |
d0ef8ea8 | 555 | l = FD_READ_METHOD(fd, buf, sb.st_size); |
111b16cf | 556 | file_close(fd); |
62e76326 | 557 | |
e0bbe966 | 558 | if (l <= 0) { |
62e76326 | 559 | safe_free (buf); |
560 | return; | |
e0bbe966 | 561 | }; |
62e76326 | 562 | |
111b16cf | 563 | while ((s = strchr(t, '\n'))) { |
62e76326 | 564 | char *q; |
565 | assert(s - buf < l); | |
566 | *s = '\0'; | |
567 | memset(&N, '\0', sizeof(netdbEntry)); | |
568 | q = strtok(t, w_space); | |
569 | t = s + 1; | |
570 | ||
571 | if (NULL == q) | |
572 | continue; | |
573 | ||
574 | if (!safe_inet_addr(q, &addr)) | |
575 | continue; | |
576 | ||
577 | if (netdbLookupAddr(addr) != NULL) /* no dups! */ | |
578 | continue; | |
579 | ||
580 | if ((q = strtok(NULL, w_space)) == NULL) | |
581 | continue; | |
582 | ||
583 | N.pings_sent = atoi(q); | |
584 | ||
585 | if ((q = strtok(NULL, w_space)) == NULL) | |
586 | continue; | |
587 | ||
588 | N.pings_recv = atoi(q); | |
589 | ||
590 | if (N.pings_recv == 0) | |
591 | continue; | |
592 | ||
593 | /* give this measurement low weight */ | |
594 | N.pings_sent = 1; | |
595 | ||
596 | N.pings_recv = 1; | |
597 | ||
598 | if ((q = strtok(NULL, w_space)) == NULL) | |
599 | continue; | |
600 | ||
601 | N.hops = atof(q); | |
602 | ||
603 | if ((q = strtok(NULL, w_space)) == NULL) | |
604 | continue; | |
605 | ||
606 | N.rtt = atof(q); | |
607 | ||
608 | if ((q = strtok(NULL, w_space)) == NULL) | |
609 | continue; | |
610 | ||
611 | N.next_ping_time = (time_t) atoi(q); | |
612 | ||
613 | if ((q = strtok(NULL, w_space)) == NULL) | |
614 | continue; | |
615 | ||
616 | N.last_use_time = (time_t) atoi(q); | |
617 | ||
618 | n = (netdbEntry *)memAllocate(MEM_NETDBENTRY); | |
619 | ||
620 | xmemcpy(n, &N, sizeof(netdbEntry)); | |
621 | ||
622 | netdbHashInsert(n, addr); | |
623 | ||
624 | while ((q = strtok(NULL, w_space)) != NULL) { | |
625 | if (netdbLookupHost(q) != NULL) /* no dups! */ | |
626 | continue; | |
627 | ||
628 | netdbHostInsert(n, q); | |
629 | } | |
630 | ||
631 | count++; | |
429fdbec | 632 | } |
62e76326 | 633 | |
111b16cf | 634 | xfree(buf); |
587d8445 | 635 | getCurrentTime(); |
67f46679 | 636 | debug(38, 1) ("NETDB state reloaded; %d entries, %d msec\n", |
62e76326 | 637 | count, tvSubMsec(start, current_time)); |
429fdbec | 638 | } |
639 | ||
858783c9 | 640 | static const char * |
429fdbec | 641 | netdbPeerName(const char *name) |
642 | { | |
858783c9 | 643 | const wordlist *w; |
62e76326 | 644 | |
429fdbec | 645 | for (w = peer_names; w; w = w->next) { |
62e76326 | 646 | if (!strcmp(w->key, name)) |
647 | return w->key; | |
429fdbec | 648 | } |
62e76326 | 649 | |
858783c9 | 650 | return wordlistAdd(&peer_names, name); |
429fdbec | 651 | } |
652 | ||
45c54bdc | 653 | static void |
654 | netdbFreeNetdbEntry(void *data) | |
655 | { | |
e6ccf245 | 656 | netdbEntry *n = (netdbEntry *)data; |
45c54bdc | 657 | safe_free(n->peers); |
db1cd23c | 658 | memFree(n, MEM_NETDBENTRY); |
45c54bdc | 659 | } |
429fdbec | 660 | |
45c54bdc | 661 | static void |
662 | netdbFreeNameEntry(void *data) | |
663 | { | |
e6ccf245 | 664 | net_db_name *x = (net_db_name *)data; |
186477c1 | 665 | xfree(x->hash.key); |
db1cd23c | 666 | memFree(x, MEM_NET_DB_NAME); |
45c54bdc | 667 | } |
668 | ||
add2192d | 669 | |
45c54bdc | 670 | static void |
4b725156 | 671 | netdbExchangeHandleReply(void *data, StoreIOBuffer recievedData) |
45c54bdc | 672 | { |
e6ccf245 | 673 | netdbExchangeState *ex = (netdbExchangeState *)data; |
45c54bdc | 674 | int rec_sz = 0; |
675 | off_t o; | |
62e76326 | 676 | |
ddfcbc22 | 677 | struct IN_ADDR addr; |
45c54bdc | 678 | double rtt; |
679 | double hops; | |
680 | char *p; | |
681 | int j; | |
528b2c61 | 682 | HttpReply const *rep; |
45c54bdc | 683 | size_t hdr_sz; |
70305391 | 684 | int nused = 0; |
add2192d | 685 | int size; |
686 | int oldbufofs = ex->buf_ofs; | |
687 | ||
45c54bdc | 688 | rec_sz = 0; |
689 | rec_sz += 1 + sizeof(addr.s_addr); | |
690 | rec_sz += 1 + sizeof(int); | |
691 | rec_sz += 1 + sizeof(int); | |
4b725156 | 692 | debug(38, 3) ("netdbExchangeHandleReply: %d read bytes\n", (int) recievedData.length); |
62e76326 | 693 | |
fa80a8ef | 694 | if (!cbdataReferenceValid(ex->p)) { |
62e76326 | 695 | debug(38, 3) ("netdbExchangeHandleReply: Peer became invalid\n"); |
696 | netdbExchangeDone(ex); | |
697 | return; | |
45c54bdc | 698 | } |
62e76326 | 699 | |
67f46679 | 700 | debug(38, 3) ("netdbExchangeHandleReply: for '%s:%d'\n", ex->p->host, ex->p->http_port); |
528b2c61 | 701 | |
62e76326 | 702 | if (recievedData.length == 0 && |
703 | !recievedData.flags.error) { | |
704 | debug(38, 3) ("netdbExchangeHandleReply: Done\n"); | |
705 | netdbExchangeDone(ex); | |
706 | return; | |
528b2c61 | 707 | } |
62e76326 | 708 | |
add2192d | 709 | p = ex->buf; |
710 | ||
711 | /* Get the size of the buffer now */ | |
4b725156 | 712 | size = ex->buf_ofs + recievedData.length; |
137a13ea | 713 | debugs(38, 3, "netdbExchangeHandleReply: " << size << " bytes buf"); |
add2192d | 714 | |
715 | /* Check if we're still doing headers */ | |
62e76326 | 716 | |
add2192d | 717 | if (ex->connstate == STATE_HEADER) { |
718 | ||
62e76326 | 719 | ex->buf_ofs += recievedData.length; |
720 | ||
721 | /* skip reply headers */ | |
722 | ||
723 | if ((hdr_sz = headersEnd(p, ex->buf_ofs))) { | |
137a13ea | 724 | debugs(38, 5, "netdbExchangeHandleReply: hdr_sz = " << hdr_sz); |
62e76326 | 725 | rep = ex->e->getReply(); |
726 | assert (0 != rep->sline.status); | |
727 | debug(38, 3) ("netdbExchangeHandleReply: reply status %d\n", | |
728 | rep->sline.status); | |
729 | ||
730 | if (HTTP_OK != rep->sline.status) { | |
731 | netdbExchangeDone(ex); | |
732 | return; | |
733 | } | |
734 | ||
735 | assert((size_t)ex->buf_ofs >= hdr_sz); | |
736 | ||
737 | /* | |
738 | * Now, point p to the part of the buffer where the data | |
739 | * starts, and update the size accordingly | |
740 | */ | |
741 | assert(ex->used == 0); | |
742 | ex->used = hdr_sz; | |
743 | size = ex->buf_ofs - hdr_sz; | |
744 | p += hdr_sz; | |
745 | ||
746 | /* Finally, set the conn state mode to STATE_BODY */ | |
747 | ex->connstate = STATE_BODY; | |
748 | } else { | |
749 | StoreIOBuffer tempBuffer; | |
750 | tempBuffer.offset = ex->buf_ofs; | |
751 | tempBuffer.length = ex->buf_sz - ex->buf_ofs; | |
752 | tempBuffer.data = ex->buf + ex->buf_ofs; | |
753 | /* Have more headers .. */ | |
754 | storeClientCopy(ex->sc, ex->e, tempBuffer, | |
755 | netdbExchangeHandleReply, ex); | |
756 | return; | |
757 | } | |
45c54bdc | 758 | } |
62e76326 | 759 | |
add2192d | 760 | assert(ex->connstate == STATE_BODY); |
761 | ||
762 | /* If we get here, we have some body to parse .. */ | |
67f46679 | 763 | debug(38, 5) ("netdbExchangeHandleReply: start parsing loop, size = %d\n", |
62e76326 | 764 | size); |
765 | ||
45c54bdc | 766 | while (size >= rec_sz) { |
62e76326 | 767 | debug(38, 5) ("netdbExchangeHandleReply: in parsing loop, size = %d\n", |
768 | size); | |
769 | addr.s_addr = any_addr.s_addr; | |
770 | hops = rtt = 0.0; | |
771 | ||
772 | for (o = 0; o < rec_sz;) { | |
773 | switch ((int) *(p + o)) { | |
774 | ||
775 | case NETDB_EX_NETWORK: | |
776 | o++; | |
777 | xmemcpy(&addr.s_addr, p + o, sizeof(addr.s_addr)); | |
778 | o += sizeof(addr.s_addr); | |
779 | break; | |
780 | ||
781 | case NETDB_EX_RTT: | |
782 | o++; | |
783 | xmemcpy(&j, p + o, sizeof(int)); | |
784 | o += sizeof(int); | |
785 | rtt = (double) ntohl(j) / 1000.0; | |
786 | break; | |
787 | ||
788 | case NETDB_EX_HOPS: | |
789 | o++; | |
790 | xmemcpy(&j, p + o, sizeof(int)); | |
791 | o += sizeof(int); | |
792 | hops = (double) ntohl(j) / 1000.0; | |
793 | break; | |
794 | ||
795 | default: | |
796 | debug(38, 1) ("netdbExchangeHandleReply: corrupt data, aborting\n"); | |
797 | netdbExchangeDone(ex); | |
798 | return; | |
799 | } | |
800 | } | |
801 | ||
802 | if (addr.s_addr != any_addr.s_addr && rtt > 0) | |
803 | netdbExchangeUpdatePeer(addr, ex->p, rtt, hops); | |
804 | ||
805 | assert(o == rec_sz); | |
806 | ||
807 | ex->used += rec_sz; | |
808 | ||
809 | size -= rec_sz; | |
810 | ||
811 | p += rec_sz; | |
812 | ||
813 | nused++; | |
45c54bdc | 814 | } |
add2192d | 815 | |
816 | /* | |
817 | * Copy anything that is left over to the beginning of the buffer, | |
818 | * and adjust buf_ofs accordingly | |
819 | */ | |
820 | ||
821 | /* | |
822 | * Evilly, size refers to the buf size left now, | |
823 | * ex->buf_ofs is the original buffer size, so just copy that | |
824 | * much data over | |
825 | */ | |
826 | memmove(ex->buf, ex->buf + (ex->buf_ofs - size), size); | |
62e76326 | 827 | |
add2192d | 828 | ex->buf_ofs = size; |
829 | ||
830 | /* | |
831 | * And don't re-copy the remaining data .. | |
832 | */ | |
833 | ex->used += size; | |
834 | ||
835 | /* | |
836 | * Now the tricky bit - size _included_ the leftover bit from the _last_ | |
837 | * storeClientCopy. We don't want to include that, or our offset will be wrong. | |
838 | * So, don't count the size of the leftover buffer we began with. | |
839 | * This can _disappear_ when we're not tracking offsets .. | |
840 | */ | |
841 | ex->used -= oldbufofs; | |
842 | ||
843 | debug(38, 3) ("netdbExchangeHandleReply: size left over in this buffer: %d bytes\n", size); | |
844 | ||
67f46679 | 845 | debug(38, 3) ("netdbExchangeHandleReply: used %d entries, (x %d bytes) == %d bytes total\n", |
62e76326 | 846 | nused, rec_sz, nused * rec_sz); |
847 | ||
fa80a8ef | 848 | debug(38, 3) ("netdbExchangeHandleReply: used %ld\n", (long int) ex->used); |
62e76326 | 849 | |
b7fe0ab0 | 850 | if (EBIT_TEST(ex->e->flags, ENTRY_ABORTED)) { |
62e76326 | 851 | debug(38, 3) ("netdbExchangeHandleReply: ENTRY_ABORTED\n"); |
852 | netdbExchangeDone(ex); | |
ce9b54e8 | 853 | } else if (ex->e->store_status == STORE_PENDING) { |
62e76326 | 854 | StoreIOBuffer tempBuffer; |
855 | tempBuffer.offset = ex->used; | |
856 | tempBuffer.length = ex->buf_sz - ex->buf_ofs; | |
857 | tempBuffer.data = ex->buf + ex->buf_ofs; | |
858 | debug(38, 3) ("netdbExchangeHandleReply: EOF not recieved\n"); | |
859 | storeClientCopy(ex->sc, ex->e, tempBuffer, | |
860 | netdbExchangeHandleReply, ex); | |
45c54bdc | 861 | } |
862 | } | |
863 | ||
864 | static void | |
865 | netdbExchangeDone(void *data) | |
866 | { | |
e6ccf245 | 867 | netdbExchangeState *ex = (netdbExchangeState *)data; |
67f46679 | 868 | debug(38, 3) ("netdbExchangeDone: %s\n", storeUrl(ex->e)); |
45c54bdc | 869 | requestUnlink(ex->r); |
06d2839d | 870 | storeUnregister(ex->sc, ex->e, ex); |
45c54bdc | 871 | storeUnlockObject(ex->e); |
fa80a8ef | 872 | cbdataReferenceDone(ex->p); |
45c54bdc | 873 | cbdataFree(ex); |
874 | } | |
429fdbec | 875 | |
e97f40f4 | 876 | #endif /* USE_ICMP */ |
877 | ||
878 | /* PUBLIC FUNCTIONS */ | |
879 | ||
67508012 | 880 | void |
e97f40f4 | 881 | netdbInit(void) |
882 | { | |
883 | #if USE_ICMP | |
aa9e2cab | 884 | int n; |
62e76326 | 885 | |
19054954 | 886 | if (addr_table) |
62e76326 | 887 | return; |
888 | ||
aa9e2cab | 889 | n = hashPrime(Config.Netdb.high / 4); |
62e76326 | 890 | |
aa9e2cab | 891 | addr_table = hash_create((HASHCMP *) strcmp, n, hash_string); |
62e76326 | 892 | |
aa9e2cab | 893 | n = hashPrime(3 * Config.Netdb.high / 4); |
62e76326 | 894 | |
aa9e2cab | 895 | host_table = hash_create((HASHCMP *) strcmp, n, hash_string); |
62e76326 | 896 | |
52040193 | 897 | eventAddIsh("netdbSaveState", netdbSaveState, NULL, 3600.0, 1); |
62e76326 | 898 | |
429fdbec | 899 | netdbReloadState(); |
62e76326 | 900 | |
22f3fd98 | 901 | cachemgrRegister("netdb", |
62e76326 | 902 | "Network Measurement Database", |
903 | netdbDump, 0, 1); | |
904 | ||
e97f40f4 | 905 | #endif |
906 | } | |
907 | ||
908 | void | |
0ee4272b | 909 | netdbPingSite(const char *hostname) |
67508012 | 910 | { |
e97f40f4 | 911 | #if USE_ICMP |
67508012 | 912 | netdbEntry *n; |
28c60158 | 913 | generic_cbdata *h; |
62e76326 | 914 | |
e97f40f4 | 915 | if ((n = netdbLookupHost(hostname)) != NULL) |
62e76326 | 916 | if (n->next_ping_time > squid_curtime) |
917 | return; | |
918 | ||
72711e31 | 919 | h = cbdataAlloc(generic_cbdata); |
62e76326 | 920 | |
28c60158 | 921 | h->data = xstrdup(hostname); |
62e76326 | 922 | |
0383c140 | 923 | ipcache_nbgethostbyname(hostname, netdbSendPing, h); |
62e76326 | 924 | |
e97f40f4 | 925 | #endif |
67508012 | 926 | } |
927 | ||
e97f40f4 | 928 | void |
62e76326 | 929 | |
0ee4272b | 930 | netdbHandlePingReply(const struct sockaddr_in *from, int hops, int rtt) |
4d311579 | 931 | { |
e97f40f4 | 932 | #if USE_ICMP |
933 | netdbEntry *n; | |
934 | int N; | |
67f46679 | 935 | debug(38, 3) ("netdbHandlePingReply: from %s\n", inet_ntoa(from->sin_addr)); |
62e76326 | 936 | |
e97f40f4 | 937 | if ((n = netdbLookupAddr(from->sin_addr)) == NULL) |
62e76326 | 938 | return; |
939 | ||
429fdbec | 940 | N = ++n->pings_recv; |
62e76326 | 941 | |
429fdbec | 942 | if (N > 5) |
62e76326 | 943 | N = 5; |
944 | ||
e6ccf245 | 945 | if (rtt < 1) |
62e76326 | 946 | rtt = 1; |
947 | ||
e97f40f4 | 948 | n->hops = ((n->hops * (N - 1)) + hops) / N; |
62e76326 | 949 | |
e97f40f4 | 950 | n->rtt = ((n->rtt * (N - 1)) + rtt) / N; |
62e76326 | 951 | |
67f46679 | 952 | debug(38, 3) ("netdbHandlePingReply: %s; rtt=%5.1f hops=%4.1f\n", |
62e76326 | 953 | n->network, |
954 | n->rtt, | |
955 | n->hops); | |
956 | ||
e97f40f4 | 957 | #endif |
4d311579 | 958 | } |
e5f6c5c2 | 959 | |
960 | void | |
961 | netdbFreeMemory(void) | |
962 | { | |
e97f40f4 | 963 | #if USE_ICMP |
ec878047 | 964 | hashFreeItems(addr_table, netdbFreeNetdbEntry); |
e5f6c5c2 | 965 | hashFreeMemory(addr_table); |
afe95a7e | 966 | addr_table = NULL; |
ec878047 | 967 | hashFreeItems(host_table, netdbFreeNameEntry); |
968 | hashFreeMemory(host_table); | |
afe95a7e | 969 | host_table = NULL; |
429fdbec | 970 | wordlistDestroy(&peer_names); |
971 | peer_names = NULL; | |
e97f40f4 | 972 | #endif |
e5f6c5c2 | 973 | } |
974 | ||
e97f40f4 | 975 | int |
62e76326 | 976 | |
ddfcbc22 | 977 | netdbHops(struct IN_ADDR addr) |
e97f40f4 | 978 | { |
979 | #if USE_ICMP | |
980 | netdbEntry *n = netdbLookupAddr(addr); | |
62e76326 | 981 | |
982 | if (n && n->pings_recv) | |
983 | { | |
984 | n->last_use_time = squid_curtime; | |
985 | return (int) (n->hops + 0.5); | |
e97f40f4 | 986 | } |
62e76326 | 987 | |
e97f40f4 | 988 | #endif |
989 | return 256; | |
990 | } | |
991 | ||
992 | void | |
993 | netdbDump(StoreEntry * sentry) | |
994 | { | |
995 | #if USE_ICMP | |
996 | netdbEntry *n; | |
997 | netdbEntry **list; | |
429fdbec | 998 | net_db_name *x; |
e97f40f4 | 999 | int k; |
1000 | int i; | |
429fdbec | 1001 | int j; |
1002 | net_db_peer *p; | |
15576b6a | 1003 | storeAppendPrintf(sentry, "Network DB Statistics:\n"); |
1004 | storeAppendPrintf(sentry, "%-16.16s %9s %7s %5s %s\n", | |
62e76326 | 1005 | "Network", |
1006 | "recv/sent", | |
1007 | "RTT", | |
1008 | "Hops", | |
1009 | "Hostnames"); | |
e6ccf245 | 1010 | list = (netdbEntry **)xcalloc(memInUse(MEM_NETDBENTRY), sizeof(netdbEntry *)); |
0ee4272b | 1011 | i = 0; |
0f6bebac | 1012 | hash_first(addr_table); |
62e76326 | 1013 | |
0f6bebac | 1014 | while ((n = (netdbEntry *) hash_next(addr_table))) |
62e76326 | 1015 | *(list + i++) = n; |
1016 | ||
587d8445 | 1017 | if (i != memInUse(MEM_NETDBENTRY)) |
62e76326 | 1018 | debug(38, 0) ("WARNING: netdb_addrs count off, found %d, expected %d\n", |
1019 | i, memInUse(MEM_NETDBENTRY)); | |
1020 | ||
0ee4272b | 1021 | qsort((char *) list, |
62e76326 | 1022 | i, |
1023 | sizeof(netdbEntry *), | |
1024 | sortByRtt); | |
1025 | ||
0ee4272b | 1026 | for (k = 0; k < i; k++) { |
62e76326 | 1027 | n = *(list + k); |
1028 | storeAppendPrintf(sentry, "%-16.16s %4d/%4d %7.1f %5.1f", | |
1029 | n->network, | |
1030 | n->pings_recv, | |
1031 | n->pings_sent, | |
1032 | n->rtt, | |
1033 | n->hops); | |
1034 | ||
1035 | for (x = n->hosts; x; x = x->next) | |
1036 | storeAppendPrintf(sentry, " %s", hashKeyStr(&x->hash)); | |
1037 | ||
1038 | storeAppendPrintf(sentry, "\n"); | |
1039 | ||
1040 | p = n->peers; | |
1041 | ||
1042 | for (j = 0; j < n->n_peers; j++, p++) { | |
1043 | storeAppendPrintf(sentry, " %-22.22s %7.1f %5.1f\n", | |
1044 | p->peername, | |
1045 | p->rtt, | |
1046 | p->hops); | |
1047 | } | |
0ee4272b | 1048 | } |
62e76326 | 1049 | |
0ee4272b | 1050 | xfree(list); |
c8391077 | 1051 | #else |
62e76326 | 1052 | |
c8391077 | 1053 | storeAppendPrintf(sentry, |
62e76326 | 1054 | "NETDB support not compiled into this Squid cache.\n"); |
e97f40f4 | 1055 | #endif |
1056 | } | |
48f44632 | 1057 | |
1058 | int | |
1059 | netdbHostHops(const char *host) | |
1060 | { | |
1061 | #if USE_ICMP | |
1062 | netdbEntry *n = netdbLookupHost(host); | |
62e76326 | 1063 | |
429fdbec | 1064 | if (n) { |
62e76326 | 1065 | n->last_use_time = squid_curtime; |
1066 | return (int) (n->hops + 0.5); | |
429fdbec | 1067 | } |
62e76326 | 1068 | |
48f44632 | 1069 | #endif |
429fdbec | 1070 | return 0; |
48f44632 | 1071 | } |
1072 | ||
1073 | int | |
1074 | netdbHostRtt(const char *host) | |
1075 | { | |
1076 | #if USE_ICMP | |
1077 | netdbEntry *n = netdbLookupHost(host); | |
62e76326 | 1078 | |
429fdbec | 1079 | if (n) { |
62e76326 | 1080 | n->last_use_time = squid_curtime; |
1081 | return (int) (n->rtt + 0.5); | |
429fdbec | 1082 | } |
62e76326 | 1083 | |
429fdbec | 1084 | #endif |
1085 | return 0; | |
1086 | } | |
1087 | ||
1d6ae62d | 1088 | void |
1089 | netdbHostData(const char *host, int *samp, int *rtt, int *hops) | |
1090 | { | |
1091 | #if USE_ICMP | |
5942e8d4 | 1092 | netdbEntry *n = netdbLookupHost(host); |
62e76326 | 1093 | |
5942e8d4 | 1094 | if (n == NULL) |
62e76326 | 1095 | return; |
1096 | ||
5942e8d4 | 1097 | *samp = n->pings_recv; |
62e76326 | 1098 | |
5942e8d4 | 1099 | *rtt = (int) (n->rtt + 0.5); |
62e76326 | 1100 | |
5942e8d4 | 1101 | *hops = (int) (n->hops + 0.5); |
62e76326 | 1102 | |
4ed6ef62 | 1103 | n->last_use_time = squid_curtime; |
62e76326 | 1104 | |
1d6ae62d | 1105 | #endif |
1106 | } | |
1107 | ||
429fdbec | 1108 | void |
190154cf | 1109 | netdbUpdatePeer(HttpRequest * r, peer * e, int irtt, int ihops) |
429fdbec | 1110 | { |
1111 | #if USE_ICMP | |
1112 | netdbEntry *n; | |
1113 | double rtt = (double) irtt; | |
1114 | double hops = (double) ihops; | |
1115 | net_db_peer *p; | |
67f46679 | 1116 | debug(38, 3) ("netdbUpdatePeer: '%s', %d hops, %d rtt\n", r->host, ihops, irtt); |
429fdbec | 1117 | n = netdbLookupHost(r->host); |
62e76326 | 1118 | |
429fdbec | 1119 | if (n == NULL) { |
62e76326 | 1120 | debug(38, 3) ("netdbUpdatePeer: host '%s' not found\n", r->host); |
1121 | return; | |
429fdbec | 1122 | } |
62e76326 | 1123 | |
429fdbec | 1124 | if ((p = netdbPeerByName(n, e->host)) == NULL) |
62e76326 | 1125 | p = netdbPeerAdd(n, e); |
1126 | ||
429fdbec | 1127 | p->rtt = rtt; |
62e76326 | 1128 | |
429fdbec | 1129 | p->hops = hops; |
62e76326 | 1130 | |
429fdbec | 1131 | p->expires = squid_curtime + 3600; |
62e76326 | 1132 | |
429fdbec | 1133 | if (n->n_peers < 2) |
62e76326 | 1134 | return; |
1135 | ||
429fdbec | 1136 | qsort((char *) n->peers, |
62e76326 | 1137 | n->n_peers, |
1138 | sizeof(net_db_peer), | |
1139 | sortPeerByRtt); | |
1140 | ||
48f44632 | 1141 | #endif |
48f44632 | 1142 | } |
ce75f381 | 1143 | |
27efd484 | 1144 | void |
62e76326 | 1145 | |
ddfcbc22 | 1146 | netdbExchangeUpdatePeer(struct IN_ADDR addr, peer * e, double rtt, double hops) |
27efd484 | 1147 | { |
1148 | #if USE_ICMP | |
1149 | netdbEntry *n; | |
1150 | net_db_peer *p; | |
67f46679 | 1151 | debug(38, 5) ("netdbExchangeUpdatePeer: '%s', %0.1f hops, %0.1f rtt\n", |
62e76326 | 1152 | inet_ntoa(addr), hops, rtt); |
27efd484 | 1153 | n = netdbLookupAddr(addr); |
62e76326 | 1154 | |
27efd484 | 1155 | if (n == NULL) |
62e76326 | 1156 | n = netdbAdd(addr); |
1157 | ||
27efd484 | 1158 | assert(NULL != n); |
62e76326 | 1159 | |
27efd484 | 1160 | if ((p = netdbPeerByName(n, e->host)) == NULL) |
62e76326 | 1161 | p = netdbPeerAdd(n, e); |
1162 | ||
27efd484 | 1163 | p->rtt = rtt; |
62e76326 | 1164 | |
27efd484 | 1165 | p->hops = hops; |
62e76326 | 1166 | |
27efd484 | 1167 | p->expires = squid_curtime + 3600; /* XXX ? */ |
62e76326 | 1168 | |
27efd484 | 1169 | if (n->n_peers < 2) |
62e76326 | 1170 | return; |
1171 | ||
27efd484 | 1172 | qsort((char *) n->peers, |
62e76326 | 1173 | n->n_peers, |
1174 | sizeof(net_db_peer), | |
1175 | sortPeerByRtt); | |
1176 | ||
27efd484 | 1177 | #endif |
1178 | } | |
1179 | ||
587d8445 | 1180 | void |
62e76326 | 1181 | |
ddfcbc22 | 1182 | netdbDeleteAddrNetwork(struct IN_ADDR addr) |
587d8445 | 1183 | { |
1184 | #if USE_ICMP | |
1185 | netdbEntry *n = netdbLookupAddr(addr); | |
62e76326 | 1186 | |
587d8445 | 1187 | if (n == NULL) |
62e76326 | 1188 | return; |
1189 | ||
fd9f2966 | 1190 | debug(38, 3) ("netdbDeleteAddrNetwork: %s\n", n->network); |
62e76326 | 1191 | |
587d8445 | 1192 | netdbRelease(n); |
62e76326 | 1193 | |
587d8445 | 1194 | #endif |
1195 | } | |
de2a0782 | 1196 | |
1197 | void | |
1198 | netdbBinaryExchange(StoreEntry * s) | |
1199 | { | |
06a5ae20 | 1200 | HttpReply *reply = new HttpReply; |
9ad1cbca | 1201 | #if USE_ICMP |
62e76326 | 1202 | |
de2a0782 | 1203 | netdbEntry *n; |
de2a0782 | 1204 | int i; |
1205 | int j; | |
1206 | int rec_sz; | |
1207 | char *buf; | |
62e76326 | 1208 | |
ddfcbc22 | 1209 | struct IN_ADDR addr; |
de2a0782 | 1210 | storeBuffer(s); |
450e0c10 | 1211 | HttpVersion version(1, 0); |
06a5ae20 | 1212 | reply->setHeaders(version, HTTP_OK, "OK", NULL, -1, squid_curtime, -2); |
4a56ee8d | 1213 | storeEntryReplaceObject(s, reply); |
de2a0782 | 1214 | rec_sz = 0; |
1215 | rec_sz += 1 + sizeof(addr.s_addr); | |
1216 | rec_sz += 1 + sizeof(int); | |
1217 | rec_sz += 1 + sizeof(int); | |
e6ccf245 | 1218 | buf = (char *)memAllocate(MEM_4K_BUF); |
de2a0782 | 1219 | i = 0; |
0f6bebac | 1220 | hash_first(addr_table); |
62e76326 | 1221 | |
0f6bebac | 1222 | while ((n = (netdbEntry *) hash_next(addr_table))) { |
62e76326 | 1223 | if (0.0 == n->rtt) |
1224 | continue; | |
1225 | ||
1226 | if (n->rtt > 60000) /* RTT > 1 MIN probably bogus */ | |
1227 | continue; | |
1228 | ||
1229 | if (!safe_inet_addr(n->network, &addr)) | |
1230 | continue; | |
1231 | ||
1232 | buf[i++] = (char) NETDB_EX_NETWORK; | |
1233 | ||
1234 | xmemcpy(&buf[i], &addr.s_addr, sizeof(addr.s_addr)); | |
1235 | ||
1236 | i += sizeof(addr.s_addr); | |
1237 | ||
1238 | buf[i++] = (char) NETDB_EX_RTT; | |
1239 | ||
1240 | j = htonl((int) (n->rtt * 1000)); | |
1241 | ||
1242 | xmemcpy(&buf[i], &j, sizeof(int)); | |
1243 | ||
1244 | i += sizeof(int); | |
1245 | ||
1246 | buf[i++] = (char) NETDB_EX_HOPS; | |
1247 | ||
1248 | j = htonl((int) (n->hops * 1000)); | |
1249 | ||
1250 | xmemcpy(&buf[i], &j, sizeof(int)); | |
1251 | ||
1252 | i += sizeof(int); | |
1253 | ||
1254 | if (i + rec_sz > 4096) { | |
1255 | storeAppend(s, buf, i); | |
1256 | i = 0; | |
1257 | } | |
de2a0782 | 1258 | } |
62e76326 | 1259 | |
84075e8f | 1260 | if (i > 0) { |
62e76326 | 1261 | storeAppend(s, buf, i); |
1262 | i = 0; | |
84075e8f | 1263 | } |
62e76326 | 1264 | |
de2a0782 | 1265 | assert(0 == i); |
1266 | storeBufferFlush(s); | |
db1cd23c | 1267 | memFree(buf, MEM_4K_BUF); |
de2a0782 | 1268 | #else |
62e76326 | 1269 | |
450e0c10 | 1270 | HttpVersion version(1,0); |
06a5ae20 | 1271 | reply->setHeaders(version, HTTP_BAD_REQUEST, "Bad Request", |
1272 | NULL, -1, squid_curtime, -2); | |
4a56ee8d | 1273 | storeEntryReplaceObject(s, reply); |
de2a0782 | 1274 | storeAppendPrintf(s, "NETDB support not compiled into this Squid cache.\n"); |
1275 | #endif | |
62e76326 | 1276 | |
528b2c61 | 1277 | s->complete(); |
9ad1cbca | 1278 | } |
1279 | ||
28c60158 | 1280 | #if USE_ICMP |
1281 | CBDATA_TYPE(netdbExchangeState); | |
1282 | #endif | |
1283 | ||
9ad1cbca | 1284 | void |
1285 | netdbExchangeStart(void *data) | |
1286 | { | |
45c54bdc | 1287 | #if USE_ICMP |
e6ccf245 | 1288 | peer *p = (peer *)data; |
a74c5601 | 1289 | char *uri; |
28c60158 | 1290 | netdbExchangeState *ex; |
528b2c61 | 1291 | StoreIOBuffer tempBuffer; |
28c60158 | 1292 | CBDATA_INIT_TYPE(netdbExchangeState); |
72711e31 | 1293 | ex = cbdataAlloc(netdbExchangeState); |
fa80a8ef | 1294 | ex->p = cbdataReference(p); |
a74c5601 | 1295 | uri = internalRemoteUri(p->host, p->http_port, "/squid-internal-dynamic/", "netdb"); |
fd9f2966 | 1296 | debug(38, 3) ("netdbExchangeStart: Requesting '%s'\n", uri); |
a74c5601 | 1297 | assert(NULL != uri); |
1298 | ex->r = urlParse(METHOD_GET, uri); | |
62e76326 | 1299 | |
a74c5601 | 1300 | if (NULL == ex->r) { |
62e76326 | 1301 | debug(38, 1) ("netdbExchangeStart: Bad URI %s\n", uri); |
1302 | return; | |
a74c5601 | 1303 | } |
62e76326 | 1304 | |
a74c5601 | 1305 | requestLink(ex->r); |
1306 | assert(NULL != ex->r); | |
450e0c10 | 1307 | ex->r->http_ver = HttpVersion(1,0); |
add2192d | 1308 | ex->connstate = STATE_HEADER; |
e429f975 | 1309 | ex->e = storeCreateEntry(uri, uri, request_flags(), METHOD_GET); |
add2192d | 1310 | ex->buf_sz = NETDB_REQBUF_SZ; |
a74c5601 | 1311 | assert(NULL != ex->e); |
06d2839d | 1312 | ex->sc = storeClientListAdd(ex->e, ex); |
4b725156 | 1313 | tempBuffer.offset = 0; |
1314 | tempBuffer.length = ex->buf_sz; | |
1315 | tempBuffer.data = ex->buf; | |
1316 | storeClientCopy(ex->sc, ex->e, tempBuffer, | |
62e76326 | 1317 | netdbExchangeHandleReply, ex); |
92695e5e | 1318 | ex->r->flags.loopdetect = 1; /* cheat! -- force direct */ |
62e76326 | 1319 | |
9bc73deb | 1320 | if (p->login) |
62e76326 | 1321 | xstrncpy(ex->r->login, p->login, MAX_LOGIN_SZ); |
1322 | ||
21ea7560 | 1323 | FwdState::fwdStart(-1, ex->e, ex->r); |
62e76326 | 1324 | |
45c54bdc | 1325 | #endif |
de2a0782 | 1326 | } |
69c95dd3 | 1327 | |
1328 | peer * | |
190154cf | 1329 | netdbClosestParent(HttpRequest * request) |
69c95dd3 | 1330 | { |
69c95dd3 | 1331 | #if USE_ICMP |
f720985e | 1332 | peer *p = NULL; |
69c95dd3 | 1333 | netdbEntry *n; |
1334 | const ipcache_addrs *ia; | |
1335 | net_db_peer *h; | |
1336 | int i; | |
8ff4505b | 1337 | n = netdbLookupHost(request->host); |
62e76326 | 1338 | |
69c95dd3 | 1339 | if (NULL == n) { |
62e76326 | 1340 | /* try IP addr */ |
1341 | ia = ipcache_gethostbyname(request->host, 0); | |
1342 | ||
1343 | if (NULL != ia) | |
1344 | n = netdbLookupAddr(ia->in_addrs[ia->cur]); | |
69c95dd3 | 1345 | } |
62e76326 | 1346 | |
69c95dd3 | 1347 | if (NULL == n) |
62e76326 | 1348 | return NULL; |
1349 | ||
69c95dd3 | 1350 | if (0 == n->n_peers) |
62e76326 | 1351 | return NULL; |
1352 | ||
4ed6ef62 | 1353 | n->last_use_time = squid_curtime; |
62e76326 | 1354 | |
1355 | /* | |
69c95dd3 | 1356 | * Find the parent with the least RTT to the origin server. |
1357 | * Make sure we don't return a parent who is farther away than | |
1358 | * we are. Note, the n->peers list is pre-sorted by RTT. | |
1359 | */ | |
1360 | for (i = 0; i < n->n_peers; i++) { | |
62e76326 | 1361 | h = &n->peers[i]; |
1362 | ||
1363 | if (n->rtt > 0) | |
1364 | if (n->rtt < h->rtt) | |
1365 | break; | |
1366 | ||
1367 | p = peerFindByName(h->peername); | |
1368 | ||
1369 | if (NULL == p) /* not found */ | |
1370 | continue; | |
1371 | ||
1372 | if (neighborType(p, request) != PEER_PARENT) | |
1373 | continue; | |
1374 | ||
1375 | if (!peerHTTPOkay(p, request)) /* not allowed */ | |
1376 | continue; | |
1377 | ||
1378 | return p; | |
69c95dd3 | 1379 | } |
62e76326 | 1380 | |
69c95dd3 | 1381 | #endif |
1382 | return NULL; | |
1383 | } |