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