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