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