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