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