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