net_db.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 38 Network Measurement Database */
10 
11 /*
12  * XXX XXX XXX
13  *
14  * This code may be slightly broken now. If you're getting consistent
15  * (sometimes working) corrupt data exchanges, please contact adrian
16  * (adrian@squid-cache.org) to sort them out.
17  */
18 
19 #include "squid.h"
20 #include "CachePeer.h"
21 #include "CachePeers.h"
22 #include "cbdata.h"
23 #include "event.h"
24 #include "fde.h"
25 #include "fs_io.h"
26 #include "FwdState.h"
27 #include "HttpReply.h"
28 #include "icmp/net_db.h"
29 #include "internal.h"
30 #include "ip/Address.h"
31 #include "log/File.h"
32 #include "MemObject.h"
33 #include "mgr/Registration.h"
34 #include "mime_header.h"
35 #include "neighbors.h"
36 #include "PeerSelectState.h"
37 #include "sbuf/SBuf.h"
38 #include "SquidConfig.h"
39 #include "Store.h"
40 #include "StoreClient.h"
41 #include "tools.h"
42 #include "wordlist.h"
43 
44 #if HAVE_SYS_STAT_H
45 #include <sys/stat.h>
46 #endif
47 
48 #if USE_ICMP
49 #include "icmp/IcmpSquid.h"
50 #include "ipcache.h"
51 #include "StoreClient.h"
52 
53 typedef enum {
58 
60 {
62 
63 public:
65  p(aPeer),
66  r(theReq)
67  {
68  assert(r);
69  // TODO: check if we actually need to do this. should be implicit
71  }
72 
74  debugs(38, 3, e->url());
75  storeUnregister(sc, e, this);
76  e->unlock("netdbExchangeDone");
77  }
78 
80  StoreEntry *e = nullptr;
81  store_client *sc = nullptr;
83 
86 
88 };
89 
91 
92 static hash_table *addr_table = nullptr;
93 static hash_table *host_table = nullptr;
94 
96 static void netdbRelease(netdbEntry * n);
97 
98 static void netdbHashInsert(netdbEntry * n, Ip::Address &addr);
99 static void netdbHashDelete(const char *key);
100 static void netdbHostInsert(netdbEntry * n, const char *hostname);
101 static void netdbHostDelete(const net_db_name * x);
102 static void netdbPurgeLRU(void);
103 static netdbEntry *netdbLookupHost(const char *key);
104 static net_db_peer *netdbPeerByName(const netdbEntry * n, const char *);
105 static net_db_peer *netdbPeerAdd(netdbEntry * n, CachePeer * e);
106 static const char *netdbPeerName(const char *name);
109 
110 /* We have to keep a local list of CachePeer names. The Peers structure
111  * gets freed during a reconfigure. We want this database to
112  * remain persisitent, so _net_db_peer->peername points into this
113  * linked list */
114 static wordlist *peer_names = nullptr;
115 
116 static void
118 {
120  n->key = n->network;
121  assert(hash_lookup(addr_table, n->network) == nullptr);
122  hash_join(addr_table, n);
123 }
124 
125 static void
126 netdbHashDelete(const char *key)
127 {
128  hash_link *hptr = (hash_link *)hash_lookup(addr_table, key);
129 
130  if (hptr == nullptr) {
131  debug_trap("netdbHashDelete: key not found");
132  return;
133  }
134 
136 }
137 
138 net_db_name::net_db_name(const char *hostname, netdbEntry *e) :
139  next(e ? e->hosts : nullptr),
140  net_db_entry(e)
141 {
142  key = xstrdup(hostname);
143  if (e) {
144  e->hosts = this;
145  ++ e->link_count;
146  }
147 }
148 
149 static void
150 netdbHostInsert(netdbEntry * n, const char *hostname)
151 {
152  net_db_name *x = new net_db_name(hostname, n);
153  assert(hash_lookup(host_table, hostname) == nullptr);
154  hash_join(host_table, x);
155 }
156 
157 static void
159 {
160  assert(x != nullptr);
161  assert(x->net_db_entry != nullptr);
162 
163  netdbEntry *n = x->net_db_entry;
164  -- n->link_count;
165 
166  for (auto **X = &n->hosts; *X; X = &(*X)->next) {
167  if (*X == x) {
168  *X = x->next;
169  break;
170  }
171  }
172 
174  delete x;
175 }
176 
177 static netdbEntry *
178 netdbLookupHost(const char *key)
179 {
181  return x ? x->net_db_entry : nullptr;
182 }
183 
184 static void
186 {
187  net_db_name *x;
188  net_db_name *next;
189 
190  for (x = n->hosts; x; x = next) {
191  next = x->next;
192  netdbHostDelete(x);
193  }
194 
195  n->hosts = nullptr;
196  safe_free(n->peers);
197  n->peers = nullptr;
198  n->n_peers = 0;
199  n->n_peers_alloc = 0;
200 
201  if (n->link_count == 0) {
203  delete n;
204  }
205 }
206 
207 static int
208 netdbLRU(const void *A, const void *B)
209 {
210  const netdbEntry *const *n1 = (const netdbEntry *const *)A;
211  const netdbEntry *const *n2 = (const netdbEntry *const *)B;
212 
213  if ((*n1)->last_use_time > (*n2)->last_use_time)
214  return (1);
215 
216  if ((*n1)->last_use_time < (*n2)->last_use_time)
217  return (-1);
218 
219  return (0);
220 }
221 
222 static void
224 {
225  netdbEntry *n;
226  netdbEntry **list;
227  int k = 0;
228  int list_count = 0;
229  list = (netdbEntry **)xcalloc(netdbEntry::UseCount(), sizeof(netdbEntry *));
231 
232  while ((n = (netdbEntry *) hash_next(addr_table))) {
233  assert(list_count < netdbEntry::UseCount());
234  *(list + list_count) = n;
235  ++list_count;
236  }
237 
238  qsort((char *) list,
239  list_count,
240  sizeof(netdbEntry *),
241  netdbLRU);
242 
243  for (k = 0; k < list_count; ++k) {
244  if (netdbEntry::UseCount() < Config.Netdb.low)
245  break;
246 
247  netdbRelease(*(list + k));
248  }
249 
250  xfree(list);
251 }
252 
253 static netdbEntry *
255 {
256  netdbEntry *n;
257  char *key = new char[MAX_IPSTRLEN];
259  n = (netdbEntry *) hash_lookup(addr_table, key);
260  delete[] key;
261  return n;
262 }
263 
264 static netdbEntry *
266 {
267  netdbEntry *n;
268 
269  if (netdbEntry::UseCount() > Config.Netdb.high)
270  netdbPurgeLRU();
271 
272  if ((n = netdbLookupAddr(addr)) == nullptr) {
273  n = new netdbEntry;
274  netdbHashInsert(n, addr);
275  }
276 
277  return n;
278 }
279 
280 static void
281 netdbSendPing(const ipcache_addrs *ia, const Dns::LookupDetails &, void *data)
282 {
283  Ip::Address addr;
284  char *hostname = nullptr;
285  static_cast<generic_cbdata *>(data)->unwrap(&hostname);
286  netdbEntry *n;
287  netdbEntry *na;
288  net_db_name *x;
289  net_db_name **X;
290 
291  if (ia == nullptr) {
292  xfree(hostname);
293  return;
294  }
295 
296  addr = ia->current();
297 
298  if ((n = netdbLookupHost(hostname)) == nullptr) {
299  n = netdbAdd(addr);
300  netdbHostInsert(n, hostname);
301  } else if ((na = netdbLookupAddr(addr)) != n) {
302  /*
303  *hostname moved from 'network n' to 'network na'!
304  */
305 
306  if (na == nullptr)
307  na = netdbAdd(addr);
308 
309  debugs(38, 3, "netdbSendPing: " << hostname << " moved from " << n->network << " to " << na->network);
310 
311  x = (net_db_name *) hash_lookup(host_table, hostname);
312 
313  if (x == nullptr) {
314  debugs(38, DBG_IMPORTANT, "ERROR: Squid BUG: net_db_name list bug: " << hostname << " not found");
315  xfree(hostname);
316  return;
317  }
318 
319  /* remove net_db_name from 'network n' linked list */
320  for (X = &n->hosts; *X; X = &(*X)->next) {
321  if (*X == x) {
322  *X = x->next;
323  break;
324  }
325  }
326 
327  -- n->link_count;
328  /* point to 'network na' from host entry */
329  x->net_db_entry = na;
330  /* link net_db_name to 'network na' */
331  x->next = na->hosts;
332  na->hosts = x;
333  ++ na->link_count;
334  n = na;
335  }
336 
337  if (n->next_ping_time <= squid_curtime) {
338  debugs(38, 3, "netdbSendPing: pinging " << hostname);
339  icmpEngine.DomainPing(addr, hostname);
340  ++ n->pings_sent;
343  }
344 
345  xfree(hostname);
346 }
347 
348 static Ip::Address
350 {
351  Ip::Address out;
352 
353  out = in;
354 
355  /* in IPv6 the 'network' should be the routing section. */
356  if ( in.isIPv6() ) {
357  out.applyMask(64, AF_INET6);
358  debugs(14, 5, "networkFromInaddr : Masked IPv6 Address to " << in << "/64 routing part.");
359  return out;
360  }
361 
362  debugs(14, 5, "networkFromInaddr : Masked IPv4 Address to " << out << "/24.");
363 
364  /* use /24 for everything under IPv4 */
365  out.applyMask(24, AF_INET);
366  debugs(14, 5, "networkFromInaddr : Masked IPv4 Address to " << in << "/24.");
367 
368  return out;
369 }
370 
371 static int
372 sortByRtt(const void *A, const void *B)
373 {
374  const netdbEntry *const *n1 = (const netdbEntry *const *)A;
375  const netdbEntry *const *n2 = (const netdbEntry *const *)B;
376 
377  if ((*n1)->rtt > (*n2)->rtt)
378  return 1;
379  else if ((*n1)->rtt < (*n2)->rtt)
380  return -1;
381  else
382  return 0;
383 }
384 
385 static net_db_peer *
386 netdbPeerByName(const netdbEntry * n, const char *peername)
387 {
388  int i;
389  net_db_peer *p = n->peers;
390 
391  for (i = 0; i < n->n_peers; ++i, ++p) {
392  if (!strcmp(p->peername, peername))
393  return p;
394  }
395 
396  return nullptr;
397 }
398 
399 static net_db_peer *
401 {
402  net_db_peer *p;
403  net_db_peer *o;
404  int osize;
405  int i;
406 
407  if (n->n_peers == n->n_peers_alloc) {
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  debugs(38, 3, "netdbPeerAdd: Growing peer list for '" << n->network << "' to " << n->n_peers_alloc);
417 
418  n->peers = (net_db_peer *)xcalloc(n->n_peers_alloc, sizeof(net_db_peer));
419 
420  for (i = 0; i < osize; ++i)
421  *(n->peers + i) = *(o + i);
422 
423  if (osize) {
424  safe_free(o);
425  }
426  }
427 
428  p = n->peers + n->n_peers;
429  p->peername = netdbPeerName(e->host);
430  ++ n->n_peers;
431  return p;
432 }
433 
434 static int
435 sortPeerByRtt(const void *A, const void *B)
436 {
437  const net_db_peer *p1 = (net_db_peer *)A;
438  const net_db_peer *p2 = (net_db_peer *)B;
439 
440  if (p1->rtt > p2->rtt)
441  return 1;
442  else if (p1->rtt < p2->rtt)
443  return -1;
444  else
445  return 0;
446 }
447 
448 static void
450 {
451  if (strcmp(Config.netdbFilename, "none") == 0)
452  return;
453 
454  Logfile *lf;
455  netdbEntry *n;
456  net_db_name *x;
457 
458  struct timeval start = current_time;
459  int count = 0;
460  /*
461  * This was nicer when we were using stdio, but thanks to
462  * Solaris bugs, its a bad idea. fopen can fail if more than
463  * 256 FDs are open.
464  */
465  /*
466  * unlink() is here because there is currently no way to make
467  * logfileOpen() use O_TRUNC.
468  */
469  unlink(Config.netdbFilename);
470  lf = logfileOpen(Config.netdbFilename, 4096, 0);
471 
472  if (!lf) {
473  int xerrno = errno;
474  debugs(50, DBG_IMPORTANT, MYNAME << Config.netdbFilename << ": " << xstrerr(xerrno));
475  return;
476  }
477 
479 
480  while ((n = (netdbEntry *) hash_next(addr_table))) {
481  if (n->pings_recv == 0)
482  continue;
483 
484  logfilePrintf(lf, "%s %d %d %10.5f %10.5f %d %d",
485  n->network,
486  n->pings_sent,
487  n->pings_recv,
488  n->hops,
489  n->rtt,
490  (int) n->next_ping_time,
491  (int) n->last_use_time);
492 
493  for (x = n->hosts; x; x = x->next)
494  logfilePrintf(lf, " %s", hashKeyStr(x));
495 
496  logfilePrintf(lf, "\n");
497 
498  ++count;
499 
500 #undef RBUF_SZ
501 
502  }
503 
504  logfileClose(lf);
505  getCurrentTime();
506  debugs(38, DBG_IMPORTANT, "NETDB state saved; " <<
507  count << " entries, " <<
508  tvSubMsec(start, current_time) << " msec" );
509  eventAddIsh("netdbSaveState", netdbSaveState, nullptr, 3600.0, 1);
510 }
511 
512 static void
514 {
515  if (strcmp(Config.netdbFilename, "none") == 0)
516  return;
517 
518  char *s;
519  int fd;
520  int l;
521 
522  struct stat sb;
523  netdbEntry *n;
524  netdbEntry N;
525 
526  Ip::Address addr;
527  int count = 0;
528 
529  struct timeval start = current_time;
530  /*
531  * This was nicer when we were using stdio, but thanks to
532  * Solaris bugs, its a bad idea. fopen can fail if more than
533  * 256 FDs are open.
534  */
535  fd = file_open(Config.netdbFilename, O_RDONLY | O_BINARY);
536 
537  if (fd < 0)
538  return;
539 
540  if (fstat(fd, &sb) < 0) {
541  file_close(fd);
542  return;
543  }
544 
545  char *t;
546  char *buf = (char *)xcalloc(1, sb.st_size + 1);
547  t = buf;
548  l = FD_READ_METHOD(fd, buf, sb.st_size);
549  file_close(fd);
550 
551  if (l <= 0) {
552  safe_free (buf);
553  return;
554  };
555 
556  while ((s = strchr(t, '\n'))) {
557  char *q;
558  assert(s - buf < l);
559  *s = '\0';
560  N = netdbEntry();
561  q = strtok(t, w_space);
562  t = s + 1;
563 
564  if (nullptr == q)
565  continue;
566 
567  if (! (addr = q) )
568  continue;
569 
570  if (netdbLookupAddr(addr) != nullptr) /* no dups! */
571  continue;
572 
573  if ((q = strtok(nullptr, w_space)) == nullptr)
574  continue;
575 
576  N.pings_sent = atoi(q);
577 
578  if ((q = strtok(nullptr, w_space)) == nullptr)
579  continue;
580 
581  N.pings_recv = atoi(q);
582 
583  if (N.pings_recv == 0)
584  continue;
585 
586  /* give this measurement low weight */
587  N.pings_sent = 1;
588 
589  N.pings_recv = 1;
590 
591  if ((q = strtok(nullptr, w_space)) == nullptr)
592  continue;
593 
594  N.hops = atof(q);
595 
596  if ((q = strtok(nullptr, w_space)) == nullptr)
597  continue;
598 
599  N.rtt = atof(q);
600 
601  if ((q = strtok(nullptr, w_space)) == nullptr)
602  continue;
603 
604  N.next_ping_time = (time_t) atoi(q);
605 
606  if ((q = strtok(nullptr, w_space)) == nullptr)
607  continue;
608 
609  N.last_use_time = (time_t) atoi(q);
610 
611  n = new netdbEntry;
612 
613  memcpy(n, &N, sizeof(netdbEntry));
614 
615  netdbHashInsert(n, addr);
616 
617  while ((q = strtok(nullptr, w_space)) != nullptr) {
618  if (netdbLookupHost(q) != nullptr) /* no dups! */
619  continue;
620 
621  netdbHostInsert(n, q);
622  }
623 
624  ++count;
625  }
626 
627  xfree(buf);
628  getCurrentTime();
629  debugs(38, DBG_IMPORTANT, "NETDB state reloaded; " <<
630  count << " entries, " <<
631  tvSubMsec(start, current_time) << " msec" );
632 }
633 
634 static const char *
635 netdbPeerName(const char *name)
636 {
637  const wordlist *w;
638 
639  for (w = peer_names; w; w = w->next) {
640  if (!strcmp(w->key, name))
641  return w->key;
642  }
643 
644  return wordlistAdd(&peer_names, name);
645 }
646 
647 static void
648 netdbExchangeHandleReply(void *data, StoreIOBuffer receivedData)
649 {
650  Ip::Address addr;
651 
653 
654  struct in_addr line_addr;
655  double rtt;
656  double hops;
657  int j;
658  int nused = 0;
659 
660  size_t rec_sz = 0; // received record size (TODO: make const)
661  rec_sz += 1 + sizeof(struct in_addr);
662  rec_sz += 1 + sizeof(int);
663  rec_sz += 1 + sizeof(int);
664  // to make progress without growing buffer space, we must parse at least one record per call
665  Assure(rec_sz <= ex->parsingBuffer.capacity());
666  debugs(38, 3, "netdbExchangeHandleReply: " << receivedData.length << " read bytes");
667 
668  if (!ex->p.valid()) {
669  debugs(38, 3, "netdbExchangeHandleReply: Peer became invalid");
670  delete ex;
671  return;
672  }
673 
674  debugs(38, 3, "for " << *ex->p);
675 
676  if (receivedData.flags.error) {
677  delete ex;
678  return;
679  }
680 
681  if (ex->connstate == STATE_HEADER) {
682  const auto scode = ex->e->mem().baseReply().sline.status();
683  assert(scode != Http::scNone);
684  debugs(38, 3, "reply status " << scode);
685  if (scode != Http::scOkay) {
686  delete ex;
687  return;
688  }
689  ex->connstate = STATE_BODY;
690  }
691 
692  assert(ex->connstate == STATE_BODY);
693 
694  ex->parsingBuffer.appended(receivedData.data, receivedData.length);
695  auto p = ex->parsingBuffer.c_str(); // current parsing position
696  auto size = ex->parsingBuffer.contentSize(); // bytes we still need to parse
697 
698  /* If we get here, we have some body to parse .. */
699  debugs(38, 5, "netdbExchangeHandleReply: start parsing loop, size = " << size);
700 
701  while (size >= rec_sz) {
702  debugs(38, 5, "netdbExchangeHandleReply: in parsing loop, size = " << size);
703  addr.setAnyAddr();
704  hops = rtt = 0.0;
705 
706  size_t o; // current record parsing offset
707  for (o = 0; o < rec_sz;) {
708  switch ((int) *(p + o)) {
709 
710  case NETDB_EX_NETWORK:
711  ++o;
712  // XXX: NetDB can still only send IPv4
713  memcpy(&line_addr, p + o, sizeof(struct in_addr));
714  addr = line_addr;
715  o += sizeof(struct in_addr);
716  break;
717 
718  case NETDB_EX_RTT:
719  ++o;
720  memcpy(&j, p + o, sizeof(int));
721  o += sizeof(int);
722  rtt = (double) ntohl(j) / 1000.0;
723  break;
724 
725  case NETDB_EX_HOPS:
726  ++o;
727  memcpy(&j, p + o, sizeof(int));
728  o += sizeof(int);
729  hops = (double) ntohl(j) / 1000.0;
730  break;
731 
732  default:
733  debugs(38, DBG_IMPORTANT, "ERROR: netdbExchangeHandleReply: corrupt data, aborting");
734  delete ex;
735  return;
736  }
737  }
738 
739  if (!addr.isAnyAddr() && rtt > 0)
740  netdbExchangeUpdatePeer(addr, ex->p.get(), rtt, hops);
741 
742  assert(o == rec_sz);
743 
744  size -= rec_sz;
745 
746  p += rec_sz;
747 
748  ++nused;
749  }
750 
751  const auto parsedSize = ex->parsingBuffer.contentSize() - size;
752  ex->parsingBuffer.consume(parsedSize);
753 
754  debugs(38, 3, "netdbExchangeHandleReply: size left over in this buffer: " << size << " bytes");
755 
756  debugs(38, 3, "netdbExchangeHandleReply: used " << nused <<
757  " entries, (x " << rec_sz << " bytes) == " << nused * rec_sz <<
758  " bytes total");
759 
760  if (EBIT_TEST(ex->e->flags, ENTRY_ABORTED)) {
761  debugs(38, 3, "netdbExchangeHandleReply: ENTRY_ABORTED");
762  delete ex;
763  return;
764  }
765 
766  if (ex->sc->atEof()) {
767  if (const auto leftoverBytes = ex->parsingBuffer.contentSize())
768  debugs(38, 2, "discarding a partially received record due to Store EOF: " << leftoverBytes);
769  delete ex;
770  return;
771  }
772 
773  // TODO: To protect us from a broken peer sending an "infinite" stream of
774  // new addresses, limit the cumulative number of received bytes or records?
775 
776  const auto remainingSpace = ex->parsingBuffer.space().positionAt(receivedData.offset + receivedData.length);
777  // rec_sz is at most buffer capacity, and we consume all fully loaded records
778  Assure(remainingSpace.length);
779  storeClientCopy(ex->sc, ex->e, remainingSpace, netdbExchangeHandleReply, ex);
780 }
781 
782 #endif /* USE_ICMP */
783 
784 /* PUBLIC FUNCTIONS */
785 
786 void
788 {
789 #if USE_ICMP
790  Mgr::RegisterAction("netdb", "Network Measurement Database", netdbDump, 0, 1);
791 
792  if (addr_table)
793  return;
794 
795  int n = hashPrime(Config.Netdb.high / 4);
796 
797  addr_table = hash_create((HASHCMP *) strcmp, n, hash_string);
798 
799  n = hashPrime(3 * Config.Netdb.high / 4);
800 
801  host_table = hash_create((HASHCMP *) strcmp, n, hash_string);
802 
803  eventAddIsh("netdbSaveState", netdbSaveState, nullptr, 3600.0, 1);
804 
806 
807 #endif
808 }
809 
810 void
811 netdbPingSite(const char *hostname)
812 {
813 #if USE_ICMP
814  netdbEntry *n;
815 
816  if ((n = netdbLookupHost(hostname)) != nullptr)
817  if (n->next_ping_time > squid_curtime)
818  return;
819 
821  new generic_cbdata(xstrdup(hostname)));
822 #else
823  (void)hostname;
824 #endif
825 }
826 
827 void
828 netdbHandlePingReply(const Ip::Address &from, int hops, int rtt)
829 {
830 #if USE_ICMP
831  netdbEntry *n;
832  int N;
833  debugs(38, 3, "netdbHandlePingReply: from " << from);
834 
835  if ((n = netdbLookupAddr(from)) == nullptr)
836  return;
837 
838  N = ++n->pings_recv;
839 
840  if (N > 5)
841  N = 5;
842 
843  if (rtt < 1)
844  rtt = 1;
845 
846  n->hops = ((n->hops * (N - 1)) + hops) / N;
847 
848  n->rtt = ((n->rtt * (N - 1)) + rtt) / N;
849 
850  debugs(38, 3, "netdbHandlePingReply: " << n->network << "; rtt="<<
851  std::setw(5)<< std::setprecision(2) << n->rtt << " hops="<<
852  std::setw(4) << n->hops);
853 #else
854  (void)from;
855  (void)hops;
856  (void)rtt;
857 #endif
858 }
859 
860 void
862 {
863 #if USE_ICMP
864  netdbEntry *n;
865  netdbEntry **list;
866  net_db_name *x;
867  int k;
868  int i;
869  int j;
870  net_db_peer *p;
871  storeAppendPrintf(sentry, "Network DB Statistics:\n");
872  storeAppendPrintf(sentry, "%-46.46s %9s %7s %5s %s\n", /* Max between 16 (IPv4) or 46 (IPv6) */
873  "Network",
874  "recv/sent",
875  "RTT",
876  "Hops",
877  "Hostnames");
878  list = (netdbEntry **)xcalloc(netdbEntry::UseCount(), sizeof(netdbEntry *));
879  i = 0;
881 
882  while ((n = (netdbEntry *) hash_next(addr_table))) {
883  *(list + i) = n;
884  ++i;
885  }
886 
887  if (i != netdbEntry::UseCount())
888  debugs(38, DBG_CRITICAL, "WARNING: netdb_addrs count off, found " << i <<
889  ", expected " << netdbEntry::UseCount());
890 
891  qsort((char *) list,
892  i,
893  sizeof(netdbEntry *),
894  sortByRtt);
895 
896  for (k = 0; k < i; ++k) {
897  n = *(list + k);
898  storeAppendPrintf(sentry, "%-46.46s %4d/%4d %7.1f %5.1f", /* Max between 16 (IPv4) or 46 (IPv6) */
899  n->network,
900  n->pings_recv,
901  n->pings_sent,
902  n->rtt,
903  n->hops);
904 
905  for (x = n->hosts; x; x = x->next)
906  storeAppendPrintf(sentry, " %s", hashKeyStr(x));
907 
908  storeAppendPrintf(sentry, "\n");
909 
910  p = n->peers;
911 
912  for (j = 0; j < n->n_peers; ++j, ++p) {
913  storeAppendPrintf(sentry, " %-22.22s %7.1f %5.1f\n",
914  p->peername,
915  p->rtt,
916  p->hops);
917  }
918  }
919 
920  xfree(list);
921 #else
922 
923  storeAppendPrintf(sentry,"NETDB support not compiled into this Squid cache.\n");
924 #endif
925 }
926 
927 int
928 netdbHostHops(const char *host)
929 {
930 #if USE_ICMP
931  netdbEntry *n = netdbLookupHost(host);
932 
933  if (n) {
935  return (int) (n->hops + 0.5);
936  }
937 #else
938  (void)host;
939 #endif
940  return 0;
941 }
942 
943 int
944 netdbHostRtt(const char *host)
945 {
946 #if USE_ICMP
947  netdbEntry *n = netdbLookupHost(host);
948 
949  if (n) {
951  return (int) (n->rtt + 0.5);
952  }
953 
954 #else
955  (void)host;
956 #endif
957  return 0;
958 }
959 
960 void
961 netdbHostData(const char *host, int *samp, int *rtt, int *hops)
962 {
963 #if USE_ICMP
964  netdbEntry *n = netdbLookupHost(host);
965 
966  if (n == nullptr)
967  return;
968 
969  *samp = n->pings_recv;
970 
971  *rtt = (int) (n->rtt + 0.5);
972 
973  *hops = (int) (n->hops + 0.5);
974 
976 
977 #else
978  (void)hops;
979  (void)rtt;
980  (void)samp;
981  (void)host;
982 #endif
983 }
984 
985 void
986 netdbUpdatePeer(const AnyP::Uri &url, CachePeer *e, int irtt, int ihops)
987 {
988 #if USE_ICMP
989  netdbEntry *n;
990  double rtt = (double) irtt;
991  double hops = (double) ihops;
992  net_db_peer *p;
993  debugs(38, 3, url.host() << ", " << ihops << " hops, " << irtt << " rtt");
994  n = netdbLookupHost(url.host());
995 
996  if (n == nullptr) {
997  debugs(38, 3, "host " << url.host() << " not found");
998  return;
999  }
1000 
1001  if ((p = netdbPeerByName(n, e->host)) == nullptr)
1002  p = netdbPeerAdd(n, e);
1003 
1004  p->rtt = rtt;
1005 
1006  p->hops = hops;
1007 
1008  p->expires = squid_curtime + 3600;
1009 
1010  if (n->n_peers < 2)
1011  return;
1012 
1013  qsort((char *) n->peers,
1014  n->n_peers,
1015  sizeof(net_db_peer),
1016  sortPeerByRtt);
1017 
1018 #else
1019  (void)ihops;
1020  (void)irtt;
1021  (void)e;
1022  (void)url;
1023 #endif
1024 }
1025 
1026 void
1027 netdbExchangeUpdatePeer(Ip::Address &addr, CachePeer * e, double rtt, double hops)
1028 {
1029 #if USE_ICMP
1030  netdbEntry *n;
1031  net_db_peer *p;
1032  debugs(38, 5, "netdbExchangeUpdatePeer: '" << addr << "', "<<
1033  std::setfill('0')<< std::setprecision(2) << hops << " hops, " <<
1034  rtt << " rtt");
1035 
1036  if ( !addr.isIPv4() ) {
1037  debugs(38, 5, "netdbExchangeUpdatePeer: Aborting peer update for '" << addr << "', NetDB cannot handle IPv6.");
1038  return;
1039  }
1040 
1041  n = netdbLookupAddr(addr);
1042 
1043  if (n == nullptr)
1044  n = netdbAdd(addr);
1045 
1046  assert(nullptr != n);
1047 
1048  if ((p = netdbPeerByName(n, e->host)) == nullptr)
1049  p = netdbPeerAdd(n, e);
1050 
1051  p->rtt = rtt;
1052 
1053  p->hops = hops;
1054 
1055  p->expires = squid_curtime + 3600; /* XXX ? */
1056 
1057  if (n->n_peers < 2)
1058  return;
1059 
1060  qsort((char *) n->peers,
1061  n->n_peers,
1062  sizeof(net_db_peer),
1063  sortPeerByRtt);
1064 
1065 #else
1066  (void)hops;
1067  (void)rtt;
1068  (void)e;
1069  (void)addr;
1070 #endif
1071 }
1072 
1073 void
1075 {
1076 #if USE_ICMP
1077  netdbEntry *n = netdbLookupAddr(addr);
1078 
1079  if (n == nullptr)
1080  return;
1081 
1082  debugs(38, 3, "netdbDeleteAddrNetwork: " << n->network);
1083 
1084  netdbRelease(n);
1085 #else
1086  (void)addr;
1087 #endif
1088 }
1089 
1090 void
1092 {
1093  HttpReply *reply = new HttpReply;
1094 #if USE_ICMP
1095 
1096  Ip::Address addr;
1097 
1098  netdbEntry *n;
1099  int i;
1100  int j;
1101  int rec_sz;
1102  char *buf;
1103 
1104  struct in_addr line_addr;
1105  s->buffer();
1106  reply->setHeaders(Http::scOkay, "OK", nullptr, -1, squid_curtime, -2);
1107  s->replaceHttpReply(reply);
1108  rec_sz = 0;
1109  rec_sz += 1 + sizeof(struct in_addr);
1110  rec_sz += 1 + sizeof(int);
1111  rec_sz += 1 + sizeof(int);
1112  buf = (char *)memAllocate(MEM_4K_BUF);
1113  i = 0;
1115 
1116  while ((n = (netdbEntry *) hash_next(addr_table))) {
1117  if (0.0 == n->rtt)
1118  continue;
1119 
1120  if (n->rtt > 60000) /* RTT > 1 MIN probably bogus */
1121  continue;
1122 
1123  if (! (addr = n->network) )
1124  continue;
1125 
1126  // XXX: NetDB cannot yet handle IPv6 addresses
1127  if ( !addr.isIPv4() )
1128  continue;
1129 
1130  buf[i] = (char) NETDB_EX_NETWORK;
1131  ++i;
1132 
1133  addr.getInAddr(line_addr);
1134  memcpy(&buf[i], &line_addr, sizeof(struct in_addr));
1135 
1136  i += sizeof(struct in_addr);
1137 
1138  buf[i] = (char) NETDB_EX_RTT;
1139  ++i;
1140 
1141  j = htonl((int) (n->rtt * 1000));
1142 
1143  memcpy(&buf[i], &j, sizeof(int));
1144 
1145  i += sizeof(int);
1146 
1147  buf[i] = (char) NETDB_EX_HOPS;
1148  ++i;
1149 
1150  j = htonl((int) (n->hops * 1000));
1151 
1152  memcpy(&buf[i], &j, sizeof(int));
1153 
1154  i += sizeof(int);
1155 
1156  if (i + rec_sz > 4096) {
1157  s->append(buf, i);
1158  i = 0;
1159  }
1160  }
1161 
1162  if (i > 0) {
1163  s->append(buf, i);
1164  i = 0;
1165  }
1166 
1167  assert(0 == i);
1168  s->flush();
1169  memFree(buf, MEM_4K_BUF);
1170 #else
1171 
1172  reply->setHeaders(Http::scBadRequest, "Bad Request", nullptr, -1, squid_curtime, -2);
1173  s->replaceHttpReply(reply);
1174  storeAppendPrintf(s, "NETDB support not compiled into this Squid cache.\n");
1175 #endif
1176 
1177  s->complete();
1178 }
1179 
1180 void
1182 {
1183 #if USE_ICMP
1184  CachePeer *p = (CachePeer *)data;
1185  static const SBuf netDB("netdb");
1186  char *uri = internalRemoteUri(p->secure.encryptTransport, p->host, p->http_port, "/squid-internal-dynamic/", netDB);
1187  debugs(38, 3, "Requesting '" << uri << "'");
1188  const auto mx = MasterXaction::MakePortless<XactionInitiator::initIcmp>();
1190 
1191  if (!req) {
1192  debugs(38, DBG_IMPORTANT, "ERROR: " << MYNAME << ": Bad URI " << uri);
1193  return;
1194  }
1195 
1196  netdbExchangeState *ex = new netdbExchangeState(p, req);
1197  ex->e = storeCreateEntry(uri, uri, RequestFlags(), Http::METHOD_GET);
1198  assert(nullptr != ex->e);
1199 
1200  ex->sc = storeClientListAdd(ex->e, ex);
1202 
1203  ex->r->flags.loopDetected = true; /* cheat! -- force direct */
1204 
1205  // XXX: send as Proxy-Authenticate instead
1206  if (p->login)
1207  ex->r->url.userInfo(SBuf(p->login));
1208 
1210 #else
1211  (void)data;
1212 #endif
1213 }
1214 
1215 #if USE_ICMP
1216 static CachePeer *
1219 findUsableParentAtHostname(PeerSelector *ps, const char * const hostname, const HttpRequest &request)
1220 {
1221  for (const auto &peer: CurrentCachePeers()) {
1222  const auto p = peer.get();
1223  // Both fields should be lowercase, but no code ensures that invariant.
1224  // TODO: net_db_peer should point to CachePeer instead of its hostname!
1225  if (strcasecmp(p->host, hostname) != 0)
1226  continue;
1227 
1228  if (neighborType(p, request.url) != PEER_PARENT)
1229  continue;
1230 
1231  if (!peerHTTPOkay(p, ps))
1232  continue;
1233 
1234  return p;
1235  }
1236 
1237  return nullptr;
1238 }
1239 #endif
1240 
1241 CachePeer *
1243 {
1244 #if USE_ICMP
1245  assert(ps);
1246  HttpRequest *request = ps->request;
1247 
1248  netdbEntry *n;
1249  const ipcache_addrs *ia;
1250  net_db_peer *h;
1251  int i;
1252  n = netdbLookupHost(request->url.host());
1253 
1254  if (nullptr == n) {
1255  /* try IP addr */
1256  ia = ipcache_gethostbyname(request->url.host(), 0);
1257 
1258  if (nullptr != ia)
1259  n = netdbLookupAddr(ia->current());
1260  }
1261 
1262  if (nullptr == n)
1263  return nullptr;
1264 
1265  if (0 == n->n_peers)
1266  return nullptr;
1267 
1269 
1270  /*
1271  * Find the parent with the least RTT to the origin server.
1272  * Make sure we don't return a parent who is farther away than
1273  * we are. Note, the n->peers list is pre-sorted by RTT.
1274  */
1275  for (i = 0; i < n->n_peers; ++i) {
1276  h = &n->peers[i];
1277 
1278  if (n->rtt > 0)
1279  if (n->rtt < h->rtt)
1280  break;
1281 
1282  if (const auto p = findUsableParentAtHostname(ps, h->peername, *request))
1283  return p;
1284  }
1285 
1286 #else
1287  (void)ps;
1288 #endif
1289  return nullptr;
1290 }
1291 
const char * xstrerr(int error)
Definition: xstrerror.cc:83
Cbc * get() const
a temporary valid raw Cbc pointer or NULL
Definition: CbcPointer.h:159
time_t period
Definition: SquidConfig.h:274
void * xcalloc(size_t n, size_t sz)
Definition: xalloc.cc:71
AnyP::ProtocolVersion http_ver
Definition: Message.h:72
void userInfo(const SBuf &s)
Definition: Uri.h:70
#define DBG_CRITICAL
Definition: Stream.h:37
struct StoreIOBuffer::@130 flags
char * netdbFilename
Definition: SquidConfig.h:225
AnyP::Uri url
the request URI
Definition: HttpRequest.h:115
CachePeer * netdbClosestParent(PeerSelector *ps)
Definition: net_db.cc:1242
net_db_name * next
Definition: net_db.h:32
void logfileClose(Logfile *lf)
Definition: File.cc:92
int link_count
Definition: net_db.h:63
Definition: Uri.h:31
HttpRequest * request
@ scBadRequest
Definition: StatusCode.h:45
static net_db_peer * netdbPeerByName(const netdbEntry *n, const char *)
Definition: net_db.cc:386
@ scNone
Definition: StatusCode.h:21
netdb_conn_state_t
Definition: net_db.cc:53
RequestFlags flags
Definition: HttpRequest.h:141
void netdbUpdatePeer(const AnyP::Uri &url, CachePeer *e, int irtt, int ihops)
Definition: net_db.cc:986
const char * url() const
Definition: store.cc:1566
net_db_name(const char *name, netdbEntry *)
Definition: net_db.cc:138
void append(char const *, int) override
Appends a c-string to existing packed data.
Definition: store.cc:803
static void netdbReloadState(void)
Definition: net_db.cc:513
bool isAnyAddr() const
Definition: Address.cc:190
static hash_table * addr_table
Definition: net_db.cc:92
MemObject & mem()
Definition: Store.h:47
struct SquidConfig::@96 Netdb
IcmpSquid icmpEngine
Definition: IcmpSquid.cc:26
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:855
static Ip::Address networkFromInaddr(const Ip::Address &a)
Definition: net_db.cc:349
HASHHASH hash_string
Definition: hash.h:45
@ ENTRY_ABORTED
Definition: enums.h:110
void hash_remove_link(hash_table *, hash_link *)
Definition: hash.cc:220
bool loopDetected
Definition: RequestFlags.h:40
char * login
Definition: CachePeer.h:202
int64_t offset
Definition: StoreIOBuffer.h:58
static net_db_peer * netdbPeerAdd(netdbEntry *n, CachePeer *e)
Definition: net_db.cc:400
Definition: SBuf.h:93
void netdbExchangeStart(void *data)
Definition: net_db.cc:1181
store_client * sc
Definition: net_db.cc:81
#define xstrdup
static netdbEntry * netdbLookupHost(const char *key)
Definition: net_db.cc:178
bool getInAddr(struct in_addr &) const
Definition: Address.cc:1040
const ipcache_addrs * ipcache_gethostbyname(const char *name, int flags)
Definition: ipcache.cc:729
StoreIOBuffer & positionAt(const int64_t newOffset)
convenience method for changing the offset of a being-configured buffer
Definition: StoreIOBuffer.h:47
net_db_peer * peers
Definition: net_db.h:65
C * getRaw() const
Definition: RefCount.h:89
uint16_t flags
Definition: Store.h:231
CbcPointer< CachePeer > p
Definition: net_db.cc:79
hash_link * hash_lookup(hash_table *, const void *)
Definition: hash.cc:146
Http::StatusLine sline
Definition: HttpReply.h:56
const Ip::Address & current() const
Definition: ipcache.h:59
@ STATE_BODY
Definition: net_db.cc:56
int HASHCMP(const void *, const void *)
Definition: hash.h:13
int netdbHostRtt(const char *host)
Definition: net_db.cc:944
time_t last_use_time
Definition: net_db.h:62
void * memAllocate(mem_type)
Allocate one element from the typed pool.
Definition: old_api.cc:122
void replaceHttpReply(const HttpReplyPointer &, const bool andStartWriting=true)
Definition: store.cc:1705
bool isIPv4() const
Definition: Address.cc:178
CBDATA_CLASS_INIT(netdbExchangeState)
void file_close(int fd)
Definition: fs_io.cc:93
int hashPrime(int n)
Definition: hash.cc:293
#define w_space
CBDATA_CLASS(netdbExchangeState)
const char * hashKeyStr(const hash_link *)
Definition: hash.cc:313
int tvSubMsec(struct timeval t1, struct timeval t2)
Definition: gadgets.cc:51
char * toStr(char *buf, const unsigned int blen, int force=AF_UNSPEC) const
Definition: Address.cc:812
void logfilePrintf(Logfile *lf, const char *fmt,...)
Definition: File.cc:114
int n_peers
Definition: net_db.h:67
const char * c_str()
a NUL-terminated version of content(); same lifetime as content()
Definition: ParsingBuffer.h:45
peer_t neighborType(const CachePeer *p, const AnyP::Uri &url)
Definition: neighbors.cc:116
#define MAX_IPSTRLEN
Length of buffer that needs to be allocated to old a null-terminated IP-string.
Definition: forward.h:25
netdbEntry * net_db_entry
Definition: net_db.h:33
void netdbInit(void)
Definition: net_db.cc:787
char * internalRemoteUri(bool encrypt, const char *host, unsigned short port, const char *dir, const SBuf &name)
Definition: internal.cc:95
#define O_BINARY
Definition: defines.h:134
int size
Definition: ModDevPoll.cc:69
struct timeval current_time
the current UNIX time in timeval {seconds, microseconds} format
Definition: gadgets.cc:18
static int netdbLRU(const void *A, const void *B)
Definition: net_db.cc:208
static netdbEntry * netdbLookupAddr(const Ip::Address &addr)
Definition: net_db.cc:254
time_t expires
Definition: net_db.h:45
@ PEER_PARENT
Definition: enums.h:25
time_t getCurrentTime() STUB_RETVAL(0) int tvSubUsec(struct timeval
Http::StatusCode status() const
retrieve the status code for this status line
Definition: StatusLine.h:45
const HttpReply & baseReply() const
Definition: MemObject.h:60
static IPH netdbSendPing
Definition: net_db.cc:107
void netdbDump(StoreEntry *sentry)
Definition: net_db.cc:861
static uint32 A
Definition: md4.c:43
@ STATE_NONE
Definition: net_db.cc:54
void consume(size_t)
get rid of previously appended() prefix of a given size
double rtt
Definition: net_db.h:60
void appended(const char *, size_t)
remember the new bytes received into the previously provided space()
bool isIPv6() const
Definition: Address.cc:184
unsigned error
Definition: StoreIOBuffer.h:55
#define EBIT_TEST(flag, bit)
Definition: defines.h:67
void ipcache_nbgethostbyname(const char *name, IPH *handler, void *handlerData)
Definition: ipcache.cc:609
netdb_conn_state_t connstate
Definition: net_db.cc:87
int n_peers_alloc
Definition: net_db.h:66
StoreEntry * e
Definition: net_db.cc:80
static void netdbSaveState(void *)
Definition: net_db.cc:449
void debug_trap(const char *message)
Definition: tools.cc:458
int unlock(const char *context)
Definition: store.cc:469
Logfile * logfileOpen(const char *path, size_t bufsz, int fatal_flag)
Definition: File.cc:40
#define safe_free(x)
Definition: xalloc.h:73
#define assert(EX)
Definition: assert.h:17
const char * peername
associated CachePeer::host (i.e. cache_peer hostname, not name=value!)
Definition: net_db.h:41
static void netdbPurgeLRU(void)
Definition: net_db.cc:223
void EVH void double
Definition: stub_event.cc:16
HttpRequestPointer r
Definition: net_db.cc:82
void buffer() override
Definition: store.cc:1601
encapsulates DNS lookup results
Definition: LookupDetails.h:22
#define Assure(condition)
Definition: Assure.h:35
void flush() override
Definition: store.cc:1612
time_t next_ping_time
Definition: net_db.h:61
static void netdbRelease(netdbEntry *n)
Definition: net_db.cc:185
double rtt
Definition: net_db.h:44
time_t squid_curtime
Definition: stub_libtime.cc:20
void hash_first(hash_table *)
Definition: hash.cc:172
netdbExchangeState(CachePeer *aPeer, const HttpRequestPointer &theReq)
Definition: net_db.cc:64
StoreEntry * storeCreateEntry(const char *url, const char *logUrl, const RequestFlags &flags, const HttpRequestMethod &method)
Definition: store.cc:759
static int sortPeerByRtt(const void *A, const void *B)
Definition: net_db.cc:435
#define xfree
static CachePeer * findUsableParentAtHostname(PeerSelector *ps, const char *const hostname, const HttpRequest &request)
Definition: net_db.cc:1219
Definition: File.h:38
wordlist * next
Definition: wordlist.h:60
static void netdbHostInsert(netdbEntry *n, const char *hostname)
Definition: net_db.cc:150
int FD_READ_METHOD(int fd, char *buf, int len)
Definition: fde.h:194
static void netdbHashInsert(netdbEntry *n, Ip::Address &addr)
Definition: net_db.cc:117
int applyMask(const Address &mask)
Definition: Address.cc:97
void complete()
Definition: store.cc:1031
@ NETDB_EX_RTT
Definition: enums.h:180
int pings_recv
Definition: net_db.h:58
@ MEM_4K_BUF
Definition: forward.h:49
StoreIOBuffer makeInitialSpace()
Definition: ParsingBuffer.h:84
char * host
Definition: CachePeer.h:66
char * key
Definition: wordlist.h:59
int netdbHostHops(const char *host)
Definition: net_db.cc:928
static void netdbHostDelete(const net_db_name *x)
Definition: net_db.cc:158
int pings_sent
Definition: net_db.h:57
@ NETDB_EX_HOPS
Definition: enums.h:181
static hash_table * host_table
Definition: net_db.cc:93
hash_table * hash_create(HASHCMP *, int, HASHHASH *)
Definition: hash.cc:108
void memFree(void *, int type)
Free a element allocated by memAllocate()
Definition: minimal.cc:61
void RegisterAction(char const *action, char const *desc, OBJH *handler, Protected, Atomic, Format)
Definition: Registration.cc:54
static HttpRequest * FromUrlXXX(const char *url, const MasterXaction::Pointer &, const HttpRequestMethod &method=Http::METHOD_GET)
Definition: HttpRequest.cc:528
void netdbDeleteAddrNetwork(Ip::Address &addr)
Definition: net_db.cc:1074
void DomainPing(Ip::Address &to, const char *domain)
Definition: IcmpSquid.cc:177
void setAnyAddr()
NOTE: Does NOT clear the Port stored. Only the Address and Type.
Definition: Address.cc:197
@ NETDB_EX_NETWORK
Definition: enums.h:179
void netdbExchangeUpdatePeer(Ip::Address &addr, CachePeer *e, double rtt, double hops)
Definition: net_db.cc:1027
#define DBG_IMPORTANT
Definition: Stream.h:38
@ STATE_HEADER
Definition: net_db.cc:55
#define MYNAME
Definition: Stream.h:219
double hops
Definition: net_db.h:59
static void netdbHashDelete(const char *key)
Definition: net_db.cc:126
void netdbBinaryExchange(StoreEntry *s)
Definition: net_db.cc:1091
static const char * netdbPeerName(const char *name)
Definition: net_db.cc:635
Store::ParsingBuffer parsingBuffer
for receiving a NetDB reply body from Store and interpreting it
Definition: net_db.cc:85
static void fwdStart(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *)
Same as Start() but no master xaction info (AccessLogEntry) available.
Definition: FwdState.cc:407
void netdbHostData(const char *host, int *samp, int *rtt, int *hops)
Definition: net_db.cc:961
bool encryptTransport
whether transport encryption (TLS/SSL) is to be used on connections to the peer
Definition: PeerOptions.h:147
bool atEof() const
Definition: StoreClient.h:106
static wordlist * peer_names
Definition: net_db.cc:114
static STCB netdbExchangeHandleReply
Definition: net_db.cc:108
void setHeaders(Http::StatusCode status, const char *reason, const char *ctype, int64_t clen, time_t lmt, time_t expires)
Definition: HttpReply.cc:170
const CachePeers & CurrentCachePeers()
Definition: CachePeers.cc:43
void eventAddIsh(const char *name, EVH *func, void *arg, double delta_ish, int weight)
Definition: event.cc:114
int file_open(const char *path, int mode)
Definition: fs_io.cc:65
static uint32 B
Definition: md4.c:43
@ scOkay
Definition: StatusCode.h:27
int peerHTTPOkay(const CachePeer *p, PeerSelector *ps)
Definition: neighbors.cc:252
void(void *, StoreIOBuffer) STCB
Definition: StoreClient.h:32
void netdbHandlePingReply(const Ip::Address &from, int hops, int rtt)
Definition: net_db.cc:828
@ METHOD_GET
Definition: MethodType.h:25
double hops
Definition: net_db.h:43
const char * wordlistAdd(wordlist **list, const char *key)
Definition: wordlist.cc:25
int storeUnregister(store_client *sc, StoreEntry *e, void *data)
static netdbEntry * netdbAdd(Ip::Address &addr)
Definition: net_db.cc:265
Security::PeerOptions secure
security settings for peer connection
Definition: CachePeer.h:219
void storeClientCopy(store_client *sc, StoreEntry *e, StoreIOBuffer copyInto, STCB *callback, void *data)
size_t contentSize() const
the total number of append()ed bytes that were not consume()d
void host(const char *src)
Definition: Uri.cc:123
StoreIOBuffer space()
void netdbPingSite(const char *hostname)
Definition: net_db.cc:811
hash_link * hash_next(hash_table *)
Definition: hash.cc:188
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
net_db_name * hosts
Definition: net_db.h:64
char network[MAX_IPSTRLEN]
Definition: net_db.h:56
void hash_join(hash_table *, hash_link *)
Definition: hash.cc:131
unsigned short http_port
Definition: CachePeer.h:104
void IPH(const ipcache_addrs *, const Dns::LookupDetails &details, void *)
Definition: ipcache.h:227
static int sortByRtt(const void *A, const void *B)
Definition: net_db.cc:372
class SquidConfig Config
Definition: SquidConfig.cc:12
store_client * storeClientListAdd(StoreEntry *e, void *data)
int unsigned int
Definition: stub_fd.cc:19
AnyP::ProtocolVersion ProtocolVersion(unsigned int aMajor, unsigned int aMinor)
HTTP version label information.

 

Introduction

Documentation

Support

Miscellaneous