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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors