]> git.ipfire.org Git - thirdparty/squid.git/blame - src/icmp/net_db.cc
Merged from trunk
[thirdparty/squid.git] / src / icmp / net_db.cc
CommitLineData
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
64typedef enum {
fa80a8ef 65 STATE_NONE,
66 STATE_HEADER,
67 STATE_BODY
add2192d 68} netdb_conn_state_t;
8b833697 69
26ac0430 70typedef 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 82static hash_table *addr_table = NULL;
365e5b34 83static hash_table *host_table = NULL;
87801fcb 84
b7ac5457 85Ip::Address networkFromInaddr(const Ip::Address &a);
f5b8bbc4 86static void netdbRelease(netdbEntry * n);
62e76326 87
b7ac5457 88static void netdbHashInsert(netdbEntry * n, Ip::Address &addr);
f5b8bbc4 89static void netdbHashDelete(const char *key);
587d8445 90static void netdbHostInsert(netdbEntry * n, const char *hostname);
91static void netdbHostDelete(const net_db_name * x);
f5b8bbc4 92static void netdbPurgeLRU(void);
23d92c64 93static netdbEntry *netdbLookupHost(const char *key);
f5b8bbc4 94static net_db_peer *netdbPeerByName(const netdbEntry * n, const char *);
95static net_db_peer *netdbPeerAdd(netdbEntry * n, peer * e);
858783c9 96static const char *netdbPeerName(const char *name);
b69f7771 97static IPH netdbSendPing;
79d39a72 98static QS sortPeerByRtt;
99static QS sortByRtt;
100static QS netdbLRU;
ec878047 101static FREE netdbFreeNameEntry;
102static FREE netdbFreeNetdbEntry;
9ad1cbca 103static STCB netdbExchangeHandleReply;
45c54bdc 104static 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 */
110static wordlist *peer_names = NULL;
67508012 111
87801fcb 112static void
b7ac5457 113netdbHashInsert(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
121static void
0ee4272b 122netdbHashDelete(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
134static void
587d8445 135netdbHostInsert(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
147static void
587d8445 148netdbHostDelete(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
169static netdbEntry *
0ee4272b 170netdbLookupHost(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 176static void
177netdbRelease(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
199static int
79d39a72 200netdbLRU(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 214static void
215netdbPurgeLRU(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 248static netdbEntry *
b7ac5457 249netdbLookupAddr(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 258static netdbEntry *
b7ac5457 259netdbAdd(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
274static void
3ff65596 275netdbSendPing(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
342Ip::Address
343networkFromInaddr(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
384static int
79d39a72 385sortByRtt(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 398static net_db_peer *
399netdbPeerByName(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
412static net_db_peer *
413netdbPeerAdd(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
447static int
79d39a72 448sortPeerByRtt(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
461static void
462netdbSaveState(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
524static void
525netdbReloadState(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 646static const char *
429fdbec 647netdbPeerName(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 659static void
660netdbFreeNetdbEntry(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 667static void
668netdbFreeNameEntry(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 676static void
2324cda2 677netdbExchangeHandleReply(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
872static void
873netdbExchangeDone(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 884static void
f69d9265 885netdbRegisterWithCacheManager(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 896void
e97f40f4 897netdbInit(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 922void
0ee4272b 923netdbPingSite(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 938void
b7ac5457 939netdbHandlePingReply(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
968void
969netdbFreeMemory(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.
985int
b7ac5457 986netdbHops(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
1001void
1002netdbDump(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
1066int
1067netdbHostHops(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
1081int
1082netdbHostRtt(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 1096void
1097netdbHostData(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 1116void
190154cf 1117netdbUpdatePeer(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 1152void
b7ac5457 1153netdbExchangeUpdatePeer(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 1194void
b7ac5457 1195netdbDeleteAddrNetwork(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 1210void
1211netdbBinaryExchange(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
1298CBDATA_TYPE(netdbExchangeState);
1299#endif
1300
9ad1cbca 1301void
1302netdbExchangeStart(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
1347peer *
190154cf 1348netdbClosestParent(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}