=== modified file 'doc/release-notes/release-3.2.sgml'
--- doc/release-notes/release-3.2.sgml 2011-03-11 22:16:05 +0000
+++ doc/release-notes/release-3.2.sgml 2011-03-23 09:42:23 +0000
@@ -389,6 +389,10 @@
cpu_affinity_map
New setting for SMP support to map Squid processes onto specific CPU cores.
+ connect_retries
+
Replacement for maximum_single_addr_tries, but instead of only applying to hosts with single addresses.
+ This directive applies to all hosts, extending the number of connection attempts to each IP address. =======
+
dns_packet_max
New setting to configure maximum number of bytes packet size to advertise via EDNS.
Set to "none" (the initial default) to disable EDNS large packet support.
@@ -587,6 +591,10 @@
log_fqdn
Obsolete. Replaced by automatic detection of the %>A logformat tag.
+ maximum_single_addr_tries
+
The behaviour controlled by this directive is no longer possible.
+ It has been replaced by connect_retries option which operates a little differently.
+
referer_log
Replaced by the referrer format option on an access_log directive.
=== modified file 'src/CacheManager.h'
--- src/CacheManager.h 2010-10-29 00:12:28 +0000
+++ src/CacheManager.h 2010-11-04 10:07:39 +0000
@@ -34,6 +34,7 @@
#ifndef SQUID_CACHEMANAGER_H
#define SQUID_CACHEMANAGER_H
+#include "comm/forward.h"
#include "mgr/Action.h"
#include "mgr/ActionProfile.h"
#include "mgr/Command.h"
@@ -72,7 +73,7 @@
Mgr::Action::Pointer createRequestedAction(const Mgr::ActionParams &);
const Menu& menu() const { return menu_; }
- void Start(int fd, HttpRequest * request, StoreEntry * entry);
+ void Start(const Comm::ConnectionPointer &client, HttpRequest * request, StoreEntry * entry);
static CacheManager* GetInstance();
const char *ActionProtection(const Mgr::ActionProfilePointer &profile);
=== modified file 'src/CommCalls.cc'
--- src/CommCalls.cc 2009-07-12 22:56:47 +0000
+++ src/CommCalls.cc 2011-03-26 03:51:19 +0000
@@ -1,16 +1,17 @@
#include "squid.h"
#include "fde.h"
+#include "comm/Connection.h"
#include "CommCalls.h"
/* CommCommonCbParams */
CommCommonCbParams::CommCommonCbParams(void *aData):
- data(cbdataReference(aData)), fd(-1), xerrno(0), flag(COMM_OK)
+ data(cbdataReference(aData)), conn(), flag(COMM_OK), xerrno(0), fd(-1)
{
}
CommCommonCbParams::CommCommonCbParams(const CommCommonCbParams &p):
- data(cbdataReference(p.data)), fd(p.fd), xerrno(p.xerrno), flag(p.flag)
+ data(cbdataReference(p.data)), conn(p.conn), flag(p.flag), xerrno(p.xerrno), fd(p.fd)
{
}
@@ -22,7 +23,11 @@
void
CommCommonCbParams::print(std::ostream &os) const
{
- os << "FD " << fd;
+ if (conn != NULL)
+ os << conn;
+ else
+ os << "FD " << fd;
+
if (xerrno)
os << ", errno=" << xerrno;
if (flag != COMM_OK)
@@ -34,17 +39,9 @@
/* CommAcceptCbParams */
-CommAcceptCbParams::CommAcceptCbParams(void *aData): CommCommonCbParams(aData),
- nfd(-1)
-{
-}
-
-void
-CommAcceptCbParams::print(std::ostream &os) const
-{
- CommCommonCbParams::print(os);
- if (nfd >= 0)
- os << ", newFD " << nfd;
+CommAcceptCbParams::CommAcceptCbParams(void *aData):
+ CommCommonCbParams(aData)
+{
}
@@ -61,19 +58,12 @@
// drop the call if the call was scheduled before comm_close but
// is being fired after comm_close
if (fd >= 0 && fd_table[fd].closing()) {
- debugs(5, 3, HERE << "droppin late connect call: FD " << fd);
+ debugs(5, 3, HERE << "dropping late connect call: FD " << fd);
return false;
}
return true; // now we are in sync and can handle the call
}
-void
-CommConnectCbParams::print(std::ostream &os) const
-{
- CommCommonCbParams::print(os);
- os << ", " << dns;
-}
-
/* CommIoCbParams */
CommIoCbParams::CommIoCbParams(void *aData): CommCommonCbParams(aData),
@@ -86,8 +76,8 @@
{
// change parameters if the call was scheduled before comm_close but
// is being fired after comm_close
- if (fd >= 0 && fd_table[fd].closing() && flag != COMM_ERR_CLOSING) {
- debugs(5, 3, HERE << "converting late call to COMM_ERR_CLOSING: FD " << fd);
+ if (conn->fd >= 0 && fd_table[conn->fd].closing() && flag != COMM_ERR_CLOSING) {
+ debugs(5, 3, HERE << "converting late call to COMM_ERR_CLOSING: " << conn);
flag = COMM_ERR_CLOSING;
size = 0;
}
@@ -130,10 +120,16 @@
{
}
+CommAcceptCbPtrFun::CommAcceptCbPtrFun(const CommAcceptCbPtrFun &o):
+ CommDialerParamsT(o.params),
+ handler(o.handler)
+{
+}
+
void
CommAcceptCbPtrFun::dial()
{
- handler(params.fd, params.nfd, ¶ms.details, params.flag, params.xerrno, params.data);
+ handler(params.fd, params.conn, params.flag, params.xerrno, params.data);
}
void
@@ -157,7 +153,7 @@
void
CommConnectCbPtrFun::dial()
{
- handler(params.fd, params.dns, params.flag, params.xerrno, params.data);
+ handler(params.conn, params.flag, params.xerrno, params.data);
}
void
@@ -180,7 +176,7 @@
void
CommIoCbPtrFun::dial()
{
- handler(params.fd, params.buf, params.size, params.flag, params.xerrno, params.data);
+ handler(params.conn, params.buf, params.size, params.flag, params.xerrno, params.data);
}
void
@@ -217,7 +213,7 @@
/* CommTimeoutCbPtrFun */
-CommTimeoutCbPtrFun::CommTimeoutCbPtrFun(PF *aHandler,
+CommTimeoutCbPtrFun::CommTimeoutCbPtrFun(CTCB *aHandler,
const CommTimeoutCbParams &aParams):
CommDialerParamsT(aParams),
handler(aHandler)
@@ -227,7 +223,7 @@
void
CommTimeoutCbPtrFun::dial()
{
- handler(params.fd, params.data);
+ handler(params);
}
void
=== modified file 'src/CommCalls.h'
--- src/CommCalls.h 2011-01-27 01:12:25 +0000
+++ src/CommCalls.h 2011-02-17 11:13:19 +0000
@@ -6,22 +6,29 @@
#ifndef SQUID_COMMCALLS_H
#define SQUID_COMMCALLS_H
-#include "comm.h"
-#include "ConnectionDetail.h"
-#include "DnsLookupDetails.h"
#include "base/AsyncCall.h"
#include "base/AsyncJobCalls.h"
+#include "comm_err_t.h"
+#include "comm/forward.h"
/* CommCalls implement AsyncCall interface for comm_* callbacks.
* The classes cover two call dialer kinds:
* - A C-style call using a function pointer (depricated);
* - A C++-style call to an AsyncJob child.
- * and three comm_* callback kinds:
- * - accept (IOACB),
- * - connect (CNCB),
- * - I/O (IOCB).
+ * and several comm_* callback kinds:
+ * - accept (IOACB)
+ * - connect (CNCB)
+ * - I/O (IOCB)
+ * - timeout (CTCB)
*/
+typedef void IOACB(int fd, const Comm::ConnectionPointer &details, comm_err_t flag, int xerrno, void *data);
+typedef void CNCB(const Comm::ConnectionPointer &conn, comm_err_t status, int xerrno, void *data);
+typedef void IOCB(const Comm::ConnectionPointer &conn, char *, size_t size, comm_err_t flag, int xerrno, void *data);
+
+class CommTimeoutCbParams;
+typedef void CTCB(const CommTimeoutCbParams ¶ms);
+
/*
* TODO: When there are no function-pointer-based callbacks left, all
* this complexity can be removed. Jobs that need comm services will just
@@ -51,10 +58,22 @@
public:
void *data; // cbdata-protected
- int fd;
- int xerrno;
- comm_err_t flag;
-
+
+ /** The connection which this call pertains to.
+ * \itemize On accept() calls this is the new client connection.
+ * \itemize On connect() finished calls this is the newely opened connection.
+ * \itemize On write calls this is the connection just written to.
+ * \itemize On read calls this is the connection just read from.
+ * \itemize On close calls this describes the connection which is now closed.
+ * \itemize On timeouts this is the connection whose operation timed out.
+ * NP: timeouts might also return to the connect/read/write handler with COMM_ERR_TIMEOUT.
+ */
+ Comm::ConnectionPointer conn;
+
+ comm_err_t flag; ///< comm layer result status.
+ int xerrno; ///< The last errno to occur. non-zero if flag is COMM_ERR.
+
+ int fd; // raw FD which the call was about. use conn instead for new code.
private:
// should not be needed and not yet implemented
CommCommonCbParams &operator =(const CommCommonCbParams ¶ms);
@@ -65,12 +84,6 @@
{
public:
CommAcceptCbParams(void *aData);
-
- void print(std::ostream &os) const;
-
-public:
- ConnectionDetail details;
- int nfd; // TODO: rename to fdNew or somesuch
};
// connect parameters
@@ -80,11 +93,6 @@
CommConnectCbParams(void *aData);
bool syncWithComm(); // see CommCommonCbParams::syncWithComm
-
- void print(std::ostream &os) const;
-
-public:
- DnsLookupDetails dns;
};
// read/write (I/O) parameters
@@ -179,6 +187,8 @@
typedef RefCount Pointer;
CommAcceptCbPtrFun(IOACB *aHandler, const CommAcceptCbParams &aParams);
+ CommAcceptCbPtrFun(const CommAcceptCbPtrFun &o);
+
void dial();
virtual void print(std::ostream &os) const;
@@ -243,13 +253,13 @@
public:
typedef CommTimeoutCbParams Params;
- CommTimeoutCbPtrFun(PF *aHandler, const Params &aParams);
+ CommTimeoutCbPtrFun(CTCB *aHandler, const Params &aParams);
void dial();
virtual void print(std::ostream &os) const;
public:
- PF *handler;
+ CTCB *handler;
};
// AsyncCall to comm handlers implemented as global functions.
=== modified file 'src/CommRead.h'
--- src/CommRead.h 2010-11-21 04:40:05 +0000
+++ src/CommRead.h 2010-12-03 05:45:25 +0000
@@ -39,15 +39,16 @@
#include "squid.h"
#include "comm.h"
#include "CommCalls.h"
+#include "comm/forward.h"
#include "CbDataList.h"
class CommRead
{
public:
- CommRead ();
- CommRead (int fd, char *buf, int len, AsyncCall::Pointer &callback);
- int fd;
+ CommRead();
+ CommRead(const Comm::ConnectionPointer &c, char *buf, int len, AsyncCall::Pointer &callback);
+ Comm::ConnectionPointer conn;
char *buf;
int len;
AsyncCall::Pointer callback;
=== modified file 'src/DelayTagged.cc'
--- src/DelayTagged.cc 2010-11-27 06:44:33 +0000
+++ src/DelayTagged.cc 2011-03-12 02:54:11 +0000
@@ -39,6 +39,7 @@
#if USE_DELAY_POOLS
#include "squid.h"
+#include "comm/Connection.h"
#include "DelayTagged.h"
#include "NullDelayId.h"
#include "Store.h"
=== modified file 'src/DelayUser.cc'
--- src/DelayUser.cc 2010-11-27 06:44:33 +0000
+++ src/DelayUser.cc 2011-03-26 03:57:39 +0000
@@ -42,6 +42,7 @@
#include "DelayUser.h"
#include "auth/UserRequest.h"
#include "auth/User.h"
+#include "comm/Connection.h"
#include "NullDelayId.h"
#include "Store.h"
=== modified file 'src/DelayVector.cc'
--- src/DelayVector.cc 2010-11-27 06:44:33 +0000
+++ src/DelayVector.cc 2011-03-26 03:58:02 +0000
@@ -41,6 +41,7 @@
#if USE_DELAY_POOLS
#include "squid.h"
+#include "comm/Connection.h"
#include "DelayVector.h"
#include "CommRead.h"
=== modified file 'src/HttpRequest.cc'
--- src/HttpRequest.cc 2011-03-11 22:22:13 +0000
+++ src/HttpRequest.cc 2011-03-26 03:59:10 +0000
@@ -35,6 +35,7 @@
*/
#include "squid.h"
+#include "DnsLookupDetails.h"
#include "HttpRequest.h"
#if USE_AUTH
#include "auth/UserRequest.h"
@@ -96,10 +97,6 @@
imslen = 0;
lastmod = -1;
client_addr.SetEmpty();
-#if USE_SQUID_EUI
- client_eui48.clear();
- client_eui64.clear();
-#endif
my_addr.SetEmpty();
body_pipe = NULL;
// hier
@@ -614,14 +611,13 @@
if (!aReq)
return false;
+ // main property is which connection the request was received on (if any)
+ clientConnectionManager = aReq->clientConnectionManager;
+
client_addr = aReq->client_addr;
#if FOLLOW_X_FORWARDED_FOR
indirect_client_addr = aReq->indirect_client_addr;
#endif
-#if USE_SQUID_EUI
- client_eui48 = aReq->client_eui48;
- client_eui64 = aReq->client_eui64;
-#endif
my_addr = aReq->my_addr;
dnsWait = aReq->dnsWait;
=== modified file 'src/HttpRequest.h'
--- src/HttpRequest.h 2011-03-11 22:22:13 +0000
+++ src/HttpRequest.h 2011-03-23 09:42:23 +0000
@@ -183,13 +183,6 @@
Ip::Address indirect_client_addr;
#endif /* FOLLOW_X_FORWARDED_FOR */
-#if USE_SQUID_EUI
- /* TODO these might be merged into one field if we can reliably map the EUI-48 into EUI-64
- there are some OS differences in the upper bytes. */
- Eui::Eui48 client_eui48;
- Eui::Eui64 client_eui64;
-#endif
-
Ip::Address my_addr;
HierarchyLogEntry hier;
@@ -261,7 +254,7 @@
}
/// client-side conn manager, if known; used for 1xx response forwarding
- CbcPointer clientConnection;
+ CbcPointer clientConnectionManager;
int64_t getRangeOffsetLimit(); /* the result of this function gets cached in rangeOffsetLimit */
=== modified file 'src/ICP.h'
--- src/ICP.h 2010-07-06 12:44:06 +0000
+++ src/ICP.h 2010-10-02 05:20:31 +0000
@@ -38,6 +38,8 @@
\ingroup ServerProtocol
*/
+#include "comm/forward.h"
+#include "ip/Address.h"
#include "StoreClient.h"
/**
@@ -121,6 +123,10 @@
struct timeval queue_time;
};
+extern Comm::ConnectionPointer icpIncomingConn;
+extern Comm::ConnectionPointer icpOutgoingConn;
+extern Ip::Address theIcpPublicHostID;
+
/// \ingroup ServerProtocolICPAPI
HttpRequest* icpGetRequest(char *url, int reqnum, int fd, Ip::Address &from);
=== modified file 'src/Makefile.am'
--- src/Makefile.am 2011-03-24 14:00:41 +0000
+++ src/Makefile.am 2011-03-26 01:48:58 +0000
@@ -47,8 +47,8 @@
if ENABLE_SSL
SUBDIRS += ssl
SSL_LIBS = \
- ssl/libsslutil.la \
- ssl/libsslsquid.la
+ ssl/libsslsquid.la \
+ ssl/libsslutil.la
else
SSL_LOCAL_LIBS =
endif
@@ -289,7 +289,6 @@
ConfigOption.cc \
ConfigParser.cc \
ConfigParser.h \
- ConnectionDetail.h \
CpuAffinity.cc \
CpuAffinity.h \
CpuAffinityMap.cc \
@@ -612,6 +611,12 @@
unlinkd_SOURCES = unlinkd_daemon.cc
+unlinkd_LDADD = \
+ ipc/libipc.la \
+ ip/libip.la \
+ $(COMPAT_LIB) \
+ $(XTRA_LIBS)
+
dnsserver_SOURCES = dnsserver.cc SquidNew.cc tests/stub_debug.cc test_tools.cc time.cc
recv_announce_SOURCES = recv-announce.cc
@@ -1517,15 +1522,18 @@
eui/libeui.la \
acl/libstate.la \
$(AUTH_LIBS) \
+ libsquid.la \
+ comm/libcomm.la \
base/libbase.la \
- libsquid.la \
ip/libip.la \
fs/libfs.la \
+ ipc/libipc.la \
$(REPL_OBJS) \
$(DISK_LIBS) \
$(DISK_OS_LIBS) \
acl/libapi.la \
mgr/libmgr.la \
+ $(SSL_LIBS) \
$(top_builddir)/lib/libmisccontainers.la \
$(top_builddir)/lib/libmiscencoding.la \
$(top_builddir)/lib/libmiscutil.la \
@@ -2398,7 +2406,11 @@
tests/testMain.cc \
tests/testUfs.h \
tests/stub_cache_manager.cc \
+ tests/stub_client_db.cc \
tests/stub_HelperChildConfig.cc \
+ tests/stub_icp.cc \
+ tests/stub_ipc.cc \
+ tests/stub_pconn.cc \
tests/stub_Port.cc \
tests/stub_TypedMsgHdr.cc \
tests/stub_UdsOp.cc \
@@ -2489,7 +2501,6 @@
SquidMath.h \
swap_log_op.cc
tests_testUfs_LDADD = \
- anyp/libanyp.la \
CommCalls.o \
DnsLookupDetails.o \
$(AUTH_ACL_LIBS) \
@@ -2506,9 +2517,24 @@
ipc/libipc.la \
mgr/libmgr.la \
$(REPL_OBJS) \
+ acl/libacls.la \
+ anyp/libanyp.la \
$(DISK_LIBS) \
$(DISK_OS_LIBS) \
+ auth/libacls.la \
+ ident/libident.la \
+ eui/libeui.la \
+ acl/libstate.la \
+ auth/libauth.la \
acl/libapi.la \
+ fs/libfs.la \
+ ipc/libipc.la \
+ mgr/libmgr.la \
+ libsquid.la \
+ $(SSL_LIBS) \
+ comm/libcomm.la \
+ base/libbase.la \
+ ip/libip.la \
$(top_builddir)/lib/libmisccontainers.la \
$(top_builddir)/lib/libmiscencoding.la \
$(top_builddir)/lib/libmiscutil.la \
@@ -2633,11 +2659,14 @@
$(REPL_OBJS) \
$(DISK_LIBS) \
$(DISK_OS_LIBS) \
+ $(COMMON_LIBS) \
+ libsquid.la \
acl/libapi.la \
$(top_builddir)/lib/libmisccontainers.la \
$(top_builddir)/lib/libmiscencoding.la \
$(top_builddir)/lib/libmiscutil.la \
$(SQUID_CPPUNIT_LIBS) \
+ $(REGEXLIB) \
$(SSLLIB) \
$(COMPAT_LIB) \
$(XTRA_LIBS)
=== modified file 'src/MemObject.cc'
--- src/MemObject.cc 2011-01-27 12:23:25 +0000
+++ src/MemObject.cc 2011-01-28 05:01:37 +0000
@@ -34,6 +34,7 @@
*/
#include "squid.h"
+#include "comm/Connection.h"
#include "MemObject.h"
#include "HttpRequest.h"
#include "HttpReply.h"
=== modified file 'src/PeerSelectState.h'
--- src/PeerSelectState.h 2010-05-02 19:32:42 +0000
+++ src/PeerSelectState.h 2011-03-26 04:01:44 +0000
@@ -33,10 +33,38 @@
#ifndef SQUID_PEERSELECTSTATE_H
#define SQUID_PEERSELECTSTATE_H
+#include "Array.h"
#include "cbdata.h"
+#include "comm/forward.h"
+#include "hier_code.h"
#include "PingData.h"
#include "ip/Address.h"
+class HttpRequest;
+class StoreEntry;
+
+typedef void PSC(Comm::ConnectionList *, void *);
+
+SQUIDCEXTERN void peerSelect(Comm::ConnectionList *, HttpRequest *, StoreEntry *, PSC *, void *data);
+SQUIDCEXTERN void peerSelectInit(void);
+
+/**
+ * A peer which has been selected as a possible destination.
+ * Listed as pointers here so as to prevent duplicates being added but will
+ * be converted to a set of IP address path options before handing back out
+ * to the caller.
+ *
+ * Certain connection flags and outgoing settings will also be looked up and
+ * set based on the received request and peer settings before handing back.
+ */
+class FwdServer
+{
+public:
+ peer *_peer; /* NULL --> origin server */
+ hier_code code;
+ FwdServer *next;
+};
+
class ps_state
{
@@ -50,7 +78,10 @@
int direct;
PSC *callback;
void *callback_data;
- FwdServer *servers;
+
+ Comm::ConnectionList *paths; ///< the callers paths array. to be filled with our final results.
+ FwdServer *servers; ///< temporary linked list of peers we will pass back.
+
/*
* Why are these Ip::Address instead of peer *? Because a
* peer structure can become invalid during the peer selection
=== modified file 'src/ProtoPort.cc'
--- src/ProtoPort.cc 2011-01-26 03:47:13 +0000
+++ src/ProtoPort.cc 2011-03-26 04:02:11 +0000
@@ -9,11 +9,10 @@
#include
#endif
-http_port_list::http_port_list(const char *aProtocol) :
- listenFd(-1)
+http_port_list::http_port_list(const char *aProtocol)
#if USE_SSL
- , http(*this)
- , dynamicCertMemCacheSize(std::numeric_limits::max())
+ : http(*this),
+ dynamicCertMemCacheSize(std::numeric_limits::max())
#endif
{
protocol = xstrdup(aProtocol);
@@ -21,9 +20,9 @@
http_port_list::~http_port_list()
{
- if (listenFd >= 0) {
- comm_close(listenFd);
- listenFd = -1;
+ if (Comm::IsConnOpen(listenConn)) {
+ listenConn->close();
+ listenConn = NULL;
}
safe_free(name);
=== modified file 'src/ProtoPort.h'
--- src/ProtoPort.h 2011-01-26 03:47:13 +0000
+++ src/ProtoPort.h 2011-03-26 04:02:45 +0000
@@ -1,10 +1,12 @@
/*
* $Id$
*/
+
#ifndef SQUID_PROTO_PORT_H
#define SQUID_PROTO_PORT_H
#include "cbdata.h"
+#include "comm/Connection.h"
#if USE_SSL
#include "ssl/gadgets.h"
@@ -41,11 +43,11 @@
} tcp_keepalive;
/**
- * The FD listening socket.
- * If >= 0 we are actively listening for client requests.
- * use comm_close(listenFd) to stop.
+ * The listening socket details.
+ * If Comm::ConnIsOpen() we are actively listening for client requests.
+ * use listenConn->close() to stop.
*/
- int listenFd;
+ Comm::ConnectionPointer listenConn;
#if USE_SSL
// XXX: temporary hack to ease move of SSL options to http_port
=== modified file 'src/Server.cc'
--- src/Server.cc 2011-03-11 23:02:23 +0000
+++ src/Server.cc 2011-03-26 04:03:13 +0000
@@ -35,10 +35,11 @@
#include "squid.h"
#include "acl/Gadgets.h"
#include "base/TextException.h"
+#include "comm/Connection.h"
+#include "comm/forward.h"
#include "comm/Write.h"
#include "Server.h"
#include "Store.h"
-#include "fde.h" /* for fd_table[fd].closing */
#include "HttpRequest.h"
#include "HttpReply.h"
#include "errorpage.h"
@@ -403,22 +404,16 @@
debugs(9,3, HERE << "waiting for body production end or abort");
}
-bool
-ServerStateData::canSend(int fd) const
-{
- return fd >= 0 && !fd_table[fd].closing();
-}
-
void
ServerStateData::sendMoreRequestBody()
{
assert(requestBodySource != NULL);
assert(!requestSender);
- const int fd = dataDescriptor();
+ const Comm::ConnectionPointer conn = dataDescriptor();
- if (!canSend(fd)) {
- debugs(9,3, HERE << "cannot send request body to closing FD " << fd);
+ if (!Comm::IsConnOpen(conn)) {
+ debugs(9,3, HERE << "cannot send request body to closing " << conn);
return; // wait for the kid's close handler; TODO: assert(closer);
}
@@ -426,9 +421,8 @@
if (getMoreRequestBody(buf) && buf.contentSize() > 0) {
debugs(9,3, HERE << "will write " << buf.contentSize() << " request body bytes");
typedef CommCbMemFunT Dialer;
- requestSender = JobCallback(93,3,
- Dialer, this, ServerStateData::sentRequestBody);
- Comm::Write(fd, &buf, requestSender);
+ requestSender = JobCallback(93,3, Dialer, this, ServerStateData::sentRequestBody);
+ Comm::Write(conn, &buf, requestSender);
} else {
debugs(9,3, HERE << "will wait for more request body bytes or eof");
requestSender = NULL;
=== modified file 'src/Server.h'
--- src/Server.h 2011-03-11 23:02:23 +0000
+++ src/Server.h 2011-03-26 04:05:58 +0000
@@ -39,7 +39,6 @@
#include "BodyPipe.h"
#include "base/AsyncJob.h"
#include "CommCalls.h"
-
#if USE_ADAPTATION
#include "adaptation/forward.h"
#include "adaptation/Initiator.h"
@@ -68,8 +67,8 @@
ServerStateData(FwdState *);
virtual ~ServerStateData();
- /// \return primary or "request data connection" fd
- virtual int dataDescriptor() const = 0;
+ /// \return primary or "request data connection"
+ virtual const Comm::ConnectionPointer & dataDescriptor() const = 0;
// BodyConsumer: consume request body or adapted response body.
// The implementation just calls the corresponding HTTP or ICAP handle*()
@@ -130,8 +129,6 @@
void handleRequestBodyProductionEnded();
virtual void handleRequestBodyProducerAborted() = 0;
- /// whether it is not too late to write to the server
- bool canSend(int fd) const;
// sending of the request body to the server
void sendMoreRequestBody();
// has body; kids overwrite to increment I/O stats counters
=== modified file 'src/Store.h'
--- src/Store.h 2010-12-04 13:10:19 +0000
+++ src/Store.h 2010-12-08 05:22:33 +0000
@@ -42,6 +42,7 @@
#include "Range.h"
#include "RefCount.h"
#include "CommRead.h"
+#include "comm/forward.h"
#include "Packer.h"
#include "RemovalPolicy.h"
@@ -131,7 +132,7 @@
void destroyMemObject();
int checkTooSmall();
- void delayAwareRead(int fd, char *buf, int len, AsyncCall::Pointer callback);
+ void delayAwareRead(const Comm::ConnectionPointer &conn, char *buf, int len, AsyncCall::Pointer callback);
void setNoDelay (bool const);
bool modifiedSince(HttpRequest * request) const;
=== modified file 'src/acl/Asn.cc'
--- src/acl/Asn.cc 2010-12-13 11:31:14 +0000
+++ src/acl/Asn.cc 2011-01-08 11:26:11 +0000
@@ -249,7 +249,8 @@
if ((e = storeGetPublic(asres, METHOD_GET)) == NULL) {
e = storeCreateEntry(asres, asres, request_flags(), METHOD_GET);
asState->sc = storeClientListAdd(e, asState);
- FwdState::fwdStart(-1, e, asState->request);
+ Comm::ConnectionPointer nul;
+ FwdState::fwdStart(nul, e, asState->request);
} else {
e->lock();
=== modified file 'src/acl/FilledChecklist.cc'
--- src/acl/FilledChecklist.cc 2011-02-07 10:27:53 +0000
+++ src/acl/FilledChecklist.cc 2011-03-03 06:23:45 +0000
@@ -7,6 +7,8 @@
#include "auth/AclProxyAuth.h"
#endif
#include "acl/FilledChecklist.h"
+#include "comm/Connection.h"
+#include "comm/forward.h"
CBDATA_CLASS_INIT(ACLFilledChecklist);
@@ -112,13 +114,13 @@
int
ACLFilledChecklist::fd() const
{
- return conn_ != NULL ? conn_->fd : fd_;
+ return (conn_ != NULL && conn_->clientConnection != NULL) ? conn_->clientConnection->fd : fd_;
}
void
ACLFilledChecklist::fd(int aDescriptor)
{
- assert(!conn() || conn()->fd == aDescriptor);
+ assert(!conn() || conn()->clientConnection == NULL || conn()->clientConnection->fd == aDescriptor);
fd_ = aDescriptor;
}
=== modified file 'src/adaptation/icap/ModXact.cc'
--- src/adaptation/icap/ModXact.cc 2011-03-23 00:18:28 +0000
+++ src/adaptation/icap/ModXact.cc 2011-03-23 09:42:23 +0000
@@ -18,6 +18,7 @@
#include "base64.h"
#include "ChunkedCodingParser.h"
#include "comm.h"
+#include "comm/Connection.h"
#include "HttpMsg.h"
#include "HttpRequest.h"
#include "HttpReply.h"
@@ -479,7 +480,7 @@
void Adaptation::Icap::ModXact::startReading()
{
- Must(connection >= 0);
+ Must(haveConnection());
Must(!reader);
Must(!adapted.header);
Must(!adapted.body_pipe);
@@ -647,7 +648,7 @@
stopParsing();
stopWriting(true); // or should we force it?
- if (connection >= 0) {
+ if (haveConnection()) {
reuseConnection = false; // be conservative
cancelRead(); // may not work; and we cannot stop connecting either
if (!doneWithIo())
@@ -1604,7 +1605,7 @@
if (virgin.body_pipe != NULL)
buf.append("R", 1);
- if (connection > 0 && !doneReading())
+ if (haveConnection() && !doneReading())
buf.append("r", 1);
if (!state.doneWriting() && state.writing != State::writingInit)
=== modified file 'src/adaptation/icap/Xaction.cc'
--- src/adaptation/icap/Xaction.cc 2010-11-27 01:46:22 +0000
+++ src/adaptation/icap/Xaction.cc 2011-03-26 04:11:29 +0000
@@ -4,6 +4,8 @@
#include "squid.h"
#include "comm.h"
+#include "comm/Connection.h"
+#include "comm/ConnOpener.h"
#include "comm/Write.h"
#include "CommCalls.h"
#include "HttpMsg.h"
@@ -14,7 +16,6 @@
#include "pconn.h"
#include "HttpRequest.h"
#include "HttpReply.h"
-#include "ip/tools.h"
#include "acl/FilledChecklist.h"
#include "icap_log.h"
#include "fde.h"
@@ -26,14 +27,13 @@
//CBDATA_NAMESPACED_CLASS_INIT(Adaptation::Icap, Xaction);
-Adaptation::Icap::Xaction::Xaction(const char *aTypeName,
- Adaptation::Icap::ServiceRep::Pointer &aService):
+Adaptation::Icap::Xaction::Xaction(const char *aTypeName, Adaptation::Icap::ServiceRep::Pointer &aService):
AsyncJob(aTypeName),
Adaptation::Initiate(aTypeName),
icapRequest(NULL),
icapReply(NULL),
attempts(0),
- connection(-1),
+ connection(NULL),
theService(aService),
commBuf(NULL), commBufSize(0),
commEof(false),
@@ -88,28 +88,35 @@
}
// TODO: obey service-specific, OPTIONS-reported connection limit
-void Adaptation::Icap::Xaction::openConnection()
+void
+Adaptation::Icap::Xaction::openConnection()
{
- Ip::Address client_addr;
-
- Must(connection < 0);
+ Must(!haveConnection());
const Adaptation::Service &s = service();
if (!TheConfig.reuse_connections)
disableRetries(); // this will also safely drain pconn pool
+ connection = new Comm::Connection;
+
+ /* NP: set these here because it applies whether a pconn or a new conn is used */
+
+ // TODO: Avoid blocking lookup if s.cfg().host is a hostname
+ connection->remote = s.cfg().host.termedBuf();
+ connection->remote.SetPort(s.cfg().port);
+
// TODO: check whether NULL domain is appropriate here
- connection = icapPconnPool->pop(s.cfg().host.termedBuf(), s.cfg().port, NULL, client_addr, isRetriable);
- if (connection >= 0) {
- debugs(93,3, HERE << "reused pconn FD " << connection);
+ icapPconnPool->pop(connection, NULL, isRetriable);
+ if (connection->isOpen()) {
+ debugs(93,3, HERE << "reused pconn " << connection);
// fake the connect callback
// TODO: can we sync call Adaptation::Icap::Xaction::noteCommConnected here instead?
typedef CommCbMemFunT Dialer;
CbcPointer self(this);
Dialer dialer(self, &Adaptation::Icap::Xaction::noteCommConnected);
- dialer.params.fd = connection;
+ dialer.params.conn = connection;
dialer.params.flag = COMM_OK;
// fake other parameters by copying from the existing connection
connector = asyncCall(93,3, "Adaptation::Icap::Xaction::noteCommConnected", dialer);
@@ -119,40 +126,11 @@
disableRetries(); // we only retry pconn failures
- Ip::Address outgoing;
- if (!Ip::EnableIpv6 && !outgoing.SetIPv4()) {
- debugs(31, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << outgoing << " is not an IPv4 address.");
- dieOnConnectionFailure(); // throws
- }
- /* split-stack for now requires default IPv4-only socket */
- if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && outgoing.IsAnyAddr() && !s.cfg().ipv6) {
- outgoing.SetIPv4();
- }
-
- connection = comm_open(SOCK_STREAM, 0, outgoing,
- COMM_NONBLOCKING, s.cfg().uri.termedBuf());
-
- if (connection < 0)
- dieOnConnectionFailure(); // throws
-
- debugs(93,3, typeName << " opens connection to " << s.cfg().host << ":" << s.cfg().port);
-
- // TODO: service bypass status may differ from that of a transaction
- typedef CommCbMemFunT TimeoutDialer;
- AsyncCall::Pointer timeoutCall = JobCallback(93, 5,
- TimeoutDialer, this, Adaptation::Icap::Xaction::noteCommTimedout);
- commSetTimeout(connection, TheConfig.connect_timeout(
- service().cfg().bypass), timeoutCall);
-
- typedef CommCbMemFunT CloseDialer;
- closer = JobCallback(93, 5,
- CloseDialer, this, Adaptation::Icap::Xaction::noteCommClosed);
- comm_add_close_handler(connection, closer);
-
typedef CommCbMemFunT ConnectDialer;
- connector = JobCallback(93,3,
- ConnectDialer, this, Adaptation::Icap::Xaction::noteCommConnected);
- commConnectStart(connection, s.cfg().host.termedBuf(), s.cfg().port, connector);
+ connector = JobCallback(93,3, ConnectDialer, this, Adaptation::Icap::Xaction::noteCommConnected);
+ Comm::ConnOpener *cs = new Comm::ConnOpener(connection, connector, TheConfig.connect_timeout(service().cfg().bypass));
+ cs->setHost(s.cfg().host.termedBuf());
+ AsyncJob::Start(cs);
}
/*
@@ -171,10 +149,10 @@
void Adaptation::Icap::Xaction::closeConnection()
{
- if (connection >= 0) {
+ if (haveConnection()) {
if (closer != NULL) {
- comm_remove_close_handler(connection, closer);
+ comm_remove_close_handler(connection->fd, closer);
closer = NULL;
}
@@ -187,38 +165,44 @@
}
if (reuseConnection) {
- Ip::Address client_addr;
//status() adds leading spaces.
debugs(93,3, HERE << "pushing pconn" << status());
- AsyncCall::Pointer call = NULL;
- commSetTimeout(connection, -1, call);
- icapPconnPool->push(connection, theService->cfg().host.termedBuf(),
- theService->cfg().port, NULL, client_addr);
+ commUnsetConnTimeout(connection);
+ icapPconnPool->push(connection, NULL);
disableRetries();
} else {
//status() adds leading spaces.
debugs(93,3, HERE << "closing pconn" << status());
- // comm_close will clear timeout
- comm_close(connection);
+ connection->close();
}
writer = NULL;
reader = NULL;
connector = NULL;
- connection = -1;
+ connection = NULL;
}
}
// connection with the ICAP service established
void Adaptation::Icap::Xaction::noteCommConnected(const CommConnectCbParams &io)
{
+ if (io.flag == COMM_TIMEOUT) {
+ handleCommTimedout();
+ return;
+ }
+
Must(connector != NULL);
connector = NULL;
if (io.flag != COMM_OK)
dieOnConnectionFailure(); // throws
- fd_table[connection].noteUse(icapPconnPool);
+ typedef CommCbMemFunT CloseDialer;
+ closer = asyncCall(93, 5, "Adaptation::Icap::Xaction::noteCommClosed",
+ CloseDialer(this,&Adaptation::Icap::Xaction::noteCommClosed));
+ comm_add_close_handler(io.conn->fd, closer);
+
+ fd_table[io.conn->fd].noteUse(icapPconnPool);
handleCommConnected();
}
@@ -233,9 +217,11 @@
void Adaptation::Icap::Xaction::scheduleWrite(MemBuf &buf)
{
+ Must(haveConnection());
+
// comm module will free the buffer
typedef CommCbMemFunT Dialer;
- writer = JobCallback(93,3,
+ writer = JobCallback(93, 3,
Dialer, this, Adaptation::Icap::Xaction::noteCommWrote);
Comm::Write(connection, &buf, writer);
@@ -315,27 +301,25 @@
void Adaptation::Icap::Xaction::updateTimeout()
{
+ Must(haveConnection());
+
if (reader != NULL || writer != NULL) {
// restart the timeout before each I/O
// XXX: why does Config.Timeout lacks a write timeout?
// TODO: service bypass status may differ from that of a transaction
typedef CommCbMemFunT TimeoutDialer;
- AsyncCall::Pointer call = JobCallback(93,5,
- TimeoutDialer, this, Adaptation::Icap::Xaction::noteCommTimedout);
-
- commSetTimeout(connection,
- TheConfig.io_timeout(service().cfg().bypass), call);
+ AsyncCall::Pointer call = JobCallback(93, 5, TimeoutDialer, this, Adaptation::Icap::Xaction::noteCommTimedout);
+ commSetConnTimeout(connection, TheConfig.io_timeout(service().cfg().bypass), call);
} else {
// clear timeout when there is no I/O
// Do we need a lifetime timeout?
- AsyncCall::Pointer call = NULL;
- commSetTimeout(connection, -1, call);
+ commUnsetConnTimeout(connection);
}
}
void Adaptation::Icap::Xaction::scheduleRead()
{
- Must(connection >= 0);
+ Must(haveConnection());
Must(!reader);
Must(readBuf.hasSpace());
@@ -344,7 +328,7 @@
* here instead of reading directly into readBuf.buf.
*/
typedef CommCbMemFunT Dialer;
- reader = JobCallback(93,3,
+ reader = JobCallback(93, 3,
Dialer, this, Adaptation::Icap::Xaction::noteCommRead);
comm_read(connection, commBuf, readBuf.spaceSize(), reader);
@@ -393,7 +377,8 @@
void Adaptation::Icap::Xaction::cancelRead()
{
if (reader != NULL) {
- comm_read_cancel(connection, reader);
+ Must(haveConnection());
+ comm_read_cancel(connection->fd, reader);
reader = NULL;
}
}
@@ -434,11 +419,16 @@
bool Adaptation::Icap::Xaction::doneWithIo() const
{
- return connection >= 0 && // or we could still be waiting to open it
+ return haveConnection() &&
!connector && !reader && !writer && // fast checks, some redundant
doneReading() && doneWriting();
}
+bool Adaptation::Icap::Xaction::haveConnection() const
+{
+ return connection != NULL && connection->isOpen();
+}
+
// initiator aborted
void Adaptation::Icap::Xaction::noteInitiatorAborted()
{
@@ -552,8 +542,8 @@
void Adaptation::Icap::Xaction::fillPendingStatus(MemBuf &buf) const
{
- if (connection >= 0) {
- buf.Printf("FD %d", connection);
+ if (haveConnection()) {
+ buf.Printf("FD %d", connection->fd);
if (writer != NULL)
buf.append("w", 1);
@@ -567,8 +557,8 @@
void Adaptation::Icap::Xaction::fillDoneStatus(MemBuf &buf) const
{
- if (connection >= 0 && commEof)
- buf.Printf("Comm(%d)", connection);
+ if (haveConnection() && commEof)
+ buf.Printf("Comm(%d)", connection->fd);
if (stopReason != NULL)
buf.Printf("Stopped");
=== modified file 'src/adaptation/icap/Xaction.h'
--- src/adaptation/icap/Xaction.h 2010-10-21 08:13:41 +0000
+++ src/adaptation/icap/Xaction.h 2010-11-04 09:30:59 +0000
@@ -34,7 +34,7 @@
#ifndef SQUID_ICAPXACTION_H
#define SQUID_ICAPXACTION_H
-#include "comm.h"
+#include "comm/forward.h"
#include "CommCalls.h"
#include "MemBuf.h"
#include "adaptation/icap/ServiceRep.h"
@@ -102,6 +102,7 @@
void openConnection();
void closeConnection();
void dieOnConnectionFailure();
+ bool haveConnection() const;
void scheduleRead();
void scheduleWrite(MemBuf &buf);
@@ -145,7 +146,7 @@
void maybeLog();
protected:
- int connection; // FD of the ICAP server connection
+ Comm::ConnectionPointer connection; ///< ICAP server connection
Adaptation::Icap::ServiceRep::Pointer theService;
/*
=== modified file 'src/auth/UserRequest.cc'
--- src/auth/UserRequest.cc 2010-05-06 11:07:19 +0000
+++ src/auth/UserRequest.cc 2011-03-26 04:12:57 +0000
@@ -48,6 +48,7 @@
*/
#include "auth/Config.h"
#include "auth/Scheme.h"
+#include "comm/Connection.h"
#include "HttpReply.h"
#include "HttpRequest.h"
@@ -345,7 +346,9 @@
debugs(29, 9, HERE << "header " << (proxy_auth ? proxy_auth : "-") << ".");
if (*auth_user_request == NULL) {
- debugs(29, 9, HERE << "This is a new checklist test on FD:" << (conn != NULL ? conn->fd : -1) );
+ if (conn != NULL) {
+ debugs(29, 9, HERE << "This is a new checklist test on:" << conn->clientConnection);
+ }
if (proxy_auth && request->auth_user_request == NULL && conn != NULL && conn->auth_user_request != NULL) {
AuthConfig * scheme = AuthConfig::Find(proxy_auth);
=== modified file 'src/cache_cf.cc'
--- src/cache_cf.cc 2011-03-18 22:09:08 +0000
+++ src/cache_cf.cc 2011-03-23 09:42:23 +0000
@@ -673,12 +673,9 @@
else
Config.appendDomainLen = 0;
- if (Config.retry.maxtries > 10)
- fatal("maximum_single_addr_tries cannot be larger than 10");
-
- if (Config.retry.maxtries < 1) {
- debugs(3, 0, "WARNING: resetting 'maximum_single_addr_tries to 1");
- Config.retry.maxtries = 1;
+ if (Config.connect_retries > 10) {
+ debugs(0,DBG_CRITICAL, "WARNING: connect_retries cannot be larger than 10. Resetting to 10.");
+ Config.connect_retries = 10;
}
requirePathnameExists("MIME Config Table", Config.mimeTablePathname);
@@ -2348,7 +2345,7 @@
p->icp.version = ICP_VERSION_CURRENT;
- p->test_fd = -1;
+ p->testing_now = false;
#if USE_CACHE_DIGESTS
@@ -3545,7 +3542,7 @@
if (Ip::EnableIpv6)
debugs(3, DBG_IMPORTANT, "Disabling IPv6 on port " << s->s << " (interception enabled)");
if ( !s->s.SetIPv4() ) {
- debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: IPv6 addresses cannot be transparent (protocol does not provide NAT)" << s->s );
+ debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: IPv6 addresses cannot NAT intercept (protocol does not provide NAT)" << s->s );
self_destruct();
}
} else if (strcmp(token, "tproxy") == 0) {
=== modified file 'src/cache_manager.cc'
--- src/cache_manager.cc 2011-01-28 18:34:27 +0000
+++ src/cache_manager.cc 2011-03-26 04:15:07 +0000
@@ -36,6 +36,7 @@
#include "config.h"
#include "base/TextException.h"
#include "CacheManager.h"
+#include "comm/Connection.h"
#include "Debug.h"
#include "errorpage.h"
#include "fde.h"
@@ -90,12 +91,6 @@
}
}
-/**
- \ingroup CacheManagerAPI
- * Registers a C-style action, which is implemented as a pointer to a function
- * taking as argument a pointer to a StoreEntry and returning void.
- * Implemented via CacheManagerActionLegacy.
- */
void
CacheManager::registerProfile(char const * action, char const * desc, OBJH * handler, int pw_req_flag, int atomic)
{
@@ -105,6 +100,12 @@
registerProfile(profile);
}
+/**
+ * \ingroup CacheManagerAPI
+ * Registers a C++-style action, via a pointer to a subclass of
+ * a CacheManagerAction object, whose run() method will be invoked when
+ * CacheManager identifies that the user has requested the action.
+ */
void
CacheManager::registerProfile(char const * action, char const * desc,
ClassActionCreator::Handler *handler,
@@ -306,7 +307,7 @@
* all needed internal work and renders the response.
*/
void
-CacheManager::Start(int fd, HttpRequest * request, StoreEntry * entry)
+CacheManager::Start(const Comm::ConnectionPointer &client, HttpRequest * request, StoreEntry * entry)
{
ErrorState *err = NULL;
debugs(16, 3, "CacheManager::Start: '" << entry->url() << "'" );
@@ -324,7 +325,7 @@
entry->expires = squid_curtime;
- debugs(16, 5, "CacheManager: " << fd_table[fd].ipaddr << " requesting '" << actionName << "'");
+ debugs(16, 5, "CacheManager: " << client << " requesting '" << actionName << "'");
/* get additional info from request headers */
ParseHeaders(request, cmd->params);
@@ -344,12 +345,12 @@
if (cmd->params.password.size()) {
debugs(16, DBG_IMPORTANT, "CacheManager: " <<
userName << "@" <<
- fd_table[fd].ipaddr << ": incorrect password for '" <<
+ client << ": incorrect password for '" <<
actionName << "'" );
} else {
debugs(16, DBG_IMPORTANT, "CacheManager: " <<
userName << "@" <<
- fd_table[fd].ipaddr << ": password needed for '" <<
+ client << ": password needed for '" <<
actionName << "'" );
}
@@ -377,11 +378,12 @@
debugs(16, 2, "CacheManager: " <<
userName << "@" <<
- fd_table[fd].ipaddr << " requesting '" <<
+ client << " requesting '" <<
actionName << "'" );
if (UsingSmp() && IamWorkerProcess()) {
- AsyncJob::Start(new Mgr::Forwarder(fd, cmd->params, request, entry));
+ // is client the right connection to pass here?
+ AsyncJob::Start(new Mgr::Forwarder(client, cmd->params, request, entry));
return;
}
=== modified file 'src/cf.data.pre'
--- src/cf.data.pre 2011-03-25 11:47:08 +0000
+++ src/cf.data.pre 2011-03-26 01:48:58 +0000
@@ -2477,6 +2477,9 @@
DOC_START
Controls how many different forward paths Squid will try
before giving up. See also forward_timeout.
+
+ NOTE: connect_retries (default: none) can make each of these
+ possible forwarding paths be tried multiple times.
DOC_END
NAME: hierarchy_stoplist
@@ -7259,21 +7262,24 @@
see also refresh_pattern for a more selective approach.
DOC_END
-NAME: maximum_single_addr_tries
+NAME: connect_retries
TYPE: int
-LOC: Config.retry.maxtries
-DEFAULT: 1
+LOC: Config.connect_retries
+DEFAULT: 0
DOC_START
- This sets the maximum number of connection attempts for a
- host that only has one address (for multiple-address hosts,
- each address is tried once).
-
- The default value is one attempt, the (not recommended)
- maximum is 255 tries. A warning message will be generated
- if it is set to a value greater than ten.
-
- Note: This is in addition to the request re-forwarding which
- takes place if Squid fails to get a satisfying response.
+ This sets the maximum number of connection attempts made for each
+ TCP connection. The connect_retries attempts must all still
+ complete within the connection timeout period.
+
+ The default is not to re-try if the first connection attempt fails.
+ The (not recommended) maximum is 10 tries.
+
+ A warning message will be generated if it is set to a too-high
+ value and the configured value will be over-ridden.
+
+ Note: These re-tries are in addition to forward_max_tries
+ which limit how many different addresses may be tried to find
+ a useful server.
DOC_END
NAME: retry_on_error
=== modified file 'src/client_side.cc'
--- src/client_side.cc 2011-03-26 02:03:49 +0000
+++ src/client_side.cc 2011-03-26 11:09:38 +0000
@@ -87,6 +87,7 @@
#if USE_AUTH
#include "auth/UserRequest.h"
#endif
+#include "base/Subscription.h"
#include "base/TextException.h"
#include "ChunkedCodingParser.h"
#include "client_side.h"
@@ -98,11 +99,11 @@
#include "ClientRequestContext.h"
#include "clientStream.h"
#include "comm.h"
+#include "comm/Connection.h"
#include "CommCalls.h"
#include "comm/Loops.h"
#include "comm/Write.h"
#include "comm/TcpAcceptor.h"
-#include "ConnectionDetail.h"
#include "eui/Config.h"
#include "fde.h"
#include "HttpHdrContRange.h"
@@ -110,7 +111,6 @@
#include "HttpRequest.h"
#include "ident/Config.h"
#include "ident/Ident.h"
-#include "ip/Intercept.h"
#include "ipc/FdNotes.h"
#include "ipc/StartListening.h"
#include "MemBuf.h"
@@ -142,17 +142,17 @@
class ListeningStartedDialer: public CallDialer, public Ipc::StartListeningCb
{
public:
- typedef void (*Handler)(int fd, int flags, int errNo, http_port_list *portCfg, const Ipc::FdNoteId note, const Subscription::Pointer &sub);
- ListeningStartedDialer(Handler aHandler, int openFlags, http_port_list *aPortCfg, const Ipc::FdNoteId note, const Subscription::Pointer &aSub):
- handler(aHandler), portCfg(aPortCfg), portTypeNote(note), commOpenListenerFlags(openFlags), sub(aSub) {}
+ typedef void (*Handler)(http_port_list *portCfg, const Ipc::FdNoteId note, const Subscription::Pointer &sub);
+ ListeningStartedDialer(Handler aHandler, http_port_list *aPortCfg, const Ipc::FdNoteId note, const Subscription::Pointer &aSub):
+ handler(aHandler), portCfg(aPortCfg), portTypeNote(note), sub(aSub) {}
virtual void print(std::ostream &os) const {
startPrint(os) <<
- ", port=" << (void*)portCfg << ')';
+ ", " << FdNote(portTypeNote) << " port=" << (void*)portCfg << ')';
}
virtual bool canDial(AsyncCall &) const { return true; }
- virtual void dial(AsyncCall &) { (handler)(fd, commOpenListenerFlags, errNo, portCfg, portTypeNote, sub); }
+ virtual void dial(AsyncCall &) { (handler)(portCfg, portTypeNote, sub); }
public:
Handler handler;
@@ -160,11 +160,10 @@
private:
http_port_list *portCfg; ///< from Config.Sockaddr.http
Ipc::FdNoteId portTypeNote; ///< Type of IPC socket being opened
- int commOpenListenerFlags; ///< flags used by comm_open_listener
Subscription::Pointer sub; ///< The handler to be subscribed for this connetion listener
};
-static void clientListenerConnectionOpened(int fd, int flags, int errNo, http_port_list *s, const Ipc::FdNoteId portTypeNote, const Subscription::Pointer &sub);
+static void clientListenerConnectionOpened(http_port_list *s, const Ipc::FdNoteId portTypeNote, const Subscription::Pointer &sub);
/* our socket-related context */
@@ -188,11 +187,15 @@
/* Local functions */
/* ClientSocketContext */
-static ClientSocketContext *ClientSocketContextNew(ClientHttpRequest *);
+static ClientSocketContext *ClientSocketContextNew(const Comm::ConnectionPointer &clientConn, ClientHttpRequest *);
/* other */
static IOCB clientWriteComplete;
static IOCB clientWriteBodyComplete;
-static PF clientLifetimeTimeout;
+static IOACB httpAccept;
+#if USE_SSL
+static IOACB httpsAccept;
+#endif
+static CTCB clientLifetimeTimeout;
static ClientSocketContext *parseHttpRequestAbort(ConnStateData * conn, const char *uri);
static ClientSocketContext *parseHttpRequest(ConnStateData *, HttpParser *, HttpRequestMethod *, HttpVersion *);
#if USE_IDENT
@@ -210,7 +213,7 @@
static bool clientPingHasFinished(ping_data const *aPing);
void prepareLogWithRequestDetails(HttpRequest *, AccessLogEntry *);
#ifndef PURIFY
-static int connIsUsable(ConnStateData * conn);
+static bool connIsUsable(ConnStateData * conn);
#endif
static int responseFinishedOrFailed(HttpReply * rep, StoreIOBuffer const &receivedData);
static void ClientSocketContextPushDeferredIfNeeded(ClientSocketContext::Pointer deferredRequest, ConnStateData * conn);
@@ -219,16 +222,8 @@
char *skipLeadingSpace(char *aString);
static void connNoteUseOfBuffer(ConnStateData* conn, size_t byteCount);
-static ConnStateData *connStateCreate(const Ip::Address &peer, const Ip::Address &me, int fd, http_port_list *port);
-
-
-int
-ClientSocketContext::fd() const
-{
- assert (http);
- assert (http->getConn() != NULL);
- return http->getConn()->fd;
-}
+static ConnStateData *connStateCreate(const Comm::ConnectionPointer &client, http_port_list *port);
+
clientStreamNode *
ClientSocketContext::getTail() const
@@ -255,15 +250,14 @@
if (reading())
return;
- debugs(33, 4, "clientReadSomeData: FD " << fd << ": reading request...");
+ debugs(33, 4, HERE << clientConnection << ": reading request...");
if (!maybeMakeSpaceAvailable())
return;
typedef CommCbMemFunT Dialer;
- reader = JobCallback(33, 5,
- Dialer, this, ConnStateData::clientReadRequest);
- comm_read(fd, in.addressToReadInto(), getAvailableBufferLength(), reader);
+ reader = JobCallback(33, 5, Dialer, this, ConnStateData::clientReadRequest);
+ comm_read(clientConnection, in.addressToReadInto(), getAvailableBufferLength(), reader);
}
@@ -352,12 +346,13 @@
}
ClientSocketContext *
-ClientSocketContextNew(ClientHttpRequest * http)
+ClientSocketContextNew(const Comm::ConnectionPointer &client, ClientHttpRequest * http)
{
ClientSocketContext *newContext;
assert(http != NULL);
newContext = new ClientSocketContext;
newContext->http = http;
+ newContext->clientConnection = client;
return newContext;
}
@@ -380,14 +375,14 @@
AsyncCall::Pointer call = commCbCall(33, 5, "ClientSocketContext::wroteControlMsg",
CommIoCbPtrFun(&WroteControlMsg, this));
- Comm::Write(fd(), mb, call);
+ Comm::Write(clientConnection, mb, call);
delete mb;
}
/// called when we wrote the 1xx response
void
-ClientSocketContext::wroteControlMsg(int fd, char *, size_t, comm_err_t errflag, int xerrno)
+ClientSocketContext::wroteControlMsg(const Comm::ConnectionPointer &conn, char *, size_t, comm_err_t errflag, int xerrno)
{
if (errflag == COMM_ERR_CLOSING)
return;
@@ -403,15 +398,15 @@
// close on 1xx errors to be conservative and to simplify the code
// (if we do not close, we must notify the source of a failure!)
- comm_close(fd);
+ conn->close();
}
/// wroteControlMsg() wrapper: ClientSocketContext is not an AsyncJob
void
-ClientSocketContext::WroteControlMsg(int fd, char *bufnotused, size_t size, comm_err_t errflag, int xerrno, void *data)
+ClientSocketContext::WroteControlMsg(const Comm::ConnectionPointer &conn, char *bufnotused, size_t size, comm_err_t errflag, int xerrno, void *data)
{
ClientSocketContext *context = static_cast(data);
- context->wroteControlMsg(fd, bufnotused, size, errflag, xerrno);
+ context->wroteControlMsg(conn, bufnotused, size, errflag, xerrno);
}
#if USE_IDENT
@@ -419,7 +414,7 @@
clientIdentDone(const char *ident, void *data)
{
ConnStateData *conn = (ConnStateData *)data;
- xstrncpy(conn->rfc931, ident ? ident : dash_str, USER_IDENT_SZ);
+ xstrncpy(conn->clientConnection->rfc931, ident ? ident : dash_str, USER_IDENT_SZ);
}
#endif
@@ -652,8 +647,8 @@
if (request)
prepareLogWithRequestDetails(request, &al);
- if (getConn() != NULL && getConn()->rfc931[0])
- al.cache.rfc931 = getConn()->rfc931;
+ if (getConn() != NULL && getConn()->clientConnection != NULL && getConn()->clientConnection->rfc931[0])
+ al.cache.rfc931 = getConn()->clientConnection->rfc931;
#if USE_SSL && 0
@@ -676,8 +671,8 @@
accessLogLog(&al, checklist);
updateCounters();
- if (getConn() != NULL)
- clientdbUpdate(getConn()->peer, logType, AnyP::PROTO_HTTP, out.size);
+ if (getConn() != NULL && getConn()->clientConnection != NULL)
+ clientdbUpdate(getConn()->clientConnection->remote, logType, AnyP::PROTO_HTTP, out.size);
}
delete checklist;
@@ -748,7 +743,6 @@
/* This is a handler normally called by comm_close() */
void ConnStateData::connStateClosed(const CommCloseCbParams &io)
{
- assert (fd == io.fd);
deleteThis("ConnStateData::connStateClosed");
}
@@ -756,10 +750,9 @@
void
ConnStateData::swanSong()
{
- debugs(33, 2, "ConnStateData::swanSong: FD " << fd);
- fd = -1;
+ debugs(33, 2, HERE << clientConnection);
flags.readMoreRequests = false;
- clientdbEstablished(peer, -1); /* decrement */
+ clientdbEstablished(clientConnection->remote, -1); /* decrement */
assert(areAllContextsForThisConnection());
freeAllContexts();
#if USE_AUTH
@@ -768,8 +761,14 @@
auth_user_request->onConnectionClose(this);
}
#endif
- if (pinning.fd >= 0)
- comm_close(pinning.fd);
+
+ if (Comm::IsConnOpen(pinning.serverConnection))
+ pinning.serverConnection->close();
+ pinning.serverConnection = NULL;
+
+ if (Comm::IsConnOpen(clientConnection))
+ clientConnection->close();
+ clientConnection = NULL;
BodyProducer::swanSong();
flags.swanSang = true;
@@ -779,20 +778,20 @@
ConnStateData::isOpen() const
{
return cbdataReferenceValid(this) && // XXX: checking "this" in a method
- fd >= 0 &&
- !fd_table[fd].closing();
+ Comm::IsConnOpen(clientConnection) &&
+ !fd_table[clientConnection->fd].closing();
}
ConnStateData::~ConnStateData()
{
assert(this != NULL);
- debugs(33, 3, "ConnStateData::~ConnStateData: FD " << fd);
+ debugs(33, 3, HERE << clientConnection);
if (isOpen())
- debugs(33, 1, "BUG: ConnStateData did not close FD " << fd);
+ debugs(33, 1, "BUG: ConnStateData did not close " << clientConnection);
if (!flags.swanSang)
- debugs(33, 1, "BUG: ConnStateData was not destroyed properly; FD " << fd);
+ debugs(33, 1, "BUG: ConnStateData was not destroyed properly; " << clientConnection);
cbdataReferenceDone(port);
@@ -853,7 +852,7 @@
int
connIsUsable(ConnStateData * conn)
{
- if (conn == NULL || !cbdataReferenceValid(conn) || conn->fd == -1)
+ if (conn == NULL || !cbdataReferenceValid(conn) || !Comm::IsConnOpen(conn->clientConnection))
return 0;
return 1;
@@ -958,7 +957,7 @@
noteSentBodyBytes (length);
AsyncCall::Pointer call = commCbCall(33, 5, "clientWriteBodyComplete",
CommIoCbPtrFun(clientWriteBodyComplete, this));
- Comm::Write(fd(), bodyData.data, length, call, NULL);
+ Comm::Write(clientConnection, bodyData.data, length, call, NULL);
return;
}
@@ -973,9 +972,9 @@
/* write */
AsyncCall::Pointer call = commCbCall(33, 5, "clientWriteComplete",
CommIoCbPtrFun(clientWriteComplete, this));
- Comm::Write(fd(), &mb, call);
+ Comm::Write(clientConnection, &mb, call);
} else
- writeComplete(fd(), NULL, 0, COMM_OK);
+ writeComplete(clientConnection, NULL, 0, COMM_OK);
}
/**
@@ -1371,8 +1370,7 @@
debugs(33,7, HERE << "sendStartOfMessage schedules clientWriteComplete");
AsyncCall::Pointer call = commCbCall(33, 5, "clientWriteComplete",
CommIoCbPtrFun(clientWriteComplete, this));
- Comm::Write(fd(), mb, call);
-
+ Comm::Write(clientConnection, mb, call);
delete mb;
}
@@ -1389,7 +1387,6 @@
clientSocketRecipient(clientStreamNode * node, ClientHttpRequest * http,
HttpReply * rep, StoreIOBuffer receivedData)
{
- int fd;
/* Test preconditions */
assert(node != NULL);
PROF_start(clientSocketRecipient);
@@ -1403,7 +1400,7 @@
ClientSocketContext::Pointer context = dynamic_cast(node->data.getRaw());
assert(context != NULL);
assert(connIsUsable(http->getConn()));
- fd = http->getConn()->fd;
+
/* TODO: check offset is what we asked for */
if (context != http->getConn()->getCurrentContext()) {
@@ -1417,7 +1414,7 @@
const bool mustSendLastChunk = http->request->flags.chunked_reply &&
!http->request->flags.stream_error && !context->startOfOutput();
if (responseFinishedOrFailed(rep, receivedData) && !mustSendLastChunk) {
- context->writeComplete(fd, NULL, 0, COMM_OK);
+ context->writeComplete(context->clientConnection, NULL, 0, COMM_OK);
PROF_stop(clientSocketRecipient);
return;
}
@@ -1460,25 +1457,25 @@
}
static void
-clientWriteBodyComplete(int fd, char *buf, size_t size, comm_err_t errflag, int xerrno, void *data)
+clientWriteBodyComplete(const Comm::ConnectionPointer &conn, char *buf, size_t size, comm_err_t errflag, int xerrno, void *data)
{
debugs(33,7, HERE << "clientWriteBodyComplete schedules clientWriteComplete");
- clientWriteComplete(fd, NULL, size, errflag, xerrno, data);
+ clientWriteComplete(conn, NULL, size, errflag, xerrno, data);
}
void
ConnStateData::readNextRequest()
{
- debugs(33, 5, "ConnStateData::readNextRequest: FD " << fd << " reading next req");
+ debugs(33, 5, HERE << clientConnection << " reading next req");
- fd_note(fd, "Waiting for next request");
+ fd_note(clientConnection->fd, "Waiting for next request");
/**
* Set the timeout BEFORE calling clientReadRequest().
*/
typedef CommCbMemFunT TimeoutDialer;
AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
TimeoutDialer, this, ConnStateData::requestTimeout);
- commSetTimeout(fd, Config.Timeout.persistent_request, timeoutCall);
+ commSetConnTimeout(clientConnection, Config.Timeout.persistent_request, timeoutCall);
readSomeData();
/** Please don't do anything with the FD past here! */
@@ -1487,7 +1484,7 @@
static void
ClientSocketContextPushDeferredIfNeeded(ClientSocketContext::Pointer deferredRequest, ConnStateData * conn)
{
- debugs(33, 2, "ClientSocketContextPushDeferredIfNeeded: FD " << conn->fd << " Sending next");
+ debugs(33, 2, HERE << conn->clientConnection << " Sending next");
/** If the client stream is waiting on a socket write to occur, then */
@@ -1512,12 +1509,12 @@
ConnStateData * conn = http->getConn();
bool do_next_read = false;
- debugs(33, 3, "ClientSocketContext::keepaliveNextRequest: FD " << conn->fd);
+ debugs(33, 3, HERE << "ConnnStateData(" << conn->clientConnection << "), Context(" << clientConnection << ")");
connIsFinished();
- if (conn->pinning.pinned && conn->pinning.fd == -1) {
- debugs(33, 2, "clientKeepaliveNextRequest: FD " << conn->fd << " Connection was pinned but server side gone. Terminating client connection");
- comm_close(conn->fd);
+ if (conn->pinning.pinned && !Comm::IsConnOpen(conn->pinning.serverConnection)) {
+ debugs(33, 2, HERE << conn->clientConnection << " Connection was pinned but server side gone. Terminating client connection");
+ conn->clientConnection->close();
return;
}
@@ -1532,7 +1529,7 @@
*/
if (conn->clientParseRequest(do_next_read)) {
- debugs(33, 3, "clientSocketContext::keepaliveNextRequest: FD " << conn->fd << ": parsed next request from buffer");
+ debugs(33, 3, HERE << conn->clientConnection << ": parsed next request from buffer");
}
/** \par
@@ -1542,9 +1539,9 @@
* half-closed _AND_ then, sometimes, spending "Timeout" time in
* the keepalive "Waiting for next request" state.
*/
- if (commIsHalfClosed(conn->fd) && (conn->getConcurrentRequestCount() == 0)) {
+ if (commIsHalfClosed(conn->clientConnection->fd) && (conn->getConcurrentRequestCount() == 0)) {
debugs(33, 3, "ClientSocketContext::keepaliveNextRequest: half-closed client with no pending requests, closing");
- comm_close(conn->fd);
+ conn->clientConnection->close();
return;
}
@@ -1559,10 +1556,10 @@
*/
if ((deferredRequest = conn->getCurrentContext()).getRaw()) {
- debugs(33, 3, "ClientSocketContext:: FD " << conn->fd << ": calling PushDeferredIfNeeded");
+ debugs(33, 3, HERE << conn->clientConnection << ": calling PushDeferredIfNeeded");
ClientSocketContextPushDeferredIfNeeded(deferredRequest, conn);
} else {
- debugs(33, 3, "ClientSocketContext:: FD " << conn->fd << ": calling conn->readNextRequest()");
+ debugs(33, 3, HERE << conn->clientConnection << ": calling conn->readNextRequest()");
conn->readNextRequest();
}
}
@@ -1592,7 +1589,7 @@
/** first update iterator "i" if needed */
if (!http->range_iter.debt()) {
- debugs(33, 5, "ClientSocketContext::canPackMoreRanges: At end of current range spec for FD " << fd());
+ debugs(33, 5, HERE << "At end of current range spec for " << clientConnection);
if (http->range_iter.pos.incrementable())
++http->range_iter.pos;
@@ -1650,8 +1647,7 @@
void
ClientSocketContext::pullData()
{
- debugs(33, 5, "ClientSocketContext::pullData: FD " << fd() <<
- " attempting to pull upstream data");
+ debugs(33, 5, HERE << clientConnection << " attempting to pull upstream data");
/* More data will be coming from the stream. */
StoreIOBuffer readBuffer;
@@ -1679,7 +1675,7 @@
if (!canPackMoreRanges()) {
debugs(33, 5, HERE << "Range request at end of returnable " <<
- "range sequence on FD " << fd());
+ "range sequence on " << clientConnection);
if (http->request->flags.proxy_keepalive)
return STREAM_COMPLETE;
@@ -1738,10 +1734,10 @@
* no more data to send.
*/
void
-clientWriteComplete(int fd, char *bufnotused, size_t size, comm_err_t errflag, int xerrno, void *data)
+clientWriteComplete(const Comm::ConnectionPointer &conn, char *bufnotused, size_t size, comm_err_t errflag, int xerrno, void *data)
{
ClientSocketContext *context = (ClientSocketContext *)data;
- context->writeComplete (fd, bufnotused, size, errflag);
+ context->writeComplete(conn, bufnotused, size, errflag);
}
/// remembers the abnormal connection termination for logging purposes
@@ -1760,7 +1756,7 @@
void
ClientSocketContext::doClose()
{
- comm_close(fd());
+ clientConnection->close();
}
/** Called to initiate (and possibly complete) closing of the context.
@@ -1804,23 +1800,21 @@
}
void
-ClientSocketContext::writeComplete(int aFileDescriptor, char *bufnotused, size_t size, comm_err_t errflag)
+ClientSocketContext::writeComplete(const Comm::ConnectionPointer &conn, char *bufnotused, size_t size, comm_err_t errflag)
{
StoreEntry *entry = http->storeEntry();
http->out.size += size;
- assert(aFileDescriptor > -1);
- debugs(33, 5, "clientWriteComplete: FD " << aFileDescriptor << ", sz " << size <<
+ debugs(33, 5, HERE << conn << ", sz " << size <<
", err " << errflag << ", off " << http->out.size << ", len " <<
entry ? entry->objectLen() : 0);
clientUpdateSocketStats(http->logType, size);
- assert (this->fd() == aFileDescriptor);
/* Bail out quickly on COMM_ERR_CLOSING - close handlers will tidy up */
- if (errflag == COMM_ERR_CLOSING)
+ if (errflag == COMM_ERR_CLOSING || !Comm::IsConnOpen(conn))
return;
- if (errflag || clientHttpRequestStatus(aFileDescriptor, http)) {
+ if (errflag || clientHttpRequestStatus(conn->fd, http)) {
initiateClose("failure or true request status");
/* Do we leak here ? */
return;
@@ -1833,7 +1827,7 @@
break;
case STREAM_COMPLETE:
- debugs(33, 5, "clientWriteComplete: FD " << aFileDescriptor << " Keeping Alive");
+ debugs(33, 5, HERE << conn << " Keeping Alive");
keepaliveNextRequest();
return;
@@ -1855,16 +1849,16 @@
extern "C" CSD clientReplyDetach;
static ClientSocketContext *
-parseHttpRequestAbort(ConnStateData * conn, const char *uri)
+parseHttpRequestAbort(ConnStateData * csd, const char *uri)
{
ClientHttpRequest *http;
ClientSocketContext *context;
StoreIOBuffer tempBuffer;
- http = new ClientHttpRequest(conn);
- http->req_sz = conn->in.notYetUsed;
+ http = new ClientHttpRequest(csd);
+ http->req_sz = csd->in.notYetUsed;
http->uri = xstrdup(uri);
setLogUri (http, uri);
- context = ClientSocketContextNew(http);
+ context = ClientSocketContextNew(csd->clientConnection, http);
tempBuffer.data = context->reqbuf;
tempBuffer.length = HTTP_REQBUF_SZ;
clientStreamInit(&http->client_stream, clientGetMoreData, clientReplyDetach,
@@ -2025,16 +2019,16 @@
/* Put the local socket IP address as the hostname. */
int url_sz = strlen(url) + 32 + Config.appendDomainLen;
http->uri = (char *)xcalloc(url_sz, 1);
- http->getConn()->me.ToHostname(ipbuf,MAX_IPSTRLEN);
+ http->getConn()->clientConnection->local.ToHostname(ipbuf,MAX_IPSTRLEN);
snprintf(http->uri, url_sz, "%s://%s:%d%s",
http->getConn()->port->protocol,
- ipbuf, http->getConn()->me.GetPort(), url);
+ ipbuf, http->getConn()->clientConnection->local.GetPort(), url);
debugs(33, 5, "ACCEL VPORT REWRITE: '" << http->uri << "'");
} else if (vport > 0) {
/* Put the local socket IP address as the hostname, but static port */
int url_sz = strlen(url) + 32 + Config.appendDomainLen;
http->uri = (char *)xcalloc(url_sz, 1);
- http->getConn()->me.ToHostname(ipbuf,MAX_IPSTRLEN);
+ http->getConn()->clientConnection->local.ToHostname(ipbuf,MAX_IPSTRLEN);
snprintf(http->uri, url_sz, "%s://%s:%d%s",
http->getConn()->port->protocol,
ipbuf, vport, url);
@@ -2064,10 +2058,10 @@
/* Put the local socket IP address as the hostname. */
int url_sz = strlen(url) + 32 + Config.appendDomainLen;
http->uri = (char *)xcalloc(url_sz, 1);
- http->getConn()->me.ToHostname(ipbuf,MAX_IPSTRLEN),
+ http->getConn()->clientConnection->local.ToHostname(ipbuf,MAX_IPSTRLEN),
snprintf(http->uri, url_sz, "http://%s:%d%s",
// http->getConn()->port->protocol,
- ipbuf, http->getConn()->me.GetPort(), url);
+ ipbuf, http->getConn()->clientConnection->local.GetPort(), url);
debugs(33, 5, "TRANSPARENT REWRITE: '" << http->uri << "'");
}
}
@@ -2082,7 +2076,7 @@
* Sets result->flags.parsed_ok to 1 if we have a good request.
*/
static ClientSocketContext *
-parseHttpRequest(ConnStateData *conn, HttpParser *hp, HttpRequestMethod * method_p, HttpVersion *http_ver)
+parseHttpRequest(ConnStateData *csd, HttpParser *hp, HttpRequestMethod * method_p, HttpVersion *http_ver)
{
char *req_hdr = NULL;
char *end;
@@ -2103,7 +2097,7 @@
} else if ( (size_t)hp->bufsiz >= Config.maxRequestHeaderSize && headersEnd(hp->buf, Config.maxRequestHeaderSize) == 0) {
debugs(33, 5, "parseHttpRequest: Too large request");
hp->request_parse_status = HTTP_HEADER_TOO_LARGE;
- return parseHttpRequestAbort(conn, "error:request-too-large");
+ return parseHttpRequestAbort(csd, "error:request-too-large");
}
/* Attempt to parse the first line; this'll define the method, url, version and header begin */
@@ -2115,7 +2109,7 @@
}
if (r == -1) {
- return parseHttpRequestAbort(conn, "error:invalid-request");
+ return parseHttpRequestAbort(csd, "error:invalid-request");
}
/* Request line is valid here .. */
@@ -2148,26 +2142,26 @@
if (req_sz >= Config.maxRequestHeaderSize) {
debugs(33, 5, "parseHttpRequest: Too large request");
hp->request_parse_status = HTTP_HEADER_TOO_LARGE;
- return parseHttpRequestAbort(conn, "error:request-too-large");
+ return parseHttpRequestAbort(csd, "error:request-too-large");
}
/* Set method_p */
*method_p = HttpRequestMethod(&hp->buf[hp->m_start], &hp->buf[hp->m_end]+1);
/* deny CONNECT via accelerated ports */
- if (*method_p == METHOD_CONNECT && conn && conn->port && conn->port->accel) {
- debugs(33, DBG_IMPORTANT, "WARNING: CONNECT method received on " << conn->port->protocol << " Accelerator port " << conn->port->s.GetPort() );
+ if (*method_p == METHOD_CONNECT && csd && csd->port && csd->port->accel) {
+ debugs(33, DBG_IMPORTANT, "WARNING: CONNECT method received on " << csd->port->protocol << " Accelerator port " << csd->port->s.GetPort() );
/* XXX need a way to say "this many character length string" */
debugs(33, DBG_IMPORTANT, "WARNING: for request: " << hp->buf);
hp->request_parse_status = HTTP_METHOD_NOT_ALLOWED;
- return parseHttpRequestAbort(conn, "error:method-not-allowed");
+ return parseHttpRequestAbort(csd, "error:method-not-allowed");
}
if (*method_p == METHOD_NONE) {
/* XXX need a way to say "this many character length string" */
debugs(33, 1, "clientParseRequestMethod: Unsupported method in request '" << hp->buf << "'");
hp->request_parse_status = HTTP_METHOD_NOT_ALLOWED;
- return parseHttpRequestAbort(conn, "error:unsupported-request-method");
+ return parseHttpRequestAbort(csd, "error:unsupported-request-method");
}
/*
@@ -2188,10 +2182,10 @@
HttpParserReqSz(hp));
/* Ok, all headers are received */
- http = new ClientHttpRequest(conn);
+ http = new ClientHttpRequest(csd);
http->req_sz = HttpParserRequestLen(hp);
- result = ClientSocketContextNew(http);
+ result = ClientSocketContextNew(csd->clientConnection, http);
tempBuffer.data = result->reqbuf;
tempBuffer.length = HTTP_REQBUF_SZ;
@@ -2232,19 +2226,13 @@
* - internal URL
* - mixed combos of the above with internal URL
*/
- if (conn->transparent()) {
+ if (csd->transparent()) {
/* intercept or transparent mode, properly working with no failures */
- http->flags.intercepted = conn->port->intercepted;
- http->flags.spoof_client_ip = conn->port->spoof_client_ip;
- prepareTransparentURL(conn, http, url, req_hdr);
-
- } else if (conn->port->intercepted || conn->port->spoof_client_ip) {
- /* transparent or intercept mode with failures */
- prepareTransparentURL(conn, http, url, req_hdr);
-
- } else if (conn->port->accel || conn->switchedToHttps()) {
+ prepareTransparentURL(csd, http, url, req_hdr);
+
+ } else if (csd->port->accel || csd->switchedToHttps()) {
/* accelerator mode */
- prepareAcceleratedURL(conn, http, url, req_hdr);
+ prepareAcceleratedURL(csd, http, url, req_hdr);
} else if (internalCheck(url)) {
/* internal URL mode */
@@ -2320,16 +2308,16 @@
ConnStateData::connReadWasError(comm_err_t flag, int size, int xerrno)
{
if (flag != COMM_OK) {
- debugs(33, 2, "connReadWasError: FD " << fd << ": got flag " << flag);
+ debugs(33, 2, "connReadWasError: FD " << clientConnection << ": got flag " << flag);
return 1;
}
if (size < 0) {
if (!ignoreErrno(xerrno)) {
- debugs(33, 2, "connReadWasError: FD " << fd << ": " << xstrerr(xerrno));
+ debugs(33, 2, "connReadWasError: FD " << clientConnection << ": " << xstrerr(xerrno));
return 1;
} else if (in.notYetUsed == 0) {
- debugs(33, 2, "connReadWasError: FD " << fd << ": no data to process (" << xstrerr(xerrno) << ")");
+ debugs(33, 2, "connReadWasError: FD " << clientConnection << ": no data to process (" << xstrerr(xerrno) << ")");
}
}
@@ -2342,11 +2330,11 @@
if (size == 0) {
if (getConcurrentRequestCount() == 0 && in.notYetUsed == 0) {
/* no current or pending requests */
- debugs(33, 4, "connFinishedWithConn: FD " << fd << " closed");
+ debugs(33, 4, HERE << clientConnection << " closed");
return 1;
} else if (!Config.onoff.half_closed_clients) {
/* admin doesn't want to support half-closed client sockets */
- debugs(33, 3, "connFinishedWithConn: FD " << fd << " aborted (half_closed_clients disabled)");
+ debugs(33, 3, HERE << clientConnection << " aborted (half_closed_clients disabled)");
notifyAllContexts(0); // no specific error implies abort
return 1;
}
@@ -2386,7 +2374,7 @@
assert (repContext);
repContext->setReplyToError(ERR_TOO_BIG,
HTTP_BAD_REQUEST, METHOD_NONE, NULL,
- peer, NULL, NULL, NULL);
+ clientConnection->remote, NULL, NULL, NULL);
context->registerWithConn();
context->pullData();
}
@@ -2404,9 +2392,9 @@
ConnStateData::clientAfterReadingRequests(int do_next_read)
{
// Were we expecting to read more request body from half-closed connection?
- if (mayNeedToReadMoreBody() && commIsHalfClosed(fd)) {
- debugs(33, 3, HERE << "truncated body: closing half-closed FD " << fd);
- comm_close(fd);
+ if (mayNeedToReadMoreBody() && commIsHalfClosed(clientConnection->fd)) {
+ debugs(33, 3, HERE << "truncated body: closing half-closed " << clientConnection);
+ clientConnection->close();
return;
}
@@ -2437,13 +2425,15 @@
assert (repContext);
switch (hp->request_parse_status) {
case HTTP_HEADER_TOO_LARGE:
- repContext->setReplyToError(ERR_TOO_BIG, HTTP_BAD_REQUEST, method, http->uri, conn->peer, NULL, conn->in.buf, NULL);
+ repContext->setReplyToError(ERR_TOO_BIG, HTTP_BAD_REQUEST, method, http->uri, conn->clientConnection->remote, NULL, conn->in.buf, NULL);
break;
case HTTP_METHOD_NOT_ALLOWED:
- repContext->setReplyToError(ERR_UNSUP_REQ, HTTP_METHOD_NOT_ALLOWED, method, http->uri, conn->peer, NULL, conn->in.buf, NULL);
+ repContext->setReplyToError(ERR_UNSUP_REQ, HTTP_METHOD_NOT_ALLOWED, method, http->uri,
+ conn->clientConnection->remote, NULL, conn->in.buf, NULL);
break;
default:
- repContext->setReplyToError(ERR_INVALID_REQ, HTTP_BAD_REQUEST, method, http->uri, conn->peer, NULL, conn->in.buf, NULL);
+ repContext->setReplyToError(ERR_INVALID_REQ, HTTP_BAD_REQUEST, method, http->uri,
+ conn->clientConnection->remote, NULL, conn->in.buf, NULL);
}
assert(context->http->out.offset == 0);
context->pullData();
@@ -2458,7 +2448,7 @@
setLogUri(http, http->uri, true);
clientReplyContext *repContext = dynamic_cast(node->data.getRaw());
assert (repContext);
- repContext->setReplyToError(ERR_INVALID_URL, HTTP_BAD_REQUEST, method, http->uri, conn->peer, NULL, NULL, NULL);
+ repContext->setReplyToError(ERR_INVALID_URL, HTTP_BAD_REQUEST, method, http->uri, conn->clientConnection->remote, NULL, NULL, NULL);
assert(context->http->out.offset == 0);
context->pullData();
conn->flags.readMoreRequests = false;
@@ -2477,7 +2467,8 @@
setLogUri(http, http->uri, true);
clientReplyContext *repContext = dynamic_cast(node->data.getRaw());
assert (repContext);
- repContext->setReplyToError(ERR_UNSUP_HTTPVERSION, HTTP_HTTP_VERSION_NOT_SUPPORTED, method, http->uri, conn->peer, NULL, HttpParserHdrBuf(hp), NULL);
+ repContext->setReplyToError(ERR_UNSUP_HTTPVERSION, HTTP_HTTP_VERSION_NOT_SUPPORTED, method, http->uri,
+ conn->clientConnection->remote, NULL, HttpParserHdrBuf(hp), NULL);
assert(context->http->out.offset == 0);
context->pullData();
conn->flags.readMoreRequests = false;
@@ -2494,13 +2485,15 @@
setLogUri(http, http->uri, true);
clientReplyContext *repContext = dynamic_cast(node->data.getRaw());
assert (repContext);
- repContext->setReplyToError(ERR_INVALID_REQ, HTTP_BAD_REQUEST, method, http->uri, conn->peer, NULL, NULL, NULL);
+ repContext->setReplyToError(ERR_INVALID_REQ, HTTP_BAD_REQUEST, method, http->uri, conn->clientConnection->remote, NULL, NULL, NULL);
assert(context->http->out.offset == 0);
context->pullData();
conn->flags.readMoreRequests = false;
goto finish;
}
+ request->clientConnectionManager = conn;
+
request->flags.accelerated = http->flags.accel;
request->flags.ignore_cc = conn->port->ignore_cc;
request->flags.no_direct = request->flags.accelerated ? !conn->port->allow_direct : 0;
@@ -2509,11 +2502,9 @@
* If transparent or interception mode is working clone the transparent and interception flags
* from the port settings to the request.
*/
- if (Ip::Interceptor.InterceptActive()) {
- request->flags.intercepted = http->flags.intercepted;
- }
- if (Ip::Interceptor.TransparentActive()) {
- request->flags.spoof_client_ip = conn->port->spoof_client_ip;
+ if (http->clientConnection != NULL) {
+ request->flags.intercepted = (http->clientConnection->flags & COMM_INTERCEPTION);
+ request->flags.spoof_client_ip = (http->clientConnection->flags & COMM_TRANSPARENT);
}
if (internalCheck(request->urlpath.termedBuf())) {
@@ -2534,15 +2525,13 @@
request->flags.internal = http->flags.internal;
setLogUri (http, urlCanonicalClean(request));
- request->client_addr = conn->peer;
-#if USE_SQUID_EUI
- request->client_eui48 = conn->peer_eui48;
- request->client_eui64 = conn->peer_eui64;
-#endif
+ request->client_addr = conn->clientConnection->remote; // XXX: remove reuest->client_addr member.
#if FOLLOW_X_FORWARDED_FOR
- request->indirect_client_addr = conn->peer;
+ // indirect client gets stored here because it is an HTTP header result (from X-Forwarded-For:)
+ // not a details about teh TCP connection itself
+ request->indirect_client_addr = conn->clientConnection->remote;
#endif /* FOLLOW_X_FORWARDED_FOR */
- request->my_addr = conn->me;
+ request->my_addr = conn->clientConnection->local;
request->myportname = conn->port->name;
request->http_ver = http_ver;
@@ -2560,9 +2549,8 @@
clientStreamNode *node = context->getClientReplyContext();
clientReplyContext *repContext = dynamic_cast(node->data.getRaw());
assert (repContext);
- repContext->setReplyToError(ERR_UNSUP_REQ,
- HTTP_NOT_IMPLEMENTED, request->method, NULL,
- conn->peer, request, NULL, NULL);
+ repContext->setReplyToError(ERR_UNSUP_REQ, HTTP_NOT_IMPLEMENTED, request->method, NULL,
+ conn->clientConnection->remote, request, NULL, NULL);
assert(context->http->out.offset == 0);
context->pullData();
conn->flags.readMoreRequests = false;
@@ -2576,7 +2564,7 @@
assert (repContext);
repContext->setReplyToError(ERR_INVALID_REQ,
HTTP_LENGTH_REQUIRED, request->method, NULL,
- conn->peer, request, NULL, NULL);
+ conn->clientConnection->remote, request, NULL, NULL);
assert(context->http->out.offset == 0);
context->pullData();
conn->flags.readMoreRequests = false;
@@ -2590,8 +2578,8 @@
clientStreamNode *node = context->getClientReplyContext();
clientReplyContext *repContext = dynamic_cast(node->data.getRaw());
assert (repContext);
- repContext->setReplyToError(ERR_INVALID_REQ, HTTP_EXPECTATION_FAILED, request->method,
- http->uri, conn->peer, request, NULL, NULL);
+ repContext->setReplyToError(ERR_INVALID_REQ, HTTP_EXPECTATION_FAILED, request->method, http->uri,
+ conn->clientConnection->remote, request, NULL, NULL);
assert(context->http->out.offset == 0);
context->pullData();
goto finish;
@@ -2623,7 +2611,7 @@
assert (repContext);
repContext->setReplyToError(ERR_TOO_BIG,
HTTP_REQUEST_ENTITY_TOO_LARGE, METHOD_NONE, NULL,
- conn->peer, http->request, NULL, NULL);
+ conn->clientConnection->remote, http->request, NULL, NULL);
assert(context->http->out.offset == 0);
context->pullData();
goto finish;
@@ -2655,10 +2643,10 @@
* be freed and the above connNoteUseOfBuffer() would hit an
* assertion, not to mention that we were accessing freed memory.
*/
- if (http->request->flags.resetTCP() && conn->fd > -1) {
- debugs(33, 3, HERE << "Sending TCP RST on FD " << conn->fd);
+ if (http->request->flags.resetTCP() && Comm::IsConnOpen(conn->clientConnection)) {
+ debugs(33, 3, HERE << "Sending TCP RST on " << conn->clientConnection);
conn->flags.readMoreRequests = false;
- comm_reset_close(conn->fd);
+ comm_reset_close(conn->clientConnection);
return;
}
}
@@ -2678,10 +2666,8 @@
int result = conn->getConcurrentRequestCount() < (Config.onoff.pipeline_prefetch ? 2 : 1);
if (!result) {
- debugs(33, 3, "connOkToAddRequest: FD " << conn->fd <<
- " max concurrent requests reached");
- debugs(33, 5, "connOkToAddRequest: FD " << conn->fd <<
- " defering new request until one is done");
+ debugs(33, 3, HERE << conn->clientConnection << " max concurrent requests reached");
+ debugs(33, 5, HERE << conn->clientConnection << " defering new request until one is done");
}
return result;
@@ -2701,7 +2687,7 @@
bool parsed_req = false;
HttpVersion http_ver;
- debugs(33, 5, HERE << "FD " << fd << ": attempting to parse");
+ debugs(33, 5, HERE << conn->clientConnection << ": attempting to parse");
// Loop while we have read bytes that are not needed for producing the body
// On errors, bodyPipe may become nil, but readMoreRequests will be cleared
@@ -2739,9 +2725,10 @@
/* status -1 or 1 */
if (context) {
- debugs(33, 5, HERE << "FD " << fd << ": parsed a request");
- commSetTimeout(fd, Config.Timeout.lifetime, clientLifetimeTimeout,
- context->http);
+ debugs(33, 5, HERE << conn->clientConnection << ": parsed a request");
+ AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "clientLifetimeTimeout",
+ CommTimeoutCbPtrFun(clientLifetimeTimeout, context->http));
+ commSetConnTimeout(conn->clientConnection, Config.Timeout.lifetime, timeoutCall);
clientProcessRequest(this, &parser_, context, method, http_ver);
@@ -2761,20 +2748,21 @@
void
ConnStateData::clientReadRequest(const CommIoCbParams &io)
{
- debugs(33,5,HERE << "clientReadRequest FD " << io.fd << " size " << io.size);
+ debugs(33,5,HERE << io.conn << " size " << io.size);
Must(reading());
reader = NULL;
bool do_next_read = 1; /* the default _is_ to read data! - adrian */
- assert (io.fd == fd);
-
/* Bail out quickly on COMM_ERR_CLOSING - close handlers will tidy up */
if (io.flag == COMM_ERR_CLOSING) {
- debugs(33,5, HERE << " FD " << fd << " closing Bailout.");
+ debugs(33,5, HERE << io.conn << " closing Bailout.");
return;
}
+ assert(Comm::IsConnOpen(clientConnection));
+ assert(io.conn->fd == clientConnection->fd);
+
/*
* Don't reset the timeout value here. The timeout value will be
* set to Config.Timeout.request by httpAccept() and
@@ -2784,7 +2772,7 @@
*/
if (connReadWasError(io.flag, io.size, io.xerrno)) {
notifyAllContexts(io.xerrno);
- comm_close(fd);
+ io.conn->close();
return;
}
@@ -2797,21 +2785,21 @@
return;
} else if (io.size == 0) {
- debugs(33, 5, "clientReadRequest: FD " << fd << " closed?");
+ debugs(33, 5, HERE << io.conn << " closed?");
if (connFinishedWithConn(io.size)) {
- comm_close(fd);
+ clientConnection->close();
return;
}
/* It might be half-closed, we can't tell */
- fd_table[fd].flags.socket_eof = 1;
+ fd_table[io.conn->fd].flags.socket_eof = 1;
- commMarkHalfClosed(fd);
+ commMarkHalfClosed(io.conn->fd);
do_next_read = 0;
- fd_note(fd, "half-closed");
+ fd_note(io.conn->fd, "half-closed");
/* There is one more close check at the end, to detect aborted
* (partial) requests. At this point we can't tell if the request
@@ -2823,7 +2811,7 @@
/* Process next request */
if (getConcurrentRequestCount() == 0)
- fd_note(fd, "Reading next request");
+ fd_note(io.fd, "Reading next request");
if (!clientParseRequest(do_next_read)) {
if (!isOpen())
@@ -2836,9 +2824,9 @@
* be if we have an incomplete request.
* XXX: This duplicates ClientSocketContext::keepaliveNextRequest
*/
- if (getConcurrentRequestCount() == 0 && commIsHalfClosed(fd)) {
- debugs(33, 5, "clientReadRequest: FD " << fd << ": half-closed connection, no completed request parsed, connection closing.");
- comm_close(fd);
+ if (getConcurrentRequestCount() == 0 && commIsHalfClosed(io.fd)) {
+ debugs(33, 5, HERE << io.conn << ": half-closed connection, no completed request parsed, connection closing.");
+ clientConnection->close();
return;
}
}
@@ -2893,7 +2881,7 @@
return false;
}
} else { // identity encoding
- debugs(33,5, HERE << "handling plain request body for FD " << fd);
+ debugs(33,5, HERE << "handling plain request body for " << clientConnection);
putSize = bodyPipe->putMoreData(in.buf, in.notYetUsed);
if (!bodyPipe->mayNeedMoreData()) {
// BodyPipe will clear us automagically when we produced everything
@@ -2905,13 +2893,13 @@
connNoteUseOfBuffer(this, putSize);
if (!bodyPipe) {
- debugs(33,5, HERE << "produced entire request body for FD " << fd);
+ debugs(33,5, HERE << "produced entire request body for " << clientConnection);
if (closing()) {
/* we've finished reading like good clients,
* now do the close that initiateClose initiated.
*/
- comm_close(fd);
+ clientConnection->close();
return false;
}
}
@@ -2923,7 +2911,7 @@
err_type
ConnStateData::handleChunkedRequestBody(size_t &putSize)
{
- debugs(33,7, HERE << "chunked from FD " << fd << ": " << in.notYetUsed);
+ debugs(33,7, HERE << "chunked from " << clientConnection << ": " << in.notYetUsed);
try { // the parser will throw on errors
@@ -2991,11 +2979,11 @@
context->pullData();
} else {
// close or otherwise we may get stuck as nobody will notice the error?
- comm_reset_close(fd);
+ comm_reset_close(clientConnection);
}
#else
debugs(33, 3, HERE << "aborting chunked request without error " << error);
- comm_reset_close(fd);
+ comm_reset_close(clientConnection);
#endif
flags.readMoreRequests = false;
}
@@ -3030,12 +3018,12 @@
/*
* Some data has been sent to the client, just close the FD
*/
- comm_close(io.fd);
+ clientConnection->close();
} else if (nrequests) {
/*
* assume its a persistent connection; just close it
*/
- comm_close(io.fd);
+ clientConnection->close();
} else {
/*
* Generate an error
@@ -3065,7 +3053,7 @@
typedef CommCbMemFunT TimeoutDialer;
AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
TimeoutDialer, this, ConnStateData::requestTimeout);
- commSetTimeout(io.fd, 30, timeoutCall);
+ commSetConnTimeout(io.conn, 30, timeoutCall);
/*
* Aha, but we don't want a read handler!
@@ -3083,63 +3071,75 @@
* connection)
*/
debugs(33, 3, "requestTimeout: FD " << io.fd << ": lifetime is expired.");
-
- comm_close(io.fd);
-
+ io.conn->close();
#endif
}
static void
-clientLifetimeTimeout(int fd, void *data)
+clientLifetimeTimeout(const CommTimeoutCbParams &io)
{
- ClientHttpRequest *http = (ClientHttpRequest *)data;
- debugs(33, 1, "WARNING: Closing client " << " connection due to lifetime timeout");
- debugs(33, 1, "\t" << http->uri);
+ ClientHttpRequest *http = static_cast(io.data);
+ debugs(33, DBG_IMPORTANT, "WARNING: Closing client connection due to lifetime timeout");
+ debugs(33, DBG_IMPORTANT, "\t" << http->uri);
http->al.http.timedout = true;
- comm_close(fd);
+ if (Comm::IsConnOpen(io.conn))
+ io.conn->close();
}
ConnStateData *
-connStateCreate(const Ip::Address &peer, const Ip::Address &me, int fd, http_port_list *port)
+connStateCreate(const Comm::ConnectionPointer &client, http_port_list *port)
{
ConnStateData *result = new ConnStateData;
- result->peer = peer;
- result->log_addr = peer;
+ result->clientConnection = client;
+ result->log_addr = client->remote;
result->log_addr.ApplyMask(Config.Addrs.client_netmask);
- result->me = me;
- result->fd = fd;
result->in.buf = (char *)memAllocBuf(CLIENT_REQ_BUF_SZ, &result->in.allocatedSize);
result->port = cbdataReference(port);
- if (port->intercepted || port->spoof_client_ip) {
- Ip::Address client, dst;
-
- if (Ip::Interceptor.NatLookup(fd, me, peer, client, dst) == 0) {
- result->me = client;
- result->peer = dst;
- result->transparent(true);
- }
- }
-
if (port->disable_pmtu_discovery != DISABLE_PMTU_OFF &&
(result->transparent() || port->disable_pmtu_discovery == DISABLE_PMTU_ALWAYS)) {
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
int i = IP_PMTUDISC_DONT;
- setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &i, sizeof i);
-
+ setsockopt(client->fd, SOL_IP, IP_MTU_DISCOVER, &i, sizeof i);
#else
-
static int reported = 0;
if (!reported) {
debugs(33, 1, "Notice: httpd_accel_no_pmtu_disc not supported on your platform");
reported = 1;
}
-
-#endif
-
- }
+#endif
+ }
+
+ typedef CommCbMemFunT Dialer;
+ AsyncCall::Pointer call = JobCallback(33, 5, Dialer, result, ConnStateData::connStateClosed);
+ comm_add_close_handler(client->fd, call);
+
+ if (Config.onoff.log_fqdn)
+ fqdncache_gethostbyaddr(client->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;
+ if (identChecklist.fastCheck())
+ Ident::Start(client, clientIdentDone, result);
+ }
+#endif
+
+#if USE_SQUID_EUI
+ if (Eui::TheConfig.euiLookup) {
+ if (client->remote.IsIPv4()) {
+ result->clientConnection->remoteEui48.lookup(client->remote);
+ } else if (client->remote.IsIPv6()) {
+ result->clientConnection->remoteEui64.lookup(client->remote);
+ }
+ }
+#endif
+
+ clientdbEstablished(client->remote, 1);
result->flags.readMoreRequests = true;
return result;
@@ -3147,64 +3147,37 @@
/** Handle a new connection on HTTP socket. */
void
-httpAccept(int, int newfd, ConnectionDetail *details, comm_err_t flag, int xerrno, void *data)
+httpAccept(int, const Comm::ConnectionPointer &details, comm_err_t flag, int xerrno, void *data)
{
http_port_list *s = (http_port_list *)data;
- ConnStateData *connState = NULL;
if (flag != COMM_OK) {
// Its possible the call was still queued when the client disconnected
- debugs(33, 2, "httpAccept: FD " << s->listenFd << ": accept failure: " << xstrerr(xerrno));
+ debugs(33, 2, "httpAccept: " << s->listenConn << ": accept failure: " << xstrerr(xerrno));
return;
}
- debugs(33, 4, "httpAccept: FD " << newfd << ": accepted");
- fd_note(newfd, "client http connect");
- connState = connStateCreate(&details->peer, &details->me, newfd, s);
-
- typedef CommCbMemFunT Dialer;
- AsyncCall::Pointer call = JobCallback(33, 5,
- Dialer, connState, ConnStateData::connStateClosed);
- comm_add_close_handler(newfd, call);
-
- if (Config.onoff.log_fqdn)
- fqdncache_gethostbyaddr(details->peer, FQDN_LOOKUP_IF_MISS);
-
- typedef CommCbMemFunT TimeoutDialer;
- AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
- TimeoutDialer, connState, ConnStateData::requestTimeout);
- commSetTimeout(newfd, Config.Timeout.read, timeoutCall);
-
-#if USE_IDENT
- if (Ident::TheConfig.identLookup) {
- ACLFilledChecklist identChecklist(Ident::TheConfig.identLookup, NULL, NULL);
- identChecklist.src_addr = details->peer;
- identChecklist.my_addr = details->me;
- if (identChecklist.fastCheck())
- Ident::Start(details->me, details->peer, clientIdentDone, connState);
- }
-#endif
-
-#if USE_SQUID_EUI
- if (Eui::TheConfig.euiLookup) {
- if (details->peer.IsIPv4()) {
- connState->peer_eui48.lookup(details->peer);
- } else if (details->peer.IsIPv6()) {
- connState->peer_eui64.lookup(details->peer);
- }
- }
-#endif
+ debugs(33, 4, HERE << details << ": accepted");
+ fd_note(details->fd, "client http connect");
if (s->tcp_keepalive.enabled) {
- commSetTcpKeepalive(newfd, s->tcp_keepalive.idle, s->tcp_keepalive.interval, s->tcp_keepalive.timeout);
+ commSetTcpKeepalive(details->fd, s->tcp_keepalive.idle, s->tcp_keepalive.interval, s->tcp_keepalive.timeout);
}
+ incoming_sockets_accepted++;
+
+ // Socket is ready, setup the connection manager to start using it
+ ConnStateData *connState = connStateCreate(details, s);
+
+ typedef CommCbMemFunT TimeoutDialer;
+ AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
+ TimeoutDialer, connState, ConnStateData::requestTimeout);
+ commSetConnTimeout(details, Config.Timeout.read, timeoutCall);
+
connState->readSomeData();
- clientdbEstablished(details->peer, 1);
-
#if USE_DELAY_POOLS
- fd_table[newfd].clientInfo = NULL;
+ fd_table[details->fd].clientInfo = NULL;
if (Config.onoff.client_db) {
/* it was said several times that client write limiter does not work if client_db is disabled */
@@ -3221,18 +3194,18 @@
// TODO: we check early to limit error response bandwith but we
// should recheck when we can honor delay_pool_uses_indirect
- ch.src_addr = details->peer;
- ch.my_addr = details->me;
+ ch.src_addr = details->remote;
+ ch.my_addr = details->local;
if (ch.fastCheck()) {
/* request client information from db after we did all checks
this will save hash lookup if client failed checks */
- ClientInfo * cli = clientdbGetInfo(details->peer);
+ ClientInfo * cli = clientdbGetInfo(details->remote);
assert(cli);
/* put client info in FDE */
- fd_table[newfd].clientInfo = cli;
+ fd_table[details->fd].clientInfo = cli;
/* setup write limiter for this request */
const double burst = floor(0.5 +
@@ -3243,31 +3216,30 @@
}
}
#endif
- incoming_sockets_accepted++;
}
#if USE_SSL
/** Create SSL connection structure and update fd_table */
static SSL *
-httpsCreate(int newfd, ConnectionDetail *details, SSL_CTX *sslContext)
+httpsCreate(const Comm::ConnectionPointer &details, SSL_CTX *sslContext)
{
SSL *ssl = SSL_new(sslContext);
if (!ssl) {
const int ssl_error = ERR_get_error();
debugs(83, 1, "httpsAccept: Error allocating handle: " << ERR_error_string(ssl_error, NULL) );
- comm_close(newfd);
+ details->close();
return NULL;
}
- SSL_set_fd(ssl, newfd);
- fd_table[newfd].ssl = ssl;
- fd_table[newfd].read_method = &ssl_read_method;
- fd_table[newfd].write_method = &ssl_write_method;
+ SSL_set_fd(ssl, details->fd);
+ fd_table[details->fd].ssl = ssl;
+ fd_table[details->fd].read_method = &ssl_read_method;
+ fd_table[details->fd].write_method = &ssl_write_method;
- debugs(33, 5, "httpsCreate: will negotate SSL on FD " << newfd);
- fd_note(newfd, "client https start");
+ debugs(33, 5, "httpsCreate: will negotate SSL on " << details);
+ fd_note(details->fd, "client https start");
return ssl;
}
@@ -3393,57 +3365,39 @@
/** handle a new HTTPS connection */
static void
-httpsAccept(int, int newfd, ConnectionDetail *details, comm_err_t flag, int xerrno, void *data)
+httpsAccept(int, const Comm::ConnectionPointer& details, comm_err_t flag, int xerrno, void *data)
{
https_port_list *s = (https_port_list *)data;
+
+ if (flag != COMM_OK) {
+ // Its possible the call was still queued when the client disconnected
+ debugs(33, 2, "httpsAccept: " << s->listenConn << ": accept failure: " << xstrerr(xerrno));
+ return;
+ }
+
SSL_CTX *sslContext = s->staticSslContext.get();
-
- if (flag != COMM_OK) {
- // Its possible the call was still queued when the client disconnected
- debugs(33, 2, "httpsAccept: FD " << s->listenFd << ": accept failure: " << xstrerr(xerrno));
- return;
- }
-
SSL *ssl = NULL;
- if (!(ssl = httpsCreate(newfd, details, sslContext)))
+ if (!(ssl = httpsCreate(details, sslContext)))
return;
- debugs(33, 5, "httpsAccept: FD " << newfd << " accepted, starting SSL negotiation.");
- fd_note(newfd, "client https connect");
- ConnStateData *connState = connStateCreate(details->peer, details->me,
- newfd, &s->http);
- typedef CommCbMemFunT Dialer;
- AsyncCall::Pointer call = JobCallback(33, 5,
- Dialer, connState, ConnStateData::connStateClosed);
- comm_add_close_handler(newfd, call);
-
- if (Config.onoff.log_fqdn)
- fqdncache_gethostbyaddr(details->peer, FQDN_LOOKUP_IF_MISS);
-
- typedef CommCbMemFunT TimeoutDialer;
- AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
- TimeoutDialer, connState, ConnStateData::requestTimeout);
- commSetTimeout(newfd, Config.Timeout.request, timeoutCall);
-
-#if USE_IDENT
- if (Ident::TheConfig.identLookup) {
- ACLFilledChecklist identChecklist(Ident::TheConfig.identLookup, NULL, NULL);
- identChecklist.src_addr = details->peer;
- identChecklist.my_addr = details->me;
- if (identChecklist.fastCheck())
- Ident::Start(details->me, details->peer, clientIdentDone, connState);
- }
-#endif
+ debugs(33, 5, HERE << details << " accepted, starting SSL negotiation.");
+ fd_note(details->fd, "client https connect");
if (s->http.tcp_keepalive.enabled) {
- commSetTcpKeepalive(newfd, s->http.tcp_keepalive.idle, s->http.tcp_keepalive.interval, s->http.tcp_keepalive.timeout);
+ commSetTcpKeepalive(details->fd, s->http.tcp_keepalive.idle, s->http.tcp_keepalive.interval, s->http.tcp_keepalive.timeout);
}
- Comm::SetSelect(newfd, COMM_SELECT_READ, clientNegotiateSSL, connState, 0);
-
- clientdbEstablished(details->peer, 1);
-
incoming_sockets_accepted++;
+
+ // Socket is ready, setup the connection manager to start using it
+ ConnStateData *connState = connStateCreate(details, &s->http);
+
+ typedef CommCbMemFunT TimeoutDialer;
+ AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
+ TimeoutDialer, connState, ConnStateData::requestTimeout);
+ commSetConnTimeout(details, Config.Timeout.request, timeoutCall);
+
+ Comm::SetSelect(details->fd, COMM_SELECT_READ, clientNegotiateSSL, connState, 0);
}
void
@@ -3525,7 +3479,7 @@
if (sslContext && sslHostName != "") {
if (!ssl_ctx_cache.add(sslHostName.termedBuf(), sslContext)) {
// If it is not in storage delete after using. Else storage deleted it.
- fd_table[fd].dynamicSslContext = sslContext;
+ fd_table[clientConnection->fd].dynamicSslContext = sslContext;
}
} else {
debugs(33, 2, HERE << "Failed to generate SSL cert for " << sslHostName);
@@ -3535,8 +3489,8 @@
// If generated ssl context = NULL, try to use static ssl context.
if (!sslContext) {
if (!port->staticSslContext) {
- debugs(83, 1, "Closing SSL FD " << fd << " as lacking SSL context");
- comm_close(fd);
+ debugs(83, 1, "Closing SSL " << clientConnection->remote << " as lacking SSL context");
+ clientConnection->close();
return false;
} else {
debugs(33, 5, HERE << "Using static ssl context.");
@@ -3544,20 +3498,15 @@
}
}
- // fake a ConnectionDetail object; XXX: make ConnState a ConnectionDetail?
- ConnectionDetail detail;
- detail.me = me;
- detail.peer = peer;
-
SSL *ssl = NULL;
- if (!(ssl = httpsCreate(fd, &detail, sslContext)))
+ if (!(ssl = httpsCreate(clientConnection, sslContext)))
return false;
- // commSetTimeout() was called for this request before we switched.
+ // commSetConnTimeout() was called for this request before we switched.
// Disable the client read handler until peer selection is complete
- Comm::SetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);
- Comm::SetSelect(fd, COMM_SELECT_READ, clientNegotiateSSL, this, 0);
+ Comm::SetSelect(clientConnection->fd, COMM_SELECT_READ, NULL, NULL, 0);
+ Comm::SetSelect(clientConnection->fd, COMM_SELECT_READ, clientNegotiateSSL, this, 0);
switchedToHttps_ = true;
return true;
}
@@ -3574,7 +3523,7 @@
freeAllContexts();
//currentobject->connIsFinished();
- debugs(33, 5, HERE << "converting FD " << fd << " to SSL");
+ debugs(33, 5, HERE << "converting " << clientConnection << " to SSL");
return getSslContextStart();
}
@@ -3583,9 +3532,9 @@
/// check FD after clientHttp[s]ConnectionOpened, adjust HttpSockets as needed
static bool
-OpenedHttpSocket(int fd, const Ipc::FdNoteId portType)
+OpenedHttpSocket(const Comm::ConnectionPointer &c, const Ipc::FdNoteId portType)
{
- if (fd < 0) {
+ if (!Comm::IsConnOpen(c)) {
Must(NHttpSockets > 0); // we tried to open some
--NHttpSockets; // there will be fewer sockets than planned
Must(HttpSockets[NHttpSockets] < 0); // no extra fds received
@@ -3600,12 +3549,12 @@
/// find any unused HttpSockets[] slot and store fd there or return false
static bool
-AddOpenedHttpSocket(int fd)
+AddOpenedHttpSocket(const Comm::ConnectionPointer &conn)
{
bool found = false;
for (int i = 0; i < NHttpSockets && !found; i++) {
if ((found = HttpSockets[i] < 0))
- HttpSockets[i] = fd;
+ HttpSockets[i] = conn->fd;
}
return found;
}
@@ -3642,10 +3591,11 @@
Ssl::Helper::GetInstance();
#endif //USE_SSL_CRTD
- /* AYJ: 2009-12-27: bit bumpy. new ListenStateData(...) should be doing all the Comm:: stuff ... */
-
- const int openFlags = COMM_NONBLOCKING |
- (s->spoof_client_ip ? COMM_TRANSPARENT : 0);
+ // Fill out a Comm::Connection which IPC will open as a listener for us
+ // then pass back when active so we can start a TcpAcceptor subscription.
+ s->listenConn = new Comm::Connection;
+ s->listenConn->local = s->s;
+ s->listenConn->flags = COMM_NONBLOCKING | (s->spoof_client_ip ? COMM_TRANSPARENT : 0) | (s->intercepted ? COMM_INTERCEPTION : 0);
// setup the subscriptions such that new connections accepted by listenConn are handled by HTTP
typedef CommCbFunPtrCallT AcceptCall;
@@ -3653,8 +3603,8 @@
Subscription::Pointer sub = new CallSubscription(subCall);
AsyncCall::Pointer listenCall = asyncCall(33,2, "clientListenerConnectionOpened",
- ListeningStartedDialer(&clientListenerConnectionOpened, openFlags, s, Ipc::fdnHttpSocket, sub));
- Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, s->s, openFlags, Ipc::fdnHttpSocket, listenCall);
+ ListeningStartedDialer(&clientListenerConnectionOpened, s, Ipc::fdnHttpSocket, sub));
+ Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, s->listenConn, Ipc::fdnHttpSocket, listenCall);
HttpSockets[NHttpSockets++] = -1; // set in clientListenerConnectionOpened
}
@@ -3667,31 +3617,6 @@
#endif
}
-/// process clientHttpConnectionsOpen result
-static void
-clientListenerConnectionOpened(int fd, int flags, int errNo, http_port_list *s, const Ipc::FdNoteId portTypeNote, const Subscription::Pointer &sub)
-{
- s->listenFd = fd;
- if (!OpenedHttpSocket(s->listenFd, portTypeNote))
- return;
-
- Must(s);
- Must(s->listenFd >= 0);
-
- // TCP: setup a job to handle accept() with subscribed handler
- AsyncJob::Start(new Comm::TcpAcceptor(s->listenFd, s->s, flags, FdNote(portTypeNote), sub));
-
- debugs(1, 1, "Accepting" <<
- (s->intercepted ? " intercepted" : "") <<
- (s->spoof_client_ip ? " spoofing" : "") <<
- (s->sslBump ? " bumpy" : "") <<
- (s->accel ? " accelerated" : "")
- << FdNote(portTypeNote) << " connections at "
- << " FD " << s->listenFd << " on " << s->s);
-
- Must(AddOpenedHttpSocket(s->listenFd)); // otherwise, we have received a fd we did not ask for
-}
-
#if USE_SSL
static void
clientHttpsConnectionsOpen(void)
@@ -3711,8 +3636,11 @@
continue;
}
- const int openFlags = COMM_NONBLOCKING |
- (s->spoof_client_ip ? COMM_TRANSPARENT : 0);
+ // Fill out a Comm::Connection which IPC will open as a listener for us
+ s->http.listenConn = new Comm::Connection;
+ s->http.listenConn->local = s->http.s;
+ s->http.listenConn->flags = COMM_NONBLOCKING | (s->http.spoof_client_ip ? COMM_TRANSPARENT : 0) |
+ (s->http.intercepted ? COMM_INTERCEPTION : 0);
// setup the subscriptions such that new connections accepted by listenConn are handled by HTTPS
typedef CommCbFunPtrCallT AcceptCall;
@@ -3720,16 +3648,38 @@
Subscription::Pointer sub = new CallSubscription(subCall);
AsyncCall::Pointer listenCall = asyncCall(33, 2, "clientListenerConnectionOpened",
- ListeningStartedDialer(&clientListenerConnectionOpened, openFlags,
+ ListeningStartedDialer(&clientListenerConnectionOpened,
&s->http, Ipc::fdnHttpsSocket, sub));
-
- Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, s->s, openFlags, Ipc::fdnHttpsSocket, listenCall);
-
+ Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, s->listenConn, Ipc::fdnHttpsSocket, listenCall);
HttpSockets[NHttpSockets++] = -1;
}
}
#endif
+/// process clientHttpConnectionsOpen result
+static void
+clientListenerConnectionOpened(http_port_list *s, const Ipc::FdNoteId portTypeNote, const Subscription::Pointer &sub)
+{
+ if (!OpenedHttpSocket(s->listenConn, portTypeNote))
+ return;
+
+ Must(s);
+ Must(Comm::IsConnOpen(s->listenConn));
+
+ // TCP: setup a job to handle accept() with subscribed handler
+ AsyncJob::Start(new Comm::TcpAcceptor(s->listenConn, FdNote(portTypeNote), sub));
+
+ debugs(1, 1, "Accepting " <<
+ (s->intercepted ? "NAT intercepted " : "") <<
+ (s->spoof_client_ip ? "TPROXY spoofing " : "") <<
+ (s->sslBump ? "SSL bumped " : "") <<
+ (s->accel ? "reverse-proxy " : "")
+ << FdNote(portTypeNote) << " connections at "
+ << s->listenConn);
+
+ Must(AddOpenedHttpSocket(s->listenConn)); // otherwise, we have received a fd we did not ask for
+}
+
void
clientOpenListenSockets(void)
{
@@ -3746,19 +3696,19 @@
clientHttpConnectionsClose(void)
{
for (http_port_list *s = Config.Sockaddr.http; s; s = s->next) {
- if (s->listenFd >= 0) {
- debugs(1, 1, "FD " << s->listenFd << " Closing HTTP connection");
- comm_close(s->listenFd);
- s->listenFd = -1;
+ if (s->listenConn != NULL) {
+ debugs(1, 1, "Closing HTTP port " << s->listenConn->local);
+ s->listenConn->close();
+ s->listenConn = NULL;
}
}
#if USE_SSL
for (http_port_list *s = Config.Sockaddr.https; s; s = s->next) {
- if (s->listenFd >= 0) {
- debugs(1, 1, "FD " << s->listenFd << " Closing HTTPS connection");
- comm_close(s->listenFd);
- s->listenFd = -1;
+ if (s->listenConn != NULL) {
+ debugs(1, 1, "Closing HTTPS port " << s->listenConn->local);
+ s->listenConn->close();
+ s->listenConn = NULL;
}
}
#endif
@@ -3839,7 +3789,7 @@
{
ConnStateData * conn = http->getConn();
ACLFilledChecklist *ch = new ACLFilledChecklist(acl, http->request,
- cbdataReferenceValid(conn) && conn != NULL ? conn->rfc931 : dash_str);
+ cbdataReferenceValid(conn) && conn != NULL && conn->clientConnection != NULL ? conn->clientConnection->rfc931 : dash_str);
/*
* hack for ident ACL. It needs to get full addresses, and a place to store
@@ -3861,9 +3811,11 @@
CBDATA_CLASS_INIT(ConnStateData);
-ConnStateData::ConnStateData() :AsyncJob("ConnStateData"), transparent_ (false), closing_ (false), switchedToHttps_(false)
+ConnStateData::ConnStateData() :
+ AsyncJob("ConnStateData"),
+ closing_(false),
+ switchedToHttps_(false)
{
- pinning.fd = -1;
pinning.pinned = false;
pinning.auth = false;
}
@@ -3871,13 +3823,7 @@
bool
ConnStateData::transparent() const
{
- return transparent_;
-}
-
-void
-ConnStateData::transparent(bool const anInt)
-{
- transparent_ = anInt;
+ return clientConnection != NULL && (clientConnection->flags & (COMM_TRANSPARENT|COMM_INTERCEPTION));
}
bool
@@ -3890,7 +3836,7 @@
ConnStateData::stopReading()
{
if (reading()) {
- comm_read_cancel(fd, reader);
+ comm_read_cancel(clientConnection->fd, reader);
reader = NULL;
}
}
@@ -4018,62 +3964,54 @@
}
debugs(33, 3, HERE << " closing due to missing context for 1xx");
- comm_close(fd);
+ clientConnection->close();
}
/* This is a comm call normally scheduled by comm_close() */
void
ConnStateData::clientPinnedConnectionClosed(const CommCloseCbParams &io)
{
- pinning.fd = -1;
- if (pinning.peer) {
- cbdataReferenceDone(pinning.peer);
- }
- safe_free(pinning.host);
- /* NOTE: pinning.pinned should be kept. This combined with fd == -1 at the end of a request indicates that the host
- * connection has gone away */
+ unpinConnection();
}
-void ConnStateData::pinConnection(int pinning_fd, HttpRequest *request, struct peer *aPeer, bool auth)
+void
+ConnStateData::pinConnection(const Comm::ConnectionPointer &pinServer, HttpRequest *request, struct peer *aPeer, bool auth)
{
- fde *f;
char desc[FD_DESC_SZ];
- if (pinning.fd == pinning_fd)
- return;
- else if (pinning.fd != -1)
- comm_close(pinning.fd);
-
- if (pinning.host)
- safe_free(pinning.host);
-
- pinning.fd = pinning_fd;
+ if (Comm::IsConnOpen(pinning.serverConnection)) {
+ if (pinning.serverConnection->fd == pinServer->fd)
+ return;
+
+ unpinConnection(); // clears fields ready for re-use. Prevent close() scheduling our close handler.
+ pinning.serverConnection->close();
+ } else
+ unpinConnection(); // clears fields ready for re-use.
+
+ pinning.serverConnection = pinServer;
pinning.host = xstrdup(request->GetHost());
pinning.port = request->port;
pinning.pinned = true;
- if (pinning.peer)
- cbdataReferenceDone(pinning.peer);
if (aPeer)
pinning.peer = cbdataReference(aPeer);
pinning.auth = auth;
- f = &fd_table[fd];
- snprintf(desc, FD_DESC_SZ, "%s pinned connection for %s:%d (%d)",
- (auth || !aPeer) ? request->GetHost() : aPeer->name, f->ipaddr, (int) f->remote_port, fd);
- fd_note(pinning_fd, desc);
+ char stmp[MAX_IPSTRLEN];
+ snprintf(desc, FD_DESC_SZ, "%s pinned connection for %s (%d)",
+ (auth || !aPeer) ? request->GetHost() : aPeer->name, clientConnection->remote.ToURL(stmp,MAX_IPSTRLEN), clientConnection->fd);
+ fd_note(pinning.serverConnection->fd, desc);
typedef CommCbMemFunT Dialer;
pinning.closeHandler = JobCallback(33, 5,
Dialer, this, ConnStateData::clientPinnedConnectionClosed);
- comm_add_close_handler(pinning_fd, pinning.closeHandler);
-
+ comm_add_close_handler(pinning.serverConnection->fd, pinning.closeHandler);
}
-int ConnStateData::validatePinnedConnection(HttpRequest *request, const struct peer *aPeer)
+const Comm::ConnectionPointer
+ConnStateData::validatePinnedConnection(HttpRequest *request, const struct peer *aPeer)
{
bool valid = true;
- if (pinning.fd < 0)
- return -1;
-
+ if (!Comm::IsConnOpen(pinning.serverConnection))
+ valid = false;
if (pinning.auth && request && strcasecmp(pinning.host, request->GetHost()) != 0) {
valid = false;
}
@@ -4088,29 +4026,32 @@
}
if (!valid) {
- int pinning_fd=pinning.fd;
/* The pinning info is not safe, remove any pinning info*/
unpinConnection();
/* also close the server side socket, we should not use it for invalid/unauthenticated
requests...
*/
- comm_close(pinning_fd);
- return -1;
+ if (Comm::IsConnOpen(pinning.serverConnection))
+ pinning.serverConnection->close();
}
- return pinning.fd;
+ return pinning.serverConnection;
}
-void ConnStateData::unpinConnection()
+void
+ConnStateData::unpinConnection()
{
if (pinning.peer)
cbdataReferenceDone(pinning.peer);
if (pinning.closeHandler != NULL) {
- comm_remove_close_handler(pinning.fd, pinning.closeHandler);
+ comm_remove_close_handler(pinning.serverConnection->fd, pinning.closeHandler);
pinning.closeHandler = NULL;
}
- pinning.fd = -1;
+
safe_free(pinning.host);
+
+ /* NOTE: pinning.pinned should be kept. This combined with fd == -1 at the end of a request indicates that the host
+ * connection has gone away */
}
=== modified file 'src/client_side.h'
--- src/client_side.h 2011-03-26 02:03:49 +0000
+++ src/client_side.h 2011-03-26 09:51:57 +0000
@@ -40,8 +40,6 @@
#include "BodyPipe.h"
#include "comm.h"
#include "CommCalls.h"
-#include "eui/Eui48.h"
-#include "eui/Eui64.h"
#include "HttpControlMsg.h"
#include "RefCount.h"
#include "StoreIOBuffer.h"
@@ -62,8 +60,10 @@
ClientSocketContext();
~ClientSocketContext();
bool startOfOutput() const;
- void writeComplete(int fd, char *bufnotused, size_t size, comm_err_t errflag);
+ void writeComplete(const Comm::ConnectionPointer &conn, char *bufnotused, size_t size, comm_err_t errflag);
void keepaliveNextRequest();
+
+ Comm::ConnectionPointer clientConnection; /// details about the client connection socket.
ClientHttpRequest *http; /* we own this */
HttpReply *reply;
char reqbuf[HTTP_REQBUF_SZ];
@@ -102,7 +102,6 @@
size_t lengthToSend(Range const &available);
void noteSentBodyBytes(size_t);
void buildRangeHeader(HttpReply * rep);
- int fd() const;
clientStreamNode * getTail() const;
clientStreamNode * getClientReplyContext() const;
void connIsFinished();
@@ -116,8 +115,8 @@
void writeControlMsg(HttpControlMsg &msg);
protected:
- static void WroteControlMsg(int fd, char *bufnotused, size_t size, comm_err_t errflag, int xerrno, void *data);
- void wroteControlMsg(int fd, char *bufnotused, size_t size, comm_err_t errflag, int xerrno);
+ static IOCB WroteControlMsg;
+ void wroteControlMsg(const Comm::ConnectionPointer &conn, char *bufnotused, size_t size, comm_err_t errflag, int xerrno);
private:
CBDATA_CLASS(ClientSocketContext);
@@ -135,8 +134,6 @@
};
-class ConnectionDetail;
-
/** A connection to a socket */
class ConnStateData : public BodyProducer, public HttpControlMsgSink
{
@@ -164,7 +161,8 @@
// HttpControlMsgSink API
virtual void sendControlMsg(HttpControlMsg msg);
- int fd;
+ // Client TCP connection details from comm layer.
+ Comm::ConnectionPointer clientConnection;
struct In {
In();
@@ -199,25 +197,15 @@
*/
ClientSocketContext::Pointer currentobject;
- Ip::Address peer;
-
- Ip::Address me;
-
Ip::Address log_addr;
- char rfc931[USER_IDENT_SZ];
int nrequests;
-#if USE_SQUID_EUI
- Eui::Eui48 peer_eui48;
- Eui::Eui64 peer_eui64;
-#endif
-
struct {
bool readMoreRequests;
bool swanSang; // XXX: temporary flag to check proper cleanup
} flags;
struct {
- int fd; /* pinned server side connection */
+ Comm::ConnectionPointer serverConnection; /* pinned server side connection */
char *host; /* host name of pinned connection */
int port; /* port of pinned connection */
bool pinned; /* this connection was pinned */
@@ -229,7 +217,6 @@
http_port_list *port;
bool transparent() const;
- void transparent(bool const);
bool reading() const;
void stopReading(); ///< cancels comm_read if it is scheduled
@@ -246,7 +233,7 @@
/**
* Correlate the current ConnStateData object with the pinning_fd socket descriptor.
*/
- void pinConnection(int fd, HttpRequest *request, struct peer *peer, bool auth);
+ void pinConnection(const Comm::ConnectionPointer &pinServerConn, HttpRequest *request, struct peer *peer, bool auth);
/**
* Decorrelate the ConnStateData object from its pinned peer
*/
@@ -256,9 +243,9 @@
* if pinned info is not valid.
\param request if it is not NULL also checks if the pinning info refers to the request client side HttpRequest
\param peer if it is not NULL also check if the peer is the pinning peer
- \return The fd of the server side connection or -1 if fails.
+ \return The details of the server side connection (may be closed if failures were present).
*/
- int validatePinnedConnection(HttpRequest *request, const struct peer *peer);
+ const Comm::ConnectionPointer validatePinnedConnection(HttpRequest *request, const struct peer *peer);
/**
* returts the pinned peer if exists, NULL otherwise
*/
@@ -314,7 +301,6 @@
// XXX: CBDATA plays with public/private and leaves the following 'private' fields all public... :(
CBDATA_CLASS2(ConnStateData);
- bool transparent_;
bool closing_;
bool switchedToHttps_;
=== modified file 'src/client_side_reply.cc'
--- src/client_side_reply.cc 2011-03-02 07:27:24 +0000
+++ src/client_side_reply.cc 2011-03-26 04:37:37 +0000
@@ -269,15 +269,15 @@
http->storeEntry(entry);
assert(http->out.offset == 0);
- http->request->clientConnection = http->getConn();
+ http->request->clientConnectionManager = http->getConn(); // AYJ: irrelevant?
/*
* A refcounted pointer so that FwdState stays around as long as
* this clientReplyContext does
*/
- FwdState::fwdStart(http->getConn() != NULL ? http->getConn()->fd : -1,
- http->storeEntry(),
- http->request);
+ Comm::ConnectionPointer conn = http->getConn() != NULL ? http->getConn()->clientConnection : NULL;
+ FwdState::fwdStart(conn, http->storeEntry(), http->request);
+
/* Register with storage manager to receive updates when data comes in. */
if (EBIT_TEST(entry->flags, ENTRY_ABORTED))
@@ -632,7 +632,7 @@
if (r->flags.loopdetect &&
(http->flags.accel || http->flags.intercepted)) {
http->al.http.code = HTTP_FORBIDDEN;
- err = clientBuildError(ERR_ACCESS_DENIED, HTTP_FORBIDDEN, NULL, http->getConn()->peer, http->request);
+ err = clientBuildError(ERR_ACCESS_DENIED, HTTP_FORBIDDEN, NULL, http->getConn()->clientConnection->remote, http->request);
createStoreEntry(r->method, request_flags());
errorAppendEntry(http->storeEntry(), err);
triggerInitialStoreRead();
@@ -660,12 +660,11 @@
if (http->flags.internal)
r->protocol = AnyP::PROTO_INTERNAL;
- r->clientConnection = http->getConn();
+ r->clientConnectionManager = http->getConn();
/** Start forwarding to get the new object from network */
- FwdState::fwdStart(http->getConn() != NULL ? http->getConn()->fd : -1,
- http->storeEntry(),
- r);
+ Comm::ConnectionPointer conn = http->getConn() != NULL ? http->getConn()->clientConnection : NULL;
+ FwdState::fwdStart(conn, http->storeEntry(), r);
}
}
@@ -678,11 +677,11 @@
void
clientReplyContext::processOnlyIfCachedMiss()
{
- ErrorState *err = NULL;
debugs(88, 4, "clientProcessOnlyIfCachedMiss: '" <<
RequestMethodStr(http->request->method) << " " << http->uri << "'");
http->al.http.code = HTTP_GATEWAY_TIMEOUT;
- err = clientBuildError(ERR_ONLY_IF_CACHED_MISS, HTTP_GATEWAY_TIMEOUT, NULL, http->getConn()->peer, http->request);
+ ErrorState *err = clientBuildError(ERR_ONLY_IF_CACHED_MISS, HTTP_GATEWAY_TIMEOUT, NULL,
+ http->getConn()->clientConnection->remote, http->request);
removeClientStoreReference(&sc, http);
startError(err);
}
@@ -848,7 +847,8 @@
if (EBIT_TEST(entry->flags, ENTRY_SPECIAL)) {
http->logType = LOG_TCP_DENIED;
- ErrorState *err = clientBuildError(ERR_ACCESS_DENIED, HTTP_FORBIDDEN, NULL, http->getConn()->peer, http->request);
+ ErrorState *err = clientBuildError(ERR_ACCESS_DENIED, HTTP_FORBIDDEN, NULL,
+ http->getConn()->clientConnection->remote, http->request);
startError(err);
return;
}
@@ -886,7 +886,7 @@
if (!Config2.onoff.enable_purge) {
http->logType = LOG_TCP_DENIED;
- ErrorState *err = clientBuildError(ERR_ACCESS_DENIED, HTTP_FORBIDDEN, NULL, http->getConn()->peer, http->request);
+ ErrorState *err = clientBuildError(ERR_ACCESS_DENIED, HTTP_FORBIDDEN, NULL, http->getConn()->clientConnection->remote, http->request);
startError(err);
return;
}
@@ -1734,11 +1734,11 @@
assert(http->out.offset == 0);
if (Ip::Qos::TheConfig.isHitTosActive()) {
- Ip::Qos::doTosLocalHit(http->getConn()->fd);
+ Ip::Qos::doTosLocalHit(http->getConn()->clientConnection);
}
if (Ip::Qos::TheConfig.isHitNfmarkActive()) {
- Ip::Qos::doNfmarkLocalHit(http->getConn()->fd);
+ Ip::Qos::doNfmarkLocalHit(http->getConn()->clientConnection);
}
localTempBuffer.offset = reqofs;
@@ -1839,7 +1839,7 @@
tmp_noaddr.SetNoAddr(); // TODO: make a global const
http->logType = LOG_TCP_DENIED_REPLY;
ErrorState *err = clientBuildError(ERR_TOO_BIG, HTTP_FORBIDDEN, NULL,
- http->getConn() != NULL ? http->getConn()->peer : tmp_noaddr,
+ http->getConn() != NULL ? http->getConn()->clientConnection->remote : tmp_noaddr,
http->request);
removeClientStoreReference(&(sc), http);
HTTPMSGUNLOCK(reply);
@@ -1854,7 +1854,7 @@
http->logType = LOG_TCP_HIT;
ErrorState *const err =
clientBuildError(ERR_PRECONDITION_FAILED, HTTP_PRECONDITION_FAILED,
- NULL, http->getConn()->peer, http->request);
+ NULL, http->getConn()->clientConnection->remote, http->request);
removeClientStoreReference(&sc, http);
HTTPMSGUNLOCK(reply);
startError(err);
@@ -1961,7 +1961,7 @@
Ip::Address tmp_noaddr;
tmp_noaddr.SetNoAddr();
err = clientBuildError(page_id, HTTP_FORBIDDEN, NULL,
- http->getConn() != NULL ? http->getConn()->peer : tmp_noaddr,
+ http->getConn() != NULL ? http->getConn()->clientConnection->remote : tmp_noaddr,
http->request);
removeClientStoreReference(&sc, http);
@@ -2051,10 +2051,11 @@
ConnStateData * conn = http->getConn();
- int fd = conn != NULL ? conn->fd : -1;
- if (fd >= 0 && fd_table[fd].closing()) { // too late, our conn is closing
- // TODO: should we also quit when fd is negative?
- debugs(33,3, HERE << "not sending more data to a closing FD " << fd);
+ // AYJ: this seems a bit weird to ignore CLOSED but drop on closing.
+ if (conn != NULL && Comm::IsConnOpen(conn->clientConnection) && fd_table[conn->clientConnection->fd].closing()) {
+ // too late, our conn is closing
+ // TODO: should we also quit?
+ debugs(33,3, HERE << "not sending more data to a closing " << conn->clientConnection);
return;
}
@@ -2069,13 +2070,12 @@
body_buf = buf;
}
- if (reqofs==0 && !logTypeIsATcpHit(http->logType)) {
- assert(fd >= 0); // the beginning of this method implies fd may be -1
+ if (reqofs==0 && !logTypeIsATcpHit(http->logType) && Comm::IsConnOpen(conn->clientConnection)) {
if (Ip::Qos::TheConfig.isHitTosActive()) {
- Ip::Qos::doTosLocalMiss(fd, http->request->hier.code);
+ Ip::Qos::doTosLocalMiss(conn->clientConnection, http->request->hier.code);
}
if (Ip::Qos::TheConfig.isHitNfmarkActive()) {
- Ip::Qos::doNfmarkLocalMiss(fd, http->request->hier.code);
+ Ip::Qos::doNfmarkLocalMiss(conn->clientConnection, http->request->hier.code);
}
}
@@ -2098,7 +2098,7 @@
reqofs << " bytes (" << result.length <<
" new bytes)");
debugs(88, 5, "clientReplyContext::sendMoreData:"
- " FD " << fd <<
+ << conn->clientConnection <<
" '" << entry->url() << "'" <<
" out.offset=" << http->out.offset);
=== modified file 'src/client_side_request.cc'
--- src/client_side_request.cc 2011-03-24 15:48:34 +0000
+++ src/client_side_request.cc 2011-03-26 01:48:58 +0000
@@ -62,6 +62,7 @@
#include "client_side_reply.h"
#include "client_side_request.h"
#include "ClientRequestContext.h"
+#include "comm/Connection.h"
#include "comm/Write.h"
#include "compat/inet_pton.h"
#include "fde.h"
@@ -169,6 +170,7 @@
{
start_time = current_time;
setConn(aConn);
+ clientConnection = aConn->clientConnection;
dlinkAdd(this, &active, &ClientActiveRequests);
#if USE_ADAPTATION
request_satisfaction_mode = false;
@@ -283,6 +285,8 @@
if (calloutContext)
delete calloutContext;
+ clientConnection = NULL;
+
if (conn_)
cbdataReferenceDone(conn_);
@@ -551,7 +555,7 @@
acl_checklist = clientAclChecklistCreate(Config.accessList.adapted_http, http);
acl_checklist->nonBlockingCheck(clientAccessCheckDoneWrapper, this);
} else {
- debugs(85, 2, HERE << "No adapted_http_access configuration.");
+ debugs(85, 2, HERE << "No adapted_http_access configuration. default: ALLOW");
clientAccessCheckDone(ACCESS_ALLOWED);
}
}
@@ -637,7 +641,7 @@
tmpnoaddr.SetNoAddr();
repContext->setReplyToError(page_id, status,
http->request->method, NULL,
- http->getConn() != NULL ? http->getConn()->peer : tmpnoaddr,
+ http->getConn() != NULL ? http->getConn()->clientConnection->remote : tmpnoaddr,
http->request,
NULL,
#if USE_AUTH
@@ -681,9 +685,10 @@
Adaptation::Icap::History::Pointer ih = http->request->icapHistory();
if (ih != NULL) {
if (http->getConn() != NULL) {
- ih->rfc931 = http->getConn()->rfc931;
+ ih->rfc931 = http->getConn()->clientConnection->rfc931;
#if USE_SSL
- ih->ssluser = sslGetUserEmail(fd_table[http->getConn()->fd].ssl);
+ assert(http->getConn()->clientConnection != NULL);
+ ih->ssluser = sslGetUserEmail(fd_table[http->getConn()->clientConnection->fd].ssl);
#endif
}
ih->log_uri = http->log_uri;
@@ -791,7 +796,7 @@
request->flags.connection_auth_disabled = http_conn->port->connection_auth_disabled;
if (!request->flags.connection_auth_disabled) {
- if (http_conn->pinning.fd != -1) {
+ if (Comm::IsConnOpen(http_conn->pinning.serverConnection)) {
if (http_conn->pinning.auth) {
request->flags.connection_auth = 1;
request->flags.auth = 1;
@@ -1069,8 +1074,8 @@
/* FIXME PIPELINE: This is innacurate during pipelining */
- if (http->getConn() != NULL)
- fd_note(http->getConn()->fd, http->uri);
+ if (http->getConn() != NULL && Comm::IsConnOpen(http->getConn()->clientConnection))
+ fd_note(http->getConn()->clientConnection->fd, http->uri);
assert(http->uri);
@@ -1172,7 +1177,7 @@
// called when comm_write has completed
static void
-SslBumpEstablish(int, char *, size_t, comm_err_t errflag, int, void *data)
+SslBumpEstablish(const Comm::ConnectionPointer &, char *, size_t, comm_err_t errflag, int, void *data)
{
ClientHttpRequest *r = static_cast(data);
debugs(85, 5, HERE << "responded to CONNECT: " << r << " ? " << errflag);
@@ -1200,18 +1205,15 @@
void
ClientHttpRequest::sslBumpStart()
{
- debugs(85, 5, HERE << "ClientHttpRequest::sslBumpStart");
-
+ debugs(85, 5, HERE << "Confirming CONNECT tunnel on FD " << getConn()->clientConnection);
// send an HTTP 200 response to kick client SSL negotiation
- const int fd = getConn()->fd;
- debugs(33, 7, HERE << "Confirming CONNECT tunnel on FD " << fd);
+ debugs(33, 7, HERE << "Confirming CONNECT tunnel on FD " << getConn()->clientConnection);
// TODO: Unify with tunnel.cc and add a Server(?) header
- static const char *const conn_established =
- "HTTP/1.1 200 Connection established\r\n\r\n";
+ static const char *const conn_established = "HTTP/1.1 200 Connection established\r\n\r\n";
AsyncCall::Pointer call = commCbCall(85, 5, "ClientSocketContext::sslBumpEstablish",
CommIoCbPtrFun(&SslBumpEstablish, this));
- Comm::Write(fd, conn_established, strlen(conn_established), call, NULL);
+ Comm::Write(getConn()->clientConnection, conn_established, strlen(conn_established), call, NULL);
}
#endif
@@ -1346,25 +1348,25 @@
if (!calloutContext->tosToClientDone) {
calloutContext->tosToClientDone = true;
- if (getConn() != NULL) {
+ if (getConn() != NULL && Comm::IsConnOpen(getConn()->clientConnection)) {
ACLFilledChecklist ch(NULL, request, NULL);
ch.src_addr = request->client_addr;
ch.my_addr = request->my_addr;
tos_t tos = aclMapTOS(Ip::Qos::TheConfig.tosToClient, &ch);
if (tos)
- Ip::Qos::setSockTos(getConn()->fd, tos);
+ Ip::Qos::setSockTos(getConn()->clientConnection, tos);
}
}
if (!calloutContext->nfmarkToClientDone) {
calloutContext->nfmarkToClientDone = true;
- if (getConn() != NULL) {
+ if (getConn() != NULL && Comm::IsConnOpen(getConn()->clientConnection)) {
ACLFilledChecklist ch(NULL, request, NULL);
ch.src_addr = request->client_addr;
ch.my_addr = request->my_addr;
nfmark_t mark = aclMapNfmark(Ip::Qos::TheConfig.nfmarkToClient, &ch);
if (mark)
- Ip::Qos::setSockNfmark(getConn()->fd, mark);
+ Ip::Qos::setSockNfmark(getConn()->clientConnection, mark);
}
}
@@ -1542,9 +1544,9 @@
debugs(85,3, HERE << "REQMOD body production failed");
if (request_satisfaction_mode) { // too late to recover or serve an error
request->detailError(ERR_ICAP_FAILURE, ERR_DETAIL_CLT_REQMOD_RESP_BODY);
- const int fd = getConn()->fd;
- Must(fd >= 0);
- comm_close(fd); // drastic, but we may be writing a response already
+ const Comm::ConnectionPointer c = getConn()->clientConnection;
+ Must(Comm::IsConnOpen(c));
+ c->close(); // drastic, but we may be writing a response already
} else {
handleAdaptationFailure(ERR_DETAIL_CLT_REQMOD_REQ_BODY);
}
@@ -1580,7 +1582,7 @@
ConnStateData * c = getConn();
repContext->setReplyToError(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR,
request->method, NULL,
- (c != NULL ? c->peer : noAddr), request, NULL,
+ (c != NULL ? c->clientConnection->remote : noAddr), request, NULL,
(c != NULL && c->auth_user_request != NULL ?
c->auth_user_request : request->auth_user_request));
=== modified file 'src/client_side_request.h'
--- src/client_side_request.h 2011-03-12 01:16:37 +0000
+++ src/client_side_request.h 2011-03-26 04:38:34 +0000
@@ -72,7 +72,7 @@
#if USE_ADAPTATION
void *toCbdata() { return this; }
#endif
- ClientHttpRequest(ConnStateData *);
+ ClientHttpRequest(ConnStateData *csd);
~ClientHttpRequest();
/* Not implemented - present to prevent synthetic operations */
ClientHttpRequest(ClientHttpRequest const &);
@@ -95,6 +95,12 @@
_SQUID_INLINE_ ConnStateData * getConn() const;
_SQUID_INLINE_ void setConn(ConnStateData *);
+
+ /** Details of the client socket which produced us.
+ * Treat as read-only for the lifetime of this HTTP request.
+ */
+ Comm::ConnectionPointer clientConnection;
+
HttpRequest *request; /* Parsed URL ... */
char *uri;
char *log_uri;
=== modified file 'src/comm.cc'
--- src/comm.cc 2011-01-28 07:58:53 +0000
+++ src/comm.cc 2011-03-26 04:47:54 +0000
@@ -33,19 +33,20 @@
*/
#include "squid.h"
+#include "base/AsyncCall.h"
#include "StoreIOBuffer.h"
#include "comm.h"
#include "event.h"
#include "fde.h"
#include "comm/AcceptLimiter.h"
#include "comm/comm_internal.h"
+#include "comm/Connection.h"
#include "comm/IoCallback.h"
#include "comm/Loops.h"
#include "comm/Write.h"
#include "comm/TcpAcceptor.h"
#include "CommIO.h"
#include "CommRead.h"
-#include "ConnectionDetail.h"
#include "MemBuf.h"
#include "pconn.h"
#include "SquidTime.h"
@@ -75,7 +76,7 @@
static void commStopHalfClosedMonitor(int fd);
static IOCB commHalfClosedReader;
-static void comm_init_opened(int new_socket, Ip::Address &addr, tos_t tos, nfmark_t nfmark, const char *note, struct addrinfo *AI);
+static void comm_init_opened(const Comm::ConnectionPointer &conn, tos_t tos, nfmark_t nfmark, const char *note, struct addrinfo *AI);
static int comm_apply_flags(int new_socket, Ip::Address &addr, int flags, struct addrinfo *AI);
#if USE_DELAY_POOLS
@@ -84,38 +85,6 @@
static void commHandleWriteHelper(void * data);
#endif
-class ConnectStateData
-{
-
-public:
- void *operator new (size_t);
- void operator delete (void *);
- static void Connect (int fd, void *me);
- void connect();
- void callCallback(comm_err_t status, int xerrno);
- void defaults();
-
-// defaults given by client
- char *host;
- u_short default_port;
- Ip::Address default_addr;
- // NP: CANNOT store the default addr:port together as it gets set/reset differently.
-
- DnsLookupDetails dns; ///< host lookup details
- Ip::Address S;
- AsyncCall::Pointer callback;
-
- int fd;
- int tries;
- int addrcount;
- int connstart;
-
-private:
- int commResetFD();
- int commRetryConnect();
- CBDATA_CLASS(ConnectStateData);
-};
-
/* STATIC */
static DescriptorSet *TheHalfClosed = NULL; /// the set of half-closed FDs
@@ -130,13 +99,6 @@
static void commSetTcpNoDelay(int);
#endif
static void commSetTcpRcvbuf(int, int);
-static PF commConnectFree;
-static IPH commConnectDnsHandle;
-
-typedef enum {
- COMM_CB_READ = 1,
- COMM_CB_DERIVED
-} comm_callback_t;
static MemAllocator *conn_close_pool = NULL;
fd_debug_t *fdd_table = NULL;
@@ -192,35 +154,28 @@
* completes, on error, or on file descriptor close.
*/
void
-comm_read(int fd, char *buf, int size, IOCB *handler, void *handler_data)
-{
- AsyncCall::Pointer call = commCbCall(5,4, "SomeCommReadHandler",
- CommIoCbPtrFun(handler, handler_data));
- comm_read(fd, buf, size, call);
-}
-
-void
-comm_read(int fd, char *buf, int size, AsyncCall::Pointer &callback)
-{
- debugs(5, 5, "comm_read, queueing read for FD " << fd << "; asynCall " << callback);
+comm_read(const Comm::ConnectionPointer &conn, char *buf, int size, AsyncCall::Pointer &callback)
+{
+ debugs(5, 5, "comm_read, queueing read for " << conn << "; asynCall " << callback);
/* Make sure we are open and not closing */
- assert(isOpen(fd));
- assert(!fd_table[fd].closing());
- Comm::IoCallback *ccb = COMMIO_FD_READCB(fd);
+ assert(Comm::IsConnOpen(conn));
+ assert(!fd_table[conn->fd].closing());
+ Comm::IoCallback *ccb = COMMIO_FD_READCB(conn->fd);
// Make sure we are either not reading or just passively monitoring.
// Active/passive conflicts are OK and simply cancel passive monitoring.
if (ccb->active()) {
// if the assertion below fails, we have an active comm_read conflict
- assert(fd_table[fd].halfClosedReader != NULL);
- commStopHalfClosedMonitor(fd);
+ assert(fd_table[conn->fd].halfClosedReader != NULL);
+ commStopHalfClosedMonitor(conn->fd);
assert(!ccb->active());
}
+ ccb->conn = conn;
/* Queue the read */
ccb->setCallback(Comm::IOCB_READ, callback, (char *)buf, NULL, size);
- Comm::SetSelect(fd, COMM_SELECT_READ, commHandleRead, ccb, 0);
+ Comm::SetSelect(conn->fd, COMM_SELECT_READ, commHandleRead, ccb, 0);
}
/**
@@ -247,6 +202,7 @@
/**
* Return whether the FD has a pending completed callback.
+ * NP: does not work.
*/
int
comm_has_pending_read_callback(int fd)
@@ -437,16 +393,12 @@
temp.FreeAddrInfo(addr);
- F->local_addr.SetPort(temp.GetPort());
-
-#if 0 // seems to undo comm_open actions on the FD ...
- // grab default socket information for this address
- temp.GetAddrInfo(addr);
-
- F->sock_family = addr->ai_family;
-
- temp.FreeAddrInfo(addr);
-#endif
+ if (F->local_addr.IsAnyAddr()) {
+ /* save the whole local address, not just the port. */
+ F->local_addr = temp;
+ } else {
+ F->local_addr.SetPort(temp.GetPort());
+ }
debugs(5, 6, "comm_local_port: FD " << fd << ": port " << F->local_addr.GetPort() << "(family=" << F->sock_family << ")");
return F->local_addr.GetPort();
@@ -481,6 +433,19 @@
return comm_openex(sock_type, proto, addr, flags, 0, 0, note);
}
+void
+comm_open_listener(int sock_type,
+ int proto,
+ Comm::ConnectionPointer &conn,
+ const char *note)
+{
+ /* all listener sockets require bind() */
+ conn->flags |= COMM_DOBIND;
+
+ /* attempt native enabled port. */
+ conn->fd = comm_openex(sock_type, proto, conn->local, conn->flags, 0, 0, note);
+}
+
int
comm_open_listener(int sock_type,
int proto,
@@ -597,62 +562,63 @@
return -1;
}
- debugs(50, 3, "comm_openex: Opened socket FD " << new_socket << " : family=" << AI->ai_family << ", type=" << AI->ai_socktype << ", protocol=" << AI->ai_protocol );
+ // XXX: temporary for the transition. comm_openex will eventually have a conn to play with.
+ Comm::ConnectionPointer conn = new Comm::Connection;
+ conn->local = addr;
+ conn->fd = new_socket;
+
+ debugs(50, 3, "comm_openex: Opened socket " << conn << " : family=" << AI->ai_family << ", type=" << AI->ai_socktype << ", protocol=" << AI->ai_protocol );
/* set TOS if needed */
if (tos)
- Ip::Qos::setSockTos(new_socket, tos);
+ Ip::Qos::setSockTos(conn, tos);
/* set netfilter mark if needed */
if (nfmark)
- Ip::Qos::setSockNfmark(new_socket, nfmark);
+ Ip::Qos::setSockNfmark(conn, nfmark);
if ( Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && addr.IsIPv6() )
- comm_set_v6only(new_socket, 1);
+ comm_set_v6only(conn->fd, 1);
/* Windows Vista supports Dual-Sockets. BUT defaults them to V6ONLY. Turn it OFF. */
/* Other OS may have this administratively disabled for general use. Same deal. */
if ( Ip::EnableIpv6&IPV6_SPECIAL_V4MAPPING && addr.IsIPv6() )
- comm_set_v6only(new_socket, 0);
+ comm_set_v6only(conn->fd, 0);
- comm_init_opened(new_socket, addr, tos, nfmark, note, AI);
- new_socket = comm_apply_flags(new_socket, addr, flags, AI);
+ comm_init_opened(conn, tos, nfmark, note, AI);
+ new_socket = comm_apply_flags(conn->fd, addr, flags, AI);
addr.FreeAddrInfo(AI);
PROF_stop(comm_open);
+ // XXX transition only. prevent conn from closing the new FD on function exit.
+ conn->fd = -1;
return new_socket;
}
/// update FD tables after a local or remote (IPC) comm_openex();
void
-comm_init_opened(int new_socket,
- Ip::Address &addr,
+comm_init_opened(const Comm::ConnectionPointer &conn,
tos_t tos,
nfmark_t nfmark,
const char *note,
struct addrinfo *AI)
{
- assert(new_socket >= 0);
+ assert(Comm::IsConnOpen(conn));
assert(AI);
- fde *F = NULL;
-
/* update fdstat */
- debugs(5, 5, "comm_open: FD " << new_socket << " is a new socket");
-
- assert(!isOpen(new_socket));
- fd_open(new_socket, FD_SOCKET, note);
-
- fdd_table[new_socket].close_file = NULL;
-
- fdd_table[new_socket].close_line = 0;
-
- F = &fd_table[new_socket];
-
- F->local_addr = addr;
-
+ debugs(5, 5, HERE << conn << " is a new socket");
+
+ assert(!isOpen(conn->fd)); // NP: global isOpen checks the fde entry for openness not the Comm::Connection
+ fd_open(conn->fd, FD_SOCKET, note);
+
+ fdd_table[conn->fd].close_file = NULL;
+ fdd_table[conn->fd].close_line = 0;
+
+ fde *F = &fd_table[conn->fd];
+ F->local_addr = conn->local;
F->tosToServer = tos;
F->nfmarkToServer = nfmark;
@@ -724,37 +690,35 @@
}
void
-comm_import_opened(int fd,
- Ip::Address &addr,
- int flags,
+comm_import_opened(const Comm::ConnectionPointer &conn,
const char *note,
struct addrinfo *AI)
{
- debugs(5, 2, HERE << " FD " << fd << " at " << addr);
- assert(fd >= 0);
+ debugs(5, 2, HERE << conn);
+ assert(Comm::IsConnOpen(conn));
assert(AI);
- comm_init_opened(fd, addr, 0, 0, note, AI);
-
- if (!(flags & COMM_NOCLOEXEC))
- fd_table[fd].flags.close_on_exec = 1;
-
- if (addr.GetPort() > (u_short) 0) {
+ comm_init_opened(conn, 0, 0, note, AI);
+
+ if (!(conn->flags & COMM_NOCLOEXEC))
+ fd_table[conn->fd].flags.close_on_exec = 1;
+
+ if (conn->local.GetPort() > (u_short) 0) {
#ifdef _SQUID_MSWIN_
- if (sock_type != SOCK_DGRAM)
+ if (AI->ai_socktype != SOCK_DGRAM)
#endif
- fd_table[fd].flags.nolinger = 1;
+ fd_table[conn->fd].flags.nolinger = 1;
}
- if ((flags & COMM_TRANSPARENT))
- fd_table[fd].flags.transparent = 1;
+ if ((conn->flags & COMM_TRANSPARENT))
+ fd_table[conn->fd].flags.transparent = 1;
- if (flags & COMM_NONBLOCKING)
- fd_table[fd].flags.nonblocking = 1;
+ if (conn->flags & COMM_NONBLOCKING)
+ fd_table[conn->fd].flags.nonblocking = 1;
#ifdef TCP_NODELAY
if (AI->ai_socktype == SOCK_STREAM)
- fd_table[fd].flags.nodelay = 1;
+ fd_table[conn->fd].flags.nodelay = 1;
#endif
/* no fd_table[fd].flags. updates needed for these conditions:
@@ -763,354 +727,9 @@
*/
}
-
-CBDATA_CLASS_INIT(ConnectStateData);
-
-void *
-ConnectStateData::operator new (size_t size)
-{
- CBDATA_INIT_TYPE(ConnectStateData);
- return cbdataAlloc(ConnectStateData);
-}
-
-void
-ConnectStateData::operator delete (void *address)
-{
- cbdataFree(address);
-}
-
-
-
-void
-commConnectStart(int fd, const char *host, u_short port, AsyncCall::Pointer &cb)
-{
- debugs(cb->debugSection, cb->debugLevel, "commConnectStart: FD " << fd <<
- ", cb " << cb << ", " << host << ":" << port); // TODO: just print *cb
-
- ConnectStateData *cs;
- cs = new ConnectStateData;
- cs->fd = fd;
- cs->host = xstrdup(host);
- cs->default_port = port;
- cs->callback = cb;
-
- comm_add_close_handler(fd, commConnectFree, cs);
- ipcache_nbgethostbyname(host, commConnectDnsHandle, cs);
-}
-
-// TODO: Remove this and similar callback registration functions by replacing
-// (callback,data) parameters with an AsyncCall so that we do not have to use
-// a generic call name and debug level when creating an AsyncCall. This will
-// also cut the number of callback registration routines in half.
-void
-commConnectStart(int fd, const char *host, u_short port, CNCB * callback, void *data)
-{
- debugs(5, 5, "commConnectStart: FD " << fd << ", data " << data << ", " << host << ":" << port);
- AsyncCall::Pointer call = commCbCall(5,3,
- "SomeCommConnectHandler", CommConnectCbPtrFun(callback, data));
- commConnectStart(fd, host, port, call);
-}
-
-static void
-commConnectDnsHandle(const ipcache_addrs *ia, const DnsLookupDetails &details, void *data)
-{
- ConnectStateData *cs = (ConnectStateData *)data;
- cs->dns = details;
-
- if (ia == NULL) {
- debugs(5, 3, "commConnectDnsHandle: Unknown host: " << cs->host);
- cs->callCallback(COMM_ERR_DNS, 0);
- return;
- }
-
- assert(ia->cur < ia->count);
-
- cs->default_addr = ia->in_addrs[ia->cur];
-
- if (Config.onoff.balance_on_multiple_ip)
- ipcacheCycleAddr(cs->host, NULL);
-
- cs->addrcount = ia->count;
-
- cs->connstart = squid_curtime;
-
- cs->connect();
-}
-
-void
-ConnectStateData::callCallback(comm_err_t status, int xerrno)
-{
- debugs(5, 3, "commConnectCallback: FD " << fd);
-
- comm_remove_close_handler(fd, commConnectFree, this);
- commSetTimeout(fd, -1, NULL, NULL);
-
- typedef CommConnectCbParams Params;
- Params ¶ms = GetCommParams(callback);
- params.fd = fd;
- params.dns = dns;
- params.flag = status;
- params.xerrno = xerrno;
- ScheduleCallHere(callback);
- callback = NULL;
-
- commConnectFree(fd, this);
-}
-
-static void
-commConnectFree(int fd, void *data)
-{
- ConnectStateData *cs = (ConnectStateData *)data;
- debugs(5, 3, "commConnectFree: FD " << fd);
-// delete cs->callback;
- cs->callback = NULL;
- safe_free(cs->host);
- delete cs;
-}
-
-static void
-copyFDFlags(int to, fde *F)
-{
- if (F->flags.close_on_exec)
- commSetCloseOnExec(to);
-
- if (F->flags.nonblocking)
- commSetNonBlocking(to);
-
-#ifdef TCP_NODELAY
-
- if (F->flags.nodelay)
- commSetTcpNoDelay(to);
-
-#endif
-
- if (Config.tcpRcvBufsz > 0)
- commSetTcpRcvbuf(to, Config.tcpRcvBufsz);
-}
-
-/* Reset FD so that we can connect() again */
-int
-ConnectStateData::commResetFD()
-{
-
-// XXX: do we have to check this?
-//
-// if (!cbdataReferenceValid(callback.data))
-// return 0;
-
- statCounter.syscalls.sock.sockets++;
-
- fde *F = &fd_table[fd];
-
- struct addrinfo *AI = NULL;
- F->local_addr.GetAddrInfo(AI);
- int new_family = AI->ai_family;
-
- int fd2 = socket(new_family, AI->ai_socktype, AI->ai_protocol);
-
- if (fd2 < 0) {
- debugs(5, DBG_CRITICAL, HERE << "WARNING: FD " << fd2 << " socket failed to allocate: " << xstrerror());
-
- if (ENFILE == errno || EMFILE == errno)
- fdAdjustReserved();
-
- F->local_addr.FreeAddrInfo(AI);
- return 0;
- }
-
-#ifdef _SQUID_MSWIN_
-
- /* On Windows dup2() can't work correctly on Sockets, the */
- /* workaround is to close the destination Socket before call them. */
- close(fd);
-
-#endif
-
- if (dup2(fd2, fd) < 0) {
- debugs(5, DBG_CRITICAL, HERE << "WARNING: dup2(FD " << fd2 << ", FD " << fd << ") failed: " << xstrerror());
-
- if (ENFILE == errno || EMFILE == errno)
- fdAdjustReserved();
-
- close(fd2);
-
- F->local_addr.FreeAddrInfo(AI);
- return 0;
- }
- Comm::ResetSelect(fd);
-
- close(fd2);
-
- debugs(50, 3, "commResetFD: Reset socket FD " << fd << "->" << fd2 << " : family=" << new_family );
-
- /* INET6: copy the new sockets family type to the FDE table */
- F->sock_family = new_family;
-
- F->flags.called_connect = 0;
-
- /*
- * yuck, this has assumptions about comm_open() arguments for
- * the original socket
- */
-
- /* MUST be done before binding or face OS Error: "(99) Cannot assign requested address"... */
- if ( F->flags.transparent ) {
- comm_set_transparent(fd);
- }
-
- if (commBind(fd, *AI) != COMM_OK) {
- debugs(5, DBG_CRITICAL, "WARNING: Reset of FD " << fd << " for " << F->local_addr << " failed to bind: " << xstrerror());
- F->local_addr.FreeAddrInfo(AI);
- return 0;
- }
- F->local_addr.FreeAddrInfo(AI);
-
- if (F->tosToServer)
- Ip::Qos::setSockTos(fd, F->tosToServer);
-
- if (F->nfmarkToServer)
- Ip::Qos::setSockNfmark(fd, F->nfmarkToServer);
-
- if ( Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && F->local_addr.IsIPv6() )
- comm_set_v6only(fd, 1);
-
- copyFDFlags(fd, F);
-
- return 1;
-}
-
-int
-ConnectStateData::commRetryConnect()
-{
- assert(addrcount > 0);
-
- if (addrcount == 1) {
- if (tries >= Config.retry.maxtries)
- return 0;
-
- if (squid_curtime - connstart > Config.Timeout.connect)
- return 0;
- } else {
- if (tries > addrcount) {
- /* Flush bad address count in case we are
- * skipping over incompatible protocol
- */
- ipcacheMarkAllGood(host);
- return 0;
- }
- }
-
- return commResetFD();
-}
-
-static void
-commReconnect(void *data)
-{
- ConnectStateData *cs = (ConnectStateData *)data;
- ipcache_nbgethostbyname(cs->host, commConnectDnsHandle, cs);
-}
-
-/** Connect SOCK to specified DEST_PORT at DEST_HOST. */
-void
-ConnectStateData::Connect(int fd, void *me)
-{
- ConnectStateData *cs = (ConnectStateData *)me;
- assert (cs->fd == fd);
- cs->connect();
-}
-
-void
-ConnectStateData::defaults()
-{
- S = default_addr;
- S.SetPort(default_port);
-}
-
-void
-ConnectStateData::connect()
-{
- defaults();
-
- debugs(5,5, HERE << "to " << S);
-
- switch (comm_connect_addr(fd, S) ) {
-
- case COMM_INPROGRESS:
- debugs(5, 5, HERE << "FD " << fd << ": COMM_INPROGRESS");
- Comm::SetSelect(fd, COMM_SELECT_WRITE, ConnectStateData::Connect, this, 0);
- break;
-
- case COMM_OK:
- debugs(5, 5, HERE << "FD " << fd << ": COMM_OK - connected");
- ipcacheMarkGoodAddr(host, S);
- callCallback(COMM_OK, 0);
- break;
-
- case COMM_ERR_PROTOCOL:
- debugs(5, 5, HERE "FD " << fd << ": COMM_ERR_PROTOCOL - try again");
- /* problem using the desired protocol over this socket.
- * skip to the next address and hope it's more compatible
- * but do not mark the current address as bad
- */
- tries++;
- if (commRetryConnect()) {
- /* Force an addr cycle to move forward to the next possible address */
- ipcacheCycleAddr(host, NULL);
- eventAdd("commReconnect", commReconnect, this, this->addrcount == 1 ? 0.05 : 0.0, 0);
- } else {
- debugs(5, 5, HERE << "FD " << fd << ": COMM_ERR_PROTOCOL - ERR tried too many times already.");
- callCallback(COMM_ERR_CONNECT, errno);
- }
- break;
-
- default:
- debugs(5, 5, HERE "FD " << fd << ": * - try again");
- tries++;
- ipcacheMarkBadAddr(host, S);
-
-#if USE_ICMP
- if (Config.onoff.test_reachability)
- netdbDeleteAddrNetwork(S);
-#endif
-
- if (commRetryConnect()) {
- eventAdd("commReconnect", commReconnect, this, this->addrcount == 1 ? 0.05 : 0.0, 0);
- } else {
- debugs(5, 5, HERE << "FD " << fd << ": * - ERR tried too many times already.");
- callCallback(COMM_ERR_CONNECT, errno);
- }
- }
-}
-/*
-int
-commSetTimeout_old(int fd, int timeout, PF * handler, void *data)
-{
- debugs(5, 3, HERE << "FD " << fd << " timeout " << timeout);
- assert(fd >= 0);
- assert(fd < Squid_MaxFD);
- fde *F = &fd_table[fd];
- assert(F->flags.open);
-
- if (timeout < 0) {
- cbdataReferenceDone(F->timeout_data);
- F->timeout_handler = NULL;
- F->timeout = 0;
- } else {
- if (handler) {
- cbdataReferenceDone(F->timeout_data);
- F->timeout_handler = handler;
- F->timeout_data = cbdataReference(data);
- }
-
- F->timeout = squid_curtime + (time_t) timeout;
- }
-
- return F->timeout;
-}
-*/
-
-int
-commSetTimeout(int fd, int timeout, PF * handler, void *data)
+// Legacy pre-AsyncCalls API for FD timeouts.
+int
+commSetTimeout(int fd, int timeout, CTCB * handler, void *data)
{
AsyncCall::Pointer call;
debugs(5, 3, HERE << "FD " << fd << " timeout " << timeout);
@@ -1121,8 +740,10 @@
return commSetTimeout(fd, timeout, call);
}
-
-int commSetTimeout(int fd, int timeout, AsyncCall::Pointer &callback)
+// Legacy pre-Comm::Connection API for FD timeouts
+// still used by non-socket FD code dealing with pipes and IPC sockets.
+int
+commSetTimeout(int fd, int timeout, AsyncCall::Pointer &callback)
{
debugs(5, 3, HERE << "FD " << fd << " timeout " << timeout);
assert(fd >= 0);
@@ -1145,7 +766,40 @@
}
return F->timeout;
-
+}
+
+int
+commSetConnTimeout(const Comm::ConnectionPointer &conn, int timeout, AsyncCall::Pointer &callback)
+{
+ debugs(5, 3, HERE << conn << " timeout " << timeout);
+ assert(Comm::IsConnOpen(conn));
+ assert(conn->fd < Squid_MaxFD);
+ fde *F = &fd_table[conn->fd];
+ assert(F->flags.open);
+
+ if (timeout < 0) {
+ F->timeoutHandler = NULL;
+ F->timeout = 0;
+ } else {
+ if (callback != NULL) {
+ typedef CommTimeoutCbParams Params;
+ Params ¶ms = GetCommParams(callback);
+ params.conn = conn;
+ F->timeoutHandler = callback;
+ }
+
+ F->timeout = squid_curtime + (time_t) timeout;
+ }
+
+ return F->timeout;
+}
+
+int
+commUnsetConnTimeout(const Comm::ConnectionPointer &conn)
+{
+ debugs(5, 3, HERE << "Remove timeout for " << conn);
+ AsyncCall::Pointer nil;
+ return commSetConnTimeout(conn, -1, nil);
}
int
@@ -1367,9 +1021,22 @@
* closed, TCP generates a RESET
*/
void
-comm_reset_close(int fd)
-{
-
+comm_reset_close(Comm::ConnectionPointer &conn)
+{
+ struct linger L;
+ L.l_onoff = 1;
+ L.l_linger = 0;
+
+ if (setsockopt(conn->fd, SOL_SOCKET, SO_LINGER, (char *) &L, sizeof(L)) < 0)
+ debugs(50, DBG_CRITICAL, "ERROR: Closing " << conn << " with TCP RST: " << xstrerror());
+
+ conn->close();
+}
+
+// Legacy close function.
+void
+old_comm_reset_close(int fd)
+{
struct linger L;
L.l_onoff = 1;
L.l_linger = 0;
@@ -2108,7 +1775,7 @@
ScheduleCallHere(callback);
} else {
debugs(5, 5, "commCloseAllSockets: FD " << fd << ": calling comm_reset_close()");
- comm_reset_close(fd);
+ old_comm_reset_close(fd);
}
}
}
@@ -2260,13 +1927,15 @@
typedef DescriptorSet::const_iterator DSCI;
const DSCI end = TheHalfClosed->end();
for (DSCI i = TheHalfClosed->begin(); i != end; ++i) {
- const int fd = *i;
- if (!fd_table[fd].halfClosedReader) { // not reading already
+ Comm::ConnectionPointer c = new Comm::Connection; // XXX: temporary. make HalfClosed a list of these.
+ c->fd = *i;
+ if (!fd_table[c->fd].halfClosedReader) { // not reading already
AsyncCall::Pointer call = commCbCall(5,4, "commHalfClosedReader",
CommIoCbPtrFun(&commHalfClosedReader, NULL));
- comm_read(fd, NULL, 0, call);
- fd_table[fd].halfClosedReader = call;
- }
+ comm_read(c, NULL, 0, call);
+ fd_table[c->fd].halfClosedReader = call;
+ } else
+ c->fd = -1; // XXX: temporary. prevent c replacement erase closing listed FD
}
WillCheckHalfClosed = false; // as far as we know
@@ -2298,13 +1967,14 @@
/// I/O handler for the possibly half-closed connection monitoring code
static void
-commHalfClosedReader(int fd, char *, size_t size, comm_err_t flag, int, void *)
+commHalfClosedReader(const Comm::ConnectionPointer &conn, char *, size_t size, comm_err_t flag, int, void *)
{
// there cannot be more data coming in on half-closed connections
assert(size == 0);
- assert(commHasHalfClosedMonitor(fd)); // or we would have canceled the read
+ assert(conn != NULL);
+ assert(commHasHalfClosedMonitor(conn->fd)); // or we would have canceled the read
- fd_table[fd].halfClosedReader = NULL; // done reading, for now
+ fd_table[conn->fd].halfClosedReader = NULL; // done reading, for now
// nothing to do if fd is being closed
if (flag == COMM_ERR_CLOSING)
@@ -2312,8 +1982,8 @@
// if read failed, close the connection
if (flag != COMM_OK) {
- debugs(5, 3, "commHalfClosedReader: closing FD " << fd);
- comm_close(fd);
+ debugs(5, 3, HERE << "closing " << conn);
+ conn->close();
return;
}
@@ -2322,10 +1992,10 @@
}
-CommRead::CommRead() : fd(-1), buf(NULL), len(0), callback(NULL) {}
+CommRead::CommRead() : conn(NULL), buf(NULL), len(0), callback(NULL) {}
-CommRead::CommRead(int fd_, char *buf_, int len_, AsyncCall::Pointer &callback_)
- : fd(fd_), buf(buf_), len(len_), callback(callback_) {}
+CommRead::CommRead(const Comm::ConnectionPointer &c, char *buf_, int len_, AsyncCall::Pointer &callback_)
+ : conn(c), buf(buf_), len(len_), callback(callback_) {}
DeferredRead::DeferredRead () : theReader(NULL), theContext(NULL), theRead(), cancelled(false) {}
@@ -2346,7 +2016,7 @@
void
DeferredReadManager::delayRead(DeferredRead const &aRead)
{
- debugs(5, 3, "Adding deferred read on FD " << aRead.theRead.fd);
+ debugs(5, 3, "Adding deferred read on " << aRead.theRead.conn);
CbDataList *temp = deferredReads.push_back(aRead);
// We have to use a global function as a closer and point to temp
@@ -2355,7 +2025,7 @@
AsyncCall::Pointer closer = commCbCall(5,4,
"DeferredReadManager::CloseHandler",
CommCloseCbPtrFun(&CloseHandler, temp));
- comm_add_close_handler(aRead.theRead.fd, closer);
+ comm_add_close_handler(aRead.theRead.conn->fd, closer);
temp->element.closer = closer; // remeber so that we can cancel
}
@@ -2378,7 +2048,7 @@
DeferredRead &read = deferredReads.head->element;
if (!read.cancelled) {
- comm_remove_close_handler(read.theRead.fd, read.closer);
+ comm_remove_close_handler(read.theRead.conn->fd, read.closer);
read.closer = NULL;
}
@@ -2428,10 +2098,10 @@
if (aRead.cancelled)
return;
- if (aRead.theRead.fd>=0 && fd_table[aRead.theRead.fd].closing())
+ if (Comm::IsConnOpen(aRead.theRead.conn) && fd_table[aRead.theRead.conn->fd].closing())
return;
- debugs(5, 3, "Kicking deferred read on FD " << aRead.theRead.fd);
+ debugs(5, 3, "Kicking deferred read on " << aRead.theRead.conn);
aRead.theReader(aRead.theContext, aRead.theRead);
}
@@ -2442,10 +2112,6 @@
cancelled = true;
}
-ConnectionDetail::ConnectionDetail() : me(), peer()
-{
-}
-
int
CommSelectEngine::checkEvents(int timeout)
{
=== modified file 'src/comm.h'
--- src/comm.h 2011-01-10 09:43:43 +0000
+++ src/comm.h 2011-01-26 11:27:41 +0000
@@ -4,17 +4,10 @@
#include "squid.h"
#include "AsyncEngine.h"
#include "base/AsyncCall.h"
+#include "CommCalls.h"
#include "comm_err_t.h"
#include "comm/IoCallback.h"
#include "StoreIOBuffer.h"
-#include "Array.h"
-#include "ip/Address.h"
-
-class DnsLookupDetails;
-typedef void CNCB(int fd, const DnsLookupDetails &dns, comm_err_t status, int xerrno, void *data);
-
-typedef void IOCB(int fd, char *, size_t size, comm_err_t flag, int xerrno, void *data);
-
/* comm.c */
extern bool comm_iocallbackpending(void); /* inline candidate */
@@ -24,13 +17,12 @@
SQUIDCEXTERN void commSetCloseOnExec(int fd);
SQUIDCEXTERN void commSetTcpKeepalive(int fd, int idle, int interval, int timeout);
extern void _comm_close(int fd, char const *file, int line);
-#define comm_close(fd) (_comm_close((fd), __FILE__, __LINE__))
-SQUIDCEXTERN void comm_reset_close(int fd);
+#define comm_close(x) (_comm_close((x), __FILE__, __LINE__))
+SQUIDCEXTERN void old_comm_reset_close(int fd);
+SQUIDCEXTERN void comm_reset_close(Comm::ConnectionPointer &conn);
#if LINGERING_CLOSE
SQUIDCEXTERN void comm_lingering_close(int fd);
#endif
-SQUIDCEXTERN void commConnectStart(int fd, const char *, u_short, CNCB *, void *);
-void commConnectStart(int fd, const char *, u_short, AsyncCall::Pointer &cb);
SQUIDCEXTERN int comm_connect_addr(int sock, const Ip::Address &addr);
SQUIDCEXTERN void comm_init(void);
@@ -39,7 +31,7 @@
SQUIDCEXTERN int comm_open(int, int, Ip::Address &, int, const char *note);
SQUIDCEXTERN int comm_open_uds(int sock_type, int proto, struct sockaddr_un* addr, int flags);
/// update Comm state after getting a comm_open() FD from another process
-SQUIDCEXTERN void comm_import_opened(int fd, Ip::Address &addr, int flags, const char *note, struct addrinfo *AI);
+SQUIDCEXTERN void comm_import_opened(const Comm::ConnectionPointer &, const char *note, struct addrinfo *AI);
/**
* Open a port specially bound for listening or sending through a specific port.
@@ -56,22 +48,30 @@
* (in debugs or cachemgr) will occur in Native IPv4 format.
* A reconfigure is needed to reset the stored IP in most cases and attempt a port re-open.
*/
-SQUIDCEXTERN int comm_open_listener(int sock_type, int proto, Ip::Address &addr, int flags, const char *note);
+extern int comm_open_listener(int sock_type, int proto, Ip::Address &addr, int flags, const char *note);
+extern void comm_open_listener(int sock_type, int proto, Comm::ConnectionPointer &conn, const char *note);
SQUIDCEXTERN int comm_openex(int, int, Ip::Address &, int, tos_t tos, nfmark_t nfmark, const char *);
SQUIDCEXTERN u_short comm_local_port(int fd);
SQUIDCEXTERN int comm_udp_sendto(int sock, const Ip::Address &to, const void *buf, int buflen);
SQUIDCEXTERN void commCallCloseHandlers(int fd);
-SQUIDCEXTERN int commSetTimeout(int fd, int, PF *, void *);
-extern int commSetTimeout(int fd, int, AsyncCall::Pointer &calback);
+SQUIDCEXTERN int commSetTimeout(int fd, int, CTCB *, void *);
+extern int commSetTimeout(int fd, int, AsyncCall::Pointer &callback);
+
+/**
+ * Set or clear the timeout for some action on an active connection.
+ * API to replace commSetTimeout() when a Comm::ConnectionPointer is available.
+ */
+extern int commSetConnTimeout(const Comm::ConnectionPointer &conn, int seconds, AsyncCall::Pointer &callback);
+extern int commUnsetConnTimeout(const Comm::ConnectionPointer &conn);
+
SQUIDCEXTERN int ignoreErrno(int);
SQUIDCEXTERN void commCloseAllSockets(void);
SQUIDCEXTERN void checkTimeouts(void);
-class ConnectionDetail;
-typedef void IOACB(int fd, int nfd, ConnectionDetail *details, comm_err_t flag, int xerrno, void *data);
+//typedef void IOACB(int fd, int nfd, Comm::ConnectionPointer details, comm_err_t flag, int xerrno, void *data);
extern void comm_add_close_handler(int fd, PF *, void *);
extern void comm_add_close_handler(int fd, AsyncCall::Pointer &);
extern void comm_remove_close_handler(int fd, PF *, void *);
@@ -80,8 +80,8 @@
extern int comm_has_pending_read_callback(int fd);
extern bool comm_monitors_read(int fd);
-extern void comm_read(int fd, char *buf, int len, IOCB *handler, void *data);
-extern void comm_read(int fd, char *buf, int len, AsyncCall::Pointer &callback);
+//extern void comm_read(const Comm::ConnectionPointer &conn, char *buf, int len, IOCB *handler, void *data);
+extern void comm_read(const Comm::ConnectionPointer &conn, char *buf, int len, AsyncCall::Pointer &callback);
extern void comm_read_cancel(int fd, IOCB *callback, void *data);
extern void comm_read_cancel(int fd, AsyncCall::Pointer &callback);
extern int comm_udp_recvfrom(int fd, void *buf, size_t len, int flags, Ip::Address &from);
=== modified file 'src/comm/AcceptLimiter.cc'
--- src/comm/AcceptLimiter.cc 2011-01-26 03:47:13 +0000
+++ src/comm/AcceptLimiter.cc 2011-01-26 11:29:16 +0000
@@ -1,5 +1,6 @@
#include "config.h"
#include "comm/AcceptLimiter.h"
+#include "comm/Connection.h"
#include "comm/TcpAcceptor.h"
#include "fde.h"
@@ -14,7 +15,7 @@
Comm::AcceptLimiter::defer(Comm::TcpAcceptor *afd)
{
afd->isLimited++;
- debugs(5, 5, HERE << "FD " << afd->fd << " x" << afd->isLimited);
+ debugs(5, 5, HERE << afd->conn << " x" << afd->isLimited);
deferred.push_back(afd);
}
@@ -25,7 +26,7 @@
if (deferred[i] == afd) {
deferred[i]->isLimited--;
deferred[i] = NULL; // fast. kick() will skip empty entries later.
- debugs(5, 5, HERE << "FD " << afd->fd << " x" << afd->isLimited);
+ debugs(5, 5, HERE << afd->conn << " x" << afd->isLimited);
}
}
}
=== modified file 'src/comm/AcceptLimiter.h'
--- src/comm/AcceptLimiter.h 2011-01-26 03:47:13 +0000
+++ src/comm/AcceptLimiter.h 2011-03-26 04:50:36 +0000
@@ -14,7 +14,8 @@
* But when doing so there were not enough FD available to handle the
* new connection. These handlers are awaiting some FD to become free.
*
- * defer - used only by Comm layer ListenStateData adding themselves when FD are limited.
+ * defer - used only by Comm layer ConnAcceptor adding themselves when FD are limited.
+ * removeDead - used only by Comm layer ConnAcceptor to remove themselves when dying.
* kick - used by Comm layer when FD are closed.
*/
class AcceptLimiter
=== added file 'src/comm/ConnOpener.cc'
--- src/comm/ConnOpener.cc 1970-01-01 00:00:00 +0000
+++ src/comm/ConnOpener.cc 2011-03-26 04:50:54 +0000
@@ -0,0 +1,326 @@
+/*
+ * DEBUG: section 05 Socket Connection Opener
+ */
+
+#include "config.h"
+#include "comm/ConnOpener.h"
+#include "comm/Connection.h"
+#include "comm/Loops.h"
+#include "comm.h"
+#include "fde.h"
+#include "icmp/net_db.h"
+#include "SquidTime.h"
+
+namespace Comm {
+ CBDATA_CLASS_INIT(ConnOpener);
+};
+
+Comm::ConnOpener::ConnOpener(Comm::ConnectionPointer &c, AsyncCall::Pointer &handler, time_t ctimeout) :
+ AsyncJob("Comm::ConnOpener"),
+ host_(NULL),
+ conn_(c),
+ callback_(handler),
+ totalTries_(0),
+ failRetries_(0),
+ connectTimeout_(ctimeout),
+ connectStart_(0)
+{}
+
+Comm::ConnOpener::~ConnOpener()
+{
+ safe_free(host_);
+}
+
+bool
+Comm::ConnOpener::doneAll() const
+{
+ // is the conn_ to be opened still waiting?
+ if (conn_ == NULL) {
+ return AsyncJob::doneAll();
+ }
+
+ // is the callback still to be called?
+ if (callback_ == NULL || callback_->canceled()) {
+ return AsyncJob::doneAll();
+ }
+
+ return false;
+}
+
+void
+Comm::ConnOpener::swanSong()
+{
+ // cancel any event watchers
+ // done here to get the "swanSong" mention in cancel debugging.
+ if (calls_.earlyAbort_ != NULL) {
+ calls_.earlyAbort_->cancel("Comm::ConnOpener::swanSong");
+ calls_.earlyAbort_ = NULL;
+ }
+ if (calls_.timeout_ != NULL) {
+ calls_.timeout_->cancel("Comm::ConnOpener::swanSong");
+ calls_.timeout_ = NULL;
+ }
+
+ // rollback what we can from the job state
+ if (conn_ != NULL && conn_->isOpen()) {
+ // drop any handlers now to save a lot of cycles later
+ Comm::SetSelect(conn_->fd, COMM_SELECT_WRITE, NULL, NULL, 0);
+ commUnsetConnTimeout(conn_);
+ // it never reached fully open, so abort the FD
+ conn_->close();
+ }
+
+ if (callback_ != NULL) {
+ if (callback_->canceled())
+ callback_ = NULL;
+ else
+ // inform the still-waiting caller we are dying
+ doneConnecting(COMM_ERR_CONNECT, 0);
+ }
+
+ AsyncJob::swanSong();
+}
+
+void
+Comm::ConnOpener::setHost(const char * new_host)
+{
+ // unset and erase if already set.
+ if (host_ != NULL)
+ safe_free(host_);
+
+ // set the new one if given.
+ if (new_host != NULL)
+ host_ = xstrdup(new_host);
+}
+
+const char *
+Comm::ConnOpener::getHost() const
+{
+ return host_;
+}
+
+/**
+ * Connection attempt are completed. One way or the other.
+ * Pass the results back to the external handler.
+ * NP: on connection errors the connection close() must be called first.
+ */
+void
+Comm::ConnOpener::doneConnecting(comm_err_t status, int xerrno)
+{
+ // only mark the address good/bad AFTER connect is finished.
+ if (host_ != NULL) {
+ if (xerrno == 0)
+ ipcacheMarkGoodAddr(host_, conn_->remote);
+ else {
+ ipcacheMarkBadAddr(host_, conn_->remote);
+#if USE_ICMP
+ if (Config.onoff.test_reachability)
+ netdbDeleteAddrNetwork(conn_->remote);
+#endif
+ }
+ }
+
+ if (callback_ != NULL) {
+ typedef CommConnectCbParams Params;
+ Params ¶ms = GetCommParams(callback_);
+ params.conn = conn_;
+ params.flag = status;
+ params.xerrno = xerrno;
+ ScheduleCallHere(callback_);
+ callback_ = NULL;
+ }
+
+ /* ensure cleared local state, we are done. */
+ conn_ = NULL;
+}
+
+void
+Comm::ConnOpener::start()
+{
+ Must(conn_ != NULL);
+
+ /* get a socket open ready for connecting with */
+ if (!conn_->isOpen()) {
+#if USE_IPV6
+ /* outbound sockets have no need to be protocol agnostic. */
+ if (conn_->remote.IsIPv4()) {
+ conn_->local.SetIPv4();
+ }
+#endif
+ conn_->fd = comm_openex(SOCK_STREAM, IPPROTO_TCP, conn_->local, conn_->flags, conn_->tos, conn_->nfmark, host_);
+ if (!conn_->isOpen()) {
+ doneConnecting(COMM_ERR_CONNECT, 0);
+ return;
+ }
+ }
+
+ typedef CommCbMemFunT abortDialer;
+ calls_.earlyAbort_ = JobCallback(5, 4, abortDialer, this, Comm::ConnOpener::earlyAbort);
+ comm_add_close_handler(conn_->fd, calls_.earlyAbort_);
+
+ typedef CommCbMemFunT timeoutDialer;
+ calls_.timeout_ = JobCallback(5, 4, timeoutDialer, this, Comm::ConnOpener::timeout);
+ debugs(5, 3, HERE << conn_ << " timeout " << connectTimeout_);
+ commSetConnTimeout(conn_, connectTimeout_, calls_.timeout_);
+
+ connectStart_ = squid_curtime;
+ connect();
+}
+
+void
+Comm::ConnOpener::connected()
+{
+ /*
+ * stats.conn_open is used to account for the number of
+ * connections that we have open to the peer, so we can limit
+ * based on the max-conn option. We need to increment here,
+ * even if the connection may fail.
+ */
+ if (conn_->getPeer())
+ conn_->getPeer()->stats.conn_open++;
+
+ lookupLocalAddress();
+
+ /* TODO: remove these fd_table accesses. But old code still depends on fd_table flags to
+ * indicate the state of a raw fd object being passed around.
+ * Also, legacy code still depends on comm_local_port() with no access to Comm::Connection
+ * when those are done comm_local_port can become one of our member functions to do the below.
+ */
+ fd_table[conn_->fd].flags.open = 1;
+ fd_table[conn_->fd].local_addr = conn_->local;
+}
+
+/** Make an FD connection attempt.
+ * Handles the case(s) when a partially setup connection gets closed early.
+ */
+void
+Comm::ConnOpener::connect()
+{
+ Must(conn_ != NULL);
+
+ // our parent Jobs signal abort by cancelling their callbacks.
+ if (callback_ == NULL || callback_->canceled())
+ return;
+
+ totalTries_++;
+
+ switch (comm_connect_addr(conn_->fd, conn_->remote) ) {
+
+ case COMM_INPROGRESS:
+ // check for timeout FIRST.
+ if (squid_curtime - connectStart_ > connectTimeout_) {
+ debugs(5, 5, HERE << conn_ << ": * - ERR took too long already.");
+ calls_.earlyAbort_->cancel("Comm::ConnOpener::connect timed out");
+ calls_.earlyAbort_ = NULL;
+ conn_->close();
+ doneConnecting(COMM_TIMEOUT, errno);
+ return;
+ } else {
+ debugs(5, 5, HERE << conn_ << ": COMM_INPROGRESS");
+ Comm::SetSelect(conn_->fd, COMM_SELECT_WRITE, Comm::ConnOpener::InProgressConnectRetry, this, 0);
+ }
+ break;
+
+ case COMM_OK:
+ debugs(5, 5, HERE << conn_ << ": COMM_OK - connected");
+ connected();
+ doneConnecting(COMM_OK, 0);
+ break;
+
+ default:
+ failRetries_++;
+
+ // check for timeout FIRST.
+ if(squid_curtime - connectStart_ > connectTimeout_) {
+ debugs(5, 5, HERE << conn_ << ": * - ERR took too long to receive response.");
+ calls_.earlyAbort_->cancel("Comm::ConnOpener::connect timed out");
+ calls_.earlyAbort_ = NULL;
+ conn_->close();
+ doneConnecting(COMM_TIMEOUT, errno);
+ } else if (failRetries_ < Config.connect_retries) {
+ debugs(5, 5, HERE << conn_ << ": * - try again");
+ eventAdd("Comm::ConnOpener::DelayedConnectRetry", Comm::ConnOpener::DelayedConnectRetry, this, 0.05, 0);
+ return;
+ } else {
+ // send ERROR back to the upper layer.
+ debugs(5, 5, HERE << conn_ << ": * - ERR tried too many times already.");
+ calls_.earlyAbort_->cancel("Comm::ConnOpener::connect failed");
+ calls_.earlyAbort_ = NULL;
+ conn_->close();
+ doneConnecting(COMM_ERR_CONNECT, errno);
+ }
+ }
+}
+
+/**
+ * Lookup local-end address and port of the TCP link just opened.
+ * This ensure the connection local details are set correctly
+ */
+void
+Comm::ConnOpener::lookupLocalAddress()
+{
+ struct addrinfo *addr = NULL;
+ conn_->local.InitAddrInfo(addr);
+
+ if (getsockname(conn_->fd, addr->ai_addr, &(addr->ai_addrlen)) != 0) {
+ debugs(50, DBG_IMPORTANT, "ERROR: Failed to retrieve TCP/UDP details for socket: " << conn_ << ": " << xstrerror());
+ conn_->local.FreeAddrInfo(addr);
+ return;
+ }
+
+ conn_->local = *addr;
+ conn_->local.FreeAddrInfo(addr);
+ debugs(5, 6, HERE << conn_);
+}
+
+/** Abort connection attempt.
+ * Handles the case(s) when a partially setup connection gets closed early.
+ */
+void
+Comm::ConnOpener::earlyAbort(const CommConnectCbParams &io)
+{
+ debugs(5, 3, HERE << io.conn);
+ doneConnecting(COMM_ERR_CLOSING, io.xerrno); // NP: is closing or shutdown better?
+}
+
+/**
+ * Handles the case(s) when a partially setup connection gets timed out.
+ * NP: When commSetConnTimeout accepts generic CommCommonCbParams this can die.
+ */
+void
+Comm::ConnOpener::timeout(const CommTimeoutCbParams &)
+{
+ connect();
+}
+
+/* Legacy Wrapper for the retry event after COMM_INPROGRESS
+ * XXX: As soon as Comm::SetSelect() accepts Async calls we can use a ConnOpener::connect call
+ */
+void
+Comm::ConnOpener::InProgressConnectRetry(int fd, void *data)
+{
+ ConnOpener *cs = static_cast(data);
+ assert(cs);
+
+ // Ew. we are now outside the all AsyncJob protections.
+ // get back inside by scheduling another call...
+ typedef NullaryMemFunT Dialer;
+ AsyncCall::Pointer call = JobCallback(5, 4, Dialer, cs, Comm::ConnOpener::connect);
+ ScheduleCallHere(call);
+}
+
+/* Legacy Wrapper for the retry event with small delay after errors.
+ * XXX: As soon as eventAdd() accepts Async calls we can use a ConnOpener::connect call
+ */
+void
+Comm::ConnOpener::DelayedConnectRetry(void *data)
+{
+ ConnOpener *cs = static_cast(data);
+ assert(cs);
+
+ // Ew. we are now outside the all AsyncJob protections.
+ // get back inside by scheduling another call...
+ typedef NullaryMemFunT Dialer;
+ AsyncCall::Pointer call = JobCallback(5, 4, Dialer, cs, Comm::ConnOpener::connect);
+ ScheduleCallHere(call);
+}
=== added file 'src/comm/ConnOpener.h'
--- src/comm/ConnOpener.h 1970-01-01 00:00:00 +0000
+++ src/comm/ConnOpener.h 2011-02-17 11:32:55 +0000
@@ -0,0 +1,73 @@
+#ifndef _SQUID_SRC_COMM_OPENERSTATEDATA_H
+#define _SQUID_SRC_COMM_OPENERSTATEDATA_H
+
+#include "base/AsyncCall.h"
+#include "base/AsyncJob.h"
+#include "cbdata.h"
+#include "CommCalls.h"
+#include "comm_err_t.h"
+#include "comm/forward.h"
+
+namespace Comm {
+
+/**
+ * Async-opener of a Comm connection.
+ */
+class ConnOpener : public AsyncJob
+{
+protected:
+ virtual void start();
+ virtual void swanSong();
+
+public:
+ virtual bool doneAll() const;
+
+ ConnOpener(Comm::ConnectionPointer &, AsyncCall::Pointer &handler, time_t connect_timeout);
+ ~ConnOpener();
+
+ void setHost(const char *); ///< set the hostname note for this connection
+ const char * getHost() const; ///< get the hostname noted for this connection
+
+private:
+ // Undefined because two openers cannot share a connection
+ ConnOpener(const ConnOpener &);
+ ConnOpener & operator =(const ConnOpener &c);
+
+ void earlyAbort(const CommConnectCbParams &);
+ void timeout(const CommTimeoutCbParams &);
+ void doneConnecting(comm_err_t status, int xerrno);
+ static void InProgressConnectRetry(int fd, void *data);
+ static void DelayedConnectRetry(void *data);
+ void connect();
+ void connected();
+ void lookupLocalAddress();
+
+private:
+ char *host_; ///< domain name we are trying to connect to.
+ Comm::ConnectionPointer conn_; ///< single connection currently being opened.
+ AsyncCall::Pointer callback_; ///< handler to be called on connection completion.
+
+ int totalTries_; ///< total number of connection attempts over all destinations so far.
+ int failRetries_; ///< number of retries current destination has been tried.
+
+ /**
+ * time at which to abandon the connection.
+ * the connection-done callback will be passed COMM_TIMEOUT
+ */
+ time_t connectTimeout_;
+
+ /// time at which this series of connection attempts was started.
+ time_t connectStart_;
+
+ /// handles to calls which we may need to cancel.
+ struct Calls {
+ AsyncCall::Pointer earlyAbort_;
+ AsyncCall::Pointer timeout_;
+ } calls_;
+
+ CBDATA_CLASS2(ConnOpener);
+};
+
+}; // namespace Comm
+
+#endif /* _SQUID_SRC_COMM_CONNOPENER_H */
=== added file 'src/comm/Connection.cc'
--- src/comm/Connection.cc 1970-01-01 00:00:00 +0000
+++ src/comm/Connection.cc 2011-02-02 04:50:36 +0000
@@ -0,0 +1,91 @@
+#include "config.h"
+#include "cbdata.h"
+#include "comm.h"
+#include "comm/Connection.h"
+#include "fde.h"
+#include "SquidTime.h"
+
+bool
+Comm::IsConnOpen(const Comm::ConnectionPointer &conn)
+{
+ return conn != NULL && conn->isOpen();
+}
+
+Comm::Connection::Connection() :
+ local(),
+ remote(),
+ peerType(HIER_NONE),
+ fd(-1),
+ tos(0),
+ flags(COMM_NONBLOCKING),
+ _peer(NULL)
+{
+ *rfc931 = 0; // quick init the head. the rest does not matter.
+}
+
+static int64_t lost_conn = 0;
+Comm::Connection::~Connection()
+{
+ assert(fd < 0); // These should never occur now.
+
+ if (fd >= 0) {
+ debugs(5, 0, "NOTE: Orphan Comm::Connection: " << *this);
+ debugs(5, 0, "NOTE: Orphaned Comm::Connections: " << ++lost_conn);
+ close();
+ }
+
+ cbdataReferenceDone(_peer);
+}
+
+Comm::ConnectionPointer
+Comm::Connection::copyDetails() const
+{
+ ConnectionPointer c = new Comm::Connection;
+
+ c->local = local;
+ c->remote = remote;
+ c->peerType = peerType;
+ c->tos = tos;
+ c->flags = flags;
+
+ // ensure FD is not open in the new copy.
+ c->fd = -1;
+
+ // ensure we have a cbdata reference to _peer not a straight ptr copy.
+ c->_peer = cbdataReference(getPeer());
+
+ return c;
+}
+
+void
+Comm::Connection::close()
+{
+ if (isOpen()) {
+ comm_close(fd);
+ fd = -1;
+ if (getPeer())
+ getPeer()->stats.conn_open--;
+ }
+}
+
+peer * const
+Comm::Connection::getPeer() const
+{
+ if (cbdataReferenceValid(_peer))
+ return _peer;
+
+ return NULL;
+}
+
+void
+Comm::Connection::setPeer(peer *p)
+{
+ /* set to self. nothing to do. */
+ if (getPeer() == p)
+ return;
+
+ cbdataReferenceDone(_peer);
+ if (p) {
+ _peer = cbdataReference(p);
+ }
+}
=== renamed file 'src/ConnectionDetail.h' => 'src/comm/Connection.h'
--- src/ConnectionDetail.h 2010-05-26 03:06:02 +0000
+++ src/comm/Connection.h 2011-02-05 14:13:18 +0000
@@ -1,5 +1,6 @@
/*
* DEBUG: section 05 Socket Functions
+ * AUTHOR: Amos Jeffries
* AUTHOR: Robert Collins
*
* SQUID Web Proxy Cache http://www.squid-cache.org/
@@ -30,23 +31,161 @@
*
*
* Copyright (c) 2003, Robert Collins
+ * Copyright (c) 2010, Amos Jeffries
*/
#ifndef _SQUIDCONNECTIONDETAIL_H_
#define _SQUIDCONNECTIONDETAIL_H_
+#include "config.h"
+#include "comm/forward.h"
+#include "hier_code.h"
#include "ip/Address.h"
-
-class ConnectionDetail
+#include "RefCount.h"
+#include "typedefs.h"
+#if USE_SQUID_EUI
+#include "eui/Eui48.h"
+#include "eui/Eui64.h"
+#endif
+
+#if HAVE_IOSFWD
+#include
+#endif
+#if HAVE_OSTREAM
+#include
+#endif
+
+struct peer;
+
+namespace Comm {
+
+/* TODO: make these a struct of boolean flags members in the connection instead of a bitmap.
+ * we can't do that until all non-comm code uses Commm::Connection objects to create FD
+ * currently there is code still using comm_open() and comm_openex() synchronously!!
+ */
+#define COMM_UNSET 0x00
+#define COMM_NONBLOCKING 0x01 // default flag.
+#define COMM_NOCLOEXEC 0x02
+#define COMM_REUSEADDR 0x04 // shared FD may be both accept()ing and read()ing
+#define COMM_DOBIND 0x08 // requires a bind()
+#define COMM_TRANSPARENT 0x10 // arrived via TPROXY
+#define COMM_INTERCEPTION 0x20 // arrived via NAT
+
+/**
+ * Store data about the physical and logical attributes of a connection.
+ *
+ * Some link state can be infered from the data, however this is not an
+ * object for state data. But a semantic equivalent for FD with easily
+ * accessible cached properties not requiring repeated complex lookups.
+ *
+ * While the properties may be changed, this is for teh purpose of creating
+ * potential connection descriptors which may be opened. Properties should
+ * be considered read-only outside of the Comm layer code once the connection
+ * is open.
+ *
+ * These objects must not be passed around directly,
+ * but a Comm::ConnectionPointer must be passed instead.
+ */
+class Connection : public RefCountable
{
-
-public:
-
- ConnectionDetail();
-
- Ip::Address me;
-
- Ip::Address peer;
+public:
+ /** standard empty connection creation */
+ Connection();
+
+ /** Clear the connection properties and close any open socket. */
+ ~Connection();
+
+ /** Copy an existing connections IP and properties.
+ * This excludes the FD. The new copy will be a closed connection.
+ */
+ ConnectionPointer copyDetails() const;
+
+ /** Close any open socket. */
+ void close();
+
+ /** determine whether this object describes an active connection or not. */
+ bool isOpen() const { return (fd >= 0); }
+
+ /** retrieve the peer pointer for use.
+ * The caller is responsible for all CBDATA operations regarding the
+ * used of the pointer returned.
+ */
+ peer * const getPeer() const;
+
+ /** alter the stored peer pointer.
+ * Perform appropriate CBDATA operations for locking the peer pointer
+ */
+ void setPeer(peer * p);
+
+private:
+ /** These objects may not be exactly duplicated. Use copyDetails() instead. */
+ Connection(const Connection &c);
+
+ /** These objects may not be exactly duplicated. Use copyDetails() instead. */
+ Connection & operator =(const Connection &c);
+
+public:
+ /** Address/Port for the Squid end of a TCP link. */
+ Ip::Address local;
+
+ /** Address for the Remote end of a TCP link. */
+ Ip::Address remote;
+
+ /** Hierarchy code for this connection link */
+ hier_code peerType;
+
+ /** Socket used by this connection. -1 if no socket has been opened. */
+ int fd;
+
+ /** Quality of Service TOS values currently sent on this connection */
+ tos_t tos;
+
+ /** Netfilter MARK values currently sent on this connection */
+ nfmark_t nfmark;
+
+ /** COMM flags set on this connection */
+ int flags;
+
+ char rfc931[USER_IDENT_SZ];
+
+#if USE_SQUID_EUI
+ Eui::Eui48 remoteEui48;
+ Eui::Eui64 remoteEui64;
+#endif
+
+private:
+ // XXX: we need to call this member peer_ but the struct peer_ global type
+ // behind peer* clashes despite our private Comm:: namespace
+ // (it being global gets inherited here too).
+
+ /** cache_peer data object (if any) */
+ peer *_peer;
};
+}; // namespace Comm
+
+
+// NP: Order and namespace here is very important.
+// * The second define inlines the first.
+// * Stream inheritance overloading is searched in the global scope first.
+
+inline std::ostream &
+operator << (std::ostream &os, const Comm::Connection &conn)
+{
+ os << "FD " << conn.fd << " local=" << conn.local <<
+ " remote=" << conn.remote << " flags=" << conn.flags;
+#if USE_IDENT
+ os << " IDENT::" << conn.rfc931;
+#endif
+ return os;
+}
+
+inline std::ostream &
+operator << (std::ostream &os, const Comm::ConnectionPointer &conn)
+{
+ if (conn != NULL)
+ os << *conn;
+ return os;
+}
+
#endif
=== modified file 'src/comm/IoCallback.cc'
--- src/comm/IoCallback.cc 2011-01-10 09:43:43 +0000
+++ src/comm/IoCallback.cc 2011-03-26 04:52:11 +0000
@@ -1,5 +1,6 @@
#include "config.h"
#include "ClientInfo.h"
+#include "comm/Connection.h"
#include "comm/IoCallback.h"
#include "comm/Loops.h"
#include "comm/Write.h"
@@ -15,9 +16,7 @@
iocb_table = static_cast(xcalloc(Squid_MaxFD, sizeof(CbEntry)));
for (int pos = 0; pos < Squid_MaxFD; pos++) {
iocb_table[pos].fd = pos;
- iocb_table[pos].readcb.fd = pos;
iocb_table[pos].readcb.type = IOCB_READ;
- iocb_table[pos].writecb.fd = pos;
iocb_table[pos].writecb.type = IOCB_WRITE;
}
}
@@ -25,6 +24,11 @@
void
Comm::CallbackTableDestruct()
{
+ // release any Comm::Connections being held.
+ for (int pos = 0; pos < Squid_MaxFD; pos++) {
+ iocb_table[pos].readcb.conn = NULL;
+ iocb_table[pos].writecb.conn = NULL;
+ }
safe_free(iocb_table);
}
@@ -57,16 +61,16 @@
{
#if USE_DELAY_POOLS
// stand in line if there is one
- if (ClientInfo *clientInfo = fd_table[fd].clientInfo) {
+ if (ClientInfo *clientInfo = fd_table[conn->fd].clientInfo) {
if (clientInfo->writeLimitingActive) {
- quotaQueueReserv = clientInfo->quotaEnqueue(fd);
+ quotaQueueReserv = clientInfo->quotaEnqueue(conn->fd);
clientInfo->kickQuotaQueue();
return;
}
}
#endif
- SetSelect(fd, COMM_SELECT_WRITE, Comm::HandleWrite, this, 0);
+ SetSelect(conn->fd, COMM_SELECT_WRITE, Comm::HandleWrite, this, 0);
}
void
@@ -83,6 +87,7 @@
void
Comm::IoCallback::reset()
{
+ conn = NULL;
if (freefunc) {
freefunc(buf);
buf = NULL;
@@ -99,7 +104,7 @@
void
Comm::IoCallback::finish(comm_err_t code, int xerrn)
{
- debugs(5, 3, HERE << "called for FD " << fd << " (" << code << ", " << xerrno << ")");
+ debugs(5, 3, HERE << "called for " << conn << " (" << code << ", " << xerrno << ")");
assert(active());
/* free data */
@@ -112,7 +117,8 @@
if (callback != NULL) {
typedef CommIoCbParams Params;
Params ¶ms = GetCommParams(callback);
- params.fd = fd;
+ if (conn != NULL) params.fd = conn->fd; // for legacy write handlers...
+ params.conn = conn;
params.buf = buf;
params.size = offset;
params.flag = code;
=== modified file 'src/comm/IoCallback.h'
--- src/comm/IoCallback.h 2010-12-10 09:49:50 +0000
+++ src/comm/IoCallback.h 2010-12-11 01:02:33 +0000
@@ -3,6 +3,7 @@
#include "base/AsyncCall.h"
#include "comm_err_t.h"
+#include "comm/forward.h"
namespace Comm
{
@@ -19,7 +20,7 @@
{
public:
iocb_type type;
- int fd;
+ Comm::ConnectionPointer conn;
AsyncCall::Pointer callback;
char *buf;
FREE *freefunc;
=== modified file 'src/comm/Makefile.am'
--- src/comm/Makefile.am 2011-01-26 03:47:13 +0000
+++ src/comm/Makefile.am 2011-03-06 09:55:34 +0000
@@ -7,6 +7,13 @@
libcomm_la_SOURCES= \
AcceptLimiter.cc \
AcceptLimiter.h \
+ ConnOpener.cc \
+ ConnOpener.h \
+ Connection.cc \
+ Connection.h \
+ forward.h \
+ IoCallback.cc \
+ IoCallback.h \
Loops.h \
ModDevPoll.cc \
ModEpoll.cc \
@@ -16,10 +23,9 @@
ModSelectWin32.cc \
TcpAcceptor.cc \
TcpAcceptor.h \
- \
- IoCallback.cc \
- IoCallback.h \
Write.cc \
Write.h \
\
comm_internal.h
+
+EXTRA_DIST= stub_libcomm.cc
=== modified file 'src/comm/ModPoll.cc'
--- src/comm/ModPoll.cc 2011-01-10 09:43:43 +0000
+++ src/comm/ModPoll.cc 2011-03-11 15:21:34 +0000
@@ -35,8 +35,10 @@
#if USE_POLL
#include "squid.h"
+#include "comm/Connection.h"
#include "comm/Loops.h"
#include "fde.h"
+#include "ICP.h"
#include "mgr/Registration.h"
#include "SquidTime.h"
#include "Store.h"
@@ -166,10 +168,10 @@
static int
fdIsIcp(int fd)
{
- if (fd == theInIcpConnection)
+ if (icpIncomingConn != NULL && icpIncomingConn->fd == fd)
return 1;
- if (fd == theOutIcpConnection)
+ if (icpOutgoingConn != NULL && icpOutgoingConn->fd == fd)
return 1;
return 0;
@@ -279,12 +281,11 @@
int nevents;
icp_io_events = 0;
- if (theInIcpConnection >= 0)
- fds[nfds++] = theInIcpConnection;
+ if (Comm::IsConnOpen(icpIncomingConn))
+ fds[nfds++] = icpIncomingConn->fd;
- if (theInIcpConnection != theOutIcpConnection)
- if (theOutIcpConnection >= 0)
- fds[nfds++] = theOutIcpConnection;
+ if (icpIncomingConn != icpOutgoingConn && Comm::IsConnOpen(icpOutgoingConn))
+ fds[nfds++] = icpOutgoingConn->fd;
if (nfds == 0)
return;
=== modified file 'src/comm/ModSelect.cc'
--- src/comm/ModSelect.cc 2011-01-10 09:43:43 +0000
+++ src/comm/ModSelect.cc 2011-03-08 07:43:51 +0000
@@ -35,7 +35,9 @@
#if USE_SELECT
#include "squid.h"
+#include "comm/Connection.h"
#include "comm/Loops.h"
+#include "ICP.h"
#include "mgr/Registration.h"
#include "SquidTime.h"
#include "Store.h"
@@ -163,10 +165,10 @@
static int
fdIsIcp(int fd)
{
- if (fd == theInIcpConnection)
+ if (icpIncomingConn != NULL && fd == icpIncomingConn->fd)
return 1;
- if (fd == theOutIcpConnection)
+ if (icpOutgoingConn != NULL && fd == icpOutgoingConn->fd)
return 1;
return 0;
@@ -273,12 +275,11 @@
int nevents;
icp_io_events = 0;
- if (theInIcpConnection >= 0)
- fds[nfds++] = theInIcpConnection;
+ if (Comm::IsConnOpen(icpIncomingConn))
+ fds[nfds++] = icpIncomingConn->fd;
- if (theInIcpConnection != theOutIcpConnection)
- if (theOutIcpConnection >= 0)
- fds[nfds++] = theOutIcpConnection;
+ if (Comm::IsConnOpen(icpOutgoingConn) && icpIncomingConn != icpOutgoingConn)
+ fds[nfds++] = icpOutgoingConn->fd;
if (nfds == 0)
return;
=== modified file 'src/comm/TcpAcceptor.cc'
--- src/comm/TcpAcceptor.cc 2011-01-27 01:12:25 +0000
+++ src/comm/TcpAcceptor.cc 2011-02-05 17:43:42 +0000
@@ -37,10 +37,11 @@
#include "CommCalls.h"
#include "comm/AcceptLimiter.h"
#include "comm/comm_internal.h"
+#include "comm/Connection.h"
#include "comm/Loops.h"
#include "comm/TcpAcceptor.h"
-#include "ConnectionDetail.h"
#include "fde.h"
+#include "ip/Intercept.h"
#include "protos.h"
#include "SquidTime.h"
@@ -49,14 +50,12 @@
CBDATA_CLASS_INIT(TcpAcceptor);
};
-Comm::TcpAcceptor::TcpAcceptor(const int listenFd, const Ip::Address &laddr, int flags,
- const char *note, const Subscription::Pointer &aSub) :
+Comm::TcpAcceptor::TcpAcceptor(const Comm::ConnectionPointer &newConn, const char *note, const Subscription::Pointer &aSub) :
AsyncJob("Comm::TcpAcceptor"),
errcode(0),
- fd(listenFd),
isLimited(0),
theCallSub(aSub),
- local_addr(laddr)
+ conn(newConn)
{}
void
@@ -79,20 +78,20 @@
{
debugs(5, 5, HERE << status() << " AsyncCall Subscription: " << theCallSub);
- Must(isOpen(fd));
+ Must(IsConnOpen(conn));
setListen();
// if no error so far start accepting connections.
if (errcode == 0)
- SetSelect(fd, COMM_SELECT_READ, doAccept, this, 0);
+ SetSelect(conn->fd, COMM_SELECT_READ, doAccept, this, 0);
}
bool
Comm::TcpAcceptor::doneAll() const
{
// stop when FD is closed
- if (!isOpen(fd)) {
+ if (!IsConnOpen(conn)) {
return AsyncJob::doneAll();
}
@@ -110,7 +109,7 @@
{
debugs(5,5, HERE);
unsubscribe("swanSong");
- fd = -1;
+ conn = NULL;
AcceptLimiter::Instance().removeDead(this);
AsyncJob::swanSong();
}
@@ -118,13 +117,16 @@
const char *
Comm::TcpAcceptor::status() const
{
+ if (conn == NULL)
+ return "[nil connection]";
+
static char ipbuf[MAX_IPSTRLEN] = {'\0'};
if (ipbuf[0] == '\0')
- local_addr.ToHostname(ipbuf, MAX_IPSTRLEN);
+ conn->local.ToHostname(ipbuf, MAX_IPSTRLEN);
static MemBuf buf;
buf.reset();
- buf.Printf(" FD %d, %s",fd, ipbuf);
+ buf.Printf(" FD %d, %s",conn->fd, ipbuf);
const char *jobStatus = AsyncJob::status();
buf.append(jobStatus, strlen(jobStatus));
@@ -143,7 +145,7 @@
Comm::TcpAcceptor::setListen()
{
errcode = 0; // reset local errno copy.
- if (listen(fd, Squid_MaxFD >> 2) < 0) {
+ if (listen(conn->fd, Squid_MaxFD >> 2) < 0) {
debugs(50, DBG_CRITICAL, "ERROR: listen(" << status() << ", " << (Squid_MaxFD >> 2) << "): " << xstrerror());
errcode = errno;
return;
@@ -153,15 +155,15 @@
#ifdef SO_ACCEPTFILTER
struct accept_filter_arg afa;
bzero(&afa, sizeof(afa));
- debugs(5, DBG_IMPORTANT, "Installing accept filter '" << Config.accept_filter << "' on FD " << fd);
+ debugs(5, DBG_IMPORTANT, "Installing accept filter '" << Config.accept_filter << "' on " << conn);
xstrncpy(afa.af_name, Config.accept_filter, sizeof(afa.af_name));
- if (setsockopt(fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0)
+ if (setsockopt(conn->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0)
debugs(5, DBG_CRITICAL, "WARNING: SO_ACCEPTFILTER '" << Config.accept_filter << "': '" << xstrerror());
#elif defined(TCP_DEFER_ACCEPT)
int seconds = 30;
if (strncmp(Config.accept_filter, "data=", 5) == 0)
seconds = atoi(Config.accept_filter + 5);
- if (setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &seconds, sizeof(seconds)) < 0)
+ if (setsockopt(conn->fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &seconds, sizeof(seconds)) < 0)
debugs(5, DBG_CRITICAL, "WARNING: TCP_DEFER_ACCEPT '" << Config.accept_filter << "': '" << xstrerror());
#else
debugs(5, DBG_CRITICAL, "WARNING: accept_filter not supported on your OS");
@@ -227,45 +229,42 @@
*/
/* Accept a new connection */
- ConnectionDetail newConnDetails;
- int newFd = -1;
- const comm_err_t flag = oldAccept(newConnDetails, &newFd);
+ ConnectionPointer newConnDetails = new Connection();
+ const comm_err_t flag = oldAccept(newConnDetails);
/* Check for errors */
- if (!isOpen(newFd)) {
+ if (!newConnDetails->isOpen()) {
if (flag == COMM_NOMESSAGE) {
/* register interest again */
- debugs(5, 5, HERE << "try later: FD " << fd << " handler Subscription: " << theCallSub);
- SetSelect(fd, COMM_SELECT_READ, doAccept, this, 0);
+ debugs(5, 5, HERE << "try later: " << conn << " handler Subscription: " << theCallSub);
+ SetSelect(conn->fd, COMM_SELECT_READ, doAccept, this, 0);
return;
}
// A non-recoverable error; notify the caller */
debugs(5, 5, HERE << "non-recoverable error:" << status() << " handler Subscription: " << theCallSub);
- notify(flag, newConnDetails, newFd);
+ notify(flag, newConnDetails);
mustStop("Listener socket closed");
return;
}
- debugs(5, 5, HERE << "Listener: FD " << fd <<
- " accepted new connection from " << newConnDetails.peer <<
+ debugs(5, 5, HERE << "Listener: " << conn <<
+ " accepted new connection " << newConnDetails <<
" handler Subscription: " << theCallSub);
- notify(flag, newConnDetails, newFd);
+ notify(flag, newConnDetails);
}
void
Comm::TcpAcceptor::acceptNext()
{
- Must(isOpen(fd));
- debugs(5, 2, HERE << "connection on FD " << fd);
+ Must(IsConnOpen(conn));
+ debugs(5, 2, HERE << "connection on " << conn);
acceptOne();
}
-// XXX: obsolete comment?
-// NP: can't be a const function because syncWithComm() side effects hit theCallSub->callback().
void
-Comm::TcpAcceptor::notify(const comm_err_t flag, const ConnectionDetail &connDetails, int newFd) const
+Comm::TcpAcceptor::notify(const comm_err_t flag, const Comm::ConnectionPointer &newConnDetails) const
{
// listener socket handlers just abandon the port with COMM_ERR_CLOSING
// it should only happen when this object is deleted...
@@ -276,9 +275,8 @@
if (theCallSub != NULL) {
AsyncCall::Pointer call = theCallSub->callback();
CommAcceptCbParams ¶ms = GetCommParams(call);
- params.fd = fd;
- params.nfd = newFd;
- params.details = connDetails;
+ params.fd = conn->fd;
+ params.conn = newConnDetails;
params.flag = flag;
params.xerrno = errcode;
ScheduleCallHere(call);
@@ -295,19 +293,19 @@
* Or if this client has too many connections already.
*/
comm_err_t
-Comm::TcpAcceptor::oldAccept(ConnectionDetail &details, int *newFd)
+Comm::TcpAcceptor::oldAccept(Comm::ConnectionPointer &details)
{
PROF_start(comm_accept);
statCounter.syscalls.sock.accepts++;
int sock;
struct addrinfo *gai = NULL;
- details.me.InitAddrInfo(gai);
+ details->local.InitAddrInfo(gai);
errcode = 0; // reset local errno copy.
- if ((sock = accept(fd, gai->ai_addr, &gai->ai_addrlen)) < 0) {
+ if ((sock = accept(conn->fd, gai->ai_addr, &gai->ai_addrlen)) < 0) {
errcode = errno; // store last accept errno locally.
- details.me.FreeAddrInfo(gai);
+ details->local.FreeAddrInfo(gai);
PROF_stop(comm_accept);
@@ -324,23 +322,23 @@
}
Must(sock >= 0);
- *newFd = sock;
- details.peer = *gai;
+ details->fd = sock;
+ details->remote = *gai;
if ( Config.client_ip_max_connections >= 0) {
- if (clientdbEstablished(details.peer, 0) > Config.client_ip_max_connections) {
- debugs(50, DBG_IMPORTANT, "WARNING: " << details.peer << " attempting more than " << Config.client_ip_max_connections << " connections.");
- details.me.FreeAddrInfo(gai);
+ if (clientdbEstablished(details->remote, 0) > Config.client_ip_max_connections) {
+ debugs(50, DBG_IMPORTANT, "WARNING: " << details->remote << " attempting more than " << Config.client_ip_max_connections << " connections.");
+ details->local.FreeAddrInfo(gai);
return COMM_ERROR;
}
}
// lookup the local-end details of this new connection
- details.me.InitAddrInfo(gai);
- details.me.SetEmpty();
+ details->local.InitAddrInfo(gai);
+ details->local.SetEmpty();
getsockname(sock, gai->ai_addr, &gai->ai_addrlen);
- details.me = *gai;
- details.me.FreeAddrInfo(gai);
+ details->local = *gai;
+ details->local.FreeAddrInfo(gai);
/* fdstat update */
// XXX : these are not all HTTP requests. use a note about type and ip:port details->
@@ -351,17 +349,23 @@
fdd_table[sock].close_line = 0;
fde *F = &fd_table[sock];
- details.peer.NtoA(F->ipaddr,MAX_IPSTRLEN);
- F->remote_port = details.peer.GetPort();
- F->local_addr = details.me;
- F->sock_family = details.me.IsIPv6()?AF_INET6:AF_INET;
+ details->remote.NtoA(F->ipaddr,MAX_IPSTRLEN);
+ F->remote_port = details->remote.GetPort();
+ F->local_addr = details->local;
+ F->sock_family = details->local.IsIPv6()?AF_INET6:AF_INET;
// set socket flags
commSetCloseOnExec(sock);
commSetNonBlocking(sock);
/* IFF the socket is (tproxy) transparent, pass the flag down to allow spoofing */
- F->flags.transparent = fd_table[fd].flags.transparent;
+ F->flags.transparent = fd_table[conn->fd].flags.transparent; // XXX: can we remove this line yet?
+
+ // Perform NAT or TPROXY operations to retrieve the real client/dest IP addresses
+ if (conn->flags&(COMM_TRANSPARENT|COMM_INTERCEPTION) && !Ip::Interceptor.Lookup(details, conn)) {
+ // Failed.
+ return COMM_ERROR;
+ }
PROF_stop(comm_accept);
return COMM_OK;
=== modified file 'src/comm/TcpAcceptor.h'
--- src/comm/TcpAcceptor.h 2011-01-26 03:47:13 +0000
+++ src/comm/TcpAcceptor.h 2011-01-26 11:00:30 +0000
@@ -5,6 +5,7 @@
#include "base/Subscription.h"
#include "CommCalls.h"
#include "comm_err_t.h"
+#include "comm/forward.h"
#include "comm/TcpAcceptor.h"
#include "ip/Address.h"
@@ -18,8 +19,8 @@
class AcceptLimiter;
/**
- * Listens on an FD for new incoming connections and
- * emits an active FD descriptor for the new client.
+ * Listens on a Comm::Connection for new incoming connections and
+ * emits an active Comm::Connection descriptor for the new client.
*
* Handles all event limiting required to quash inbound connection
* floods within the global FD limits of available Squid_MaxFD and
@@ -40,8 +41,7 @@
TcpAcceptor(const TcpAcceptor &); // not implemented.
public:
- TcpAcceptor(const int listenFd, const Ip::Address &laddr, int flags,
- const char *note, const Subscription::Pointer &aSub);
+ TcpAcceptor(const Comm::ConnectionPointer &conn, const char *note, const Subscription::Pointer &aSub);
/** Subscribe a handler to receive calls back about new connections.
* Unsubscribes any existing subscribed handler.
@@ -60,16 +60,11 @@
void acceptNext();
/// Call the subscribed callback handler with details about a new connection.
- void notify(const comm_err_t flags, const ConnectionDetail &newConnDetails, const int newFd) const;
+ void notify(const comm_err_t flag, const Comm::ConnectionPointer &details) const;
/// errno code of the last accept() or listen() action if one occurred.
int errcode;
- /// conn being listened on for new connections
- /// Reserved for read-only use.
- // NP: public only until we can hide it behind connection handles
- int fd;
-
protected:
friend class AcceptLimiter;
int32_t isLimited; ///< whether this socket is delayed and on the AcceptLimiter queue.
@@ -77,8 +72,9 @@
private:
Subscription::Pointer theCallSub; ///< used to generate AsyncCalls handling our events.
- /// IP Address and port being listened on
- Ip::Address local_addr;
+ /// conn being listened on for new connections
+ /// Reserved for read-only use.
+ ConnectionPointer conn;
/// Method to test if there are enough file descriptors to open a new client connection
/// if not the accept() will be postponed
@@ -88,7 +84,7 @@
static void doAccept(int fd, void *data);
void acceptOne();
- comm_err_t oldAccept(ConnectionDetail &newConnDetails, int *fd);
+ comm_err_t oldAccept(Comm::ConnectionPointer &details);
void setListen();
CBDATA_CLASS2(TcpAcceptor);
=== modified file 'src/comm/Write.cc'
--- src/comm/Write.cc 2010-11-28 01:15:27 +0000
+++ src/comm/Write.cc 2010-12-03 00:09:52 +0000
@@ -2,6 +2,7 @@
#if USE_DELAY_POOLS
#include "ClientInfo.h"
#endif
+#include "comm/Connection.h"
#include "comm/IoCallback.h"
#include "comm/Write.h"
#include "fde.h"
@@ -9,23 +10,24 @@
#include "MemBuf.h"
void
-Comm::Write(int fd, MemBuf *mb, AsyncCall::Pointer &callback)
+Comm::Write(const Comm::ConnectionPointer &conn, MemBuf *mb, AsyncCall::Pointer &callback)
{
- Comm::Write(fd, mb->buf, mb->size, callback, mb->freeFunc());
+ Comm::Write(conn, mb->buf, mb->size, callback, mb->freeFunc());
}
void
-Comm::Write(int fd, const char *buf, int size, AsyncCall::Pointer &callback, FREE * free_func)
+Comm::Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE * free_func)
{
- debugs(5, 5, HERE << "FD " << fd << ": sz " << size << ": asynCall " << callback);
+ debugs(5, 5, HERE << conn << ": sz " << size << ": asynCall " << callback);
/* Make sure we are open, not closing, and not writing */
- assert(fd_table[fd].flags.open);
- assert(!fd_table[fd].closing());
- Comm::IoCallback *ccb = COMMIO_FD_WRITECB(fd);
+ assert(fd_table[conn->fd].flags.open);
+ assert(!fd_table[conn->fd].closing());
+ Comm::IoCallback *ccb = COMMIO_FD_WRITECB(conn->fd);
assert(!ccb->active());
- fd_table[fd].writeStart = squid_curtime;
+ fd_table[conn->fd].writeStart = squid_curtime;
+ ccb->conn = conn;
/* Queue the write */
ccb->setCallback(IOCB_WRITE, callback, (char *)buf, free_func, size);
ccb->selectOrQueueWrite();
@@ -33,7 +35,7 @@
/** Write to FD.
* This function is used by the lowest level of IO loop which only has access to FD numbers.
- * We have to use the comm iocb_table to map FD numbers to waiting data.
+ * We have to use the comm iocb_table to map FD numbers to waiting data and Comm::Connections.
* Once the write has been concluded we schedule the waiting call with success/fail results.
*/
void
@@ -43,10 +45,10 @@
int len = 0;
int nleft;
- assert(state->fd == fd);
+ assert(state->conn != NULL && state->conn->fd == fd);
PROF_start(commHandleWrite);
- debugs(5, 5, HERE << "FD " << state->fd << ": off " <<
+ debugs(5, 5, HERE << state->conn << ": off " <<
(long int) state->offset << ", sz " << (long int) state->size << ".");
nleft = state->size - state->offset;
@@ -76,7 +78,7 @@
const int nleft_corrected = min(nleft, quota);
if (nleft != nleft_corrected) {
- debugs(5, 5, HERE << "FD " << fd << " writes only " <<
+ debugs(5, 5, HERE << state->conn << " writes only " <<
nleft_corrected << " out of " << nleft);
nleft = nleft_corrected;
}
=== modified file 'src/comm/Write.h'
--- src/comm/Write.h 2010-11-28 01:15:27 +0000
+++ src/comm/Write.h 2010-12-03 00:09:52 +0000
@@ -2,6 +2,7 @@
#define _SQUID_COMM_IOWRITE_H
#include "base/AsyncCall.h"
+#include "comm/forward.h"
namespace Comm
{
@@ -12,16 +13,16 @@
*
* free_func is used to free the passed buffer when the write has completed.
*/
-void Write(int fd, const char *buf, int size, AsyncCall::Pointer &callback, FREE *free_func);
+void Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE *free_func);
/**
* Queue a write. callback is scheduled when the write
* completes, on error, or on file descriptor close.
*/
-void Write(int fd, MemBuf *mb, AsyncCall::Pointer &callback);
+void Write(const Comm::ConnectionPointer &conn, MemBuf *mb, AsyncCall::Pointer &callback);
/// Cancel the write pending on FD. No action if none pending.
-void WriteCancel(int fd, const char *reason);
+void WriteCancel(const Comm::ConnectionPointer &conn, const char *reason);
// callback handler to process an FD which is available for writing.
extern PF HandleWrite;
=== added file 'src/comm/comm_err_t.h'
--- src/comm/comm_err_t.h 1970-01-01 00:00:00 +0000
+++ src/comm/comm_err_t.h 2010-05-15 14:57:24 +0000
@@ -0,0 +1,21 @@
+#ifndef _SQUID_COMM_COMM_ERR_T_H
+#define _SQUID_COMM_COMM_ERR_T_H
+
+#include "config.h"
+
+typedef enum {
+ COMM_OK = 0,
+ COMM_ERROR = -1,
+ COMM_NOMESSAGE = -3,
+ COMM_TIMEOUT = -4,
+ COMM_SHUTDOWN = -5,
+ COMM_IDLE = -6, /* there are no active fds and no pending callbacks. */
+ COMM_INPROGRESS = -7,
+ COMM_ERR_CONNECT = -8,
+ COMM_ERR_DNS = -9,
+ COMM_ERR_CLOSING = -10,
+ COMM_ERR_PROTOCOL = -11, /* IPv4 or IPv6 cannot be used on the fd socket */
+ COMM_ERR__END__ = -999999 /* Dummy entry to make syntax valid (comma on line above), do not use. New entries added above */
+} comm_err_t;
+
+#endif /* _SQUID_COMM_COMM_ERR_T_H */
=== added file 'src/comm/forward.h'
--- src/comm/forward.h 1970-01-01 00:00:00 +0000
+++ src/comm/forward.h 2010-11-28 02:58:18 +0000
@@ -0,0 +1,19 @@
+#ifndef _SQUID_COMM_FORWARD_H
+#define _SQUID_COMM_FORWARD_H
+
+#include "Array.h"
+#include "RefCount.h"
+
+namespace Comm {
+
+class Connection;
+
+typedef RefCount ConnectionPointer;
+
+typedef Vector ConnectionList;
+
+bool IsConnOpen(const Comm::ConnectionPointer &conn);
+
+}; // namespace Comm
+
+#endif /* _SQUID_COMM_FORWARD_H */
=== added file 'src/comm/stub_libcomm.cc'
--- src/comm/stub_libcomm.cc 1970-01-01 00:00:00 +0000
+++ src/comm/stub_libcomm.cc 2011-03-12 08:55:37 +0000
@@ -0,0 +1,60 @@
+#include "config.h"
+#include "base/AsyncJob.h"
+#include "structs.h"
+
+#define STUB { fatal("comm/libcomm.la required."); }
+#define STUB_RETVAL(x) { fatal("comm/libcomm.la required."); return (x); }
+#define STUB_RETREF(x) { fatal("comm/libcomm.la required."); static x v; return v; }
+
+#include "AcceptLimiter.h"
+Comm::AcceptLimiter & Comm::AcceptLimiter::Instance() STUB_RETREF(Comm::AcceptLimiter)
+void Comm::AcceptLimiter::defer(Comm::TcpAcceptor *afd) STUB
+void Comm::AcceptLimiter::removeDead(const Comm::TcpAcceptor *afd) STUB
+void Comm::AcceptLimiter::kick() STUB
+
+#include "comm/Connection.h"
+Comm::Connection::Connection() STUB
+Comm::Connection::~Connection() STUB
+Comm::ConnectionPointer Comm::Connection::copyDetails() const STUB_RETVAL(NULL)
+void Comm::Connection::close() STUB
+peer * const Comm::Connection::getPeer() const STUB_RETVAL(NULL)
+void Comm::Connection::setPeer(peer * p) STUB
+
+#include "comm/ConnOpener.h"
+bool Comm::ConnOpener::doneAll() const STUB_RETVAL(false)
+//Comm::ConnOpener::ConnOpener(Comm::ConnectionPointer &, AsyncCall::Pointer &, time_t) STUB
+//Comm::ConnOpener::~ConnOpener() STUB
+void Comm::ConnOpener::setHost(const char *) STUB
+const char * Comm::ConnOpener::getHost() const STUB_RETVAL(NULL)
+
+#include "comm/forward.h"
+bool Comm::IsConnOpen(const Comm::ConnectionPointer &) STUB_RETVAL(false)
+
+#include "comm/IoCallback.h"
+void Comm::IoCallback::setCallback(iocb_type type, AsyncCall::Pointer &cb, char *buf, FREE *func, int sz) STUB
+void Comm::IoCallback::selectOrQueueWrite() STUB
+void Comm::IoCallback::cancel(const char *reason) STUB
+void Comm::IoCallback::finish(comm_err_t code, int xerrn) STUB
+Comm::CbEntry *Comm::iocb_table = NULL;
+void Comm::CallbackTableInit() STUB
+void Comm::CallbackTableDestruct() STUB
+
+#include "comm/Loops.h"
+void Comm::SelectLoopInit(void) STUB
+void Comm::SetSelect(int, unsigned int, PF *, void *, time_t) STUB
+void Comm::ResetSelect(int) STUB
+comm_err_t Comm::DoSelect(int) STUB_RETVAL(COMM_ERROR)
+void Comm::QuickPollRequired(void) STUB
+
+#include "comm/TcpAcceptor.h"
+//Comm::TcpAcceptor(const Comm::ConnectionPointer &conn, const char *note, const Subscription::Pointer &aSub) STUB
+void Comm::TcpAcceptor::subscribe(const Subscription::Pointer &aSub) STUB
+void Comm::TcpAcceptor::unsubscribe(const char *) STUB
+void Comm::TcpAcceptor::acceptNext() STUB
+void Comm::TcpAcceptor::notify(const comm_err_t flag, const Comm::ConnectionPointer &) const STUB
+
+#include "comm/Write.h"
+void Comm::Write(const Comm::ConnectionPointer &, const char *, int, AsyncCall::Pointer &, FREE *) STUB
+void Comm::Write(const Comm::ConnectionPointer &conn, MemBuf *mb, AsyncCall::Pointer &callback) STUB
+void Comm::WriteCancel(const Comm::ConnectionPointer &conn, const char *reason) STUB
+//PF Comm::HandleWrite STUB
=== modified file 'src/defines.h'
--- src/defines.h 2011-01-28 07:58:53 +0000
+++ src/defines.h 2011-03-26 04:55:58 +0000
@@ -62,12 +62,6 @@
#define COMM_SELECT_READ (0x1)
#define COMM_SELECT_WRITE (0x2)
-#define COMM_NONBLOCKING 0x01
-#define COMM_NOCLOEXEC 0x02
-#define COMM_REUSEADDR 0x04
-#define COMM_TRANSPARENT 0x08
-#define COMM_DOBIND 0x10
-
#define DISK_OK (0)
#define DISK_ERROR (-1)
#define DISK_EOF (-2)
=== modified file 'src/delay_pools.cc'
--- src/delay_pools.cc 2010-11-27 06:44:33 +0000
+++ src/delay_pools.cc 2011-03-12 02:52:56 +0000
@@ -65,6 +65,7 @@
#include "DelayUser.h"
#include "DelayTagged.h"
#include "ip/Address.h"
+#include "comm/Connection.h"
/// \ingroup DelayPoolsInternal
long DelayPools::MemoryUsed = 0;
=== modified file 'src/dns_internal.cc'
--- src/dns_internal.cc 2011-03-16 00:12:38 +0000
+++ src/dns_internal.cc 2011-03-26 04:58:54 +0000
@@ -33,6 +33,8 @@
*/
#include "squid.h"
+#include "comm/Connection.h"
+#include "comm/ConnOpener.h"
#include "comm.h"
#include "comm/Loops.h"
#include "comm/Write.h"
@@ -152,7 +154,7 @@
struct _nsvc {
int ns;
- int fd;
+ Comm::ConnectionPointer conn;
unsigned short msglen;
int read_msglen;
MemBuf *msg;
@@ -234,6 +236,9 @@
static void idnsSendQuery(idns_query * q);
static IOCB idnsReadVCHeader;
static void idnsDoSendQueryVC(nsvc *vc);
+static CNCB idnsInitVCConnected;
+static IOCB idnsReadVC;
+static IOCB idnsSentQueryVC;
static int idnsFromKnownNameserver(Ip::Address const &from);
static idns_query *idnsFindQuery(unsigned short id);
@@ -242,6 +247,7 @@
static EVH idnsCheckQueue;
static void idnsTickleQueue(void);
static void idnsRcodeCount(int, int);
+static void idnsVCClosed(int fd, void *data);
static unsigned short idnsQueryID(void);
static void
@@ -732,18 +738,19 @@
}
static void
-idnsSentQueryVC(int fd, char *buf, size_t size, comm_err_t flag, int xerrno, void *data)
+idnsSentQueryVC(const Comm::ConnectionPointer &conn, char *buf, size_t size, comm_err_t flag, int xerrno, void *data)
{
nsvc * vc = (nsvc *)data;
if (flag == COMM_ERR_CLOSING)
return;
- if (fd_table[fd].closing())
+ // XXX: irrelevant now that we have conn pointer?
+ if (!Comm::IsConnOpen(conn) || fd_table[conn->fd].closing())
return;
if (flag != COMM_OK || size <= 0) {
- comm_close(fd);
+ conn->close();
return;
}
@@ -769,32 +776,36 @@
// Comm needs seconds but idnsCheckQueue() will check the exact timeout
const int timeout = (Config.Timeout.idns_query % 1000 ?
Config.Timeout.idns_query + 1000 : Config.Timeout.idns_query) / 1000;
+ AsyncCall::Pointer nil;
- commSetTimeout(vc->fd, timeout, NULL, NULL);
+ commSetConnTimeout(vc->conn, timeout, nil);
AsyncCall::Pointer call = commCbCall(78, 5, "idnsSentQueryVC",
CommIoCbPtrFun(&idnsSentQueryVC, vc));
-
- Comm::Write(vc->fd, mb, call);
+ Comm::Write(vc->conn, mb, call);
delete mb;
}
static void
-idnsInitVCConnected(int fd, const DnsLookupDetails &details, comm_err_t status, int xerrno, void *data)
+idnsInitVCConnected(const Comm::ConnectionPointer &conn, comm_err_t status, int xerrno, void *data)
{
nsvc * vc = (nsvc *)data;
- if (status != COMM_OK) {
+ if (status != COMM_OK || !conn) {
char buf[MAX_IPSTRLEN] = "";
if (vc->ns < nns)
nameservers[vc->ns].S.NtoA(buf,MAX_IPSTRLEN);
- debugs(78, 1, HERE << "Failed to connect to nameserver " << buf << " using TCP: " << details);
- comm_close(fd);
+ debugs(78, 1, HERE << "Failed to connect to nameserver " << buf << " using TCP.");
return;
}
- comm_read(fd, (char *)&vc->msglen, 2 , idnsReadVCHeader, vc);
+ vc->conn = conn;
+
+ comm_add_close_handler(conn->fd, idnsVCClosed, vc);
+ AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVCHeader",
+ CommIoCbPtrFun(idnsReadVCHeader, vc));
+ comm_read(conn, (char *)&vc->msglen, 2, call);
vc->busy = 0;
idnsDoSendQueryVC(vc);
}
@@ -805,6 +816,7 @@
nsvc * vc = (nsvc *)data;
delete vc->queue;
delete vc->msg;
+ vc->conn = NULL;
if (vc->ns < nns) // XXX: idnsShutdown may have freed nameservers[]
nameservers[vc->ns].vc = NULL;
cbdataFree(vc);
@@ -813,44 +825,29 @@
static void
idnsInitVC(int ns)
{
- char buf[MAX_IPSTRLEN];
-
nsvc *vc = cbdataAlloc(nsvc);
assert(ns < nns);
+ assert(vc->conn == NULL); // MUST be NULL from the construction process!
nameservers[ns].vc = vc;
vc->ns = ns;
+ vc->queue = new MemBuf;
+ vc->msg = new MemBuf;
+ vc->busy = 1;
- Ip::Address addr;
+ Comm::ConnectionPointer conn = new Comm::Connection();
if (!Config.Addrs.udp_outgoing.IsNoAddr())
- addr = Config.Addrs.udp_outgoing;
+ conn->local = Config.Addrs.udp_outgoing;
else
- addr = Config.Addrs.udp_incoming;
-
- if (nameservers[ns].S.IsIPv4() && !addr.SetIPv4()) {
- debugs(31, DBG_CRITICAL, "ERROR: Cannot contact DNS nameserver " << nameservers[ns].S << " from " << addr);
- addr.SetAnyAddr();
- addr.SetIPv4();
- }
-
- vc->queue = new MemBuf;
-
- vc->msg = new MemBuf;
-
- vc->fd = comm_open(SOCK_STREAM,
- IPPROTO_TCP,
- addr,
- COMM_NONBLOCKING,
- "DNS TCP Socket");
-
- if (vc->fd < 0)
- fatal("Could not create a DNS socket");
-
- comm_add_close_handler(vc->fd, idnsVCClosed, vc);
-
- vc->busy = 1;
-
- commConnectStart(vc->fd, nameservers[ns].S.NtoA(buf,MAX_IPSTRLEN), nameservers[ns].S.GetPort(), idnsInitVCConnected, vc);
+ conn->local = Config.Addrs.udp_incoming;
+
+ conn->remote = nameservers[ns].S;
+
+ AsyncCall::Pointer call = commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected, vc));
+
+ Comm::ConnOpener *cs = new Comm::ConnOpener(conn, call, Config.Timeout.connect);
+ cs->setHost("DNS TCP Socket");
+ AsyncJob::Start(cs);
}
static void
@@ -1385,7 +1382,7 @@
}
static void
-idnsReadVC(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
+idnsReadVC(const Comm::ConnectionPointer &conn, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
{
nsvc * vc = (nsvc *)data;
@@ -1393,29 +1390,32 @@
return;
if (flag != COMM_OK || len <= 0) {
- comm_close(fd);
+ if (Comm::IsConnOpen(conn))
+ conn->close();
return;
}
vc->msg->size += len; // XXX should not access -> size directly
if (vc->msg->contentSize() < vc->msglen) {
- comm_read(fd, buf + len, vc->msglen - vc->msg->contentSize(), idnsReadVC, vc);
+ AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVC",
+ CommIoCbPtrFun(idnsReadVC, vc));
+ comm_read(conn, buf+len, vc->msglen - vc->msg->contentSize(), call);
return;
}
assert(vc->ns < nns);
- debugs(78, 3, "idnsReadVC: FD " << fd << ": received " <<
- (int) vc->msg->contentSize() << " bytes via tcp from " <<
- nameservers[vc->ns].S << ".");
+ debugs(78, 3, HERE << conn << ": received " << vc->msg->contentSize() << " bytes via TCP from " << nameservers[vc->ns].S << ".");
idnsGrokReply(vc->msg->buf, vc->msg->contentSize(), vc->ns);
vc->msg->clean();
- comm_read(fd, (char *)&vc->msglen, 2 , idnsReadVCHeader, vc);
+ AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVCHeader",
+ CommIoCbPtrFun(idnsReadVCHeader, vc));
+ comm_read(conn, (char *)&vc->msglen, 2, call);
}
static void
-idnsReadVCHeader(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
+idnsReadVCHeader(const Comm::ConnectionPointer &conn, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
{
nsvc * vc = (nsvc *)data;
@@ -1423,7 +1423,8 @@
return;
if (flag != COMM_OK || len <= 0) {
- comm_close(fd);
+ if (Comm::IsConnOpen(conn))
+ conn->close();
return;
}
@@ -1432,7 +1433,9 @@
assert(vc->read_msglen <= 2);
if (vc->read_msglen < 2) {
- comm_read(fd, buf + len, 2 - vc->read_msglen, idnsReadVCHeader, vc);
+ AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVCHeader",
+ CommIoCbPtrFun(idnsReadVCHeader, vc));
+ comm_read(conn, buf+len, 2 - vc->read_msglen, call);
return;
}
@@ -1441,7 +1444,9 @@
vc->msglen = ntohs(vc->msglen);
vc->msg->init(vc->msglen, vc->msglen);
- comm_read(fd, vc->msg->buf, vc->msglen, idnsReadVC, vc);
+ AsyncCall::Pointer call = commCbCall(5,4, "idnsReadVC",
+ CommIoCbPtrFun(idnsReadVC, vc));
+ comm_read(conn, vc->msg->buf, vc->msglen, call);
}
/*
@@ -1585,8 +1590,8 @@
for (int i = 0; i < nns; i++) {
if (nsvc *vc = nameservers[i].vc) {
- if (vc->fd >= 0)
- comm_close(vc->fd);
+ if (Comm::IsConnOpen(vc->conn))
+ vc->conn->close();
}
}
=== modified file 'src/errorpage.cc'
--- src/errorpage.cc 2011-03-16 09:29:40 +0000
+++ src/errorpage.cc 2011-03-26 05:02:22 +0000
@@ -32,6 +32,7 @@
*
*/
#include "config.h"
+#include "comm/Connection.h"
#include "comm/Write.h"
#include "errorpage.h"
#if USE_AUTH
@@ -485,11 +486,11 @@
}
void
-errorSend(int fd, ErrorState * err)
+errorSend(const Comm::ConnectionPointer &conn, ErrorState * err)
{
HttpReply *rep;
- debugs(4, 3, "errorSend: FD " << fd << ", err=" << err);
- assert(fd >= 0);
+ debugs(4, 3, HERE << conn << ", err=" << err);
+ assert(Comm::IsConnOpen(conn));
/*
* ugh, this is how we make sure error codes get back to
* the client side for logging and error tracking.
@@ -506,7 +507,7 @@
MemBuf *mb = rep->pack();
AsyncCall::Pointer call = commCbCall(78, 5, "errorSendComplete",
CommIoCbPtrFun(&errorSendComplete, err));
- Comm::Write(fd, mb, call);
+ Comm::Write(conn, mb, call);
delete mb;
delete rep;
@@ -522,18 +523,18 @@
* closing the FD, otherwise we do it ourselves.
*/
static void
-errorSendComplete(int fd, char *bufnotused, size_t size, comm_err_t errflag, int xerrno, void *data)
+errorSendComplete(const Comm::ConnectionPointer &conn, char *bufnotused, size_t size, comm_err_t errflag, int xerrno, void *data)
{
ErrorState *err = static_cast(data);
- debugs(4, 3, "errorSendComplete: FD " << fd << ", size=" << size);
+ debugs(4, 3, HERE << conn << ", size=" << size);
if (errflag != COMM_ERR_CLOSING) {
if (err->callback) {
debugs(4, 3, "errorSendComplete: callback");
- err->callback(fd, err->callback_data, size);
+ err->callback(conn->fd, err->callback_data, size);
} else {
- comm_close(fd);
debugs(4, 3, "errorSendComplete: comm_close");
+ conn->close();
}
}
=== modified file 'src/errorpage.h'
--- src/errorpage.h 2011-02-07 10:27:53 +0000
+++ src/errorpage.h 2011-03-26 05:03:52 +0000
@@ -39,6 +39,7 @@
#include "auth/UserRequest.h"
#endif
#include "cbdata.h"
+#include "comm/forward.h"
#include "ip/Address.h"
#if USE_SSL
#include "ssl/ErrorDetail.h"
@@ -199,7 +200,7 @@
* This function generates a error page from the info contained
* by err and then sends it to the client.
* The callback function errorSendComplete() is called after
- * the page has been written to the client socket (fd).
+ * the page has been written to the client (clientConn).
* errorSendComplete() deallocates err. We need to add
* err to the cbdata because comm_write() requires it
* for all callback data pointers.
@@ -210,10 +211,10 @@
* for errors and use errorAppendEntry() to account for
* persistent/pipeline connections.
*
- \param fd socket where page object is to be written
- \param err This object is destroyed after use in this function.
+ \param clientConn socket where page object is to be written
+ \param err This object is destroyed after use in this function.
*/
-SQUIDCEXTERN void errorSend(int fd, ErrorState *err);
+SQUIDCEXTERN void errorSend(const Comm::ConnectionPointer &conn, ErrorState *err);
/**
\ingroup ErrorPageAPI
=== modified file 'src/esi/Esi.cc'
--- src/esi/Esi.cc 2010-12-13 11:31:14 +0000
+++ src/esi/Esi.cc 2011-03-12 00:57:48 +0000
@@ -41,6 +41,7 @@
#include "esi/Esi.h"
#include "clientStream.h"
#include "client_side_request.h"
+#include "comm/Connection.h"
#include "errorpage.h"
#include "esi/Segment.h"
#include "esi/Element.h"
@@ -1459,7 +1460,8 @@
/* don't honour range requests - for errors we send it all */
flags.error = 1;
/* create an error object */
- ErrorState * err = clientBuildError(errorpage, errorstatus, NULL, http->getConn()->peer, http->request);
+ // XXX: with the in-direction on remote IP. does the http->getConn()->clientConnection exist?
+ ErrorState * err = clientBuildError(errorpage, errorstatus, NULL, http->getConn()->clientConnection->remote, http->request);
err->err_msg = errormessage;
errormessage = NULL;
rep = err->BuildHttpReply();
=== modified file 'src/eui/Eui48.cc'
--- src/eui/Eui48.cc 2011-01-28 07:58:53 +0000
+++ src/eui/Eui48.cc 2011-03-26 05:04:58 +0000
@@ -156,7 +156,7 @@
// return binary representation of the EUI
bool
-Eui::Eui48::lookup(Ip::Address &c)
+Eui::Eui48::lookup(const Ip::Address &c)
{
struct arpreq arpReq;
#if !_SQUID_WINDOWS_
=== modified file 'src/eui/Eui48.h'
--- src/eui/Eui48.h 2010-11-27 01:58:38 +0000
+++ src/eui/Eui48.h 2010-11-27 02:52:51 +0000
@@ -64,7 +64,7 @@
bool encode(char *buf, const int len);
// lookup an EUI-48 / MAC address via ARP
- bool lookup(Ip::Address &c);
+ bool lookup(const Ip::Address &c);
private:
unsigned char eui[SZ_EUI48_BUF];
=== modified file 'src/eui/Eui64.cc'
--- src/eui/Eui64.cc 2010-07-25 08:10:12 +0000
+++ src/eui/Eui64.cc 2010-10-03 09:58:30 +0000
@@ -36,7 +36,7 @@
// return binary representation of the EUI
bool
-Eui::Eui64::lookup(Ip::Address &c)
+Eui::Eui64::lookup(const Ip::Address &c)
{
/* try to short-circuit slow OS lookups by using SLAAC data */
if (lookupSlaac(c)) return true;
@@ -46,7 +46,7 @@
}
bool
-Eui::Eui64::lookupSlaac(Ip::Address &c)
+Eui::Eui64::lookupSlaac(const Ip::Address &c)
{
/* RFC 4291 Link-Local unicast addresses which contain SLAAC - usually trustable. */
if (c.IsSiteLocal6() && c.IsSlaac() ) {
@@ -63,7 +63,7 @@
// return binary representation of the EUI
bool
-Eui::Eui64::lookupNdp(Ip::Address &c)
+Eui::Eui64::lookupNdp(const Ip::Address &c)
{
#if 0 /* no actual lookup coded yet */
=== modified file 'src/eui/Eui64.h'
--- src/eui/Eui64.h 2010-11-27 01:58:38 +0000
+++ src/eui/Eui64.h 2010-11-27 02:52:51 +0000
@@ -71,13 +71,13 @@
bool encode(char *buf, const int len);
// lookup an EUI-64 address via IPv6 SLAAC or NDP
- bool lookup(Ip::Address &c);
+ bool lookup(const Ip::Address &c);
// lookup an EUI-64 address via IPv6 NDP
- bool lookupNdp(Ip::Address &c);
+ bool lookupNdp(const Ip::Address &c);
// lookup an EUI-64 address via decoding the IPv6 address SLAAC data
- bool lookupSlaac(Ip::Address &c);
+ bool lookupSlaac(const Ip::Address &c);
private:
unsigned char eui[SZ_EUI64_BUF];
=== modified file 'src/external_acl.cc'
--- src/external_acl.cc 2011-03-02 07:27:24 +0000
+++ src/external_acl.cc 2011-03-03 06:23:45 +0000
@@ -59,6 +59,7 @@
#endif
#include "ip/tools.h"
#include "client_side.h"
+#include "comm/Connection.h"
#include "HttpRequest.h"
#include "HttpReply.h"
#include "helper.h"
@@ -926,12 +927,14 @@
#if USE_SQUID_EUI
case _external_acl_format::EXT_ACL_SRCEUI48:
- if (request->client_eui48.encode(buf, sizeof(buf)))
+ if (request->clientConnectionManager.valid() && request->clientConnectionManager->clientConnection != NULL &&
+ request->clientConnectionManager->clientConnection->remoteEui48.encode(buf, sizeof(buf)))
str = buf;
break;
case _external_acl_format::EXT_ACL_SRCEUI64:
- if (request->client_eui64.encode(buf, sizeof(buf)))
+ if (request->clientConnectionManager.valid() && request->clientConnectionManager->clientConnection != NULL &&
+ request->clientConnectionManager->clientConnection->remoteEui64.encode(buf, sizeof(buf)))
str = buf;
break;
#endif
@@ -1021,8 +1024,8 @@
case _external_acl_format::EXT_ACL_USER_CERT_RAW:
- if (ch->conn() != NULL) {
- SSL *ssl = fd_table[ch->conn()->fd].ssl;
+ if (ch->conn() != NULL && Comm::IsConnOpen(ch->conn()->clientConnection)) {
+ SSL *ssl = fd_table[ch->conn()->clientConnection->fd].ssl;
if (ssl)
str = sslGetUserCertificatePEM(ssl);
@@ -1032,8 +1035,8 @@
case _external_acl_format::EXT_ACL_USER_CERTCHAIN_RAW:
- if (ch->conn() != NULL) {
- SSL *ssl = fd_table[ch->conn()->fd].ssl;
+ if (ch->conn() != NULL && Comm::IsConnOpen(ch->conn()->clientConnection)) {
+ SSL *ssl = fd_table[ch->conn()->clientConnection->fd].ssl;
if (ssl)
str = sslGetUserCertificateChainPEM(ssl);
@@ -1043,8 +1046,8 @@
case _external_acl_format::EXT_ACL_USER_CERT:
- if (ch->conn() != NULL) {
- SSL *ssl = fd_table[ch->conn()->fd].ssl;
+ if (ch->conn() != NULL && Comm::IsConnOpen(ch->conn()->clientConnection)) {
+ SSL *ssl = fd_table[ch->conn()->clientConnection->fd].ssl;
if (ssl)
str = sslGetUserAttribute(ssl, format->header);
@@ -1054,8 +1057,8 @@
case _external_acl_format::EXT_ACL_CA_CERT:
- if (ch->conn() != NULL) {
- SSL *ssl = fd_table[ch->conn()->fd].ssl;
+ if (ch->conn() != NULL && Comm::IsConnOpen(ch->conn()->clientConnection)) {
+ SSL *ssl = fd_table[ch->conn()->clientConnection->fd].ssl;
if (ssl)
str = sslGetCAAttribute(ssl, format->header);
=== modified file 'src/fd.cc'
--- src/fd.cc 2011-01-10 09:43:43 +0000
+++ src/fd.cc 2011-01-26 10:44:23 +0000
@@ -105,6 +105,9 @@
{
fde *F = &fd_table[fd];
+ assert(fd >= 0);
+ assert(F->flags.open == 1);
+
if (F->type == FD_FILE) {
assert(F->read_handler == NULL);
assert(F->write_handler == NULL);
=== modified file 'src/forward.cc'
--- src/forward.cc 2011-03-02 20:43:21 +0000
+++ src/forward.cc 2011-03-26 05:16:22 +0000
@@ -36,6 +36,9 @@
#include "acl/FilledChecklist.h"
#include "acl/Gadgets.h"
#include "CacheManager.h"
+#include "comm/Connection.h"
+#include "comm/ConnOpener.h"
+#include "CommCalls.h"
#include "comm/Loops.h"
#include "event.h"
#include "errorpage.h"
@@ -46,6 +49,7 @@
#include "ip/QosConfig.h"
#include "MemObject.h"
#include "pconn.h"
+#include "PeerSelectState.h"
#include "SquidTime.h"
#include "Store.h"
#include "icmp/net_db.h"
@@ -57,17 +61,14 @@
#include "ssl/ErrorDetail.h"
#endif
-static PSC fwdStartCompleteWrapper;
+static PSC fwdPeerSelectionCompleteWrapper;
static PF fwdServerClosedWrapper;
#if USE_SSL
static PF fwdNegotiateSSLWrapper;
#endif
-static PF fwdConnectTimeoutWrapper;
-static EVH fwdConnectStartWrapper;
static CNCB fwdConnectDoneWrapper;
static OBJH fwdStats;
-static void fwdServerFree(FwdServer * fs);
#define MAX_FWD_STATS_IDX 9
static int FwdReplyCodes[MAX_FWD_STATS_IDX + 1][HTTP_INVALID_HEADER + 1];
@@ -81,24 +82,23 @@
FwdState* fwd = (FwdState*)d;
Pointer tmp = fwd; // Grab a temporary pointer to keep the object alive during our scope.
- if (fwd->server_fd >= 0) {
- comm_close(fwd->server_fd);
- fwd->server_fd = -1;
+ if (Comm::IsConnOpen(fwd->serverConnection())) {
+ comm_remove_close_handler(fwd->serverConnection()->fd, fwdServerClosedWrapper, fwd);
}
-
+ fwd->serverDestinations.clean();
fwd->self = NULL;
}
/**** PUBLIC INTERFACE ********************************************************/
-FwdState::FwdState(int fd, StoreEntry * e, HttpRequest * r)
+FwdState::FwdState(const Comm::ConnectionPointer &client, StoreEntry * e, HttpRequest * r)
{
+ debugs(17, 1, HERE << "Forwarding client request " << client << ", url=" << e->url() );
entry = e;
- client_fd = fd;
- server_fd = -1;
+ clientConn = client;
request = HTTPMSGLOCK(r);
start_t = squid_curtime;
-
+ serverDestinations.reserve(Config.forward_max_tries);
e->lock();
EBIT_SET(e->flags, ENTRY_FWD_HDR_WAIT);
}
@@ -116,10 +116,7 @@
// Otherwise we are going to leak our object.
entry->registerAbort(FwdState::abort, this);
- peerSelect(request, entry, fwdStartCompleteWrapper, this);
-
- // TODO: set self _after_ the peer is selected because we do not need
- // self until we start talking to some Server.
+ peerSelect(&serverDestinations, request, entry, fwdPeerSelectionCompleteWrapper, this);
}
void
@@ -161,8 +158,6 @@
if (! flags.forward_completed)
completed();
- serversFree(&servers);
-
doneWithRetries();
HTTPMSGUNLOCK(request);
@@ -176,14 +171,18 @@
entry = NULL;
- int fd = server_fd;
-
- if (fd > -1) {
- server_fd = -1;
- comm_remove_close_handler(fd, fwdServerClosedWrapper, this);
- debugs(17, 3, "fwdStateFree: closing FD " << fd);
- comm_close(fd);
- }
+ if (calls.connector != NULL) {
+ calls.connector->cancel("FwdState destructed");
+ calls.connector = NULL;
+ }
+
+ if (Comm::IsConnOpen(serverConn)) {
+ comm_remove_close_handler(serverConnection()->fd, fwdServerClosedWrapper, this);
+ debugs(17, 3, HERE << "closing FD " << serverConnection()->fd);
+ serverConn->close();
+ }
+
+ serverDestinations.clean();
debugs(17, 3, HERE << "FwdState destructor done");
}
@@ -194,7 +193,7 @@
* allocate a FwdState.
*/
void
-FwdState::fwdStart(int client_fd, StoreEntry *entry, HttpRequest *request)
+FwdState::fwdStart(const Comm::ConnectionPointer &clientConn, StoreEntry *entry, HttpRequest *request)
{
/** \note
* client_addr == no_addr indicates this is an "internal" request
@@ -227,7 +226,7 @@
}
}
- debugs(17, 3, "FwdState::start() '" << entry->url() << "'");
+ debugs(17, 3, HERE << "'" << entry->url() << "'");
/*
* This seems like an odd place to bind mem_obj and request.
* Might want to assert that request is NULL at this point
@@ -252,7 +251,7 @@
return;
case AnyP::PROTO_CACHE_OBJECT:
- CacheManager::GetInstance()->Start(client_fd, request, entry);
+ CacheManager::GetInstance()->Start(clientConn, request, entry);
return;
case AnyP::PROTO_URN:
@@ -260,14 +259,7 @@
return;
default:
- FwdState::Pointer fwd = new FwdState(client_fd, entry, request);
-
- /* If we need to transparently proxy the request
- * then we need the client source protocol, address and port */
- if (request->flags.spoof_client_ip) {
- fwd->src = request->client_addr;
- }
-
+ FwdState::Pointer fwd = new FwdState(clientConn, entry, request);
fwd->start(fwd);
return;
}
@@ -276,6 +268,22 @@
}
void
+FwdState::startConnectionOrFail()
+{
+ debugs(17, 3, HERE << entry->url() );
+
+ if (serverDestinations.size() > 0) {
+ connectStart();
+ } else {
+ debugs(17, 3, HERE << entry->url() );
+ ErrorState *anErr = errorCon(ERR_CANNOT_FORWARD, HTTP_SERVICE_UNAVAILABLE, request);
+ anErr->xerrno = errno;
+ fail(anErr);
+ self = NULL; // refcounted
+ }
+}
+
+void
FwdState::fail(ErrorState * errorState)
{
debugs(17, 3, HERE << err_type_str[errorState->type] << " \"" << httpStatusString(errorState->httpStatus) << "\"\n\t" << entry->url() );
@@ -295,13 +303,22 @@
* Frees fwdState without closing FD or generating an abort
*/
void
+FwdState::unregister(Comm::ConnectionPointer &conn)
+{
+ debugs(17, 3, HERE << entry->url() );
+ assert(serverConnection() == conn);
+ assert(Comm::IsConnOpen(conn));
+ comm_remove_close_handler(conn->fd, fwdServerClosedWrapper, this);
+ serverConn = NULL;
+}
+
+// Legacy method to be removed in favor of the above as soon as possible
+void
FwdState::unregister(int fd)
{
- debugs(17, 3, HERE << entry->url() );
- assert(fd == server_fd);
- assert(fd > -1);
- comm_remove_close_handler(fd, fwdServerClosedWrapper, this);
- server_fd = -1;
+ debugs(17, 3, HERE << entry->url() );
+ assert(fd == serverConnection()->fd);
+ unregister(serverConn);
}
/**
@@ -313,9 +330,8 @@
void
FwdState::complete()
{
- StoreEntry *e = entry;
assert(entry->store_status == STORE_PENDING);
- debugs(17, 3, HERE << e->url() << "\n\tstatus " << entry->getReply()->sline.status );
+ debugs(17, 3, HERE << entry->url() << "\n\tstatus " << entry->getReply()->sline.status );
#if URL_CHECKSUM_DEBUG
entry->mem_obj->checkUrlChecksum();
@@ -324,20 +340,27 @@
logReplyStatus(n_tries, entry->getReply()->sline.status);
if (reforward()) {
- debugs(17, 3, "fwdComplete: re-forwarding " << entry->getReply()->sline.status << " " << e->url());
-
- if (server_fd > -1)
- unregister(server_fd);
-
- e->reset();
-
- startComplete(servers);
+ assert(serverDestinations.size() > 0);
+ debugs(17, 3, HERE << "re-forwarding " << entry->getReply()->sline.status << " " << entry->url());
+
+ if (Comm::IsConnOpen(serverConn))
+ unregister(serverConn);
+
+ entry->reset();
+
+ /* the call to reforward() has already dropped the last path off the
+ * selection list. all we have now are the next path(s) to be tried.
+ */
+ connectStart();
} else {
- debugs(17, 3, "fwdComplete: server FD " << server_fd << " not re-forwarding status " << entry->getReply()->sline.status);
+ if (Comm::IsConnOpen(serverConn))
+ debugs(17, 3, HERE << "server FD " << serverConnection()->fd << " not re-forwarding status " << entry->getReply()->sline.status);
+ else
+ debugs(17, 3, HERE << "server (FD closed) not re-forwarding status " << entry->getReply()->sline.status);
EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
entry->complete();
- if (server_fd < 0)
+ if (!Comm::IsConnOpen(serverConn))
completed();
self = NULL; // refcounted
@@ -348,10 +371,10 @@
/**** CALLBACK WRAPPERS ************************************************************/
static void
-fwdStartCompleteWrapper(FwdServer * servers, void *data)
+fwdPeerSelectionCompleteWrapper(Comm::ConnectionList * unused, void *data)
{
FwdState *fwd = (FwdState *) data;
- fwd->startComplete(servers);
+ fwd->startConnectionOrFail();
}
static void
@@ -361,13 +384,6 @@
fwd->serverClosed(fd);
}
-static void
-fwdConnectStartWrapper(void *data)
-{
- FwdState *fwd = (FwdState *) data;
- fwd->connectStart();
-}
-
#if USE_SSL
static void
fwdNegotiateSSLWrapper(int fd, void *data)
@@ -378,28 +394,11 @@
#endif
-static void
-fwdConnectDoneWrapper(int server_fd, const DnsLookupDetails &dns, comm_err_t status, int xerrno, void *data)
-{
- FwdState *fwd = (FwdState *) data;
- fwd->connectDone(server_fd, dns, status, xerrno);
-}
-
-static void
-fwdConnectTimeoutWrapper(int fd, void *data)
-{
- FwdState *fwd = (FwdState *) data;
- fwd->connectTimeout(fd);
-}
-
-/*
- * Accounts for closed persistent connections
- */
-static void
-fwdPeerClosed(int fd, void *data)
-{
- peer *p = (peer *)data;
- p->stats.conn_open--;
+void
+fwdConnectDoneWrapper(const Comm::ConnectionPointer &conn, comm_err_t status, int xerrno, void *data)
+{
+ FwdState *fwd = (FwdState *) data;
+ fwd->connectDone(conn, status, xerrno);
}
/**** PRIVATE *****************************************************************/
@@ -496,10 +495,7 @@
void
FwdState::serverClosed(int fd)
{
- debugs(17, 2, "fwdServerClosed: FD " << fd << " " << entry->url());
- assert(server_fd == fd);
- server_fd = -1;
-
+ debugs(17, 2, HERE << "FD " << fd << " " << entry->url());
retryOrBail();
}
@@ -507,46 +503,36 @@
FwdState::retryOrBail()
{
if (checkRetry()) {
- int originserver = (servers->_peer == NULL);
- debugs(17, 3, "fwdServerClosed: re-forwarding (" << n_tries << " tries, " << (squid_curtime - start_t) << " secs)");
-
- if (servers->next) {
- /* use next, or cycle if origin server isn't last */
- FwdServer *fs = servers;
- FwdServer **T, *T2 = NULL;
- servers = fs->next;
-
- for (T = &servers; *T; T2 = *T, T = &(*T)->next);
- if (T2 && T2->_peer) {
- /* cycle */
- *T = fs;
- fs->next = NULL;
- } else {
- /* Use next. The last "direct" entry is retried multiple times */
- servers = fs->next;
- fwdServerFree(fs);
- originserver = 0;
+ debugs(17, 3, HERE << "re-forwarding (" << n_tries << " tries, " << (squid_curtime - start_t) << " secs)");
+
+ serverDestinations.shift(); // last one failed. try another.
+
+ if (serverDestinations.size() > 0) {
+ /* Ditch error page if it was created before.
+ * A new one will be created if there's another problem */
+ if (err) {
+ errorStateFree(err);
+ err = NULL;
}
- }
-
- /* Ditch error page if it was created before.
- * A new one will be created if there's another problem */
- if (err) {
- errorStateFree(err);
- err = NULL;
- }
-
- /* use eventAdd to break potential call sequence loops and to slow things down a little */
- eventAdd("fwdConnectStart", fwdConnectStartWrapper, this, originserver ? 0.05 : 0.005, 0);
-
- return;
+
+ connectStart();
+ return;
+ }
+ // else bail. no more serverDestinations possible to try.
+
+ // produce cannot-forward error, but only if no more specific one exists
+ if (!err) {
+ ErrorState *anErr = errorCon(ERR_CANNOT_FORWARD, HTTP_INTERNAL_SERVER_ERROR, request);
+ errorAppendEntry(entry, anErr);
+ }
}
// TODO: should we call completed() here and move doneWithRetries there?
doneWithRetries();
if (self != NULL && !err && shutting_down) {
- errorCon(ERR_SHUTTING_DOWN, HTTP_SERVICE_UNAVAILABLE, request);
+ ErrorState *anErr = errorCon(ERR_SHUTTING_DOWN, HTTP_SERVICE_UNAVAILABLE, request);
+ errorAppendEntry(entry, anErr);
}
self = NULL; // refcounted
@@ -566,9 +552,8 @@
void
FwdState::handleUnregisteredServerEnd()
{
- debugs(17, 2, "handleUnregisteredServerEnd: self=" << self <<
- " err=" << err << ' ' << entry->url());
- assert(server_fd < 0);
+ debugs(17, 2, HERE << "self=" << self << " err=" << err << ' ' << entry->url());
+ assert(!Comm::IsConnOpen(serverConn));
retryOrBail();
}
@@ -576,7 +561,6 @@
void
FwdState::negotiateSSL(int fd)
{
- FwdServer *fs = servers;
SSL *ssl = fd_table[fd].ssl;
int ret;
@@ -616,21 +600,20 @@
fail(anErr);
- if (fs->_peer) {
- peerConnectFailed(fs->_peer);
- fs->_peer->stats.conn_open--;
+ if (serverConnection()->getPeer()) {
+ peerConnectFailed(serverConnection()->getPeer());
}
- comm_close(fd);
+ serverConn->close();
return;
}
}
- if (fs->_peer && !SSL_session_reused(ssl)) {
- if (fs->_peer->sslSession)
- SSL_SESSION_free(fs->_peer->sslSession);
+ if (serverConnection()->getPeer() && !SSL_session_reused(ssl)) {
+ if (serverConnection()->getPeer()->sslSession)
+ SSL_SESSION_free(serverConnection()->getPeer()->sslSession);
- fs->_peer->sslSession = SSL_get1_session(ssl);
+ serverConnection()->getPeer()->sslSession = SSL_get1_session(ssl);
}
dispatch();
@@ -639,11 +622,10 @@
void
FwdState::initiateSSL()
{
- FwdServer *fs = servers;
- int fd = server_fd;
SSL *ssl;
SSL_CTX *sslContext = NULL;
- peer *peer = fs->_peer;
+ const peer *peer = serverConnection()->getPeer();
+ int fd = serverConnection()->fd;
if (peer) {
assert(peer->use_ssl);
@@ -703,188 +685,173 @@
#endif
void
-FwdState::connectDone(int aServerFD, const DnsLookupDetails &dns, comm_err_t status, int xerrno)
+FwdState::connectDone(const Comm::ConnectionPointer &conn, comm_err_t status, int xerrno)
{
- FwdServer *fs = servers;
- assert(server_fd == aServerFD);
-
- request->recordLookup(dns);
-
- if (Config.onoff.log_ip_on_direct && status != COMM_ERR_DNS && fs->code == HIER_DIRECT)
- updateHierarchyInfo();
-
- if (status == COMM_ERR_DNS) {
- /*
- * Only set the dont_retry flag if the DNS lookup fails on
- * a direct connection. If DNS lookup fails when trying
- * a neighbor cache, we may want to retry another option.
- */
-
- if (NULL == fs->_peer)
- flags.dont_retry = 1;
-
- debugs(17, 4, "fwdConnectDone: Unknown host: " << request->GetHost());
-
- ErrorState *const anErr = makeConnectingError(ERR_DNS_FAIL);
-
- anErr->dnsError = dns.error;
-
- fail(anErr);
-
- comm_close(server_fd);
- } else if (status != COMM_OK) {
- assert(fs);
+ if (status != COMM_OK) {
ErrorState *const anErr = makeConnectingError(ERR_CONNECT_FAIL);
anErr->xerrno = xerrno;
-
fail(anErr);
- if (fs->_peer)
- peerConnectFailed(fs->_peer);
-
- comm_close(server_fd);
- } else {
- debugs(17, 3, "fwdConnectDone: FD " << server_fd << ": '" << entry->url() << "'" );
-
- if (fs->_peer)
- peerConnectSucceded(fs->_peer);
+ /* it might have been a timeout with a partially open link */
+ if (conn != NULL) {
+ if (conn->getPeer())
+ peerConnectFailed(conn->getPeer());
+
+ conn->close();
+ }
+ retryOrBail();
+ return;
+ }
+
+ serverConn = conn;
+
+#if REDUNDANT_NOW
+ if (Config.onoff.log_ip_on_direct && serverConnection()->peerType == HIER_DIRECT)
+ updateHierarchyInfo();
+#endif
+
+ debugs(17, 3, HERE << serverConnection() << ": '" << entry->url() << "'" );
+
+ comm_add_close_handler(serverConnection()->fd, fwdServerClosedWrapper, this);
+
+ if (serverConnection()->getPeer())
+ peerConnectSucceded(serverConnection()->getPeer());
+
+ updateHierarchyInfo();
#if USE_SSL
-
- if ((fs->_peer && fs->_peer->use_ssl) ||
- (!fs->_peer && request->protocol == AnyP::PROTO_HTTPS)) {
- initiateSSL();
- return;
- }
-
+ if ((serverConnection()->getPeer() && serverConnection()->getPeer()->use_ssl) ||
+ (!serverConnection()->getPeer() && request->protocol == AnyP::PROTO_HTTPS)) {
+ initiateSSL();
+ return;
+ }
#endif
- dispatch();
- }
+
+ dispatch();
}
void
FwdState::connectTimeout(int fd)
{
- FwdServer *fs = servers;
-
debugs(17, 2, "fwdConnectTimeout: FD " << fd << ": '" << entry->url() << "'" );
- assert(fd == server_fd);
+ assert(serverDestinations[0] != NULL);
+ assert(fd == serverDestinations[0]->fd);
- if (Config.onoff.log_ip_on_direct && fs->code == HIER_DIRECT && fd_table[fd].ipaddr[0])
+ if (Config.onoff.log_ip_on_direct && serverDestinations[0]->peerType == HIER_DIRECT)
updateHierarchyInfo();
if (entry->isEmpty()) {
ErrorState *anErr = errorCon(ERR_CONNECT_FAIL, HTTP_GATEWAY_TIMEOUT, request);
anErr->xerrno = ETIMEDOUT;
fail(anErr);
- /*
- * This marks the peer DOWN ...
- */
-
- if (servers)
- if (servers->_peer)
- peerConnectFailed(servers->_peer);
- }
-
- comm_close(fd);
+
+ /* This marks the peer DOWN ... */
+ if (serverDestinations[0]->getPeer())
+ peerConnectFailed(serverDestinations[0]->getPeer());
+ }
+
+ if (Comm::IsConnOpen(serverDestinations[0])) {
+ serverDestinations[0]->close();
+ }
}
+/**
+ * Called after Forwarding path selection (via peer select) has taken place.
+ * And whenever forwarding needs to attempt a new connection (routing failover)
+ * We have a vector of possible localIP->remoteIP paths now ready to start being connected.
+ */
void
FwdState::connectStart()
{
- const char *url = entry->url();
- int fd = -1;
- FwdServer *fs = servers;
- const char *host;
- unsigned short port;
- int ctimeout;
- int ftimeout = Config.Timeout.forward - (squid_curtime - start_t);
+ assert(serverDestinations.size() > 0);
- Ip::Address outgoing;
- Ip::Address client_addr;
- assert(fs);
- assert(server_fd == -1);
- debugs(17, 3, "fwdConnectStart: " << url);
+ debugs(17, 3, "fwdConnectStart: " << entry->url());
if (n_tries == 0) // first attempt
request->hier.first_conn_start = current_time;
- if (fs->_peer) {
- ctimeout = fs->_peer->connect_timeout > 0 ? fs->_peer->connect_timeout
- : Config.Timeout.peer_connect;
+ /* connection timeout */
+ int ctimeout;
+ if (serverDestinations[0]->getPeer()) {
+ ctimeout = serverDestinations[0]->getPeer()->connect_timeout > 0 ?
+ serverDestinations[0]->getPeer()->connect_timeout : Config.Timeout.peer_connect;
} else {
ctimeout = Config.Timeout.connect;
}
- if (request->flags.spoof_client_ip) {
- if (!fs->_peer || !fs->_peer->options.no_tproxy)
- client_addr = request->client_addr;
- // else no tproxy today ...
- }
-
+ /* calculate total forwarding timeout ??? */
+ int ftimeout = Config.Timeout.forward - (squid_curtime - start_t);
if (ftimeout < 0)
ftimeout = 5;
if (ftimeout < ctimeout)
ctimeout = ftimeout;
-
request->flags.pinned = 0;
- if (fs->code == PINNED) {
+ if (serverDestinations[0]->peerType == PINNED) {
ConnStateData *pinned_connection = request->pinnedConnection();
assert(pinned_connection);
- fd = pinned_connection->validatePinnedConnection(request, fs->_peer);
- if (fd >= 0) {
- pinned_connection->unpinConnection();
+ serverConn = pinned_connection->validatePinnedConnection(request, serverDestinations[0]->getPeer());
+ if (Comm::IsConnOpen(serverConn)) {
+ pinned_connection->unpinConnection(); // XXX: this should be just remove the pinning close handler ??
#if 0
- if (!fs->_peer)
- fs->code = HIER_DIRECT;
+ if (!serverConn->getPeer())
+ serverConn->peerType = HIER_DIRECT;
#endif
- server_fd = fd;
n_tries++;
request->flags.pinned = 1;
if (pinned_connection->pinnedAuth())
request->flags.auth = 1;
- comm_add_close_handler(fd, fwdServerClosedWrapper, this);
updateHierarchyInfo();
- connectDone(fd, DnsLookupDetails(), COMM_OK, 0);
+ dispatch();
return;
}
/* Failure. Fall back on next path */
- debugs(17,2,HERE << " Pinned connection " << pinned_connection << " not valid. Releasing.");
+ debugs(17, 2, HERE << " Pinned connection " << pinned_connection << " not valid. Releasing.");
request->releasePinnedConnection();
- servers = fs->next;
- fwdServerFree(fs);
- connectStart();
+ serverDestinations.shift();
+ startConnectionOrFail();
return;
}
- if (fs->_peer) {
- host = fs->_peer->host;
- port = fs->_peer->http_port;
- fd = fwdPconnPool->pop(fs->_peer->name, fs->_peer->http_port, request->GetHost(), client_addr, checkRetriable());
+ // Use pconn to avoid opening a new connection.
+ const char *host;
+ int port;
+ if (serverDestinations[0]->getPeer()) {
+ host = serverDestinations[0]->getPeer()->host;
+ port = serverDestinations[0]->getPeer()->http_port;
} else {
host = request->GetHost();
port = request->port;
- fd = fwdPconnPool->pop(host, port, NULL, client_addr, checkRetriable());
}
- if (fd >= 0) {
- debugs(17, 3, "fwdConnectStart: reusing pconn FD " << fd);
- server_fd = fd;
+ serverDestinations[0]->remote.SetPort(port);
+ Comm::ConnectionPointer temp = fwdPconnPool->pop(serverDestinations[0], host, checkRetriable());
+
+ // if we found an open persistent connection to use. use it.
+ if (temp != NULL && Comm::IsConnOpen(temp)) {
+ serverConn = temp;
+ debugs(17, 3, HERE << "reusing pconn " << serverConnection());
n_tries++;
- if (!fs->_peer)
+ if (!serverConnection()->getPeer())
origin_tries++;
updateHierarchyInfo();
-
- comm_add_close_handler(fd, fwdServerClosedWrapper, this);
-
- // TODO: Avoid this if %local_port is often cached.
- request->hier.peer_local_port = comm_local_port(fd);
+ comm_add_close_handler(serverConnection()->fd, fwdServerClosedWrapper, this);
+
+ /* Update server side TOS and Netfilter mark on the connection. */
+ if (Ip::Qos::TheConfig.isAclTosActive()) {
+ temp->tos = GetTosToServer(request);
+ Ip::Qos::setSockTos(temp, temp->tos);
+ }
+#if SO_MARK
+ if (Ip::Qos::TheConfig.isAclNfmarkActive()) {
+ temp->nfmark = GetNfmarkToServer(request);
+ Ip::Qos::setSockNfmark(temp, temp->nfmark);
+ }
+#endif
dispatch();
-
return;
}
@@ -892,123 +859,39 @@
entry->mem_obj->checkUrlChecksum();
#endif
- outgoing = getOutgoingAddr(request, fs->_peer);
-
- // if IPv6 is disabled try to force IPv4-only outgoing.
- if (!Ip::EnableIpv6 && !outgoing.SetIPv4()) {
- debugs(50, 4, "fwdConnectStart: IPv6 is Disabled. Cannot connect from " << outgoing);
- ErrorState *anErr = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE, request);
- anErr->xerrno = EAFNOSUPPORT;
- fail(anErr);
- self = NULL; // refcounted
- return;
- }
-
- // if IPv6 is split-stack, prefer IPv4
- if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK) {
- // NP: This is not a great choice of default,
- // but with the current Internet being IPv4-majority has a higher success rate.
- // if setting to IPv4 fails we dont care, that just means to use IPv6 outgoing.
- outgoing.SetIPv4();
- }
-
- tos_t tos = GetTosToServer(request);
-
+ /* Get the server side TOS and Netfilter mark to be set on the connection. */
+ if (Ip::Qos::TheConfig.isAclTosActive()) {
+ serverDestinations[0]->tos = GetTosToServer(request);
+ }
#if SO_MARK
- nfmark_t mark = GetNfmarkToServer(request);
- debugs(17, 3, "fwdConnectStart: got outgoing addr " << outgoing << ", tos " << int(tos)
- << ", netfilter mark " << mark);
+ serverDestinations[0]->nfmark = GetNfmarkToServer(request);
+ debugs(17, 3, "fwdConnectStart: got outgoing addr " << serverDestinations[0]->local << ", tos " << int(serverDestinations[0]->tos)
+ << ", netfilter mark " << serverDestinations[0]->nfmark);
#else
- nfmark_t mark = 0;
- debugs(17, 3, "fwdConnectStart: got outgoing addr " << outgoing << ", tos " << int(tos));
+ serverDestinations[0]->nfmark = 0;
+ debugs(17, 3, "fwdConnectStart: got outgoing addr " << serverDestinations[0]->local << ", tos " << int(serverDestinations[0]->tos));
#endif
- int commFlags = COMM_NONBLOCKING;
- if (request->flags.spoof_client_ip) {
- if (!fs->_peer || !fs->_peer->options.no_tproxy)
- commFlags |= COMM_TRANSPARENT;
- // else no tproxy today ...
- }
-
- fd = comm_openex(SOCK_STREAM, IPPROTO_TCP, outgoing, commFlags, tos, mark, url);
-
- debugs(17, 3, "fwdConnectStart: got TCP FD " << fd);
-
- if (fd < 0) {
- debugs(50, 4, "fwdConnectStart: " << xstrerror());
- ErrorState *anErr = errorCon(ERR_SOCKET_FAILURE, HTTP_INTERNAL_SERVER_ERROR, request);
- anErr->xerrno = errno;
- fail(anErr);
- self = NULL; // refcounted
- return;
- }
-
- server_fd = fd;
- n_tries++;
-
- if (!fs->_peer)
- origin_tries++;
-
- request->hier.peer_local_port = comm_local_port(fd);
-
- /*
- * stats.conn_open is used to account for the number of
- * connections that we have open to the peer, so we can limit
- * based on the max-conn option. We need to increment here,
- * even if the connection may fail.
- */
-
- if (fs->_peer) {
- fs->_peer->stats.conn_open++;
- comm_add_close_handler(fd, fwdPeerClosed, fs->_peer);
- }
-
- comm_add_close_handler(fd, fwdServerClosedWrapper, this);
-
- commSetTimeout(fd, ctimeout, fwdConnectTimeoutWrapper, this);
-
- updateHierarchyInfo();
- commConnectStart(fd, host, port, fwdConnectDoneWrapper, this);
-}
-
-void
-FwdState::startComplete(FwdServer * theServers)
-{
- debugs(17, 3, "fwdStartComplete: " << entry->url() );
-
- if (theServers != NULL) {
- servers = theServers;
- connectStart();
- } else {
- startFail();
- }
-}
-
-void
-FwdState::startFail()
-{
- debugs(17, 3, "fwdStartFail: " << entry->url() );
- ErrorState *anErr = errorCon(ERR_CANNOT_FORWARD, HTTP_SERVICE_UNAVAILABLE, request);
- anErr->xerrno = errno;
- fail(anErr);
- self = NULL; // refcounted
+ calls.connector = commCbCall(17,3, "fwdConnectDoneWrapper", CommConnectCbPtrFun(fwdConnectDoneWrapper, this));
+ Comm::ConnOpener *cs = new Comm::ConnOpener(serverDestinations[0], calls.connector, ctimeout);
+ cs->setHost(host);
+ AsyncJob::Start(cs);
}
void
FwdState::dispatch()
{
- peer *p = NULL;
- debugs(17, 3, "fwdDispatch: FD " << client_fd << ": Fetching '" << RequestMethodStr(request->method) << " " << entry->url() << "'" );
+ debugs(17, 3, HERE << clientConn << ": Fetching '" << RequestMethodStr(request->method) << " " << entry->url() << "'");
/*
* Assert that server_fd is set. This is to guarantee that fwdState
* is attached to something and will be deallocated when server_fd
* is closed.
*/
- assert(server_fd > -1);
-
- fd_note(server_fd, entry->url());
-
- fd_table[server_fd].noteUse(fwdPconnPool);
+ assert(Comm::IsConnOpen(serverConn));
+
+ fd_note(serverConnection()->fd, entry->url());
+
+ fd_table[serverConnection()->fd].noteUse(fwdPconnPool);
/*assert(!EBIT_TEST(entry->flags, ENTRY_DISPATCHED)); */
assert(entry->ping_status != PING_WAITING);
@@ -1019,48 +902,33 @@
netdbPingSite(request->GetHost());
- /* Update server side TOS and Netfilter mark if using persistent connections. */
- if (Config.onoff.server_pconns) {
- if (Ip::Qos::TheConfig.isAclTosActive()) {
- tos_t tos = GetTosToServer(request);
- Ip::Qos::setSockTos(server_fd, tos);
- }
-#if SO_MARK
- if (Ip::Qos::TheConfig.isAclNfmarkActive()) {
- nfmark_t mark = GetNfmarkToServer(request);
- Ip::Qos::setSockNfmark(server_fd, mark);
- }
-#endif
- }
-
/* Retrieves remote server TOS or MARK value, and stores it as part of the
* original client request FD object. It is later used to forward
* remote server's TOS/MARK in the response to the client in case of a MISS.
*/
if (Ip::Qos::TheConfig.isHitNfmarkActive()) {
- fde * clientFde = &fd_table[client_fd];
- fde * servFde = &fd_table[server_fd];
- if (clientFde && servFde) {
+ if (Comm::IsConnOpen(clientConn) && Comm::IsConnOpen(serverConnection())) {
+ fde * clientFde = &fd_table[clientConn->fd]; // XXX: move the fd_table access into Ip::Qos
/* Get the netfilter mark for the connection */
- Ip::Qos::getNfmarkFromServer(server_fd, servFde, clientFde);
+ Ip::Qos::getNfmarkFromServer(serverConnection(), clientFde);
}
}
#if _SQUID_LINUX_
/* Bug 2537: The TOS forward part of QOS only applies to patched Linux kernels. */
if (Ip::Qos::TheConfig.isHitTosActive()) {
- fde * clientFde = &fd_table[client_fd];
- if (clientFde) {
+ if (Comm::IsConnOpen(clientConn)) {
+ fde * clientFde = &fd_table[clientConn->fd]; // XXX: move the fd_table access into Ip::Qos
/* Get the TOS value for the packet */
- Ip::Qos::getTosFromServer(server_fd, clientFde);
+ Ip::Qos::getTosFromServer(serverConnection(), clientFde);
}
}
#endif
- if (servers && (p = servers->_peer)) {
- p->stats.fetches++;
- request->peer_login = p->login;
- request->peer_domain = p->domain;
+ if (serverConnection()->getPeer() != NULL) {
+ serverConnection()->getPeer()->stats.fetches++;
+ request->peer_login = serverConnection()->getPeer()->login;
+ request->peer_domain = serverConnection()->getPeer()->domain;
httpStart(this);
} else {
request->peer_login = NULL;
@@ -1111,11 +979,13 @@
*/
request->flags.proxy_keepalive = 0;
/*
- * Set the dont_retry flag becuase this is not a
+ * Set the dont_retry flag because this is not a
* transient (network) error; its a bug.
*/
flags.dont_retry = 1;
- comm_close(server_fd);
+ if (Comm::IsConnOpen(serverConn)) {
+ serverConn->close();
+ }
break;
}
}
@@ -1125,7 +995,7 @@
* FwdState::reforward
*
* returns TRUE if the transaction SHOULD be re-forwarded to the
- * next choice in the FwdServers list. This method is called when
+ * next choice in the serverDestinations list. This method is called when
* server-side communication completes normally, or experiences
* some error after receiving the end of HTTP headers.
*/
@@ -1133,7 +1003,6 @@
FwdState::reforward()
{
StoreEntry *e = entry;
- FwdServer *fs = servers;
http_status s;
assert(e->store_status == STORE_PENDING);
assert(e->mem_obj);
@@ -1142,10 +1011,10 @@
e->mem_obj->checkUrlChecksum();
#endif
- debugs(17, 3, "fwdReforward: " << e->url() << "?" );
+ debugs(17, 3, HERE << e->url() << "?" );
if (!EBIT_TEST(e->flags, ENTRY_FWD_HDR_WAIT)) {
- debugs(17, 3, "fwdReforward: No, ENTRY_FWD_HDR_WAIT isn't set");
+ debugs(17, 3, HERE << "No, ENTRY_FWD_HDR_WAIT isn't set");
return 0;
}
@@ -1158,19 +1027,15 @@
if (request->bodyNibbled())
return 0;
- assert(fs);
-
- servers = fs->next;
-
- fwdServerFree(fs);
-
- if (servers == NULL) {
- debugs(17, 3, "fwdReforward: No forward-servers left");
+ serverDestinations.shift();
+
+ if (serverDestinations.size() == 0) {
+ debugs(17, 3, HERE << "No alternative forwarding paths left");
return 0;
}
s = e->getReply()->sline.status;
- debugs(17, 3, "fwdReforward: status " << s);
+ debugs(17, 3, HERE << "status " << s);
return reforwardableStatus(s);
}
@@ -1246,27 +1111,22 @@
/**
* Decide where details need to be gathered to correctly describe a persistent connection.
* What is needed:
- * - host name of server at other end of this link (either peer or requested host)
- * - port to which we connected the other end of this link (for peer or request)
- * - domain for which the connection is supposed to be used
- * - address of the client for which we made the connection
+ * - the address/port details about this link
+ * - domain name of server at other end of this link (either peer or requested host)
*/
void
-FwdState::pconnPush(int fd, const peer *_peer, const HttpRequest *req, const char *domain, Ip::Address &client_addr)
+FwdState::pconnPush(Comm::ConnectionPointer &conn, const char *domain)
{
- if (_peer) {
- fwdPconnPool->push(fd, _peer->name, _peer->http_port, domain, client_addr);
+ if (conn->getPeer()) {
+ fwdPconnPool->push(conn, conn->getPeer()->name);
} else {
- /* small performance improvement, using NULL for domain instead of listing it twice */
- /* although this will leave a gap open for url-rewritten domains to share a link */
- fwdPconnPool->push(fd, req->GetHost(), req->port, NULL, client_addr);
+ fwdPconnPool->push(conn, domain);
}
}
void
FwdState::initModule()
{
- memDataInit(MEM_FWD_SERVER, "FwdServer", sizeof(FwdServer), 0);
RegisterWithCacheManager();
}
@@ -1282,9 +1142,7 @@
if (status > HTTP_INVALID_HEADER)
return;
- assert(tries);
-
- tries--;
+ assert(tries >= 0);
if (tries > MAX_FWD_STATS_IDX)
tries = MAX_FWD_STATS_IDX;
@@ -1292,17 +1150,6 @@
FwdReplyCodes[tries][status]++;
}
-void
-FwdState::serversFree(FwdServer ** FSVR)
-{
- FwdServer *fs;
-
- while ((fs = *FSVR)) {
- *FSVR = fs->next;
- fwdServerFree(fs);
- }
-}
-
/** From Comment #5 by Henrik Nordstrom made at
http://www.squid-cache.org/bugs/show_bug.cgi?id=2391 on 2008-09-19
@@ -1321,54 +1168,30 @@
{
assert(request);
- FwdServer *fs = servers;
- assert(fs);
-
- const char *nextHop = NULL;
-
- if (fs->_peer) {
+ assert(serverDestinations.size() > 0);
+
+ char nextHop[256];
+
+ if (serverConnection()->getPeer()) {
// went to peer, log peer host name
- nextHop = fs->_peer->name;
+ snprintf(nextHop,256,"%s", serverConnection()->getPeer()->name);
} else {
// went DIRECT, must honor log_ip_on_direct
-
- // XXX: or should we use request->host_addr here? how?
- assert(server_fd >= 0);
- nextHop = fd_table[server_fd].ipaddr;
- if (!Config.onoff.log_ip_on_direct || !nextHop[0])
- nextHop = request->GetHost(); // domain name
+ if (!Config.onoff.log_ip_on_direct)
+ snprintf(nextHop,256,"%s",request->GetHost()); // domain name
+ else
+ serverConnection()->remote.NtoA(nextHop, 256);
}
- assert(nextHop);
- hierarchyNote(&request->hier, fs->code, nextHop);
+ request->hier.peer_local_port = serverConnection()->local.GetPort();
+
+ assert(nextHop[0]);
+ hierarchyNote(&request->hier, serverConnection()->peerType, nextHop);
}
/**** PRIVATE NON-MEMBER FUNCTIONS ********************************************/
-static void
-fwdServerFree(FwdServer * fs)
-{
- cbdataReferenceDone(fs->_peer);
- memFree(fs, MEM_FWD_SERVER);
-}
-
-static Ip::Address
-aclMapAddr(acl_address * head, ACLChecklist * ch)
-{
- acl_address *l;
-
- Ip::Address addr;
-
- for (l = head; l; l = l->next) {
- if (!l->aclList || ch->matchAclListFast(l->aclList))
- return l->addr;
- }
-
- addr.SetAnyAddr();
- return addr;
-}
-
/*
* DPW 2007-05-19
* Formerly static, but now used by client_side_request.cc
@@ -1401,27 +1224,39 @@
return 0;
}
-Ip::Address
-getOutgoingAddr(HttpRequest * request, struct peer *dst_peer)
+void
+getOutgoingAddress(HttpRequest * request, Comm::ConnectionPointer conn)
{
+ /* skip if an outgoing address is already set. */
+ if (!conn->local.IsAnyAddr()) return;
+
+ // maybe use TPROXY client address
if (request && request->flags.spoof_client_ip) {
- if (!dst_peer || !dst_peer->options.no_tproxy) {
+ if (!conn->getPeer() || !conn->getPeer()->options.no_tproxy) {
#if FOLLOW_X_FORWARDED_FOR && LINUX_NETFILTER
if (Config.onoff.tproxy_uses_indirect_client)
- return request->indirect_client_addr;
+ conn->local = request->indirect_client_addr;
else
#endif
- return request->client_addr;
+ conn->local = request->client_addr;
+ // some flags need setting on the socket to use this address
+ conn->flags |= COMM_DOBIND;
+ conn->flags |= COMM_TRANSPARENT;
+ return;
}
// else no tproxy today ...
}
if (!Config.accessList.outgoing_address) {
- return Ip::Address(); // anything will do.
+ return; // anything will do.
}
ACLFilledChecklist ch(NULL, request, NULL);
- ch.dst_peer = dst_peer;
+ ch.dst_peer = conn->getPeer();
+ ch.dst_addr = conn->remote;
+
+ // TODO use the connection details in ACL.
+ // needs a bit of rework in ACLFilledChecklist to use Comm::Connection instead of ConnStateData
if (request) {
#if FOLLOW_X_FORWARDED_FOR
@@ -1433,7 +1268,18 @@
ch.my_addr = request->my_addr;
}
- return aclMapAddr(Config.accessList.outgoing_address, &ch);
+ acl_address *l;
+ for (l = Config.accessList.outgoing_address; l; l = l->next) {
+
+ /* check if the outgoing address is usable to the destination */
+ if (conn->remote.IsIPv4() != l->addr.IsIPv4()) continue;
+
+ /* check ACLs for this outgoing address */
+ if (!l->aclList || ch.matchAclListFast(l->aclList)) {
+ conn->local = l->addr;
+ return;
+ }
+ }
}
tos_t
=== modified file 'src/forward.h'
--- src/forward.h 2010-12-12 05:30:58 +0000
+++ src/forward.h 2011-01-08 11:32:09 +0000
@@ -7,8 +7,10 @@
class HttpRequest;
#include "comm.h"
-#include "hier_code.h"
+#include "comm/Connection.h"
+#include "fde.h"
#include "ip/Address.h"
+#include "Array.h"
/**
* Returns the TOS value that we should be setting on the connection
@@ -23,14 +25,6 @@
nfmark_t GetNfmarkToServer(HttpRequest * request);
-class FwdServer
-{
-public:
- peer *_peer; /* NULL --> origin server */
- hier_code code;
- FwdServer *next;
-};
-
class FwdState : public RefCountable
{
public:
@@ -38,10 +32,10 @@
~FwdState();
static void initModule();
- static void fwdStart(int fd, StoreEntry *, HttpRequest *);
- void startComplete(FwdServer *);
- void startFail();
+ static void fwdStart(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *);
+ void startConnectionOrFail();
void fail(ErrorState *err);
+ void unregister(Comm::ConnectionPointer &conn);
void unregister(int fd);
void complete();
void handleUnregisteredServerEnd();
@@ -49,28 +43,25 @@
bool reforwardableStatus(http_status s);
void serverClosed(int fd);
void connectStart();
- void connectDone(int server_fd, const DnsLookupDetails &dns, comm_err_t status, int xerrno);
+ void connectDone(const Comm::ConnectionPointer & conn, comm_err_t status, int xerrno);
void connectTimeout(int fd);
void initiateSSL();
void negotiateSSL(int fd);
bool checkRetry();
bool checkRetriable();
void dispatch();
- void pconnPush(int fd, const peer *_peer, const HttpRequest *req, const char *domain, Ip::Address &client_addr);
+ void pconnPush(Comm::ConnectionPointer & conn, const char *domain);
bool dontRetry() { return flags.dont_retry; }
void dontRetry(bool val) { flags.dont_retry = val; }
- bool ftpPasvFailed() { return flags.ftp_pasv_failed; }
-
- void ftpPasvFailed(bool val) { flags.ftp_pasv_failed = val; }
-
- static void serversFree(FwdServer **);
+ /** return a ConnectionPointer to the current server connection (may or may not be open) */
+ Comm::ConnectionPointer const & serverConnection() const { return serverConn; };
private:
// hidden for safer management of self; use static fwdStart
- FwdState(int fd, StoreEntry *, HttpRequest *);
+ FwdState(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *);
void start(Pointer aSelf);
static void logReplyStatus(int tries, http_status status);
@@ -84,25 +75,30 @@
public:
StoreEntry *entry;
HttpRequest *request;
- int server_fd;
- FwdServer *servers;
static void abort(void*);
private:
Pointer self;
ErrorState *err;
- int client_fd;
+ Comm::ConnectionPointer clientConn; ///< a possibly open connection to the client.
time_t start_t;
int n_tries;
int origin_tries;
+ // AsyncCalls which we set and may need cancelling.
+ struct {
+ AsyncCall::Pointer connector; ///< a call linking us to the ConnOpener producing serverConn.
+ } calls;
+
struct {
unsigned int dont_retry:1;
- unsigned int ftp_pasv_failed:1;
unsigned int forward_completed:1;
} flags;
- Ip::Address src; /* Client address for this connection. Needed for transparent operations. */
+ /** connections to open, in order, until successful */
+ Comm::ConnectionList serverDestinations;
+
+ Comm::ConnectionPointer serverConn; ///< a successfully opened connection to a server.
// NP: keep this last. It plays with private/public
CBDATA_CLASS2(FwdState);
=== modified file 'src/fqdncache.cc'
--- src/fqdncache.cc 2011-01-27 09:29:04 +0000
+++ src/fqdncache.cc 2011-01-28 05:01:37 +0000
@@ -34,6 +34,7 @@
#include "squid.h"
#include "cbdata.h"
+#include "DnsLookupDetails.h"
#include "event.h"
#include "mgr/Registration.h"
#include "SquidTime.h"
=== modified file 'src/ftp.cc'
--- src/ftp.cc 2011-03-12 03:34:48 +0000
+++ src/ftp.cc 2011-03-26 05:18:39 +0000
@@ -34,11 +34,11 @@
#include "squid.h"
#include "comm.h"
+#include "comm/ConnOpener.h"
#include "CommCalls.h"
#include "comm/TcpAcceptor.h"
#include "comm/Write.h"
#include "compat/strtoll.h"
-#include "ConnectionDetail.h"
#include "errorpage.h"
#include "fde.h"
#include "forward.h"
@@ -71,8 +71,9 @@
/// \ingroup ServerProtocolFTPInternal
static const char *const crlf = "\r\n";
+#define CTRL_BUFLEN 1024
/// \ingroup ServerProtocolFTPInternal
-static char cbuf[1024];
+static char cbuf[CTRL_BUFLEN];
/// \ingroup ServerProtocolFTPInternal
typedef enum {
@@ -107,6 +108,7 @@
bool pasv_supported; ///< PASV command is allowed
bool epsv_all_sent; ///< EPSV ALL has been used. Must abort on failures.
bool pasv_only;
+ bool pasv_failed; // was FwdState::flags.ftp_pasv_failed
/* authentication */
bool authenticated; ///< authentication success
@@ -138,30 +140,34 @@
typedef void (FTPSM) (FtpStateData *);
/// common code for FTP control and data channels
-// does not own the channel descriptor, which is managed by FtpStateData
+/// does not own the channel descriptor, which is managed by FtpStateData
class FtpChannel
{
public:
- FtpChannel(): fd(-1) {}
+ FtpChannel() {};
/// called after the socket is opened, sets up close handler
- void opened(int aFd, const AsyncCall::Pointer &aCloser);
+ void opened(const Comm::ConnectionPointer &conn, const AsyncCall::Pointer &aCloser);
/** Handles all operations needed to properly close the active channel FD.
* clearing the close handler, clearing the listen socket properly, and calling comm_close
*/
void close();
- void clear(); /// just resets fd and close handler. does not close active connections.
-
- int fd; /// channel descriptor
-
- Ip::Address local; ///< The local IP address:port this channel is using
-
- int flags; ///< socket flags used when opening.
-
+ void clear(); ///< just drops conn and close handler. does not close active connections.
+
+ Comm::ConnectionPointer conn; ///< channel descriptor
+
+ /** A temporary handle to the connection being listened on.
+ * Closing this will also close the waiting Data channel acceptor.
+ * If a data connection has already been accepted but is still waiting in the event queue
+ * the callback will still happen and needs to be handled (usually dropped).
+ */
+ Comm::ConnectionPointer listenConn;
+
+ AsyncCall::Pointer opener; ///< Comm opener handler callback.
private:
- AsyncCall::Pointer closer; /// Comm close handler callback
+ AsyncCall::Pointer closer; ///< Comm close handler callback
};
/// \ingroup ServerProtocolFTPInternal
@@ -173,7 +179,7 @@
void operator delete (void *);
void *toCbdata() { return this; }
- FtpStateData(FwdState *);
+ FtpStateData(FwdState *, const Comm::ConnectionPointer &conn);
~FtpStateData();
char user[MAX_URL];
char password[MAX_URL];
@@ -248,14 +254,14 @@
/// ignore timeout on CTRL channel. set read timeout on DATA channel.
void switchTimeoutToDataChannel();
/// create a data channel acceptor and start listening.
- void listenForDataChannel(const int fd, const char *note);
+ void listenForDataChannel(const Comm::ConnectionPointer &conn, const char *note);
int checkAuth(const HttpHeader * req_hdr);
void checkUrlpath();
void buildTitleUrl();
void writeReplyBody(const char *, size_t len);
void printfReplyBody(const char *fmt, ...);
- virtual int dataDescriptor() const;
+ virtual const Comm::ConnectionPointer & dataDescriptor() const;
virtual void maybeReadVirginBody();
virtual void closeServer();
virtual void completeForwarding();
@@ -289,6 +295,7 @@
virtual bool doneWithServer() const;
virtual bool haveControlChannel(const char *caller_name) const;
AsyncCall::Pointer dataCloser(); /// creates a Comm close callback
+ AsyncCall::Pointer dataOpener(); /// creates a Comm connect callback
private:
// BodyConsumer for HTTP: consume request body.
@@ -458,21 +465,22 @@
FtpStateData::dataClosed(const CommCloseCbParams &io)
{
debugs(9, 4, HERE);
- if (data.fd >= 0) {
- comm_close(data.fd);
+ if (data.listenConn != NULL) {
+ data.listenConn->close();
+ data.listenConn = NULL;
// NP clear() does the: data.fd = -1;
}
data.clear();
failed(ERR_FTP_FAILURE, 0);
- /* failed closes ctrl.fd and frees ftpState */
+ /* failed closes ctrl.conn and frees ftpState */
- /* NP: failure recovery may be possible when its only a data.fd failure.
- * is the ctrl.fd is still fine, we can send ABOR down it and retry.
+ /* NP: failure recovery may be possible when its only a data.conn failure.
+ * if the ctrl.conn is still fine, we can send ABOR down it and retry.
* Just need to watch out for wider Squid states like shutting down or reconfigure.
*/
}
-FtpStateData::FtpStateData(FwdState *theFwdState) : AsyncJob("FtpStateData"), ServerStateData(theFwdState)
+FtpStateData::FtpStateData(FwdState *theFwdState, const Comm::ConnectionPointer &conn) : AsyncJob("FtpStateData"), ServerStateData(theFwdState)
{
const char *url = entry->url();
debugs(9, 3, HERE << "'" << url << "'" );
@@ -481,15 +489,14 @@
theSize = -1;
mdtm = -1;
- if (Config.Ftp.passive && !theFwdState->ftpPasvFailed())
+ if (Config.Ftp.passive && !flags.pasv_failed)
flags.pasv_supported = 1;
flags.rest_supported = 1;
typedef CommCbMemFunT Dialer;
- AsyncCall::Pointer closer = JobCallback(9, 5,
- Dialer, this, FtpStateData::ctrlClosed);
- ctrl.opened(theFwdState->server_fd, closer);
+ AsyncCall::Pointer closer = JobCallback(9, 5, Dialer, this, FtpStateData::ctrlClosed);
+ ctrl.opened(conn, closer);
if (request->method == METHOD_PUT)
flags.put = 1;
@@ -504,11 +511,15 @@
reply_hdr = NULL;
}
+ if (data.opener != NULL) {
+ data.opener->cancel("FtpStateData destructed");
+ data.opener = NULL;
+ }
data.close();
- if (ctrl.fd >= 0) {
+ if (Comm::IsConnOpen(ctrl.conn)) {
debugs(9, DBG_IMPORTANT, HERE << "Internal bug: FtpStateData left " <<
- "control FD " << ctrl.fd << " open");
+ "open control channel " << ctrl.conn);
}
if (ctrl.buf) {
@@ -611,20 +622,24 @@
debugs(9, 9, HERE << ": OUT: login='" << login << "', escaped=" << escaped << ", user=" << user << ", password=" << password);
}
+/**
+ * Cancel the timeout on the Control socket and establish one
+ * on the data socket
+ */
void
FtpStateData::switchTimeoutToDataChannel()
{
- commSetTimeout(ctrl.fd, -1, NULL, NULL);
+ commUnsetConnTimeout(ctrl.conn);
typedef CommCbMemFunT TimeoutDialer;
AsyncCall::Pointer timeoutCall = JobCallback(9, 5, TimeoutDialer, this, FtpStateData::ftpTimeout);
- commSetTimeout(data.fd, Config.Timeout.read, timeoutCall);
+ commSetConnTimeout(data.conn, Config.Timeout.read, timeoutCall);
}
void
-FtpStateData::listenForDataChannel(const int fd, const char *note)
+FtpStateData::listenForDataChannel(const Comm::ConnectionPointer &conn, const char *note)
{
- assert(data.fd < 0);
+ assert(!Comm::IsConnOpen(data.conn));
typedef CommCbMemFunT AcceptDialer;
typedef AsyncCallT AcceptCall;
@@ -632,39 +647,36 @@
Subscription::Pointer sub = new CallSubscription(call);
/* open the conn if its not already open */
- int newFd = fd;
- if (newFd < 0) {
- newFd = comm_open_listener(SOCK_STREAM, IPPROTO_TCP, data.local, data.flags, note);
- if (newFd < 0) {
- debugs(5, DBG_CRITICAL, HERE << "comm_open_listener failed:" << data.local << " error: " << errno);
+ if (!Comm::IsConnOpen(conn)) {
+ conn->fd = comm_open_listener(SOCK_STREAM, IPPROTO_TCP, conn->local, conn->flags, note);
+ if (!Comm::IsConnOpen(conn)) {
+ debugs(5, DBG_CRITICAL, HERE << "comm_open_listener failed:" << conn->local << " error: " << errno);
return;
}
- debugs(9, 3, HERE << "Unconnected data socket created on FD " << newFd << ", " << data.local);
+ debugs(9, 3, HERE << "Unconnected data socket created on " << conn);
}
- assert(newFd >= 0);
- Comm::TcpAcceptor *tmp = new Comm::TcpAcceptor(newFd, data.local, data.flags, note, sub);
- AsyncJob::Start(tmp);
+ assert(Comm::IsConnOpen(conn));
+ AsyncJob::Start(new Comm::TcpAcceptor(conn, note, sub));
// Ensure we have a copy of the FD opened for listening and a close handler on it.
- data.opened(newFd, dataCloser());
+ data.opened(conn, dataCloser());
switchTimeoutToDataChannel();
}
void
FtpStateData::ftpTimeout(const CommTimeoutCbParams &io)
{
- debugs(9, 4, "ftpTimeout: FD " << io.fd << ": '" << entry->url() << "'" );
+ debugs(9, 4, HERE << io.conn << ": '" << entry->url() << "'" );
- if (SENT_PASV == state && io.fd == data.fd) {
+ if (SENT_PASV == state && io.conn->fd == data.conn->fd) {
/* stupid ftp.netscape.com */
- fwd->dontRetry(false);
- fwd->ftpPasvFailed(true);
+ flags.pasv_supported = false;
debugs(9, DBG_IMPORTANT, "ftpTimeout: timeout in SENT_PASV state" );
}
failed(ERR_READ_TIMEOUT, 0);
- /* failed() closes ctrl.fd and frees ftpState */
+ /* failed() closes ctrl.conn and frees ftpState */
}
#if DEAD_CODE // obsoleted by ERR_DIR_LISTING
@@ -1165,10 +1177,10 @@
xfree(sbuf);
}
-int
+const Comm::ConnectionPointer &
FtpStateData::dataDescriptor() const
{
- return data.fd;
+ return data.conn;
}
void
@@ -1203,7 +1215,7 @@
void
FtpStateData::maybeReadVirginBody()
{
- if (data.fd < 0)
+ if (!Comm::IsConnOpen(data.conn))
return;
if (data.read_pending)
@@ -1221,12 +1233,12 @@
typedef CommCbMemFunT TimeoutDialer;
AsyncCall::Pointer timeoutCall = JobCallback(9, 5,
TimeoutDialer, this, FtpStateData::ftpTimeout);
- commSetTimeout(data.fd, Config.Timeout.read, timeoutCall);
+ commSetConnTimeout(data.conn, Config.Timeout.read, timeoutCall);
- debugs(9,5,HERE << "queueing read on FD " << data.fd);
+ debugs(9,5,HERE << "queueing read on FD " << data.conn->fd);
typedef CommCbMemFunT Dialer;
- entry->delayAwareRead(data.fd, data.readBuf->space(), read_sz,
+ entry->delayAwareRead(data.conn, data.readBuf->space(), read_sz,
JobCallback(9, 5, Dialer, this, FtpStateData::dataRead));
}
@@ -1248,7 +1260,7 @@
if (io.flag == COMM_ERR_CLOSING)
return;
- assert(io.fd == data.fd);
+ assert(io.fd == data.conn->fd);
if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
abortTransaction("entry aborted during dataRead");
@@ -1278,17 +1290,12 @@
typedef CommCbMemFunT TimeoutDialer;
AsyncCall::Pointer timeoutCall = JobCallback(9, 5,
TimeoutDialer, this, FtpStateData::ftpTimeout);
- commSetTimeout(io.fd, Config.Timeout.read, timeoutCall);
+ commSetConnTimeout(io.conn, Config.Timeout.read, timeoutCall);
maybeReadVirginBody();
} else {
- if (!flags.http_header_sent && !fwd->ftpPasvFailed() && flags.pasv_supported && !flags.listing) {
- fwd->dontRetry(false); /* this is a retryable error */
- fwd->ftpPasvFailed(true);
- }
-
failed(ERR_READ_ERROR, 0);
- /* failed closes ctrl.fd and frees ftpState */
+ /* failed closes ctrl.conn and frees ftpState */
return;
}
} else if (io.size == 0) {
@@ -1506,7 +1513,7 @@
void
ftpStart(FwdState * fwd)
{
- FtpStateData *ftpState = new FtpStateData(fwd);
+ FtpStateData *ftpState = new FtpStateData(fwd, fwd->serverConnection());
ftpState->start();
}
@@ -1523,9 +1530,8 @@
checkUrlpath();
buildTitleUrl();
- debugs(9, 5, HERE << "host=" << request->GetHost() << ", path=" <<
- request->urlpath << ", user=" << user << ", passwd=" <<
- password);
+ debugs(9, 5, HERE << "FD " << ctrl.conn->fd << " : host=" << request->GetHost() <<
+ ", path=" << request->urlpath << ", user=" << user << ", passwd=" << password);
state = BEGIN;
ctrl.last_command = xstrdup("Connect to server");
@@ -1583,16 +1589,15 @@
ctrl.last_command = ebuf;
- if (!canSend(ctrl.fd)) {
- debugs(9, 2, HERE << "cannot send to closing ctrl FD " << ctrl.fd);
+ if (!Comm::IsConnOpen(ctrl.conn)) {
+ debugs(9, 2, HERE << "cannot send to closing ctrl " << ctrl.conn);
// TODO: assert(ctrl.closer != NULL);
return;
}
typedef CommCbMemFunT Dialer;
- AsyncCall::Pointer call = JobCallback(9, 5,
- Dialer, this, FtpStateData::ftpWriteCommandCallback);
- Comm::Write(ctrl.fd, ctrl.last_command, strlen(ctrl.last_command), call, NULL);
+ AsyncCall::Pointer call = JobCallback(9, 5, Dialer, this, FtpStateData::ftpWriteCommandCallback);
+ Comm::Write(ctrl.conn, ctrl.last_command, strlen(ctrl.last_command), call, NULL);
scheduleReadControlReply(0);
}
@@ -1613,9 +1618,9 @@
return;
if (io.flag) {
- debugs(9, DBG_IMPORTANT, "ftpWriteCommandCallback: FD " << io.fd << ": " << xstrerr(io.xerrno));
+ debugs(9, DBG_IMPORTANT, "ftpWriteCommandCallback: " << io.conn << ": " << xstrerr(io.xerrno));
failed(ERR_WRITE_ERROR, io.xerrno);
- /* failed closes ctrl.fd and frees ftpState */
+ /* failed closes ctrl.conn and frees ftpState */
return;
}
}
@@ -1717,32 +1722,27 @@
void
FtpStateData::scheduleReadControlReply(int buffered_ok)
{
- debugs(9, 3, HERE << "FD " << ctrl.fd);
+ debugs(9, 3, HERE << ctrl.conn);
if (buffered_ok && ctrl.offset > 0) {
/* We've already read some reply data */
handleControlReply();
} else {
- /* XXX What about Config.Timeout.read? */
- typedef CommCbMemFunT Dialer;
- AsyncCall::Pointer reader = JobCallback(9, 5,
- Dialer, this, FtpStateData::ftpReadControlReply);
- comm_read(ctrl.fd, ctrl.buf + ctrl.offset, ctrl.size - ctrl.offset, reader);
/*
* Cancel the timeout on the Data socket (if any) and
* establish one on the control socket.
*/
-
- if (data.fd >= 0) {
- AsyncCall::Pointer nullCall = NULL;
- commSetTimeout(data.fd, -1, nullCall);
+ if (Comm::IsConnOpen(data.conn)) {
+ commUnsetConnTimeout(data.conn);
}
typedef CommCbMemFunT TimeoutDialer;
- AsyncCall::Pointer timeoutCall = JobCallback(9, 5,
- TimeoutDialer, this, FtpStateData::ftpTimeout);
+ AsyncCall::Pointer timeoutCall = JobCallback(9, 5, TimeoutDialer, this, FtpStateData::ftpTimeout);
+ commSetConnTimeout(ctrl.conn, Config.Timeout.read, timeoutCall);
- commSetTimeout(ctrl.fd, Config.Timeout.read, timeoutCall);
+ typedef CommCbMemFunT Dialer;
+ AsyncCall::Pointer reader = JobCallback(9, 5, Dialer, this, FtpStateData::ftpReadControlReply);
+ comm_read(ctrl.conn, ctrl.buf + ctrl.offset, ctrl.size - ctrl.offset, reader);
}
}
@@ -1777,7 +1777,7 @@
scheduleReadControlReply(0);
} else {
failed(ERR_READ_ERROR, io.xerrno);
- /* failed closes ctrl.fd and frees ftpState */
+ /* failed closes ctrl.conn and frees ftpState */
}
return;
}
@@ -1785,7 +1785,7 @@
if (io.size == 0) {
if (entry->store_status == STORE_PENDING) {
failed(ERR_FTP_FAILURE, 0);
- /* failed closes ctrl.fd and frees ftpState */
+ /* failed closes ctrl.conn and frees ftpState */
return;
}
@@ -1863,9 +1863,6 @@
if (ftpState->flags.pasv_only)
ftpState->login_att++;
- /* Dont retry if the FTP server accepted the connection */
- ftpState->fwd->dontRetry(true);
-
if (code == 220) {
if (ftpState->ctrl.message) {
if (strstr(ftpState->ctrl.message->key, "NetWare"))
@@ -1978,11 +1975,11 @@
return;
if (ftpState->proxy_host != NULL)
- snprintf(cbuf, 1024, "USER %s@%s\r\n",
+ snprintf(cbuf, CTRL_BUFLEN, "USER %s@%s\r\n",
ftpState->user,
ftpState->request->GetHost());
else
- snprintf(cbuf, 1024, "USER %s\r\n", ftpState->user);
+ snprintf(cbuf, CTRL_BUFLEN, "USER %s\r\n", ftpState->user);
ftpState->writeCommand(cbuf);
@@ -2013,7 +2010,7 @@
if (!ftpState || !ftpState->haveControlChannel("ftpSendPass"))
return;
- snprintf(cbuf, 1024, "PASS %s\r\n", ftpState->password);
+ snprintf(cbuf, CTRL_BUFLEN, "PASS %s\r\n", ftpState->password);
ftpState->writeCommand(cbuf);
ftpState->state = SENT_PASS;
}
@@ -2078,7 +2075,7 @@
else
ftpState->flags.binary = 0;
- snprintf(cbuf, 1024, "TYPE %c\r\n", mode);
+ snprintf(cbuf, CTRL_BUFLEN, "TYPE %c\r\n", mode);
ftpState->writeCommand(cbuf);
@@ -2092,7 +2089,7 @@
int code = ftpState->ctrl.replycode;
char *path;
char *d, *p;
- debugs(9, 3, HERE);
+ debugs(9, 3, HERE << "code=" << code);
if (code == 200) {
p = path = xstrdup(ftpState->request->urlpath.termedBuf());
@@ -2182,7 +2179,7 @@
ftpState->flags.no_dotdot = 0;
}
- snprintf(cbuf, 1024, "CWD %s\r\n", path);
+ snprintf(cbuf, CTRL_BUFLEN, "CWD %s\r\n", path);
ftpState->writeCommand(cbuf);
@@ -2232,7 +2229,7 @@
path = ftpState->filepath;
debugs(9, 3, HERE << "with path=" << path);
- snprintf(cbuf, 1024, "MKD %s\r\n", path);
+ snprintf(cbuf, CTRL_BUFLEN, "MKD %s\r\n", path);
ftpState->writeCommand(cbuf);
ftpState->state = SENT_MKDIR;
}
@@ -2290,7 +2287,7 @@
return;
assert(*ftpState->filepath != '\0');
- snprintf(cbuf, 1024, "MDTM %s\r\n", ftpState->filepath);
+ snprintf(cbuf, CTRL_BUFLEN, "MDTM %s\r\n", ftpState->filepath);
ftpState->writeCommand(cbuf);
ftpState->state = SENT_MDTM;
}
@@ -2327,7 +2324,7 @@
if (ftpState->flags.binary) {
assert(ftpState->filepath != NULL);
assert(*ftpState->filepath != '\0');
- snprintf(cbuf, 1024, "SIZE %s\r\n", ftpState->filepath);
+ snprintf(cbuf, CTRL_BUFLEN, "SIZE %s\r\n", ftpState->filepath);
ftpState->writeCommand(cbuf);
ftpState->state = SENT_SIZE;
} else
@@ -2367,11 +2364,7 @@
ftpReadEPSV(FtpStateData* ftpState)
{
int code = ftpState->ctrl.replycode;
- char h1, h2, h3, h4;
- int n;
- u_short port;
Ip::Address ipa_remote;
- int fd = ftpState->data.fd;
char *buf;
debugs(9, 3, HERE);
@@ -2380,7 +2373,7 @@
/* handle broken servers (RFC 2428 says OK code for EPSV MUST be 229 not 200) */
/* vsftpd for one send '200 EPSV ALL ok.' without even port info.
* Its okay to re-send EPSV 1/2 but nothing else. */
- debugs(9, DBG_IMPORTANT, "Broken FTP Server at " << fd_table[ftpState->ctrl.fd].ipaddr << ". Wrong accept code for EPSV");
+ debugs(9, DBG_IMPORTANT, "Broken FTP Server at " << ftpState->ctrl.conn->remote << ". Wrong accept code for EPSV");
} else {
debugs(9, 2, "EPSV not supported by remote end");
ftpState->state = SENT_EPSV_1; /* simulate having failed EPSV 1 (last EPSV to try before shifting to PASV) */
@@ -2403,7 +2396,7 @@
if (buf == NULL || *buf == '\0') {
/* handle broken server (RFC 2428 says MUST specify supported protocols in 522) */
- debugs(9, DBG_IMPORTANT, "Broken FTP Server at " << fd_table[ftpState->ctrl.fd].ipaddr << ". 522 error missing protocol negotiation hints");
+ debugs(9, DBG_IMPORTANT, "Broken FTP Server at " << ftpState->ctrl.conn->remote << ". 522 error missing protocol negotiation hints");
ftpSendPassive(ftpState);
} else if (strcmp(buf, "(1)") == 0) {
ftpState->state = SENT_EPSV_2; /* simulate having sent and failed EPSV 2 */
@@ -2424,7 +2417,7 @@
}
} else {
/* handle broken server (RFC 2428 says MUST specify supported protocols in 522) */
- debugs(9, DBG_IMPORTANT, "WARNING: Server at " << fd_table[ftpState->ctrl.fd].ipaddr << " sent unknown protocol negotiation hint: " << buf);
+ debugs(9, DBG_IMPORTANT, "WARNING: Server at " << ftpState->ctrl.conn->remote << " sent unknown protocol negotiation hint: " << buf);
ftpSendPassive(ftpState);
}
return;
@@ -2436,11 +2429,13 @@
buf = ftpState->ctrl.last_reply + strcspn(ftpState->ctrl.last_reply, "(");
- n = sscanf(buf, "(%c%c%c%hu%c)", &h1, &h2, &h3, &port, &h4);
+ char h1, h2, h3, h4;
+ u_short port;
+ int n = sscanf(buf, "(%c%c%c%hu%c)", &h1, &h2, &h3, &port, &h4);
- if (h1 != h2 || h1 != h3 || h1 != h4) {
+ if (n < 4 || h1 != h2 || h1 != h3 || h1 != h4) {
debugs(9, DBG_IMPORTANT, "Invalid EPSV reply from " <<
- fd_table[ftpState->ctrl.fd].ipaddr << ": " <<
+ ftpState->ctrl.conn->remote << ": " <<
ftpState->ctrl.last_reply);
ftpSendPassive(ftpState);
@@ -2449,7 +2444,7 @@
if (0 == port) {
debugs(9, DBG_IMPORTANT, "Unsafe EPSV reply from " <<
- fd_table[ftpState->ctrl.fd].ipaddr << ": " <<
+ ftpState->ctrl.conn->remote << ": " <<
ftpState->ctrl.last_reply);
ftpSendPassive(ftpState);
@@ -2459,7 +2454,7 @@
if (Config.Ftp.sanitycheck) {
if (port < 1024) {
debugs(9, DBG_IMPORTANT, "Unsafe EPSV reply from " <<
- fd_table[ftpState->ctrl.fd].ipaddr << ": " <<
+ ftpState->ctrl.conn->remote << ": " <<
ftpState->ctrl.last_reply);
ftpSendPassive(ftpState);
@@ -2469,7 +2464,7 @@
ftpState->data.port = port;
- ftpState->data.host = xstrdup(fd_table[ftpState->ctrl.fd].ipaddr);
+ ftpState->data.host = xstrdup(fd_table[ftpState->ctrl.conn->fd].ipaddr);
safe_free(ftpState->ctrl.last_command);
@@ -2477,9 +2472,19 @@
ftpState->ctrl.last_command = xstrdup("Connect to server data port");
- debugs(9, 3, HERE << "connecting to " << ftpState->data.host << ", port " << ftpState->data.port);
-
- commConnectStart(fd, ftpState->data.host, port, FtpStateData::ftpPasvCallback, ftpState);
+ // Generate a new data channel descriptor to be opened.
+ Comm::ConnectionPointer conn = new Comm::Connection;
+ conn->local = ftpState->ctrl.conn->local;
+ conn->local.SetPort(0);
+ conn->remote = ftpState->ctrl.conn->remote;
+ conn->remote.SetPort(port);
+
+ debugs(9, 3, HERE << "connecting to " << conn->remote);
+
+ ftpState->data.opener = commCbCall(9,3, "FtpStateData::ftpPasvCallback", CommConnectCbPtrFun(FtpStateData::ftpPasvCallback, ftpState));
+ Comm::ConnOpener *cs = new Comm::ConnOpener(conn, ftpState->data.opener, Config.Timeout.connect);
+ cs->setHost(ftpState->data.host);
+ AsyncJob::Start(cs);
}
/** \ingroup ServerProtocolFTPInternal
@@ -2491,9 +2496,6 @@
static void
ftpSendPassive(FtpStateData * ftpState)
{
- Ip::Address addr;
- struct addrinfo *AI = NULL;
-
/** Checks the server control channel is still available before running. */
if (!ftpState || !ftpState->haveControlChannel("ftpSendPassive"))
return;
@@ -2530,21 +2532,6 @@
}
/** \par
- * Locates the Address of the remote server. */
- addr.InitAddrInfo(AI);
-
- if (getsockname(ftpState->ctrl.fd, AI->ai_addr, &AI->ai_addrlen)) {
- /** If it cannot be located the FTP Session is killed. */
- addr.FreeAddrInfo(AI);
- debugs(9, DBG_CRITICAL, HERE << "getsockname(" << ftpState->ctrl.fd << ",'" << addr << "',...): " << xstrerror());
- ftpFail(ftpState);
- return;
- }
-
- addr = *AI;
- addr.FreeAddrInfo(AI);
-
- /** \par
* Send EPSV (ALL,2,1) or PASV on the control channel.
*
* - EPSV ALL is used if enabled.
@@ -2555,18 +2542,18 @@
switch (ftpState->state) {
case SENT_EPSV_ALL: /* EPSV ALL resulted in a bad response. Try ther EPSV methods. */
ftpState->flags.epsv_all_sent = true;
- if (addr.IsIPv6()) {
- debugs(9, 5, HERE << "FTP Channel is IPv6 (" << addr << ") attempting EPSV 2 after EPSV ALL has failed.");
- snprintf(cbuf, 1024, "EPSV 2\r\n");
+ if (ftpState->ctrl.conn->local.IsIPv6()) {
+ debugs(9, 5, HERE << "FTP Channel is IPv6 (" << ftpState->ctrl.conn->remote << ") attempting EPSV 2 after EPSV ALL has failed.");
+ snprintf(cbuf, CTRL_BUFLEN, "EPSV 2\r\n");
ftpState->state = SENT_EPSV_2;
break;
}
// else fall through to skip EPSV 2
case SENT_EPSV_2: /* EPSV IPv6 failed. Try EPSV IPv4 */
- if (addr.IsIPv4()) {
- debugs(9, 5, HERE << "FTP Channel is IPv4 (" << addr << ") attempting EPSV 1 after EPSV ALL has failed.");
- snprintf(cbuf, 1024, "EPSV 1\r\n");
+ if (ftpState->ctrl.conn->local.IsIPv4()) {
+ debugs(9, 5, HERE << "FTP Channel is IPv4 (" << ftpState->ctrl.conn->remote << ") attempting EPSV 1 after EPSV ALL has failed.");
+ snprintf(cbuf, CTRL_BUFLEN, "EPSV 1\r\n");
ftpState->state = SENT_EPSV_1;
break;
} else if (ftpState->flags.epsv_all_sent) {
@@ -2577,64 +2564,47 @@
// else fall through to skip EPSV 1
case SENT_EPSV_1: /* EPSV options exhausted. Try PASV now. */
- debugs(9, 5, HERE << "FTP Channel (" << addr << ") rejects EPSV connection attempts. Trying PASV instead.");
- snprintf(cbuf, 1024, "PASV\r\n");
+ debugs(9, 5, HERE << "FTP Channel (" << ftpState->ctrl.conn->remote << ") rejects EPSV connection attempts. Trying PASV instead.");
+ snprintf(cbuf, CTRL_BUFLEN, "PASV\r\n");
ftpState->state = SENT_PASV;
break;
default:
if (!Config.Ftp.epsv) {
- debugs(9, 5, HERE << "EPSV support manually disabled. Sending PASV for FTP Channel (" << addr <<")");
- snprintf(cbuf, 1024, "PASV\r\n");
+ debugs(9, 5, HERE << "EPSV support manually disabled. Sending PASV for FTP Channel (" << ftpState->ctrl.conn->remote <<")");
+ snprintf(cbuf, CTRL_BUFLEN, "PASV\r\n");
ftpState->state = SENT_PASV;
} else if (Config.Ftp.epsv_all) {
- debugs(9, 5, HERE << "EPSV ALL manually enabled. Attempting with FTP Channel (" << addr <<")");
- snprintf(cbuf, 1024, "EPSV ALL\r\n");
+ debugs(9, 5, HERE << "EPSV ALL manually enabled. Attempting with FTP Channel (" << ftpState->ctrl.conn->remote <<")");
+ snprintf(cbuf, CTRL_BUFLEN, "EPSV ALL\r\n");
ftpState->state = SENT_EPSV_ALL;
/* block other non-EPSV connections being attempted */
ftpState->flags.epsv_all_sent = true;
} else {
- if (addr.IsIPv6()) {
- debugs(9, 5, HERE << "FTP Channel (" << addr << "). Sending default EPSV 2");
- snprintf(cbuf, 1024, "EPSV 2\r\n");
+ if (ftpState->ctrl.conn->local.IsIPv6()) {
+ debugs(9, 5, HERE << "FTP Channel (" << ftpState->ctrl.conn->remote << "). Sending default EPSV 2");
+ snprintf(cbuf, CTRL_BUFLEN, "EPSV 2\r\n");
ftpState->state = SENT_EPSV_2;
}
- if (addr.IsIPv4()) {
- debugs(9, 5, HERE << "Channel (" << addr <<"). Sending default EPSV 1");
- snprintf(cbuf, 1024, "EPSV 1\r\n");
+ if (ftpState->ctrl.conn->local.IsIPv4()) {
+ debugs(9, 5, HERE << "Channel (" << ftpState->ctrl.conn->remote <<"). Sending default EPSV 1");
+ snprintf(cbuf, CTRL_BUFLEN, "EPSV 1\r\n");
ftpState->state = SENT_EPSV_1;
}
}
break;
}
- /** Otherwise, Open data channel with the same local address as control channel (on a new random port!) */
- addr.SetPort(0);
- int fd = comm_open(SOCK_STREAM,
- IPPROTO_TCP,
- addr,
- COMM_NONBLOCKING,
- ftpState->entry->url());
-
- debugs(9, 3, HERE << "Unconnected data socket created on FD " << fd << " from " << addr);
-
- if (fd < 0) {
- ftpFail(ftpState);
- return;
- }
-
- ftpState->data.opened(fd, ftpState->dataCloser());
ftpState->writeCommand(cbuf);
/*
* ugly hack for ftp servers like ftp.netscape.com that sometimes
- * dont acknowledge PASV commands.
+ * dont acknowledge PASV commands. Use connect timeout to be faster then read timeout (minutes).
*/
typedef CommCbMemFunT TimeoutDialer;
AsyncCall::Pointer timeoutCall = JobCallback(9, 5,
TimeoutDialer, ftpState, FtpStateData::ftpTimeout);
-
- commSetTimeout(ftpState->data.fd, 15, timeoutCall);
+ commSetConnTimeout(ftpState->ctrl.conn, Config.Timeout.connect, timeoutCall);
}
void
@@ -2675,7 +2645,6 @@
int n;
u_short port;
Ip::Address ipa_remote;
- int fd = ftpState->data.fd;
char *buf;
LOCAL_ARRAY(char, ipaddr, 1024);
debugs(9, 3, HERE);
@@ -2696,7 +2665,7 @@
if (n != 6 || p1 < 0 || p2 < 0 || p1 > 255 || p2 > 255) {
debugs(9, DBG_IMPORTANT, "Unsafe PASV reply from " <<
- fd_table[ftpState->ctrl.fd].ipaddr << ": " <<
+ ftpState->ctrl.conn->remote << ": " <<
ftpState->ctrl.last_reply);
ftpSendEPRT(ftpState);
@@ -2709,7 +2678,7 @@
if ( ipa_remote.IsAnyAddr() ) {
debugs(9, DBG_IMPORTANT, "Unsafe PASV reply from " <<
- fd_table[ftpState->ctrl.fd].ipaddr << ": " <<
+ ftpState->ctrl.conn->remote << ": " <<
ftpState->ctrl.last_reply);
ftpSendEPRT(ftpState);
@@ -2720,7 +2689,7 @@
if (0 == port) {
debugs(9, DBG_IMPORTANT, "Unsafe PASV reply from " <<
- fd_table[ftpState->ctrl.fd].ipaddr << ": " <<
+ ftpState->ctrl.conn->remote << ": " <<
ftpState->ctrl.last_reply);
ftpSendEPRT(ftpState);
@@ -2730,7 +2699,7 @@
if (Config.Ftp.sanitycheck) {
if (port < 1024) {
debugs(9, DBG_IMPORTANT, "Unsafe PASV reply from " <<
- fd_table[ftpState->ctrl.fd].ipaddr << ": " <<
+ ftpState->ctrl.conn->remote << ": " <<
ftpState->ctrl.last_reply);
ftpSendEPRT(ftpState);
@@ -2741,7 +2710,7 @@
ftpState->data.port = port;
if (Config.Ftp.sanitycheck)
- ftpState->data.host = xstrdup(fd_table[ftpState->ctrl.fd].ipaddr);
+ ftpState->data.host = xstrdup(fd_table[ftpState->ctrl.conn->fd].ipaddr);
else
ftpState->data.host = xstrdup(ipaddr);
@@ -2751,57 +2720,60 @@
ftpState->ctrl.last_command = xstrdup("Connect to server data port");
- debugs(9, 3, HERE << "connecting to " << ftpState->data.host << ", port " << ftpState->data.port);
-
- commConnectStart(fd, ipaddr, port, FtpStateData::ftpPasvCallback, ftpState);
+ Comm::ConnectionPointer conn = new Comm::Connection;
+ conn->local = ftpState->ctrl.conn->local;
+ conn->remote = ipaddr;
+ conn->remote.SetPort(port);
+
+ debugs(9, 3, HERE << "connecting to " << conn->remote);
+
+ ftpState->data.opener = commCbCall(9,3, "FtpStateData::ftpPasvCallback", CommConnectCbPtrFun(FtpStateData::ftpPasvCallback, ftpState));
+ Comm::ConnOpener *cs = new Comm::ConnOpener(conn, ftpState->data.opener, Config.Timeout.connect);
+ cs->setHost(ftpState->data.host);
+ AsyncJob::Start(cs);
}
void
-FtpStateData::ftpPasvCallback(int fd, const DnsLookupDetails &dns, comm_err_t status, int xerrno, void *data)
+FtpStateData::ftpPasvCallback(const Comm::ConnectionPointer &conn, comm_err_t status, int xerrno, void *data)
{
FtpStateData *ftpState = (FtpStateData *)data;
debugs(9, 3, HERE);
- ftpState->request->recordLookup(dns);
+ ftpState->data.opener = NULL;
if (status != COMM_OK) {
- debugs(9, 2, HERE << "Failed to connect. Retrying without PASV.");
- ftpState->fwd->dontRetry(false); /* this is a retryable error */
- ftpState->fwd->ftpPasvFailed(true);
- ftpState->failed(ERR_NONE, 0);
- /* failed closes ctrl.fd and frees ftpState */
+ debugs(9, 2, HERE << "Failed to connect. Retrying via another method.");
+
+ // ABORT on timeouts. server may be waiting on a broken TCP link.
+ if (status == COMM_TIMEOUT)
+ ftpState->writeCommand("ABOR");
+
+ // try another connection attempt with some other method
+ ftpSendPassive(ftpState);
return;
}
+ ftpState->data.opened(conn, ftpState->dataCloser());
ftpRestOrList(ftpState);
}
/// \ingroup ServerProtocolFTPInternal
-static int
+static void
ftpOpenListenSocket(FtpStateData * ftpState, int fallback)
{
- struct addrinfo *AI = NULL;
- int x = 0;
-
/// Close old data channels, if any. We may open a new one below.
- if ((ftpState->data.flags & COMM_REUSEADDR))
+ if ((ftpState->data.conn->flags & COMM_REUSEADDR))
// NP: in fact it points to the control channel. just clear it.
ftpState->data.clear();
else
ftpState->data.close();
+ ftpState->data.host = NULL;
/*
* Set up a listen socket on the same local address as the
* control connection.
*/
- ftpState->data.local.InitAddrInfo(AI);
- x = getsockname(ftpState->ctrl.fd, AI->ai_addr, &AI->ai_addrlen);
- ftpState->data.local = *AI;
- ftpState->data.local.FreeAddrInfo(AI);
-
- if (x) {
- debugs(9, DBG_CRITICAL, HERE << "getsockname(" << ftpState->ctrl.fd << ",..): " << xstrerror());
- return -1;
- }
+ Comm::ConnectionPointer temp = new Comm::Connection;
+ temp->local = ftpState->ctrl.conn->local;
/*
* REUSEADDR is needed in fallback mode, since the same port is
@@ -2809,29 +2781,21 @@
*/
if (fallback) {
int on = 1;
- setsockopt(ftpState->ctrl.fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));
- ftpState->ctrl.flags |= COMM_REUSEADDR;
- ftpState->data.flags |= COMM_REUSEADDR;
+ setsockopt(ftpState->ctrl.conn->fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));
+ ftpState->ctrl.conn->flags |= COMM_REUSEADDR;
+ temp->flags |= COMM_REUSEADDR;
} else {
/* if not running in fallback mode a new port needs to be retrieved */
- ftpState->data.local.SetPort(0);
- ftpState->data.flags = COMM_NONBLOCKING;
+ temp->local.SetPort(0);
}
- ftpState->listenForDataChannel((fallback?ftpState->ctrl.fd:-1), ftpState->entry->url());
- return ftpState->data.fd;
+ ftpState->listenForDataChannel(temp, ftpState->entry->url());
}
/// \ingroup ServerProtocolFTPInternal
static void
ftpSendPORT(FtpStateData * ftpState)
{
- int fd;
- Ip::Address ipa;
- struct addrinfo *AI = NULL;
- unsigned char *addrptr;
- unsigned char *portptr;
-
/* check the server control channel is still available */
if (!ftpState || !ftpState->haveControlChannel("ftpSendPort"))
return;
@@ -2843,36 +2807,36 @@
debugs(9, 3, HERE);
ftpState->flags.pasv_supported = 0;
- fd = ftpOpenListenSocket(ftpState, 0);
- ipa.InitAddrInfo(AI);
+ ftpOpenListenSocket(ftpState, 0);
- if (getsockname(fd, AI->ai_addr, &AI->ai_addrlen)) {
- ipa.FreeAddrInfo(AI);
- debugs(9, DBG_CRITICAL, HERE << "getsockname(" << fd << ",..): " << xstrerror());
+ if (!Comm::IsConnOpen(ftpState->data.listenConn)) {
+ if ( ftpState->data.listenConn != NULL && !ftpState->data.listenConn->local.IsIPv4() ) {
+ /* non-IPv4 CANNOT send PORT command. */
+ /* we got here by attempting and failing an EPRT */
+ /* using the same reply code should simulate a PORT failure */
+ ftpReadPORT(ftpState);
+ return;
+ }
/* XXX Need to set error message */
ftpFail(ftpState);
return;
}
- if ( AI->ai_addrlen != sizeof(struct sockaddr_in) ) {
- ipa.FreeAddrInfo(AI);
- /* IPv6 CANNOT send PORT command. */
- /* we got here by attempting and failing an EPRT */
- /* using the same reply code should simulate a PORT failure */
- ftpReadPORT(ftpState);
- return;
- }
+ // pull out the internal IP address bytes to send in PORT command...
+ // source them from the listen_conn->local
- addrptr = (unsigned char *) &((struct sockaddr_in*)AI->ai_addr)->sin_addr;
- portptr = (unsigned char *) &((struct sockaddr_in*)AI->ai_addr)->sin_port;
- snprintf(cbuf, 1024, "PORT %d,%d,%d,%d,%d,%d\r\n",
+ struct addrinfo *AI = NULL;
+ ftpState->data.listenConn->local.GetAddrInfo(AI, AF_INET);
+ unsigned char *addrptr = (unsigned char *) &((struct sockaddr_in*)AI->ai_addr)->sin_addr;
+ unsigned char *portptr = (unsigned char *) &((struct sockaddr_in*)AI->ai_addr)->sin_port;
+ snprintf(cbuf, CTRL_BUFLEN, "PORT %d,%d,%d,%d,%d,%d\r\n",
addrptr[0], addrptr[1], addrptr[2], addrptr[3],
portptr[0], portptr[1]);
ftpState->writeCommand(cbuf);
ftpState->state = SENT_PORT;
- ipa.FreeAddrInfo(AI);
+ ftpState->data.listenConn->local.FreeAddrInfo(AI);
}
/// \ingroup ServerProtocolFTPInternal
@@ -2907,40 +2871,28 @@
return;
}
- int fd;
- Ip::Address addr;
- struct addrinfo *AI = NULL;
+ debugs(9, 3, HERE);
+ ftpState->flags.pasv_supported = 0;
+
+ ftpOpenListenSocket(ftpState, 0);
+ debugs(9, 3, "Listening for FTP data connection with FD " << ftpState->data.conn);
+ if (!Comm::IsConnOpen(ftpState->data.conn)) {
+ /* XXX Need to set error message */
+ ftpFail(ftpState);
+ return;
+ }
+
char buf[MAX_IPSTRLEN];
- debugs(9, 3, HERE);
- ftpState->flags.pasv_supported = 0;
- fd = ftpOpenListenSocket(ftpState, 0);
- debugs(9, 3, "Listening for FTP data connection with FD " << fd);
-
- Ip::Address::InitAddrInfo(AI);
-
- if (getsockname(fd, AI->ai_addr, &AI->ai_addrlen)) {
- Ip::Address::FreeAddrInfo(AI);
- debugs(9, DBG_CRITICAL, HERE << "getsockname(" << fd << ",..): " << xstrerror());
-
- /* XXX Need to set error message */
- ftpFail(ftpState);
- return;
- }
-
- addr = *AI;
-
/* RFC 2428 defines EPRT as IPv6 equivalent to IPv4 PORT command. */
/* Which can be used by EITHER protocol. */
- snprintf(cbuf, 1024, "EPRT |%d|%s|%d|\r\n",
- ( addr.IsIPv6() ? 2 : 1 ),
- addr.NtoA(buf,MAX_IPSTRLEN),
- addr.GetPort() );
+ snprintf(cbuf, CTRL_BUFLEN, "EPRT |%d|%s|%d|\r\n",
+ ( ftpState->data.listenConn->local.IsIPv6() ? 2 : 1 ),
+ ftpState->data.listenConn->local.NtoA(buf,MAX_IPSTRLEN),
+ ftpState->data.listenConn->local.GetPort() );
ftpState->writeCommand(cbuf);
ftpState->state = SENT_EPRT;
-
- Ip::Address::FreeAddrInfo(AI);
}
static void
@@ -2966,12 +2918,30 @@
*
\param io comm accept(2) callback parameters
*/
-void FtpStateData::ftpAcceptDataConnection(const CommAcceptCbParams &io)
+void
+FtpStateData::ftpAcceptDataConnection(const CommAcceptCbParams &io)
{
debugs(9, 3, HERE);
if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
abortTransaction("entry aborted when accepting data conn");
+ data.listenConn->close();
+ data.listenConn = NULL;
+ return;
+ }
+
+ if (io.flag != COMM_OK) {
+ data.listenConn->close();
+ data.listenConn = NULL;
+ debugs(9, DBG_IMPORTANT, "FTP AcceptDataConnection: " << io.conn << ": " << xstrerr(io.xerrno));
+ /** \todo Need to send error message on control channel*/
+ ftpFail(this);
+ return;
+ }
+
+ /* data listening conn is no longer even open. abort. */
+ if (!Comm::IsConnOpen(data.listenConn)) {
+ data.listenConn = NULL; // ensure that it's cleared and not just closed.
return;
}
@@ -2984,7 +2954,7 @@
}
/* data listening conn is no longer even open. abort. */
- if (data.fd <= 0 || fd_table[data.fd].flags.open == 0) {
+ if (!Comm::IsConnOpen(data.conn)) {
data.clear(); // ensure that it's cleared and not just closed.
return;
}
@@ -2996,35 +2966,30 @@
* This prevents third-party hacks, but also third-party load balancing handshakes.
*/
if (Config.Ftp.sanitycheck) {
- char ntoapeer[MAX_IPSTRLEN];
- io.details.peer.NtoA(ntoapeer,MAX_IPSTRLEN);
-
- if (strcmp(fd_table[ctrl.fd].ipaddr, ntoapeer) != 0 &&
- strcmp(fd_table[data.fd].ipaddr, ntoapeer) != 0) {
+ // accept if either our data or ctrl connection is talking to this remote peer.
+ if (data.conn->remote != io.conn->remote && ctrl.conn->remote != io.conn->remote) {
debugs(9, DBG_IMPORTANT,
"FTP data connection from unexpected server (" <<
- io.details.peer << "), expecting " <<
- fd_table[ctrl.fd].ipaddr << " or " << fd_table[data.fd].ipaddr);
+ io.conn->remote << "), expecting " <<
+ data.conn->remote << " or " << ctrl.conn->remote);
/* close the bad sources connection down ASAP. */
- comm_close(io.nfd);
+ io.conn->close();
/* drop the bad connection (io) by ignoring the attempt. */
return;
}
}
- /**\par
- * Replace the Listening socket with the accepted data socket */
+ /** On COMM_OK start using the accepted data socket and discard the temporary listen socket. */
data.close();
- data.opened(io.nfd, dataCloser());
- data.port = io.details.peer.GetPort();
- data.host = xstrdup(fd_table[io.nfd].ipaddr);
+ data.opened(io.conn, dataCloser());
+ io.conn->remote.NtoA(data.host,SQUIDHOSTNAMELEN);
- debugs(9, 3, "ftpAcceptDataConnection: Connected data socket on " <<
- "FD " << io.nfd << " to " << io.details.peer << " FD table says: " <<
- "ctrl-peer= " << fd_table[ctrl.fd].ipaddr << ", " <<
- "data-peer= " << fd_table[data.fd].ipaddr);
+ debugs(9, 3, HERE << "Connected data socket on " <<
+ io.conn << ". FD table says: " <<
+ "ctrl-peer= " << fd_table[ctrl.conn->fd].ipaddr << ", " <<
+ "data-peer= " << fd_table[data.conn->fd].ipaddr);
assert(haveControlChannel("ftpAcceptDataConnection"));
assert(ctrl.message == NULL);
@@ -3068,12 +3033,12 @@
if (ftpState->filepath != NULL) {
/* Plain file upload */
- snprintf(cbuf, 1024, "STOR %s\r\n", ftpState->filepath);
+ snprintf(cbuf, CTRL_BUFLEN, "STOR %s\r\n", ftpState->filepath);
ftpState->writeCommand(cbuf);
ftpState->state = SENT_STOR;
} else if (ftpState->request->header.getInt64(HDR_CONTENT_LENGTH) > 0) {
/* File upload without a filename. use STOU to generate one */
- snprintf(cbuf, 1024, "STOU\r\n");
+ snprintf(cbuf, CTRL_BUFLEN, "STOU\r\n");
ftpState->writeCommand(cbuf);
ftpState->state = SENT_STOR;
} else {
@@ -3095,23 +3060,23 @@
int code = ctrl.replycode;
debugs(9, 3, HERE);
- if (code == 125 || (code == 150 && data.host)) {
+ if (code == 125 || (code == 150 && Comm::IsConnOpen(data.conn))) {
if (!startRequestBodyFlow()) { // register to receive body data
ftpFail(this);
return;
}
- /* When client status is 125, or 150 without a hostname, Begin data transfer. */
+ /* When client status is 125, or 150 and the data connection is open, Begin data transfer. */
debugs(9, 3, HERE << "starting data transfer");
switchTimeoutToDataChannel();
sendMoreRequestBody();
+ fwd->dontRetry(true); // dont permit re-trying if the body was sent.
state = WRITING_DATA;
debugs(9, 3, HERE << "writing data channel");
} else if (code == 150) {
- /*\par
- * When client code is 150 without a hostname, Accept data channel. */
+ /* When client code is 150 with no data channel, Accept data channel. */
debugs(9, 3, "ftpReadStor: accepting data channel");
- listenForDataChannel(data.fd, data.host);
+ listenForDataChannel(data.conn, data.host);
} else {
debugs(9, DBG_IMPORTANT, HERE << "Unexpected reply code "<< std::setfill('0') << std::setw(3) << code);
ftpFail(this);
@@ -3128,7 +3093,7 @@
debugs(9, 3, HERE);
- snprintf(cbuf, 1024, "REST %"PRId64"\r\n", ftpState->restart_offset);
+ snprintf(cbuf, CTRL_BUFLEN, "REST %"PRId64"\r\n", ftpState->restart_offset);
ftpState->writeCommand(cbuf);
ftpState->state = SENT_REST;
}
@@ -3191,9 +3156,9 @@
debugs(9, 3, HERE);
if (ftpState->filepath) {
- snprintf(cbuf, 1024, "LIST %s\r\n", ftpState->filepath);
+ snprintf(cbuf, CTRL_BUFLEN, "LIST %s\r\n", ftpState->filepath);
} else {
- snprintf(cbuf, 1024, "LIST\r\n");
+ snprintf(cbuf, CTRL_BUFLEN, "LIST\r\n");
}
ftpState->writeCommand(cbuf);
@@ -3213,9 +3178,9 @@
ftpState->flags.tried_nlst = 1;
if (ftpState->filepath) {
- snprintf(cbuf, 1024, "NLST %s\r\n", ftpState->filepath);
+ snprintf(cbuf, CTRL_BUFLEN, "NLST %s\r\n", ftpState->filepath);
} else {
- snprintf(cbuf, 1024, "NLST\r\n");
+ snprintf(cbuf, CTRL_BUFLEN, "NLST\r\n");
}
ftpState->writeCommand(cbuf);
@@ -3229,17 +3194,17 @@
int code = ftpState->ctrl.replycode;
debugs(9, 3, HERE);
- if (code == 125 || (code == 150 && ftpState->data.host)) {
+ if (code == 125 || (code == 150 && Comm::IsConnOpen(ftpState->data.conn))) {
/* Begin data transfer */
- debugs(9, 3, HERE << "begin data transfer from " << ftpState->data.host << " (" << ftpState->data.local << ")");
+ debugs(9, 3, HERE << "begin data transfer from " << ftpState->data.conn->remote << " (" << ftpState->data.conn->local << ")");
ftpState->switchTimeoutToDataChannel();
ftpState->maybeReadVirginBody();
ftpState->state = READING_DATA;
return;
} else if (code == 150) {
/* Accept data channel */
- debugs(9, 3, HERE << "accept data channel from " << ftpState->data.host << " (" << ftpState->data.local << ")");
- ftpState->listenForDataChannel(ftpState->data.fd, ftpState->data.host);
+ debugs(9, 3, HERE << "accept data channel from " << ftpState->data.conn->remote << " (" << ftpState->data.conn->local << ")");
+ ftpState->listenForDataChannel(ftpState->data.conn, ftpState->data.host);
return;
} else if (!ftpState->flags.tried_nlst && code > 300) {
ftpSendNlst(ftpState);
@@ -3260,7 +3225,7 @@
debugs(9, 3, HERE);
assert(ftpState->filepath != NULL);
- snprintf(cbuf, 1024, "RETR %s\r\n", ftpState->filepath);
+ snprintf(cbuf, CTRL_BUFLEN, "RETR %s\r\n", ftpState->filepath);
ftpState->writeCommand(cbuf);
ftpState->state = SENT_RETR;
}
@@ -3272,7 +3237,7 @@
int code = ftpState->ctrl.replycode;
debugs(9, 3, HERE);
- if (code == 125 || (code == 150 && ftpState->data.host)) {
+ if (code == 125 || (code == 150 && Comm::IsConnOpen(ftpState->data.conn))) {
/* Begin data transfer */
debugs(9, 3, HERE << "reading data channel");
ftpState->switchTimeoutToDataChannel();
@@ -3280,7 +3245,7 @@
ftpState->state = READING_DATA;
} else if (code == 150) {
/* Accept data channel */
- ftpState->listenForDataChannel(ftpState->data.fd, ftpState->data.host);
+ ftpState->listenForDataChannel(ftpState->data.conn, ftpState->data.host);
} else if (code >= 300) {
if (!ftpState->flags.try_slash_hack) {
/* Try this as a directory missing trailing slash... */
@@ -3332,7 +3297,7 @@
} else { /* != 226 */
debugs(9, DBG_IMPORTANT, HERE << "Got code " << code << " after reading data");
ftpState->failed(ERR_FTP_FAILURE, 0);
- /* failed closes ctrl.fd and frees ftpState */
+ /* failed closes ctrl.conn and frees ftpState */
return;
}
}
@@ -3382,7 +3347,7 @@
if (!ftpState || !ftpState->haveControlChannel("ftpSendQuit"))
return;
- snprintf(cbuf, 1024, "QUIT\r\n");
+ snprintf(cbuf, CTRL_BUFLEN, "QUIT\r\n");
ftpState->writeCommand(cbuf);
ftpState->state = SENT_QUIT;
}
@@ -3494,7 +3459,7 @@
}
ftpState->failed(ERR_NONE, 0);
- /* failed() closes ctrl.fd and frees this */
+ /* failed() closes ctrl.conn and frees this */
}
void
@@ -3835,7 +3800,7 @@
{
if (fwd == NULL || flags.completed_forwarding) {
debugs(9, 3, HERE << "completeForwarding avoids " <<
- "double-complete on FD " << ctrl.fd << ", Data FD " << data.fd <<
+ "double-complete on FD " << ctrl.conn->fd << ", Data FD " << data.conn->fd <<
", this " << this << ", fwd " << fwd);
return;
}
@@ -3850,26 +3815,30 @@
void
FtpStateData::closeServer()
{
- debugs(9,3, HERE << "closing FTP server FD " << ctrl.fd << ", Data FD " << data.fd << ", this " << this);
-
- if (ctrl.fd > -1) {
- fwd->unregister(ctrl.fd);
+ if (Comm::IsConnOpen(ctrl.conn)) {
+ debugs(9,3, HERE << "closing FTP server FD " << ctrl.conn->fd << ", this " << this);
+ fwd->unregister(ctrl.conn);
ctrl.close();
}
- data.close();
+ if (Comm::IsConnOpen(data.conn)) {
+ debugs(9,3, HERE << "closing FTP data FD " << data.conn->fd << ", this " << this);
+ data.close();
+ }
+
+ debugs(9,3, HERE << "FTP ctrl and data connections closed. this " << this);
}
/**
* Did we close all FTP server connection(s)?
*
- \retval true Both server control and data channels are closed. And not waitigng for a new data connection to open.
+ \retval true Both server control and data channels are closed. And not waiting for a new data connection to open.
\retval false Either control channel or data is still active.
*/
bool
FtpStateData::doneWithServer() const
{
- return ctrl.fd < 0 && data.fd < 0;
+ return !Comm::IsConnOpen(ctrl.conn) && !Comm::IsConnOpen(data.conn);
}
/**
@@ -3885,7 +3854,7 @@
return false;
/* doneWithServer() only checks BOTH channels are closed. */
- if (ctrl.fd < 0) {
+ if (!Comm::IsConnOpen(ctrl.conn)) {
debugs(9, DBG_IMPORTANT, "WARNING! FTP Server Control channel is closed, but Data channel still active.");
debugs(9, 2, caller_name << ": attempted on a closed FTP channel.");
return false;
@@ -3904,9 +3873,9 @@
FtpStateData::abortTransaction(const char *reason)
{
debugs(9, 3, HERE << "aborting transaction for " << reason <<
- "; FD " << ctrl.fd << ", Data FD " << data.fd << ", this " << this);
- if (ctrl.fd >= 0) {
- comm_close(ctrl.fd);
+ "; FD " << (ctrl.conn!=NULL?ctrl.conn->fd:-1) << ", Data FD " << (data.conn!=NULL?data.conn->fd:-1) << ", this " << this);
+ if (Comm::IsConnOpen(ctrl.conn)) {
+ ctrl.conn->close();
return;
}
@@ -3924,24 +3893,17 @@
/// configures the channel with a descriptor and registers a close handler
void
-FtpChannel::opened(int aFd, const AsyncCall::Pointer &aCloser)
+FtpChannel::opened(const Comm::ConnectionPointer &newConn, const AsyncCall::Pointer &aCloser)
{
- assert(fd < 0);
+ assert(!Comm::IsConnOpen(conn));
assert(closer == NULL);
- assert(aFd >= 0);
+ assert(Comm::IsConnOpen(newConn));
assert(aCloser != NULL);
- fd = aFd;
+ conn = newConn;
closer = aCloser;
- comm_add_close_handler(fd, closer);
-
- // grab the local IP address:port details for this connection
- struct addrinfo *AI = NULL;
- local.InitAddrInfo(AI);
- getsockname(aFd, AI->ai_addr, &AI->ai_addrlen);
- local = *AI;
- local.FreeAddrInfo(AI);
+ comm_add_close_handler(conn->fd, closer);
}
/// planned close: removes the close handler and calls comm_close
@@ -3949,20 +3911,17 @@
FtpChannel::close()
{
// channels with active listeners will be closed when the listener handler dies.
- if (fd >= 0) {
- if (closer != NULL) {
- comm_remove_close_handler(fd, closer);
- closer = NULL;
- }
- comm_close(fd); // we do not expect to be called back
- fd = -1;
+ if (Comm::IsConnOpen(conn)) {
+ comm_remove_close_handler(conn->fd, closer);
+ closer = NULL;
+ conn->close(); // we do not expect to be called back
}
+ conn = NULL;
}
-/// just resets fd and close handler
void
FtpChannel::clear()
{
- fd = -1;
+ conn = NULL;
closer = NULL;
}
=== modified file 'src/globals.h'
--- src/globals.h 2011-01-28 07:58:53 +0000
+++ src/globals.h 2011-03-03 06:23:45 +0000
@@ -97,17 +97,8 @@
extern int opt_create_swap_dirs; /* 0 */
extern int opt_store_doublecheck; /* 0 */
extern int syslog_enable; /* 0 */
- extern int theInIcpConnection; /* -1 */
- extern int theOutIcpConnection; /* -1 */
extern int DnsSocketA; /* -1 */
extern int DnsSocketB; /* -1 */
-#if SQUID_SNMP
-
- extern int theInSnmpConnection; /* -1 */
- extern int theOutSnmpConnection; /* -1 */
- extern char *snmp_agentinfo;
-#endif
-
extern int n_disk_objects; /* 0 */
extern iostats IOStats;
=== modified file 'src/gopher.cc'
--- src/gopher.cc 2011-03-12 03:34:48 +0000
+++ src/gopher.cc 2011-03-26 05:26:31 +0000
@@ -135,7 +135,7 @@
int cso_recno;
int len;
char *buf; /* pts to a 4k page */
- int fd;
+ Comm::ConnectionPointer serverConn;
HttpRequest *req;
FwdState::Pointer fwd;
char replybuf[BUFSIZ];
@@ -148,7 +148,7 @@
char *request);
static void gopherEndHTML(GopherStateData *);
static void gopherToHTML(GopherStateData *, char *inbuf, int len);
-static PF gopherTimeout;
+static CTCB gopherTimeout;
static IOCB gopherReadReply;
static IOCB gopherSendComplete;
static PF gopherSendRequest;
@@ -161,7 +161,7 @@
/// \ingroup ServerProtocolGopherInternal
static void
-gopherStateFree(int fdnotused, void *data)
+gopherStateFree(int, void *data)
{
GopherStateData *gopherState = (GopherStateData *)data;
@@ -752,15 +752,15 @@
/// \ingroup ServerProtocolGopherInternal
static void
-gopherTimeout(int fd, void *data)
+gopherTimeout(const CommTimeoutCbParams &io)
{
- GopherStateData *gopherState = (GopherStateData *)data;
- StoreEntry *entry = gopherState->entry;
- debugs(10, 4, "gopherTimeout: FD " << fd << ": '" << entry->url() << "'" );
+ GopherStateData *gopherState = static_cast(io.data);
+ debugs(10, 4, HERE << io.conn << ": '" << gopherState->entry->url() << "'" );
gopherState->fwd->fail(errorCon(ERR_READ_TIMEOUT, HTTP_GATEWAY_TIMEOUT, gopherState->fwd->request));
- comm_close(fd);
+ if (Comm::IsConnOpen(io.conn))
+ io.conn->close();
}
/**
@@ -769,7 +769,7 @@
* Read until error or connection closed.
*/
static void
-gopherReadReply(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
+gopherReadReply(const Comm::ConnectionPointer &conn, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
{
GopherStateData *gopherState = (GopherStateData *)data;
StoreEntry *entry = gopherState->entry;
@@ -789,7 +789,7 @@
assert(buf == gopherState->replybuf);
if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
- comm_close(fd);
+ gopherState->serverConn->close();
return;
}
@@ -809,10 +809,11 @@
kb_incr(&statCounter.server.other.kbytes_in, len);
}
- debugs(10, 5, "gopherReadReply: FD " << fd << " read len=" << len);
+ debugs(10, 5, HERE << conn << " read len=" << len);
if (flag == COMM_OK && len > 0) {
- commSetTimeout(fd, Config.Timeout.read, NULL, NULL);
+ AsyncCall::Pointer nil;
+ commSetConnTimeout(conn, Config.Timeout.read, nil);
IOStats.Gopher.reads++;
for (clen = len - 1, bin = 0; clen; bin++)
@@ -831,17 +832,19 @@
debugs(50, 1, "gopherReadReply: error reading: " << xstrerror());
if (ignoreErrno(errno)) {
- comm_read(fd, buf, read_sz, gopherReadReply, gopherState);
+ AsyncCall::Pointer call = commCbCall(5,4, "gopherReadReply",
+ CommIoCbPtrFun(gopherReadReply, gopherState));
+ comm_read(conn, buf, read_sz, call);
} else {
ErrorState *err;
err = errorCon(ERR_READ_ERROR, HTTP_INTERNAL_SERVER_ERROR, gopherState->fwd->request);
err->xerrno = errno;
gopherState->fwd->fail(err);
- comm_close(fd);
+ gopherState->serverConn->close();
}
} else if (len == 0 && entry->isEmpty()) {
gopherState->fwd->fail(errorCon(ERR_ZERO_SIZE_OBJECT, HTTP_SERVICE_UNAVAILABLE, gopherState->fwd->request));
- comm_close(fd);
+ gopherState->serverConn->close();
} else if (len == 0) {
/* Connection closed; retrieval done. */
/* flush the rest of data in temp buf if there is one. */
@@ -852,14 +855,16 @@
entry->timestampsSet();
entry->flush();
gopherState->fwd->complete();
- comm_close(fd);
+ gopherState->serverConn->close();
} else {
if (gopherState->conversion != gopher_ds::NORMAL) {
gopherToHTML(gopherState, buf, len);
} else {
entry->append(buf, len);
}
- comm_read(fd, buf, read_sz, gopherReadReply, gopherState);
+ AsyncCall::Pointer call = commCbCall(5,4, "gopherReadReply",
+ CommIoCbPtrFun(gopherReadReply, gopherState));
+ comm_read(conn, buf, read_sz, call);
}
}
@@ -868,14 +873,14 @@
* This will be called when request write is complete. Schedule read of reply.
*/
static void
-gopherSendComplete(int fd, char *buf, size_t size, comm_err_t errflag, int xerrno, void *data)
+gopherSendComplete(const Comm::ConnectionPointer &conn, char *buf, size_t size, comm_err_t errflag, int xerrno, void *data)
{
GopherStateData *gopherState = (GopherStateData *) data;
StoreEntry *entry = gopherState->entry;
- debugs(10, 5, "gopherSendComplete: FD " << fd << " size: " << size << " errflag: " << errflag);
+ debugs(10, 5, HERE << conn << " size: " << size << " errflag: " << errflag);
if (size > 0) {
- fd_bytes(fd, size, FD_WRITE);
+ fd_bytes(conn->fd, size, FD_WRITE);
kb_incr(&statCounter.server.all.kbytes_out, size);
kb_incr(&statCounter.server.other.kbytes_out, size);
}
@@ -887,7 +892,7 @@
err->port = gopherState->fwd->request->port;
err->url = xstrdup(entry->url());
gopherState->fwd->fail(err);
- comm_close(fd);
+ gopherState->serverConn->close();
if (buf)
memFree(buf, MEM_4K_BUF); /* Allocated by gopherSendRequest. */
@@ -930,9 +935,9 @@
}
/* Schedule read reply. */
- AsyncCall::Pointer call = commCbCall(10,5, "gopherReadReply",
+ AsyncCall::Pointer call = commCbCall(5,5, "gopherReadReply",
CommIoCbPtrFun(gopherReadReply, gopherState));
- entry->delayAwareRead(fd, gopherState->replybuf, BUFSIZ, call);
+ entry->delayAwareRead(conn, gopherState->replybuf, BUFSIZ, call);
if (buf)
memFree(buf, MEM_4K_BUF); /* Allocated by gopherSendRequest. */
@@ -968,10 +973,10 @@
snprintf(buf, 4096, "%s\r\n", gopherState->request);
}
- debugs(10, 5, "gopherSendRequest: FD " << fd);
+ debugs(10, 5, HERE << gopherState->serverConn);
AsyncCall::Pointer call = commCbCall(5,5, "gopherSendComplete",
CommIoCbPtrFun(gopherSendComplete, gopherState));
- Comm::Write(fd, buf, strlen(buf), call, NULL);
+ Comm::Write(gopherState->serverConn, buf, strlen(buf), call, NULL);
if (EBIT_TEST(gopherState->entry->flags, ENTRY_CACHABLE))
gopherState->entry->setPublicKey(); /* Make it public */
@@ -984,7 +989,6 @@
void
gopherStart(FwdState * fwd)
{
- int fd = fwd->server_fd;
StoreEntry *entry = fwd->entry;
GopherStateData *gopherState;
CBDATA_INIT_TYPE(GopherStateData);
@@ -1006,7 +1010,7 @@
gopher_request_parse(fwd->request,
&gopherState->type_id, gopherState->request);
- comm_add_close_handler(fd, gopherStateFree, gopherState);
+ comm_add_close_handler(fwd->serverConnection()->fd, gopherStateFree, gopherState);
if (((gopherState->type_id == GOPHER_INDEX) || (gopherState->type_id == GOPHER_CSO))
&& (strchr(gopherState->request, '?') == NULL)) {
@@ -1026,12 +1030,12 @@
gopherToHTML(gopherState, (char *) NULL, 0);
fwd->complete();
- comm_close(fd);
return;
}
- gopherState->fd = fd;
- gopherState->fwd = fwd;
- gopherSendRequest(fd, gopherState);
- commSetTimeout(fd, Config.Timeout.read, gopherTimeout, gopherState);
+ gopherState->serverConn = fwd->serverConnection();
+ gopherSendRequest(fwd->serverConnection()->fd, gopherState);
+ AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "gopherTimeout",
+ CommTimeoutCbPtrFun(gopherTimeout, gopherState));
+ commSetConnTimeout(fwd->serverConnection(), Config.Timeout.read, timeoutCall);
}
=== modified file 'src/helper.cc'
--- src/helper.cc 2011-03-16 12:03:03 +0000
+++ src/helper.cc 2011-03-23 10:17:53 +0000
@@ -33,14 +33,15 @@
*/
#include "squid.h"
+#include "comm.h"
+#include "comm/Connection.h"
#include "comm/Write.h"
#include "helper.h"
#include "log/Gadgets.h"
+#include "MemBuf.h"
#include "SquidMath.h"
#include "SquidTime.h"
#include "Store.h"
-#include "comm.h"
-#include "MemBuf.h"
#include "wordlist.h"
#define HELPER_MAX_ARGS 64
@@ -76,6 +77,62 @@
CBDATA_TYPE(helper_stateful_server);
void
+HelperServerBase::closePipesSafely()
+{
+#ifdef _SQUID_MSWIN_
+ int no = index + 1;
+
+ shutdown(writePipe->fd, SD_BOTH);
+#endif
+
+ flags.closing = 1;
+ if (readPipe->fd == writePipe->fd)
+ readPipe->fd = -1;
+ else
+ readPipe->close();
+ writePipe->close();
+
+#ifdef _SQUID_MSWIN_
+ if (hIpc) {
+ if (WaitForSingleObject(hIpc, 5000) != WAIT_OBJECT_0) {
+ getCurrentTime();
+ debugs(84, DBG_IMPORTANT, "WARNING: " << hlp->id_name <<
+ " #" << no << " (" << hlp->cmdline->key << "," <<
+ (long int)pid << ") didn't exit in 5 seconds");
+ }
+ CloseHandle(hIpc);
+ }
+#endif
+}
+
+void
+HelperServerBase::closeWritePipeSafely()
+{
+#ifdef _SQUID_MSWIN_
+ int no = index + 1;
+
+ shutdown(writePipe->fd, (readPipe->fd == writePipe->fd ? SD_BOTH : SD_SEND));
+#endif
+
+ flags.closing = 1;
+ if (readPipe->fd == writePipe->fd)
+ readPipe->fd = -1;
+ writePipe->close();
+
+#ifdef _SQUID_MSWIN_
+ if (hIpc) {
+ if (WaitForSingleObject(hIpc, 5000) != WAIT_OBJECT_0) {
+ getCurrentTime();
+ debugs(84, DBG_IMPORTANT, "WARNING: " << hlp->id_name <<
+ " #" << no << " (" << hlp->cmdline->key << "," <<
+ (long int)pid << ") didn't exit in 5 seconds");
+ }
+ CloseHandle(hIpc);
+ }
+#endif
+}
+
+void
helperOpenServers(helper * hlp)
{
char *s;
@@ -150,8 +207,10 @@
srv->pid = pid;
srv->index = k;
srv->addr = hlp->addr;
- srv->rfd = rfd;
- srv->wfd = wfd;
+ srv->readPipe = new Comm::Connection;
+ srv->readPipe->fd = rfd;
+ srv->writePipe = new Comm::Connection;
+ srv->writePipe->fd = wfd;
srv->rbuf = (char *)memAllocBuf(BUF_8KB, &srv->rbuf_sz);
srv->wqueue = new MemBuf;
srv->roffset = 0;
@@ -176,7 +235,9 @@
comm_add_close_handler(rfd, helperServerFree, srv);
- comm_read(srv->rfd, srv->rbuf, srv->rbuf_sz - 1, helperHandleRead, srv);
+ AsyncCall::Pointer call = commCbCall(5,4, "helperHandleRead",
+ CommIoCbPtrFun(helperHandleRead, srv));
+ comm_read(srv->readPipe, srv->rbuf, srv->rbuf_sz - 1, call);
}
hlp->last_restart = squid_curtime;
@@ -264,8 +325,10 @@
srv->stats.releases = 0;
srv->index = k;
srv->addr = hlp->addr;
- srv->rfd = rfd;
- srv->wfd = wfd;
+ srv->readPipe = new Comm::Connection;
+ srv->readPipe->fd = rfd;
+ srv->writePipe = new Comm::Connection;
+ srv->writePipe->fd = wfd;
srv->rbuf = (char *)memAllocBuf(BUF_8KB, &srv->rbuf_sz);
srv->roffset = 0;
srv->parent = cbdataReference(hlp);
@@ -292,7 +355,9 @@
comm_add_close_handler(rfd, helperStatefulServerFree, srv);
- comm_read(srv->rfd, srv->rbuf, srv->rbuf_sz - 1, helperStatefulHandleRead, srv);
+ AsyncCall::Pointer call = commCbCall(5,4, "helperStatefulHandleRead",
+ CommIoCbPtrFun(helperStatefulHandleRead, srv));
+ comm_read(srv->readPipe, srv->rbuf, srv->rbuf_sz - 1, call);
}
hlp->last_restart = squid_curtime;
@@ -433,7 +498,7 @@
double tt = 0.001 * (srv->requests[0] ? tvSubMsec(srv->requests[0]->dispatch_time, current_time) : tvSubMsec(srv->dispatch_time, srv->answer_time));
storeAppendPrintf(sentry, "%7d\t%7d\t%7d\t%11d\t%c%c%c%c\t%7.3f\t%7d\t%s\n",
srv->index + 1,
- srv->rfd,
+ srv->readPipe->fd,
srv->pid,
srv->stats.uses,
srv->stats.pending ? 'B' : ' ',
@@ -486,7 +551,7 @@
double tt = 0.001 * tvSubMsec(srv->dispatch_time, srv->flags.busy ? current_time : srv->answer_time);
storeAppendPrintf(sentry, "%7d\t%7d\t%7d\t%11d\t%c%c%c%c%c\t%7.3f\t%7d\t%s\n",
srv->index + 1,
- srv->rfd,
+ srv->readPipe->fd,
srv->pid,
srv->stats.uses,
srv->flags.busy ? 'B' : ' ',
@@ -511,12 +576,6 @@
helperShutdown(helper * hlp)
{
dlink_node *link = hlp->servers.head;
-#ifdef _SQUID_MSWIN_
-
- HANDLE hIpc;
- pid_t pid;
- int no;
-#endif
while (link) {
helper_server *srv;
@@ -542,36 +601,11 @@
continue;
}
- srv->flags.closing = 1;
-#ifdef _SQUID_MSWIN_
-
- hIpc = srv->hIpc;
- pid = srv->pid;
- no = srv->index + 1;
- shutdown(srv->wfd, SD_BOTH);
-#endif
-
debugs(84, 3, "helperShutdown: " << hlp->id_name << " #" << srv->index + 1 << " shutting down.");
/* the rest of the details is dealt with in the helperServerFree
* close handler
*/
- comm_close(srv->rfd);
-#ifdef _SQUID_MSWIN_
-
- if (hIpc) {
- if (WaitForSingleObject(hIpc, 5000) != WAIT_OBJECT_0) {
- getCurrentTime();
- debugs(84, 1, "helperShutdown: WARNING: " << hlp->id_name <<
- " #" << no << " (" << hlp->cmdline->key << "," <<
- (long int)pid << ") didn't exit in 5 seconds");
-
- }
-
- CloseHandle(hIpc);
- }
-
-#endif
-
+ srv->closePipesSafely();
}
}
@@ -580,12 +614,6 @@
{
dlink_node *link = hlp->servers.head;
helper_stateful_server *srv;
-#ifdef _SQUID_MSWIN_
-
- HANDLE hIpc;
- pid_t pid;
- int no;
-#endif
while (link) {
srv = (helper_stateful_server *)link->data;
@@ -619,36 +647,12 @@
}
}
- srv->flags.closing = 1;
-#ifdef _SQUID_MSWIN_
-
- hIpc = srv->hIpc;
- pid = srv->pid;
- no = srv->index + 1;
- shutdown(srv->wfd, SD_BOTH);
-#endif
-
debugs(84, 3, "helperStatefulShutdown: " << hlp->id_name << " #" << srv->index + 1 << " shutting down.");
/* the rest of the details is dealt with in the helperStatefulServerFree
* close handler
*/
- comm_close(srv->rfd);
-#ifdef _SQUID_MSWIN_
-
- if (hIpc) {
- if (WaitForSingleObject(hIpc, 5000) != WAIT_OBJECT_0) {
- getCurrentTime();
- debugs(84, 1, "helperShutdown: WARNING: " << hlp->id_name <<
- " #" << no << " (" << hlp->cmdline->key << "," <<
- (long int)pid << ") didn't exit in 5 seconds");
- }
-
- CloseHandle(hIpc);
- }
-
-#endif
-
+ srv->closePipesSafely();
}
}
@@ -689,8 +693,8 @@
srv->writebuf = NULL;
}
- if (srv->wfd != srv->rfd && srv->wfd != -1)
- comm_close(srv->wfd);
+ if (Comm::IsConnOpen(srv->writePipe))
+ srv->closeWritePipeSafely();
dlinkDelete(&srv->link, &hlp->servers);
@@ -751,8 +755,8 @@
#endif
/* TODO: walk the local queue of requests and carry them all out */
- if (srv->wfd != srv->rfd && srv->wfd != -1)
- comm_close(srv->wfd);
+ if (Comm::IsConnOpen(srv->writePipe))
+ srv->closeWritePipeSafely();
dlinkDelete(&srv->link, &hlp->servers);
@@ -834,18 +838,14 @@
if (!srv->flags.shutdown) {
helperKickQueue(hlp);
} else if (!srv->flags.closing && !srv->stats.pending) {
- int wfd = srv->wfd;
- srv->wfd = -1;
- if (srv->rfd == wfd)
- srv->rfd = -1;
srv->flags.closing=1;
- comm_close(wfd);
+ srv->writePipe->close();
return;
}
}
static void
-helperHandleRead(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
+helperHandleRead(const Comm::ConnectionPointer &conn, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
{
char *t = NULL;
helper_server *srv = (helper_server *)data;
@@ -858,12 +858,12 @@
return;
}
- assert(fd == srv->rfd);
+ assert(conn->fd == srv->readPipe->fd);
debugs(84, 5, "helperHandleRead: " << len << " bytes from " << hlp->id_name << " #" << srv->index + 1);
if (flag != COMM_OK || len == 0) {
- comm_close(fd);
+ srv->closePipesSafely();
return;
}
@@ -907,12 +907,15 @@
}
}
- if (srv->rfd != -1)
- comm_read(fd, srv->rbuf + srv->roffset, srv->rbuf_sz - srv->roffset - 1, helperHandleRead, srv);
+ if (Comm::IsConnOpen(srv->readPipe)) {
+ AsyncCall::Pointer call = commCbCall(5,4, "helperHandleRead",
+ CommIoCbPtrFun(helperHandleRead, srv));
+ comm_read(srv->readPipe, srv->rbuf + srv->roffset, srv->rbuf_sz - srv->roffset - 1, call);
+ }
}
static void
-helperStatefulHandleRead(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
+helperStatefulHandleRead(const Comm::ConnectionPointer &conn, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
{
char *t = NULL;
helper_stateful_server *srv = (helper_stateful_server *)data;
@@ -926,14 +929,14 @@
return;
}
- assert(fd == srv->rfd);
+ assert(conn->fd == srv->readPipe->fd);
debugs(84, 5, "helperStatefulHandleRead: " << len << " bytes from " <<
hlp->id_name << " #" << srv->index + 1);
if (flag != COMM_OK || len == 0) {
- comm_close(fd);
+ srv->closePipesSafely();
return;
}
@@ -984,9 +987,11 @@
helperStatefulReleaseServer(srv);
}
- if (srv->rfd != -1)
- comm_read(srv->rfd, srv->rbuf + srv->roffset, srv->rbuf_sz - srv->roffset - 1,
- helperStatefulHandleRead, srv);
+ if (Comm::IsConnOpen(srv->readPipe)) {
+ AsyncCall::Pointer call = commCbCall(5,4, "helperStatefulHandleRead",
+ CommIoCbPtrFun(helperStatefulHandleRead, srv));
+ comm_read(srv->readPipe, srv->rbuf + srv->roffset, srv->rbuf_sz - srv->roffset - 1, call);
+ }
}
static void
@@ -1163,7 +1168,7 @@
static void
-helperDispatchWriteDone(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
+helperDispatchWriteDone(const Comm::ConnectionPointer &conn, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
{
helper_server *srv = (helper_server *)data;
@@ -1184,7 +1189,7 @@
srv->flags.writing = 1;
AsyncCall::Pointer call = commCbCall(5,5, "helperDispatchWriteDone",
CommIoCbPtrFun(helperDispatchWriteDone, srv));
- Comm::Write(srv->wfd, srv->writebuf->content(), srv->writebuf->contentSize(), call, NULL);
+ Comm::Write(srv->writePipe, srv->writebuf->content(), srv->writebuf->contentSize(), call, NULL);
}
}
@@ -1228,7 +1233,7 @@
srv->flags.writing = 1;
AsyncCall::Pointer call = commCbCall(5,5, "helperDispatchWriteDone",
CommIoCbPtrFun(helperDispatchWriteDone, srv));
- Comm::Write(srv->wfd, srv->writebuf->content(), srv->writebuf->contentSize(), call, NULL);
+ Comm::Write(srv->writePipe, srv->writebuf->content(), srv->writebuf->contentSize(), call, NULL);
}
debugs(84, 5, "helperDispatch: Request sent to " << hlp->id_name << " #" << srv->index + 1 << ", " << strlen(r->buf) << " bytes");
@@ -1238,7 +1243,7 @@
}
static void
-helperStatefulDispatchWriteDone(int fd, char *buf, size_t len, comm_err_t flag,
+helperStatefulDispatchWriteDone(const Comm::ConnectionPointer &conn, char *buf, size_t len, comm_err_t flag,
int xerrno, void *data)
{
/* nothing! */
@@ -1281,7 +1286,7 @@
srv->dispatch_time = current_time;
AsyncCall::Pointer call = commCbCall(5,5, "helperStatefulDispatchWriteDone",
CommIoCbPtrFun(helperStatefulDispatchWriteDone, hlp));
- Comm::Write(srv->wfd, r->buf, strlen(r->buf), call, NULL);
+ Comm::Write(srv->writePipe, r->buf, strlen(r->buf), call, NULL);
debugs(84, 5, "helperStatefulDispatch: Request sent to " <<
hlp->id_name << " #" << srv->index + 1 << ", " <<
(int) strlen(r->buf) << " bytes");
@@ -1317,12 +1322,7 @@
if (!srv->flags.shutdown) {
helperStatefulKickQueue(srv->parent);
} else if (!srv->flags.closing && !srv->flags.reserved && !srv->flags.busy) {
- int wfd = srv->wfd;
- srv->wfd = -1;
- if (srv->rfd == wfd)
- srv->rfd = -1;
- srv->flags.closing=1;
- comm_close(wfd);
+ srv->closeWritePipeSafely();
return;
}
}
=== modified file 'src/helper.h'
--- src/helper.h 2010-11-18 08:01:53 +0000
+++ src/helper.h 2011-03-26 05:28:28 +0000
@@ -35,15 +35,12 @@
#include "squid.h"
#include "cbdata.h"
+#include "comm/forward.h"
#include "ip/Address.h"
#include "HelperChildConfig.h"
class helper_request;
-typedef struct _helper_flags helper_flags;
-
-typedef struct _helper_stateful_flags helper_stateful_flags;
-
typedef void HLPSCB(void *, void *lastserver, char *buf);
class helper
@@ -97,11 +94,23 @@
class HelperServerBase
{
public:
+ /** Closes pipes to the helper safely.
+ * Handles the case where the read and write pipes are the same FD.
+ */
+ void closePipesSafely();
+
+ /** Closes the reading pipe.
+ * If the read and write sockets are the same the write pipe will
+ * also be closed. Otherwise its left open for later handling.
+ */
+ void closeWritePipeSafely();
+
+public:
int index;
int pid;
Ip::Address addr;
- int rfd;
- int wfd;
+ Comm::ConnectionPointer readPipe;
+ Comm::ConnectionPointer writePipe;
void *hIpc;
char *rbuf;
@@ -112,6 +121,15 @@
struct timeval answer_time;
dlink_node link;
+
+ struct _helper_flags {
+ unsigned int busy:1;
+ unsigned int writing:1;
+ unsigned int closing:1;
+ unsigned int shutdown:1;
+ unsigned int reserved:1;
+ } flags;
+
};
class helper_server : public HelperServerBase
@@ -123,12 +141,6 @@
helper *parent;
helper_request **requests;
- struct _helper_flags {
- unsigned int writing:1;
- unsigned int closing:1;
- unsigned int shutdown:1;
- } flags;
-
struct {
int uses;
unsigned int pending;
@@ -146,13 +158,6 @@
statefulhelper *parent;
helper_stateful_request *request;
- struct _helper_stateful_flags {
- unsigned int busy:1;
- unsigned int closing:1;
- unsigned int shutdown:1;
- unsigned int reserved:1;
- } flags;
-
struct {
int uses;
int submits;
=== modified file 'src/htcp.cc'
--- src/htcp.cc 2011-02-10 14:04:35 +0000
+++ src/htcp.cc 2011-03-03 06:23:45 +0000
@@ -55,13 +55,12 @@
public Ipc::StartListeningCb
{
public:
- typedef void (*Handler)(int fd, int errNo);
+ typedef void (*Handler)(int errNo);
HtcpListeningStartedDialer(Handler aHandler): handler(aHandler) {}
virtual void print(std::ostream &os) const { startPrint(os) << ')'; }
-
virtual bool canDial(AsyncCall &) const { return true; }
- virtual void dial(AsyncCall &) { (handler)(fd, errNo); }
+ virtual void dial(AsyncCall &) { (handler)(errNo); }
public:
Handler handler;
@@ -245,11 +244,11 @@
RR_RESPONSE
};
-static void htcpIncomingConnectionOpened(int fd, int errNo);
+static void htcpIncomingConnectionOpened(int errNo);
static uint32_t msg_id_counter = 0;
-static int htcpInSocket = -1;
-static int htcpOutSocket = -1;
+static Comm::ConnectionPointer htcpOutgoingConn = NULL;
+static Comm::ConnectionPointer htcpIncomingConn = NULL;
#define N_QUERIED_KEYS 8192
static uint32_t queried_id[N_QUERIED_KEYS];
static cache_key queried_keys[N_QUERIED_KEYS][SQUID_MD5_DIGEST_LENGTH];
@@ -614,21 +613,13 @@
}
static void
-
htcpSend(const char *buf, int len, Ip::Address &to)
{
- int x;
-
- debugs(31, 3, "htcpSend: " << to );
+ debugs(31, 3, HERE << to);
htcpHexdump("htcpSend", buf, len);
- x = comm_udp_sendto(htcpOutSocket,
- to,
- buf,
- len);
-
- if (x < 0)
- debugs(31, 3, "htcpSend: FD " << htcpOutSocket << " sendto: " << xstrerror());
+ if (comm_udp_sendto(htcpOutgoingConn->fd, to, buf, len) < 0)
+ debugs(31, 3, HERE << htcpOutgoingConn << " sendto: " << xstrerror());
else
statCounter.htcp.pkts_sent++;
}
@@ -638,7 +629,6 @@
*/
void
-
htcpSpecifier::setFrom(Ip::Address &aSocket)
{
from = aSocket;
@@ -1498,20 +1488,21 @@
htcpInit(void)
{
if (Config.Port.htcp <= 0) {
- debugs(31, 1, "HTCP Disabled.");
+ debugs(31, DBG_IMPORTANT, "HTCP Disabled.");
return;
}
- Ip::Address incomingAddr = Config.Addrs.udp_incoming;
- incomingAddr.SetPort(Config.Port.htcp);
+ htcpIncomingConn = new Comm::Connection;
+ htcpIncomingConn->local = Config.Addrs.udp_incoming;
+ htcpIncomingConn->local.SetPort(Config.Port.htcp);
- if (!Ip::EnableIpv6 && !incomingAddr.SetIPv4()) {
- debugs(31, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << incomingAddr << " is not an IPv4 address.");
+ if (!Ip::EnableIpv6 && !htcpIncomingConn->local.SetIPv4()) {
+ debugs(31, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << htcpIncomingConn->local << " is not an IPv4 address.");
fatal("HTCP port cannot be opened.");
}
/* split-stack for now requires default IPv4-only HTCP */
- if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && incomingAddr.IsAnyAddr()) {
- incomingAddr.SetIPv4();
+ if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && htcpIncomingConn->local.IsAnyAddr()) {
+ htcpIncomingConn->local.SetIPv4();
}
AsyncCall::Pointer call = asyncCall(31, 2,
@@ -1520,39 +1511,33 @@
Ipc::StartListening(SOCK_DGRAM,
IPPROTO_UDP,
- incomingAddr,
- COMM_NONBLOCKING,
+ htcpIncomingConn,
Ipc::fdnInHtcpSocket, call);
if (!Config.Addrs.udp_outgoing.IsNoAddr()) {
- Ip::Address outgoingAddr = Config.Addrs.udp_outgoing;
- outgoingAddr.SetPort(Config.Port.htcp);
+ htcpOutgoingConn = new Comm::Connection;
+ htcpOutgoingConn->local = Config.Addrs.udp_outgoing;
+ htcpOutgoingConn->local.SetPort(Config.Port.htcp);
- if (!Ip::EnableIpv6 && !outgoingAddr.SetIPv4()) {
- debugs(31, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << outgoingAddr << " is not an IPv4 address.");
+ if (!Ip::EnableIpv6 && !htcpOutgoingConn->local.SetIPv4()) {
+ debugs(31, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << htcpOutgoingConn->local << " is not an IPv4 address.");
fatal("HTCP port cannot be opened.");
}
/* split-stack for now requires default IPv4-only HTCP */
- if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && outgoingAddr.IsAnyAddr()) {
- outgoingAddr.SetIPv4();
+ if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && htcpOutgoingConn->local.IsAnyAddr()) {
+ htcpOutgoingConn->local.SetIPv4();
}
enter_suid();
- htcpOutSocket = comm_open_listener(SOCK_DGRAM,
- IPPROTO_UDP,
- outgoingAddr,
- COMM_NONBLOCKING,
- "Outgoing HTCP Socket");
+ comm_open_listener(SOCK_DGRAM, IPPROTO_UDP, htcpOutgoingConn, "Outgoing HTCP Socket");
leave_suid();
- if (htcpOutSocket < 0)
+ if (!Comm::IsConnOpen(htcpOutgoingConn))
fatal("Cannot open Outgoing HTCP Socket");
- Comm::SetSelect(htcpOutSocket, COMM_SELECT_READ, htcpRecv, NULL, 0);
-
- debugs(31, 1, "Outgoing HTCP messages on port " << Config.Port.htcp << ", FD " << htcpOutSocket << ".");
-
- fd_note(htcpInSocket, "Incoming HTCP socket");
+ Comm::SetSelect(htcpOutgoingConn->fd, COMM_SELECT_READ, htcpRecv, NULL, 0);
+
+ debugs(31, DBG_IMPORTANT, "Sending HTCP messages from " << htcpOutgoingConn->local);
}
if (!htcpDetailPool) {
@@ -1561,19 +1546,19 @@
}
static void
-htcpIncomingConnectionOpened(int fd, int errNo)
+htcpIncomingConnectionOpened(int)
{
- htcpInSocket = fd;
-
- if (htcpInSocket < 0)
+ if (!Comm::IsConnOpen(htcpIncomingConn))
fatal("Cannot open HTCP Socket");
- Comm::SetSelect(htcpInSocket, COMM_SELECT_READ, htcpRecv, NULL, 0);
-
- debugs(31, 1, "Accepting HTCP messages on port " << Config.Port.htcp << ", FD " << htcpInSocket << ".");
-
- if (Config.Addrs.udp_outgoing.IsNoAddr())
- htcpOutSocket = htcpInSocket;
+ Comm::SetSelect(htcpIncomingConn->fd, COMM_SELECT_READ, htcpRecv, NULL, 0);
+
+ debugs(31, DBG_CRITICAL, "Accepting HTCP messages on " << htcpIncomingConn->local);
+
+ if (Config.Addrs.udp_outgoing.IsNoAddr()) {
+ htcpOutgoingConn = htcpIncomingConn;
+ debugs(31, DBG_IMPORTANT, "Sending HTCP messages from " << htcpOutgoingConn->local);
+ }
}
int
@@ -1589,7 +1574,7 @@
MemBuf mb;
http_state_flags flags;
- if (htcpInSocket < 0)
+ if (!Comm::IsConnOpen(htcpIncomingConn))
return 0;
old_squid_format = p->options.htcp_oldsquid;
@@ -1644,7 +1629,7 @@
MemBuf mb;
http_state_flags flags;
- if (htcpInSocket < 0)
+ if (!Comm::IsConnOpen(htcpIncomingConn))
return;
old_squid_format = p->options.htcp_oldsquid;
@@ -1707,21 +1692,17 @@
void
htcpSocketShutdown(void)
{
- if (htcpInSocket < 0)
+ if (!Comm::IsConnOpen(htcpIncomingConn))
return;
- if (htcpInSocket != htcpOutSocket) {
- debugs(12, 1, "FD " << htcpInSocket << " Closing HTCP socket");
- comm_close(htcpInSocket);
- }
-
+ debugs(12, DBG_IMPORTANT, "Stop accepting HTCP on " << htcpIncomingConn->local);
/*
- * Here we set 'htcpInSocket' to -1 even though the HTCP 'in'
+ * Here we just unlink htcpIncomingConn because the HTCP 'in'
* and 'out' sockets might be just one FD. This prevents this
* function from executing repeatedly. When we are really ready to
* exit or restart, main will comm_close the 'out' descriptor.
*/
- htcpInSocket = -1;
+ htcpIncomingConn = NULL;
/*
* Normally we only write to the outgoing HTCP socket, but
@@ -1732,9 +1713,9 @@
/* XXX Don't we need this handler to read replies while shutting down?
* I think there should be a separate hander for reading replies..
*/
- assert(htcpOutSocket > -1);
+ assert(Comm::IsConnOpen(htcpOutgoingConn));
- Comm::SetSelect(htcpOutSocket, COMM_SELECT_READ, NULL, NULL, 0);
+ Comm::SetSelect(htcpOutgoingConn->fd, COMM_SELECT_READ, NULL, NULL, 0);
}
void
@@ -1742,10 +1723,9 @@
{
htcpSocketShutdown();
- if (htcpOutSocket > -1) {
- debugs(12, 1, "FD " << htcpOutSocket << " Closing HTCP socket");
- comm_close(htcpOutSocket);
- htcpOutSocket = -1;
+ if (htcpOutgoingConn != NULL) {
+ debugs(12, DBG_IMPORTANT, "Stop sending HTCP from " << htcpOutgoingConn->local);
+ htcpOutgoingConn = NULL;
}
}
=== modified file 'src/http.cc'
--- src/http.cc 2011-03-23 00:32:37 +0000
+++ src/http.cc 2011-03-26 05:31:32 +0000
@@ -47,6 +47,7 @@
#include "base/AsyncJobCalls.h"
#include "base/TextException.h"
#include "base64.h"
+#include "comm/Connection.h"
#include "comm/Write.h"
#if USE_DELAY_POOLS
#include "DelayPools.h"
@@ -91,7 +92,7 @@
debugs(11,5,HERE << "HttpStateData " << this << " created");
ignoreCacheControl = false;
surrogateNoStore = false;
- fd = fwd->server_fd;
+ serverConnection = fwd->serverConnection();
readBuf = new MemBuf;
readBuf->init();
orig_request = HTTPMSGLOCK(fwd->request);
@@ -100,8 +101,8 @@
orig_request->hier.peer_http_request_sent.tv_sec = 0;
orig_request->hier.peer_http_request_sent.tv_usec = 0;
- if (fwd->servers)
- _peer = fwd->servers->_peer; /* might be NULL */
+ if (fwd->serverConnection() != NULL)
+ _peer = cbdataReference(fwd->serverConnection()->getPeer()); /* might be NULL */
if (_peer) {
const char *url;
@@ -111,8 +112,7 @@
else
url = entry->url();
- HttpRequest * proxy_req = new HttpRequest(orig_request->method,
- orig_request->protocol, url);
+ HttpRequest * proxy_req = new HttpRequest(orig_request->method, orig_request->protocol, url);
proxy_req->SetHost(_peer->host);
@@ -145,9 +145,8 @@
* register the handler to free HTTP state data when the FD closes
*/
typedef CommCbMemFunT Dialer;
- closeHandler = JobCallback(9, 5,
- Dialer, this, HttpStateData::httpStateConnClosed);
- comm_add_close_handler(fd, closeHandler);
+ closeHandler = JobCallback(9, 5, Dialer, this, HttpStateData::httpStateConnClosed);
+ comm_add_close_handler(serverConnection->fd, closeHandler);
}
HttpStateData::~HttpStateData()
@@ -166,14 +165,17 @@
HTTPMSGUNLOCK(orig_request);
- debugs(11,5, HERE << "HttpStateData " << this << " destroyed; FD " << fd);
+ cbdataReferenceDone(_peer);
+
+ debugs(11,5, HERE << "HttpStateData " << this << " destroyed; " << serverConnection);
}
-int
+const Comm::ConnectionPointer &
HttpStateData::dataDescriptor() const
{
- return fd;
+ return serverConnection;
}
+
/*
static void
httpStateFree(int fd, void *data)
@@ -206,13 +208,13 @@
void
HttpStateData::httpTimeout(const CommTimeoutCbParams ¶ms)
{
- debugs(11, 4, "httpTimeout: FD " << fd << ": '" << entry->url() << "'" );
+ debugs(11, 4, HERE << serverConnection << ": '" << entry->url() << "'" );
if (entry->store_status == STORE_PENDING) {
fwd->fail(errorCon(ERR_READ_TIMEOUT, HTTP_GATEWAY_TIMEOUT, fwd->request));
}
- comm_close(fd);
+ serverConnection->close();
}
static void
@@ -785,7 +787,7 @@
typedef NullaryMemFunT CbDialer;
const AsyncCall::Pointer cb = JobCallback(11, 3, CbDialer, this,
HttpStateData::proceedAfter1xx);
- CallJobHere1(11, 4, orig_request->clientConnection, ConnStateData,
+ CallJobHere1(11, 4, orig_request->clientConnectionManager, ConnStateData,
ConnStateData::sendControlMsg, HttpControlMsg(msg, cb));
// If the call is not fired, then the Sink is gone, and HttpStateData
// will terminate due to an aborted store entry or another similar error.
@@ -1006,7 +1008,7 @@
HttpStateData::ConnectionStatus
HttpStateData::persistentConnStatus() const
{
- debugs(11, 3, "persistentConnStatus: FD " << fd << " eof=" << eof);
+ debugs(11, 3, HERE << serverConnection << " eof=" << eof);
if (eof) // already reached EOF
return COMPLETE_NONPERSISTENT_MSG;
@@ -1014,7 +1016,7 @@
I/O to avoid assertions. TODO: Change Comm API to handle callers that
want more I/O after async closing (usually initiated by others). */
// XXX: add canReceive or s/canSend/canTalkToServer/
- if (!canSend(fd))
+ if (!Comm::IsConnOpen(serverConnection))
return COMPLETE_NONPERSISTENT_MSG;
/** \par
@@ -1065,7 +1067,7 @@
HttpStateData::ReadReplyWrapper(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
{
HttpStateData *httpState = static_cast(data);
- assert (fd == httpState->fd);
+ assert (fd == httpState->serverConnection->fd);
// assert(buf == readBuf->content());
PROF_start(HttpStateData_readReply);
httpState->readReply(len, flag, xerrno);
@@ -1081,11 +1083,9 @@
int clen;
int len = io.size;
- assert(fd == io.fd);
-
flags.do_next_read = 0;
- debugs(11, 5, "httpReadReply: FD " << fd << ": len " << len << ".");
+ debugs(11, 5, HERE << io.conn << ": len " << len << ".");
// Bail out early on COMM_ERR_CLOSING - close handlers will tidy up for us
if (io.flag == COMM_ERR_CLOSING) {
@@ -1100,7 +1100,7 @@
// handle I/O errors
if (io.flag != COMM_OK || len < 0) {
- debugs(11, 2, "httpReadReply: FD " << fd << ": read failure: " << xstrerror() << ".");
+ debugs(11, 2, HERE << io.conn << ": read failure: " << xstrerror() << ".");
if (ignoreErrno(io.xerrno)) {
flags.do_next_read = 1;
@@ -1110,7 +1110,7 @@
err->xerrno = io.xerrno;
fwd->fail(err);
flags.do_next_read = 0;
- comm_close(fd);
+ serverConnection->close();
}
return;
@@ -1147,7 +1147,7 @@
* not allowing connection reuse in the first place.
*/
#if DONT_DO_THIS
- if (!flags.headers_parsed && len > 0 && fd_table[fd].uses > 1) {
+ if (!flags.headers_parsed && len > 0 && fd_table[serverConnection->fd].uses > 1) {
/* Skip whitespace between replies */
while (len > 0 && xisspace(*buf))
@@ -1277,7 +1277,7 @@
entry->reset();
fwd->fail(errorCon(error, HTTP_BAD_GATEWAY, fwd->request));
flags.do_next_read = 0;
- comm_close(fd);
+ serverConnection->close();
return false; // quit on error
}
@@ -1355,7 +1355,6 @@
void
HttpStateData::processReplyBody()
{
- AsyncCall::Pointer call;
Ip::Address client_addr;
bool ispinned = false;
@@ -1396,29 +1395,29 @@
} else
switch (persistentConnStatus()) {
case INCOMPLETE_MSG:
- debugs(11, 5, "processReplyBody: INCOMPLETE_MSG");
+ {
+ debugs(11, 5, "processReplyBody: INCOMPLETE_MSG from " << serverConnection);
/* Wait for more data or EOF condition */
+ AsyncCall::Pointer nil;
if (flags.keepalive_broken) {
- call = NULL;
- commSetTimeout(fd, 10, call);
+ commSetConnTimeout(serverConnection, 10, nil);
} else {
- call = NULL;
- commSetTimeout(fd, Config.Timeout.read, call);
+ commSetConnTimeout(serverConnection, Config.Timeout.read, nil);
}
flags.do_next_read = 1;
+ }
break;
case COMPLETE_PERSISTENT_MSG:
- debugs(11, 5, "processReplyBody: COMPLETE_PERSISTENT_MSG");
+ debugs(11, 5, "processReplyBody: COMPLETE_PERSISTENT_MSG from " << serverConnection);
/* yes we have to clear all these! */
- call = NULL;
- commSetTimeout(fd, -1, call);
+ commUnsetConnTimeout(serverConnection);
flags.do_next_read = 0;
- comm_remove_close_handler(fd, closeHandler);
+ comm_remove_close_handler(serverConnection->fd, closeHandler);
closeHandler = NULL;
- fwd->unregister(fd);
+ fwd->unregister(serverConnection);
if (orig_request->flags.spoof_client_ip)
client_addr = orig_request->client_addr;
@@ -1431,19 +1430,18 @@
}
if (orig_request->pinnedConnection() && ispinned) {
- orig_request->pinnedConnection()->pinConnection(fd, orig_request, _peer,
+ orig_request->pinnedConnection()->pinConnection(serverConnection, orig_request, _peer,
(request->flags.connection_auth != 0));
} else {
- fwd->pconnPush(fd, _peer, request, orig_request->GetHost(), client_addr);
+ fwd->pconnPush(serverConnection, request->GetHost());
}
- fd = -1;
-
+ serverConnection = NULL;
serverComplete();
return;
case COMPLETE_NONPERSISTENT_MSG:
- debugs(11, 5, "processReplyBody: COMPLETE_NONPERSISTENT_MSG");
+ debugs(11, 5, "processReplyBody: COMPLETE_NONPERSISTENT_MSG from " << serverConnection);
serverComplete();
return;
}
@@ -1459,7 +1457,7 @@
const int read_size = replyBodySpace(*readBuf, minRead);
debugs(11,9, HERE << (flags.do_next_read ? "may" : "wont") <<
- " read up to " << read_size << " bytes from FD " << fd);
+ " read up to " << read_size << " bytes from " << serverConnection);
/*
* why <2? Because delayAwareRead() won't actually read if
@@ -1475,7 +1473,7 @@
if (flags.do_next_read) {
flags.do_next_read = 0;
typedef CommCbMemFunT Dialer;
- entry->delayAwareRead(fd, readBuf->space(read_size), read_size,
+ entry->delayAwareRead(serverConnection, readBuf->space(read_size), read_size,
JobCallback(11, 5, Dialer, this, HttpStateData::readReply));
}
}
@@ -1484,14 +1482,14 @@
void
HttpStateData::wroteLast(const CommIoCbParams &io)
{
- debugs(11, 5, HERE << "FD " << fd << ": size " << io.size << ": errflag " << io.flag << ".");
+ debugs(11, 5, HERE << serverConnection << ": size " << io.size << ": errflag " << io.flag << ".");
#if URL_CHECKSUM_DEBUG
entry->mem_obj->checkUrlChecksum();
#endif
if (io.size > 0) {
- fd_bytes(fd, io.size, FD_WRITE);
+ fd_bytes(io.fd, io.size, FD_WRITE);
kb_incr(&statCounter.server.all.kbytes_out, io.size);
kb_incr(&statCounter.server.http.kbytes_out, io.size);
}
@@ -1504,7 +1502,7 @@
err = errorCon(ERR_WRITE_ERROR, HTTP_BAD_GATEWAY, fwd->request);
err->xerrno = io.xerrno;
fwd->fail(err);
- comm_close(fd);
+ serverConnection->close();
return;
}
@@ -1527,7 +1525,7 @@
AsyncCall::Pointer timeoutCall = JobCallback(11, 5,
TimeoutDialer, this, HttpStateData::httpTimeout);
- commSetTimeout(fd, Config.Timeout.read, timeoutCall);
+ commSetConnTimeout(serverConnection, Config.Timeout.read, timeoutCall);
flags.request_sent = 1;
@@ -1538,24 +1536,22 @@
void
HttpStateData::closeServer()
{
- debugs(11,5, HERE << "closing HTTP server FD " << fd << " this " << this);
+ debugs(11,5, HERE << "closing HTTP server " << serverConnection << " this " << this);
- if (fd >= 0) {
- fwd->unregister(fd);
- comm_remove_close_handler(fd, closeHandler);
+ if (Comm::IsConnOpen(serverConnection)) {
+ fwd->unregister(serverConnection);
+ comm_remove_close_handler(serverConnection->fd, closeHandler);
closeHandler = NULL;
- comm_close(fd);
- fd = -1;
+ serverConnection->close();
}
}
bool
HttpStateData::doneWithServer() const
{
- return fd < 0;
+ return !Comm::IsConnOpen(serverConnection);
}
-
/*
* Fixup authentication request headers for special cases
*/
@@ -2064,10 +2060,10 @@
{
MemBuf mb;
- debugs(11, 5, "httpSendRequest: FD " << fd << ", request " << request << ", this " << this << ".");
+ debugs(11, 5, HERE << serverConnection << ", request " << request << ", this " << this << ".");
- if (!canSend(fd)) {
- debugs(11,3, HERE << "cannot send request to closing FD " << fd);
+ if (!Comm::IsConnOpen(serverConnection)) {
+ debugs(11,3, HERE << "cannot send request to closing " << serverConnection);
assert(closeHandler != NULL);
return false;
}
@@ -2075,7 +2071,7 @@
typedef CommCbMemFunT TimeoutDialer;
AsyncCall::Pointer timeoutCall = JobCallback(11, 5,
TimeoutDialer, this, HttpStateData::httpTimeout);
- commSetTimeout(fd, Config.Timeout.lifetime, timeoutCall);
+ commSetConnTimeout(serverConnection, Config.Timeout.lifetime, timeoutCall);
flags.do_next_read = 1;
maybeReadVirginBody();
@@ -2136,8 +2132,8 @@
mb.init();
request->peer_host=_peer?_peer->host:NULL;
buildRequestPrefix(request, orig_request, entry, &mb);
- debugs(11, 6, "httpSendRequest: FD " << fd << ":\n" << mb.buf);
- Comm::Write(fd, &mb, requestSender);
+ debugs(11, 6, HERE << serverConnection << ":\n" << mb.buf);
+ Comm::Write(serverConnection, &mb, requestSender);
return true;
}
@@ -2214,8 +2210,8 @@
return false;
}
- if (!canSend(fd)) {
- debugs(11,2, HERE << "ignoring broken POST for closing FD " << fd);
+ if (!Comm::IsConnOpen(serverConnection)) {
+ debugs(11,2, HERE << "ignoring broken POST for closed " << serverConnection);
assert(closeHandler != NULL);
return true; // prevent caller from proceeding as if nothing happened
}
@@ -2224,7 +2220,7 @@
typedef CommCbMemFunT Dialer;
requestSender = JobCallback(11,5,
Dialer, this, HttpStateData::wroteLast);
- Comm::Write(fd, "\r\n", 2, requestSender, NULL);
+ Comm::Write(serverConnection, "\r\n", 2, requestSender, NULL);
return true;
#else
return false;
@@ -2244,9 +2240,8 @@
flags.sentLastChunk = true;
typedef CommCbMemFunT Dialer;
- requestSender = JobCallback(11,5,
- Dialer, this, HttpStateData::wroteLast);
- Comm::Write(fd, "0\r\n\r\n", 5, requestSender, NULL);
+ requestSender = JobCallback(11,5, Dialer, this, HttpStateData::wroteLast);
+ Comm::Write(serverConnection, "0\r\n\r\n", 5, requestSender, NULL);
return true;
}
@@ -2254,7 +2249,7 @@
HttpStateData::doneSendingRequestBody()
{
ServerStateData::doneSendingRequestBody();
- debugs(11,5, HERE << "doneSendingRequestBody: FD " << fd);
+ debugs(11,5, HERE << serverConnection);
// do we need to write something after the last body byte?
if (flags.chunked_request && finishingChunkedRequest())
@@ -2269,7 +2264,7 @@
void
HttpStateData::handleMoreRequestBodyAvailable()
{
- if (eof || fd < 0) {
+ if (eof || !Comm::IsConnOpen(serverConnection)) {
// XXX: we should check this condition in other callbacks then!
// TODO: Check whether this can actually happen: We should unsubscribe
// as a body consumer when the above condition(s) are detected.
@@ -2287,7 +2282,7 @@
debugs(11, 1, "http handleMoreRequestBodyAvailable: Likely proxy abuse detected '" << orig_request->client_addr << "' -> '" << entry->url() << "'" );
if (virginReply()->sline.status == HTTP_INVALID_HEADER) {
- comm_close(fd);
+ serverConnection->close();
return;
}
}
@@ -2302,7 +2297,7 @@
{
ServerStateData::handleRequestBodyProducerAborted();
if (entry->isEmpty()) {
- debugs(11, 3, "request body aborted: FD " << fd);
+ debugs(11, 3, "request body aborted: " << serverConnection);
ErrorState *err;
err = errorCon(ERR_READ_ERROR, HTTP_BAD_GATEWAY, fwd->request);
err->xerrno = errno;
@@ -2329,10 +2324,10 @@
HttpStateData::abortTransaction(const char *reason)
{
debugs(11,5, HERE << "aborting transaction for " << reason <<
- "; FD " << fd << ", this " << this);
+ "; " << serverConnection << ", this " << this);
- if (fd >= 0) {
- comm_close(fd);
+ if (Comm::IsConnOpen(serverConnection)) {
+ serverConnection->close();
return;
}
=== modified file 'src/http.h'
--- src/http.h 2010-09-14 05:40:33 +0000
+++ src/http.h 2010-10-02 15:30:00 +0000
@@ -36,6 +36,7 @@
#include "StoreIOBuffer.h"
#include "comm.h"
+#include "comm/forward.h"
#include "forward.h"
#include "Server.h"
#include "ChunkedCodingParser.h"
@@ -53,7 +54,7 @@
HttpHeader * hdr_out,
const http_state_flags flags);
- virtual int dataDescriptor() const;
+ virtual const Comm::ConnectionPointer & dataDescriptor() const;
/* should be private */
bool sendRequest();
void processReplyHeader();
@@ -66,7 +67,6 @@
int eof; /* reached end-of-object? */
int lastChunk; /* reached last chunk of a chunk-encoded reply */
HttpRequest *orig_request;
- int fd;
http_state_flags flags;
size_t read_sz;
int header_bytes_read; // to find end of response,
@@ -86,6 +86,12 @@
void handle1xx(HttpReply *msg);
private:
+ /**
+ * The current server connection.
+ * Maybe open, closed, or NULL.
+ * Use doneWithServer() to check if the server is available for use.
+ */
+ Comm::ConnectionPointer serverConnection;
AsyncCall::Pointer closeHandler;
enum ConnectionStatus {
INCOMPLETE_MSG,
=== modified file 'src/icmp/net_db.cc'
--- src/icmp/net_db.cc 2010-12-13 11:31:14 +0000
+++ src/icmp/net_db.cc 2011-01-08 11:26:11 +0000
@@ -1336,7 +1336,8 @@
urlCanonical(ex->r);
- FwdState::fwdStart(-1, ex->e, ex->r);
+ Comm::ConnectionPointer nul;
+ FwdState::fwdStart(nul, ex->e, ex->r);
#endif
}
=== modified file 'src/icp_v2.cc'
--- src/icp_v2.cc 2011-03-02 07:27:24 +0000
+++ src/icp_v2.cc 2011-03-26 08:23:12 +0000
@@ -40,6 +40,7 @@
#include "comm.h"
#include "comm/Loops.h"
#include "ICP.h"
+#include "comm/Connection.h"
#include "HttpRequest.h"
#include "acl/FilledChecklist.h"
#include "acl/Acl.h"
@@ -58,24 +59,19 @@
public Ipc::StartListeningCb
{
public:
- typedef void (*Handler)(int fd, int errNo, Ip::Address& addr);
- IcpListeningStartedDialer(Handler aHandler, Ip::Address& anAddr):
- handler(aHandler), addr(anAddr) {}
-
- virtual void print(std::ostream &os) const {
- startPrint(os) <<
- ", address=" << addr << ')';
- }
-
+ typedef void (*Handler)(int errNo);
+ IcpListeningStartedDialer(Handler aHandler):
+ handler(aHandler) {}
+
+ virtual void print(std::ostream &os) const { startPrint(os) << ')'; }
virtual bool canDial(AsyncCall &) const { return true; }
- virtual void dial(AsyncCall &) { (handler)(fd, errNo, addr); }
+ virtual void dial(AsyncCall &) { (handler)(errNo); }
public:
Handler handler;
- Ip::Address addr;
};
-static void icpIncomingConnectionOpened(int fd, int errNo, Ip::Address& addr);
+static void icpIncomingConnectionOpened(int errNo);
/// \ingroup ServerProtocolICPInternal2
static void icpLogIcp(const Ip::Address &, log_type, int, const char *, int);
@@ -99,7 +95,24 @@
static icpUdpData *IcpQueueTail = NULL;
/// \ingroup ServerProtocolICPInternal2
-Ip::Address theOutICPAddr;
+Comm::ConnectionPointer icpIncomingConn = NULL;
+/// \ingroup ServerProtocolICPInternal2
+Comm::ConnectionPointer icpOutgoingConn = NULL;
+
+/** \ingroup ServerProtocolICPInternal2
+ * ICP v2 uses the outgoing address as host ID.
+ * NP: this *may* be identical to icpOutgoingConn->local
+ * but when IN/OUT sockets are shared we can't guarantee that
+ * so a separate variable is used for now.
+ *
+ * We have one for private use (sent only by this local cache)
+ * and one for public use (for external caches to contact us)
+ */
+Ip::Address theIcpPrivateHostID;
+
+/// \see theIcpPrivateHostID
+Ip::Address theIcpPublicHostID;
+
/* icp_common_t */
_icp_common_t::_icp_common_t() : opcode(ICP_INVALID), version(0), length(0), reqnum(0), flags(0), pad(0), shostid(0)
@@ -285,7 +298,7 @@
headerp->pad = htonl(pad);
- theOutICPAddr.GetInAddr( *((struct in_addr*)&headerp->shostid) );
+ theIcpPrivateHostID.GetInAddr( *((struct in_addr*)&headerp->shostid) );
urloffset = buf + sizeof(icp_common_t);
@@ -678,103 +691,108 @@
icpConnectionsOpen(void)
{
uint16_t port;
- Ip::Address addr;
if ((port = Config.Port.icp) <= 0)
return;
- addr = Config.Addrs.udp_incoming;
- addr.SetPort(port);
+ icpIncomingConn = new Comm::Connection;
+ icpIncomingConn->local = Config.Addrs.udp_incoming;
+ icpIncomingConn->local.SetPort(port);
- if (!Ip::EnableIpv6 && !addr.SetIPv4()) {
- debugs(12, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << addr << " is not an IPv4 address.");
+ if (!Ip::EnableIpv6 && !icpIncomingConn->local.SetIPv4()) {
+ debugs(12, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << icpIncomingConn->local << " is not an IPv4 address.");
fatal("ICP port cannot be opened.");
}
/* split-stack for now requires default IPv4-only ICP */
- if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && addr.IsAnyAddr()) {
- addr.SetIPv4();
+ if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && icpIncomingConn->local.IsAnyAddr()) {
+ icpIncomingConn->local.SetIPv4();
}
AsyncCall::Pointer call = asyncCall(12, 2,
"icpIncomingConnectionOpened",
- IcpListeningStartedDialer(&icpIncomingConnectionOpened, addr));
+ IcpListeningStartedDialer(&icpIncomingConnectionOpened));
Ipc::StartListening(SOCK_DGRAM,
IPPROTO_UDP,
- addr,
- COMM_NONBLOCKING,
+ icpIncomingConn,
Ipc::fdnInIcpSocket, call);
- addr.SetEmpty(); // clear for next use.
- addr = Config.Addrs.udp_outgoing;
- if ( !addr.IsNoAddr() ) {
- enter_suid();
- addr.SetPort(port);
+ if ( !Config.Addrs.udp_outgoing.IsNoAddr() ) {
+ icpOutgoingConn = new Comm::Connection;
+ icpOutgoingConn->local = Config.Addrs.udp_outgoing;
+ icpOutgoingConn->local.SetPort(port);
- if (!Ip::EnableIpv6 && !addr.SetIPv4()) {
- debugs(49, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << addr << " is not an IPv4 address.");
+ if (!Ip::EnableIpv6 && !icpOutgoingConn->local.SetIPv4()) {
+ debugs(49, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << icpOutgoingConn->local << " is not an IPv4 address.");
fatal("ICP port cannot be opened.");
}
/* split-stack for now requires default IPv4-only ICP */
- if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && addr.IsAnyAddr()) {
- addr.SetIPv4();
+ if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && icpOutgoingConn->local.IsAnyAddr()) {
+ icpOutgoingConn->local.SetIPv4();
}
- theOutIcpConnection = comm_open_listener(SOCK_DGRAM,
- IPPROTO_UDP,
- addr,
- COMM_NONBLOCKING,
- "ICP Port");
+ enter_suid();
+ comm_open_listener(SOCK_DGRAM, IPPROTO_UDP, icpOutgoingConn, "Outgoing ICP Port");
leave_suid();
- if (theOutIcpConnection < 0)
+ if (!Comm::IsConnOpen(icpOutgoingConn))
fatal("Cannot open Outgoing ICP Port");
- Comm::SetSelect(theOutIcpConnection, COMM_SELECT_READ, icpHandleUdp, NULL, 0);
-
- debugs(12, 1, "Outgoing ICP messages on port " << addr.GetPort() << ", FD " << theOutIcpConnection << ".");
-
- fd_note(theOutIcpConnection, "Outgoing ICP socket");
+ debugs(12, DBG_CRITICAL, "Sending ICP messages from " << icpOutgoingConn->local);
+
+ Comm::SetSelect(icpOutgoingConn->fd, COMM_SELECT_READ, icpHandleUdp, NULL, 0);
+ fd_note(icpOutgoingConn->fd, "Outgoing ICP socket");
icpGetOutgoingIpAddress();
}
}
+// Ensure that we have the IP address(es) to use for Host ID.
+// The outgoing address is used as 'private' host ID used only on packets we send
static void
icpGetOutgoingIpAddress()
{
struct addrinfo *xai = NULL;
- theOutICPAddr.SetEmpty();
- theOutICPAddr.InitAddrInfo(xai);
-
- if (getsockname(theOutIcpConnection, xai->ai_addr, &xai->ai_addrlen) < 0)
- debugs(50, 1, "theOutIcpConnection FD " << theOutIcpConnection << ": getsockname: " << xstrerror());
+ theIcpPrivateHostID.SetEmpty();
+ theIcpPrivateHostID.InitAddrInfo(xai);
+ if (getsockname(icpOutgoingConn->fd, xai->ai_addr, &xai->ai_addrlen) < 0)
+ debugs(50, DBG_IMPORTANT, "ERROR: Unable to identify ICP host ID to use for " << icpOutgoingConn
+ << ": getsockname: " << xstrerror());
else
- theOutICPAddr = *xai;
-
- theOutICPAddr.FreeAddrInfo(xai);
+ theIcpPrivateHostID = *xai;
+ theIcpPrivateHostID.FreeAddrInfo(xai);
}
static void
-icpIncomingConnectionOpened(int fd, int errNo, Ip::Address& addr)
+icpIncomingConnectionOpened(int errNo)
{
- theInIcpConnection = fd;
-
- if (theInIcpConnection < 0)
+ if (!Comm::IsConnOpen(icpIncomingConn))
fatal("Cannot open ICP Port");
- Comm::SetSelect(theInIcpConnection, COMM_SELECT_READ, icpHandleUdp, NULL, 0);
+ Comm::SetSelect(icpIncomingConn->fd, COMM_SELECT_READ, icpHandleUdp, NULL, 0);
for (const wordlist *s = Config.mcast_group_list; s; s = s->next)
- ipcache_nbgethostbyname(s->key, mcastJoinGroups, NULL);
-
- debugs(12, 1, "Accepting ICP messages at " << addr << ", FD " << theInIcpConnection << ".");
-
- fd_note(theInIcpConnection, "Incoming ICP socket");
+ ipcache_nbgethostbyname(s->key, mcastJoinGroups, NULL); // XXX: pass the icpIncomingConn for mcastJoinGroups usage.
+
+ debugs(12, DBG_IMPORTANT, "Accepting ICP messages on " << icpIncomingConn->local);
+
+ fd_note(icpIncomingConn->fd, "Incoming ICP port");
if (Config.Addrs.udp_outgoing.IsNoAddr()) {
- theOutIcpConnection = theInIcpConnection;
+ icpOutgoingConn = icpIncomingConn;
+ debugs(12, DBG_IMPORTANT, "Sending ICP messages from " << icpOutgoingConn->local);
icpGetOutgoingIpAddress();
}
+
+ // Ensure that we have the IP address(es) to use for Host ID.
+ // The listening address is used as 'public' host ID which can be used to contact us
+ struct addrinfo *xai = NULL;
+ theIcpPublicHostID.InitAddrInfo(xai); // reset xai
+ if (getsockname(icpIncomingConn->fd, xai->ai_addr, &xai->ai_addrlen) < 0)
+ debugs(50, DBG_IMPORTANT, "ERROR: Unable to identify ICP host ID to use for " << icpIncomingConn
+ << ": getsockname: " << xstrerror());
+ else
+ theIcpPublicHostID = *xai;
+ theIcpPublicHostID.FreeAddrInfo(xai);
}
/**
@@ -784,21 +802,16 @@
void
icpConnectionShutdown(void)
{
- if (theInIcpConnection < 0)
+ if (!Comm::IsConnOpen(icpIncomingConn))
return;
- if (theInIcpConnection != theOutIcpConnection) {
- debugs(12, 1, "FD " << theInIcpConnection << " Closing ICP connection");
- comm_close(theInIcpConnection);
- }
+ debugs(12, DBG_IMPORTANT, "Stop receiving ICP on " << icpIncomingConn->local);
- /**
- * Here we set 'theInIcpConnection' to -1 even though the ICP 'in'
- * and 'out' sockets might be just one FD. This prevents this
- * function from executing repeatedly. When we are really ready to
- * exit or restart, main will comm_close the 'out' descriptor.
+ /** Release the 'in' socket for lazy closure.
+ * in and out sockets may be sharing one same FD.
+ * This prevents this function from executing repeatedly.
*/
- theInIcpConnection = -1;
+ icpIncomingConn = NULL;
/**
* Normally we only write to the outgoing ICP socket, but
@@ -806,9 +819,9 @@
* to that specific interface. During shutdown, we must
* disable reading on the outgoing socket.
*/
- assert(theOutIcpConnection > -1);
+ assert(Comm::IsConnOpen(icpOutgoingConn));
- Comm::SetSelect(theOutIcpConnection, COMM_SELECT_READ, NULL, NULL, 0);
+ Comm::SetSelect(icpOutgoingConn->fd, COMM_SELECT_READ, NULL, NULL, 0);
}
void
@@ -816,10 +829,9 @@
{
icpConnectionShutdown();
- if (theOutIcpConnection > -1) {
- debugs(12, 1, "FD " << theOutIcpConnection << " Closing ICP connection");
- comm_close(theOutIcpConnection);
- theOutIcpConnection = -1;
+ if (icpOutgoingConn != NULL) {
+ debugs(12, DBG_IMPORTANT, "Stop sending ICP from " << icpOutgoingConn->local);
+ icpOutgoingConn = NULL;
}
}
=== modified file 'src/ident/AclIdent.cc'
--- src/ident/AclIdent.cc 2009-06-02 15:37:40 +0000
+++ src/ident/AclIdent.cc 2011-02-02 07:07:32 +0000
@@ -42,6 +42,7 @@
#include "acl/RegexData.h"
#include "acl/UserData.h"
#include "client_side.h"
+#include "comm/Connection.h"
#include "ident/AclIdent.h"
#include "ident/Ident.h"
@@ -86,8 +87,8 @@
ACLFilledChecklist *checklist = Filled(cl);
if (checklist->rfc931[0]) {
return data->match(checklist->rfc931);
- } else if (checklist->conn() != NULL && checklist->conn()->rfc931[0]) {
- return data->match(checklist->conn()->rfc931);
+ } else if (checklist->conn() != NULL && checklist->conn()->clientConnection != NULL && checklist->conn()->clientConnection->rfc931[0]) {
+ return data->match(checklist->conn()->clientConnection->rfc931);
} else {
debugs(28, 3, HERE << "switching to ident lookup state");
checklist->changeState(IdentLookup::Instance());
@@ -126,10 +127,10 @@
IdentLookup::checkForAsync(ACLChecklist *cl)const
{
ACLFilledChecklist *checklist = Filled(cl);
- if (checklist->conn() != NULL) {
+ if (checklist->conn() != NULL && Comm::IsConnOpen(checklist->conn()->clientConnection)) {
debugs(28, 3, HERE << "Doing ident lookup" );
checklist->asyncInProgress(true);
- Ident::Start(checklist->conn()->me, checklist->conn()->peer, LookupDone, checklist);
+ Ident::Start(checklist->conn()->clientConnection, LookupDone, checklist);
} else {
debugs(28, DBG_IMPORTANT, "IdentLookup::checkForAsync: Can't start ident lookup. No client connection" );
checklist->currentAnswer(ACCESS_DENIED);
@@ -153,8 +154,8 @@
* Cache the ident result in the connection, to avoid redoing ident lookup
* over and over on persistent connections
*/
- if (checklist->conn() != NULL && !checklist->conn()->rfc931[0])
- xstrncpy(checklist->conn()->rfc931, checklist->rfc931, USER_IDENT_SZ);
+ if (checklist->conn() != NULL && checklist->conn()->clientConnection != NULL && !checklist->conn()->clientConnection->rfc931[0])
+ xstrncpy(checklist->conn()->clientConnection->rfc931, checklist->rfc931, USER_IDENT_SZ);
checklist->asyncInProgress(false);
checklist->changeState(ACLChecklist::NullState::Instance());
=== modified file 'src/ident/Ident.cc'
--- src/ident/Ident.cc 2010-11-27 01:58:38 +0000
+++ src/ident/Ident.cc 2010-12-04 12:52:45 +0000
@@ -37,6 +37,9 @@
#if USE_IDENT
#include "comm.h"
+#include "comm/Connection.h"
+#include "comm/ConnOpener.h"
+#include "CommCalls.h"
#include "comm/Write.h"
#include "ident/Config.h"
#include "ident/Ident.h"
@@ -47,6 +50,7 @@
#define IDENT_PORT 113
#define IDENT_KEY_SZ 50
+#define IDENT_BUFSIZE 4096
typedef struct _IdentClient {
IDCB *callback;
@@ -57,18 +61,15 @@
typedef struct _IdentStateData {
hash_link hash; /* must be first */
- int fd; /* IDENT fd */
-
- Ip::Address me;
- Ip::Address my_peer;
+ Comm::ConnectionPointer conn;
IdentClient *clients;
- char buf[4096];
+ char buf[IDENT_BUFSIZE];
} IdentStateData;
-// TODO: make these all a series of Async jobs. They are self-contained callbacks now.
+// TODO: make these all a series of Async job calls. They are self-contained callbacks now.
static IOCB ReadReply;
static PF Close;
-static PF Timeout;
+static CTCB Timeout;
static CNCB ConnectDone;
static hash_table *ident_hash = NULL;
static void ClientAdd(IdentStateData * state, IDCB * callback, void *callback_data);
@@ -104,36 +105,37 @@
{
IdentStateData *state = (IdentStateData *)data;
identCallback(state, NULL);
- comm_close(state->fd);
+ state->conn->close();
hash_remove_link(ident_hash, (hash_link *) state);
xfree(state->hash.key);
cbdataFree(state);
}
void
-Ident::Timeout(int fd, void *data)
+Ident::Timeout(const CommTimeoutCbParams &io)
{
- IdentStateData *state = (IdentStateData *)data;
- debugs(30, 3, "identTimeout: FD " << fd << ", " << state->my_peer);
-
- comm_close(fd);
+ debugs(30, 3, HERE << io.conn);
+ io.conn->close();
}
void
-Ident::ConnectDone(int fd, const DnsLookupDetails &, comm_err_t status, int xerrno, void *data)
+Ident::ConnectDone(const Comm::ConnectionPointer &conn, comm_err_t status, int xerrno, void *data)
{
IdentStateData *state = (IdentStateData *)data;
- IdentClient *c;
if (status != COMM_OK) {
- /* Failed to connect */
- comm_close(fd);
+ if (status == COMM_TIMEOUT) {
+ debugs(30, 3, "IDENT connection timeout to " << state->conn->remote);
+ }
return;
}
+ assert(conn != NULL && conn == state->conn);
+
/*
* see if any of our clients still care
*/
+ IdentClient *c;
for (c = state->clients; c; c = c->next) {
if (cbdataReferenceValid(c->callback_data))
break;
@@ -141,33 +143,39 @@
if (c == NULL) {
/* no clients care */
- comm_close(fd);
+ conn->close();
return;
}
+ comm_add_close_handler(conn->fd, Ident::Close, state);
+
MemBuf mb;
mb.init();
mb.Printf("%d, %d\r\n",
- state->my_peer.GetPort(),
- state->me.GetPort());
-
+ conn->remote.GetPort(),
+ conn->local.GetPort());
AsyncCall::Pointer nil;
- Comm::Write(fd, &mb, nil);
- comm_read(fd, state->buf, BUFSIZ, Ident::ReadReply, state);
- commSetTimeout(fd, Ident::TheConfig.timeout, Ident::Timeout, state);
+ Comm::Write(conn, &mb, nil);
+ AsyncCall::Pointer readCall = commCbCall(5,4, "Ident::ReadReply",
+ CommIoCbPtrFun(Ident::ReadReply, state));
+ comm_read(conn, state->buf, IDENT_BUFSIZE, readCall);
+ AsyncCall::Pointer timeoutCall = commCbCall(5,4, "Ident::Timeout",
+ CommTimeoutCbPtrFun(Ident::Timeout, state));
+ commSetConnTimeout(conn, Ident::TheConfig.timeout, timeoutCall);
}
void
-Ident::ReadReply(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
+Ident::ReadReply(const Comm::ConnectionPointer &conn, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
{
IdentStateData *state = (IdentStateData *)data;
char *ident = NULL;
char *t = NULL;
- assert (buf == state->buf);
+ assert(buf == state->buf);
+ assert(conn->fd == state->conn->fd);
if (flag != COMM_OK || len <= 0) {
- comm_close(fd);
+ state->conn->close();
return;
}
@@ -184,7 +192,7 @@
if ((t = strchr(buf, '\n')))
*t = '\0';
- debugs(30, 5, "identReadReply: FD " << fd << ": Read '" << buf << "'");
+ debugs(30, 5, HERE << conn << ": Read '" << buf << "'");
if (strstr(buf, "USERID")) {
if ((ident = strrchr(buf, ':'))) {
@@ -193,7 +201,7 @@
}
}
- comm_close(fd);
+ state->conn->close();
}
void
@@ -216,17 +224,15 @@
* start a TCP connection to the peer host on port 113
*/
void
-Ident::Start(Ip::Address &me, Ip::Address &my_peer, IDCB * callback, void *data)
+Ident::Start(const Comm::ConnectionPointer &conn, IDCB * callback, void *data)
{
IdentStateData *state;
- int fd;
char key1[IDENT_KEY_SZ];
char key2[IDENT_KEY_SZ];
char key[IDENT_KEY_SZ];
- char ntoabuf[MAX_IPSTRLEN];
- me.ToURL(key1, IDENT_KEY_SZ);
- my_peer.ToURL(key2, IDENT_KEY_SZ);
+ conn->local.ToURL(key1, IDENT_KEY_SZ);
+ conn->remote.ToURL(key2, IDENT_KEY_SZ);
snprintf(key, IDENT_KEY_SZ, "%s,%s", key1, key2);
if (!ident_hash) {
@@ -237,33 +243,20 @@
return;
}
- Ip::Address addr = me;
- addr.SetPort(0); // NP: use random port for secure outbound to IDENT_PORT
-
- fd = comm_open_listener(SOCK_STREAM,
- IPPROTO_TCP,
- addr,
- COMM_NONBLOCKING,
- "ident");
-
- if (fd == COMM_ERROR) {
- /* Failed to get a local socket */
- callback(NULL, data);
- return;
- }
-
CBDATA_INIT_TYPE(IdentStateData);
state = cbdataAlloc(IdentStateData);
state->hash.key = xstrdup(key);
- state->fd = fd;
- state->me = me;
- state->my_peer = my_peer;
+
+ // copy the conn details. We dont want the original FD to be re-used by IDENT.
+ state->conn = conn->copyDetails();
+ // NP: use random port for secure outbound to IDENT_PORT
+ state->conn->local.SetPort(0);
+
ClientAdd(state, callback, data);
hash_join(ident_hash, &state->hash);
- comm_add_close_handler(fd, Ident::Close, state);
- commSetTimeout(fd, Ident::TheConfig.timeout, Ident::Timeout, state);
- state->my_peer.NtoA(ntoabuf,MAX_IPSTRLEN);
- commConnectStart(fd, ntoabuf, IDENT_PORT, Ident::ConnectDone, state);
+
+ AsyncCall::Pointer call = commCbCall(30,3, "Ident::ConnectDone", CommConnectCbPtrFun(Ident::ConnectDone, state));
+ AsyncJob::Start(new Comm::ConnOpener(state->conn, call, Ident::TheConfig.timeout));
}
void
=== modified file 'src/ident/Ident.h'
--- src/ident/Ident.h 2010-11-21 04:40:05 +0000
+++ src/ident/Ident.h 2010-11-27 02:52:51 +0000
@@ -12,8 +12,7 @@
#if USE_IDENT
#include "cbdata.h"
-
-#include "ip/forward.h"
+#include "comm/forward.h"
namespace Ident
{
@@ -26,7 +25,7 @@
* Self-registers with a global ident lookup manager,
* will call Ident::Init() itself if the manager has not been initialized already.
*/
-void Start(Ip::Address &me, Ip::Address &my_peer, IDCB * callback, void *cbdata);
+void Start(const Comm::ConnectionPointer &conn, IDCB * callback, void *cbdata);
/**
\ingroup IdentAPI
=== modified file 'src/ip/Intercept.cc'
--- src/ip/Intercept.cc 2010-07-25 08:10:12 +0000
+++ src/ip/Intercept.cc 2011-03-11 23:43:09 +0000
@@ -31,6 +31,7 @@
*
*/
#include "config.h"
+#include "comm/Connection.h"
#include "ip/Intercept.h"
#include "fde.h"
@@ -96,104 +97,90 @@
void
Ip::Intercept::StopTransparency(const char *str)
{
- if (transparent_active) {
+ if (transparentActive_) {
debugs(89, DBG_IMPORTANT, "Stopping full transparency: " << str);
- transparent_active = 0;
+ transparentActive_ = 0;
}
}
void
Ip::Intercept::StopInterception(const char *str)
{
- if (intercept_active) {
+ if (interceptActive_) {
debugs(89, DBG_IMPORTANT, "Stopping IP interception: " << str);
- intercept_active = 0;
+ interceptActive_ = 0;
}
}
-int
-Ip::Intercept::NetfilterInterception(int fd, const Ip::Address &me, Ip::Address &dst, int silent)
+bool
+Ip::Intercept::NetfilterInterception(const Comm::ConnectionPointer &newConn, int silent)
{
#if LINUX_NETFILTER
- struct addrinfo *lookup = NULL;
-
- dst.GetAddrInfo(lookup,AF_INET);
+ struct sockaddr_in lookup;
+ socklen_t len = sizeof(struct sockaddr_in);
+ newConn->local.GetSockAddr(lookup);
/** \par
* Try NAT lookup for REDIRECT or DNAT targets. */
- if ( getsockopt(fd, IPPROTO_IP, SO_ORIGINAL_DST, lookup->ai_addr, &lookup->ai_addrlen) != 0) {
+ if ( getsockopt(newConn->fd, IPPROTO_IP, SO_ORIGINAL_DST, &lookup, &len) != 0) {
if (!silent) {
- debugs(89, DBG_IMPORTANT, HERE << " NF getsockopt(SO_ORIGINAL_DST) failed on FD " << fd << ": " << xstrerror());
- last_reported = squid_curtime;
+ debugs(89, DBG_IMPORTANT, HERE << " NF getsockopt(SO_ORIGINAL_DST) failed on " << newConn << ": " << xstrerror());
+ lastReported_ = squid_curtime;
}
+ debugs(89, 9, HERE << "address: " << newConn);
+ return false;
} else {
- dst = *lookup;
- }
-
- Address::FreeAddrInfo(lookup);
-
- if (me != dst) {
- debugs(89, 5, HERE << "address NAT: me= " << me << ", dst= " << dst);
- return 0;
- }
-
- debugs(89, 9, HERE << "address: me= " << me << ", dst= " << dst);
+ newConn->local = lookup;
+ debugs(89, 5, HERE << "address NAT: " << newConn);
+ return true;
+ }
#endif
- return -1;
+ return false;
}
-int
-Ip::Intercept::NetfilterTransparent(int fd, const Ip::Address &me, Ip::Address &client, int silent)
+bool
+Ip::Intercept::NetfilterTransparent(const Comm::ConnectionPointer &newConn, int silent)
{
#if LINUX_NETFILTER
-
/* Trust the user configured properly. If not no harm done.
* We will simply attempt a bind outgoing on our own IP.
*/
- if (fd_table[fd].flags.transparent) {
- client.SetPort(0); // allow random outgoing port to prevent address clashes
- debugs(89, 5, HERE << "address TPROXY: me= " << me << ", client= " << client);
- return 0;
- }
-
- debugs(89, 9, HERE << "address: me= " << me << ", client= " << client);
+ newConn->remote.SetPort(0); // allow random outgoing port to prevent address clashes
+ debugs(89, 5, HERE << "address TPROXY: " << newConn);
+ return true;
+#else
+ return false;
#endif
- return -1;
}
-int
-Ip::Intercept::IpfwInterception(int fd, const Ip::Address &me, Ip::Address &dst, int silent)
+bool
+Ip::Intercept::IpfwInterception(const Comm::ConnectionPointer &newConn, int silent)
{
#if IPFW_TRANSPARENT
- struct addrinfo *lookup = NULL;
-
- dst.GetAddrInfo(lookup,AF_INET);
+ struct sockaddr_storage lookup;
+ socklen_t len = sizeof(struct sockaddr_storage);
+ newConn->local.GetSockAddr(lookup, AF_INET);
/** \par
* Try lookup for IPFW interception. */
- if ( getsockname(fd, lookup->ai_addr, &lookup->ai_addrlen) != 0 ) {
+ if ( getsockname(newConn->fd, (struct sockaddr*)&lookup, &len) != 0 ) {
if ( !silent ) {
debugs(89, DBG_IMPORTANT, HERE << " IPFW getsockname(...) failed: " << xstrerror());
- last_reported = squid_curtime;
+ lastReported_ = squid_curtime;
}
+ debugs(89, 9, HERE << "address: " << newConn);
+ return false;
} else {
- dst = *lookup;
- }
-
- Address::FreeAddrInfo(lookup);
-
- if (me != dst) {
- debugs(89, 5, HERE << "address NAT: me= " << me << ", dst= " << dst);
- return 0;
- }
-
- debugs(89, 9, HERE << "address: me= " << me << ", dst= " << dst);
+ newConn->local = lookup;
+ debugs(89, 5, HERE << "address NAT: " << newConn);
+ return true;
+ }
#endif
- return -1;
+ return false;
}
-int
-Ip::Intercept::IpfInterception(int fd, const Ip::Address &me, Ip::Address &client, Ip::Address &dst, int silent)
+bool
+Ip::Intercept::IpfInterception(const Comm::ConnectionPointer &newConn, int silent)
{
#if IPF_TRANSPARENT /* --enable-ipf-transparent */
@@ -215,10 +202,10 @@
obj.ipfo_offset = 0;
#endif
- natLookup.nl_inport = htons(me.GetPort());
- natLookup.nl_outport = htons(dst.GetPort());
- me.GetInAddr(natLookup.nl_inip);
- dst.GetInAddr(natLookup.nl_outip);
+ natLookup.nl_inport = htons(newConn->local.GetPort());
+ newConn->local.GetInAddr(natLookup.nl_inip);
+ natLookup.nl_outport = htons(neConn->remote.GetPort());
+ newConn->remote.GetInAddr(natLookup.nl_outip);
natLookup.nl_flags = IPN_TCP;
if (natfd < 0) {
@@ -237,8 +224,8 @@
if (natfd < 0) {
if (!silent) {
debugs(89, DBG_IMPORTANT, HERE << "NAT open failed: " << xstrerror());
- last_reported = squid_curtime;
- return -1;
+ lastReported_ = squid_curtime;
+ return false;
}
}
@@ -264,33 +251,28 @@
if (errno != ESRCH) {
if (!silent) {
debugs(89, DBG_IMPORTANT, HERE << "NAT lookup failed: ioctl(SIOCGNATL)");
- last_reported = squid_curtime;
+ lastReported_ = squid_curtime;
}
close(natfd);
natfd = -1;
}
- return -1;
+ debugs(89, 9, HERE << "address: " << newConn);
+ return false;
} else {
- if (client != natLookup.nl_realip) {
- client = natLookup.nl_realip;
- client.SetPort(ntohs(natLookup.nl_realport));
- }
- // else. we already copied it.
-
- debugs(89, 5, HERE << "address NAT: me= " << me << ", client= " << client << ", dst= " << dst);
- return 0;
+ newConn->local = natLookup.nl_realip;
+ newConn->local.SetPort(ntohs(natLookup.nl_realport));
+ debugs(89, 5, HERE << "address NAT: " << newConn);
+ return true;
}
- debugs(89, 9, HERE << "address: me= " << me << ", client= " << client << ", dst= " << dst);
-
#endif /* --enable-ipf-transparent */
- return -1;
+ return false;
}
-int
-Ip::Intercept::PfInterception(int fd, const Ip::Address &me, Ip::Address &client, Ip::Address &dst, int silent)
+bool
+Ip::Intercept::PfInterception(const Comm::ConnectionPointer &newConn, int silent)
{
#if PF_TRANSPARENT /* --enable-pf-transparent */
@@ -303,17 +285,17 @@
if (pffd < 0) {
if (!silent) {
debugs(89, DBG_IMPORTANT, HERE << "PF open failed: " << xstrerror());
- last_reported = squid_curtime;
+ lastReported_ = squid_curtime;
}
- return -1;
+ return false;
}
memset(&nl, 0, sizeof(struct pfioc_natlook));
- dst.GetInAddr(nl.saddr.v4);
- nl.sport = htons(dst.GetPort());
+ newConn->remote.GetInAddr(nl.saddr.v4);
+ nl.sport = htons(newConn->remote.GetPort());
- me.GetInAddr(nl.daddr.v4);
- nl.dport = htons(me.GetPort());
+ newConn->local.GetInAddr(nl.daddr.v4);
+ nl.dport = htons(newConn->local.GetPort());
nl.af = AF_INET;
nl.proto = IPPROTO_TCP;
@@ -323,31 +305,26 @@
if (errno != ENOENT) {
if (!silent) {
debugs(89, DBG_IMPORTANT, HERE << "PF lookup failed: ioctl(DIOCNATLOOK)");
- last_reported = squid_curtime;
+ lastReported_ = squid_curtime;
}
close(pffd);
pffd = -1;
}
+ debugs(89, 9, HERE << "address: " << newConn);
+ return false;
} else {
- int natted = (client != nl.rdaddr.v4);
- client = nl.rdaddr.v4;
- client.SetPort(ntohs(nl.rdport));
-
- if (natted) {
- debugs(89, 5, HERE << "address NAT: me= " << me << ", client= " << client << ", dst= " << dst);
- return 0;
- }
+ newConn->local = nl.rdaddr.v4;
+ newConn->local.SetPort(ntohs(nl.rdport));
+ debugs(89, 5, HERE << "address NAT: " << newConn);
+ return true;
}
- debugs(89, 9, HERE << "address: me= " << me << ", client= " << client << ", dst= " << dst);
-
#endif /* --enable-pf-transparent */
- return -1;
+ return false;
}
-
-int
-Ip::Intercept::NatLookup(int fd, const Ip::Address &me, const Ip::Address &peer, Ip::Address &client, Ip::Address &dst)
+bool
+Ip::Intercept::Lookup(const Comm::ConnectionPointer &newConn, const Comm::ConnectionPointer &listenConn)
{
/* --enable-linux-netfilter */
/* --enable-ipfw-transparent */
@@ -355,44 +332,42 @@
/* --enable-pf-transparent */
#if IPF_TRANSPARENT || LINUX_NETFILTER || IPFW_TRANSPARENT || PF_TRANSPARENT
- client = me;
- dst = peer;
-
#if 0
// Crop interception errors down to one per minute.
- int silent = (squid_curtime - last_reported > 60 ? 0 : 1);
+ int silent = (squid_curtime - lastReported_ > 60 ? 0 : 1);
#else
// Show all interception errors.
int silent = 0;
#endif
- debugs(89, 5, HERE << "address BEGIN: me= " << me << ", client= " << client <<
- ", dst= " << dst << ", peer= " << peer);
+ debugs(89, 5, HERE << "address BEGIN: me/client= " << newConn->local << ", destination/me= " << newConn->remote);
+
+ newConn->flags |= (listenConn->flags & (COMM_TRANSPARENT|COMM_INTERCEPTION));
/* NP: try TPROXY first, its much quieter than NAT when non-matching */
- if (transparent_active) {
- if ( NetfilterTransparent(fd, me, dst, silent) == 0) return 0;
+ if (transparentActive_ && listenConn->flags&COMM_TRANSPARENT) {
+ if (NetfilterTransparent(newConn, silent)) return true;
}
/* NAT is only available in IPv4 */
- if ( !me.IsIPv4() ) return -1;
- if ( !peer.IsIPv4() ) return -1;
+ if ( !newConn->local.IsIPv4() ) return false;
+ if ( !newConn->remote.IsIPv4() ) return false;
- if (intercept_active) {
+ if (interceptActive_ && listenConn->flags&COMM_INTERCEPTION) {
/* NAT methods that use sock-opts to return client address */
- if ( NetfilterInterception(fd, me, client, silent) == 0) return 0;
- if ( IpfwInterception(fd, me, client, silent) == 0) return 0;
+ if (NetfilterInterception(newConn, silent)) return true;
+ if (IpfwInterception(newConn, silent)) return true;
/* NAT methods that use ioctl to return client address AND destination address */
- if ( PfInterception(fd, me, client, dst, silent) == 0) return 0;
- if ( IpfInterception(fd, me, client, dst, silent) == 0) return 0;
+ if (PfInterception(newConn, silent)) return true;
+ if (IpfInterception(newConn, silent)) return true;
}
#else /* none of the transparent options configured */
debugs(89, DBG_IMPORTANT, "WARNING: transparent proxying not supported");
#endif
- return -1;
+ return false;
}
bool
=== modified file 'src/ip/Intercept.h'
--- src/ip/Intercept.h 2010-11-27 01:58:38 +0000
+++ src/ip/Intercept.h 2011-02-05 17:35:44 +0000
@@ -26,11 +26,11 @@
class Intercept
{
public:
- Intercept() : transparent_active(0), intercept_active(0), last_reported(0) {};
+ Intercept() : transparentActive_(0), interceptActive_(0), lastReported_(0) {};
~Intercept() {};
/** Perform NAT lookups */
- int NatLookup(int fd, const Address &me, const Address &peer, Address &client, Address &dst);
+ bool Lookup(const Comm::ConnectionPointer &newConn, const Comm::ConnectionPointer &listenConn);
/**
* Test system networking calls for TPROXY support.
@@ -47,14 +47,14 @@
\retval 0 Full transparency is disabled.
\retval 1 Full transparency is enabled and active.
*/
- inline int TransparentActive() { return transparent_active; };
+ inline int TransparentActive() { return transparentActive_; };
/** \par
* Turn on fully Transparent-Proxy activities.
* This function should be called during parsing of the squid.conf
* When any option requiring full-transparency is encountered.
*/
- inline void StartTransparency() { transparent_active=1; };
+ inline void StartTransparency() { transparentActive_=1; };
/** \par
* Turn off fully Transparent-Proxy activities on all new connections.
@@ -68,14 +68,14 @@
\retval 0 IP Interception is disabled.
\retval 1 IP Interception is enabled and active.
*/
- inline int InterceptActive() { return intercept_active; };
+ inline int InterceptActive() { return interceptActive_; };
/** \par
* Turn on IP-Interception-Proxy activities.
* This function should be called during parsing of the squid.conf
* When any option requiring interception / NAT handling is encountered.
*/
- inline void StartInterception() { intercept_active=1; };
+ inline void StartInterception() { interceptActive_=1; };
/** \par
* Turn off IP-Interception-Proxy activities on all new connections.
@@ -91,83 +91,52 @@
/**
* perform Lookups on Netfilter interception targets (REDIRECT, DNAT).
*
- \param silent 0 if errors are to be displayed. 1 if errors are to be hidden.
- \param fd FD for the current TCP connection being tested.
- \param me IP address Squid received the connection on
- \param client IP address from which Squid received the connection.
- * May be updated by the NAT table information.
- * Default is the same value as the me IP address.
- \retval 0 Successfuly located the new address.
- \retval -1 An error occured during NAT lookups.
+ * \param silent 0 if errors are to be displayed. 1 if errors are to be hidden.
+ * \param newConn Details known, to be updated where relevant.
+ * \return Whether successfuly located the new address.
*/
- int NetfilterInterception(int fd, const Address &me, Address &client, int silent);
+ bool NetfilterInterception(const Comm::ConnectionPointer &newConn, int silent);
/**
* perform Lookups on Netfilter fully-transparent interception targets (TPROXY).
*
- \param silent 0 if errors are to be displayed. 1 if errors are to be hidden.
- \param fd FD for the current TCP connection being tested.
- \param me IP address Squid received the connection on
- \param dst IP address to which the request was made.
- * expected to be updated from the NAT table information.
- * Default is the same value as the peer IP address sent to NatLookup().
- \retval 0 Successfuly located the new address.
- \retval -1 An error occured during NAT lookups.
+ * \param silent 0 if errors are to be displayed. 1 if errors are to be hidden.
+ * \param newConn Details known, to be updated where relevant.
+ * \return Whether successfuly located the new address.
*/
- int NetfilterTransparent(int fd, const Address &me, Address &dst, int silent);
+ bool NetfilterTransparent(const Comm::ConnectionPointer &newConn, int silent);
/**
* perform Lookups on IPFW interception.
*
- \param silent 0 if errors are to be displayed. 1 if errors are to be hidden.
- \param fd FD for the current TCP connection being tested.
- \param me IP address Squid received the connection on
- \param client IP address from which Squid received the connection.
- * May be updated by the NAT table information.
- * Default is the same value as the me IP address.
- \retval 0 Successfuly located the new address.
- \retval -1 An error occured during NAT lookups.
+ * \param silent 0 if errors are to be displayed. 1 if errors are to be hidden.
+ * \param newConn Details known, to be updated where relevant.
+ * \return Whether successfuly located the new address.
*/
- int IpfwInterception(int fd, const Address &me, Address &client, int silent);
+ bool IpfwInterception(const Comm::ConnectionPointer &newConn, int silent);
/**
* perform Lookups on IPF interception.
*
- \param silent 0 if errors are to be displayed. 1 if errors are to be hidden.
- \param fd FD for the current TCP connection being tested.
- \param me IP address Squid received the connection on
- \param client IP address from which Squid received the connection.
- * May be updated by the NAT table information.
- * Default is the same value as the me IP address.
- \param dst IP address to which the request was made.
- * expected to be updated from the NAT table information.
- * Default is the same value as the peer IP address sent to NatLookup().
- \retval 0 Successfuly located the new address.
- \retval -1 An error occured during NAT lookups.
+ * \param silent 0 if errors are to be displayed. 1 if errors are to be hidden.
+ * \param newConn Details known, to be updated where relevant.
+ * \return Whether successfuly located the new address.
*/
- int IpfInterception(int fd, const Address &me, Address &client, Address &dst, int silent);
+ bool IpfInterception(const Comm::ConnectionPointer &newConn, int silent);
/**
* perform Lookups on PF interception.
*
- \param silent 0 if errors are to be displayed. 1 if errors are to be hidden.
- \param fd FD for the current TCP connection being tested.
- \param me IP address Squid received the connection on
- \param client IP address from which Squid received the connection.
- * May be updated by the NAT table information.
- * Default is the same value as the me IP address.
- \param dst IP address to which the request was made.
- * expected to be updated from the NAT table information.
- * Default is the same value as the peer IP address sent to NatLookup().
- \retval 0 Successfuly located the new address.
- \retval -1 An error occured during NAT lookups.
+ * \param silent 0 if errors are to be displayed. 1 if errors are to be hidden.
+ * \param newConn Details known, to be updated where relevant.
+ * \return Whether successfuly located the new address.
*/
- int PfInterception(int fd, const Address &me, Address &client, Address &dst, int silent);
-
-
- int transparent_active;
- int intercept_active;
- time_t last_reported; /**< Time of last error report. Throttles NAT error display to 1 per minute */
+ bool PfInterception(const Comm::ConnectionPointer &newConn, int silent);
+
+
+ int transparentActive_;
+ int interceptActive_;
+ time_t lastReported_; /**< Time of last error report. Throttles NAT error display to 1 per minute */
};
#if LINUX_NETFILTER && !defined(IP_TRANSPARENT)
=== modified file 'src/ip/Qos.cci'
--- src/ip/Qos.cci 2010-10-13 00:14:42 +0000
+++ src/ip/Qos.cci 2010-11-04 09:30:59 +0000
@@ -1,12 +1,13 @@
/* Inline QOS functions */
+#include "comm/Connection.h"
int
-Ip::Qos::setSockTos(int fd, tos_t tos)
+Ip::Qos::setSockTos(const Comm::ConnectionPointer &conn, tos_t tos)
{
#ifdef IP_TOS
- int x = setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos_t));
+ int x = setsockopt(conn->fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos_t));
if (x < 0)
- debugs(50, 2, "Ip::Qos::setSockTos: setsockopt(IP_TOS) on FD " << fd << ": " << xstrerror());
+ debugs(50, 2, "Ip::Qos::setSockTos: setsockopt(IP_TOS) on " << conn << ": " << xstrerror());
return x;
#else
debugs(50, DBG_IMPORTANT, "WARNING: setsockopt(IP_TOS) not supported on this platform");
@@ -15,12 +16,12 @@
}
int
-Ip::Qos::setSockNfmark(int fd, nfmark_t mark)
+Ip::Qos::setSockNfmark(const Comm::ConnectionPointer &conn, nfmark_t mark)
{
#if SO_MARK
- int x = setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(nfmark_t));
+ int x = setsockopt(conn->fd, SOL_SOCKET, SO_MARK, &mark, sizeof(nfmark_t));
if (x < 0)
- debugs(50, 2, "setSockNfmark: setsockopt(SO_MARK) on FD " << fd << ": " << xstrerror());
+ debugs(50, 2, "setSockNfmark: setsockopt(SO_MARK) on " << conn << ": " << xstrerror());
return x;
#else
debugs(50, DBG_IMPORTANT, "WARNING: setsockopt(SO_MARK) not supported on this platform");
=== modified file 'src/ip/QosConfig.cc'
--- src/ip/QosConfig.cc 2010-10-13 00:14:42 +0000
+++ src/ip/QosConfig.cc 2011-01-28 09:52:03 +0000
@@ -1,6 +1,7 @@
#include "squid.h"
#include "acl/Gadgets.h"
+#include "comm/Connection.h"
#include "ConfigParser.h"
#include "fde.h"
#include "hier_code.h"
@@ -11,17 +12,17 @@
/* Qos namespace */
void
-Ip::Qos::getTosFromServer(const int server_fd, fde *clientFde)
+Ip::Qos::getTosFromServer(const Comm::ConnectionPointer &server, fde *clientFde)
{
#if USE_QOS_TOS && _SQUID_LINUX_
/* Bug 2537: This part of ZPH only applies to patched Linux kernels. */
tos_t tos = 1;
int tos_len = sizeof(tos);
clientFde->tosFromServer = 0;
- if (setsockopt(server_fd,SOL_IP,IP_RECVTOS,&tos,tos_len)==0) {
+ if (setsockopt(server->fd,SOL_IP,IP_RECVTOS,&tos,tos_len)==0) {
unsigned char buf[512];
int len = 512;
- if (getsockopt(server_fd,SOL_IP,IP_PKTOPTIONS,buf,(socklen_t*)&len) == 0) {
+ if (getsockopt(server->fd,SOL_IP,IP_PKTOPTIONS,buf,(socklen_t*)&len) == 0) {
/* Parse the PKTOPTIONS structure to locate the TOS data message
* prepared in the kernel by the ZPH incoming TCP TOS preserving
* patch.
@@ -40,15 +41,15 @@
pbuf += CMSG_LEN(o->cmsg_len);
}
} else {
- debugs(33, 1, "QOS: error in getsockopt(IP_PKTOPTIONS) on FD " << server_fd << " " << xstrerror());
+ debugs(33, DBG_IMPORTANT, "QOS: error in getsockopt(IP_PKTOPTIONS) on " << server << " " << xstrerror());
}
} else {
- debugs(33, 1, "QOS: error in setsockopt(IP_RECVTOS) on FD " << server_fd << " " << xstrerror());
+ debugs(33, DBG_IMPORTANT, "QOS: error in setsockopt(IP_RECVTOS) on " << server << " " << xstrerror());
}
#endif
}
-void Ip::Qos::getNfmarkFromServer(const int server_fd, const fde *servFde, const fde *clientFde)
+void Ip::Qos::getNfmarkFromServer(const Comm::ConnectionPointer &server, const fde *clientFde)
{
#if USE_LIBNETFILTERCONNTRACK
/* Allocate a new conntrack */
@@ -59,34 +60,27 @@
* port numbers.
*/
- Ip::Address serv_fde_local_conn;
- struct addrinfo *addr = NULL;
- serv_fde_local_conn.InitAddrInfo(addr);
- getsockname(server_fd, addr->ai_addr, &(addr->ai_addrlen));
- serv_fde_local_conn = *addr;
- serv_fde_local_conn.GetAddrInfo(addr);
-
- unsigned short serv_fde_local_port = ((struct sockaddr_in*)addr->ai_addr)->sin_port;
- struct in6_addr serv_fde_local_ip6;
- struct in_addr serv_fde_local_ip;
-
- if (Ip::EnableIpv6 && serv_fde_local_conn.IsIPv6()) {
- serv_fde_local_ip6 = ((struct sockaddr_in6*)addr->ai_addr)->sin6_addr;
+ if (Ip::EnableIpv6 && server->local.IsIPv6()) {
nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET6);
struct in6_addr serv_fde_remote_ip6;
- inet_pton(AF_INET6,servFde->ipaddr,(struct in6_addr*)&serv_fde_remote_ip6);
+ server->remote.GetInAddr(serv_fde_remote_ip6);
nfct_set_attr(ct, ATTR_IPV6_DST, serv_fde_remote_ip6.s6_addr);
+ struct in6_addr serv_fde_local_ip6;
+ server->local.GetInAddr(serv_fde_local_ip6);
nfct_set_attr(ct, ATTR_IPV6_SRC, serv_fde_local_ip6.s6_addr);
} else {
- serv_fde_local_ip = ((struct sockaddr_in*)addr->ai_addr)->sin_addr;
nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET);
- nfct_set_attr_u32(ct, ATTR_IPV4_DST, inet_addr(servFde->ipaddr));
+ struct in_addr serv_fde_remote_ip;
+ server->remote.GetInAddr(serv_fde_remote_ip);
+ nfct_set_attr_u32(ct, ATTR_IPV4_DST, serv_fde_remote_ip.s_addr);
+ struct in_addr serv_fde_local_ip;
+ server->local.GetInAddr(serv_fde_local_ip);
nfct_set_attr_u32(ct, ATTR_IPV4_SRC, serv_fde_local_ip.s_addr);
}
nfct_set_attr_u8(ct, ATTR_L4PROTO, IPPROTO_TCP);
- nfct_set_attr_u16(ct, ATTR_PORT_DST, htons(servFde->remote_port));
- nfct_set_attr_u16(ct, ATTR_PORT_SRC, serv_fde_local_port);
+ nfct_set_attr_u16(ct, ATTR_PORT_DST, htons(server->remote.GetPort()));
+ nfct_set_attr_u16(ct, ATTR_PORT_SRC, htons(server->local.GetPort()));
/* Open a handle to the conntrack */
if (struct nfct_handle *h = nfct_open(CONNTRACK, 0)) {
@@ -96,15 +90,12 @@
int x = nfct_query(h, NFCT_Q_GET, ct);
if (x == -1) {
debugs(17, 2, "QOS: Failed to retrieve connection mark: (" << x << ") " << strerror(errno)
- << " (Destination " << servFde->ipaddr << ":" << servFde->remote_port
- << ", source " << serv_fde_local_conn << ")" );
+ << " (Destination " << server->remote << ", source " << server->local << ")" );
}
-
nfct_close(h);
} else {
debugs(17, 2, "QOS: Failed to open conntrack handle for upstream netfilter mark retrieval.");
}
- serv_fde_local_conn.FreeAddrInfo(addr);
nfct_destroy(ct);
} else {
@@ -128,7 +119,7 @@
#endif
int
-Ip::Qos::doTosLocalMiss(const int fd, const hier_code hierCode)
+Ip::Qos::doTosLocalMiss(const Comm::ConnectionPointer &conn, const hier_code hierCode)
{
tos_t tos = 0;
if (Ip::Qos::TheConfig.tosSiblingHit && hierCode==SIBLING_HIT) {
@@ -141,14 +132,14 @@
tos = Ip::Qos::TheConfig.tosMiss;
debugs(33, 2, "QOS: Cache miss, setting TOS=" << int(tos));
} else if (Ip::Qos::TheConfig.preserveMissTos && Ip::Qos::TheConfig.preserveMissTosMask) {
- tos = fd_table[fd].tosFromServer & Ip::Qos::TheConfig.preserveMissTosMask;
+ tos = fd_table[conn->fd].tosFromServer & Ip::Qos::TheConfig.preserveMissTosMask;
debugs(33, 2, "QOS: Preserving TOS on miss, TOS=" << int(tos));
}
- return setSockTos(fd, tos);
+ return setSockTos(conn, tos);
}
int
-Ip::Qos::doNfmarkLocalMiss(const int fd, const hier_code hierCode)
+Ip::Qos::doNfmarkLocalMiss(const Comm::ConnectionPointer &conn, const hier_code hierCode)
{
nfmark_t mark = 0;
if (Ip::Qos::TheConfig.markSiblingHit && hierCode==SIBLING_HIT) {
@@ -161,24 +152,24 @@
mark = Ip::Qos::TheConfig.markMiss;
debugs(33, 2, "QOS: Cache miss, setting Mark=" << mark);
} else if (Ip::Qos::TheConfig.preserveMissMark) {
- mark = fd_table[fd].nfmarkFromServer & Ip::Qos::TheConfig.preserveMissMarkMask;
+ mark = fd_table[conn->fd].nfmarkFromServer & Ip::Qos::TheConfig.preserveMissMarkMask;
debugs(33, 2, "QOS: Preserving mark on miss, Mark=" << mark);
}
- return setSockNfmark(fd, mark);
+ return setSockNfmark(conn, mark);
}
int
-Ip::Qos::doTosLocalHit(const int fd)
+Ip::Qos::doTosLocalHit(const Comm::ConnectionPointer &conn)
{
debugs(33, 2, "QOS: Setting TOS for local hit, TOS=" << int(Ip::Qos::TheConfig.tosLocalHit));
- return setSockTos(fd, Ip::Qos::TheConfig.tosLocalHit);
+ return setSockTos(conn, Ip::Qos::TheConfig.tosLocalHit);
}
int
-Ip::Qos::doNfmarkLocalHit(const int fd)
+Ip::Qos::doNfmarkLocalHit(const Comm::ConnectionPointer &conn)
{
debugs(33, 2, "QOS: Setting netfilter mark for local hit, mark=" << Ip::Qos::TheConfig.markLocalHit);
- return setSockNfmark(fd, Ip::Qos::TheConfig.markLocalHit);
+ return setSockNfmark(conn, Ip::Qos::TheConfig.markLocalHit);
}
/* Qos::Config class */
=== modified file 'src/ip/QosConfig.h'
--- src/ip/QosConfig.h 2010-11-27 01:58:38 +0000
+++ src/ip/QosConfig.h 2011-01-08 11:24:39 +0000
@@ -2,6 +2,7 @@
#define SQUID_QOSCONFIG_H
#include "hier_code.h"
+#include "ip/forward.h"
#if HAVE_LIBNETFILTER_CONNTRACK_LIBNETFILTER_CONNTRACK_H
#include
@@ -28,89 +29,88 @@
namespace Qos
{
-/**
-* Function to retrieve the TOS value of the inbound packet.
-* Called by FwdState::dispatch if QOS options are enabled.
-* Bug 2537: This part of ZPH only applies to patched Linux kernels
-* @param server_fd Server side descriptor of connection to get TOS for
-* @param clientFde Pointer to client side fde instance to set tosFromServer in
-*/
-void getTosFromServer(const int server_fd, fde *clientFde);
+ /**
+ * Function to retrieve the TOS value of the inbound packet.
+ * Called by FwdState::dispatch if QOS options are enabled.
+ * Bug 2537: This part of ZPH only applies to patched Linux kernels
+ * @param server Server side descriptor of connection to get TOS for
+ * @param clientFde Pointer to client side fde instance to set tosFromServer in
+ */
+ void getTosFromServer(const Comm::ConnectionPointer &server, fde *clientFde);
-/**
-* Function to retrieve the netfilter mark value of the connection
-* to the upstream server. Called by FwdState::dispatch if QOS
-* options are enabled.
-* @param server_fd Server side descriptor of connection to get mark for
-* @param servFde Pointer to server side fde instance to get mark for
-* @param clientFde Pointer to client side fde instance to set nfmarkFromServer in
-*/
-void getNfmarkFromServer(const int server_fd, const fde *servFde, const fde *clientFde);
+ /**
+ * Function to retrieve the netfilter mark value of the connection
+ * to the upstream server. Called by FwdState::dispatch if QOS
+ * options are enabled.
+ * @param server Server side descriptor of connection to get mark for
+ * @param clientFde Pointer to client side fde instance to set nfmarkFromServer in
+ */
+ void getNfmarkFromServer(const Comm::ConnectionPointer &server, const fde *clientFde);
#if USE_LIBNETFILTERCONNTRACK
-/**
-* Callback function to mark connection once it's been found.
-* This function is called by the libnetfilter_conntrack
-* libraries, during nfct_query in Ip::Qos::getNfmarkFromServer.
-* nfct_callback_register is used to register this function.
-* @param nf_conntrack_msg_type Type of conntrack message
-* @param nf_conntrack Pointer to the conntrack structure
-* @param clientFde Pointer to client side fde instance to set nfmarkFromServer in
-*/
-int getNfMarkCallback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *clientFde);
+ /**
+ * Callback function to mark connection once it's been found.
+ * This function is called by the libnetfilter_conntrack
+ * libraries, during nfct_query in Ip::Qos::getNfmarkFromServer.
+ * nfct_callback_register is used to register this function.
+ * @param nf_conntrack_msg_type Type of conntrack message
+ * @param nf_conntrack Pointer to the conntrack structure
+ * @param clientFde Pointer to client side fde instance to set nfmarkFromServer in
+ */
+ int getNfMarkCallback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *clientFde);
#endif
-/**
-* Function to work out and then apply to the socket the appropriate
-* TOS value to set on packets when items have not been retrieved from
-* local cache. Called by clientReplyContext::sendMoreData if QOS is
-* enabled for TOS.
-* @param fd Descriptor of socket to set the TOS for
-* @param hierCode Hier code of request
-*/
-int doTosLocalMiss(const int fd, const hier_code hierCode);
-
-/**
-* Function to work out and then apply to the socket the appropriate
-* netfilter mark value to set on packets when items have not been
-* retrieved from local cache. Called by clientReplyContext::sendMoreData
-* if QOS is enabled for TOS.
-* @param fd Descriptor of socket to set the mark for
-* @param hierCode Hier code of request
-*/
-int doNfmarkLocalMiss(const int fd, const hier_code hierCode);
-
-/**
-* Function to work out and then apply to the socket the appropriate
-* TOS value to set on packets when items *have* been retrieved from
-* local cache. Called by clientReplyContext::doGetMoreData if QOS is
-* enabled for TOS.
-* @param fd Descriptor of socket to set the TOS for
-*/
-int doTosLocalHit(const int fd);
-
-/**
-* Function to work out and then apply to the socket the appropriate
-* netfilter mark value to set on packets when items *have* been
-* retrieved from local cache. Called by clientReplyContext::doGetMoreData
-* if QOS is enabled for TOS.
-* @param fd Descriptor of socket to set the mark for
-*/
-int doNfmarkLocalHit(const int fd);
-
-/**
-* Function to set the TOS value of packets. Sets the value on the socket
-* which then gets copied to the packets.
-* @param fd Descriptor of socket to set the TOS for
-*/
-_SQUID_INLINE_ int setSockTos(int fd, tos_t tos);
-
-/**
-* Function to set the netfilter mark value of packets. Sets the value on the
-* socket which then gets copied to the packets. Called from Ip::Qos::doNfmarkLocalMiss
-* @param fd Descriptor of socket to set the mark for
-*/
-_SQUID_INLINE_ int setSockNfmark(int fd, nfmark_t mark);
+ /**
+ * Function to work out and then apply to the socket the appropriate
+ * TOS value to set on packets when items have not been retrieved from
+ * local cache. Called by clientReplyContext::sendMoreData if QOS is
+ * enabled for TOS.
+ * @param conn Descriptor of socket to set the TOS for
+ * @param hierCode Hier code of request
+ */
+ int doTosLocalMiss(const Comm::ConnectionPointer &conn, const hier_code hierCode);
+
+ /**
+ * Function to work out and then apply to the socket the appropriate
+ * netfilter mark value to set on packets when items have not been
+ * retrieved from local cache. Called by clientReplyContext::sendMoreData
+ * if QOS is enabled for TOS.
+ * @param conn Descriptor of socket to set the mark for
+ * @param hierCode Hier code of request
+ */
+ int doNfmarkLocalMiss(const Comm::ConnectionPointer &conn, const hier_code hierCode);
+
+ /**
+ * Function to work out and then apply to the socket the appropriate
+ * TOS value to set on packets when items *have* been retrieved from
+ * local cache. Called by clientReplyContext::doGetMoreData if QOS is
+ * enabled for TOS.
+ * @param conn Descriptor of socket to set the TOS for
+ */
+ int doTosLocalHit(const Comm::ConnectionPointer &conn);
+
+ /**
+ * Function to work out and then apply to the socket the appropriate
+ * netfilter mark value to set on packets when items *have* been
+ * retrieved from local cache. Called by clientReplyContext::doGetMoreData
+ * if QOS is enabled for TOS.
+ * @param conn Descriptor of socket to set the mark for
+ */
+ int doNfmarkLocalHit(const Comm::ConnectionPointer &conn);
+
+ /**
+ * Function to set the TOS value of packets. Sets the value on the socket
+ * which then gets copied to the packets.
+ * @param conn Descriptor of socket to set the TOS for
+ */
+ _SQUID_INLINE_ int setSockTos(const Comm::ConnectionPointer &conn, tos_t tos);
+
+ /**
+ * Function to set the netfilter mark value of packets. Sets the value on the
+ * socket which then gets copied to the packets. Called from Ip::Qos::doNfmarkLocalMiss
+ * @param conn Descriptor of socket to set the mark for
+ */
+ _SQUID_INLINE_ int setSockNfmark(const Comm::ConnectionPointer &conn, nfmark_t mark);
/**
* QOS configuration class. Contains all the parameters for QOS functions as well
=== modified file 'src/ipc.cc'
--- src/ipc.cc 2010-05-02 19:32:42 +0000
+++ src/ipc.cc 2010-10-09 03:24:43 +0000
@@ -31,7 +31,7 @@
*/
#include "squid.h"
-#include "comm.h"
+#include "comm/Connection.h"
#include "fde.h"
#include "ip/Address.h"
#include "rfc1738.h"
@@ -129,18 +129,18 @@
if (pipe(p2c) < 0) {
debugs(54, 0, "ipcCreate: pipe: " << xstrerror());
- return -1;
- }
-
- if (pipe(c2p) < 0) {
- debugs(54, 0, "ipcCreate: pipe: " << xstrerror());
- return -1;
- }
-
+ return -1; // maybe ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
+ }
fd_open(prfd = p2c[0], FD_PIPE, "IPC FIFO Parent Read");
fd_open(cwfd = p2c[1], FD_PIPE, "IPC FIFO Child Write");
+
+ if (pipe(c2p) < 0) {
+ debugs(54, 0, "ipcCreate: pipe: " << xstrerror());
+ return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
+ }
fd_open(crfd = c2p[0], FD_PIPE, "IPC FIFO Child Read");
fd_open(pwfd = c2p[1], FD_PIPE, "IPC FIFO Parent Write");
+
#if HAVE_SOCKETPAIR && defined(AF_UNIX)
} else if (type == IPC_UNIX_STREAM) {
=== modified file 'src/ipc/Coordinator.cc'
--- src/ipc/Coordinator.cc 2011-02-03 07:39:31 +0000
+++ src/ipc/Coordinator.cc 2011-03-03 07:52:29 +0000
@@ -7,9 +7,11 @@
#include "config.h"
+#include "base/Subscription.h"
#include "base/TextException.h"
#include "CacheManager.h"
#include "comm.h"
+#include "comm/Connection.h"
#include "ipc/Coordinator.h"
#include "ipc/SharedListen.h"
#include "mgr/Inquirer.h"
@@ -119,14 +121,14 @@
" needs shared listen FD for " << request.params.addr);
Listeners::const_iterator i = listeners.find(request.params);
int errNo = 0;
- const int sock = (i != listeners.end()) ?
+ const Comm::ConnectionPointer c = (i != listeners.end()) ?
i->second : openListenSocket(request, errNo);
- debugs(54, 3, HERE << "sending shared listen FD " << sock << " for " <<
+ debugs(54, 3, HERE << "sending shared listen " << c << " for " <<
request.params.addr << " to kid" << request.requestorId <<
" mapId=" << request.mapId);
- SharedListenResponse response(sock, errNo, request.mapId);
+ SharedListenResponse response(c, errNo, request.mapId);
TypedMsgHdr message;
response.pack(message);
SendMessage(MakeAddr(strandAddrPfx, request.requestorId), message);
@@ -176,7 +178,7 @@
}
#endif
-int
+Comm::ConnectionPointer
Ipc::Coordinator::openListenSocket(const SharedListenRequest& request,
int &errNo)
{
@@ -185,19 +187,23 @@
debugs(54, 6, HERE << "opening listen FD at " << p.addr << " for kid" <<
request.requestorId);
- Ip::Address addr = p.addr; // comm_open_listener may modify it
+ Comm::ConnectionPointer conn = new Comm::Connection;
+ conn->local = p.addr; // comm_open_listener may modify it
+ conn->flags = p.flags;
enter_suid();
- const int sock = comm_open_listener(p.sock_type, p.proto, addr, p.flags,
- FdNote(p.fdNote));
- errNo = (sock >= 0) ? 0 : errno;
+ comm_open_listener(p.sock_type, p.proto, conn, FdNote(p.fdNote));
+ errNo = Comm::IsConnOpen(conn) ? 0 : errno;
leave_suid();
+ debugs(54, 6, HERE << "tried listening on " << conn << " for kid" <<
+ request.requestorId);
+
// cache positive results
- if (sock >= 0)
- listeners[request.params] = sock;
+ if (Comm::IsConnOpen(conn))
+ listeners[request.params] = conn;
- return sock;
+ return conn;
}
void Ipc::Coordinator::broadcastSignal(int sig) const
=== modified file 'src/ipc/Coordinator.h'
--- src/ipc/Coordinator.h 2011-01-31 14:04:00 +0000
+++ src/ipc/Coordinator.h 2011-03-03 06:23:45 +0000
@@ -53,12 +53,12 @@
void handleSnmpResponse(const Snmp::Response& response);
#endif
/// calls comm_open_listener()
- int openListenSocket(const SharedListenRequest& request, int &errNo);
+ Comm::ConnectionPointer openListenSocket(const SharedListenRequest& request, int &errNo);
private:
StrandCoords strands_; ///< registered processes and threads
- typedef std::map Listeners; ///< params:fd map
+ typedef std::map Listeners; ///< params:fd map
Listeners listeners; ///< cached comm_open_listener() results
static Coordinator* TheInstance; ///< the only class instance in existence
=== modified file 'src/ipc/Forwarder.cc'
--- src/ipc/Forwarder.cc 2011-02-03 08:02:28 +0000
+++ src/ipc/Forwarder.cc 2011-03-26 08:23:20 +0000
@@ -8,6 +8,9 @@
#include "config.h"
#include "base/AsyncJobCalls.h"
#include "base/TextException.h"
+#include "errorpage.h"
+#include "HttpReply.h"
+#include "HttpRequest.h"
#include "ipc/Forwarder.h"
#include "ipc/Port.h"
#include "ipc/TypedMsgHdr.h"
=== modified file 'src/ipc/Forwarder.h'
--- src/ipc/Forwarder.h 2011-01-19 10:12:54 +0000
+++ src/ipc/Forwarder.h 2011-03-04 14:25:09 +0000
@@ -9,6 +9,7 @@
#define SQUID_IPC_FORWARDER_H
#include "base/AsyncJob.h"
+#include "mgr/ActionParams.h"
#include "ipc/Request.h"
#include