Bumping this old design conversation back into gear. I would like to
start implementation and rollout of this master transaction code,
effective immediately.
Attached is a patch implementing a basic MasterXaction class. It is
created by TcpAcceptor when a new client connects and gets passed out
for use when constructing a ConnStateData object to manage the
connection. The ConnStateData object does need to retain its own
pointers to the data received in that initial transaction - so that when
receiving pipelined requests on a persistent connection it can spawn new
MasterXaction objects with the same TCP details as the original.
I've marked all the branching points where MasterXaction could extend
out of ConnStateData with XXX right now instead of rolling MasterXaction
down through the entire codebase. As you can see from this patch already
simply rolling it fully into ConnStateData is causing a lot of polishing
changes to happen. That is likely to be the norm rather than the
exception, so I'm intending to submit each individual step as a separate
patch on trunk with SourceLayout bundled alongside Xaction rollout.
I've also created an array in ConnStateData which will hold a vector of
the active transactions, one for each pipelined request on the
connection. This is intended to replace the "currentobject" list of
ClientSocketContext's currently used for pipeline state. In the final
product the MasterXaction object passed down to each child Job will be
the authoritative source of information about the transaction, and
ConnStateData will be freed up to pre-parse as many pipelined requests
as we want it to and juggle them as internal private state. I've also
polished the pipeline_prefetch code to use a #define macro which can be
altered at compile-time for experiments instead of hard-coded magic
numbers. And added a few XXX to start documenting what needs fixing there.
If you like the design I will commit before passing it on to the
sub-Jobs ConnStateData makes use of.
Amos
On 21/05/2011 5:16 a.m., Alex Rousskov wrote:
On 05/20/2011 01:31 AM, Amos Jeffries wrote:
For starters. This is probably 3.3. We can continue to hack our way
around data passing limitations in 3.2. Although with Alex emphasis on
optimization going into 3.2, some of this may help that.
THE RANT:
The more I've been looking at the client-side the more I see duplicated
copies and re-copies of transaction details. I know you all agree there
is too much of it.
What I've seen myself...
ACLChecklist - storing a copy of as many currently known transaction
details as people have asked to be checked so far.
HttpRequest - storing copy of *almost* all transaction details.
ClientHttpRequest - copy of the transaction details needed by client-side
ConnSateData - copy of the transaction TCP details and some
HttpRequest details needed by pinning, 1xx and other weird state handling.
AccessLogEntry - copy of all most known transaction details.
There is also the opposite side of the same coin -- code that does not
care about the HTTP request details but cares about some master
transaction information is currently forced to deal with the whole
HttpRequest structure, increasing the number of dependencies and
complications associated with changing the request.
... and by "copy" I mean complete duplicate. xstrdup() galore etc.
With a bunch of code doing nothing but checking the local copy is up to
date with whatever other copy or function parameter it sourced the
detail from. A bunch of other code *assuming* that its getting the right
details (sometimes wrongly).
* Have not yet got a good look at the reply handling path in detail yet.
Overall it seems to be using the request-path objects in reverse. So no
worse or better.
Yes, the XXXs and TODOs associated with the lack of "master transaction"
class exist on all Squid sides.
IDEAS:
Note that ClientHttpRequest has a member copy of AccessLogEntry. This is
*already* available and unique on a per-request basis from the very
start of the HTTP request arrival and parsing. Persists across the whole
transaction lifetime and is used for logging at the end.
I suspect it would be easier and overall better to implement and review
a good master transaction class from scratch than to modify and existing
class, especially such rotten class as AccessLogEntry.
The focus of the master transaction class is on persistence
(refcounting) and isolation of information (each module does not need to
know about all others). This is very different from AccessLogEntry.
I propose that the first thing we do is clean up its internal structure
design. To make sure it has all the fields we will need in the net step.
I propose then to rename as a general-purpose transaction storage area
(TransactionDetails?). To avoid people ignoring it as a "logging-only"
thing.
I propose then to roll each step/object along the transaction pathway
to using it as their primary storage area for transaction details and
history.
- incremental so can be done in the background for low impact starting
immediately.
- will soon lead to removal of several useless copies.
- will mean component/Jobs updated are guaranteed to have *all* details
for the current state of the transaction available should they need it.
I would rather see a new MasterXact class added. It may have
AccessLogEntry as a member, but it will not immediately inherit all the
AccessLogEntry problems.
Ack. With my now slightly better knowledge of where and how
AccessLogEntry is used, I am thinking AccessLogEntry should probably
inherit from MasterXact. Such that it grows all the master classes
fields and the old rotten ALE structure can slowly be superceded.
NOTE: little fine-detail processing pathways like ident will only need
a selected refcount/cbdata/locked sub-child of the whole slab object.
This is fine and will help drop dependencies. Thus the proposed modular
hierarchy structure below.
The proposed structure does not work for isolating the components from
each other. And one cannot refcount/cbdata/lock a sub-structure.
If we want to truly isolate components, we should probably follow this
sketch:
class Component1;
class Component2;
class Component3;
class Component4;
class MasterXaction: public RefCountable {
public:
Component1 *component1;
Component2 *component2;
Component3 *component3;
Component4 *component4;
...
const InstanceId<MasterXact> id;
};
The above can be compiled and linked without knowing anything about
individual Component classes. The code that needs access to componentN,
will include ComponentN.h and MasterXact.h. "ComponentN" is not a real
name; the actual name will be specific to the component purpose, of
course. For example, there may be AdaptationDetails, AuthenticationInfo,
and similar components.
Simple components that do not use complex data member types can be
inlined to avoid additional memory allocation, like you show in your
sketch below.
An important goal here would be to eventually move everything not
related to a single HTTP request from HttpRequest to MasterXaction and
change most of the code not related to handling HTTP requests to use
MasterXaction as the primary source of information.
With the above sketch, it is not necessary to lock individual
components. We can pass MasterXaction objects around instead.
I am not sure exactly how to make the master transaction both refcounted
and cbdata-safe, but it is probably possible.
I'm not sure if we need to CBDATA it. We can look at that later if we
find a reason to of course. We can RefCount and CbDataCount an object if
necessary, it is just super messy.
My current thinking is that we need AsyncJob to take MasterXact as a
parameter to constructor for all objects, each object then retains a
pointer to it and a pointer to its own state data ComponentX object. The
pointer to MasterXact is only necessary to pass on to child Jobs or
access other components data. For some Jobs this may involve abstracting
their member fields out into what you descrie as ComponentX objects
which can be pointed to be the MasterXaction and Job without RefCount loops.
We can RefCount MasterXact and guarantee that it exists so long as all
Jobs using it are running.
To kick-start things this is what I've been thinking we need its
structure to look like:
class TransactionDetails {
class TimeDetails {
// all the timing and wait stats we can dream up.
// for the transaction as a whole.
// specific times stay in their own component.
} time;
// Details about the TCP links used by this transaction.
class TcpDetails {
struct { FD, ip, port, eui, ident } client;
struct s_ { FP, ip, port, eui, ident } server;
vector<s_> serverHistory;
// NP: not sure if we want a server-side history
// if so it would go here listing all outbound attempts.
} tcp;
class SquidInternalDetails {
// which worker/disker served this request?
ext_acl; // details from external ACL tested
auth; // details from proxy-auth helpers
status; // status flags hit/miss/peer/aborted/timeout etc
hier; // heirarchy details, HierarchyLogEntry
} squid;
// Details about the ICP used by this transaction.
class IcpDetails {
icp_opcode opcode;
}
// Details about the HTCP used by this transaction.
class HtcpDetails {
htcp_opcode? opcode;
}
// Details about the HTTP used by this transaction.
class HttpDetails {
// currently to be used request/reply.
// points to the later specific objects
HttpRequestPointer request;
HttpReplyPointer reply;
// specific state objects
HttpRequestPointer original_request; // original received
HttpRequestPointer adapted_request; // after adaptation
HttpRequestPointer original_reply; // original received
HttpRequestPointer adapted_reply; // after adaptation
// NP: original reply may be nil if non-HTTP source.
// in which case...
HttpRequestPointer generated_reply; // pre-adaptation.
} http;
// Details about the adaptation used by this transaction.
class AdaptationDetails {
{ ...} icap; // icap state and history, pretty much as-is
{...} ecap; // ecap state if we find anythig to log.
} adapt;
// Details about the FTP used by this transaction.
class FtpDetails {
vector<String> protoLog; // FTP msgs used in this fetch.
}
// ... other entries similar to FTP for gopher, wais, etc.
}
NOTE that "headers", "private" and "cache" are gone.
- "headers" blobs are part of HttpRequest (or should be)
- "private" is duplicate of HttpRequest details
- "cache" is split into whichever component is actually relevant for
the particular field.
Individual parts sound like a good starting point to me, with the
exception of SquidInternalDetails which has too vague scope and should
probably be split or merged with others.
Some fields may need stricter descriptions (e.g., there can be many
adapted requests if there is an adaptation chain). And we will probably
add more (e.g., request_sent and response_sent?).
We should probably discuss specific fields later.
Cheers,
Alex.
=== modified file 'src/CommCalls.cc'
--- src/CommCalls.cc 2012-08-28 13:00:30 +0000
+++ src/CommCalls.cc 2013-05-10 14:34:10 +0000
@@ -7,12 +7,12 @@
/* CommCommonCbParams */
CommCommonCbParams::CommCommonCbParams(void *aData):
- data(cbdataReference(aData)), conn(), flag(COMM_OK), xerrno(0), fd(-1)
+ data(cbdataReference(aData)), conn(), flag(COMM_OK), xerrno(0),
fd(-1), xaction()
{
}
CommCommonCbParams::CommCommonCbParams(const CommCommonCbParams &p):
- data(cbdataReference(p.data)), conn(p.conn), flag(p.flag),
xerrno(p.xerrno), fd(p.fd)
+ data(cbdataReference(p.data)), conn(p.conn), flag(p.flag),
xerrno(p.xerrno), fd(p.fd), xaction(p.xaction)
{
}
@@ -35,6 +35,9 @@
os << ", flag=" << flag;
if (data)
os << ", data=" << data;
+
+ if (xaction != NULL)
+ os << ", xaction.id=" << xaction->id;
}
/* CommAcceptCbParams */
=== modified file 'src/CommCalls.h'
--- src/CommCalls.h 2013-01-02 23:40:49 +0000
+++ src/CommCalls.h 2013-05-05 04:31:05 +0000
@@ -5,6 +5,7 @@
#include "base/AsyncJobCalls.h"
#include "comm_err_t.h"
#include "comm/forward.h"
+#include "MasterXaction.h"
/* CommCalls implement AsyncCall interface for comm_* callbacks.
* The classes cover two call dialer kinds:
@@ -79,6 +80,9 @@
int xerrno; ///< The last errno to occur. non-zero if flag is
COMM_ERR.
int fd; ///< FD which the call was about. Set by the async call creator.
+
+ /// Transaction which this call is part of.
+ MasterXaction::Pointer xaction;
private:
// should not be needed and not yet implemented
CommCommonCbParams &operator =(const CommCommonCbParams ¶ms);
=== modified file 'src/Makefile.am'
--- src/Makefile.am 2013-05-08 03:02:01 +0000
+++ src/Makefile.am 2013-05-08 03:14:01 +0000
@@ -422,6 +422,8 @@
LogTags.h \
lookup_t.h \
main.cc \
+ MasterXaction.cc \
+ MasterXaction.h \
Mem.h \
mem.cc \
mem_node.cc \
@@ -1249,6 +1251,8 @@
HttpRequestMethod.cc \
int.h \
int.cc \
+ MasterXaction.cc \
+ MasterXaction.h \
SquidList.h \
SquidList.cc \
mem_node.cc \
@@ -1485,6 +1489,8 @@
internal.cc \
SquidList.h \
SquidList.cc \
+ MasterXaction.cc \
+ MasterXaction.h \
multicast.h \
multicast.cc \
mem_node.cc \
@@ -1664,6 +1670,8 @@
int.cc \
SquidList.h \
SquidList.cc \
+ MasterXaction.cc \
+ MasterXaction.h \
MemBuf.cc \
MemObject.cc \
mem_node.cc \
@@ -1899,6 +1907,8 @@
internal.cc \
SquidList.h \
SquidList.cc \
+ MasterXaction.cc \
+ MasterXaction.h \
Mem.h \
mem.cc \
mem_node.cc \
@@ -2145,6 +2155,8 @@
internal.cc \
SquidList.h \
SquidList.cc \
+ MasterXaction.cc \
+ MasterXaction.h \
MemBuf.cc \
MemObject.cc \
Mem.h \
@@ -2388,6 +2400,8 @@
ipcache.cc \
SquidList.h \
SquidList.cc \
+ MasterXaction.cc \
+ MasterXaction.h \
MemBuf.cc \
MemObject.cc \
Mem.h \
@@ -2676,6 +2690,8 @@
internal.cc \
SquidList.h \
SquidList.cc \
+ MasterXaction.cc \
+ MasterXaction.h \
multicast.h \
multicast.cc \
mem_node.cc \
@@ -2848,6 +2864,8 @@
int.cc \
SquidList.h \
SquidList.cc \
+ MasterXaction.cc \
+ MasterXaction.h \
Mem.h \
mem.cc \
mem_node.cc \
@@ -3073,6 +3091,8 @@
RequestFlags.cc \
SquidList.h \
SquidList.cc \
+ MasterXaction.cc \
+ MasterXaction.h \
MemObject.cc \
StoreSwapLogData.cc \
StoreIOState.cc \
@@ -3259,6 +3279,8 @@
int.cc \
SquidList.h \
SquidList.cc \
+ MasterXaction.cc \
+ MasterXaction.h \
Mem.h \
mem.cc \
MemBuf.cc \
@@ -3642,6 +3664,8 @@
internal.cc \
SquidList.h \
SquidList.cc \
+ MasterXaction.cc \
+ MasterXaction.h \
multicast.h \
multicast.cc \
Mem.h \
=== added file 'src/MasterXaction.cc'
--- src/MasterXaction.cc 1970-01-01 00:00:00 +0000
+++ src/MasterXaction.cc 2013-05-05 14:14:17 +0000
@@ -0,0 +1,4 @@
+#include "squid.h"
+#include "MasterXaction.h"
+
+InstanceIdDefinitions(MasterXaction, "MXID_");
=== added file 'src/MasterXaction.h'
--- src/MasterXaction.h 1970-01-01 00:00:00 +0000
+++ src/MasterXaction.h 2013-05-10 14:50:03 +0000
@@ -0,0 +1,49 @@
+#ifndef SQUID_SRC_MASTERXACTION_H
+#define SQUID_SRC_MASTERXACTION_H
+
+#include "anyp/PortCfg.h"
+#include "base/CbcPointer.h"
+#include "base/InstanceId.h"
+#include "base/Lock.h"
+#include "comm/forward.h"
+
+/** Maximum number of pipelined requests to pre-parse.
+ *
+ * Squid can pre-parse requests on a persistent connection and queue them for
+ * service while waiting for a leading transaction to complete.
+ *
+ * It is generally better to leave most pipelined requests in TCP buffers,
+ * which provides some push-back on the client sending rate.
+ *
+ * NP: currently limited to 2 in case there is any hidden code relying on that
+ * old hard-coded value still hanging around.
+ * May be set using -D in CXXFLAGS to test other values.
+ */
+#if !defined(SQUID_PIPELINE_MAX)
+#define SQUID_PIPELINE_MAX 2
+#endif
+
+/** Master transaction state object.
+ *
+ * This class holds pointers to all the state
+ * generated during the processing of a client
+ * transaction.
+ */
+class MasterXaction : public RefCountable
+{
+public:
+ typedef RefCount<MasterXaction> Pointer;
+
+ /// transaction ID.
+ InstanceId<MasterXaction> id;
+
+ /// the listening port which originated this transaction
+ CbcPointer<AnyP::PortCfg> squidPort;
+
+ /// the client TCP connection which originated this transaction
+ Comm::ConnectionPointer tcpClient;
+
+ // TODO: add state from other Jobs in the transaction
+};
+
+#endif /* SQUID_SRC_MASTERXACTION_H */
=== modified file 'src/client_side.cc'
--- src/client_side.cc 2013-05-08 03:02:01 +0000
+++ src/client_side.cc 2013-05-10 14:56:12 +0000
@@ -245,8 +245,6 @@
char *skipLeadingSpace(char *aString);
static void connNoteUseOfBuffer(ConnStateData* conn, size_t byteCount);
-static ConnStateData *connStateCreate(const Comm::ConnectionPointer &client,
AnyP::PortCfg *port);
-
clientStreamNode *
ClientSocketContext::getTail() const
{
@@ -2935,14 +2933,21 @@
}
}
-static int
+// XXX: make this a private method of ConnStateData
+static bool
connOkToAddRequest(ConnStateData * conn)
{
- int result = conn->getConcurrentRequestCount() <
(Config.onoff.pipeline_prefetch ? 2 : 1);
+ const int maxReq = (Config.onoff.pipeline_prefetch ? SQUID_PIPELINE_MAX :
1);
+ const bool result = conn->getConcurrentRequestCount() < maxReq;
+
+ // XXX: make this more dynamic?
+ // ... false / no pipelines for HTTP/1.0 clients?
+ // ... false if NTLM/Negotiate handshake is being done by the last parsed
request
+ // ie, pipeline prefetch non-auth requests, halt during handshake, and
resume pipeline prefetch after authed.
if (!result) {
- debugs(33, 3, HERE << conn->clientConnection << " max concurrent
requests reached");
- debugs(33, 5, HERE << conn->clientConnection << " defering new request
until one is done");
+ debugs(33, 3, conn->clientConnection << " max concurrent requests
reached (" << maxReq << ")");
+ debugs(33, 5, conn->clientConnection << " defering new request until
one is done");
}
return result;
@@ -3364,23 +3369,43 @@
io.conn->close();
}
-ConnStateData *
-connStateCreate(const Comm::ConnectionPointer &client, AnyP::PortCfg *port)
+ConnStateData::ConnStateData(const MasterXaction::Pointer &xact) :
+ AsyncJob("ConnStateData"),
+#if USE_SSL
+ sslBumpMode(Ssl::bumpEnd),
+ switchedToHttps_(false),
+ sslServerBump(NULL),
+#endif
+ stoppedSending_(NULL),
+ stoppedReceiving_(NULL)
{
- ConnStateData *result = new ConnStateData;
-
- result->clientConnection = client;
- result->log_addr = client->remote;
- result->log_addr.ApplyMask(Config.Addrs.client_netmask);
- result->in.buf = (char *)memAllocBuf(CLIENT_REQ_BUF_SZ,
&result->in.allocatedSize);
- result->port = cbdataReference(port);
-
+ pinning.host = NULL;
+ pinning.port = -1;
+ pinning.pinned = false;
+ pinning.auth = false;
+ pinning.zeroReply = false;
+ pinning.peer = NULL;
+
+ // on a new connection there is one transaction (about to start)
+ xaction[0] = xact;
+
+ // store the details required for creating more MasterXaction objects
+ // later when the xaction[] has been completed and removed
+ clientConnection = xact->tcpClient;
+ port = cbdataReference(xact->squidPort.get());
+ log_addr = xact->tcpClient->remote;
+ log_addr.ApplyMask(Config.Addrs.client_netmask);
+
+ // TODO: make this a MemBuf (with higher than 64KB limits?)
+ in.buf = (char *)memAllocBuf(CLIENT_REQ_BUF_SZ, &in.allocatedSize);
+
+ // XXX: do this in TcpAcceptor? this is a socket layer operation.
if (port->disable_pmtu_discovery != DISABLE_PMTU_OFF &&
- (result->transparent() || port->disable_pmtu_discovery ==
DISABLE_PMTU_ALWAYS)) {
+ (transparent() || port->disable_pmtu_discovery ==
DISABLE_PMTU_ALWAYS)) {
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
int i = IP_PMTUDISC_DONT;
- if (setsockopt(client->fd, SOL_IP, IP_MTU_DISCOVER, &i, sizeof(i)) < 0)
- debugs(33, 2, "WARNING: Path MTU discovery disabling failed on "
<< client << " : " << xstrerror());
+ if (setsockopt(clientConnection->fd, SOL_IP, IP_MTU_DISCOVER, &i,
sizeof(i)) < 0)
+ debugs(33, 2, "WARNING: Path MTU discovery disabling failed on "
<< clientConnection << " : " << xstrerror());
#else
static bool reported = false;
@@ -3392,37 +3417,39 @@
}
typedef CommCbMemFunT<ConnStateData, CommCloseCbParams> Dialer;
- AsyncCall::Pointer call = JobCallback(33, 5, Dialer, result,
ConnStateData::connStateClosed);
- comm_add_close_handler(client->fd, call);
+ AsyncCall::Pointer call = JobCallback(33, 5, Dialer, this,
ConnStateData::connStateClosed);
+ comm_add_close_handler(clientConnection->fd, call);
if (Config.onoff.log_fqdn)
- fqdncache_gethostbyaddr(client->remote, FQDN_LOOKUP_IF_MISS);
+ fqdncache_gethostbyaddr(clientConnection->remote, FQDN_LOOKUP_IF_MISS);
#if USE_IDENT
if (Ident::TheConfig.identLookup) {
ACLFilledChecklist identChecklist(Ident::TheConfig.identLookup, NULL,
NULL);
- identChecklist.src_addr = client->remote;
- identChecklist.my_addr = client->local;
+// XXX: pass xact to the checklist constructor instead of the below
+ identChecklist.src_addr = xact->tcpClient->remote;
+ identChecklist.my_addr = xact->tcpClient->local;
if (identChecklist.fastCheck() == ACCESS_ALLOWED)
- Ident::Start(client, clientIdentDone, result);
+ Ident::Start(xact->tcpClient, clientIdentDone, this);
}
#endif
- clientdbEstablished(client->remote, 1);
+ clientdbEstablished(clientConnection->remote, 1);
- result->flags.readMore = true;
- return result;
+ flags.readMore = true;
}
/** Handle a new connection on HTTP socket. */
void
httpAccept(const CommAcceptCbParams ¶ms)
{
- AnyP::PortCfg *s = static_cast<AnyP::PortCfg *>(params.data);
+ MasterXaction::Pointer xact = params.xaction;
+ AnyP::PortCfg *s = xact->squidPort.get(); // XXX: avoid get()
if (params.flag != COMM_OK) {
// Its possible the call was still queued when the client disconnected
debugs(33, 2, "httpAccept: " << s->listenConn << ": accept failure: "
<< xstrerr(params.xerrno));
+// XXX: log the failed connection?
return;
}
@@ -3436,7 +3463,7 @@
++ incoming_sockets_accepted;
// Socket is ready, setup the connection manager to start using it
- ConnStateData *connState = connStateCreate(params.conn, s);
+ ConnStateData *connState = new ConnStateData(xact);
typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
@@ -3453,6 +3480,7 @@
ClientDelayPools& pools(Config.ClientDelay.pools);
ACLFilledChecklist ch(NULL, NULL, NULL);
+// XXX: pass MasterXaction xact to ACLFilledChecklist constructor instead of
the below
// TODO: we check early to limit error response bandwith but we
// should recheck when we can honor delay_pool_uses_indirect
@@ -3471,6 +3499,7 @@
/* request client information from db after we did all
checks
this will save hash lookup if client failed checks */
ClientInfo * cli = clientdbGetInfo(params.conn->remote);
+// XXX: save this ClientInfo data to MasterXaction xact ?
assert(cli);
/* put client info in FDE */
@@ -3480,6 +3509,7 @@
const double burst = floor(0.5 +
(pools[pool].highwatermark *
Config.ClientDelay.initial)/100.0);
cli->setWriteLimiter(pools[pool].rate, burst,
pools[pool].highwatermark);
+// XXX: save this delay pool data to MasterXaction xact ?
break;
} else {
debugs(83, 4, HERE << "Delay pool " << pool << " skipped
because ACL " << answer);
@@ -3676,7 +3706,7 @@
/**
* A callback function to use with the ACLFilledChecklist callback.
- * In the case of ACCES_ALLOWED answer initializes a bumped SSL connection,
+ * In the case of ACCESS_ALLOWED answer initializes a bumped SSL connection,
* else reverts the connection to tunnel mode.
*/
static void
@@ -3718,11 +3748,14 @@
static void
httpsAccept(const CommAcceptCbParams ¶ms)
{
- AnyP::PortCfg *s = static_cast<AnyP::PortCfg *>(params.data);
+ MasterXaction::Pointer xact = params.xaction;
+ AnyP::PortCfg *s = xact->squidPort.get(); // XXX: avoid get()
+ assert(s);
if (params.flag != COMM_OK) {
// Its possible the call was still queued when the client disconnected
debugs(33, 2, "httpsAccept: " << s->listenConn << ": accept failure: "
<< xstrerr(params.xerrno));
+// XXX: log the failed connection?
return;
}
@@ -3736,7 +3769,7 @@
++incoming_sockets_accepted;
// Socket is ready, setup the connection manager to start using it
- ConnStateData *connState = connStateCreate(params.conn, s);
+ ConnStateData *connState = new ConnStateData(xact);
if (s->flags.tunnelSslBumping) {
debugs(33, 5, "httpsAccept: accept transparent connection: " <<
params.conn);
@@ -3746,6 +3779,8 @@
return;
}
+// XXX: when ACLs are using MasterXaction xact members the below can die ...
+
// Create a fake HTTP request for ssl_bump ACL check,
// using tproxy/intercept provided destination IP and port.
HttpRequest *request = new HttpRequest();
=== modified file 'src/client_side.h'
--- src/client_side.h 2013-04-04 06:15:00 +0000
+++ src/client_side.h 2013-05-06 03:19:49 +0000
@@ -175,10 +175,11 @@
class ServerBump;
}
#endif
+
/**
* Manages a connection to a client.
*
- * Multiple requests (up to 2) can be pipelined. This object is responsible
for managing
+ * Multiple requests (up to SQUID_PIPELINE_MAX) can be pipelined. This object
is responsible for managing
* which one is currently being fulfilled and what happens to the queue if the
current one
* causes the client connection to be closed early.
*
@@ -195,6 +196,7 @@
public:
ConnStateData();
+ ConnStateData(const MasterXaction::Pointer &xact);
~ConnStateData();
void readSomeData();
@@ -215,7 +217,16 @@
// HttpControlMsgSink API
virtual void sendControlMsg(HttpControlMsg msg);
+ /**
+ * Transaction state for the current client transaction(s).
+ * Squid accepts up to SQUID_PIPELINE_MAX pipelined requests
+ * at any one time on a connection.
+ */
+ MasterXaction::Pointer xaction[SQUID_PIPELINE_MAX];
+
// Client TCP connection details from comm layer.
+ // XXX: make private now, useful only to spawn new MasterXaction objects
for pipeline requests
+ // we need to retain because the client conn may be idle between requests
with no MasterXaction to clone
Comm::ConnectionPointer clientConnection;
struct In {
@@ -261,13 +272,15 @@
*/
ClientSocketContext::Pointer currentobject;
- Ip::Address log_addr;
+ Ip::Address log_addr; // TODO: remove entirely and produce masked IP on
demand.
int nrequests;
struct {
bool readMore; ///< needs comm_read (for this request or new requests)
bool swanSang; // XXX: temporary flag to check proper cleanup
} flags;
+
+ // XXX: make private now? hidden behind pinning API, and used to fill
MasterXaction
struct {
Comm::ConnectionPointer serverConnection; /* pinned server side
connection */
char *host; /* host name of pinned connection */
@@ -279,6 +292,9 @@
AsyncCall::Pointer closeHandler; /*The close handler for pinned server
side connection*/
} pinning;
+
+ // XXX: make private now, useful only to spawn new MasterXaction objects
for pipeline requests
+ // we need to retain because the client conn may be idle between requests
with no MasterXaction to clone
AnyP::PortCfg *port;
bool transparent() const;
=== modified file 'src/comm/TcpAcceptor.cc'
--- src/comm/TcpAcceptor.cc 2013-05-08 03:02:01 +0000
+++ src/comm/TcpAcceptor.cc 2013-05-08 03:14:01 +0000
@@ -46,6 +46,7 @@
#include "fde.h"
#include "globals.h"
#include "ip/Intercept.h"
+#include "MasterXaction.h"
#include "profiler/Profiler.h"
#include "SquidConfig.h"
#include "SquidTime.h"
@@ -286,8 +287,10 @@
if (theCallSub != NULL) {
AsyncCall::Pointer call = theCallSub->callback();
CommAcceptCbParams ¶ms = GetCommParams<CommAcceptCbParams>(call);
+ params.xaction = new MasterXaction;
+ params.xaction->squidPort = static_cast<AnyP::PortCfg*>(params.data);
// do this here or in the caller?
params.fd = conn->fd;
- params.conn = newConnDetails;
+ params.conn = params.xaction->tcpClient = newConnDetails;
params.flag = flag;
params.xerrno = errcode;
ScheduleCallHere(call);