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