2 * DEBUG: section 38 Network Measurement Database
3 * AUTHOR: Duane Wessels
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
36 * This code may be slightly broken now. If you're getting consistent
37 * (sometimes working) corrupt data exchanges, please contact adrian
38 * (adrian@squid-cache.org) to sort them out.
42 #include "icmp/net_db.h"
46 #include "CacheManager.h"
49 #include "HttpRequest.h"
50 #include "HttpReply.h"
51 #include "MemObject.h"
54 #include "SquidTime.h"
56 #include "ip/IpAddress.h"
59 #include "icmp/IcmpSquid.h"
60 #include "StoreClient.h"
62 #define NETDB_REQBUF_SZ 4096
77 char buf
[NETDB_REQBUF_SZ
];
79 netdb_conn_state_t connstate
;
82 static hash_table
*addr_table
= NULL
;
83 static hash_table
*host_table
= NULL
;
85 IpAddress
networkFromInaddr(const IpAddress
&a
);
86 static void netdbRelease(netdbEntry
* n
);
88 static void netdbHashInsert(netdbEntry
* n
, IpAddress
&addr
);
89 static void netdbHashDelete(const char *key
);
90 static void netdbHostInsert(netdbEntry
* n
, const char *hostname
);
91 static void netdbHostDelete(const net_db_name
* x
);
92 static void netdbPurgeLRU(void);
93 static netdbEntry
*netdbLookupHost(const char *key
);
94 static net_db_peer
*netdbPeerByName(const netdbEntry
* n
, const char *);
95 static net_db_peer
*netdbPeerAdd(netdbEntry
* n
, peer
* e
);
96 static const char *netdbPeerName(const char *name
);
97 static IPH netdbSendPing
;
98 static QS sortPeerByRtt
;
101 static FREE netdbFreeNameEntry
;
102 static FREE netdbFreeNetdbEntry
;
103 static STCB netdbExchangeHandleReply
;
104 static void netdbExchangeDone(void *);
106 /* We have to keep a local list of peer names. The Peers structure
107 * gets freed during a reconfigure. We want this database to
108 * remain persisitent, so _net_db_peer->peername points into this
110 static wordlist
*peer_names
= NULL
;
113 netdbHashInsert(netdbEntry
* n
, IpAddress
&addr
)
115 networkFromInaddr(addr
).NtoA(n
->network
, MAX_IPSTRLEN
);
116 n
->hash
.key
= n
->network
;
117 assert(hash_lookup(addr_table
, n
->network
) == NULL
);
118 hash_join(addr_table
, &n
->hash
);
122 netdbHashDelete(const char *key
)
124 hash_link
*hptr
= (hash_link
*)hash_lookup(addr_table
, key
);
127 debug_trap("netdbHashDelete: key not found");
131 hash_remove_link(addr_table
, hptr
);
135 netdbHostInsert(netdbEntry
* n
, const char *hostname
)
137 net_db_name
*x
= (net_db_name
*)memAllocate(MEM_NET_DB_NAME
);
138 x
->hash
.key
= xstrdup(hostname
);
142 assert(hash_lookup(host_table
, hostname
) == NULL
);
143 hash_join(host_table
, &x
->hash
);
148 netdbHostDelete(const net_db_name
* x
)
153 assert(x
->net_db_entry
!= NULL
);
157 for (X
= &n
->hosts
; *X
; X
= &(*X
)->next
) {
164 hash_remove_link(host_table
, (hash_link
*) x
);
166 memFree((void *) x
, MEM_NET_DB_NAME
);
170 netdbLookupHost(const char *key
)
172 net_db_name
*x
= (net_db_name
*) hash_lookup(host_table
, key
);
173 return x
? x
->net_db_entry
: NULL
;
177 netdbRelease(netdbEntry
* n
)
182 for (x
= n
->hosts
; x
; x
= next
) {
191 n
->n_peers_alloc
= 0;
193 if (n
->link_count
== 0) {
194 netdbHashDelete(n
->network
);
195 memFree(n
, MEM_NETDBENTRY
);
200 netdbLRU(const void *A
, const void *B
)
202 const netdbEntry
*const *n1
= (const netdbEntry
*const *)A
;
203 const netdbEntry
*const *n2
= (const netdbEntry
*const *)B
;
205 if ((*n1
)->last_use_time
> (*n2
)->last_use_time
)
208 if ((*n1
)->last_use_time
< (*n2
)->last_use_time
)
222 list
= (netdbEntry
**)xcalloc(memInUse(MEM_NETDBENTRY
), sizeof(netdbEntry
*));
223 hash_first(addr_table
);
225 while ((n
= (netdbEntry
*) hash_next(addr_table
))) {
226 assert(list_count
< memInUse(MEM_NETDBENTRY
));
227 *(list
+ list_count
) = n
;
233 sizeof(netdbEntry
*),
236 for (k
= 0; k
< list_count
; k
++) {
237 if (memInUse(MEM_NETDBENTRY
) < Config
.Netdb
.low
)
240 netdbRelease(*(list
+ k
));
249 netdbLookupAddr(const IpAddress
&addr
)
252 char *key
= new char[MAX_IPSTRLEN
];
253 networkFromInaddr(addr
).NtoA(key
,MAX_IPSTRLEN
);
254 n
= (netdbEntry
*) hash_lookup(addr_table
, key
);
259 netdbAdd(IpAddress
&addr
)
263 if (memInUse(MEM_NETDBENTRY
) > Config
.Netdb
.high
)
266 if ((n
= netdbLookupAddr(addr
)) == NULL
) {
267 n
= (netdbEntry
*)memAllocate(MEM_NETDBENTRY
);
268 netdbHashInsert(n
, addr
);
275 netdbSendPing(const ipcache_addrs
*ia
, const DnsLookupDetails
&, void *data
)
278 char *hostname
= NULL
;
279 static_cast<generic_cbdata
*>(data
)->unwrap(&hostname
);
290 addr
= ia
->in_addrs
[ia
->cur
];
292 if ((n
= netdbLookupHost(hostname
)) == NULL
) {
294 netdbHostInsert(n
, hostname
);
295 } else if ((na
= netdbLookupAddr(addr
)) != n
) {
297 *hostname moved from 'network n' to 'network na'!
303 debugs(38, 3, "netdbSendPing: " << hostname
<< " moved from " << n
->network
<< " to " << na
->network
);
305 x
= (net_db_name
*) hash_lookup(host_table
, hostname
);
308 debugs(38, 1, "netdbSendPing: net_db_name list bug: " << hostname
<< " not found");
313 /* remove net_db_name from 'network n' linked list */
314 for (X
= &n
->hosts
; *X
; X
= &(*X
)->next
) {
322 /* point to 'network na' from host entry */
323 x
->net_db_entry
= na
;
324 /* link net_db_name to 'network na' */
331 if (n
->next_ping_time
<= squid_curtime
) {
332 debugs(38, 3, "netdbSendPing: pinging " << hostname
);
333 icmpEngine
.DomainPing(addr
, hostname
);
335 n
->next_ping_time
= squid_curtime
+ Config
.Netdb
.period
;
336 n
->last_use_time
= squid_curtime
;
343 networkFromInaddr(const IpAddress
&in
)
350 /* in IPv6 the 'network' should be the routing section. */
353 out
.ApplyMask(64, AF_INET6
);
354 debugs(14, 5, "networkFromInaddr : Masked IPv6 Address to " << in
<< "/64 routing part.");
364 if (IN_CLASSC(b
.s_addr
))
365 b
.s_addr
&= IN_CLASSC_NET
;
366 else if (IN_CLASSB(b
.s_addr
))
367 b
.s_addr
&= IN_CLASSB_NET
;
368 else if (IN_CLASSA(b
.s_addr
))
369 b
.s_addr
&= IN_CLASSA_NET
;
375 debugs(14, 5, "networkFromInaddr : Masked IPv4 Address to " << out
<< "/24.");
377 /* use /24 for everything under IPv4 */
378 out
.ApplyMask(24, AF_INET
);
379 debugs(14, 5, "networkFromInaddr : Masked IPv4 Address to " << in
<< "/24.");
385 sortByRtt(const void *A
, const void *B
)
387 const netdbEntry
*const *n1
= (const netdbEntry
*const *)A
;
388 const netdbEntry
*const *n2
= (const netdbEntry
*const *)B
;
390 if ((*n1
)->rtt
> (*n2
)->rtt
)
392 else if ((*n1
)->rtt
< (*n2
)->rtt
)
399 netdbPeerByName(const netdbEntry
* n
, const char *peername
)
402 net_db_peer
*p
= n
->peers
;
404 for (i
= 0; i
< n
->n_peers
; i
++, p
++) {
405 if (!strcmp(p
->peername
, peername
))
413 netdbPeerAdd(netdbEntry
* n
, peer
* e
)
420 if (n
->n_peers
== n
->n_peers_alloc
) {
422 osize
= n
->n_peers_alloc
;
424 if (n
->n_peers_alloc
== 0)
425 n
->n_peers_alloc
= 2;
427 n
->n_peers_alloc
<<= 1;
429 debugs(38, 3, "netdbPeerAdd: Growing peer list for '" << n
->network
<< "' to " << n
->n_peers_alloc
);
431 n
->peers
= (net_db_peer
*)xcalloc(n
->n_peers_alloc
, sizeof(net_db_peer
));
433 for (i
= 0; i
< osize
; i
++)
434 *(n
->peers
+ i
) = *(o
+ i
);
441 p
= n
->peers
+ n
->n_peers
;
442 p
->peername
= netdbPeerName(e
->host
);
448 sortPeerByRtt(const void *A
, const void *B
)
450 const net_db_peer
*p1
= (net_db_peer
*)A
;
451 const net_db_peer
*p2
= (net_db_peer
*)B
;
453 if (p1
->rtt
> p2
->rtt
)
455 else if (p1
->rtt
< p2
->rtt
)
462 netdbSaveState(void *foo
)
464 if (strcmp(Config
.netdbFilename
, "none") == 0)
471 struct timeval start
= current_time
;
474 * This was nicer when we were using stdio, but thanks to
475 * Solaris bugs, its a bad idea. fopen can fail if more than
479 * unlink() is here because there is currently no way to make
480 * logfileOpen() use O_TRUNC.
482 unlink(Config
.netdbFilename
);
483 lf
= logfileOpen(Config
.netdbFilename
, 4096, 0);
486 debugs(50, 1, "netdbSaveState: " << Config
.netdbFilename
<< ": " << xstrerror());
490 hash_first(addr_table
);
492 while ((n
= (netdbEntry
*) hash_next(addr_table
))) {
493 if (n
->pings_recv
== 0)
496 logfilePrintf(lf
, "%s %d %d %10.5f %10.5f %d %d",
502 (int) n
->next_ping_time
,
503 (int) n
->last_use_time
);
505 for (x
= n
->hosts
; x
; x
= x
->next
)
506 logfilePrintf(lf
, " %s", hashKeyStr(&x
->hash
));
508 logfilePrintf(lf
, "\n");
518 debugs(38, 1, "NETDB state saved; " <<
519 count
<< " entries, " <<
520 tvSubMsec(start
, current_time
) << " msec" );
521 eventAddIsh("netdbSaveState", netdbSaveState
, NULL
, 3600.0, 1);
525 netdbReloadState(void)
527 if (strcmp(Config
.netdbFilename
, "none") == 0)
541 struct timeval start
= current_time
;
543 * This was nicer when we were using stdio, but thanks to
544 * Solaris bugs, its a bad idea. fopen can fail if more than
547 fd
= file_open(Config
.netdbFilename
, O_RDONLY
| O_BINARY
);
552 if (fstat(fd
, &sb
) < 0) {
558 char *buf
= (char *)xcalloc(1, sb
.st_size
+ 1);
560 l
= FD_READ_METHOD(fd
, buf
, sb
.st_size
);
568 while ((s
= strchr(t
, '\n'))) {
572 memset(&N
, '\0', sizeof(netdbEntry
));
573 q
= strtok(t
, w_space
);
582 if (netdbLookupAddr(addr
) != NULL
) /* no dups! */
585 if ((q
= strtok(NULL
, w_space
)) == NULL
)
588 N
.pings_sent
= atoi(q
);
590 if ((q
= strtok(NULL
, w_space
)) == NULL
)
593 N
.pings_recv
= atoi(q
);
595 if (N
.pings_recv
== 0)
598 /* give this measurement low weight */
603 if ((q
= strtok(NULL
, w_space
)) == NULL
)
608 if ((q
= strtok(NULL
, w_space
)) == NULL
)
613 if ((q
= strtok(NULL
, w_space
)) == NULL
)
616 N
.next_ping_time
= (time_t) atoi(q
);
618 if ((q
= strtok(NULL
, w_space
)) == NULL
)
621 N
.last_use_time
= (time_t) atoi(q
);
623 n
= (netdbEntry
*)memAllocate(MEM_NETDBENTRY
);
625 xmemcpy(n
, &N
, sizeof(netdbEntry
));
627 netdbHashInsert(n
, addr
);
629 while ((q
= strtok(NULL
, w_space
)) != NULL
) {
630 if (netdbLookupHost(q
) != NULL
) /* no dups! */
633 netdbHostInsert(n
, q
);
641 debugs(38, 1, "NETDB state reloaded; " <<
642 count
<< " entries, " <<
643 tvSubMsec(start
, current_time
) << " msec" );
647 netdbPeerName(const char *name
)
651 for (w
= peer_names
; w
; w
= w
->next
) {
652 if (!strcmp(w
->key
, name
))
656 return wordlistAdd(&peer_names
, name
);
660 netdbFreeNetdbEntry(void *data
)
662 netdbEntry
*n
= (netdbEntry
*)data
;
664 memFree(n
, MEM_NETDBENTRY
);
668 netdbFreeNameEntry(void *data
)
670 net_db_name
*x
= (net_db_name
*)data
;
672 memFree(x
, MEM_NET_DB_NAME
);
677 netdbExchangeHandleReply(void *data
, StoreIOBuffer receivedData
)
681 netdbExchangeState
*ex
= (netdbExchangeState
*)data
;
685 struct in_addr line_addr
;
690 HttpReply
const *rep
;
694 int oldbufofs
= ex
->buf_ofs
;
697 rec_sz
+= 1 + sizeof(struct in_addr
);
698 rec_sz
+= 1 + sizeof(int);
699 rec_sz
+= 1 + sizeof(int);
700 debugs(38, 3, "netdbExchangeHandleReply: " << receivedData
.length
<< " read bytes");
702 if (!cbdataReferenceValid(ex
->p
)) {
703 debugs(38, 3, "netdbExchangeHandleReply: Peer became invalid");
704 netdbExchangeDone(ex
);
708 debugs(38, 3, "netdbExchangeHandleReply: for '" << ex
->p
->host
<< ":" << ex
->p
->http_port
<< "'");
710 if (receivedData
.length
== 0 &&
711 !receivedData
.flags
.error
) {
712 debugs(38, 3, "netdbExchangeHandleReply: Done");
713 netdbExchangeDone(ex
);
719 /* Get the size of the buffer now */
720 size
= ex
->buf_ofs
+ receivedData
.length
;
721 debugs(38, 3, "netdbExchangeHandleReply: " << size
<< " bytes buf");
723 /* Check if we're still doing headers */
725 if (ex
->connstate
== STATE_HEADER
) {
727 ex
->buf_ofs
+= receivedData
.length
;
729 /* skip reply headers */
731 if ((hdr_sz
= headersEnd(p
, ex
->buf_ofs
))) {
732 debugs(38, 5, "netdbExchangeHandleReply: hdr_sz = " << hdr_sz
);
733 rep
= ex
->e
->getReply();
734 assert (0 != rep
->sline
.status
);
735 debugs(38, 3, "netdbExchangeHandleReply: reply status " << rep
->sline
.status
);
737 if (HTTP_OK
!= rep
->sline
.status
) {
738 netdbExchangeDone(ex
);
742 assert((size_t)ex
->buf_ofs
>= hdr_sz
);
745 * Now, point p to the part of the buffer where the data
746 * starts, and update the size accordingly
748 assert(ex
->used
== 0);
750 size
= ex
->buf_ofs
- hdr_sz
;
753 /* Finally, set the conn state mode to STATE_BODY */
754 ex
->connstate
= STATE_BODY
;
756 StoreIOBuffer tempBuffer
;
757 tempBuffer
.offset
= ex
->buf_ofs
;
758 tempBuffer
.length
= ex
->buf_sz
- ex
->buf_ofs
;
759 tempBuffer
.data
= ex
->buf
+ ex
->buf_ofs
;
760 /* Have more headers .. */
761 storeClientCopy(ex
->sc
, ex
->e
, tempBuffer
,
762 netdbExchangeHandleReply
, ex
);
767 assert(ex
->connstate
== STATE_BODY
);
769 /* If we get here, we have some body to parse .. */
770 debugs(38, 5, "netdbExchangeHandleReply: start parsing loop, size = " << size
);
772 while (size
>= rec_sz
) {
773 debugs(38, 5, "netdbExchangeHandleReply: in parsing loop, size = " << size
);
777 for (o
= 0; o
< rec_sz
;) {
778 switch ((int) *(p
+ o
)) {
780 case NETDB_EX_NETWORK
:
782 /* FIXME INET6 : NetDB can still ony send IPv4 */
783 xmemcpy(&line_addr
, p
+ o
, sizeof(struct in_addr
));
785 o
+= sizeof(struct in_addr
);
790 xmemcpy(&j
, p
+ o
, sizeof(int));
792 rtt
= (double) ntohl(j
) / 1000.0;
797 xmemcpy(&j
, p
+ o
, sizeof(int));
799 hops
= (double) ntohl(j
) / 1000.0;
803 debugs(38, 1, "netdbExchangeHandleReply: corrupt data, aborting");
804 netdbExchangeDone(ex
);
809 if (!addr
.IsAnyAddr() && rtt
> 0)
810 netdbExchangeUpdatePeer(addr
, ex
->p
, rtt
, hops
);
824 * Copy anything that is left over to the beginning of the buffer,
825 * and adjust buf_ofs accordingly
829 * Evilly, size refers to the buf size left now,
830 * ex->buf_ofs is the original buffer size, so just copy that
833 memmove(ex
->buf
, ex
->buf
+ (ex
->buf_ofs
- size
), size
);
838 * And don't re-copy the remaining data ..
843 * Now the tricky bit - size _included_ the leftover bit from the _last_
844 * storeClientCopy. We don't want to include that, or our offset will be wrong.
845 * So, don't count the size of the leftover buffer we began with.
846 * This can _disappear_ when we're not tracking offsets ..
848 ex
->used
-= oldbufofs
;
850 debugs(38, 3, "netdbExchangeHandleReply: size left over in this buffer: " << size
<< " bytes");
852 debugs(38, 3, "netdbExchangeHandleReply: used " << nused
<<
853 " entries, (x " << rec_sz
<< " bytes) == " << nused
* rec_sz
<<
856 debugs(38, 3, "netdbExchangeHandleReply: used " << ex
->used
);
858 if (EBIT_TEST(ex
->e
->flags
, ENTRY_ABORTED
)) {
859 debugs(38, 3, "netdbExchangeHandleReply: ENTRY_ABORTED");
860 netdbExchangeDone(ex
);
861 } else if (ex
->e
->store_status
== STORE_PENDING
) {
862 StoreIOBuffer tempBuffer
;
863 tempBuffer
.offset
= ex
->used
;
864 tempBuffer
.length
= ex
->buf_sz
- ex
->buf_ofs
;
865 tempBuffer
.data
= ex
->buf
+ ex
->buf_ofs
;
866 debugs(38, 3, "netdbExchangeHandleReply: EOF not received");
867 storeClientCopy(ex
->sc
, ex
->e
, tempBuffer
,
868 netdbExchangeHandleReply
, ex
);
873 netdbExchangeDone(void *data
)
875 netdbExchangeState
*ex
= (netdbExchangeState
*)data
;
876 debugs(38, 3, "netdbExchangeDone: " << ex
->e
->url() );
877 HTTPMSGUNLOCK(ex
->r
);
878 storeUnregister(ex
->sc
, ex
->e
, ex
);
880 cbdataReferenceDone(ex
->p
);
885 netdbRegisterWithCacheManager(void)
887 CacheManager::GetInstance()->
888 registerAction("netdb", "Network Measurement Database", netdbDump
, 0, 1);
891 #endif /* USE_ICMP */
894 /* PUBLIC FUNCTIONS */
902 netdbRegisterWithCacheManager();
907 n
= hashPrime(Config
.Netdb
.high
/ 4);
909 addr_table
= hash_create((HASHCMP
*) strcmp
, n
, hash_string
);
911 n
= hashPrime(3 * Config
.Netdb
.high
/ 4);
913 host_table
= hash_create((HASHCMP
*) strcmp
, n
, hash_string
);
915 eventAddIsh("netdbSaveState", netdbSaveState
, NULL
, 3600.0, 1);
923 netdbPingSite(const char *hostname
)
928 if ((n
= netdbLookupHost(hostname
)) != NULL
)
929 if (n
->next_ping_time
> squid_curtime
)
932 ipcache_nbgethostbyname(hostname
, netdbSendPing
,
933 new generic_cbdata(xstrdup(hostname
)));
939 netdbHandlePingReply(const IpAddress
&from
, int hops
, int rtt
)
944 debugs(38, 3, "netdbHandlePingReply: from " << from
);
946 if ((n
= netdbLookupAddr(from
)) == NULL
)
957 n
->hops
= ((n
->hops
* (N
- 1)) + hops
) / N
;
959 n
->rtt
= ((n
->rtt
* (N
- 1)) + rtt
) / N
;
961 debugs(38, 3, "netdbHandlePingReply: " << n
->network
<< "; rtt="<<
962 std::setw(5)<< std::setprecision(2) << n
->rtt
<< " hops="<<
963 std::setw(4) << n
->hops
);
969 netdbFreeMemory(void)
972 hashFreeItems(addr_table
, netdbFreeNetdbEntry
);
973 hashFreeMemory(addr_table
);
975 hashFreeItems(host_table
, netdbFreeNameEntry
);
976 hashFreeMemory(host_table
);
978 wordlistDestroy(&peer_names
);
984 #if 0 // AYJ: Looks to be unused code.
986 netdbHops(IpAddress
&addr
)
989 netdbEntry
*n
= netdbLookupAddr(addr
);
991 if (n
&& n
->pings_recv
) {
992 n
->last_use_time
= squid_curtime
;
993 return (int) (n
->hops
+ 0.5);
1002 netdbDump(StoreEntry
* sentry
)
1012 storeAppendPrintf(sentry
, "Network DB Statistics:\n");
1013 storeAppendPrintf(sentry
, "%-46.46s %9s %7s %5s %s\n", /* Max between 16 (IPv4) or 46 (IPv6) */
1019 list
= (netdbEntry
**)xcalloc(memInUse(MEM_NETDBENTRY
), sizeof(netdbEntry
*));
1021 hash_first(addr_table
);
1023 while ((n
= (netdbEntry
*) hash_next(addr_table
)))
1026 if (i
!= memInUse(MEM_NETDBENTRY
))
1027 debugs(38, 0, "WARNING: netdb_addrs count off, found " << i
<<
1028 ", expected " << memInUse(MEM_NETDBENTRY
));
1030 qsort((char *) list
,
1032 sizeof(netdbEntry
*),
1035 for (k
= 0; k
< i
; k
++) {
1037 storeAppendPrintf(sentry
, "%-46.46s %4d/%4d %7.1f %5.1f", /* Max between 16 (IPv4) or 46 (IPv6) */
1044 for (x
= n
->hosts
; x
; x
= x
->next
)
1045 storeAppendPrintf(sentry
, " %s", hashKeyStr(&x
->hash
));
1047 storeAppendPrintf(sentry
, "\n");
1051 for (j
= 0; j
< n
->n_peers
; j
++, p
++) {
1052 storeAppendPrintf(sentry
, " %-22.22s %7.1f %5.1f\n",
1062 storeAppendPrintf(sentry
,"NETDB support not compiled into this Squid cache.\n");
1067 netdbHostHops(const char *host
)
1070 netdbEntry
*n
= netdbLookupHost(host
);
1073 n
->last_use_time
= squid_curtime
;
1074 return (int) (n
->hops
+ 0.5);
1082 netdbHostRtt(const char *host
)
1085 netdbEntry
*n
= netdbLookupHost(host
);
1088 n
->last_use_time
= squid_curtime
;
1089 return (int) (n
->rtt
+ 0.5);
1097 netdbHostData(const char *host
, int *samp
, int *rtt
, int *hops
)
1100 netdbEntry
*n
= netdbLookupHost(host
);
1105 *samp
= n
->pings_recv
;
1107 *rtt
= (int) (n
->rtt
+ 0.5);
1109 *hops
= (int) (n
->hops
+ 0.5);
1111 n
->last_use_time
= squid_curtime
;
1117 netdbUpdatePeer(HttpRequest
* r
, peer
* e
, int irtt
, int ihops
)
1121 double rtt
= (double) irtt
;
1122 double hops
= (double) ihops
;
1124 debugs(38, 3, "netdbUpdatePeer: '" << r
->GetHost() << "', " << ihops
<< " hops, " << irtt
<< " rtt");
1125 n
= netdbLookupHost(r
->GetHost());
1128 debugs(38, 3, "netdbUpdatePeer: host '" << r
->GetHost() << "' not found");
1132 if ((p
= netdbPeerByName(n
, e
->host
)) == NULL
)
1133 p
= netdbPeerAdd(n
, e
);
1139 p
->expires
= squid_curtime
+ 3600;
1144 qsort((char *) n
->peers
,
1146 sizeof(net_db_peer
),
1153 netdbExchangeUpdatePeer(IpAddress
&addr
, peer
* e
, double rtt
, double hops
)
1158 debugs(38, 5, "netdbExchangeUpdatePeer: '" << addr
<< "', "<<
1159 std::setfill('0')<< std::setprecision(2) << hops
<< " hops, " <<
1162 if ( !addr
.IsIPv4() ) {
1163 debugs(38, 5, "netdbExchangeUpdatePeer: Aborting peer update for '" << addr
<< "', NetDB cannot handle IPv6.");
1167 n
= netdbLookupAddr(addr
);
1174 if ((p
= netdbPeerByName(n
, e
->host
)) == NULL
)
1175 p
= netdbPeerAdd(n
, e
);
1181 p
->expires
= squid_curtime
+ 3600; /* XXX ? */
1186 qsort((char *) n
->peers
,
1188 sizeof(net_db_peer
),
1195 netdbDeleteAddrNetwork(IpAddress
&addr
)
1198 netdbEntry
*n
= netdbLookupAddr(addr
);
1203 debugs(38, 3, "netdbDeleteAddrNetwork: " << n
->network
);
1211 netdbBinaryExchange(StoreEntry
* s
)
1213 HttpReply
*reply
= new HttpReply
;
1224 struct in_addr line_addr
;
1226 HttpVersion
version(1, 0);
1227 reply
->setHeaders(version
, HTTP_OK
, "OK", NULL
, -1, squid_curtime
, -2);
1228 s
->replaceHttpReply(reply
);
1230 rec_sz
+= 1 + sizeof(struct in_addr
);
1231 rec_sz
+= 1 + sizeof(int);
1232 rec_sz
+= 1 + sizeof(int);
1233 buf
= (char *)memAllocate(MEM_4K_BUF
);
1235 hash_first(addr_table
);
1237 while ((n
= (netdbEntry
*) hash_next(addr_table
))) {
1241 if (n
->rtt
> 60000) /* RTT > 1 MIN probably bogus */
1244 if (! (addr
= n
->network
) )
1247 /* FIXME INET6 : NetDB cannot yet handle IPv6 addresses. Ensure only IPv4 get sent. */
1248 if ( !addr
.IsIPv4() )
1251 buf
[i
++] = (char) NETDB_EX_NETWORK
;
1253 addr
.GetInAddr(line_addr
);
1254 xmemcpy(&buf
[i
], &line_addr
, sizeof(struct in_addr
));
1256 i
+= sizeof(struct in_addr
);
1258 buf
[i
++] = (char) NETDB_EX_RTT
;
1260 j
= htonl((int) (n
->rtt
* 1000));
1262 xmemcpy(&buf
[i
], &j
, sizeof(int));
1266 buf
[i
++] = (char) NETDB_EX_HOPS
;
1268 j
= htonl((int) (n
->hops
* 1000));
1270 xmemcpy(&buf
[i
], &j
, sizeof(int));
1274 if (i
+ rec_sz
> 4096) {
1287 memFree(buf
, MEM_4K_BUF
);
1290 HttpVersion
version(1,0);
1291 reply
->setHeaders(version
, HTTP_BAD_REQUEST
, "Bad Request",
1292 NULL
, -1, squid_curtime
, -2);
1293 s
->replaceHttpReply(reply
);
1294 storeAppendPrintf(s
, "NETDB support not compiled into this Squid cache.\n");
1301 CBDATA_TYPE(netdbExchangeState
);
1305 netdbExchangeStart(void *data
)
1308 peer
*p
= (peer
*)data
;
1310 netdbExchangeState
*ex
;
1311 StoreIOBuffer tempBuffer
;
1312 CBDATA_INIT_TYPE(netdbExchangeState
);
1313 ex
= cbdataAlloc(netdbExchangeState
);
1314 ex
->p
= cbdataReference(p
);
1315 uri
= internalRemoteUri(p
->host
, p
->http_port
, "/squid-internal-dynamic/", "netdb");
1316 debugs(38, 3, "netdbExchangeStart: Requesting '" << uri
<< "'");
1317 assert(NULL
!= uri
);
1318 ex
->r
= HttpRequest::CreateFromUrl(uri
);
1320 if (NULL
== ex
->r
) {
1321 debugs(38, 1, "netdbExchangeStart: Bad URI " << uri
);
1326 assert(NULL
!= ex
->r
);
1327 ex
->r
->http_ver
= HttpVersion(1,0);
1328 ex
->connstate
= STATE_HEADER
;
1329 ex
->e
= storeCreateEntry(uri
, uri
, request_flags(), METHOD_GET
);
1330 ex
->buf_sz
= NETDB_REQBUF_SZ
;
1331 assert(NULL
!= ex
->e
);
1332 ex
->sc
= storeClientListAdd(ex
->e
, ex
);
1333 tempBuffer
.offset
= 0;
1334 tempBuffer
.length
= ex
->buf_sz
;
1335 tempBuffer
.data
= ex
->buf
;
1336 storeClientCopy(ex
->sc
, ex
->e
, tempBuffer
,
1337 netdbExchangeHandleReply
, ex
);
1338 ex
->r
->flags
.loopdetect
= 1; /* cheat! -- force direct */
1341 xstrncpy(ex
->r
->login
, p
->login
, MAX_LOGIN_SZ
);
1343 urlCanonical(ex
->r
);
1345 FwdState::fwdStart(-1, ex
->e
, ex
->r
);
1351 netdbClosestParent(HttpRequest
* request
)
1356 const ipcache_addrs
*ia
;
1359 n
= netdbLookupHost(request
->GetHost());
1363 ia
= ipcache_gethostbyname(request
->GetHost(), 0);
1366 n
= netdbLookupAddr(ia
->in_addrs
[ia
->cur
]);
1372 if (0 == n
->n_peers
)
1375 n
->last_use_time
= squid_curtime
;
1378 * Find the parent with the least RTT to the origin server.
1379 * Make sure we don't return a parent who is farther away than
1380 * we are. Note, the n->peers list is pre-sorted by RTT.
1382 for (i
= 0; i
< n
->n_peers
; i
++) {
1386 if (n
->rtt
< h
->rtt
)
1389 p
= peerFindByName(h
->peername
);
1391 if (NULL
== p
) /* not found */
1394 if (neighborType(p
, request
) != PEER_PARENT
)
1397 if (!peerHTTPOkay(p
, request
)) /* not allowed */