The bug directly affected some ICAP OPTIONS transactions and indirectly
affected some ICAP REQMOD/RESPMOD transactions:
* OPTIONS: When a transaction needed to look up an IP address of the
ICAP service, and that address was not cached by Squid, it ended
prematurely because Adaptation::Icap::Xaction::doneAll() was unaware
of ipcache_nbgethostbyname()'s async nature. This bug is fixed now.
* REQMOD/RESPMOD: Adaptation::Icap::ModXact masked the _direct_ effects
of the bug: ModXact::startWriting() sets state.writing before calling
openConnection() which schedules the DNS lookup. That "I am still
writing" state makes ModXact::doneAll() false while a REQMOD or
RESPMOD transaction waits for the DNS lookup.
However, REQMOD and RESPMOD transactions that require an OPTIONS
transaction (because the service options have never been fetched
before or have expired) could still fail because the OPTIONS
transaction they trigger could fail as described in the first bullet.
For example, the first few REQMOD and RESPMOD transactions for a given
service -- all those started before the DNS lookup completes and Squid
caches its result -- could fail this way. With the OPTIONS now fixed,
these REQMOD and RESPMOD transactions should work correctly.
Broken since inception (commit
fb505fa).
isRetriable(true),
isRepeatable(true),
ignoreLastWrite(false),
+ waitingForDns(false),
stopReason(NULL),
connector(NULL),
reader(NULL),
debugs(93,3, typeName << " opens connection to " << s.cfg().host.termedBuf() << ":" << s.cfg().port);
// Locate the Service IP(s) to open
+ assert(!waitingForDns);
+ waitingForDns = true; // before the possibly-synchronous ipcache_nbgethostbyname()
ipcache_nbgethostbyname(s.cfg().host.termedBuf(), icapLookupDnsResults, this);
}
void
Adaptation::Icap::Xaction::dnsLookupDone(const ipcache_addrs *ia)
{
+ assert(waitingForDns);
+ waitingForDns = false;
+
Adaptation::Icap::ServiceRep &s = service();
if (ia == NULL) {
bool Adaptation::Icap::Xaction::doneAll() const
{
- return !connector && !securer && !reader && !writer && Adaptation::Initiate::doneAll();
+ return !waitingForDns && !connector && !securer && !reader && !writer &&
+ Adaptation::Initiate::doneAll();
}
void Adaptation::Icap::Xaction::updateTimeout()
buf.append(";", 1);
}
+
+ if (waitingForDns)
+ buf.append("D", 1);
}
void Adaptation::Icap::Xaction::fillDoneStatus(MemBuf &buf) const
bool isRetriable; ///< can retry on persistent connection failures
bool isRepeatable; ///< can repeat if no or unsatisfactory response
bool ignoreLastWrite;
+ bool waitingForDns; ///< expecting a ipcache_nbgethostbyname() callback
const char *stopReason;