/*
- * DEBUG: section 38 Network Measurement Database
- * AUTHOR: Duane Wessels
- *
- * SQUID Web Proxy Cache http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- * Squid is the result of efforts by numerous individuals from
- * the Internet community; see the CONTRIBUTORS file for full
- * details. Many organizations have provided support for Squid's
- * development; see the SPONSORS file for full details. Squid is
- * Copyrighted (C) 2001 by the Regents of the University of
- * California; see the COPYRIGHT file for full details. Squid
- * incorporates software developed and/or copyrighted by other
- * sources; see the CREDITS file for full details.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ * Copyright (C) 1996-2018 The Squid Software Foundation and contributors
*
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
*/
+/* DEBUG: section 38 Network Measurement Database */
+
/*
* XXX XXX XXX
*
#include "squid.h"
#include "CachePeer.h"
#include "cbdata.h"
-#include "disk.h"
#include "event.h"
#include "fde.h"
+#include "fs_io.h"
#include "FwdState.h"
#include "HttpReply.h"
-#include "HttpRequest.h"
#include "icmp/net_db.h"
#include "internal.h"
#include "ip/Address.h"
#include "log/File.h"
-#include "Mem.h"
#include "MemObject.h"
#include "mgr/Registration.h"
#include "mime_header.h"
#include "neighbors.h"
+#include "SquidConfig.h"
#include "SquidTime.h"
#include "Store.h"
#include "StoreClient.h"
-#include "SwapDir.h"
#include "tools.h"
-#include "URL.h"
#include "wordlist.h"
#if HAVE_SYS_STAT_H
#include "ipcache.h"
#include "StoreClient.h"
-#define NETDB_REQBUF_SZ 4096
+#define NETDB_REQBUF_SZ 4096
typedef enum {
STATE_NONE,
STATE_BODY
} netdb_conn_state_t;
-typedef struct {
- CachePeer *p;
- StoreEntry *e;
- store_client *sc;
- HttpRequest *r;
- int64_t used;
- size_t buf_sz;
+class netdbExchangeState
+{
+ CBDATA_CLASS(netdbExchangeState);
+
+public:
+ netdbExchangeState(CachePeer *aPeer, const HttpRequestPointer &theReq) :
+ p(aPeer),
+ r(theReq)
+ {
+ *buf = 0;
+ assert(r);
+ // TODO: check if we actually need to do this. should be implicit
+ r->http_ver = Http::ProtocolVersion();
+ }
+
+ ~netdbExchangeState() {
+ debugs(38, 3, e->url());
+ storeUnregister(sc, e, this);
+ e->unlock("netdbExchangeDone");
+ }
+
+ CbcPointer<CachePeer> p;
+ StoreEntry *e = nullptr;
+ store_client *sc = nullptr;
+ HttpRequestPointer r;
+ int64_t used = 0;
+ size_t buf_sz = NETDB_REQBUF_SZ;
char buf[NETDB_REQBUF_SZ];
- int buf_ofs;
- netdb_conn_state_t connstate;
-} netdbExchangeState;
+ int buf_ofs = 0;
+ netdb_conn_state_t connstate = STATE_HEADER;
+};
+
+CBDATA_CLASS_INIT(netdbExchangeState);
static hash_table *addr_table = NULL;
static hash_table *host_table = NULL;
static net_db_peer *netdbPeerAdd(netdbEntry * n, CachePeer * e);
static const char *netdbPeerName(const char *name);
static IPH netdbSendPing;
-static QS sortPeerByRtt;
-static QS sortByRtt;
-static QS netdbLRU;
static FREE netdbFreeNameEntry;
static FREE netdbFreeNetdbEntry;
static STCB netdbExchangeHandleReply;
-static void netdbExchangeDone(void *);
/* We have to keep a local list of CachePeer names. The Peers structure
* gets freed during a reconfigure. We want this database to
netdbHashInsert(netdbEntry * n, Ip::Address &addr)
{
networkFromInaddr(addr).toStr(n->network, MAX_IPSTRLEN);
- n->hash.key = n->network;
+ n->key = n->network;
assert(hash_lookup(addr_table, n->network) == NULL);
- hash_join(addr_table, &n->hash);
+ hash_join(addr_table, n);
}
static void
hash_remove_link(addr_table, hptr);
}
+net_db_name::net_db_name(const char *hostname, netdbEntry *e) :
+ next(e ? e->hosts : nullptr),
+ net_db_entry(e)
+{
+ key = xstrdup(hostname);
+ if (e) {
+ e->hosts = this;
+ ++ e->link_count;
+ }
+}
+
static void
netdbHostInsert(netdbEntry * n, const char *hostname)
{
- net_db_name *x = (net_db_name *)memAllocate(MEM_NET_DB_NAME);
- x->hash.key = xstrdup(hostname);
- x->next = n->hosts;
- n->hosts = x;
- x->net_db_entry = n;
+ net_db_name *x = new net_db_name(hostname, n);
assert(hash_lookup(host_table, hostname) == NULL);
- hash_join(host_table, &x->hash);
- ++ n->link_count;
+ hash_join(host_table, x);
}
static void
netdbHostDelete(const net_db_name * x)
{
- netdbEntry *n;
- net_db_name **X;
assert(x != NULL);
assert(x->net_db_entry != NULL);
- n = x->net_db_entry;
+
+ netdbEntry *n = x->net_db_entry;
-- n->link_count;
- for (X = &n->hosts; *X; X = &(*X)->next) {
+ for (auto **X = &n->hosts; *X; X = &(*X)->next) {
if (*X == x) {
*X = x->next;
break;
}
hash_remove_link(host_table, (hash_link *) x);
- xfree(x->hash.key);
- memFree((void *) x, MEM_NET_DB_NAME);
+ delete x;
}
static netdbEntry *
if (n->link_count == 0) {
netdbHashDelete(n->network);
- memFree(n, MEM_NETDBENTRY);
+ delete n;
}
}
int k = 0;
int list_count = 0;
int removed = 0;
- list = (netdbEntry **)xcalloc(memInUse(MEM_NETDBENTRY), sizeof(netdbEntry *));
+ list = (netdbEntry **)xcalloc(netdbEntry::UseCount(), sizeof(netdbEntry *));
hash_first(addr_table);
while ((n = (netdbEntry *) hash_next(addr_table))) {
- assert(list_count < memInUse(MEM_NETDBENTRY));
+ assert(list_count < netdbEntry::UseCount());
*(list + list_count) = n;
++list_count;
}
netdbLRU);
for (k = 0; k < list_count; ++k) {
- if (memInUse(MEM_NETDBENTRY) < Config.Netdb.low)
+ if (netdbEntry::UseCount() < Config.Netdb.low)
break;
netdbRelease(*(list + k));
{
netdbEntry *n;
- if (memInUse(MEM_NETDBENTRY) > Config.Netdb.high)
+ if (netdbEntry::UseCount() > Config.Netdb.high)
netdbPurgeLRU();
if ((n = netdbLookupAddr(addr)) == NULL) {
- n = (netdbEntry *)memAllocate(MEM_NETDBENTRY);
+ n = new netdbEntry;
netdbHashInsert(n, addr);
}
}
static void
-netdbSendPing(const ipcache_addrs *ia, const DnsLookupDetails &, void *data)
+netdbSendPing(const ipcache_addrs *ia, const Dns::LookupDetails &, void *data)
{
Ip::Address addr;
char *hostname = NULL;
return;
}
- addr = ia->in_addrs[ia->cur];
+ addr = ia->current();
if ((n = netdbLookupHost(hostname)) == NULL) {
n = netdbAdd(addr);
unlink(Config.netdbFilename);
lf = logfileOpen(Config.netdbFilename, 4096, 0);
- if (NULL == lf) {
- debugs(50, DBG_IMPORTANT, "netdbSaveState: " << Config.netdbFilename << ": " << xstrerror());
+ if (lf) {
+ int xerrno = errno;
+ debugs(50, DBG_IMPORTANT, MYNAME << Config.netdbFilename << ": " << xstrerr(xerrno));
return;
}
(int) n->last_use_time);
for (x = n->hosts; x; x = x->next)
- logfilePrintf(lf, " %s", hashKeyStr(&x->hash));
+ logfilePrintf(lf, " %s", hashKeyStr(x));
logfilePrintf(lf, "\n");
if (! (addr = q) )
continue;
- if (netdbLookupAddr(addr) != NULL) /* no dups! */
+ if (netdbLookupAddr(addr) != NULL) /* no dups! */
continue;
if ((q = strtok(NULL, w_space)) == NULL)
N.last_use_time = (time_t) atoi(q);
- n = (netdbEntry *)memAllocate(MEM_NETDBENTRY);
+ n = new netdbEntry;
memcpy(n, &N, sizeof(netdbEntry));
netdbHashInsert(n, addr);
while ((q = strtok(NULL, w_space)) != NULL) {
- if (netdbLookupHost(q) != NULL) /* no dups! */
+ if (netdbLookupHost(q) != NULL) /* no dups! */
continue;
netdbHostInsert(n, q);
{
netdbEntry *n = (netdbEntry *)data;
safe_free(n->peers);
- memFree(n, MEM_NETDBENTRY);
+ delete n;
}
static void
netdbFreeNameEntry(void *data)
{
net_db_name *x = (net_db_name *)data;
- xfree(x->hash.key);
- memFree(x, MEM_NET_DB_NAME);
+ delete x;
}
static void
rec_sz += 1 + sizeof(int);
debugs(38, 3, "netdbExchangeHandleReply: " << receivedData.length << " read bytes");
- if (!cbdataReferenceValid(ex->p)) {
+ if (!ex->p.valid()) {
debugs(38, 3, "netdbExchangeHandleReply: Peer became invalid");
- netdbExchangeDone(ex);
+ delete ex;
return;
}
debugs(38, 3, "netdbExchangeHandleReply: for '" << ex->p->host << ":" << ex->p->http_port << "'");
- if (receivedData.length == 0 &&
- !receivedData.flags.error) {
+ if (receivedData.length == 0 && !receivedData.flags.error) {
debugs(38, 3, "netdbExchangeHandleReply: Done");
- netdbExchangeDone(ex);
+ delete ex;
return;
}
debugs(38, 3, "netdbExchangeHandleReply: reply status " << rep->sline.status());
if (rep->sline.status() != Http::scOkay) {
- netdbExchangeDone(ex);
+ delete ex;
return;
}
default:
debugs(38, DBG_IMPORTANT, "netdbExchangeHandleReply: corrupt data, aborting");
- netdbExchangeDone(ex);
+ delete ex;
return;
}
}
if (!addr.isAnyAddr() && rtt > 0)
- netdbExchangeUpdatePeer(addr, ex->p, rtt, hops);
+ netdbExchangeUpdatePeer(addr, ex->p.get(), rtt, hops);
assert(o == rec_sz);
if (EBIT_TEST(ex->e->flags, ENTRY_ABORTED)) {
debugs(38, 3, "netdbExchangeHandleReply: ENTRY_ABORTED");
- netdbExchangeDone(ex);
+ delete ex;
} else if (ex->e->store_status == STORE_PENDING) {
StoreIOBuffer tempBuffer;
tempBuffer.offset = ex->used;
}
}
-static void
-netdbExchangeDone(void *data)
-{
- netdbExchangeState *ex = (netdbExchangeState *)data;
- debugs(38, 3, "netdbExchangeDone: " << ex->e->url() );
- HTTPMSGUNLOCK(ex->r);
- storeUnregister(ex->sc, ex->e, ex);
- ex->e->unlock("netdbExchangeDone");
- cbdataReferenceDone(ex->p);
- cbdataFree(ex);
-}
-
-static void
-netdbRegisterWithCacheManager(void)
-{
- Mgr::RegisterAction("netdb", "Network Measurement Database", netdbDump, 0, 1);
-}
-
#endif /* USE_ICMP */
/* PUBLIC FUNCTIONS */
netdbInit(void)
{
#if USE_ICMP
- int n;
-
- netdbRegisterWithCacheManager();
+ Mgr::RegisterAction("netdb", "Network Measurement Database", netdbDump, 0, 1);
if (addr_table)
return;
- n = hashPrime(Config.Netdb.high / 4);
+ int n = hashPrime(Config.Netdb.high / 4);
addr_table = hash_create((HASHCMP *) strcmp, n, hash_string);
"RTT",
"Hops",
"Hostnames");
- list = (netdbEntry **)xcalloc(memInUse(MEM_NETDBENTRY), sizeof(netdbEntry *));
+ list = (netdbEntry **)xcalloc(netdbEntry::UseCount(), sizeof(netdbEntry *));
i = 0;
hash_first(addr_table);
++i;
}
- if (i != memInUse(MEM_NETDBENTRY))
+ if (i != netdbEntry::UseCount())
debugs(38, DBG_CRITICAL, "WARNING: netdb_addrs count off, found " << i <<
- ", expected " << memInUse(MEM_NETDBENTRY));
+ ", expected " << netdbEntry::UseCount());
qsort((char *) list,
i,
n->hops);
for (x = n->hosts; x; x = x->next)
- storeAppendPrintf(sentry, " %s", hashKeyStr(&x->hash));
+ storeAppendPrintf(sentry, " %s", hashKeyStr(x));
storeAppendPrintf(sentry, "\n");
}
void
-netdbUpdatePeer(HttpRequest * r, CachePeer * e, int irtt, int ihops)
+netdbUpdatePeer(const URL &url, CachePeer * e, int irtt, int ihops)
{
#if USE_ICMP
netdbEntry *n;
double rtt = (double) irtt;
double hops = (double) ihops;
net_db_peer *p;
- debugs(38, 3, "netdbUpdatePeer: '" << r->GetHost() << "', " << ihops << " hops, " << irtt << " rtt");
- n = netdbLookupHost(r->GetHost());
+ debugs(38, 3, url.host() << ", " << ihops << " hops, " << irtt << " rtt");
+ n = netdbLookupHost(url.host());
if (n == NULL) {
- debugs(38, 3, "netdbUpdatePeer: host '" << r->GetHost() << "' not found");
+ debugs(38, 3, "host " << url.host() << " not found");
return;
}
p->hops = hops;
- p->expires = squid_curtime + 3600; /* XXX ? */
+ p->expires = squid_curtime + 3600; /* XXX ? */
if (n->n_peers < 2)
return;
if (0.0 == n->rtt)
continue;
- if (n->rtt > 60000) /* RTT > 1 MIN probably bogus */
+ if (n->rtt > 60000) /* RTT > 1 MIN probably bogus */
continue;
if (! (addr = n->network) )
s->complete();
}
-#if USE_ICMP
-CBDATA_TYPE(netdbExchangeState);
-#endif
-
void
netdbExchangeStart(void *data)
{
#if USE_ICMP
CachePeer *p = (CachePeer *)data;
- char *uri;
- netdbExchangeState *ex;
- StoreIOBuffer tempBuffer;
- CBDATA_INIT_TYPE(netdbExchangeState);
- ex = cbdataAlloc(netdbExchangeState);
- ex->p = cbdataReference(p);
- uri = internalRemoteUri(p->host, p->http_port, "/squid-internal-dynamic/", "netdb");
- debugs(38, 3, "netdbExchangeStart: Requesting '" << uri << "'");
- assert(NULL != uri);
- ex->r = HttpRequest::CreateFromUrl(uri);
-
- if (NULL == ex->r) {
- debugs(38, DBG_IMPORTANT, "netdbExchangeStart: Bad URI " << uri);
+ static const SBuf netDB("netdb");
+ char *uri = internalRemoteUri(p->host, p->http_port, "/squid-internal-dynamic/", netDB);
+ debugs(38, 3, "Requesting '" << uri << "'");
+ const MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initIcmp);
+ HttpRequestPointer req(HttpRequest::FromUrl(uri, mx));
+
+ if (!req) {
+ debugs(38, DBG_IMPORTANT, MYNAME << ": Bad URI " << uri);
return;
}
- HTTPMSGLOCK(ex->r);
- assert(NULL != ex->r);
- ex->r->http_ver = Http::ProtocolVersion(1,1);
- ex->connstate = STATE_HEADER;
+ netdbExchangeState *ex = new netdbExchangeState(p, req);
ex->e = storeCreateEntry(uri, uri, RequestFlags(), Http::METHOD_GET);
- ex->buf_sz = NETDB_REQBUF_SZ;
assert(NULL != ex->e);
- ex->sc = storeClientListAdd(ex->e, ex);
- tempBuffer.offset = 0;
+
+ StoreIOBuffer tempBuffer;
tempBuffer.length = ex->buf_sz;
tempBuffer.data = ex->buf;
+
+ ex->sc = storeClientListAdd(ex->e, ex);
+
storeClientCopy(ex->sc, ex->e, tempBuffer,
netdbExchangeHandleReply, ex);
- ex->r->flags.loopDetected = true; /* cheat! -- force direct */
+ ex->r->flags.loopDetected = true; /* cheat! -- force direct */
+ // XXX: send as Proxy-Authenticate instead
if (p->login)
- xstrncpy(ex->r->login, p->login, MAX_LOGIN_SZ);
-
- urlCanonical(ex->r);
-
- FwdState::fwdStart(Comm::ConnectionPointer(), ex->e, ex->r);
+ ex->r->url.userInfo(SBuf(p->login));
+ FwdState::fwdStart(Comm::ConnectionPointer(), ex->e, ex->r.getRaw());
#endif
}
const ipcache_addrs *ia;
net_db_peer *h;
int i;
- n = netdbLookupHost(request->GetHost());
+ n = netdbLookupHost(request->url.host());
if (NULL == n) {
/* try IP addr */
- ia = ipcache_gethostbyname(request->GetHost(), 0);
+ ia = ipcache_gethostbyname(request->url.host(), 0);
if (NULL != ia)
- n = netdbLookupAddr(ia->in_addrs[ia->cur]);
+ n = netdbLookupAddr(ia->current());
}
if (NULL == n)
p = peerFindByName(h->peername);
- if (NULL == p) /* not found */
+ if (NULL == p) /* not found */
continue;
- if (neighborType(p, request) != PEER_PARENT)
+ if (neighborType(p, request->url) != PEER_PARENT)
continue;
- if (!peerHTTPOkay(p, request)) /* not allowed */
+ if (!peerHTTPOkay(p, request)) /* not allowed */
continue;
return p;
#endif
return NULL;
}
+