=== 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 === modified file 'src/ipc/Inquirer.cc' --- src/ipc/Inquirer.cc 2011-03-02 16:40:40 +0000 +++ src/ipc/Inquirer.cc 2011-03-03 08:09:22 +0000 @@ -7,6 +7,7 @@ #include "config.h" #include "base/TextException.h" +#include "comm.h" #include "comm/Write.h" #include "ipc/Inquirer.h" #include "ipc/Port.h" === modified file 'src/ipc/Port.cc' --- src/ipc/Port.cc 2010-08-24 00:12:54 +0000 +++ src/ipc/Port.cc 2011-03-26 08:23:39 +0000 @@ -7,7 +7,9 @@ #include "config.h" +#include "comm.h" #include "CommCalls.h" +#include "comm/Connection.h" #include "ipc/Port.h" const char Ipc::coordinatorAddr[] = DEFAULT_PREFIX "/var/run/coordinator.ipc"; @@ -33,7 +35,7 @@ typedef CommCbMemFunT Dialer; AsyncCall::Pointer readHandler = JobCallback(54, 6, Dialer, this, Port::noteRead); - comm_read(fd(), buf.raw(), buf.size(), readHandler); + comm_read(conn(), buf.raw(), buf.size(), readHandler); } bool Ipc::Port::doneAll() const @@ -53,7 +55,7 @@ void Ipc::Port::noteRead(const CommIoCbParams& params) { - debugs(54, 6, HERE << "FD " << params.fd << " flag " << params.flag << + debugs(54, 6, HERE << params.conn << " flag " << params.flag << " [" << this << ']'); if (params.flag == COMM_OK) { assert(params.buf == buf.raw()); === modified file 'src/ipc/SharedListen.cc' --- src/ipc/SharedListen.cc 2010-10-28 18:52:59 +0000 +++ src/ipc/SharedListen.cc 2011-03-26 08:24:25 +0000 @@ -9,6 +9,7 @@ #include #include "comm.h" #include "base/TextException.h" +#include "comm/Connection.h" #include "ipc/Port.h" #include "ipc/Messages.h" #include "ipc/Kids.h" @@ -16,7 +17,6 @@ #include "ipc/StartListening.h" #include "ipc/SharedListen.h" - /// holds information necessary to handle JoinListen response class PendingOpenRequest { @@ -82,24 +82,26 @@ } -Ipc::SharedListenResponse::SharedListenResponse(int aFd, int anErrNo, int aMapId): - fd(aFd), errNo(anErrNo), mapId(aMapId) +Ipc::SharedListenResponse::SharedListenResponse(const Comm::ConnectionPointer &c, int anErrNo, int aMapId): + conn(c), errNo(anErrNo), mapId(aMapId) { } Ipc::SharedListenResponse::SharedListenResponse(const TypedMsgHdr &hdrMsg): - fd(-1), errNo(0), mapId(-1) + conn(NULL), errNo(0), mapId(-1) { hdrMsg.checkType(mtSharedListenResponse); hdrMsg.getPod(*this); - fd = hdrMsg.getFd(); + conn = new Comm::Connection; + conn->fd = hdrMsg.getFd(); + // other conn details are passed in OpenListenerParams and filled out by SharedListenJoin() } void Ipc::SharedListenResponse::pack(TypedMsgHdr &hdrMsg) const { hdrMsg.setType(mtSharedListenResponse); hdrMsg.putPod(*this); - hdrMsg.putFd(fd); + hdrMsg.putFd(conn->fd); } @@ -125,9 +127,10 @@ void Ipc::SharedListenJoined(const SharedListenResponse &response) { - const int fd = response.fd; + Comm::ConnectionPointer c = response.conn; - debugs(54, 3, HERE << "got listening FD " << fd << " errNo=" << + // Dont debugs c fully since only FD is filled right now. + debugs(54, 3, HERE << "got listening FD " << c->fd << " errNo=" << response.errNo << " mapId=" << response.mapId); Must(TheSharedListenRequestMap.find(response.mapId) != TheSharedListenRequestMap.end()); @@ -135,20 +138,23 @@ Must(por.callback != NULL); TheSharedListenRequestMap.erase(response.mapId); - if (fd >= 0) { + if (Comm::IsConnOpen(c)) { OpenListenerParams &p = por.params; + c->local = p.addr; + c->flags = p.flags; + // XXX: leave the comm AI stuff to comm_import_opened()? struct addrinfo *AI = NULL; p.addr.GetAddrInfo(AI); AI->ai_socktype = p.sock_type; AI->ai_protocol = p.proto; - comm_import_opened(fd, p.addr, p.flags, FdNote(p.fdNote), AI); + comm_import_opened(c, FdNote(p.fdNote), AI); p.addr.FreeAddrInfo(AI); } - StartListeningCb *cbd = - dynamic_cast(por.callback->getDialer()); + StartListeningCb *cbd = dynamic_cast(por.callback->getDialer()); Must(cbd); - cbd->fd = fd; + cbd->conn = c; cbd->errNo = response.errNo; + cbd->handlerSubscription = por.params.handlerSubscription; ScheduleCallHere(por.callback); } === modified file 'src/ipc/SharedListen.h' --- src/ipc/SharedListen.h 2010-07-06 23:09:44 +0000 +++ src/ipc/SharedListen.h 2010-11-26 03:37:04 +0000 @@ -9,13 +9,15 @@ #define SQUID_IPC_SHARED_LISTEN_H #include "base/AsyncCall.h" +#include "base/Subscription.h" namespace Ipc { /// "shared listen" is when concurrent processes are listening on the same fd -/// comm_open_listener() parameters holder +/// Comm::ConnAcceptor parameters holder +/// all the details necessary to recreate a Comm::Connection and fde entry for the kid listener FD class OpenListenerParams { public: @@ -23,11 +25,17 @@ bool operator <(const OpenListenerParams &p) const; ///< useful for map<> + // bits to re-create the fde entry int sock_type; int proto; + int fdNote; ///< index into fd_note() comment strings + + // bits to re-create the listener Comm::Connection descriptor Ip::Address addr; ///< will be memset and memcopied int flags; - int fdNote; ///< index into fd_note() comment strings + + /// handler to subscribe to Comm::ConnAcceptor when we get the response + Subscription::Pointer handlerSubscription; }; class TypedMsgHdr; @@ -52,12 +60,12 @@ class SharedListenResponse { public: - SharedListenResponse(int fd, int errNo, int mapId); + SharedListenResponse(const Comm::ConnectionPointer &c, int errNo, int mapId); explicit SharedListenResponse(const TypedMsgHdr &hdrMsg); ///< from recvmsg() void pack(TypedMsgHdr &hdrMsg) const; ///< prepare for sendmsg() public: - int fd; ///< opened listening socket or -1 + Comm::ConnectionPointer conn; ///< opened listening socket or -1 int errNo; ///< errno value from comm_open_sharedListen() call int mapId; ///< to map future response to the requestor's callback }; === modified file 'src/ipc/StartListening.cc' --- src/ipc/StartListening.cc 2011-01-22 01:12:30 +0000 +++ src/ipc/StartListening.cc 2011-01-28 10:44:26 +0000 @@ -8,11 +8,12 @@ #include "config.h" #include "base/TextException.h" #include "comm.h" +#include "comm/Connection.h" #include "ipc/SharedListen.h" #include "ipc/StartListening.h" -Ipc::StartListeningCb::StartListeningCb(): fd(-1), errNo(0) +Ipc::StartListeningCb::StartListeningCb(): conn(NULL), errNo(0) { } @@ -22,19 +23,19 @@ std::ostream &Ipc::StartListeningCb::startPrint(std::ostream &os) const { - return os << "(FD " << fd << ", err=" << errNo; + return os << "(" << conn << ", err=" << errNo; } void -Ipc::StartListening(int sock_type, int proto, Ip::Address &addr, int flags, +Ipc::StartListening(int sock_type, int proto, const Comm::ConnectionPointer &listenConn, FdNoteId fdNote, AsyncCall::Pointer &callback) { if (UsingSmp()) { // if SMP is on, share OpenListenerParams p; p.sock_type = sock_type; p.proto = proto; - p.addr = addr; - p.flags = flags; + p.addr = listenConn->local; + p.flags = listenConn->flags; p.fdNote = fdNote; Ipc::JoinSharedListen(p, callback); return; // wait for the call back @@ -42,12 +43,13 @@ StartListeningCb *cbd = dynamic_cast(callback->getDialer()); Must(cbd); + cbd->conn = listenConn; enter_suid(); - cbd->fd = comm_open_listener(sock_type, proto, addr, flags, FdNote(fdNote)); - cbd->errNo = cbd->fd >= 0 ? 0 : errno; + comm_open_listener(sock_type, proto, cbd->conn, FdNote(fdNote)); + cbd->errNo = Comm::IsConnOpen(cbd->conn) ? 0 : errno; leave_suid(); - debugs(54, 3, HERE << "opened listen FD " << cbd->fd << " on " << addr); + debugs(54, 3, HERE << "opened listen " << cbd->conn); ScheduleCallHere(callback); } === modified file 'src/ipc/StartListening.h' --- src/ipc/StartListening.h 2010-11-21 04:40:05 +0000 +++ src/ipc/StartListening.h 2011-03-26 08:25:28 +0000 @@ -8,6 +8,8 @@ #ifndef SQUID_IPC_START_LISTENING_H #define SQUID_IPC_START_LISTENING_H +#include "base/Subscription.h" +#include "comm/forward.h" #include "ip/forward.h" #include "ipc/FdNotes.h" #include "base/AsyncCall.h" @@ -30,14 +32,15 @@ std::ostream &startPrint(std::ostream &os) const; public: - int fd; ///< opened listening socket or -1 + Comm::ConnectionPointer conn; ///< opened listening socket int errNo; ///< errno value from the comm_open_listener() call + Subscription::Pointer handlerSubscription; ///< The subscription we will pass on to the ConnAcceptor }; /// Depending on whether SMP is on, either ask Coordinator to send us -/// the listening FD or call comm_open_listener() directly. -extern void StartListening(int sock_type, int proto, Ip::Address &addr, - int flags, FdNoteId fdNote, AsyncCall::Pointer &callback); +/// the listening FD or open a listening socket directly. +extern void StartListening(int sock_type, int proto, const Comm::ConnectionPointer &listenConn, + FdNoteId fdNote, AsyncCall::Pointer &callback); } // namespace Ipc; === modified file 'src/ipc/Strand.cc' --- src/ipc/Strand.cc 2011-02-03 07:39:31 +0000 +++ src/ipc/Strand.cc 2011-03-03 08:06:10 +0000 @@ -6,7 +6,9 @@ */ #include "config.h" +#include "base/Subscription.h" #include "base/TextException.h" +#include "comm/Connection.h" #include "ipc/Strand.h" #include "ipc/StrandCoord.h" #include "ipc/Messages.h" === modified file 'src/ipc/UdsOp.cc' --- src/ipc/UdsOp.cc 2011-02-02 17:41:41 +0000 +++ src/ipc/UdsOp.cc 2011-03-26 08:25:46 +0000 @@ -9,6 +9,7 @@ #include "config.h" #include "comm.h" #include "CommCalls.h" +#include "comm/Connection.h" #include "comm/Write.h" #include "base/TextException.h" #include "ipc/UdsOp.h" @@ -17,8 +18,7 @@ Ipc::UdsOp::UdsOp(const String& pathAddr): AsyncJob("Ipc::UdsOp"), address(PathToAddress(pathAddr)), - options(COMM_NONBLOCKING), - fd_(-1) + options(COMM_NONBLOCKING) { debugs(54, 5, HERE << '[' << this << "] pathAddr=" << pathAddr); } @@ -26,8 +26,9 @@ Ipc::UdsOp::~UdsOp() { debugs(54, 5, HERE << '[' << this << ']'); - if (fd_ >= 0) - comm_close(fd_); + if (Comm::IsConnOpen(conn_)) + conn_->close(); + conn_ = NULL; } void Ipc::UdsOp::setOptions(int newOptions) @@ -35,15 +36,18 @@ options = newOptions; } -int Ipc::UdsOp::fd() +Comm::ConnectionPointer & +Ipc::UdsOp::conn() { - if (fd_ < 0) { + if (!Comm::IsConnOpen(conn_)) { if (options & COMM_DOBIND) unlink(address.sun_path); - fd_ = comm_open_uds(SOCK_DGRAM, 0, &address, options); - Must(fd_ >= 0); + if (conn_ == NULL) + conn_ = new Comm::Connection; + conn_->fd = comm_open_uds(SOCK_DGRAM, 0, &address, options); + Must(Comm::IsConnOpen(conn_)); } - return fd_; + return conn_; } void Ipc::UdsOp::setTimeout(int seconds, const char *handlerName) @@ -51,12 +55,12 @@ typedef CommCbMemFunT Dialer; AsyncCall::Pointer handler = asyncCall(54,5, handlerName, Dialer(CbcPointer(this), &UdsOp::noteTimeout)); - commSetTimeout(fd(), seconds, handler); + commSetConnTimeout(conn(), seconds, handler); } void Ipc::UdsOp::clearTimeout() { - commSetTimeout(fd(), -1, NULL, NULL); // TODO: add Comm::ClearTimeout(fd) + commUnsetConnTimeout(conn()); } void Ipc::UdsOp::noteTimeout(const CommTimeoutCbParams &) @@ -107,17 +111,17 @@ typedef CommCbMemFunT Dialer; AsyncCall::Pointer writeHandler = JobCallback(54, 5, Dialer, this, UdsSender::wrote); - Comm::Write(fd(), message.raw(), message.size(), writeHandler, NULL); + Comm::Write(conn(), message.raw(), message.size(), writeHandler, NULL); writing = true; } void Ipc::UdsSender::wrote(const CommIoCbParams& params) { - debugs(54, 5, HERE << "FD " << params.fd << " flag " << params.flag << " retries " << retries << " [" << this << ']'); + debugs(54, 5, HERE << params.conn << " flag " << params.flag << " retries " << retries << " [" << this << ']'); writing = false; if (params.flag != COMM_OK && retries-- > 0) { sleep(1); // do not spend all tries at once; XXX: use an async timed event instead of blocking here; store the time when we started writing so that we do not sleep if not needed? - write(); // XXX: should we close on error so that fd() reopens? + write(); // XXX: should we close on error so that conn() reopens? } } @@ -133,22 +137,22 @@ AsyncJob::Start(new UdsSender(toAddress, message)); } -int Ipc::ImportFdIntoComm(int fd, int socktype, int protocol, Ipc::FdNoteId noteId) +const Comm::ConnectionPointer & +Ipc::ImportFdIntoComm(const Comm::ConnectionPointer &conn, int socktype, int protocol, Ipc::FdNoteId noteId) { struct sockaddr_in addr; socklen_t len = sizeof(addr); - if (getsockname(fd, reinterpret_cast(&addr), &len) == 0) { - Ip::Address ipAddr(addr); + if (getsockname(conn->fd, reinterpret_cast(&addr), &len) == 0) { + conn->remote = addr; struct addrinfo* addr_info = NULL; - ipAddr.GetAddrInfo(addr_info); + conn->remote.GetAddrInfo(addr_info); addr_info->ai_socktype = socktype; addr_info->ai_protocol = protocol; - comm_import_opened(fd, ipAddr, COMM_NONBLOCKING, Ipc::FdNote(noteId), addr_info); - ipAddr.FreeAddrInfo(addr_info); + comm_import_opened(conn, Ipc::FdNote(noteId), addr_info); + conn->remote.FreeAddrInfo(addr_info); } else { - debugs(54, DBG_CRITICAL, HERE << "ERROR: FD " << fd << ' ' << xstrerror()); - ::close(fd); - fd = -1; + debugs(54, DBG_CRITICAL, "ERROR: Ipc::ImportFdIntoComm: " << conn << ' ' << xstrerror()); + conn->close(); } - return fd; + return conn; } === modified file 'src/ipc/UdsOp.h' --- src/ipc/UdsOp.h 2011-01-19 10:12:54 +0000 +++ src/ipc/UdsOp.h 2011-03-03 11:11:01 +0000 @@ -11,6 +11,7 @@ #include "SquidString.h" #include "base/AsyncJob.h" +#include "comm/forward.h" #include "ipc/TypedMsgHdr.h" #include "ipc/FdNotes.h" @@ -34,7 +35,7 @@ protected: virtual void timedout() {} ///< called after setTimeout() if timed out - int fd(); ///< creates if needed and returns raw UDS socket descriptor + Comm::ConnectionPointer &conn(); ///< creates if needed and returns raw UDS socket descriptor /// call timedout() if no UDS messages in a given number of seconds void setTimeout(int seconds, const char *handlerName); @@ -48,7 +49,7 @@ private: int options; ///< UDS options - int fd_; ///< UDS descriptor + Comm::ConnectionPointer conn_; ///< UDS descriptor private: UdsOp(const UdsOp &); // not implemented @@ -92,7 +93,7 @@ void SendMessage(const String& toAddress, const TypedMsgHdr& message); /// import socket fd from another strand into our Comm state -int ImportFdIntoComm(int fd, int socktype, int protocol, FdNoteId noteId); +const Comm::ConnectionPointer & ImportFdIntoComm(const Comm::ConnectionPointer &conn, int socktype, int protocol, FdNoteId noteId); } === modified file 'src/ipcache.cc' --- src/ipcache.cc 2011-01-27 09:29:04 +0000 +++ src/ipcache.cc 2011-01-28 05:01:37 +0000 @@ -32,6 +32,8 @@ #include "squid.h" #include "cbdata.h" +#include "CacheManager.h" +#include "DnsLookupDetails.h" #include "event.h" #include "ip/Address.h" #include "ip/tools.h" @@ -625,9 +627,9 @@ * of scheduling an async call. This reentrant behavior means that the * user job must be extra careful after calling ipcache_nbgethostbyname, * especially if the handler destroys the job. Moreover, the job has - * no way of knowing whether the reentrant call happened. commConnectStart - * protects the job by scheduling an async call, but some user code calls - * ipcache_nbgethostbyname directly. + * no way of knowing whether the reentrant call happened. + * Comm::Connection setup usually protects the job by scheduling an async call, + * but some user code calls ipcache_nbgethostbyname directly. */ void ipcache_nbgethostbyname(const char *name, IPH * handler, void *handlerData) === modified file 'src/log/FormatSquidCustom.cc' --- src/log/FormatSquidCustom.cc 2011-03-11 22:38:29 +0000 +++ src/log/FormatSquidCustom.cc 2011-03-23 09:42:23 +0000 @@ -34,6 +34,7 @@ #include "config.h" #include "AccessLogEntry.h" +#include "comm/Connection.h" #include "log/File.h" #include "log/Formats.h" #include "log/Gadgets.h" @@ -152,11 +153,12 @@ #if USE_SQUID_EUI case LFT_CLIENT_EUI: - if (al->request) { - if (al->cache.caddr.IsIPv4()) - al->request->client_eui48.encode(tmp, 1024); + // TODO make the ACL checklist have a direct link to any TCP details. + if (al->request && al->request->clientConnectionManager.valid() && al->request->clientConnectionManager->clientConnection != NULL) { + if (al->request->clientConnectionManager->clientConnection->remote.IsIPv4()) + al->request->clientConnectionManager->clientConnection->remoteEui48.encode(tmp, 1024); else - al->request->client_eui64.encode(tmp, 1024); + al->request->clientConnectionManager->clientConnection->remoteEui64.encode(tmp, 1024); out = tmp; } break; === modified file 'src/log/ModTcp.cc' --- src/log/ModTcp.cc 2011-03-25 09:05:41 +0000 +++ src/log/ModTcp.cc 2011-03-26 01:48:58 +0000 @@ -33,6 +33,7 @@ #include "squid.h" #include "comm.h" +#include "comm/Connection.h" #include "log/File.h" #include "log/ModTcp.h" #include "Parsing.h" === modified file 'src/log/ModUdp.cc' --- src/log/ModUdp.cc 2010-12-13 11:31:14 +0000 +++ src/log/ModUdp.cc 2011-01-08 11:26:11 +0000 @@ -32,6 +32,7 @@ #include "squid.h" #include "comm.h" +#include "comm/Connection.h" #include "log/File.h" #include "log/ModUdp.h" #include "Parsing.h" === modified file 'src/main.cc' --- src/main.cc 2011-02-07 10:27:53 +0000 +++ src/main.cc 2011-03-26 08:35:52 +0000 @@ -34,12 +34,20 @@ #include "squid.h" #include "AccessLogEntry.h" +#if USE_ADAPTATION +#include "adaptation/Config.h" +#endif +#if USE_ECAP +#include "adaptation/ecap/Config.h" +#endif #if ICAP_CLIENT +#include "adaptation/icap/Config.h" #include "adaptation/icap/icap_log.h" #endif #if USE_AUTH #include "auth/Gadgets.h" #endif +#include "base/Subscription.h" #include "base/TextException.h" #if USE_DELAY_POOLS #include "ClientDelayConfig.h" @@ -54,6 +62,8 @@ #include "event.h" #include "EventLoop.h" #include "ExternalACL.h" +#include "fs/Module.h" +#include "PeerSelectState.h" #include "Store.h" #include "ICP.h" #include "ident/Ident.h" === modified file 'src/mgr/Action.cc' --- src/mgr/Action.cc 2010-10-28 18:52:59 +0000 +++ src/mgr/Action.cc 2011-03-05 01:34:44 +0000 @@ -6,6 +6,7 @@ */ #include "config.h" +#include "comm/Connection.h" #include "HttpReply.h" #include "ipc/Port.h" #include "mgr/ActionCreator.h" @@ -69,7 +70,7 @@ // Assume most kid classes are fully aggregatable (i.e., they do not dump // local info at all). Do not import the remote HTTP fd into our Comm // space; collect and send an IPC msg with collected info to Coordinator. - ::close(request.fd); + request.conn->close(); collect(); sendResponse(request.requestId); } === modified file 'src/mgr/ActionWriter.cc' --- src/mgr/ActionWriter.cc 2010-10-29 00:12:28 +0000 +++ src/mgr/ActionWriter.cc 2010-11-26 04:20:34 +0000 @@ -7,17 +7,18 @@ #include "config.h" #include "base/TextException.h" +#include "comm/Connection.h" #include "mgr/ActionWriter.h" #include "Store.h" CBDATA_NAMESPACED_CLASS_INIT(Mgr, ActionWriter); -Mgr::ActionWriter::ActionWriter(const Action::Pointer &anAction, int aFd): - StoreToCommWriter(aFd, anAction->createStoreEntry()), +Mgr::ActionWriter::ActionWriter(const Action::Pointer &anAction, const Comm::ConnectionPointer &conn): + StoreToCommWriter(conn, anAction->createStoreEntry()), action(anAction) { - debugs(16, 5, HERE << "FD " << aFd << " action: " << action); + debugs(16, 5, HERE << conn << " action: " << action); } void === modified file 'src/mgr/ActionWriter.h' --- src/mgr/ActionWriter.h 2010-10-28 18:52:59 +0000 +++ src/mgr/ActionWriter.h 2010-11-26 04:18:59 +0000 @@ -8,6 +8,7 @@ #ifndef SQUID_MGR_ACTION_WRITER_H #define SQUID_MGR_ACTION_WRITER_H +#include "comm/forward.h" #include "HttpRequestMethod.h" #include "mgr/StoreToCommWriter.h" @@ -20,7 +21,7 @@ class ActionWriter: public StoreToCommWriter { public: - ActionWriter(const Action::Pointer &anAction, int aFd); + ActionWriter(const Action::Pointer &anAction, const Comm::ConnectionPointer &conn); protected: /* AsyncJob API */ === modified file 'src/mgr/Filler.cc' --- src/mgr/Filler.cc 2010-10-29 00:12:28 +0000 +++ src/mgr/Filler.cc 2010-11-26 04:25:58 +0000 @@ -7,6 +7,7 @@ #include "config.h" #include "base/TextException.h" +#include "comm/Connection.h" #include "mgr/Filler.h" #include "mgr/Response.h" #include "Store.h" @@ -14,13 +15,13 @@ CBDATA_NAMESPACED_CLASS_INIT(Mgr, Filler); -Mgr::Filler::Filler(const Action::Pointer &anAction, int aFd, +Mgr::Filler::Filler(const Action::Pointer &anAction, const Comm::ConnectionPointer &conn, unsigned int aRequestId): - StoreToCommWriter(aFd, anAction->createStoreEntry()), + StoreToCommWriter(conn, anAction->createStoreEntry()), action(anAction), requestId(aRequestId) { - debugs(16, 5, HERE << "FD " << aFd << " action: " << action); + debugs(16, 5, HERE << conn << " action: " << action); } void === modified file 'src/mgr/Filler.h' --- src/mgr/Filler.h 2010-10-28 18:52:59 +0000 +++ src/mgr/Filler.h 2010-11-26 04:08:37 +0000 @@ -8,6 +8,7 @@ #ifndef SQUID_MGR_FILLER_H #define SQUID_MGR_FILLER_H +#include "comm/forward.h" #include "HttpRequestMethod.h" #include "mgr/Action.h" #include "mgr/StoreToCommWriter.h" @@ -19,7 +20,7 @@ class Filler: public StoreToCommWriter { public: - Filler(const Action::Pointer &anAction, int aFd, unsigned int aRequestId); + Filler(const Action::Pointer &anAction, const Comm::ConnectionPointer &conn, unsigned int aRequestId); protected: /* AsyncJob API */ === modified file 'src/mgr/Forwarder.cc' --- src/mgr/Forwarder.cc 2011-01-19 10:12:54 +0000 +++ src/mgr/Forwarder.cc 2011-03-26 08:32:16 +0000 @@ -9,6 +9,7 @@ #include "base/AsyncJobCalls.h" #include "base/TextException.h" #include "CommCalls.h" +#include "comm/Connection.h" #include "errorpage.h" #include "HttpReply.h" #include "HttpRequest.h" @@ -22,13 +23,13 @@ CBDATA_NAMESPACED_CLASS_INIT(Mgr, Forwarder); -Mgr::Forwarder::Forwarder(int aFd, const ActionParams &aParams, +Mgr::Forwarder::Forwarder(const Comm::ConnectionPointer &aConn, const ActionParams &aParams, HttpRequest* aRequest, StoreEntry* anEntry): - Ipc::Forwarder(new Request(KidIdentifier, 0, aFd, aParams), 10), - httpRequest(aRequest), entry(anEntry), fd(aFd) + Ipc::Forwarder(new Request(KidIdentifier, 0, aConn, aParams), 10), + httpRequest(aRequest), entry(anEntry), conn(aConn) { - debugs(16, 5, HERE << "FD " << fd); - Must(fd >= 0); + debugs(16, 5, HERE << conn); + Must(Comm::IsConnOpen(conn)); Must(httpRequest != NULL); Must(entry != NULL); @@ -38,7 +39,7 @@ closer = asyncCall(16, 5, "Mgr::Forwarder::noteCommClosed", CommCbMemFunT(this, &Forwarder::noteCommClosed)); - comm_add_close_handler(fd, closer); + comm_add_close_handler(conn->fd, closer); } Mgr::Forwarder::~Forwarder() @@ -57,14 +58,14 @@ void Mgr::Forwarder::cleanup() { - if (fd >= 0) { + if (Comm::IsConnOpen(conn)) { if (closer != NULL) { - comm_remove_close_handler(fd, closer); + comm_remove_close_handler(conn->fd, closer); closer = NULL; } - comm_close(fd); - fd = -1; + conn->close(); } + conn = NULL; } void @@ -85,7 +86,7 @@ void Mgr::Forwarder::handleException(const std::exception& e) { - if (entry != NULL && httpRequest != NULL && fd >= 0) + if (entry != NULL && httpRequest != NULL && Comm::IsConnOpen(conn)) sendError(errorCon(ERR_INVALID_RESP, HTTP_INTERNAL_SERVER_ERROR, httpRequest)); Ipc::Forwarder::handleException(e); } @@ -95,8 +96,7 @@ Mgr::Forwarder::noteCommClosed(const CommCloseCbParams& params) { debugs(16, 5, HERE); - Must(fd == params.fd); - fd = -1; + conn = NULL; // needed? mustStop("commClosed"); } === modified file 'src/mgr/Forwarder.h' --- src/mgr/Forwarder.h 2011-01-19 10:12:54 +0000 +++ src/mgr/Forwarder.h 2011-03-05 01:28:07 +0000 @@ -8,6 +8,7 @@ #ifndef SQUID_MGR_FORWARDER_H #define SQUID_MGR_FORWARDER_H +#include "comm/forward.h" #include "ipc/Forwarder.h" #include "mgr/ActionParams.h" @@ -27,7 +28,7 @@ class Forwarder: public Ipc::Forwarder { public: - Forwarder(int aFd, const ActionParams &aParams, HttpRequest* aRequest, + Forwarder(const Comm::ConnectionPointer &aConn, const ActionParams &aParams, HttpRequest* aRequest, StoreEntry* anEntry); virtual ~Forwarder(); @@ -46,7 +47,7 @@ private: HttpRequest* httpRequest; ///< HTTP client request for detailing errors StoreEntry* entry; ///< Store entry expecting the response - int fd; ///< HTTP client connection descriptor + Comm::ConnectionPointer conn; ///< HTTP client connection descriptor AsyncCall::Pointer closer; ///< comm_close handler for the HTTP connection CBDATA_CLASS2(Forwarder); === modified file 'src/mgr/FunAction.cc' --- src/mgr/FunAction.cc 2011-01-19 10:12:54 +0000 +++ src/mgr/FunAction.cc 2011-03-04 14:47:09 +0000 @@ -7,6 +7,7 @@ #include "config.h" #include "base/TextException.h" +#include "comm/Connection.h" #include "ipc/UdsOp.h" #include "mgr/Command.h" #include "mgr/Filler.h" @@ -32,10 +33,10 @@ Mgr::FunAction::respond(const Request& request) { debugs(16, 5, HERE); - const int fd = Ipc::ImportFdIntoComm(request.fd, SOCK_STREAM, IPPROTO_TCP, Ipc::fdnHttpSocket); - Must(fd >= 0); + Ipc::ImportFdIntoComm(request.conn, SOCK_STREAM, IPPROTO_TCP, Ipc::fdnHttpSocket); + Must(Comm::IsConnOpen(request.conn)); Must(request.requestId != 0); - AsyncJob::Start(new Mgr::Filler(this, fd, request.requestId)); + AsyncJob::Start(new Mgr::Filler(this, request.conn, request.requestId)); } void === modified file 'src/mgr/InfoAction.cc' --- src/mgr/InfoAction.cc 2011-01-19 10:12:54 +0000 +++ src/mgr/InfoAction.cc 2011-03-04 14:52:35 +0000 @@ -7,6 +7,7 @@ #include "config.h" #include "base/TextException.h" +#include "comm/Connection.h" #include "HttpReply.h" #include "ipc/Messages.h" #include "ipc/UdsOp.h" @@ -156,10 +157,10 @@ Mgr::InfoAction::respond(const Request& request) { debugs(16, 5, HERE); - int fd = Ipc::ImportFdIntoComm(request.fd, SOCK_STREAM, IPPROTO_TCP, Ipc::fdnHttpSocket); - Must(fd >= 0); + Ipc::ImportFdIntoComm(request.conn, SOCK_STREAM, IPPROTO_TCP, Ipc::fdnHttpSocket); + Must(Comm::IsConnOpen(request.conn)); Must(request.requestId != 0); - AsyncJob::Start(new Mgr::Filler(this, fd, request.requestId)); + AsyncJob::Start(new Mgr::Filler(this, request.conn, request.requestId)); } void === modified file 'src/mgr/Inquirer.cc' --- src/mgr/Inquirer.cc 2011-03-03 04:31:33 +0000 +++ src/mgr/Inquirer.cc 2011-03-26 08:36:48 +0000 @@ -7,6 +7,7 @@ #include "config.h" #include "base/TextException.h" +#include "comm/Connection.h" #include "comm/Write.h" #include "CommCalls.h" #include "HttpReply.h" @@ -30,24 +31,25 @@ Mgr::Inquirer::Inquirer(Action::Pointer anAction, const Request &aCause, const Ipc::StrandCoords &coords): Ipc::Inquirer(aCause.clone(), applyQueryParams(coords, aCause.params.queryParams), anAction->atomic() ? 10 : 100), - aggrAction(anAction), - fd(Ipc::ImportFdIntoComm(aCause.fd, SOCK_STREAM, IPPROTO_TCP, Ipc::fdnHttpSocket)) + aggrAction(anAction) { - debugs(16, 5, HERE << "FD " << fd << " action: " << aggrAction); + conn = aCause.conn; + Ipc::ImportFdIntoComm(conn, SOCK_STREAM, IPPROTO_TCP, Ipc::fdnHttpSocket); + + debugs(16, 5, HERE << conn << " action: " << aggrAction); closer = asyncCall(16, 5, "Mgr::Inquirer::noteCommClosed", CommCbMemFunT(this, &Inquirer::noteCommClosed)); - comm_add_close_handler(fd, closer); + comm_add_close_handler(conn->fd, closer); } /// closes our copy of the client HTTP connection socket void Mgr::Inquirer::cleanup() { - if (fd >= 0) { + if (Comm::IsConnOpen(conn)) { removeCloseHandler(); - comm_close(fd); - fd = -1; + conn->close(); } } @@ -55,7 +57,7 @@ Mgr::Inquirer::removeCloseHandler() { if (closer != NULL) { - comm_remove_close_handler(fd, closer); + comm_remove_close_handler(conn->fd, closer); closer = NULL; } } @@ -65,7 +67,7 @@ { debugs(16, 5, HERE); Ipc::Inquirer::start(); - Must(fd >= 0); + Must(Comm::IsConnOpen(conn)); Must(aggrAction != NULL); std::auto_ptr replyBuf; @@ -85,7 +87,7 @@ } writer = asyncCall(16, 5, "Mgr::Inquirer::noteWroteHeader", CommCbMemFunT(this, &Inquirer::noteWroteHeader)); - Comm::Write(fd, replyBuf.get(), writer); + Comm::Write(conn, replyBuf.get(), writer); } /// called when we wrote the response header @@ -95,7 +97,7 @@ debugs(16, 5, HERE); writer = NULL; Must(params.flag == COMM_OK); - Must(params.fd == fd); + Must(params.conn.getRaw() == conn.getRaw()); Must(params.size != 0); // start inquiries at the initial pos inquire(); @@ -106,8 +108,8 @@ Mgr::Inquirer::noteCommClosed(const CommCloseCbParams& params) { debugs(16, 5, HERE); - Must(fd < 0 || fd == params.fd); - fd = -1; + Must(!Comm::IsConnOpen(conn) && params.conn.getRaw() == conn.getRaw()); + conn = NULL; mustStop("commClosed"); } @@ -125,8 +127,8 @@ { if (!strands.empty() && aggrAction->aggregatable()) { removeCloseHandler(); - AsyncJob::Start(new ActionWriter(aggrAction, fd)); - fd = -1; // should not close fd because we passed it to ActionWriter + AsyncJob::Start(new ActionWriter(aggrAction, conn)); + conn = NULL; // should not close because we passed it to ActionWriter } } === modified file 'src/mgr/Inquirer.h' --- src/mgr/Inquirer.h 2011-03-02 16:40:40 +0000 +++ src/mgr/Inquirer.h 2011-03-26 08:37:43 +0000 @@ -8,6 +8,7 @@ #ifndef SQUID_MGR_INQUIRER_H #define SQUID_MGR_INQUIRER_H +#include "comm/forward.h" #include "ipc/Inquirer.h" #include "mgr/Action.h" @@ -44,7 +45,7 @@ private: Action::Pointer aggrAction; //< action to aggregate - int fd; ///< HTTP client socket descriptor + Comm::ConnectionPointer conn; ///< HTTP client socket descriptor AsyncCall::Pointer writer; ///< comm_write callback AsyncCall::Pointer closer; ///< comm_close handler === modified file 'src/mgr/Request.cc' --- src/mgr/Request.cc 2011-02-03 08:02:28 +0000 +++ src/mgr/Request.cc 2011-03-05 01:45:34 +0000 @@ -7,23 +7,25 @@ #include "config.h" #include "base/TextException.h" +#include "comm/Connection.h" #include "ipc/Messages.h" #include "ipc/TypedMsgHdr.h" #include "mgr/ActionParams.h" #include "mgr/Request.h" -Mgr::Request::Request(int aRequestorId, unsigned int aRequestId, int aFd, +Mgr::Request::Request(int aRequestorId, unsigned int aRequestId, const Comm::ConnectionPointer &aConn, const ActionParams &aParams): Ipc::Request(aRequestorId, aRequestId), - fd(aFd), params(aParams) + conn(aConn), + params(aParams) { Must(requestorId > 0); } Mgr::Request::Request(const Request& request): Ipc::Request(request.requestorId, request.requestId), - fd(request.fd), params(request.params) + conn(request.conn), params(request.params) { } @@ -35,7 +37,10 @@ msg.getPod(requestId); params = ActionParams(msg); - fd = msg.getFd(); + conn = new Comm::Connection; + conn->fd = msg.getFd(); + // For now we just have the FD. + // Address and connectio details wil be pulled/imported by the component later } void @@ -46,7 +51,7 @@ msg.putPod(requestId); params.pack(msg); - msg.putFd(fd); + msg.putFd(conn->fd); } Ipc::Request::Pointer === modified file 'src/mgr/Request.h' --- src/mgr/Request.h 2011-01-19 10:12:54 +0000 +++ src/mgr/Request.h 2011-03-05 01:31:39 +0000 @@ -20,7 +20,7 @@ class Request: public Ipc::Request { public: - Request(int aRequestorId, unsigned int aRequestId, int aFd, + Request(int aRequestorId, unsigned int aRequestId, const Comm::ConnectionPointer &aConn, const ActionParams &aParams); explicit Request(const Ipc::TypedMsgHdr& msg); ///< from recvmsg() @@ -32,7 +32,7 @@ Request(const Request& request); public: - int fd; ///< HTTP client connection descriptor + Comm::ConnectionPointer conn; ///< HTTP client connection descriptor ActionParams params; ///< action name and parameters }; === modified file 'src/mgr/StoreToCommWriter.cc' --- src/mgr/StoreToCommWriter.cc 2011-01-19 10:12:54 +0000 +++ src/mgr/StoreToCommWriter.cc 2011-03-26 08:38:57 +0000 @@ -7,6 +7,7 @@ #include "config.h" #include "base/TextException.h" +#include "comm/Connection.h" #include "CommCalls.h" #include "comm/Write.h" #include "ipc/FdNotes.h" @@ -18,14 +19,14 @@ CBDATA_NAMESPACED_CLASS_INIT(Mgr, StoreToCommWriter); -Mgr::StoreToCommWriter::StoreToCommWriter(int aFd, StoreEntry* anEntry): +Mgr::StoreToCommWriter::StoreToCommWriter(const Comm::ConnectionPointer &conn, StoreEntry* anEntry): AsyncJob("Mgr::StoreToCommWriter"), - fd(aFd), entry(anEntry), sc(NULL), writeOffset(0), closer(NULL) + clientConnection(conn), entry(anEntry), sc(NULL), writeOffset(0), closer(NULL) { - debugs(16, 6, HERE << "FD " << fd); + debugs(16, 6, HERE << clientConnection); closer = asyncCall(16, 5, "Mgr::StoreToCommWriter::noteCommClosed", CommCbMemFunT(this, &StoreToCommWriter::noteCommClosed)); - comm_add_close_handler(fd, closer); + comm_add_close_handler(clientConnection->fd, closer); } Mgr::StoreToCommWriter::~StoreToCommWriter() @@ -40,13 +41,12 @@ void Mgr::StoreToCommWriter::close() { - if (fd >= 0) { + if (Comm::IsConnOpen(clientConnection)) { if (closer != NULL) { - comm_remove_close_handler(fd, closer); + comm_remove_close_handler(clientConnection->fd, closer); closer = NULL; } - comm_close(fd); - fd = -1; + clientConnection->close(); } } @@ -54,7 +54,7 @@ Mgr::StoreToCommWriter::start() { debugs(16, 6, HERE); - Must(fd >= 0); + Must(Comm::IsConnOpen(clientConnection)); Must(entry != NULL); entry->registerAbort(&StoreToCommWriter::Abort, this); sc = storeClientListAdd(entry, this); @@ -102,14 +102,14 @@ Mgr::StoreToCommWriter::scheduleCommWrite(const StoreIOBuffer& ioBuf) { debugs(16, 6, HERE); - Must(fd >= 0); + Must(Comm::IsConnOpen(clientConnection)); Must(ioBuf.data != NULL); // write filled buffer typedef CommCbMemFunT MyDialer; AsyncCall::Pointer writer = asyncCall(16, 5, "Mgr::StoreToCommWriter::noteCommWrote", MyDialer(this, &StoreToCommWriter::noteCommWrote)); - Comm::Write(fd, ioBuf.data, ioBuf.length, writer, NULL); + Comm::Write(clientConnection, ioBuf.data, ioBuf.length, writer, NULL); } void @@ -117,7 +117,7 @@ { debugs(16, 6, HERE); Must(params.flag == COMM_OK); - Must(params.fd == fd); + Must(clientConnection != NULL && params.fd == clientConnection->fd); Must(params.size != 0); writeOffset += params.size; if (!doneAll()) @@ -128,8 +128,7 @@ Mgr::StoreToCommWriter::noteCommClosed(const CommCloseCbParams& params) { debugs(16, 6, HERE); - Must(fd == params.fd); - fd = -1; + Must(!Comm::IsConnOpen(clientConnection)); mustStop("commClosed"); } @@ -161,6 +160,6 @@ Mgr::StoreToCommWriter::Abort(void* param) { StoreToCommWriter* mgrWriter = static_cast(param); - if (mgrWriter->fd >= 0) - comm_close(mgrWriter->fd); + if (Comm::IsConnOpen(mgrWriter->clientConnection)) + mgrWriter->clientConnection->close(); } === modified file 'src/mgr/StoreToCommWriter.h' --- src/mgr/StoreToCommWriter.h 2011-01-19 10:12:54 +0000 +++ src/mgr/StoreToCommWriter.h 2011-03-03 08:02:35 +0000 @@ -9,6 +9,7 @@ #define SQUID_MGR_STORE_TO_COMM_WRITER_H #include "base/AsyncJob.h" +#include "comm/forward.h" #include "mgr/Action.h" #include "StoreIOBuffer.h" @@ -25,7 +26,7 @@ class StoreToCommWriter: public AsyncJob { public: - StoreToCommWriter(int aFd, StoreEntry *anEntry); + StoreToCommWriter(const Comm::ConnectionPointer &conn, StoreEntry *anEntry); virtual ~StoreToCommWriter(); protected: @@ -53,7 +54,7 @@ void close(); protected: - int fd; ///< HTTP client descriptor + Comm::ConnectionPointer clientConnection; ///< HTTP client descriptor StoreEntry* entry; ///< store entry with the cache manager response store_client* sc; ///< our registration with the store === modified file 'src/multicast.cc' --- src/multicast.cc 2010-07-25 08:10:12 +0000 +++ src/multicast.cc 2011-03-26 08:43:06 +0000 @@ -34,6 +34,9 @@ */ #include "squid.h" +#include "comm/Connection.h" +// XXX: for icpIncomingConn - need to pass it as a generic parameter. +#include "ICP.h" int mcastSetTtl(int fd, int mcast_ttl) @@ -53,12 +56,8 @@ mcastJoinGroups(const ipcache_addrs *ia, const DnsLookupDetails &, void *datanotused) { #ifdef IP_MULTICAST_TTL - int fd = theInIcpConnection; - struct ip_mreq mr; int i; - int x; - char c = 0; if (ia == NULL) { debugs(7, 0, "comm_join_mcast_groups: Unknown host"); @@ -76,16 +75,13 @@ ia->in_addrs[i].GetInAddr(mr.imr_multiaddr); mr.imr_interface.s_addr = INADDR_ANY; - x = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, - (char *) &mr, sizeof(struct ip_mreq)); - - if (x < 0) - debugs(7, 1, "comm_join_mcast_groups: FD " << fd << ", IP=" << ia->in_addrs[i]); - - x = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &c, 1); - - if (x < 0) - debugs(7, 1, "Can't disable multicast loopback: " << xstrerror()); + + if (setsockopt(icpIncomingConn->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mr, sizeof(struct ip_mreq)) < 0) + debugs(7, DBG_IMPORTANT, "ERROR: Join failed for " << icpIncomingConn << ", Multicast IP=" << ia->in_addrs[i]); + + char c = 0; + if (setsockopt(icpIncomingConn->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &c, 1) < 0) + debugs(7, DBG_IMPORTANT, "ERROR: " << icpIncomingConn << " can't disable multicast loopback: " << xstrerror()); } #endif === modified file 'src/neighbors.cc' --- src/neighbors.cc 2011-03-02 07:27:24 +0000 +++ src/neighbors.cc 2011-03-26 08:44:58 +0000 @@ -33,6 +33,8 @@ #include "squid.h" #include "ProtoPort.h" #include "acl/FilledChecklist.h" +#include "comm/Connection.h" +#include "comm/ConnOpener.h" #include "event.h" #include "htcp.h" #include "HttpRequest.h" @@ -62,7 +64,7 @@ static void neighborCountIgnored(peer *); static void peerRefreshDNS(void *); static IPH peerDNSConfigure; -static int peerProbeConnect(peer *); +static bool peerProbeConnect(peer *); static CNCB peerProbeConnectDone; static void peerCountMcastPeersDone(void *data); static void peerCountMcastPeersStart(void *data); @@ -549,7 +551,7 @@ "Peer Cache Statistics", neighborDumpPeers, 0, 1); - if (theInIcpConnection >= 0) { + if (Comm::IsConnOpen(icpIncomingConn)) { Mgr::RegisterAction("non_peers", "List of Unknown sites sending ICP messages", neighborDumpNonPeers, 0, 1); @@ -559,23 +561,14 @@ void neighbors_init(void) { - Ip::Address nul; - struct addrinfo *AI = NULL; struct servent *sep = NULL; const char *me = getMyHostname(); peer *thisPeer = NULL; peer *next = NULL; - int fd = theInIcpConnection; neighborsRegisterWithCacheManager(); - /* setup addrinfo for use */ - nul.InitAddrInfo(AI); - - if (fd >= 0) { - - if (getsockname(fd, AI->ai_addr, &AI->ai_addrlen) < 0) - debugs(15, 1, "getsockname(" << fd << "," << AI->ai_addr << "," << &AI->ai_addrlen << ") failed."); + if (Comm::IsConnOpen(icpIncomingConn)) { for (thisPeer = Config.peers; thisPeer; thisPeer = next) { http_port_list *s = NULL; @@ -609,14 +602,12 @@ echo_hdr.reqnum = 0; echo_hdr.flags = 0; echo_hdr.pad = 0; - nul = *AI; - nul.GetInAddr( *((struct in_addr*)&echo_hdr.shostid) ); + theIcpPublicHostID.GetInAddr( *((struct in_addr*)&echo_hdr.shostid) ); sep = getservbyname("echo", "udp"); echo_port = sep ? ntohs((u_short) sep->s_port) : 7; } first_ping = Config.peers; - nul.FreeAddrInfo(AI); } int @@ -682,19 +673,19 @@ } else #endif { - if (Config.Port.icp <= 0 || theOutIcpConnection <= 0) { + if (Config.Port.icp <= 0 || !Comm::IsConnOpen(icpOutgoingConn)) { debugs(15, DBG_CRITICAL, "ICP is disabled! Cannot send ICP request to peer."); continue; } else { if (p->type == PEER_MULTICAST) - mcastSetTtl(theOutIcpConnection, p->mcast.ttl); + mcastSetTtl(icpOutgoingConn->fd, p->mcast.ttl); if (p->icp.port == echo_port) { debugs(15, 4, "neighborsUdpPing: Looks like a dumb cache, send DECHO ping"); echo_hdr.reqnum = reqnum; query = _icp_common_t::createMessage(ICP_DECHO, 0, url, reqnum, 0); - icpUdpSend(theOutIcpConnection,p->in_addr,query,LOG_ICP_QUERY,0); + icpUdpSend(icpOutgoingConn->fd, p->in_addr, query, LOG_ICP_QUERY, 0); } else { flags = 0; @@ -704,7 +695,7 @@ query = _icp_common_t::createMessage(ICP_QUERY, flags, url, reqnum, 0); - icpUdpSend(theOutIcpConnection, p->in_addr, query, LOG_ICP_QUERY, 0); + icpUdpSend(icpOutgoingConn->fd, p->in_addr, query, LOG_ICP_QUERY, 0); } } } @@ -1345,82 +1336,43 @@ p->tcp_up = p->connect_fail_limit; } -/// called by Comm when test_fd is closed while connect is in progress -static void -peerProbeClosed(int fd, void *data) -{ - peer *p = (peer*)data; - p->test_fd = -1; - // it is a failure because we failed to connect - peerConnectFailedSilent(p); -} - -static void -peerProbeConnectTimeout(int fd, void *data) -{ - peer * p = (peer *)data; - comm_remove_close_handler(fd, &peerProbeClosed, p); - comm_close(fd); - p->test_fd = -1; - peerConnectFailedSilent(p); -} - /* * peerProbeConnect will be called on dead peers by neighborUp */ -static int +static bool peerProbeConnect(peer * p) { - int fd; - time_t ctimeout = p->connect_timeout > 0 ? p->connect_timeout - : Config.Timeout.peer_connect; - int ret = squid_curtime - p->stats.last_connect_failure > ctimeout * 10; + time_t ctimeout = p->connect_timeout > 0 ? p->connect_timeout : Config.Timeout.peer_connect; + bool ret = (squid_curtime - p->stats.last_connect_failure) > (ctimeout * 10); - if (p->test_fd != -1) + if (p->testing_now > 0) return ret;/* probe already running */ if (squid_curtime - p->stats.last_connect_probe == 0) return ret;/* don't probe to often */ - Ip::Address temp(getOutgoingAddr(NULL,p)); - - // if IPv6 is disabled try to force IPv4-only outgoing. - if (!Ip::EnableIpv6 && !temp.SetIPv4()) { - debugs(50, DBG_IMPORTANT, "WARNING: IPv6 is disabled. Failed to use " << temp << " to probe " << p->host); - return ret; - } - - // 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. - temp.SetIPv4(); - } - - fd = comm_open(SOCK_STREAM, IPPROTO_TCP, temp, COMM_NONBLOCKING, p->host); - - if (fd < 0) - return ret; - - comm_add_close_handler(fd, &peerProbeClosed, p); - commSetTimeout(fd, ctimeout, peerProbeConnectTimeout, p); - - p->test_fd = fd; + /* for each IP address of this peer. find one that we can connect to and probe it. */ + for (int i = 0; i < p->n_addresses; i++) { + Comm::ConnectionPointer conn = new Comm::Connection; + conn->remote = p->addresses[i]; + conn->remote.SetPort(p->http_port); + getOutgoingAddress(NULL, conn); + + p->testing_now++; + + AsyncCall::Pointer call = commCbCall(15,3, "peerProbeConnectDone", CommConnectCbPtrFun(peerProbeConnectDone, p)); + Comm::ConnOpener *cs = new Comm::ConnOpener(conn, call, ctimeout); + cs->setHost(p->host); + AsyncJob::Start(cs); + } p->stats.last_connect_probe = squid_curtime; - commConnectStart(p->test_fd, - p->host, - p->http_port, - peerProbeConnectDone, - p); - return ret; } static void -peerProbeConnectDone(int fd, const DnsLookupDetails &, comm_err_t status, int xerrno, void *data) +peerProbeConnectDone(const Comm::ConnectionPointer &conn, comm_err_t status, int xerrno, void *data) { peer *p = (peer*)data; @@ -1430,9 +1382,7 @@ peerConnectFailedSilent(p); } - comm_remove_close_handler(fd, &peerProbeClosed, p); - comm_close(fd); - p->test_fd = -1; + p->testing_now--; return; } @@ -1478,15 +1428,11 @@ mem->start_ping = current_time; mem->ping_reply_callback = peerCountHandleIcpReply; mem->ircb_data = psstate; - mcastSetTtl(theOutIcpConnection, p->mcast.ttl); + mcastSetTtl(icpOutgoingConn->fd, p->mcast.ttl); p->mcast.id = mem->id; reqnum = icpSetCacheKey((const cache_key *)fake->key); query = _icp_common_t::createMessage(ICP_QUERY, 0, url, reqnum, 0); - icpUdpSend(theOutIcpConnection, - p->in_addr, - query, - LOG_ICP_QUERY, - 0); + icpUdpSend(icpOutgoingConn->fd, p->in_addr, query, LOG_ICP_QUERY, 0); fake->ping_status = PING_WAITING; eventAdd("peerCountMcastPeersDone", peerCountMcastPeersDone, === modified file 'src/pconn.cc' --- src/pconn.cc 2010-12-14 14:01:14 +0000 +++ src/pconn.cc 2011-03-26 08:48:25 +0000 @@ -33,99 +33,120 @@ */ #include "squid.h" +#include "comm/Connection.h" #include "mgr/Registration.h" #include "Store.h" +#include "pconn.h" #include "comm.h" -#include "pconn.h" #include "fde.h" #define PCONN_FDS_SZ 8 /* pconn set size, increase for better memcache hit rate */ -static MemAllocator *pconn_fds_pool = NULL; +//TODO: re-attach to MemPools. WAS: static MemAllocator *pconn_fds_pool = NULL; PconnModule * PconnModule::instance = NULL; CBDATA_CLASS_INIT(IdleConnList); /* ========== IdleConnList ============================================ */ -IdleConnList::IdleConnList(const char *key, PconnPool *thePool) : parent(thePool) +IdleConnList::IdleConnList(const char *key, PconnPool *thePool) : + capacity_(PCONN_FDS_SZ), + size_(0), + parent_(thePool) { hash.key = xstrdup(key); - nfds_alloc = PCONN_FDS_SZ; - nfds = 0; - fds = (int *)pconn_fds_pool->alloc(); + theList_ = new Comm::ConnectionPointer[capacity_]; +// TODO: re-attach to MemPools. WAS: theList = (?? *)pconn_fds_pool->alloc(); } IdleConnList::~IdleConnList() { - - parent->unlinkList(this); - - if (nfds_alloc == PCONN_FDS_SZ) - pconn_fds_pool->freeOne(fds); + parent_->unlinkList(this); + +/* TODO: re-attach to MemPools. + if (capacity_ == PCONN_FDS_SZ) + pconn_fds_pool->freeOne(theList_); else - xfree(fds); +*/ + delete[] theList_; xfree(hash.key); } +/** Search the list. Matches by FD socket number. + * Performed from the end of list where newest entries are. + * + * \retval <0 The connection is not listed + * \retval >=0 The connection array index + */ int -IdleConnList::findFDIndex (int fd) +IdleConnList::findIndexOf(const Comm::ConnectionPointer &conn) const { - int index; - - for (index = nfds - 1; index >= 0; --index) { - if (fds[index] == fd) + for (int index = size_ - 1; index >= 0; --index) { + if (conn->fd == theList_[index]->fd) { + debugs(48, 3, HERE << "found " << conn << " at index " << index); return index; + } } + debugs(48, 2, HERE << conn << " NOT FOUND!"); return -1; } -void -IdleConnList::removeFD(int fd) +/** Remove the entry at specified index. + * \retval false The index is not an in-use entry. + */ +bool +IdleConnList::removeAt(int index) { - int index = findFDIndex(fd); - if (index < 0) { - debugs(48, 2, "IdleConnList::removeFD: FD " << fd << " NOT FOUND!"); - return; - } - debugs(48, 3, "IdleConnList::removeFD: found FD " << fd << " at index " << index); - - for (; index < nfds - 1; index++) - fds[index] = fds[index + 1]; - - if (--nfds == 0) { - debugs(48, 3, "IdleConnList::removeFD: deleting " << hashKeyStr(&hash)); + if (index < 0 || index >= size_) + return false; + + // shuffle the remaining entries to fill the new gap. + for (; index < size_ - 1; index++) + theList_[index] = theList_[index + 1]; + theList_[size_-1] = NULL; + + if (--size_ == 0) { + debugs(48, 3, HERE << "deleting " << hashKeyStr(&hash)); delete this; } -} - -void -IdleConnList::clearHandlers(int fd) -{ - comm_read_cancel(fd, IdleConnList::read, this); - commSetTimeout(fd, -1, NULL, NULL); -} - -void -IdleConnList::push(int fd) -{ - if (nfds == nfds_alloc) { - debugs(48, 3, "IdleConnList::push: growing FD array"); - nfds_alloc <<= 1; - int *old = fds; - fds = (int *)xmalloc(nfds_alloc * sizeof(int)); - memcpy(fds, old, nfds * sizeof(int)); - - if (nfds == PCONN_FDS_SZ) - pconn_fds_pool->freeOne(old); + return true; +} + +void +IdleConnList::clearHandlers(const Comm::ConnectionPointer &conn) +{ + debugs(48, 3, HERE << "removing close handler for " << conn); + comm_read_cancel(conn->fd, IdleConnList::Read, this); + commUnsetConnTimeout(conn); +} + +void +IdleConnList::push(const Comm::ConnectionPointer &conn) +{ + if (size_ == capacity_) { + debugs(48, 3, HERE << "growing idle Connection array"); + capacity_ <<= 1; + const Comm::ConnectionPointer *oldList = theList_; + theList_ = new Comm::ConnectionPointer[capacity_]; + for (int index = 0; index < size_; index++) + theList_[index] = oldList[index]; + +/* TODO: re-attach to MemPools. + if (size_ == PCONN_FDS_SZ) + pconn_fds_pool->freeOne(oldList); else - xfree(old); +*/ + delete[] oldList; } - fds[nfds++] = fd; - comm_read(fd, fakeReadBuf, sizeof(fakeReadBuf), IdleConnList::read, this); - commSetTimeout(fd, Config.Timeout.pconn, IdleConnList::timeout, this); + theList_[size_++] = conn; + AsyncCall::Pointer readCall = commCbCall(5,4, "IdleConnList::Read", + CommIoCbPtrFun(IdleConnList::Read, this)); + comm_read(conn, fakeReadBuf_, sizeof(fakeReadBuf_), readCall); + AsyncCall::Pointer timeoutCall = commCbCall(5,4, "IdleConnList::Read", + CommTimeoutCbPtrFun(IdleConnList::Timeout, this)); + commSetConnTimeout(conn, Config.Timeout.pconn, timeoutCall); } /* @@ -136,24 +157,50 @@ * of requests JUST as they timeout (say, it shuts down) we'll be wasting * quite a bit of CPU. Just keep it in mind. */ -int -IdleConnList::findUseableFD() +Comm::ConnectionPointer +IdleConnList::findUseable(const Comm::ConnectionPointer &key) { - assert(nfds); - - for (int i=nfds-1; i>=0; i--) { - if (!comm_has_pending_read_callback(fds[i])) { - return fds[i]; - } + assert(size_); + + // small optimization: do the constant bool tests only once. + const bool keyCheckAddr = !key->local.IsAnyAddr(); + const bool keyCheckPort = key->local.GetPort() > 0; + + for (int i=size_-1; i>=0; i--) { + + // Is the FD pending completion of the closure callback? + // this flag is set while our early-read/close handler is + // waiting for a remote response. It gets unset when the + // handler is scheduled. + if (!fd_table[theList_[i]->fd].flags.read_pending) + continue; + + // connection already closed. useless. + if (!Comm::IsConnOpen(theList_[i])) + continue; + + // local end port is required, but dont match. + if (keyCheckPort && key->local.GetPort() != theList_[i]->local.GetPort()) + continue; + + // local address is required, but does not match. + if (keyCheckAddr && key->local.matchIPAddr(theList_[i]->local) != 0) + continue; + + // finally, a match. pop and return it. + Comm::ConnectionPointer result = theList_[i]; + /* may delete this */ + removeAt(i); + return result; } - return -1; + return Comm::ConnectionPointer(); } void -IdleConnList::read(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data) +IdleConnList::Read(const Comm::ConnectionPointer &conn, char *buf, size_t len, comm_err_t flag, int xerrno, void *data) { - debugs(48, 3, "IdleConnList::read: " << len << " bytes from FD " << fd); + debugs(48, 3, HERE << len << " bytes from " << conn); if (flag == COMM_ERR_CLOSING) { /* Bail out early on COMM_ERR_CLOSING - close handlers will tidy up for us */ @@ -161,44 +208,51 @@ } IdleConnList *list = (IdleConnList *) data; - list->removeFD(fd); /* might delete list */ - comm_close(fd); + int index = list->findIndexOf(conn); + if (index >= 0) { + /* might delete list */ + list->removeAt(index); + list->clearHandlers(conn); + } + // else we lost a race. + // Somebody started using the pconn since the remote end disconnected. + // pass the closure info on! + conn->close(); } void -IdleConnList::timeout(int fd, void *data) +IdleConnList::Timeout(const CommTimeoutCbParams &io) { - debugs(48, 3, "IdleConnList::timeout: FD " << fd); - IdleConnList *list = (IdleConnList *) data; - list->removeFD(fd); /* might delete list */ - comm_close(fd); + debugs(48, 3, HERE << io.conn); + IdleConnList *list = static_cast(io.data); + int index = list->findIndexOf(io.conn); + if (index >= 0) { + /* might delete list */ + list->removeAt(index); + io.conn->close(); + } } /* ========== PconnPool PRIVATE FUNCTIONS ============================================ */ const char * -PconnPool::key(const char *host, u_short port, const char *domain, Ip::Address &client_address) +PconnPool::key(const Comm::ConnectionPointer &destLink, const char *domain) { LOCAL_ARRAY(char, buf, SQUIDHOSTNAMELEN * 3 + 10); - char ntoabuf[MAX_IPSTRLEN]; - - if (domain && !client_address.IsAnyAddr()) - snprintf(buf, SQUIDHOSTNAMELEN * 3 + 10, "%s:%d-%s/%s", host, (int) port, client_address.NtoA(ntoabuf,MAX_IPSTRLEN), domain); - else if (domain && client_address.IsAnyAddr()) - snprintf(buf, SQUIDHOSTNAMELEN * 3 + 10, "%s:%d/%s", host, (int) port, domain); - else if ((!domain) && !client_address.IsAnyAddr()) - snprintf(buf, SQUIDHOSTNAMELEN * 3 + 10, "%s:%d-%s", host, (int) port, client_address.NtoA(ntoabuf,MAX_IPSTRLEN)); - else - snprintf(buf, SQUIDHOSTNAMELEN * 3 + 10, "%s:%d", host, (int) port); - - debugs(48,6,"PconnPool::key(" << (host?host:"(no host!)") << "," << port << "," << (domain?domain:"(no domain)") << "," << client_address << "is {" << buf << "}" ); + + destLink->remote.ToURL(buf, SQUIDHOSTNAMELEN * 3 + 10); + if (domain) { + const int used = strlen(buf); + snprintf(buf+used, SQUIDHOSTNAMELEN * 3 + 10-used, "/%s", domain); + } + + debugs(48,6,"PconnPool::key(" << destLink << ", " << (domain?domain:"[no domain]") << ") is {" << buf << "}" ); return buf; } void -PconnPool::dumpHist(StoreEntry * e) +PconnPool::dumpHist(StoreEntry * e) const { - int i; storeAppendPrintf(e, "%s persistent connection counts:\n" "\n" @@ -207,7 +261,7 @@ "\t---- ---------\n", descr); - for (i = 0; i < PCONN_HIST_SZ; i++) { + for (int i = 0; i < PCONN_HIST_SZ; i++) { if (hist[i] == 0) continue; @@ -216,14 +270,13 @@ } void -PconnPool::dumpHash(StoreEntry *e) +PconnPool::dumpHash(StoreEntry *e) const { - int i; - hash_link *walker = NULL; hash_table *hid = table; hash_first(hid); - for (i = 0, walker = hid->next; walker; walker = hash_next(hid)) { + int i = 0; + for (hash_link *walker = hid->next; walker; walker = hash_next(hid)) { storeAppendPrintf(e, "\t item %5d: %s\n", i++, (char *)(walker->key)); } } @@ -248,76 +301,57 @@ } void -PconnPool::push(int fd, const char *host, u_short port, const char *domain, Ip::Address &client_address) +PconnPool::push(const Comm::ConnectionPointer &conn, const char *domain) { - IdleConnList *list; - const char *aKey; - LOCAL_ARRAY(char, desc, FD_DESC_SZ); - if (fdUsageHigh()) { - debugs(48, 3, "PconnPool::push: Not many unused FDs"); - comm_close(fd); + debugs(48, 3, HERE << "Not many unused FDs"); + conn->close(); return; } else if (shutting_down) { - comm_close(fd); - debugs(48, 3, "PconnPool::push: Squid is shutting down. Refusing to do anything"); + conn->close(); + debugs(48, 3, HERE << "Squid is shutting down. Refusing to do anything"); return; } - aKey = key(host, port, domain, client_address); - - list = (IdleConnList *) hash_lookup(table, aKey); + const char *aKey = key(conn, domain); + IdleConnList *list = (IdleConnList *) hash_lookup(table, aKey); if (list == NULL) { list = new IdleConnList(aKey, this); - debugs(48, 3, "PconnPool::push: new IdleConnList for {" << hashKeyStr(&list->hash) << "}" ); + debugs(48, 3, HERE << "new IdleConnList for {" << hashKeyStr(&list->hash) << "}" ); hash_join(table, &list->hash); } else { - debugs(48, 3, "PconnPool::push: found IdleConnList for {" << hashKeyStr(&list->hash) << "}" ); + debugs(48, 3, HERE << "found IdleConnList for {" << hashKeyStr(&list->hash) << "}" ); } - list->push(fd); + list->push(conn); + assert(!comm_has_incomplete_write(conn->fd)); - assert(!comm_has_incomplete_write(fd)); - snprintf(desc, FD_DESC_SZ, "%s idle connection", host); - fd_note(fd, desc); - debugs(48, 3, "PconnPool::push: pushed FD " << fd << " for " << aKey); + LOCAL_ARRAY(char, desc, FD_DESC_SZ); + snprintf(desc, FD_DESC_SZ, "Idle: %s", aKey); + fd_note(conn->fd, desc); + debugs(48, 3, HERE << "pushed " << conn << " for " << aKey); } -/** - * Return a pconn fd for host:port if available and retriable. - * Otherwise, return -1. - * - * We close available persistent connection if the caller transaction is not - * retriable to avoid having a growing number of open connections when many - * transactions create persistent connections but are not retriable. - */ -int -PconnPool::pop(const char *host, u_short port, const char *domain, Ip::Address &client_address, bool isRetriable) +Comm::ConnectionPointer +PconnPool::pop(const Comm::ConnectionPointer &destLink, const char *domain, bool isRetriable) { - const char * aKey = key(host, port, domain, client_address); + const char * aKey = key(destLink, domain); IdleConnList *list = (IdleConnList *)hash_lookup(table, aKey); if (list == NULL) { - debugs(48, 3, "PconnPool::pop: lookup for key {" << aKey << "} failed."); - return -1; + debugs(48, 3, HERE << "lookup for key {" << aKey << "} failed."); + return Comm::ConnectionPointer(); } else { - debugs(48, 3, "PconnPool::pop: found " << hashKeyStr(&list->hash) << (isRetriable?"(to use)":"(to kill)") ); - } - - int fd = list->findUseableFD(); // search from the end. skip pending reads. - - if (fd >= 0) { - list->clearHandlers(fd); - list->removeFD(fd); /* might delete list */ - - if (!isRetriable) { - comm_close(fd); - return -1; - } - } - - return fd; + debugs(48, 3, HERE << "found " << hashKeyStr(&list->hash) << (isRetriable?"(to use)":"(to kill)") ); + } + + /* may delete list */ + Comm::ConnectionPointer temp = list->findUseable(destLink); + if (!isRetriable && Comm::IsConnOpen(temp)) + temp->close(); + + return temp; } void @@ -344,7 +378,7 @@ PconnModule::PconnModule() : pools(NULL), poolCount(0) { pools = (PconnPool **) xcalloc(MAX_NUM_PCONN_POOLS, sizeof(*pools)); - pconn_fds_pool = memPoolCreate("pconn_fds", PCONN_FDS_SZ * sizeof(int)); +//TODO: re-link to MemPools. WAS: pconn_fds_pool = memPoolCreate("pconn_fds", PCONN_FDS_SZ * sizeof(int)); debugs(48, 0, "persistent connection module initialized"); registerWithCacheManager(); } === modified file 'src/pconn.h' --- src/pconn.h 2010-10-07 06:34:34 +0000 +++ src/pconn.h 2010-12-04 12:50:51 +0000 @@ -26,33 +26,59 @@ /// \ingroup PConnAPI #define PCONN_HIST_SZ (1<<16) -/// \ingroup PConnAPI +/** \ingroup PConnAPI + * A list of connections currently open to a particular destination end-point. + */ class IdleConnList { public: IdleConnList(const char *key, PconnPool *parent); ~IdleConnList(); - int numIdle() { return nfds; } - - int findFDIndex(int fd); ///< search from the end of array - void removeFD(int fd); - void push(int fd); - int findUseableFD(); ///< find first from the end not pending read fd. - void clearHandlers(int fd); + + /// Pass control of the connection to the idle list. + void push(const Comm::ConnectionPointer &conn); + + /** Search the list for a connection which matches the 'key' details + * and pop it off the list. + * The list is created based on remote IP:port hash. This further filters + * the choices based on specific local-end details requested. + * If nothing usable is found the a nil pointer is returned. + */ + Comm::ConnectionPointer findUseable(const Comm::ConnectionPointer &key); + + void clearHandlers(const Comm::ConnectionPointer &conn); private: - static IOCB read; - static PF timeout; + bool removeAt(int index); + int findIndexOf(const Comm::ConnectionPointer &conn) const; + static IOCB Read; + static CTCB Timeout; public: hash_link hash; /** must be first */ private: - int *fds; - int nfds_alloc; - int nfds; - PconnPool *parent; - char fakeReadBuf[4096]; + /** List of connections we are holding. + * Sorted oldest to newest for most efficient speeds on pop() and findUsable() + * The worst-case pop() and scans occur on timeout and link closure events + * where timing is less critical. Occasional slow additions are okay. + */ + Comm::ConnectionPointer *theList_; + + /// Number of entries theList can currently hold without re-allocating (capacity). + int capacity_; + ///< Number of in-use entries in theList + int size_; + + /** The pool containing this sub-list. + * The parent performs all stats accounting, and + * will delete us when it dies. It persists for the + * full duration of our existence. + */ + PconnPool *parent_; + + char fakeReadBuf_[4096]; // TODO: kill magic number. + CBDATA_CLASS2(IdleConnList); }; @@ -80,28 +106,38 @@ ~PconnPool(); void moduleInit(); - void push(int fd, const char *host, u_short port, const char *domain, Ip::Address &client_address); - int pop(const char *host, u_short port, const char *domain, Ip::Address &client_address, bool retriable); + void push(const Comm::ConnectionPointer &serverConn, const char *domain); + + /** + * Updates destLink to point at an existing open connection if available and retriable. + * Otherwise, return false. + * + * We close available persistent connection if the caller transaction is not + * retriable to avoid having a growing number of open connections when many + * transactions create persistent connections but are not retriable. + */ + Comm::ConnectionPointer pop(const Comm::ConnectionPointer &destLink, const char *domain, bool retriable); void count(int uses); - void dumpHist(StoreEntry *e); - void dumpHash(StoreEntry *e); + void dumpHist(StoreEntry *e) const; + void dumpHash(StoreEntry *e) const; void unlinkList(IdleConnList *list) const; private: - static const char *key(const char *host, u_short port, const char *domain, Ip::Address &client_address); + static const char *key(const Comm::ConnectionPointer &destLink, const char *domain); int hist[PCONN_HIST_SZ]; hash_table *table; const char *descr; - }; class StoreEntry; class PconnPool; -/// \ingroup PConnAPI +/** \ingroup PConnAPI + * The global registry of persistent connection pools. + */ class PconnModule { === modified file 'src/peer_digest.cc' --- src/peer_digest.cc 2010-12-13 11:31:14 +0000 +++ src/peer_digest.cc 2011-01-08 11:26:11 +0000 @@ -393,7 +393,8 @@ /* push towards peer cache */ debugs(72, 3, "peerDigestRequest: forwarding to fwdStart..."); - FwdState::fwdStart(-1, e, req); + Comm::ConnectionPointer nul; + FwdState::fwdStart(nul, e, req); tempBuffer.offset = 0; === modified file 'src/peer_select.cc' --- src/peer_select.cc 2011-03-02 07:27:24 +0000 +++ src/peer_select.cc 2011-03-26 08:53:13 +0000 @@ -33,6 +33,7 @@ */ #include "squid.h" +#include "DnsLookupDetails.h" #include "event.h" #include "PeerSelectState.h" #include "Store.h" @@ -58,7 +59,6 @@ static void peerSelectFoo(ps_state *); static void peerPingTimeout(void *data); -static void peerSelectCallback(ps_state * psstate); static IRCB peerHandlePingReply; static void peerSelectStateFree(ps_state * psstate); static void peerIcpParentMiss(peer *, icp_common_t *, ps_state *); @@ -74,12 +74,22 @@ static void peerGetAllParents(ps_state *); static void peerAddFwdServer(FwdServer **, peer *, hier_code); static void peerSelectPinned(ps_state * ps); +static void peerSelectDnsResults(const ipcache_addrs *ia, const DnsLookupDetails &details, void *data); CBDATA_CLASS_INIT(ps_state); static void peerSelectStateFree(ps_state * psstate) { + if (psstate->entry) { + debugs(44, 3, HERE << psstate->entry->url()); + + if (psstate->entry->ping_status == PING_WAITING) + eventDelete(peerPingTimeout, psstate); + + psstate->entry->ping_status = PING_DONE; + } + if (psstate->acl_checklist) { debugs(44, 1, "calling aclChecklistFree() from peerSelectStateFree"); delete (psstate->acl_checklist); @@ -121,7 +131,8 @@ void -peerSelect(HttpRequest * request, +peerSelect(Comm::ConnectionList * paths, + HttpRequest * request, StoreEntry * entry, PSC * callback, void *callback_data) @@ -138,6 +149,7 @@ psstate->request = HTTPMSGLOCK(request); psstate->entry = entry; + psstate->paths = paths; psstate->callback = callback; @@ -177,43 +189,99 @@ peerSelectFoo(psstate); } -static void -peerSelectCallback(ps_state * psstate) +void +peerSelectDnsPaths(ps_state *psstate) { - StoreEntry *entry = psstate->entry; FwdServer *fs = psstate->servers; - PSC *callback; - void *cbdata; - - if (entry) { - debugs(44, 3, "peerSelectCallback: " << entry->url() ); - - if (entry->ping_status == PING_WAITING) - eventDelete(peerPingTimeout, psstate); - - entry->ping_status = PING_DONE; + + // convert the list of FwdServer destinations into destinations IP addresses + if (fs && psstate->paths->size() < (unsigned int)Config.forward_max_tries) { + // send the next one off for DNS lookup. + const char *host = fs->_peer ? fs->_peer->host : psstate->request->GetHost(); + debugs(44, 2, "Find IP destination for: " << psstate->entry->url() << "' via " << host); + ipcache_nbgethostbyname(host, peerSelectDnsResults, psstate); + return; } - if (fs == NULL) { - debugs(44, 1, "Failed to select source for '" << entry->url() << "'" ); - debugs(44, 1, " always_direct = " << psstate->always_direct ); - debugs(44, 1, " never_direct = " << psstate->never_direct ); - debugs(44, 1, " timedout = " << psstate->ping.timedout ); + // done with DNS lookups. pass back to caller + PSC *callback = psstate->callback; + psstate->callback = NULL; + + if (psstate->paths->size() < 1) { + debugs(44, DBG_IMPORTANT, "Failed to select source for '" << psstate->entry->url() << "'" ); + debugs(44, DBG_IMPORTANT, " always_direct = " << psstate->always_direct ); + debugs(44, DBG_IMPORTANT, " never_direct = " << psstate->never_direct ); + debugs(44, DBG_IMPORTANT, " timedout = " << psstate->ping.timedout ); + } else { + debugs(44, 2, "Found IP destination for: " << psstate->entry->url() << "'"); } psstate->ping.stop = current_time; psstate->request->hier.ping = psstate->ping; - callback = psstate->callback; - psstate->callback = NULL; + void *cbdata; if (cbdataReferenceValidDone(psstate->callback_data, &cbdata)) { - psstate->servers = NULL; - callback(fs, cbdata); + callback(psstate->paths, cbdata); } peerSelectStateFree(psstate); } +static void +peerSelectDnsResults(const ipcache_addrs *ia, const DnsLookupDetails &details, void *data) +{ + ps_state *psstate = (ps_state *)data; + + psstate->request->recordLookup(details); + + FwdServer *fs = psstate->servers; + if (ia != NULL) { + + assert(ia->cur < ia->count); + + // loop over each result address, adding to the possible destinations. + int ip = ia->cur; + for (int n = 0; n < ia->count; n++, ip++) { + Comm::ConnectionPointer p; + + if (ip >= ia->count) ip = 0; // looped back to zero. + + // Enforce forward_max_tries configuration. + if (psstate->paths->size() >= (unsigned int)Config.forward_max_tries) + break; + + // for TPROXY we must skip unusable addresses. + if (psstate->request->flags.spoof_client_ip && !(fs->_peer && fs->_peer->options.no_tproxy) ) { + if(ia->in_addrs[n].IsIPv4() != psstate->request->client_addr.IsIPv4()) { + // we CAN'T spoof the address on this link. find another. + continue; + } + } + + p = new Comm::Connection(); + p->remote = ia->in_addrs[n]; + if (fs->_peer) + p->remote.SetPort(fs->_peer->http_port); + else + p->remote.SetPort(psstate->request->port); + p->peerType = fs->code; + + // check for a configured outgoing address for this destination... + getOutgoingAddress(psstate->request, p); + psstate->paths->push_back(p); + } + } else { + debugs(44, 3, HERE << "Unknown host: " << fs->_peer ? fs->_peer->host : psstate->request->GetHost()); + } + + psstate->servers = fs->next; + cbdataReferenceDone(fs->_peer); + memFree(fs, MEM_FWD_SERVER); + + // see if more paths can be found + peerSelectDnsPaths(psstate); +} + static int peerCheckNetdbDirect(ps_state * psstate) { @@ -344,29 +412,30 @@ break; } - peerSelectCallback(ps); + // resolve the possible peers + peerSelectDnsPaths(ps); } +int peerAllowedToUse(const peer * p, HttpRequest * request); + /* * peerSelectPinned * * Selects a pinned connection */ -int peerAllowedToUse(const peer * p, HttpRequest * request); static void peerSelectPinned(ps_state * ps) { HttpRequest *request = ps->request; - peer *peer; if (!request->pinnedConnection()) return; - peer = request->pinnedConnection()->pinnedPeer(); - if (request->pinnedConnection()->validatePinnedConnection(request, peer) != -1) { - if (peer && peerAllowedToUse(peer, request)) { - peerAddFwdServer(&ps->servers, peer, PINNED); + peer *pear = request->pinnedConnection()->pinnedPeer(); + if (Comm::IsConnOpen(request->pinnedConnection()->validatePinnedConnection(request, pear))) { + if (pear && peerAllowedToUse(pear, request)) { + peerAddFwdServer(&ps->servers, pear, PINNED); if (ps->entry) ps->entry->ping_status = PING_DONE; /* Skip ICP */ - } else if (!peer && ps->direct != DIRECT_NO) { + } else if (!pear && ps->direct != DIRECT_NO) { peerAddFwdServer(&ps->servers, NULL, PINNED); if (ps->entry) ps->entry->ping_status = PING_DONE; /* Skip ICP */ @@ -601,6 +670,7 @@ peerSelectInit(void) { memset(&PeerStats, '\0', sizeof(PeerStats)); + memDataInit(MEM_FWD_SERVER, "FwdServer", sizeof(FwdServer), 0); } static void === modified file 'src/protos.h' --- src/protos.h 2011-03-02 07:27:24 +0000 +++ src/protos.h 2011-03-03 06:23:45 +0000 @@ -399,9 +399,6 @@ SQUIDCEXTERN peer *whichPeer(const Ip::Address &from); -SQUIDCEXTERN void peerSelect(HttpRequest *, StoreEntry *, PSC *, void *data); -SQUIDCEXTERN void peerSelectInit(void); - /* peer_digest.c */ class PeerDigest; SQUIDCEXTERN PeerDigest *peerDigestCreate(peer * p); @@ -409,6 +406,8 @@ SQUIDCEXTERN void peerDigestNotePeerGone(PeerDigest * pd); SQUIDCEXTERN void peerDigestStatsReport(const PeerDigest * pd, StoreEntry * e); +#include "comm/forward.h" +extern void getOutgoingAddress(HttpRequest * request, Comm::ConnectionPointer conn); extern Ip::Address getOutgoingAddr(HttpRequest * request, struct peer *dst_peer); SQUIDCEXTERN void urnStart(HttpRequest *, StoreEntry *); === modified file 'src/redirect.cc' --- src/redirect.cc 2011-02-08 01:12:42 +0000 +++ src/redirect.cc 2011-03-05 06:20:17 +0000 @@ -37,6 +37,7 @@ #if USE_AUTH #include "auth/UserRequest.h" #endif +#include "comm/Connection.h" #include "mgr/Registration.h" #include "Store.h" #include "fde.h" @@ -155,13 +156,13 @@ r->client_ident = http->request->extacl_user.termedBuf(); } - if (!r->client_ident && (conn != NULL && conn->rfc931[0])) - r->client_ident = conn->rfc931; + if (!r->client_ident && conn != NULL && conn->clientConnection != NULL && conn->clientConnection->rfc931[0]) + r->client_ident = conn->clientConnection->rfc931; #if USE_SSL - if (!r->client_ident && conn != NULL) - r->client_ident = sslGetUserEmail(fd_table[conn->fd].ssl); + if (!r->client_ident && conn != NULL && Comm::IsConnOpen(conn->clientConnection)) + r->client_ident = sslGetUserEmail(fd_table[conn->clientConnection->fd].ssl); #endif @@ -202,7 +203,8 @@ tmpnoaddr.SetNoAddr(); repContext->setReplyToError(ERR_GATEWAY_FAILURE, status, http->request->method, NULL, - http->getConn() != NULL ? http->getConn()->peer : tmpnoaddr, + http->getConn() != NULL && http->getConn()->clientConnection != NULL ? + http->getConn()->clientConnection->remote : tmpnoaddr, http->request, NULL, #if USE_AUTH === modified file 'src/send-announce.cc' --- src/send-announce.cc 2010-12-12 05:30:58 +0000 +++ src/send-announce.cc 2011-01-08 11:26:11 +0000 @@ -34,8 +34,10 @@ */ #include "squid.h" +#include "comm/Connection.h" #include "event.h" #include "fde.h" +#include "ICP.h" #include "SquidTime.h" static IPH send_announce; @@ -46,7 +48,7 @@ if (0 == Config.onoff.announce) return; - if (theOutIcpConnection < 0) + if (!Comm::IsConnOpen(icpOutgoingConn)) return; ipcache_nbgethostbyname(Config.Announce.host, send_announce, NULL); @@ -60,14 +62,12 @@ LOCAL_ARRAY(char, tbuf, 256); LOCAL_ARRAY(char, sndbuf, BUFSIZ); - Ip::Address S; char *host = Config.Announce.host; char *file = NULL; u_short port = Config.Announce.port; int l; int n; int fd; - int x; if (ia == NULL) { debugs(27, 1, "send_announce: Unknown host '" << host << "'"); @@ -109,11 +109,10 @@ } } - S = ia->in_addrs[0]; + Ip::Address S = ia->in_addrs[0]; S.SetPort(port); - assert(theOutIcpConnection > 0); - x = comm_udp_sendto(theOutIcpConnection, S, sndbuf, strlen(sndbuf) + 1); + assert(Comm::IsConnOpen(icpOutgoingConn)); - if (x < 0) - debugs(27, 1, "send_announce: FD " << theOutIcpConnection << ": " << xstrerror()); + if (comm_udp_sendto(icpOutgoingConn->fd, S, sndbuf, strlen(sndbuf) + 1) < 0) + debugs(27, 1, "ERROR: Failed to announce to " << S << " from " << icpOutgoingConn->local << ": " << xstrerror()); } === modified file 'src/snmp/Forwarder.cc' --- src/snmp/Forwarder.cc 2011-01-31 14:04:00 +0000 +++ src/snmp/Forwarder.cc 2011-03-03 15:49:32 +0000 @@ -8,6 +8,7 @@ #include "config.h" #include "base/TextException.h" #include "CommCalls.h" +#include "comm.h" #include "ipc/Port.h" #include "snmp_core.h" #include "snmp/Forwarder.h" === modified file 'src/snmp/Inquirer.cc' --- src/snmp/Inquirer.cc 2011-03-02 16:46:09 +0000 +++ src/snmp/Inquirer.cc 2011-03-04 14:16:02 +0000 @@ -8,6 +8,8 @@ #include "config.h" #include "base/TextException.h" #include "CommCalls.h" +#include "comm.h" +#include "comm/Connection.h" #include "ipc/UdsOp.h" #include "snmp_core.h" #include "snmp/Inquirer.h" @@ -20,27 +22,30 @@ Snmp::Inquirer::Inquirer(const Request& aRequest, const Ipc::StrandCoords& coords): Ipc::Inquirer(aRequest.clone(), coords, 2), - aggrPdu(aRequest.pdu), - fd(ImportFdIntoComm(aRequest.fd, SOCK_DGRAM, IPPROTO_UDP, Ipc::fdnInSnmpSocket)) + aggrPdu(aRequest.pdu) { + conn = new Comm::Connection; + conn->fd = aRequest.fd; + ImportFdIntoComm(conn, SOCK_DGRAM, IPPROTO_UDP, Ipc::fdnInSnmpSocket); + debugs(49, 5, HERE); closer = asyncCall(49, 5, "Snmp::Inquirer::noteCommClosed", CommCbMemFunT(this, &Inquirer::noteCommClosed)); - comm_add_close_handler(fd, closer); + comm_add_close_handler(conn->fd, closer); } /// closes our copy of the client connection socket void Snmp::Inquirer::cleanup() { - if (fd >= 0) { + if (Comm::IsConnOpen(conn)) { if (closer != NULL) { - comm_remove_close_handler(fd, closer); + comm_remove_close_handler(conn->fd, closer); closer = NULL; } - comm_close(fd); - fd = -1; + conn->close(); } + conn = NULL; } void @@ -48,7 +53,7 @@ { debugs(49, 5, HERE); Ipc::Inquirer::start(); - Must(fd >= 0); + Must(Comm::IsConnOpen(conn)); inquire(); } @@ -77,8 +82,8 @@ Snmp::Inquirer::noteCommClosed(const CommCloseCbParams& params) { debugs(49, 5, HERE); - Must(fd < 0 || fd == params.fd); - fd = -1; + Must(!Comm::IsConnOpen(conn) || conn->fd == params.conn->fd); + conn = NULL; mustStop("commClosed"); } @@ -98,5 +103,5 @@ int len = sizeof(buffer); Snmp::Request& req = static_cast(*request); snmp_build(&req.session, &aggrPdu, buffer, &len); - comm_udp_sendto(fd, req.address, buffer, len); + comm_udp_sendto(conn->fd, req.address, buffer, len); } === modified file 'src/snmp/Inquirer.h' --- src/snmp/Inquirer.h 2011-01-31 14:04:00 +0000 +++ src/snmp/Inquirer.h 2011-03-26 08:54:07 +0000 @@ -8,6 +8,7 @@ #ifndef SQUID_SNMPX_INQUIRER_H #define SQUID_SNMPX_INQUIRER_H +#include "comm/forward.h" #include "ipc/Inquirer.h" #include "snmp/forward.h" #include "snmp/Pdu.h" @@ -41,7 +42,7 @@ private: Pdu aggrPdu; ///< aggregated pdu - int fd; ///< client connection descriptor + Comm::ConnectionPointer conn; ///< client connection descriptor AsyncCall::Pointer writer; ///< comm_write callback AsyncCall::Pointer closer; ///< comm_close handler === modified file 'src/snmp_core.cc' --- src/snmp_core.cc 2011-02-03 08:02:28 +0000 +++ src/snmp_core.cc 2011-03-26 08:55:05 +0000 @@ -33,6 +33,7 @@ #include "acl/FilledChecklist.h" #include "base/CbcPointer.h" #include "comm.h" +#include "comm/Connection.h" #include "comm/Loops.h" #include "ipc/StartListening.h" #include "ip/Address.h" @@ -46,26 +47,27 @@ public Ipc::StartListeningCb { public: - typedef void (*Handler)(int fd, int errNo); + typedef void (*Handler)(const Comm::ConnectionPointer &conn, int errNo); SnmpListeningStartedDialer(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)(conn, errNo); } public: Handler handler; }; -Ip::Address theOutSNMPAddr; +static void snmpPortOpened(const Comm::ConnectionPointer &conn, int errNo); + mib_tree_entry *mib_tree_head; mib_tree_entry *mib_tree_last; -static void snmpIncomingConnectionOpened(int fd, int errNo); -static void snmpOutgoingConnectionOpened(int fd, int errNo); +Comm::ConnectionPointer snmpIncomingConn; +Comm::ConnectionPointer snmpOutgoingConn; static mib_tree_entry * snmpAddNodeStr(const char *base_str, int o, oid_ParseFn * parsefunction, instance_Fn * instancefunction, AggrType aggrType = atNone); static mib_tree_entry *snmpAddNode(oid * name, int len, oid_ParseFn * parsefunction, instance_Fn * instancefunction, AggrType aggrType, int children,...); @@ -296,118 +298,73 @@ { debugs(49, 5, "snmpConnectionOpen: Called"); - if (Config.Port.snmp > 0) { - Config.Addrs.snmp_incoming.SetPort(Config.Port.snmp); - - if (!Ip::EnableIpv6 && !Config.Addrs.snmp_incoming.SetIPv4()) { - debugs(49, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << Config.Addrs.snmp_incoming << " is not an IPv4 address."); + if (Config.Port.snmp <= 0) + return; + + snmpIncomingConn = new Comm::Connection; + snmpIncomingConn->local = Config.Addrs.snmp_incoming; + snmpIncomingConn->local.SetPort(Config.Port.snmp); + + if (!Ip::EnableIpv6 && !snmpIncomingConn->local.SetIPv4()) { + debugs(49, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << snmpIncomingConn->local << " is not an IPv4 address."); + fatal("SNMP port cannot be opened."); + } + /* split-stack for now requires IPv4-only SNMP */ + if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && snmpIncomingConn->local.IsAnyAddr()) { + snmpIncomingConn->local.SetIPv4(); + } + + AsyncCall::Pointer call = asyncCall(49, 2, "snmpIncomingConnectionOpened", + SnmpListeningStartedDialer(&snmpPortOpened)); + Ipc::StartListening(SOCK_DGRAM, IPPROTO_UDP, snmpIncomingConn, Ipc::fdnInSnmpSocket, call); + + if (!Config.Addrs.snmp_outgoing.IsNoAddr()) { + snmpOutgoingConn = new Comm::Connection; + snmpOutgoingConn->local = Config.Addrs.snmp_outgoing; + snmpOutgoingConn->local.SetPort(Config.Port.snmp); + + if (!Ip::EnableIpv6 && !snmpOutgoingConn->local.SetIPv4()) { + debugs(49, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << snmpOutgoingConn->local << " is not an IPv4 address."); fatal("SNMP port cannot be opened."); } /* split-stack for now requires IPv4-only SNMP */ - if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && Config.Addrs.snmp_incoming.IsAnyAddr()) { - Config.Addrs.snmp_incoming.SetIPv4(); - } - - AsyncCall::Pointer call = asyncCall(49, 2, - "snmpIncomingConnectionOpened", - SnmpListeningStartedDialer(&snmpIncomingConnectionOpened)); - - Ipc::StartListening(SOCK_DGRAM, - IPPROTO_UDP, - Config.Addrs.snmp_incoming, - COMM_NONBLOCKING, - Ipc::fdnInSnmpSocket, call); - - if (!Config.Addrs.snmp_outgoing.IsNoAddr()) { - Config.Addrs.snmp_outgoing.SetPort(Config.Port.snmp); - - if (!Ip::EnableIpv6 && !Config.Addrs.snmp_outgoing.SetIPv4()) { - debugs(49, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << Config.Addrs.snmp_outgoing << " is not an IPv4 address."); - fatal("SNMP port cannot be opened."); - } - /* split-stack for now requires IPv4-only SNMP */ - if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && Config.Addrs.snmp_outgoing.IsAnyAddr()) { - Config.Addrs.snmp_outgoing.SetIPv4(); - } - AsyncCall::Pointer call = asyncCall(49, 2, - "snmpOutgoingConnectionOpened", - SnmpListeningStartedDialer(&snmpOutgoingConnectionOpened)); - - Ipc::StartListening(SOCK_DGRAM, - IPPROTO_UDP, - Config.Addrs.snmp_outgoing, - COMM_NONBLOCKING, - Ipc::fdnOutSnmpSocket, call); - } - } -} - -static void -snmpIncomingConnectionOpened(int fd, int errNo) -{ - theInSnmpConnection = fd; - if (theInSnmpConnection < 0) - fatal("Cannot open Incoming SNMP Port"); - - Comm::SetSelect(theInSnmpConnection, COMM_SELECT_READ, snmpHandleUdp, NULL, 0); - - debugs(1, 1, "Accepting SNMP messages on " << Config.Addrs.snmp_incoming << - ", FD " << theInSnmpConnection << "."); - - if (Config.Addrs.snmp_outgoing.IsNoAddr()) - theOutSnmpConnection = theInSnmpConnection; -} - -static void -snmpOutgoingConnectionOpened(int fd, int errNo) -{ - theOutSnmpConnection = fd; - if (theOutSnmpConnection < 0) - fatal("Cannot open Outgoing SNMP Port"); - - Comm::SetSelect(theOutSnmpConnection, COMM_SELECT_READ, snmpHandleUdp, NULL, 0); - - debugs(1, 1, "Outgoing SNMP messages on " << Config.Addrs.snmp_outgoing << - ", FD " << theOutSnmpConnection << "."); - - { - struct addrinfo *xaddr = NULL; - int x; - - - theOutSNMPAddr.SetEmpty(); - - theOutSNMPAddr.InitAddrInfo(xaddr); - - x = getsockname(theOutSnmpConnection, xaddr->ai_addr, &xaddr->ai_addrlen); - - if (x < 0) - debugs(51, 1, "theOutSnmpConnection FD " << theOutSnmpConnection << ": getsockname: " << xstrerror()); - else - theOutSNMPAddr = *xaddr; - - theOutSNMPAddr.FreeAddrInfo(xaddr); - } + if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && snmpOutgoingConn->local.IsAnyAddr()) { + snmpOutgoingConn->local.SetIPv4(); + } + AsyncCall::Pointer call = asyncCall(49, 2, "snmpOutgoingConnectionOpened", + SnmpListeningStartedDialer(&snmpPortOpened)); + Ipc::StartListening(SOCK_DGRAM, IPPROTO_UDP, snmpOutgoingConn, Ipc::fdnOutSnmpSocket, call); + } else { + snmpOutgoingConn = snmpIncomingConn; + debugs(1, DBG_IMPORTANT, "Sending SNMP messages from " << snmpOutgoingConn->local); + } +} + +static void +snmpPortOpened(const Comm::ConnectionPointer &conn, int errNo) +{ + if (!Comm::IsConnOpen(conn)) + fatalf("Cannot open SNMP %s Port",(conn->fd == snmpIncomingConn->fd?"receiving":"sending")); + + Comm::SetSelect(conn->fd, COMM_SELECT_READ, snmpHandleUdp, NULL, 0); + + if (conn->fd == snmpIncomingConn->fd) + debugs(1, DBG_IMPORTANT, "Accepting SNMP messages on " << snmpIncomingConn->local); + else if (conn->fd == snmpOutgoingConn->fd) + debugs(1, DBG_IMPORTANT, "Sending SNMP messages from " << snmpOutgoingConn->local); + else + fatalf("Lost SNMP port (%d) on FD %d", (int)conn->local.GetPort(), conn->fd); } void snmpConnectionShutdown(void) { - if (theInSnmpConnection < 0) + if (!Comm::IsConnOpen(snmpIncomingConn)) return; - if (theInSnmpConnection != theOutSnmpConnection) { - debugs(49, 1, "FD " << theInSnmpConnection << " Closing SNMP socket"); - comm_close(theInSnmpConnection); - } - - /* - * Here we set 'theInSnmpConnection' to -1 even though the SNMP '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. - */ - theInSnmpConnection = -1; + // Perform lazy closure. So as not to step on outgoing connection when sharing. + debugs(49, DBG_IMPORTANT, "Closing SNMP receiving port " << snmpIncomingConn->local); + snmpIncomingConn = NULL; /* * Normally we only write to the outgoing SNMP socket, but we @@ -415,9 +372,9 @@ * specific interface. During shutdown, we must disable reading * on the outgoing socket. */ - assert(theOutSnmpConnection > -1); + assert(Comm::IsConnOpen(snmpOutgoingConn)); - Comm::SetSelect(theOutSnmpConnection, COMM_SELECT_READ, NULL, NULL, 0); + Comm::SetSelect(snmpOutgoingConn->fd, COMM_SELECT_READ, NULL, NULL, 0); } void @@ -425,12 +382,11 @@ { snmpConnectionShutdown(); - if (theOutSnmpConnection > -1) { - debugs(49, 1, "FD " << theOutSnmpConnection << " Closing SNMP socket"); - comm_close(theOutSnmpConnection); - /* make sure the SNMP out connection is unset */ - theOutSnmpConnection = -1; - } + if (!Comm::IsConnOpen(snmpOutgoingConn)) + return; + + debugs(49, DBG_IMPORTANT, "Closing SNMP sending port " << snmpOutgoingConn->local); + snmpOutgoingConn = NULL; } /* === modified file 'src/snmp_core.h' --- src/snmp_core.h 2011-01-19 10:12:54 +0000 +++ src/snmp_core.h 2011-03-26 08:56:15 +0000 @@ -10,6 +10,7 @@ #include "config.h" #include "cache_snmp.h" +#include "comm/forward.h" #define SNMP_REQUEST_SIZE 4096 #define MAX_PROTOSTAT 5 @@ -35,4 +36,6 @@ extern struct snmp_pdu* snmpAgentResponse(struct snmp_pdu* PDU); extern AggrType snmpAggrType(oid* Current, snint CurrentLen); +extern Comm::ConnectionPointer snmpOutgoingConn; + #endif /* SQUID_SNMP_CORE_H */ === modified file 'src/ssl/Makefile.am' --- src/ssl/Makefile.am 2010-12-13 23:02:52 +0000 +++ src/ssl/Makefile.am 2011-03-13 02:55:18 +0000 @@ -6,6 +6,8 @@ EXTRA_PROGRAMS = \ ssl_crtd +EXTRA_DIST = stub_libsslsquid.cc stub_libsslutil.cc + if USE_SSL_CRTD SSL_CRTD = ssl_crtd SSL_CRTD_SOURCE = \ === added file 'src/ssl/stub_libsslsquid.cc' --- src/ssl/stub_libsslsquid.cc 1970-01-01 00:00:00 +0000 +++ src/ssl/stub_libsslsquid.cc 2011-03-13 02:52:52 +0000 @@ -0,0 +1,60 @@ +#include "config.h" +#include "fatal.h" + +/* Stub File for the ssl/libsslsquid.la convenience library */ + +#define STUB_BASE "ssl/libsslsquid.la" + +#define STUB { fatal(STUB_BASE " required."); } +#define STUB_RETVAL(x) { fatal(STUB_BASE " required."); return (x); } +#define STUB_RETREF(x) { fatal(STUB_BASE " required."); static x v; return v; } +#define STUB_RETREF2(x,y) { fatal(STUB_BASE " required."); static x v((y)); return v; } + +#include "ssl/Config.h" +Ssl::Config::Config() STUB +Ssl::Config::~Config() STUB +Ssl::Config Ssl::TheConfig; + +#include "ssl/context_storage.h" +//Ssl::CertificateStorageAction::CertificateStorageAction(const Mgr::Command::Pointer &cmd) STUB +Ssl::CertificateStorageAction::Pointer Ssl::CertificateStorageAction::Create(const Mgr::Command::Pointer &cmd) STUB_RETREF(Ssl::CertificateStorageAction::Pointer) +void Ssl::CertificateStorageAction::dump(StoreEntry *sentry) STUB +Ssl::LocalContextStorage::Item::Item(SSL_CTX * aSsl_ctx, std::string const & aName) STUB +Ssl::LocalContextStorage::Item::~Item() STUB +Ssl::LocalContextStorage::LocalContextStorage(size_t aMax_memory) STUB +Ssl::LocalContextStorage::~LocalContextStorage() STUB +void Ssl::LocalContextStorage::SetSize(size_t aMax_memory) STUB +SSL_CTX * Ssl::LocalContextStorage::add(char const * host_name, SSL_CTX * ssl_ctx) STUB_RETVAL(NULL) +SSL_CTX * Ssl::LocalContextStorage::find(char const * host_name) STUB_RETVAL(NULL) +void Ssl::LocalContextStorage::remove(char const * host_name) STUB +Ssl::GlobalContextStorage::GlobalContextStorage() STUB +Ssl::GlobalContextStorage::~GlobalContextStorage() STUB +void Ssl::GlobalContextStorage::addLocalStorage(Ip::Address const & address, size_t size_of_store) STUB +Ssl::LocalContextStorage & Ssl::GlobalContextStorage::getLocalStorage(Ip::Address const & address) STUB_RETREF2(Ssl::LocalContextStorage, 0) +void Ssl::GlobalContextStorage::reconfigureStart() STUB +//Ssl::GlobalContextStorage Ssl::TheGlobalContextStorage; + +#include "ssl/ErrorDetail.h" +Ssl::ssl_error_t parseErrorString(const char *name) STUB_RETVAL(0) +const char *Ssl::getErrorName(ssl_error_t value) STUB_RETVAL(NULL) +Ssl::ErrorDetail::ErrorDetail(ssl_error_t err_no, X509 *cert) STUB +Ssl::ErrorDetail::ErrorDetail(ErrorDetail const &) STUB +const String & Ssl::ErrorDetail::toString() const STUB_RETREF(String) + +#include "ssl/support.h" +SSL_CTX *sslCreateServerContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options, const char *flags, const char *clientCA, const char *CAfile, const char *CApath, const char *CRLfile, const char *dhpath, const char *context) STUB_RETVAL(NULL) +SSL_CTX *sslCreateClientContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options, const char *flags, const char *CAfile, const char *CApath, const char *CRLfile) STUB_RETVAL(NULL) +int ssl_read_method(int, char *, int) STUB_RETVAL(0) +int ssl_write_method(int, const char *, int) STUB_RETVAL(0) +void ssl_shutdown_method(int) STUB +const char *sslGetUserEmail(SSL *ssl) STUB_RETVAL(NULL) +// typedef char const *SSLGETATTRIBUTE(SSL *, const char *); +// SSLGETATTRIBUTE sslGetUserAttribute; +// SSLGETATTRIBUTE sslGetCAAttribute; +const char *sslGetUserCertificatePEM(SSL *ssl) STUB_RETVAL(NULL) +const char *sslGetUserCertificateChainPEM(SSL *ssl) STUB_RETVAL(NULL) +SSL_CTX *Ssl::generateSslContext(char const *host, Ssl::X509_Pointer const & signedX509, Ssl::EVP_PKEY_Pointer const & signedPkey) STUB_RETVAL(NULL) +bool Ssl::verifySslCertificateDate(SSL_CTX * sslContext) STUB_RETVAL(false) +SSL_CTX * Ssl::generateSslContextUsingPkeyAndCertFromMemory(const char * data) STUB_RETVAL(NULL) +int Ssl::matchX509CommonNames(X509 *peer_cert, void *check_data, int (*check_func)(void *check_data, ASN1_STRING *cn_data)) STUB_RETVAL(0) +int Ssl::asn1timeToString(ASN1_TIME *tm, char *buf, int len) STUB_RETVAL(0) === added file 'src/ssl/stub_libsslutil.cc' --- src/ssl/stub_libsslutil.cc 1970-01-01 00:00:00 +0000 +++ src/ssl/stub_libsslutil.cc 2011-03-13 02:54:43 +0000 @@ -0,0 +1,39 @@ +#include "config.h" +#include "fatal.h" + +/* Stub File for the ssl/libsslutil.la convenience library */ + +#define STUB_BASE "ssl/libsslutil.la" + +#define STUB { fatal(STUB_BASE " required."); } +#define STUB_RETVAL(x) { fatal(STUB_BASE " required."); return (x); } +#define STUB_RETREF(x) { fatal(STUB_BASE " required."); static x v; return v; } +#define STUB_RETREF2(x,y) { fatal(STUB_BASE " required."); static x v((y)); return v; } + +#include "ssl/crtd_message.h" +Ssl::CrtdMessage::CrtdMessage() STUB +Ssl::CrtdMessage::ParseResult Ssl::CrtdMessage::parse(const char * buffer, size_t len) STUB_RETVAL(ERROR) +std::string const & Ssl::CrtdMessage::getBody() const STUB_RETREF(std::string) +std::string const & Ssl::CrtdMessage::getCode() const STUB_RETREF(std::string) +void Ssl::CrtdMessage::setBody(std::string const & aBody) STUB +void Ssl::CrtdMessage::setCode(std::string const & aCode) STUB +std::string Ssl::CrtdMessage::compose() const STUB_RETREF(std::string) +void Ssl::CrtdMessage::clear() STUB +void Ssl::CrtdMessage::parseBody(BodyParams & map, std::string & other_part) const STUB +void Ssl::CrtdMessage::composeBody(BodyParams const & map, std::string const & other_part) STUB + +#include "ssl/gadgets.h" +X509_REQ * Ssl::createNewX509Request(EVP_PKEY_Pointer const & pkey, const char * hostname) STUB_RETVAL(NULL) +bool Ssl::writeCertAndPrivateKeyToMemory(X509_Pointer const & cert, EVP_PKEY_Pointer const & pkey, std::string & bufferToWrite) STUB_RETVAL(false) +bool Ssl::writeCertAndPrivateKeyToFile(X509_Pointer const & cert, EVP_PKEY_Pointer const & pkey, char const * filename) STUB_RETVAL(false) +bool Ssl::readCertAndPrivateKeyFromMemory(X509_Pointer & cert, EVP_PKEY_Pointer & pkey, char const * bufferToRead) STUB_RETVAL(false) +X509 * Ssl::signRequest(X509_REQ_Pointer const & request, X509_Pointer const & x509, EVP_PKEY_Pointer const & pkey, ASN1_TIME * timeNotAfter, BIGNUM const * serial) STUB_RETVAL(NULL) +bool Ssl::generateSslCertificateAndPrivateKey(char const *host, X509_Pointer const & signedX509, EVP_PKEY_Pointer const & signedPkey, X509_Pointer & cert, EVP_PKEY_Pointer & pkey, BIGNUM const* serial) STUB_RETVAL(false) +void Ssl::readCertAndPrivateKeyFromFiles(X509_Pointer & cert, EVP_PKEY_Pointer & pkey, char const * certFilename, char const * keyFilename) STUB +bool Ssl::sslDateIsInTheFuture(char const * date) STUB_RETVAL(false) + +#include "ssl/helper.h" +Ssl::Helper * Ssl::Helper::GetInstance() STUB_RETVAL(NULL) +void Ssl::Helper::Init() STUB +void Ssl::Helper::Shutdown() STUB +void Ssl::Helper::sslSubmit(Ssl::CrtdMessage const & message, HLPCB * callback, void *data) STUB === modified file 'src/stat.cc' --- src/stat.cc 2011-02-08 01:12:42 +0000 +++ src/stat.cc 2011-03-26 08:57:09 +0000 @@ -38,6 +38,7 @@ #if USE_AUTH #include "auth/UserRequest.h" #endif +#include "comm/Connection.h" #include "mgr/Registration.h" #include "Store.h" #include "HttpRequest.h" @@ -2011,7 +2012,6 @@ dlink_node *i; ClientHttpRequest *http; StoreEntry *e; - int fd; char buf[MAX_IPSTRLEN]; for (i = ClientActiveRequests.head; i; i = i->next) { @@ -2022,18 +2022,16 @@ storeAppendPrintf(s, "Connection: %p\n", conn); if (conn != NULL) { - fd = conn->fd; + const int fd = conn->clientConnection->fd; storeAppendPrintf(s, "\tFD %d, read %"PRId64", wrote %"PRId64"\n", fd, fd_table[fd].bytes_read, fd_table[fd].bytes_written); storeAppendPrintf(s, "\tFD desc: %s\n", fd_table[fd].desc); storeAppendPrintf(s, "\tin: buf %p, offset %ld, size %ld\n", conn->in.buf, (long int) conn->in.notYetUsed, (long int) conn->in.allocatedSize); - storeAppendPrintf(s, "\tpeer: %s:%d\n", - conn->peer.NtoA(buf,MAX_IPSTRLEN), - conn->peer.GetPort()); - storeAppendPrintf(s, "\tme: %s:%d\n", - conn->me.NtoA(buf,MAX_IPSTRLEN), - conn->me.GetPort()); + storeAppendPrintf(s, "\tremote: %s\n", + conn->clientConnection->remote.ToURL(buf,MAX_IPSTRLEN)); + storeAppendPrintf(s, "\tlocal: %s\n", + conn->clientConnection->local.ToURL(buf,MAX_IPSTRLEN)); storeAppendPrintf(s, "\tnrequests: %d\n", conn->nrequests); } @@ -2064,13 +2062,13 @@ p = http->request->extacl_user.termedBuf(); } - if (!p && (conn != NULL && conn->rfc931[0])) - p = conn->rfc931; + if (!p && conn != NULL && conn->clientConnection->rfc931[0]) + p = conn->clientConnection->rfc931; #if USE_SSL - if (!p && conn != NULL) - p = sslGetUserEmail(fd_table[conn->fd].ssl); + if (!p && conn != NULL && Comm::IsConnOpen(conn->clientConnection)) + p = sslGetUserEmail(fd_table[conn->clientConnection->fd].ssl); #endif === modified file 'src/store.cc' --- src/store.cc 2011-03-22 12:23:25 +0000 +++ src/store.cc 2011-03-26 09:01:20 +0000 @@ -34,6 +34,8 @@ */ #include "squid.h" +#include "CacheManager.h" +#include "comm/Connection.h" #include "event.h" #include "fde.h" #include "Store.h" @@ -219,14 +221,14 @@ StoreEntry::DeferReader(void *theContext, CommRead const &aRead) { StoreEntry *anEntry = (StoreEntry *)theContext; - anEntry->delayAwareRead(aRead.fd, + anEntry->delayAwareRead(aRead.conn, aRead.buf, aRead.len, aRead.callback); } void -StoreEntry::delayAwareRead(int fd, char *buf, int len, AsyncCall::Pointer callback) +StoreEntry::delayAwareRead(const Comm::ConnectionPointer &conn, char *buf, int len, AsyncCall::Pointer callback) { size_t amountToRead = bytesWanted(Range(0, len)); /* sketch: readdeferer* = getdeferer. @@ -240,21 +242,20 @@ #if USE_DELAY_POOLS if (!mem_obj->readAheadPolicyCanRead()) { #endif - mem_obj->delayRead(DeferredRead(DeferReader, this, CommRead(fd, buf, len, callback))); + mem_obj->delayRead(DeferredRead(DeferReader, this, CommRead(conn, buf, len, callback))); return; #if USE_DELAY_POOLS } /* delay id limit */ - mem_obj->mostBytesAllowed().delayRead(DeferredRead(DeferReader, this, CommRead(fd, buf, len, callback))); - + mem_obj->mostBytesAllowed().delayRead(DeferredRead(DeferReader, this, CommRead(conn, buf, len, callback))); return; #endif } - comm_read(fd, buf, amountToRead, callback); + comm_read(conn, buf, amountToRead, callback); } size_t === modified file 'src/structs.h' --- src/structs.h 2011-03-15 17:31:34 +0000 +++ src/structs.h 2011-03-23 09:42:23 +0000 @@ -438,6 +438,7 @@ } onoff; int forward_max_tries; + int connect_retries; class ACL *aclList; @@ -515,7 +516,6 @@ char *errorStylesheet; struct { - int maxtries; int onerror; } retry; @@ -919,7 +919,7 @@ int n_addresses; int rr_count; peer *next; - int test_fd; + int testing_now; struct { unsigned int hash; === modified file 'src/tests/stub_MemObject.cc' --- src/tests/stub_MemObject.cc 2010-11-27 06:44:33 +0000 +++ src/tests/stub_MemObject.cc 2011-02-18 07:26:56 +0000 @@ -33,6 +33,7 @@ */ #include "squid.h" +#include "comm/Connection.h" #include "MemObject.h" #include "HttpReply.h" #if USE_DELAY_POOLS === modified file 'src/tests/stub_cache_manager.cc' --- src/tests/stub_cache_manager.cc 2010-12-03 03:38:34 +0000 +++ src/tests/stub_cache_manager.cc 2010-12-08 05:22:33 +0000 @@ -41,7 +41,7 @@ } void -CacheManager::Start(int fd, HttpRequest * request, StoreEntry * entry) +CacheManager::Start(const Comm::ConnectionPointer &conn, HttpRequest * request, StoreEntry * entry) { return; } === added file 'src/tests/stub_client_db.cc' --- src/tests/stub_client_db.cc 1970-01-01 00:00:00 +0000 +++ src/tests/stub_client_db.cc 2011-03-05 07:28:09 +0000 @@ -0,0 +1,68 @@ +#include "config.h" +/* because the clientdb API is defined in protos.h still */ +#include "protos.h" + +void +clientdbInit(void) +{ + fatal("client_db.cc required"); +} + +void +clientdbUpdate(const Ip::Address &, log_type, AnyP::ProtocolType, size_t) +{ + fatal("client_db.cc required"); +} + +int +clientdbCutoffDenied(const Ip::Address &) +{ + fatal("client_db.cc required"); + return -1; +} + +void +clientdbDump(StoreEntry *) +{ + fatal("client_db.cc required"); +} + +void +clientdbFreeMemory(void) +{ + fatal("client_db.cc required"); +} + +int +clientdbEstablished(const Ip::Address &, int) +{ + fatal("client_db.cc required"); + return -1; +} + +#if USE_DELAY_POOLS +void +clientdbSetWriteLimiter(ClientInfo * info, const int writeSpeedLimit,const double initialBurst,const double highWatermark) +{ + fatal("client_db.cc required"); +} + +ClientInfo * +clientdbGetInfo(const Ip::Address &addr) +{ + fatal("client_db.cc required"); + return NULL; +} +#endif + +void +clientOpenListenSockets(void) +{ + fatal("client_db.cc required"); +} + +void +clientHttpConnectionsClose(void) +{ + fatal("client_db.cc required"); +} === modified file 'src/tests/stub_comm.cc' --- src/tests/stub_comm.cc 2011-01-10 09:43:43 +0000 +++ src/tests/stub_comm.cc 2011-03-07 09:52:12 +0000 @@ -34,6 +34,7 @@ #include "squid.h" #include "comm.h" +#include "comm/Connection.h" #include "comm/Loops.h" #include "CommRead.h" #include "fde.h" @@ -61,20 +62,20 @@ } void -comm_read(int fd, char *buf, int size, IOCB *handler, void *handler_data) +comm_read(const Comm::ConnectionPointer &conn, char *buf, int size, IOCB *handler, void *handler_data) { fatal ("Not implemented"); } void -comm_read(int, char*, int, AsyncCall::Pointer &callback) +comm_read(const Comm::ConnectionPointer &conn, char*, int, AsyncCall::Pointer &callback) { fatal ("Not implemented"); } /* should be in stub_CommRead */ #include "CommRead.h" -CommRead::CommRead (int fd, char *buf, int len, AsyncCall::Pointer &callback) +CommRead::CommRead(const Comm::ConnectionPointer &, char *buf, int len, AsyncCall::Pointer &callback) { fatal ("Not implemented"); } @@ -130,15 +131,6 @@ return -1; } -/* bah, cheating on stub count */ - -pid_t -ipcCreate(int type, const char *prog, const char *const args[], const char *name, Ip::Address &local_addr, int *rfd, int *wfd, void **hIpc) -{ - fatal ("Not implemented"); - return -1; -} - void comm_init(void) { @@ -176,8 +168,3 @@ { fatal ("Not implemented"); } - -ConnectionDetail::ConnectionDetail() : me(), peer() -{ - fatal ("Not implemented"); -} === added file 'src/tests/stub_icp.cc' --- src/tests/stub_icp.cc 1970-01-01 00:00:00 +0000 +++ src/tests/stub_icp.cc 2011-03-11 13:01:58 +0000 @@ -0,0 +1,37 @@ +#include "config.h" +#include "comm/Connection.h" +#include "ICP.h" +#include "icp_opcode.h" + +#define STUB { fatal("icp_*.cc required."); } +#define STUB_RETVAL(x) { fatal("icp_*.cc required."); return (x); } +//#define STUB_RETREF(x) { fatal("icp_*.cc required."); static x v; return v; } + +#ifdef __cplusplus +_icp_common_t::_icp_common_t() STUB +_icp_common_t::_icp_common_t(char *buf, unsigned int len) STUB +void _icp_common_t::handleReply(char *buf, Ip::Address &from) STUB +_icp_common_t *_icp_common_t::createMessage(icp_opcode opcode, int flags, const char *url, int reqnum, int pad) STUB_RETVAL(NULL) +icp_opcode _icp_common_t::getOpCode() const STUB_RETVAL(ICP_INVALID) +ICPState::ICPState(icp_common_t &aHeader, HttpRequest *aRequest) STUB +ICPState::~ICPState() STUB +#endif + +Comm::ConnectionPointer icpIncomingConn; +Comm::ConnectionPointer icpOutgoingConn; +Ip::Address theIcpPublicHostID; + +HttpRequest* icpGetRequest(char *url, int reqnum, int fd, Ip::Address &from) STUB_RETVAL(NULL) +int icpAccessAllowed(Ip::Address &from, HttpRequest * icp_request) STUB_RETVAL(0) +void icpCreateAndSend(icp_opcode, int flags, char const *url, int reqnum, int pad, int fd, const Ip::Address &from) STUB +icp_opcode icpGetCommonOpcode() STUB_RETVAL(ICP_INVALID) +int icpUdpSend(int, const Ip::Address &, icp_common_t *, log_type, int) STUB_RETVAL(0) +log_type icpLogFromICPCode(icp_opcode opcode) STUB_RETVAL(LOG_TAG_NONE) +void icpDenyAccess(Ip::Address &from, char *url, int reqnum, int fd) STUB +void icpHandleIcpV3(int, Ip::Address &, char *, int) STUB +int icpCheckUdpHit(StoreEntry *, HttpRequest * request) STUB_RETVAL(0) +void icpConnectionsOpen(void) STUB +void icpConnectionShutdown(void) STUB +void icpConnectionClose(void) STUB +int icpSetCacheKey(const cache_key * key) STUB_RETVAL(0) +const cache_key *icpGetCacheKey(const char *url, int reqnum) STUB_RETVAL(NULL) === added file 'src/tests/stub_ipc.cc' --- src/tests/stub_ipc.cc 1970-01-01 00:00:00 +0000 +++ src/tests/stub_ipc.cc 2011-03-07 09:53:30 +0000 @@ -0,0 +1,10 @@ +#include "config.h" +// because ipcCreate is defined in protos.h still +#include "protos.h" + +pid_t +ipcCreate(int type, const char *prog, const char *const args[], const char *name, Ip::Address &local_addr, int *rfd, int *wfd, void **hIpc) +{ + fatal("ipc.cc required."); + return -1; +} === added file 'src/tests/stub_pconn.cc' --- src/tests/stub_pconn.cc 1970-01-01 00:00:00 +0000 +++ src/tests/stub_pconn.cc 2011-02-25 12:03:47 +0000 @@ -0,0 +1,125 @@ +/* + * STUB file for the pconn.cc API + * Functions here are inactive. + */ +#include "config.h" +#include "pconn.h" +#include "comm/Connection.h" + +IdleConnList::IdleConnList(const char *key, PconnPool *parent) +{ + fatal("pconn.cc required"); +} + +IdleConnList::~IdleConnList() +{ + fatal("pconn.cc required"); +} + +void +IdleConnList::push(const Comm::ConnectionPointer &conn) +{ + fatal("pconn.cc required"); +} + +Comm::ConnectionPointer +IdleConnList::findUseable(const Comm::ConnectionPointer &key) +{ + fatal("pconn.cc required"); + return Comm::ConnectionPointer(); +} + +void +IdleConnList::clearHandlers(const Comm::ConnectionPointer &conn) +{ + fatal("pconn.cc required"); +} + +PconnPool::PconnPool(const char *) +{ + fatal("pconn.cc required"); +} + +PconnPool::~PconnPool() +{ + fatal("pconn.cc required"); +} + +void +PconnPool::moduleInit() +{ + fatal("pconn.cc required"); +} + +void +PconnPool::push(const Comm::ConnectionPointer &serverConn, const char *domain) +{ + fatal("pconn.cc required"); +} + +Comm::ConnectionPointer +PconnPool::pop(const Comm::ConnectionPointer &destLink, const char *domain, bool retriable) +{ + fatal("pconn.cc required"); + return Comm::ConnectionPointer(); +} + +void +PconnPool::count(int uses) +{ + fatal("pconn.cc required"); +} + +void +PconnPool::dumpHist(StoreEntry *e) const +{ + fatal("pconn.cc required"); +} + +void +PconnPool::dumpHash(StoreEntry *e) const +{ + fatal("pconn.cc required"); +} + +void +PconnPool::unlinkList(IdleConnList *list) const +{ + fatal("pconn.cc required"); +} + +PconnModule * +PconnModule::GetInstance() +{ + fatal("pconn.cc required"); + return NULL; +} + +void +PconnModule::DumpWrapper(StoreEntry *e) +{ + fatal("pconn.cc required"); +} + +PconnModule::PconnModule() +{ + fatal("pconn.cc required"); +} + +void +PconnModule::registerWithCacheManager(void) +{ + fatal("pconn.cc required"); +} + +void +PconnModule::add(PconnPool *) +{ + fatal("pconn.cc required"); +} + +void +PconnModule::dump(StoreEntry *) +{ + fatal("pconn.cc required"); +} === modified file 'src/tests/stub_tools.cc' --- src/tests/stub_tools.cc 2010-10-28 18:52:59 +0000 +++ src/tests/stub_tools.cc 2011-02-25 10:58:22 +0000 @@ -44,8 +44,7 @@ void death(int sig) { - fprintf(stderr, "Not implemented"); - exit(1); + fatal("tools.cc required"); } void* @@ -54,3 +53,15 @@ assert(dst); return memset(dst, val, sz); } + +void +logsFlush(void) +{ + fatal("tools.cc required"); +} + +void +no_suid(void) +{ + fatal("tools.cc required"); +} === modified file 'src/tools.cc' --- src/tools.cc 2011-01-28 07:58:53 +0000 +++ src/tools.cc 2011-03-26 09:03:28 +0000 @@ -33,11 +33,9 @@ */ #include "squid.h" -#include "compat/initgroups.h" -#include "compat/getaddrinfo.h" -#include "compat/getnameinfo.h" -#include "compat/tempnam.h" +#include "base/Subscription.h" #include "fde.h" +#include "ICP.h" #include "ip/Intercept.h" #include "ip/QosConfig.h" #include "MemBuf.h" @@ -92,16 +90,16 @@ int i; /* Release the main ports as early as possible */ + // clear both http_port and https_port lists. for (i = 0; i < NHttpSockets; i++) { if (HttpSockets[i] >= 0) close(HttpSockets[i]); } - if (theInIcpConnection >= 0) - close(theInIcpConnection); + // clear icp_port's + icpConnectionClose(); - if (theOutIcpConnection >= 0 && theOutIcpConnection != theInIcpConnection) - close(theOutIcpConnection); + // XXX: Why not the HTCP, SNMP, DNS ports as well? } static char * === modified file 'src/tunnel.cc' --- src/tunnel.cc 2011-03-23 08:55:43 +0000 +++ src/tunnel.cc 2011-03-26 09:09:32 +0000 @@ -37,7 +37,10 @@ #include "errorpage.h" #include "HttpRequest.h" #include "fde.h" +#include "Array.h" #include "comm.h" +#include "comm/Connection.h" +#include "comm/ConnOpener.h" #include "comm/Write.h" #include "client_side_request.h" #include "acl/FilledChecklist.h" @@ -47,7 +50,7 @@ #include "client_side.h" #include "MemBuf.h" #include "http.h" -#include "ip/tools.h" +#include "PeerSelectState.h" class TunnelStateData { @@ -57,28 +60,28 @@ class Connection; void *operator new(size_t); void operator delete (void *); - static void ReadClient(int fd, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data); - static void ReadServer(int fd, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data); - static void WriteClientDone(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data); - static void WriteServerDone(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data); + static void ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data); + static void ReadServer(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data); + static void WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t flag, int xerrno, void *data); + static void WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t flag, int xerrno, void *data); bool noConnections() const; char *url; - char *host; /* either request->host or proxy host */ - u_short port; HttpRequest *request; - FwdServer *servers; + Comm::ConnectionList serverDestinations; + + const char * getHost() const { + return (server.conn != NULL && server.conn->getPeer() ? server.conn->getPeer()->host : request->GetHost()); + }; class Connection { public: - Connection() : len (0),buf ((char *)xmalloc(SQUID_TCP_SO_RCVBUF)), size_ptr(NULL), fd_(-1) {} + Connection() : len (0), buf ((char *)xmalloc(SQUID_TCP_SO_RCVBUF)), size_ptr(NULL) {} ~Connection(); - int const & fd() const { return fd_;} - void fd(int const newFD); int bytesWanted(int lower=0, int upper = INT_MAX) const; void bytesIn(int const &); #if USE_DELAY_POOLS @@ -94,8 +97,9 @@ char *buf; int64_t *size_ptr; /* pointer to size in an ConnStateData for logging */ + Comm::ConnectionPointer conn; ///< The currently connected connection. + private: - int fd_; #if USE_DELAY_POOLS DelayId delayId; @@ -116,27 +120,24 @@ void writeServerDone(char *buf, size_t len, comm_err_t flag, int xerrno); }; -#define fd_closed(fd) (fd == -1 || fd_table[fd].closing()) - static const char *const conn_established = "HTTP/1.1 200 Connection established\r\n\r\n"; static CNCB tunnelConnectDone; static ERCB tunnelErrorComplete; static PF tunnelServerClosed; static PF tunnelClientClosed; -static PF tunnelTimeout; +static CTCB tunnelTimeout; static PSC tunnelPeerSelectComplete; static void tunnelStateFree(TunnelStateData * tunnelState); -static void tunnelConnected(int fd, void *); -static void tunnelProxyConnected(int fd, void *); +static void tunnelConnected(const Comm::ConnectionPointer &server, void *); +static void tunnelRelayConnectRequest(const Comm::ConnectionPointer &server, void *); static void tunnelServerClosed(int fd, void *data) { TunnelStateData *tunnelState = (TunnelStateData *)data; debugs(26, 3, "tunnelServerClosed: FD " << fd); - assert(fd == tunnelState->server.fd()); - tunnelState->server.fd(-1); + tunnelState->server.conn = NULL; if (tunnelState->noConnections()) { tunnelStateFree(tunnelState); @@ -144,7 +145,7 @@ } if (!tunnelState->server.len) { - comm_close(tunnelState->client.fd()); + tunnelState->client.conn->close(); return; } } @@ -154,8 +155,7 @@ { TunnelStateData *tunnelState = (TunnelStateData *)data; debugs(26, 3, "tunnelClientClosed: FD " << fd); - assert(fd == tunnelState->client.fd()); - tunnelState->client.fd(-1); + tunnelState->client.conn = NULL; if (tunnelState->noConnections()) { tunnelStateFree(tunnelState); @@ -163,7 +163,7 @@ } if (!tunnelState->client.len) { - comm_close(tunnelState->server.fd()); + tunnelState->server.conn->close(); return; } } @@ -175,8 +175,7 @@ assert(tunnelState != NULL); assert(tunnelState->noConnections()); safe_free(tunnelState->url); - FwdState::serversFree(&tunnelState->servers); - safe_free(tunnelState->host); + tunnelState->serverDestinations.clean(); HTTPMSGUNLOCK(tunnelState->request); delete tunnelState; } @@ -225,18 +224,19 @@ /* Read from server side and queue it for writing to the client */ void -TunnelStateData::ReadServer(int fd, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data) +TunnelStateData::ReadServer(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data) { TunnelStateData *tunnelState = (TunnelStateData *)data; - assert (cbdataReferenceValid (tunnelState)); + assert(cbdataReferenceValid(tunnelState)); - assert(fd == tunnelState->server.fd()); tunnelState->readServer(buf, len, errcode, xerrno); } void TunnelStateData::readServer(char *buf, size_t len, comm_err_t errcode, int xerrno) { + debugs(26, 3, HERE << server.conn << ", read " << len << " bytes"); + /* * Bail out early on COMM_ERR_CLOSING * - close handlers will tidy up for us @@ -245,8 +245,6 @@ if (errcode == COMM_ERR_CLOSING) return; - debugs(26, 3, "tunnelReadServer: FD " << server.fd() << ", read " << len << " bytes"); - if (len > 0) { server.bytesIn(len); kb_incr(&statCounter.server.all.kbytes_in, len); @@ -262,27 +260,27 @@ /* XXX fixme xstrerror and xerrno... */ errno = xerrno; - debugs(50, debugLevelForError(xerrno), "TunnelStateData::Connection::error: FD " << fd() << - ": read/write failure: " << xstrerror()); + debugs(50, debugLevelForError(xerrno), HERE << conn << ": read/write failure: " << xstrerror()); if (!ignoreErrno(xerrno)) - comm_close(fd()); + conn->close(); } /* Read from client side and queue it for writing to the server */ void -TunnelStateData::ReadClient(int fd, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data) +TunnelStateData::ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data) { TunnelStateData *tunnelState = (TunnelStateData *)data; assert (cbdataReferenceValid (tunnelState)); - assert(fd == tunnelState->client.fd()); tunnelState->readClient(buf, len, errcode, xerrno); } void TunnelStateData::readClient(char *buf, size_t len, comm_err_t errcode, int xerrno) { + debugs(26, 3, HERE << client.conn << ", read " << len << " bytes"); + /* * Bail out early on COMM_ERR_CLOSING * - close handlers will tidy up for us @@ -291,8 +289,6 @@ if (errcode == COMM_ERR_CLOSING) return; - debugs(26, 3, "tunnelReadClient: FD " << client.fd() << ", read " << len << " bytes"); - if (len > 0) { client.bytesIn(len); kb_incr(&statCounter.client_http.kbytes_in, len); @@ -306,26 +302,30 @@ { /* I think this is to prevent free-while-in-a-callback behaviour * - RBC 20030229 + * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData */ cbdataInternalLock(this); /* ??? should be locked by the caller... */ - /* Bump the server connection timeout on any activity */ - if (!fd_closed(server.fd())) - commSetTimeout(server.fd(), Config.Timeout.read, tunnelTimeout, this); + /* Bump the source connection read timeout on any activity */ + if (Comm::IsConnOpen(from.conn)) { + AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout", + CommTimeoutCbPtrFun(tunnelTimeout, this)); + commSetConnTimeout(from.conn, Config.Timeout.read, timeoutCall); + } if (errcode) from.error (xerrno); - else if (len == 0 || fd_closed(to.fd())) { - comm_close(from.fd()); + else if (len == 0 || !Comm::IsConnOpen(to.conn)) { + from.conn->close(); + /* Only close the remote end if we've finished queueing data to it */ - - if (from.len == 0 && !fd_closed(to.fd()) ) { - comm_close(to.fd()); + if (from.len == 0 && Comm::IsConnOpen(to.conn) ) { + to.conn->close(); } } else if (cbdataReferenceValid(this)) { AsyncCall::Pointer call = commCbCall(5,5, "SomeTunnelWriteHandler", CommIoCbPtrFun(completion, this)); - Comm::Write(to.fd(), from.buf, len, call, NULL); + Comm::Write(to.conn, from.buf, len, call, NULL); } cbdataInternalUnlock(this); /* ??? */ @@ -333,19 +333,18 @@ /* Writes data from the client buffer to the server side */ void -TunnelStateData::WriteServerDone(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data) +TunnelStateData::WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t flag, int xerrno, void *data) { TunnelStateData *tunnelState = (TunnelStateData *)data; assert (cbdataReferenceValid (tunnelState)); - assert(fd == tunnelState->server.fd()); tunnelState->writeServerDone(buf, len, flag, xerrno); } void TunnelStateData::writeServerDone(char *buf, size_t len, comm_err_t flag, int xerrno) { - debugs(26, 3, "tunnelWriteServer: FD " << server.fd() << ", " << len << " bytes written"); + debugs(26, 3, HERE << server.conn << ", " << len << " bytes written"); /* Error? */ if (flag != COMM_OK) { @@ -356,7 +355,7 @@ /* EOF? */ if (len == 0) { - comm_close(server.fd()); + server.conn->close(); return; } @@ -366,8 +365,8 @@ client.dataSent(len); /* If the other end has closed, so should we */ - if (fd_closed(client.fd())) { - comm_close(server.fd()); + if (!Comm::IsConnOpen(client.conn)) { + server.conn->close(); return; } @@ -381,17 +380,16 @@ /* Writes data from the server buffer to the client side */ void -TunnelStateData::WriteClientDone(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data) +TunnelStateData::WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t flag, int xerrno, void *data) { TunnelStateData *tunnelState = (TunnelStateData *)data; assert (cbdataReferenceValid (tunnelState)); - assert(fd == tunnelState->client.fd()); tunnelState->writeClientDone(buf, len, flag, xerrno); } void -TunnelStateData::Connection::dataSent (size_t amount) +TunnelStateData::Connection::dataSent(size_t amount) { assert(amount == (size_t)len); len =0; @@ -404,7 +402,7 @@ void TunnelStateData::writeClientDone(char *buf, size_t len, comm_err_t flag, int xerrno) { - debugs(26, 3, "tunnelWriteClient: FD " << client.fd() << ", " << len << " bytes written"); + debugs(26, 3, HERE << client.conn << ", " << len << " bytes written"); /* Error? */ if (flag != COMM_OK) { @@ -415,7 +413,7 @@ /* EOF? */ if (len == 0) { - comm_close(client.fd()); + client.conn->close(); return; } @@ -424,8 +422,8 @@ server.dataSent(len); /* If the other end has closed, so should we */ - if (fd_closed(server.fd())) { - comm_close(client.fd()); + if (!Comm::IsConnOpen(server.conn)) { + client.conn->close(); return; } @@ -438,10 +436,10 @@ } static void -tunnelTimeout(int fd, void *data) +tunnelTimeout(const CommTimeoutCbParams &io) { - TunnelStateData *tunnelState = (TunnelStateData *)data; - debugs(26, 3, "tunnelTimeout: FD " << fd); + TunnelStateData *tunnelState = static_cast(io.data); + debugs(26, 3, HERE << io.conn); /* Temporary lock to protect our own feets (comm_close -> tunnelClientClosed -> Free) */ cbdataInternalLock(tunnelState); @@ -453,63 +451,37 @@ void TunnelStateData::Connection::closeIfOpen() { - if (!fd_closed(fd())) - comm_close(fd()); + if (Comm::IsConnOpen(conn)) + conn->close(); } void TunnelStateData::copyRead(Connection &from, IOCB *completion) { assert(from.len == 0); - comm_read(from.fd(), from.buf, from.bytesWanted(1, SQUID_TCP_SO_RCVBUF), completion, this); -} - -static void -tunnelConnectTimeout(int fd, void *data) -{ - TunnelStateData *tunnelState = (TunnelStateData *)data; - HttpRequest *request = tunnelState->request; - ErrorState *err = NULL; - - if (tunnelState->servers) { - if (tunnelState->servers->_peer) - hierarchyNote(&tunnelState->request->hier, tunnelState->servers->code, - tunnelState->servers->_peer->host); - else if (Config.onoff.log_ip_on_direct) - hierarchyNote(&tunnelState->request->hier, tunnelState->servers->code, - fd_table[tunnelState->server.fd()].ipaddr); - else - hierarchyNote(&tunnelState->request->hier, tunnelState->servers->code, - tunnelState->host); - } else - debugs(26, 1, "tunnelConnectTimeout(): tunnelState->servers is NULL"); - - err = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE, request); - - *tunnelState->status_ptr = HTTP_SERVICE_UNAVAILABLE; - - err->xerrno = ETIMEDOUT; - - err->port = tunnelState->port; - - err->callback = tunnelErrorComplete; - - err->callback_data = tunnelState; - - errorSend(tunnelState->client.fd(), err); - comm_close(fd); -} - -static void -tunnelConnectedWriteDone(int fd, char *buf, size_t size, comm_err_t flag, int xerrno, void *data) + AsyncCall::Pointer call = commCbCall(5,4, "SomeTunnelReadHandler", + CommIoCbPtrFun(completion, this)); + comm_read(from.conn, from.buf, from.bytesWanted(1, SQUID_TCP_SO_RCVBUF), call); +} + +/** + * All the pieces we need to write to client and/or server connection + * have been written. + * - Set the HTTP status for this request. + * - Start the blind pump. + */ +static void +tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *buf, size_t size, comm_err_t flag, int xerrno, void *data) { TunnelStateData *tunnelState = (TunnelStateData *)data; if (flag != COMM_OK) { - tunnelErrorComplete(fd, data, 0); + *tunnelState->status_ptr = HTTP_INTERNAL_SERVER_ERROR; + tunnelErrorComplete(conn->fd, data, 0); return; } + *tunnelState->status_ptr = HTTP_OK; if (cbdataReferenceValid(tunnelState)) { tunnelState->copyRead(tunnelState->server, TunnelStateData::ReadServer); tunnelState->copyRead(tunnelState->client, TunnelStateData::ReadClient); @@ -517,93 +489,104 @@ } /* - * handle the write completion from a proxy request to an upstream proxy + * handle the write completion from a proxy request to an upstream origin */ static void -tunnelProxyConnectedWriteDone(int fd, char *buf, size_t size, comm_err_t flag, int xerrno, void *data) -{ - TunnelStateData *tunnelState = static_cast(data); - debugs(26, 3, HERE << "FD " << fd << " tunnelState=" << tunnelState); - *tunnelState->status_ptr = HTTP_OK; - tunnelConnectedWriteDone(fd, buf, size, flag, xerrno, data); -} - -static void -tunnelConnected(int fd, void *data) +tunnelConnected(const Comm::ConnectionPointer &server, void *data) { TunnelStateData *tunnelState = (TunnelStateData *)data; - debugs(26, 3, "tunnelConnected: FD " << fd << " tunnelState=" << tunnelState); - *tunnelState->status_ptr = HTTP_OK; + debugs(26, 3, HERE << server << ", tunnelState=" << tunnelState); AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone", CommIoCbPtrFun(tunnelConnectedWriteDone, tunnelState)); - Comm::Write(tunnelState->client.fd(), conn_established, strlen(conn_established), call, NULL); + Comm::Write(tunnelState->client.conn, conn_established, strlen(conn_established), call, NULL); } static void -tunnelErrorComplete(int fdnotused, void *data, size_t sizenotused) +tunnelErrorComplete(int /*const Comm::ConnectionPointer &*/, void *data, size_t) { TunnelStateData *tunnelState = (TunnelStateData *)data; assert(tunnelState != NULL); /* temporary lock to save our own feets (comm_close -> tunnelClientClosed -> Free) */ cbdataInternalLock(tunnelState); - if (!fd_closed(tunnelState->client.fd())) - comm_close(tunnelState->client.fd()); + if (Comm::IsConnOpen(tunnelState->client.conn)) + tunnelState->client.conn->close(); - if (fd_closed(tunnelState->server.fd())) - comm_close(tunnelState->server.fd()); + if (Comm::IsConnOpen(tunnelState->server.conn)) + tunnelState->server.conn->close(); cbdataInternalUnlock(tunnelState); } static void -tunnelConnectDone(int fdnotused, const DnsLookupDetails &dns, comm_err_t status, int xerrno, void *data) +tunnelConnectDone(const Comm::ConnectionPointer &conn, comm_err_t status, int xerrno, void *data) { TunnelStateData *tunnelState = (TunnelStateData *)data; HttpRequest *request = tunnelState->request; ErrorState *err = NULL; - request->recordLookup(dns); +#if USE_DELAY_POOLS + /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */ + if (conn->getPeer() && conn->getPeer()->options.no_delay) + tunnelState->server.setDelayId(DelayId()); +#endif - if (tunnelState->servers->_peer) - hierarchyNote(&tunnelState->request->hier, tunnelState->servers->code, - tunnelState->servers->_peer->host); + if (conn != NULL && conn->getPeer()) + hierarchyNote(&tunnelState->request->hier, conn->peerType, conn->getPeer()->host); else if (Config.onoff.log_ip_on_direct) - hierarchyNote(&tunnelState->request->hier, tunnelState->servers->code, - fd_table[tunnelState->server.fd()].ipaddr); + hierarchyNote(&tunnelState->request->hier, conn->peerType, fd_table[conn->fd].ipaddr); else - hierarchyNote(&tunnelState->request->hier, tunnelState->servers->code, - tunnelState->host); - - if (status == COMM_ERR_DNS) { - debugs(26, 4, "tunnelConnect: Unknown host: " << tunnelState->host); - err = errorCon(ERR_DNS_FAIL, HTTP_NOT_FOUND, request); - *tunnelState->status_ptr = HTTP_NOT_FOUND; - err->dnsError = dns.error; - err->callback = tunnelErrorComplete; - err->callback_data = tunnelState; - errorSend(tunnelState->client.fd(), err); - } else if (status != COMM_OK) { - err = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE, request); - *tunnelState->status_ptr = HTTP_SERVICE_UNAVAILABLE; - err->xerrno = xerrno; - err->port = tunnelState->port; - err->callback = tunnelErrorComplete; - err->callback_data = tunnelState; - errorSend(tunnelState->client.fd(), err); + hierarchyNote(&tunnelState->request->hier, conn->peerType, tunnelState->getHost()); + + // TODO: merge this into hierarchyNote with a conn parameter instead of peerType + request->hier.peer_local_port = conn->local.GetPort(); // for %serverDestinations.shift(); + if (status != COMM_TIMEOUT && tunnelState->serverDestinations.size() > 0) { + /* Try another IP of this destination host */ + AsyncCall::Pointer call = commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone, tunnelState)); + Comm::ConnOpener *cs = new Comm::ConnOpener(tunnelState->serverDestinations[0], call, Config.Timeout.connect); + cs->setHost(tunnelState->url); + AsyncJob::Start(cs); + } else { + err = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE, request); + *tunnelState->status_ptr = HTTP_SERVICE_UNAVAILABLE; + err->xerrno = xerrno; + // on timeout is this still: err->xerrno = ETIMEDOUT; + err->port = conn->remote.GetPort(); + err->callback = tunnelErrorComplete; + err->callback_data = tunnelState; + errorSend(tunnelState->client.conn, err); + } + return; + } + + tunnelState->server.conn = conn; + request->peer_host = conn->getPeer() ? conn->getPeer()->host : NULL; + comm_add_close_handler(conn->fd, tunnelServerClosed, tunnelState); + + if (conn->getPeer()) { + tunnelState->request->peer_login = conn->getPeer()->login; + tunnelState->request->flags.proxying = 1; } else { - if (tunnelState->servers->_peer) - tunnelProxyConnected(tunnelState->server.fd(), tunnelState); - else { - tunnelConnected(tunnelState->server.fd(), tunnelState); - } - - commSetTimeout(tunnelState->server.fd(), - Config.Timeout.read, - tunnelTimeout, - tunnelState); - } + tunnelState->request->peer_login = NULL; + tunnelState->request->flags.proxying = 0; + } + + if (conn->getPeer()) + tunnelRelayConnectRequest(conn, tunnelState); + else { + tunnelConnected(conn, tunnelState); + } + + AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout", + CommTimeoutCbPtrFun(tunnelTimeout, tunnelState)); + commSetConnTimeout(conn, Config.Timeout.read, timeoutCall); } extern tos_t GetTosToServer(HttpRequest * request); @@ -614,12 +597,11 @@ { /* Create state structure. */ TunnelStateData *tunnelState = NULL; - int sock; ErrorState *err = NULL; int answer; - int fd = http->getConn()->fd; HttpRequest *request = http->request; char *url = http->uri; + /* * client_addr.IsNoAddr() indicates this is an "internal" request * from peer_digest.c, asn.c, netdb.c, etc and should always @@ -639,7 +621,7 @@ if (answer == 0) { err = errorCon(ERR_FORWARDING_DENIED, HTTP_FORBIDDEN, request); *status_ptr = HTTP_FORBIDDEN; - errorSend(fd, err); + errorSend(http->getConn()->clientConnection, err); return; } } @@ -647,89 +629,39 @@ debugs(26, 3, "tunnelStart: '" << RequestMethodStr(request->method) << " " << url << "'"); statCounter.server.all.requests++; statCounter.server.other.requests++; - /* Create socket. */ - Ip::Address temp = getOutgoingAddr(request,NULL); - - // if IPv6 is disabled try to force IPv4-only outgoing. - if (!Ip::EnableIpv6 && !temp.SetIPv4()) { - debugs(50, 4, "tunnelStart: IPv6 is Disabled. Tunnel failed from " << temp); - ErrorState *anErr = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE, request); - anErr->xerrno = EAFNOSUPPORT; - errorSend(fd, anErr); - 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. - temp.SetIPv4(); - } - - int flags = COMM_NONBLOCKING; - if (request->flags.spoof_client_ip) { - flags |= COMM_TRANSPARENT; - } - sock = comm_openex(SOCK_STREAM, - IPPROTO_TCP, - temp, - flags, - GetTosToServer(request), - GetNfmarkToServer(request), - url); - - if (sock == COMM_ERROR) { - debugs(26, 4, "tunnelStart: Failed because we're out of sockets."); - err = errorCon(ERR_SOCKET_FAILURE, HTTP_INTERNAL_SERVER_ERROR, request); - *status_ptr = HTTP_INTERNAL_SERVER_ERROR; - err->xerrno = errno; - errorSend(fd, err); - return; - } - - request->hier.peer_local_port = comm_local_port(sock); // for %server.setDelayId(DelayId::DelayClient(http)); #endif - tunnelState->url = xstrdup(url); tunnelState->request = HTTPMSGLOCK(request); tunnelState->server.size_ptr = size_ptr; tunnelState->status_ptr = status_ptr; - tunnelState->client.fd(fd); - tunnelState->server.fd(sock); - comm_add_close_handler(tunnelState->server.fd(), - tunnelServerClosed, - tunnelState); - comm_add_close_handler(tunnelState->client.fd(), + tunnelState->client.conn = http->getConn()->clientConnection; + + comm_add_close_handler(tunnelState->client.conn->fd, tunnelClientClosed, tunnelState); - commSetTimeout(tunnelState->client.fd(), - Config.Timeout.lifetime, - tunnelTimeout, - tunnelState); - commSetTimeout(tunnelState->server.fd(), - Config.Timeout.connect, - tunnelConnectTimeout, - tunnelState); - peerSelect(request, + + AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout", + CommTimeoutCbPtrFun(tunnelTimeout, tunnelState)); + commSetConnTimeout(tunnelState->client.conn, Config.Timeout.lifetime, timeoutCall); + + peerSelect(&(tunnelState->serverDestinations), request, NULL, tunnelPeerSelectComplete, tunnelState); } static void -tunnelProxyConnected(int fd, void *data) +tunnelRelayConnectRequest(const Comm::ConnectionPointer &srv, void *data) { TunnelStateData *tunnelState = (TunnelStateData *)data; HttpHeader hdr_out(hoRequest); Packer p; http_state_flags flags; - debugs(26, 3, "tunnelProxyConnected: FD " << fd << " tunnelState=" << tunnelState); + debugs(26, 3, HERE << srv << ", tunnelState=" << tunnelState); memset(&flags, '\0', sizeof(flags)); flags.proxying = tunnelState->request->flags.proxying; MemBuf mb; @@ -746,64 +678,34 @@ packerClean(&p); mb.append("\r\n", 2); - AsyncCall::Pointer call = commCbCall(5,5, "tunnelProxyConnectedWriteDone", - CommIoCbPtrFun(tunnelProxyConnectedWriteDone, tunnelState)); + AsyncCall::Pointer writeCall = commCbCall(5,5, "tunnelConnectedWriteDone", + CommIoCbPtrFun(tunnelConnectedWriteDone, tunnelState)); + Comm::Write(srv, &mb, writeCall); - Comm::Write(tunnelState->server.fd(), &mb, call); - commSetTimeout(tunnelState->server.fd(), Config.Timeout.read, tunnelTimeout, tunnelState); + AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout", + CommTimeoutCbPtrFun(tunnelTimeout, tunnelState)); + commSetConnTimeout(srv, Config.Timeout.read, timeoutCall); } static void -tunnelPeerSelectComplete(FwdServer * fs, void *data) +tunnelPeerSelectComplete(Comm::ConnectionList *peer_paths, void *data) { TunnelStateData *tunnelState = (TunnelStateData *)data; - HttpRequest *request = tunnelState->request; - peer *g = NULL; - if (fs == NULL) { + if (peer_paths == NULL || peer_paths->size() < 1) { ErrorState *err; - err = errorCon(ERR_CANNOT_FORWARD, HTTP_SERVICE_UNAVAILABLE, request); + err = errorCon(ERR_CANNOT_FORWARD, HTTP_SERVICE_UNAVAILABLE, tunnelState->request); *tunnelState->status_ptr = HTTP_SERVICE_UNAVAILABLE; err->callback = tunnelErrorComplete; err->callback_data = tunnelState; - errorSend(tunnelState->client.fd(), err); + errorSend(tunnelState->client.conn, err); return; } - tunnelState->servers = fs; - tunnelState->host = fs->_peer ? xstrdup(fs->_peer->host) : xstrdup(request->GetHost()); - request->peer_host = fs->_peer ? fs->_peer->host : NULL; - - if (fs->_peer == NULL) { - tunnelState->port = request->port; - } else if (fs->_peer->http_port != 0) { - tunnelState->port = fs->_peer->http_port; - } else if ((g = peerFindByName(fs->_peer->host))) { - tunnelState->port = g->http_port; - } else { - tunnelState->port = CACHE_HTTP_PORT; - } - - if (fs->_peer) { - tunnelState->request->peer_login = fs->_peer->login; - tunnelState->request->flags.proxying = 1; - } else { - tunnelState->request->peer_login = NULL; - tunnelState->request->flags.proxying = 0; - } - -#if USE_DELAY_POOLS - /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */ - if (g && g->options.no_delay) - tunnelState->server.setDelayId(DelayId()); - -#endif - - commConnectStart(tunnelState->server.fd(), - tunnelState->host, - tunnelState->port, - tunnelConnectDone, - tunnelState); + AsyncCall::Pointer call = commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone, tunnelState)); + Comm::ConnOpener *cs = new Comm::ConnOpener(tunnelState->serverDestinations[0], call, Config.Timeout.connect); + cs->setHost(tunnelState->url); + AsyncJob::Start(cs); } CBDATA_CLASS_INIT(TunnelStateData); @@ -823,16 +725,10 @@ cbdataFree(t); } -void -TunnelStateData::Connection::fd(int const newFD) -{ - fd_ = newFD; -} - bool TunnelStateData::noConnections() const { - return fd_closed(server.fd()) && fd_closed(client.fd()); + return !Comm::IsConnOpen(server.conn) && !Comm::IsConnOpen(client.conn); } #if USE_DELAY_POOLS === modified file 'src/typedefs.h' --- src/typedefs.h 2011-03-15 17:31:34 +0000 +++ src/typedefs.h 2011-03-23 09:42:23 +0000 @@ -158,8 +158,6 @@ #include "anyp/ProtocolType.h" typedef void IRCB(struct peer *, peer_t, AnyP::ProtocolType, void *, void *data); -class FwdServer; -typedef void PSC(FwdServer *, void *); typedef void RH(void *data, char *); /* in wordlist.h */ === modified file 'src/urn.cc' --- src/urn.cc 2011-03-23 08:55:43 +0000 +++ src/urn.cc 2011-03-23 09:42:23 +0000 @@ -256,7 +256,8 @@ if (urlres_e->isNull()) { urlres_e = storeCreateEntry(urlres, urlres, request_flags(), METHOD_GET); sc = storeClientListAdd(urlres_e, this); - FwdState::fwdStart(-1, urlres_e, urlres_r); + Comm::ConnectionPointer nul; + FwdState::fwdStart(nul, urlres_e, urlres_r); } else { urlres_e->lock(); === modified file 'src/wccp.cc' --- src/wccp.cc 2011-01-10 09:43:43 +0000 +++ src/wccp.cc 2011-03-26 09:11:42 +0000 @@ -38,6 +38,7 @@ #include "squid.h" #include "comm.h" +#include "comm/Connection.h" #include "comm/Loops.h" #include "event.h" === modified file 'src/wccp2.cc' --- src/wccp2.cc 2011-01-10 09:43:43 +0000 +++ src/wccp2.cc 2011-01-26 12:27:31 +0000 @@ -35,6 +35,7 @@ #if USE_WCCPv2 #include "comm.h" +#include "comm/Connection.h" #include "comm/Loops.h" #include "compat/strsep.h" #include "event.h" === modified file 'src/whois.cc' --- src/whois.cc 2011-03-23 08:55:43 +0000 +++ src/whois.cc 2011-03-23 09:48:27 +0000 @@ -50,7 +50,7 @@ public: ~WhoisState(); - void readReply (int fd, char *aBuffer, size_t aBufferLength, comm_err_t flag, int xerrno); + void readReply(const Comm::ConnectionPointer &, char *aBuffer, size_t aBufferLength, comm_err_t flag, int xerrno); void setReplyToOK(StoreEntry *sentry); StoreEntry *entry; HttpRequest *request; @@ -60,7 +60,7 @@ }; static PF whoisClose; -static PF whoisTimeout; +static CTCB whoisTimeout; static IOCB whoisReadReply; /* PUBLIC */ @@ -73,7 +73,7 @@ } static void -whoisWriteComplete(int fd, char *buf, size_t size, comm_err_t flag, int xerrno, void *data) +whoisWriteComplete(const Comm::ConnectionPointer &, char *buf, size_t size, comm_err_t flag, int xerrno, void *data) { xfree(buf); } @@ -82,7 +82,6 @@ whoisStart(FwdState * fwd) { WhoisState *p; - int fd = fwd->server_fd; char *buf; size_t l; CBDATA_INIT_TYPE(WhoisState); @@ -93,7 +92,7 @@ p->dataWritten = false; p->entry->lock(); - comm_add_close_handler(fd, whoisClose, p); + comm_add_close_handler(fwd->serverConnection()->fd, whoisClose, p); l = p->request->urlpath.size() + 3; @@ -102,29 +101,32 @@ String str_print=p->request->urlpath.substr(1,p->request->urlpath.size()); snprintf(buf, l, SQUIDSTRINGPH"\r\n", SQUIDSTRINGPRINT(str_print)); - AsyncCall::Pointer call = commCbCall(5,5, "whoisWriteComplete", - CommIoCbPtrFun(whoisWriteComplete, p)); - - Comm::Write(fd, buf, strlen(buf), call, NULL); - comm_read(fd, p->buf, BUFSIZ, whoisReadReply, p); - commSetTimeout(fd, Config.Timeout.read, whoisTimeout, p); + AsyncCall::Pointer writeCall = commCbCall(5,5, "whoisWriteComplete", + CommIoCbPtrFun(whoisWriteComplete, p)); + Comm::Write(fwd->serverConnection(), buf, strlen(buf), writeCall, NULL); + AsyncCall::Pointer readCall = commCbCall(5,4, "whoisReadReply", + CommIoCbPtrFun(whoisReadReply, p)); + comm_read(fwd->serverConnection(), p->buf, BUFSIZ, readCall); + AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "whoisTimeout", + CommTimeoutCbPtrFun(whoisTimeout, p)); + commSetConnTimeout(fwd->serverConnection(), Config.Timeout.read, timeoutCall); } /* PRIVATE */ static void -whoisTimeout(int fd, void *data) +whoisTimeout(const CommTimeoutCbParams &io) { - WhoisState *p = (WhoisState *)data; - debugs(75, 1, "whoisTimeout: " << p->entry->url() ); - whoisClose(fd, p); + WhoisState *p = static_cast(io.data); + debugs(75, 3, HERE << io.conn << ", URL " << p->entry->url()); + io.conn->close(); } static void -whoisReadReply(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data) +whoisReadReply(const Comm::ConnectionPointer &conn, char *buf, size_t len, comm_err_t flag, int xerrno, void *data) { WhoisState *p = (WhoisState *)data; - p->readReply(fd, buf, len, flag, xerrno); + p->readReply(conn, buf, len, flag, xerrno); } void @@ -137,27 +139,29 @@ } void -WhoisState::readReply (int fd, char *aBuffer, size_t aBufferLength, comm_err_t flag, int xerrno) +WhoisState::readReply(const Comm::ConnectionPointer &conn, char *aBuffer, size_t aBufferLength, comm_err_t flag, int xerrno) { /* Bail out early on COMM_ERR_CLOSING - close handlers will tidy up for us */ if (flag == COMM_ERR_CLOSING) return; aBuffer[aBufferLength] = '\0'; - debugs(75, 3, "whoisReadReply: FD " << fd << " read " << aBufferLength << " bytes"); + debugs(75, 3, HERE << conn << " read " << aBufferLength << " bytes"); debugs(75, 5, "{" << aBuffer << "}"); if (flag != COMM_OK) { - debugs(50, 2, "whoisReadReply: FD " << fd << ": read failure: " << xstrerror() << "."); + debugs(50, 2, HERE << conn << ": read failure: " << xstrerror() << "."); if (ignoreErrno(errno)) { - comm_read(fd, aBuffer, BUFSIZ, whoisReadReply, this); + AsyncCall::Pointer call = commCbCall(5,4, "whoisReadReply", + CommIoCbPtrFun(whoisReadReply, this)); + comm_read(conn, aBuffer, BUFSIZ, call); } else { ErrorState *err; err = errorCon(ERR_READ_ERROR, HTTP_INTERNAL_SERVER_ERROR, fwd->request); err->xerrno = errno; fwd->fail(err); - comm_close(fd); + conn->close(); } return; } @@ -174,7 +178,9 @@ entry->append(aBuffer, aBufferLength); entry->flush(); - comm_read(fd, aBuffer, BUFSIZ, whoisReadReply, this); + AsyncCall::Pointer call = commCbCall(5,4, "whoisReadReply", + CommIoCbPtrFun(whoisReadReply, this)); + comm_read(conn, aBuffer, BUFSIZ, call); return; } @@ -187,7 +193,7 @@ fwd->complete(); debugs(75, 3, "whoisReadReply: Done: " << entry->url()); - comm_close(fd); + conn->close(); } static void