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