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