50 const time_t timeout = 0):
77 reuseConnection(true),
80 ignoreLastWrite(false),
86 " [icapx" <<
id <<
']');
87 const auto mx = MasterXaction::MakePortless<XactionInitiator::initAdaptation>();
97 debugs(93,3, typeName <<
" destructed, this=" <<
this <<
98 " [icapx" <<
id <<
']');
112 Must(theService !=
nullptr);
118 debugs(93,5, typeName << (isRetriable ?
" from now on" :
" still") <<
119 " cannot be retried " << status());
125 debugs(93,5, typeName << (isRepeatable ?
" from now on" :
" still") <<
126 " cannot be repeated because " << reason << status());
127 isRepeatable =
false;
140operator <<(std::ostream &os,
const std::optional<Address> &optional)
142 if (optional.has_value())
143 os << optional.value();
155 const auto &addr = ia ? std::optional<Ip::Address>(ia->
current()) : std::optional<Ip::Address>();
163 Must(!haveConnection());
171 useTransportConnection(pconn);
182 waitingForDns =
true;
190 waitingForDns =
false;
194 if (!addr.has_value()) {
197#if WHEN_IPCACHE_NBGETHOSTBYNAME_USES_ASYNC_CALLS
198 dieOnConnectionFailure();
206 conn->
remote = addr.value();
215 transportWait.start(cs, callback);
220 if (haveConnection()) {
222 if (closer !=
nullptr) {
231 if (reuseConnection && !doneWithIo()) {
233 debugs(93,5,
"not reusing pconn due to pending I/O" << status());
234 reuseConnection =
false;
240 const bool reset = !reuseConnection &&
244 s.putConnection(connection, reuseConnection, reset, status());
248 connection =
nullptr;
255 transportWait.finish();
258 dieOnConnectionFailure();
262 useTransportConnection(io.
conn);
276 if (!ssl && service().cfg().secure.encryptTransport) {
281 encryptionWait.start(sslConnector, callback);
285 useIcapConnection(conn);
296 service().noteConnectionUse(connection);
299 closer =
asyncCall(93, 5,
"Adaptation::Icap::Xaction::noteCommClosed",
309 " failed to connect to " << service().cfg().uri);
310 service().noteConnectionFailed(
"failure");
313 throw TexcHere(
"cannot connect to the ICAP service");
318 Must(haveConnection());
331 Must(writer !=
nullptr);
334 if (ignoreLastWrite) {
336 ignoreLastWrite =
false;
337 debugs(93, 7,
"ignoring last write; status: " << io.
flag);
340 al.icap.bytesSent += io.
size;
342 handleCommWrote(io.
size);
349 debugs(93, 2, typeName <<
" failed: timeout with " <<
350 theService->cfg().methodStr() <<
" " <<
351 theService->cfg().uri << status());
352 reuseConnection =
false;
362 connection->noteClosure();
363 connection =
nullptr;
369 mustStop(
"ICAP service connection externally closed");
375 service().noteFailure();
382 debugs(93, 5, typeName <<
" done with I/O" << status());
390 return !waitingForDns && !transportWait && !encryptionWait &&
391 !reader && !writer &&
397 Must(haveConnection());
399 if (reader !=
nullptr || writer !=
nullptr) {
415 Must(haveConnection());
428 Must(reader !=
nullptr);
439 readBuf.rawAppendStart(1);
447 if (readBuf.isEmpty())
453 al.icap.bytesRead += rd.
size;
457 debugs(93, 3,
"read " << rd.
size <<
" bytes");
466 reuseConnection =
false;
469 if (!al.icap.bytesRead && retriable()) {
471 mustStop(
"pconn race");
480 mustStop(
"unknown ICAP I/O read error");
484 handleCommRead(io.
size);
489 if (reader !=
nullptr) {
490 Must(haveConnection());
499 debugs(93, 5,
"have " << readBuf.length() <<
" head bytes to parse");
503 const char *buf = readBuf.c_str();
504 const bool parsed = msg->
parse(buf, readBuf.length(), commEof, &
error);
513 readBuf.consume(msg->
hdr_sz);
519 return !doneReading() &&
535 return haveConnection() &&
536 !transportWait && !reader && !writer &&
537 doneReading() && doneWriting();
542 return connection !=
nullptr && connection->isOpen();
549 if (theInitiator.set()) {
550 debugs(93,4,
"Initiator gone before ICAP transaction ended");
555 mustStop(
"initiator aborted");
563 debugs(93, 3,
"WARNING: resetting outcome: from " << al.icap.outcome <<
" to " << xo);
567 al.icap.outcome = xo;
576 if (transportWait || encryptionWait) {
577 service().noteConnectionFailed(
"abort");
593 if (theInitiator.set()) {
595 retriable(), repeatable());
599 Launcher, noteXactAbort, abortInfo);
619 al.icap.serviceName = s.
cfg().
key;
620 al.icap.reqUri = s.
cfg().
uri;
622 tvSub(al.icap.ioTime, icap_tio_start, icap_tio_finish);
625 al.icap.request = icapRequest;
627 if (icapReply !=
nullptr) {
628 al.icap.reply = icapReply.getRaw();
630 al.icap.resStatus = icapReply->sline.status();
640 fillPendingStatus(buf);
643 buf.
appendf(
" %s%u]",
id.prefix(),
id.value);
651 if (haveConnection()) {
652 buf.
appendf(
"FD %d", connection->fd);
654 if (writer !=
nullptr)
657 if (reader !=
nullptr)
669 if (haveConnection() && commEof)
670 buf.
appendf(
"Comm(%d)", connection->fd);
672 if (stopReason !=
nullptr)
687 assert(!icapService->cfg().secure.sslDomain.isEmpty());
689 SBuf *host =
new SBuf(icapService->cfg().secure.sslDomain);
703 checklist.
dst_peer_name = icapService->cfg().secure.sslDomain;
712 const int fd = serverConnection()->fd;
719 encryptionWait.finish();
726 " TLS negotiation to " << service().cfg().uri <<
" failed");
727 service().noteConnectionFailed(
"failure");
730 throw TexcHere(
"cannot connect to the TLS ICAP service");
733 debugs(93, 5,
"TLS negotiation to " << service().cfg().uri <<
" complete");
741 service().noteConnectionFailed(
"external TLS connection closure");
744 throw TexcHere(
"external closure of the TLS ICAP service connection");
747 useIcapConnection(answer.
conn);
RefCount< AsyncCallT< Dialer > > asyncCall(int aDebugSection, int aDebugLevel, const char *aName, const Dialer &aDialer)
#define asyncCallback(dbgSection, dbgLevel, method, object)
#define JobCallback(dbgSection, dbgLevel, Dialer, job, method)
Convenience macro to create a Dialer-based job callback.
#define CallJobHere(debugSection, debugLevel, job, Class, method)
#define CallJobHere1(debugSection, debugLevel, job, Class, method, arg1)
ErrorDetail::Pointer MakeNamedErrorDetail(const char *name)
void getOutgoingAddress(HttpRequest *request, const Comm::ConnectionPointer &conn)
#define Here()
source code location of the caller
static std::ostream & operator<<(std::ostream &os, const acl_httpstatus_data *status)
reports acl_httpstatus_data using squid.conf http_status ACL value format
#define TexcHere(msg)
legacy convenience macro; it is not difficult to type Here() now
static void icapLookupDnsResults(const ipcache_addrs *ia, const Dns::LookupDetails &, void *data)
void error(char *format,...)
#define SQUID_TCP_SO_RCVBUF
#define CBDATA_NAMESPACED_CLASS_INIT(namespace, type)
time_t io_timeout(bool bypassable) const
time_t connect_timeout(bool bypassable) const
Comm::ConnectionPointer getIdleConnection(bool isRetriable)
void handleSecuredPeer(Security::EncryptorAnswer &answer)
void noteCommConnected(const CommConnectCbParams &io)
called when the connection attempt to an ICAP service completes (successfully or not)
void start() override
called by AsyncStart; do not call directly
void noteCommWrote(const CommIoCbParams &io)
void callException(const std::exception &e) override
called when the job throws during an async call
bool haveConnection() const
virtual bool fillVirginHttpHeader(MemBuf &) const
HttpRequest * icapRequest
sent (or at least created) ICAP request
bool parseHttpMsg(Http::Message *msg)
void useTransportConnection(const Comm::ConnectionPointer &)
void useIcapConnection(const Comm::ConnectionPointer &)
react to the availability of a fully-ready ICAP connection
void noteCommClosed(const CommCloseCbParams &io)
void dieOnConnectionFailure()
virtual AccessLogEntry::Pointer masterLogEntry()
virtual bool doneReading() const
bool doneAll() const override
whether positive goal has been reached
virtual bool doneWriting() const
Xaction(const char *aTypeName, ServiceRep::Pointer &aService)
virtual void fillDoneStatus(MemBuf &buf) const
void disableRepeats(const char *reason)
void dnsLookupDone(std::optional< Ip::Address >)
const char * status() const override
internal cleanup; do not call directly
void noteCommRead(const CommIoCbParams &io)
void noteInitiatorAborted() override
void scheduleWrite(MemBuf &buf)
virtual void fillPendingStatus(MemBuf &buf) const
void callEnd() override
called right after the called job method
void setOutcome(const XactOutcome &xo)
void noteCommTimedout(const CommTimeoutCbParams &io)
virtual void finalizeLogInfo()
const ServiceConfig & cfg() const
a smart AsyncCall pointer for delivery of future results
virtual bool doneAll() const
whether positive goal has been reached
virtual void start()
called by AsyncStart; do not call directly
virtual void callEnd()
called right after the called job method
const char * typeName
kid (leaf) class name, for debugging
virtual void callException(const std::exception &e)
called when the job throws during an async call
Cbc * get() const
a temporary valid raw Cbc pointer or NULL
int xerrno
The last errno to occur. non-zero if flag is Comm::COMM_ERROR.
Comm::Flag flag
comm layer result status.
Comm::ConnectionPointer conn
const Ip::Address & current() const
encapsulates DNS lookup results
common parts of HttpRequest and HttpReply
bool parse(const char *buf, const size_t sz, bool eol, Http::StatusCode *error)
unsigned short port() const
void append(const char *c, int sz) override
char * content()
start of the added data
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
CbcPointer< ErrorState > error
problem details (nil on success)
Comm::ConnectionPointer conn
peer connection (secured on success)
bool tunneled
whether we spliced the connections instead of negotiating encryption
A combination of PeerOptions and the corresponding Context.
virtual bool initialize(Security::SessionPointer &)
PeerConnector(const Comm::ConnectionPointer &aServerConn, const AsyncCallback< EncryptorAnswer > &, const AccessLogEntryPointer &alp, const time_t timeout=0)
void fillChecklist(ACLFilledChecklist &) const override
configure the given checklist (to reflect the current transaction state)
A simple PeerConnector for Secure ICAP services. No SslBump capabilities.
Adaptation::Icap::ServiceRep::Pointer icapService
IcapPeerConnector(Adaptation::Icap::ServiceRep::Pointer &service, const Comm::ConnectionPointer &aServerConn, const AsyncCallback< Security::EncryptorAnswer > &aCallback, AccessLogEntry::Pointer const &alp, const time_t timeout=0)
void fillChecklist(ACLFilledChecklist &) const override
configure the given checklist (to reflect the current transaction state)
CBDATA_CHILD(IcapPeerConnector)
bool initialize(Security::SessionPointer &) override
Security::FuturePeerContext * peerContext() const override
void noteNegotiationDone(ErrorState *error) override
char const * termedBuf() const
an std::runtime_error with thrower location info
void commUnsetConnTimeout(const Comm::ConnectionPointer &conn)
AsyncCall::Pointer comm_add_close_handler(int fd, CLCB *handler, void *data)
void comm_remove_close_handler(int fd, CLCB *handler, void *data)
void commSetConnTimeout(const Comm::ConnectionPointer &conn, time_t timeout, AsyncCall::Pointer &callback)
#define debugs(SECTION, LEVEL, CONTENT)
void ipcache_nbgethostbyname(const char *name, IPH *handler, void *handlerData)
void setClientSNI(SSL *ssl, const char *fqdn)
void HTTPMSGUNLOCK(M *&a)
void HTTPMSGLOCK(Http::Message *a)
void icapLogLog(AccessLogEntry::Pointer &al)
const XactOutcome xoGone
initiator gone, will not continue
const XactOutcome xoRace
ICAP server closed pconn when we started.
const XactOutcome xoError
all kinds of transaction errors
const char * XactOutcome
transaction result for logging
const XactOutcome xoUnknown
initial value: outcome was not set
void ReadCancel(int fd, AsyncCall::Pointer &callback)
Cancel the read pending on FD. No action if none pending.
void Read(const Comm::ConnectionPointer &conn, AsyncCall::Pointer &callback)
bool IsConnOpen(const Comm::ConnectionPointer &conn)
void Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE *free_func)
Comm::Flag ReadNow(CommIoCbParams ¶ms, SBuf &buf)
Network/connection security abstraction layer.
void SetSessionResumeData(const Security::SessionPointer &, const Security::SessionStatePointer &)
std::shared_ptr< SSL > SessionPointer
void MaybeGetSessionResumeData(const Security::SessionPointer &, Security::SessionStatePointer &data)
void tvSub(struct timeval &res, struct timeval const &t1, struct timeval const &t2)
struct timeval current_time
the current UNIX time in timeval {seconds, microseconds} format
const char * xstrerr(int error)