3 * $Id: net_db.cc,v 1.172 2003/08/10 11:00:44 robertc Exp $
5 * DEBUG: section 38 Network Measurement Database
6 * AUTHOR: Duane Wessels
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
39 * This code may be slightly broken now. If you're getting consistent
40 * (sometimes working) corrupt data exchanges, please contact adrian
41 * (adrian@squid-cache.org) to sort them out.
46 #include "HttpRequest.h"
47 #include "HttpReply.h"
48 #include "MemObject.h"
53 #include "StoreClient.h"
55 #define NETDB_REQBUF_SZ 4096
71 char buf
[NETDB_REQBUF_SZ
];
73 netdb_conn_state_t connstate
;
78 static hash_table
*addr_table
= NULL
;
79 static hash_table
*host_table
= NULL
;
81 static struct in_addr
networkFromInaddr(struct in_addr a
);
82 static void netdbRelease(netdbEntry
* n
);
84 static void netdbHashInsert(netdbEntry
* n
, struct in_addr addr
);
85 static void netdbHashDelete(const char *key
);
86 static void netdbHostInsert(netdbEntry
* n
, const char *hostname
);
87 static void netdbHostDelete(const net_db_name
* x
);
88 static void netdbPurgeLRU(void);
89 static netdbEntry
*netdbLookupHost(const char *key
);
90 static net_db_peer
*netdbPeerByName(const netdbEntry
* n
, const char *);
91 static net_db_peer
*netdbPeerAdd(netdbEntry
* n
, peer
* e
);
92 static const char *netdbPeerName(const char *name
);
93 static IPH netdbSendPing
;
94 static QS sortPeerByRtt
;
97 static FREE netdbFreeNameEntry
;
98 static FREE netdbFreeNetdbEntry
;
99 static STCB netdbExchangeHandleReply
;
100 static void netdbExchangeDone(void *);
102 /* We have to keep a local list of peer names. The Peers structure
103 * gets freed during a reconfigure. We want this database to
104 * remain persisitent, so _net_db_peer->peername points into this
106 static wordlist
*peer_names
= NULL
;
110 netdbHashInsert(netdbEntry
* n
, struct in_addr addr
)
112 xstrncpy(n
->network
, inet_ntoa(networkFromInaddr(addr
)), 16);
113 n
->hash
.key
= n
->network
;
114 assert(hash_lookup(addr_table
, n
->network
) == NULL
);
115 hash_join(addr_table
, &n
->hash
);
119 netdbHashDelete(const char *key
)
121 hash_link
*hptr
= (hash_link
*)hash_lookup(addr_table
, key
);
124 debug_trap("netdbHashDelete: key not found");
128 hash_remove_link(addr_table
, hptr
);
132 netdbHostInsert(netdbEntry
* n
, const char *hostname
)
134 net_db_name
*x
= (net_db_name
*)memAllocate(MEM_NET_DB_NAME
);
135 x
->hash
.key
= xstrdup(hostname
);
139 assert(hash_lookup(host_table
, hostname
) == NULL
);
140 hash_join(host_table
, &x
->hash
);
145 netdbHostDelete(const net_db_name
* x
)
150 assert(x
->net_db_entry
!= NULL
);
154 for (X
= &n
->hosts
; *X
; X
= &(*X
)->next
) {
161 hash_remove_link(host_table
, (hash_link
*) x
);
163 memFree((void *) x
, MEM_NET_DB_NAME
);
167 netdbLookupHost(const char *key
)
169 net_db_name
*x
= (net_db_name
*) hash_lookup(host_table
, key
);
170 return x
? x
->net_db_entry
: NULL
;
174 netdbRelease(netdbEntry
* n
)
179 for (x
= n
->hosts
; x
; x
= next
) {
188 n
->n_peers_alloc
= 0;
190 if (n
->link_count
== 0) {
191 netdbHashDelete(n
->network
);
192 memFree(n
, MEM_NETDBENTRY
);
197 netdbLRU(const void *A
, const void *B
)
199 const netdbEntry
*const *n1
= (const netdbEntry
*const *)A
;
200 const netdbEntry
*const *n2
= (const netdbEntry
*const *)B
;
202 if ((*n1
)->last_use_time
> (*n2
)->last_use_time
)
205 if ((*n1
)->last_use_time
< (*n2
)->last_use_time
)
219 list
= (netdbEntry
**)xcalloc(memInUse(MEM_NETDBENTRY
), sizeof(netdbEntry
*));
220 hash_first(addr_table
);
222 while ((n
= (netdbEntry
*) hash_next(addr_table
))) {
223 assert(list_count
< memInUse(MEM_NETDBENTRY
));
224 *(list
+ list_count
) = n
;
230 sizeof(netdbEntry
*),
233 for (k
= 0; k
< list_count
; k
++) {
234 if (memInUse(MEM_NETDBENTRY
) < Config
.Netdb
.low
)
237 netdbRelease(*(list
+ k
));
247 netdbLookupAddr(struct in_addr addr
)
250 char *key
= inet_ntoa(networkFromInaddr(addr
));
251 n
= (netdbEntry
*) hash_lookup(addr_table
, key
);
257 netdbAdd(struct in_addr addr
)
261 if (memInUse(MEM_NETDBENTRY
) > Config
.Netdb
.high
)
264 if ((n
= netdbLookupAddr(addr
)) == NULL
)
266 n
= (netdbEntry
*)memAllocate(MEM_NETDBENTRY
);
267 netdbHashInsert(n
, addr
);
274 netdbSendPing(const ipcache_addrs
* ia
, void *data
)
278 char *hostname
= (char *)((generic_cbdata
*) data
)->data
;
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 debug(38, 3) ("netdbSendPing: %s moved from %s to %s\n",
304 hostname
, n
->network
, na
->network
);
306 x
= (net_db_name
*) hash_lookup(host_table
, hostname
);
309 debug(38, 1) ("netdbSendPing: net_db_name list bug: %s not found", hostname
);
314 /* remove net_db_name from 'network n' linked list */
315 for (X
= &n
->hosts
; *X
; X
= &(*X
)->next
) {
323 /* point to 'network na' from host entry */
324 x
->net_db_entry
= na
;
325 /* link net_db_name to 'network na' */
332 if (n
->next_ping_time
<= squid_curtime
) {
333 debug(38, 3) ("netdbSendPing: pinging %s\n", hostname
);
334 icmpDomainPing(addr
, hostname
);
336 n
->next_ping_time
= squid_curtime
+ Config
.Netdb
.period
;
337 n
->last_use_time
= squid_curtime
;
343 static struct in_addr
345 networkFromInaddr(struct in_addr a
)
349 b
.s_addr
= ntohl(a
.s_addr
);
352 if (IN_CLASSC(b
.s_addr
))
353 b
.s_addr
&= IN_CLASSC_NET
;
354 else if (IN_CLASSB(b
.s_addr
))
355 b
.s_addr
&= IN_CLASSB_NET
;
356 else if (IN_CLASSA(b
.s_addr
))
357 b
.s_addr
&= IN_CLASSA_NET
;
360 /* use /24 for everything */
361 b
.s_addr
&= IN_CLASSC_NET
;
365 b
.s_addr
= htonl(b
.s_addr
);
371 sortByRtt(const void *A
, const void *B
)
373 const netdbEntry
*const *n1
= (const netdbEntry
*const *)A
;
374 const netdbEntry
*const *n2
= (const netdbEntry
*const *)B
;
376 if ((*n1
)->rtt
> (*n2
)->rtt
)
378 else if ((*n1
)->rtt
< (*n2
)->rtt
)
385 netdbPeerByName(const netdbEntry
* n
, const char *peername
)
388 net_db_peer
*p
= n
->peers
;
390 for (i
= 0; i
< n
->n_peers
; i
++, p
++) {
391 if (!strcmp(p
->peername
, peername
))
399 netdbPeerAdd(netdbEntry
* n
, peer
* e
)
406 if (n
->n_peers
== n
->n_peers_alloc
) {
408 osize
= n
->n_peers_alloc
;
410 if (n
->n_peers_alloc
== 0)
411 n
->n_peers_alloc
= 2;
413 n
->n_peers_alloc
<<= 1;
415 debug(38, 3) ("netdbPeerAdd: Growing peer list for '%s' to %d\n",
416 n
->network
, n
->n_peers_alloc
);
418 n
->peers
= (net_db_peer
*)xcalloc(n
->n_peers_alloc
, sizeof(net_db_peer
));
420 for (i
= 0; i
< osize
; i
++)
421 *(n
->peers
+ i
) = *(o
+ i
);
428 p
= n
->peers
+ n
->n_peers
;
429 p
->peername
= netdbPeerName(e
->host
);
435 sortPeerByRtt(const void *A
, const void *B
)
437 const net_db_peer
*p1
= (net_db_peer
*)A
;
438 const net_db_peer
*p2
= (net_db_peer
*)B
;
440 if (p1
->rtt
> p2
->rtt
)
442 else if (p1
->rtt
< p2
->rtt
)
449 netdbSaveState(void *foo
)
451 LOCAL_ARRAY(char, path
, SQUID_MAXPATHLEN
);
456 struct timeval start
= current_time
;
458 snprintf(path
, SQUID_MAXPATHLEN
, "%s/netdb_state", storeSwapDir(0));
460 * This was nicer when we were using stdio, but thanks to
461 * Solaris bugs, its a bad idea. fopen can fail if more than
465 * unlink() is here because there is currently no way to make
466 * logfileOpen() use O_TRUNC.
469 lf
= logfileOpen(path
, 4096, 0);
472 debug(50, 1) ("netdbSaveState: %s: %s\n", path
, xstrerror());
476 hash_first(addr_table
);
478 while ((n
= (netdbEntry
*) hash_next(addr_table
))) {
479 if (n
->pings_recv
== 0)
482 logfilePrintf(lf
, "%s %d %d %10.5f %10.5f %d %d",
488 (int) n
->next_ping_time
,
489 (int) n
->last_use_time
);
491 for (x
= n
->hosts
; x
; x
= x
->next
)
492 logfilePrintf(lf
, " %s", hashKeyStr(&x
->hash
));
494 logfilePrintf(lf
, "\n");
504 debug(38, 1) ("NETDB state saved; %d entries, %d msec\n",
505 count
, tvSubMsec(start
, current_time
));
506 eventAddIsh("netdbSaveState", netdbSaveState
, NULL
, 3600.0, 1);
510 netdbReloadState(void)
512 LOCAL_ARRAY(char, path
, SQUID_MAXPATHLEN
);
524 struct timeval start
= current_time
;
525 snprintf(path
, SQUID_MAXPATHLEN
, "%s/netdb_state", storeSwapDir(0));
527 * This was nicer when we were using stdio, but thanks to
528 * Solaris bugs, its a bad idea. fopen can fail if more than
531 fd
= file_open(path
, O_RDONLY
| O_BINARY
);
536 if (fstat(fd
, &sb
) < 0) {
542 char *buf
= (char *)xcalloc(1, sb
.st_size
+ 1);
544 l
= FD_READ_METHOD(fd
, buf
, sb
.st_size
);
552 while ((s
= strchr(t
, '\n'))) {
556 memset(&N
, '\0', sizeof(netdbEntry
));
557 q
= strtok(t
, w_space
);
563 if (!safe_inet_addr(q
, &addr
))
566 if (netdbLookupAddr(addr
) != NULL
) /* no dups! */
569 if ((q
= strtok(NULL
, w_space
)) == NULL
)
572 N
.pings_sent
= atoi(q
);
574 if ((q
= strtok(NULL
, w_space
)) == NULL
)
577 N
.pings_recv
= atoi(q
);
579 if (N
.pings_recv
== 0)
582 /* give this measurement low weight */
587 if ((q
= strtok(NULL
, w_space
)) == NULL
)
592 if ((q
= strtok(NULL
, w_space
)) == NULL
)
597 if ((q
= strtok(NULL
, w_space
)) == NULL
)
600 N
.next_ping_time
= (time_t) atoi(q
);
602 if ((q
= strtok(NULL
, w_space
)) == NULL
)
605 N
.last_use_time
= (time_t) atoi(q
);
607 n
= (netdbEntry
*)memAllocate(MEM_NETDBENTRY
);
609 xmemcpy(n
, &N
, sizeof(netdbEntry
));
611 netdbHashInsert(n
, addr
);
613 while ((q
= strtok(NULL
, w_space
)) != NULL
) {
614 if (netdbLookupHost(q
) != NULL
) /* no dups! */
617 netdbHostInsert(n
, q
);
625 debug(38, 1) ("NETDB state reloaded; %d entries, %d msec\n",
626 count
, tvSubMsec(start
, current_time
));
630 netdbPeerName(const char *name
)
634 for (w
= peer_names
; w
; w
= w
->next
) {
635 if (!strcmp(w
->key
, name
))
639 return wordlistAdd(&peer_names
, name
);
643 netdbFreeNetdbEntry(void *data
)
645 netdbEntry
*n
= (netdbEntry
*)data
;
647 memFree(n
, MEM_NETDBENTRY
);
651 netdbFreeNameEntry(void *data
)
653 net_db_name
*x
= (net_db_name
*)data
;
655 memFree(x
, MEM_NET_DB_NAME
);
660 netdbExchangeHandleReply(void *data
, StoreIOBuffer recievedData
)
662 netdbExchangeState
*ex
= (netdbExchangeState
*)data
;
671 HttpReply
const *rep
;
675 int oldbufofs
= ex
->buf_ofs
;
678 rec_sz
+= 1 + sizeof(addr
.s_addr
);
679 rec_sz
+= 1 + sizeof(int);
680 rec_sz
+= 1 + sizeof(int);
681 debug(38, 3) ("netdbExchangeHandleReply: %d read bytes\n", (int) recievedData
.length
);
683 if (!cbdataReferenceValid(ex
->p
)) {
684 debug(38, 3) ("netdbExchangeHandleReply: Peer became invalid\n");
685 netdbExchangeDone(ex
);
689 debug(38, 3) ("netdbExchangeHandleReply: for '%s:%d'\n", ex
->p
->host
, ex
->p
->http_port
);
691 if (recievedData
.length
== 0 &&
692 !recievedData
.flags
.error
) {
693 debug(38, 3) ("netdbExchangeHandleReply: Done\n");
694 netdbExchangeDone(ex
);
700 /* Get the size of the buffer now */
701 size
= ex
->buf_ofs
+ recievedData
.length
;
702 debug(38, 3) ("netdbExchangeHandleReply: %d bytes buf\n", (int) size
);
704 /* Check if we're still doing headers */
706 if (ex
->connstate
== STATE_HEADER
) {
708 ex
->buf_ofs
+= recievedData
.length
;
710 /* skip reply headers */
712 if ((hdr_sz
= headersEnd(p
, ex
->buf_ofs
))) {
713 debug(38, 5) ("netdbExchangeHandleReply: hdr_sz = %d\n", hdr_sz
);
714 rep
= ex
->e
->getReply();
715 assert (0 != rep
->sline
.status
);
716 debug(38, 3) ("netdbExchangeHandleReply: reply status %d\n",
719 if (HTTP_OK
!= rep
->sline
.status
) {
720 netdbExchangeDone(ex
);
724 assert((size_t)ex
->buf_ofs
>= hdr_sz
);
727 * Now, point p to the part of the buffer where the data
728 * starts, and update the size accordingly
730 assert(ex
->used
== 0);
732 size
= ex
->buf_ofs
- hdr_sz
;
735 /* Finally, set the conn state mode to STATE_BODY */
736 ex
->connstate
= STATE_BODY
;
738 StoreIOBuffer tempBuffer
;
739 tempBuffer
.offset
= ex
->buf_ofs
;
740 tempBuffer
.length
= ex
->buf_sz
- ex
->buf_ofs
;
741 tempBuffer
.data
= ex
->buf
+ ex
->buf_ofs
;
742 /* Have more headers .. */
743 storeClientCopy(ex
->sc
, ex
->e
, tempBuffer
,
744 netdbExchangeHandleReply
, ex
);
749 assert(ex
->connstate
== STATE_BODY
);
751 /* If we get here, we have some body to parse .. */
752 debug(38, 5) ("netdbExchangeHandleReply: start parsing loop, size = %d\n",
755 while (size
>= rec_sz
) {
756 debug(38, 5) ("netdbExchangeHandleReply: in parsing loop, size = %d\n",
758 addr
.s_addr
= any_addr
.s_addr
;
761 for (o
= 0; o
< rec_sz
;) {
762 switch ((int) *(p
+ o
)) {
764 case NETDB_EX_NETWORK
:
766 xmemcpy(&addr
.s_addr
, p
+ o
, sizeof(addr
.s_addr
));
767 o
+= sizeof(addr
.s_addr
);
772 xmemcpy(&j
, p
+ o
, sizeof(int));
774 rtt
= (double) ntohl(j
) / 1000.0;
779 xmemcpy(&j
, p
+ o
, sizeof(int));
781 hops
= (double) ntohl(j
) / 1000.0;
785 debug(38, 1) ("netdbExchangeHandleReply: corrupt data, aborting\n");
786 netdbExchangeDone(ex
);
791 if (addr
.s_addr
!= any_addr
.s_addr
&& rtt
> 0)
792 netdbExchangeUpdatePeer(addr
, ex
->p
, rtt
, hops
);
806 * Copy anything that is left over to the beginning of the buffer,
807 * and adjust buf_ofs accordingly
811 * Evilly, size refers to the buf size left now,
812 * ex->buf_ofs is the original buffer size, so just copy that
815 memmove(ex
->buf
, ex
->buf
+ (ex
->buf_ofs
- size
), size
);
820 * And don't re-copy the remaining data ..
825 * Now the tricky bit - size _included_ the leftover bit from the _last_
826 * storeClientCopy. We don't want to include that, or our offset will be wrong.
827 * So, don't count the size of the leftover buffer we began with.
828 * This can _disappear_ when we're not tracking offsets ..
830 ex
->used
-= oldbufofs
;
832 debug(38, 3) ("netdbExchangeHandleReply: size left over in this buffer: %d bytes\n", size
);
834 debug(38, 3) ("netdbExchangeHandleReply: used %d entries, (x %d bytes) == %d bytes total\n",
835 nused
, rec_sz
, nused
* rec_sz
);
837 debug(38, 3) ("netdbExchangeHandleReply: used %ld\n", (long int) ex
->used
);
839 if (EBIT_TEST(ex
->e
->flags
, ENTRY_ABORTED
)) {
840 debug(38, 3) ("netdbExchangeHandleReply: ENTRY_ABORTED\n");
841 netdbExchangeDone(ex
);
842 } else if (ex
->e
->store_status
== STORE_PENDING
) {
843 StoreIOBuffer tempBuffer
;
844 tempBuffer
.offset
= ex
->used
;
845 tempBuffer
.length
= ex
->buf_sz
- ex
->buf_ofs
;
846 tempBuffer
.data
= ex
->buf
+ ex
->buf_ofs
;
847 debug(38, 3) ("netdbExchangeHandleReply: EOF not recieved\n");
848 storeClientCopy(ex
->sc
, ex
->e
, tempBuffer
,
849 netdbExchangeHandleReply
, ex
);
854 netdbExchangeDone(void *data
)
856 netdbExchangeState
*ex
= (netdbExchangeState
*)data
;
857 debug(38, 3) ("netdbExchangeDone: %s\n", storeUrl(ex
->e
));
858 requestUnlink(ex
->r
);
859 storeUnregister(ex
->sc
, ex
->e
, ex
);
860 storeUnlockObject(ex
->e
);
861 cbdataReferenceDone(ex
->p
);
865 #endif /* USE_ICMP */
867 /* PUBLIC FUNCTIONS */
878 n
= hashPrime(Config
.Netdb
.high
/ 4);
880 addr_table
= hash_create((HASHCMP
*) strcmp
, n
, hash_string
);
882 n
= hashPrime(3 * Config
.Netdb
.high
/ 4);
884 host_table
= hash_create((HASHCMP
*) strcmp
, n
, hash_string
);
886 eventAddIsh("netdbSaveState", netdbSaveState
, NULL
, 3600.0, 1);
890 cachemgrRegister("netdb",
891 "Network Measurement Database",
898 netdbPingSite(const char *hostname
)
904 if ((n
= netdbLookupHost(hostname
)) != NULL
)
905 if (n
->next_ping_time
> squid_curtime
)
908 h
= cbdataAlloc(generic_cbdata
);
910 h
->data
= xstrdup(hostname
);
912 ipcache_nbgethostbyname(hostname
, netdbSendPing
, h
);
919 netdbHandlePingReply(const struct sockaddr_in
*from
, int hops
, int rtt
)
924 debug(38, 3) ("netdbHandlePingReply: from %s\n", inet_ntoa(from
->sin_addr
));
926 if ((n
= netdbLookupAddr(from
->sin_addr
)) == NULL
)
937 n
->hops
= ((n
->hops
* (N
- 1)) + hops
) / N
;
939 n
->rtt
= ((n
->rtt
* (N
- 1)) + rtt
) / N
;
941 debug(38, 3) ("netdbHandlePingReply: %s; rtt=%5.1f hops=%4.1f\n",
950 netdbFreeMemory(void)
953 hashFreeItems(addr_table
, netdbFreeNetdbEntry
);
954 hashFreeMemory(addr_table
);
956 hashFreeItems(host_table
, netdbFreeNameEntry
);
957 hashFreeMemory(host_table
);
959 wordlistDestroy(&peer_names
);
966 netdbHops(struct in_addr addr
)
969 netdbEntry
*n
= netdbLookupAddr(addr
);
971 if (n
&& n
->pings_recv
)
973 n
->last_use_time
= squid_curtime
;
974 return (int) (n
->hops
+ 0.5);
982 netdbDump(StoreEntry
* sentry
)
992 storeAppendPrintf(sentry
, "Network DB Statistics:\n");
993 storeAppendPrintf(sentry
, "%-16.16s %9s %7s %5s %s\n",
999 list
= (netdbEntry
**)xcalloc(memInUse(MEM_NETDBENTRY
), sizeof(netdbEntry
*));
1001 hash_first(addr_table
);
1003 while ((n
= (netdbEntry
*) hash_next(addr_table
)))
1006 if (i
!= memInUse(MEM_NETDBENTRY
))
1007 debug(38, 0) ("WARNING: netdb_addrs count off, found %d, expected %d\n",
1008 i
, memInUse(MEM_NETDBENTRY
));
1010 qsort((char *) list
,
1012 sizeof(netdbEntry
*),
1015 for (k
= 0; k
< i
; k
++) {
1017 storeAppendPrintf(sentry
, "%-16.16s %4d/%4d %7.1f %5.1f",
1024 for (x
= n
->hosts
; x
; x
= x
->next
)
1025 storeAppendPrintf(sentry
, " %s", hashKeyStr(&x
->hash
));
1027 storeAppendPrintf(sentry
, "\n");
1031 for (j
= 0; j
< n
->n_peers
; j
++, p
++) {
1032 storeAppendPrintf(sentry
, " %-22.22s %7.1f %5.1f\n",
1042 storeAppendPrintf(sentry
,
1043 "NETDB support not compiled into this Squid cache.\n");
1048 netdbHostHops(const char *host
)
1051 netdbEntry
*n
= netdbLookupHost(host
);
1054 n
->last_use_time
= squid_curtime
;
1055 return (int) (n
->hops
+ 0.5);
1063 netdbHostRtt(const char *host
)
1066 netdbEntry
*n
= netdbLookupHost(host
);
1069 n
->last_use_time
= squid_curtime
;
1070 return (int) (n
->rtt
+ 0.5);
1078 netdbHostData(const char *host
, int *samp
, int *rtt
, int *hops
)
1081 netdbEntry
*n
= netdbLookupHost(host
);
1086 *samp
= n
->pings_recv
;
1088 *rtt
= (int) (n
->rtt
+ 0.5);
1090 *hops
= (int) (n
->hops
+ 0.5);
1092 n
->last_use_time
= squid_curtime
;
1098 netdbUpdatePeer(HttpRequest
* r
, peer
* e
, int irtt
, int ihops
)
1102 double rtt
= (double) irtt
;
1103 double hops
= (double) ihops
;
1105 debug(38, 3) ("netdbUpdatePeer: '%s', %d hops, %d rtt\n", r
->host
, ihops
, irtt
);
1106 n
= netdbLookupHost(r
->host
);
1109 debug(38, 3) ("netdbUpdatePeer: host '%s' not found\n", r
->host
);
1113 if ((p
= netdbPeerByName(n
, e
->host
)) == NULL
)
1114 p
= netdbPeerAdd(n
, e
);
1120 p
->expires
= squid_curtime
+ 3600;
1125 qsort((char *) n
->peers
,
1127 sizeof(net_db_peer
),
1135 netdbExchangeUpdatePeer(struct in_addr addr
, peer
* e
, double rtt
, double hops
)
1140 debug(38, 5) ("netdbExchangeUpdatePeer: '%s', %0.1f hops, %0.1f rtt\n",
1141 inet_ntoa(addr
), hops
, rtt
);
1142 n
= netdbLookupAddr(addr
);
1149 if ((p
= netdbPeerByName(n
, e
->host
)) == NULL
)
1150 p
= netdbPeerAdd(n
, e
);
1156 p
->expires
= squid_curtime
+ 3600; /* XXX ? */
1161 qsort((char *) n
->peers
,
1163 sizeof(net_db_peer
),
1171 netdbDeleteAddrNetwork(struct in_addr addr
)
1174 netdbEntry
*n
= netdbLookupAddr(addr
);
1179 debug(38, 3) ("netdbDeleteAddrNetwork: %s\n", n
->network
);
1187 netdbBinaryExchange(StoreEntry
* s
)
1189 HttpReply
*reply
= httpReplyCreate();
1190 http_version_t version
;
1199 struct in_addr addr
;
1201 httpBuildVersion(&version
, 1, 0);
1202 httpReplySetHeaders(reply
, version
, HTTP_OK
, "OK",
1203 NULL
, -1, squid_curtime
, -2);
1204 httpReplySwapOut(reply
, s
);
1206 rec_sz
+= 1 + sizeof(addr
.s_addr
);
1207 rec_sz
+= 1 + sizeof(int);
1208 rec_sz
+= 1 + sizeof(int);
1209 buf
= (char *)memAllocate(MEM_4K_BUF
);
1211 hash_first(addr_table
);
1213 while ((n
= (netdbEntry
*) hash_next(addr_table
))) {
1217 if (n
->rtt
> 60000) /* RTT > 1 MIN probably bogus */
1220 if (!safe_inet_addr(n
->network
, &addr
))
1223 buf
[i
++] = (char) NETDB_EX_NETWORK
;
1225 xmemcpy(&buf
[i
], &addr
.s_addr
, sizeof(addr
.s_addr
));
1227 i
+= sizeof(addr
.s_addr
);
1229 buf
[i
++] = (char) NETDB_EX_RTT
;
1231 j
= htonl((int) (n
->rtt
* 1000));
1233 xmemcpy(&buf
[i
], &j
, sizeof(int));
1237 buf
[i
++] = (char) NETDB_EX_HOPS
;
1239 j
= htonl((int) (n
->hops
* 1000));
1241 xmemcpy(&buf
[i
], &j
, sizeof(int));
1245 if (i
+ rec_sz
> 4096) {
1246 storeAppend(s
, buf
, i
);
1252 storeAppend(s
, buf
, i
);
1257 storeBufferFlush(s
);
1258 memFree(buf
, MEM_4K_BUF
);
1261 httpBuildVersion(&version
, 1, 0);
1262 httpReplySetHeaders(reply
, version
, HTTP_BAD_REQUEST
, "Bad Request",
1263 NULL
, -1, squid_curtime
, -2);
1264 httpReplySwapOut(reply
, s
);
1265 storeAppendPrintf(s
, "NETDB support not compiled into this Squid cache.\n");
1272 CBDATA_TYPE(netdbExchangeState
);
1276 netdbExchangeStart(void *data
)
1279 peer
*p
= (peer
*)data
;
1281 netdbExchangeState
*ex
;
1282 StoreIOBuffer tempBuffer
;
1283 CBDATA_INIT_TYPE(netdbExchangeState
);
1284 ex
= cbdataAlloc(netdbExchangeState
);
1285 ex
->p
= cbdataReference(p
);
1286 uri
= internalRemoteUri(p
->host
, p
->http_port
, "/squid-internal-dynamic/", "netdb");
1287 debug(38, 3) ("netdbExchangeStart: Requesting '%s'\n", uri
);
1288 assert(NULL
!= uri
);
1289 ex
->r
= urlParse(METHOD_GET
, uri
);
1291 if (NULL
== ex
->r
) {
1292 debug(38, 1) ("netdbExchangeStart: Bad URI %s\n", uri
);
1297 assert(NULL
!= ex
->r
);
1298 httpBuildVersion(&ex
->r
->http_ver
, 1, 0);
1299 ex
->connstate
= STATE_HEADER
;
1300 ex
->e
= storeCreateEntry(uri
, uri
, request_flags(), METHOD_GET
);
1301 ex
->buf_sz
= NETDB_REQBUF_SZ
;
1302 assert(NULL
!= ex
->e
);
1303 ex
->sc
= storeClientListAdd(ex
->e
, ex
);
1304 tempBuffer
.offset
= 0;
1305 tempBuffer
.length
= ex
->buf_sz
;
1306 tempBuffer
.data
= ex
->buf
;
1307 storeClientCopy(ex
->sc
, ex
->e
, tempBuffer
,
1308 netdbExchangeHandleReply
, ex
);
1309 ex
->r
->flags
.loopdetect
= 1; /* cheat! -- force direct */
1312 xstrncpy(ex
->r
->login
, p
->login
, MAX_LOGIN_SZ
);
1314 fwdStart(-1, ex
->e
, ex
->r
);
1320 netdbClosestParent(HttpRequest
* request
)
1325 const ipcache_addrs
*ia
;
1328 n
= netdbLookupHost(request
->host
);
1332 ia
= ipcache_gethostbyname(request
->host
, 0);
1335 n
= netdbLookupAddr(ia
->in_addrs
[ia
->cur
]);
1341 if (0 == n
->n_peers
)
1344 n
->last_use_time
= squid_curtime
;
1347 * Find the parent with the least RTT to the origin server.
1348 * Make sure we don't return a parent who is farther away than
1349 * we are. Note, the n->peers list is pre-sorted by RTT.
1351 for (i
= 0; i
< n
->n_peers
; i
++) {
1355 if (n
->rtt
< h
->rtt
)
1358 p
= peerFindByName(h
->peername
);
1360 if (NULL
== p
) /* not found */
1363 if (neighborType(p
, request
) != PEER_PARENT
)
1366 if (!peerHTTPOkay(p
, request
)) /* not allowed */