]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Merge from trunk
authorAmos Jeffries <squid3@treenet.co.nz>
Thu, 15 Jul 2010 10:04:21 +0000 (22:04 +1200)
committerAmos Jeffries <squid3@treenet.co.nz>
Thu, 15 Jul 2010 10:04:21 +0000 (22:04 +1200)
53 files changed:
doc/release-notes/release-3.2.sgml
src/CommCalls.cc
src/CommCalls.h
src/ConnectionDetail.h [deleted file]
src/HttpRequest.cc
src/Makefile.am
src/PeerSelectState.h
src/adaptation/icap/ModXact.cc
src/adaptation/icap/Xaction.cc
src/adaptation/icap/Xaction.h
src/cache_cf.cc
src/cf.data.pre
src/client_side.cc
src/client_side.h
src/client_side_request.cc
src/comm.cc
src/comm.h
src/comm/ConnOpener.cc [new file with mode: 0644]
src/comm/ConnOpener.h [new file with mode: 0644]
src/comm/Connection.cc [new file with mode: 0644]
src/comm/Connection.h [new file with mode: 0644]
src/comm/ListenStateData.cc
src/comm/ListenStateData.h
src/comm/Makefile.am
src/comm/comm_err_t.h [new file with mode: 0644]
src/comm/forward.h [new file with mode: 0644]
src/defines.h
src/dns_internal.cc
src/forward.cc
src/forward.h
src/fqdncache.cc
src/ftp.cc
src/gopher.cc
src/http.cc
src/icp_v2.cc
src/ident/AclIdent.cc
src/ident/Ident.cc
src/ident/Ident.h
src/ipc.cc
src/ipcache.cc
src/log/ModTcp.cc
src/log/ModUdp.cc
src/main.cc
src/neighbors.cc
src/peer_select.cc
src/protos.h
src/snmp_core.cc
src/structs.h
src/tunnel.cc
src/typedefs.h
src/wccp.cc
src/wccp2.cc
src/whois.cc

index f5256caeb704c81eb804371304d6bbd53519e1d9..21f59059004f2cc4c6734704a73c4216a55aee13 100644 (file)
@@ -223,6 +223,10 @@ This section gives a thorough account of those changes in three categories:
        <p>Access control based on altered HTTP request following adaptation alterations (ICAP, eCAP, URL rewriter).
        An upgraded drop-in replacement for <em>http_access2</em> found in Squid-2.
 
+       <tag>connect_retries</tag>
+       <p>Replacement for <em>maximum_single_addr_tries</em>, 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.
+
        <tag>else</tag>
        <p>Part of conditional SMP support syyntax. see <em>if</em>
 
@@ -335,6 +339,10 @@ This section gives a thorough account of those changes in three categories:
        <tag>ftp_list_width</tag>
        <p>Obsolete.
 
+       <tag>maximum_single_addr_tries</tag>
+       <p>The behaviour controlled by this directive is no longer possible.
+       It has been replaced by <em>connect_retries</em> option which operates a little differently.
+
        <tag>url_rewrite_concurrency</tag>
        <p>Replaced by url_rewrite_children ... concurrency=N option.
 
index 3f7da9996bce9c9d840186f36ef9cdaeeed1c973..da1754e04ea00e226f1a1c855a78eea8a02baf80 100644 (file)
@@ -1,5 +1,6 @@
 #include "squid.h"
 #include "fde.h"
+#include "comm/Connection.h"
 #include "CommCalls.h"
 
 /* CommCommonCbParams */
@@ -45,6 +46,7 @@ CommAcceptCbParams::print(std::ostream &os) const
     CommCommonCbParams::print(os);
     if (nfd >= 0)
         os << ", newFD " << nfd;
+    os << ", " << details;
 }
 
 
@@ -71,7 +73,8 @@ void
 CommConnectCbParams::print(std::ostream &os) const
 {
     CommCommonCbParams::print(os);
-    os << ", " << dns;
+    if (conn != NULL)
+      os << ", from my " << conn->local << " to " << conn->remote;
 }
 
 /* CommIoCbParams */
@@ -133,7 +136,7 @@ CommAcceptCbPtrFun::CommAcceptCbPtrFun(IOACB *aHandler,
 void
 CommAcceptCbPtrFun::dial()
 {
-    handler(params.fd, params.nfd, &params.details, params.flag, params.xerrno, params.data);
+    handler(params.fd, params.nfd, params.details, params.flag, params.xerrno, params.data);
 }
 
 void
@@ -157,7 +160,7 @@ CommConnectCbPtrFun::CommConnectCbPtrFun(CNCB *aHandler,
 void
 CommConnectCbPtrFun::dial()
 {
-    handler(params.fd, params.dns, params.flag, params.xerrno, params.data);
+    handler(params.conn, params.flag, params.xerrno, params.data);
 }
 
 void
index 5012e836b2ce721602adc52c79d7e76b829b417e..0a9e147f1d1c59612a31a9817c44a54f4821681d 100644 (file)
@@ -6,11 +6,10 @@
 #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/comm_err_t.h"
+#include "comm/forward.h"
 
 /* CommCalls implement AsyncCall interface for comm_* callbacks.
  * The classes cover two call dialer kinds:
  *     - I/O (IOCB).
  */
 
+typedef void IOACB(int fd, int nfd, Comm::ConnectionPointer &details, comm_err_t flag, int xerrno, void *data);
+typedef void CNCB(Comm::ConnectionPointer &conn, 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);
+
 /*
  * TODO: When there are no function-pointer-based callbacks left, all
  * this complexity can be removed. Jobs that need comm services will just
@@ -69,7 +72,7 @@ public:
     void print(std::ostream &os) const;
 
 public:
-    ConnectionDetail details;
+    Comm::ConnectionPointer details;
     int nfd; // TODO: rename to fdNew or somesuch
 };
 
@@ -84,7 +87,7 @@ public:
     void print(std::ostream &os) const;
 
 public:
-    DnsLookupDetails dns;
+    Comm::ConnectionPointer conn;
 };
 
 // read/write (I/O) parameters
diff --git a/src/ConnectionDetail.h b/src/ConnectionDetail.h
deleted file mode 100644 (file)
index 1c5ea36..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * DEBUG: section 05    Socket Functions
- * AUTHOR: Robert Collins
- *
- * SQUID Web Proxy Cache          http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- *  Squid is the result of efforts by numerous individuals from
- *  the Internet community; see the CONTRIBUTORS file for full
- *  details.   Many organizations have provided support for Squid's
- *  development; see the SPONSORS file for full details.  Squid is
- *  Copyrighted (C) 2001 by the Regents of the University of
- *  California; see the COPYRIGHT file for full details.  Squid
- *  incorporates software developed and/or copyrighted by other
- *  sources; see the CREDITS file for full details.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
- *
- * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
- */
-
-#ifndef _SQUIDCONNECTIONDETAIL_H_
-#define _SQUIDCONNECTIONDETAIL_H_
-
-#include "ip/Address.h"
-
-class ConnectionDetail
-{
-
-public:
-
-    ConnectionDetail();
-
-    Ip::Address me;
-
-    Ip::Address peer;
-};
-
-#endif
index d79704ba3d7cf84f0e860879cdd5a0cd4e78421f..3c0d4c861c58b3acc485747c0c34c3601e15f28f 100644 (file)
  */
 
 #include "squid.h"
-#include "HttpRequest.h"
+#include "acl/FilledChecklist.h"
+#if ICAP_CLIENT
+#include "adaptation/icap/icap_log.h"
+#endif
 #include "auth/UserRequest.h"
+#include "DnsLookupDetails.h"
+#include "HttpRequest.h"
 #include "HttpHeaderRange.h"
 #include "MemBuf.h"
 #include "Store.h"
-#if ICAP_CLIENT
-#include "adaptation/icap/icap_log.h"
-#endif
-#include "acl/FilledChecklist.h"
 
 HttpRequest::HttpRequest() : HttpMsg(hoRequest)
 {
index e73f6b17c55e1e22295c8b648e3d47c3c6a2f632..d19ca0855922a0557c453cefcd28ff1cd12f648d 100644 (file)
@@ -290,7 +290,6 @@ squid_SOURCES = \
        ConfigOption.cc \
        ConfigParser.cc \
        ConfigParser.h \
-       ConnectionDetail.h \
        debug.cc \
        Debug.h \
        defines.h \
@@ -533,7 +532,7 @@ nodist_squid_SOURCES = \
 
 squid_LDADD = \
        $(COMMON_LIBS) \
-       comm/libcomm-listener.la \
+       comm/libcomm.la \
        eui/libeui.la \
        icmp/libicmp.la icmp/libicmp-core.la \
        log/liblog.la \
@@ -1236,10 +1235,10 @@ tests_testCacheManager_SOURCES = \
        wordlist.cc
 nodist_tests_testCacheManager_SOURCES = \
        $(BUILT_SOURCES)
-# comm.cc only requires comm/libcomm-listener.la until fdc_table is dead.
+# comm.cc only requires comm/libcomm.la until fdc_table is dead.
 tests_testCacheManager_LDADD = \
        $(COMMON_LIBS) \
-       comm/libcomm-listener.la \
+       comm/libcomm.la \
        icmp/libicmp.la icmp/libicmp-core.la \
        log/liblog.la \
        $(REPL_OBJS) \
@@ -1422,7 +1421,7 @@ nodist_tests_testEvent_SOURCES = \
 tests_testEvent_LDADD = \
        $(COMMON_LIBS) \
        icmp/libicmp.la icmp/libicmp-core.la \
-       comm/libcomm-listener.la \
+       comm/libcomm.la \
        log/liblog.la \
        $(REPL_OBJS) \
        ${ADAPTATION_LIBS} \
@@ -1577,7 +1576,7 @@ nodist_tests_testEventLoop_SOURCES = \
 tests_testEventLoop_LDADD = \
        $(COMMON_LIBS) \
        icmp/libicmp.la icmp/libicmp-core.la \
-       comm/libcomm-listener.la \
+       comm/libcomm.la \
        log/liblog.la \
        $(REPL_OBJS) \
        ${ADAPTATION_LIBS} \
@@ -1727,7 +1726,7 @@ nodist_tests_test_http_range_SOURCES = \
 tests_test_http_range_LDADD = \
        $(COMMON_LIBS) \
        icmp/libicmp.la icmp/libicmp-core.la \
-       comm/libcomm-listener.la \
+       comm/libcomm.la \
        log/liblog.la \
        $(REPL_OBJS) \
        ${ADAPTATION_LIBS} \
@@ -1882,7 +1881,7 @@ nodist_tests_testHttpRequest_SOURCES = \
 tests_testHttpRequest_LDADD = \
        $(COMMON_LIBS) \
        icmp/libicmp.la icmp/libicmp-core.la \
-       comm/libcomm-listener.la \
+       comm/libcomm.la \
        log/liblog.la \
        $(REPL_OBJS) \
        ${ADAPTATION_LIBS} \
@@ -2254,7 +2253,7 @@ nodist_tests_testURL_SOURCES = \
 tests_testURL_LDADD = \
        $(COMMON_LIBS) \
        icmp/libicmp.la icmp/libicmp-core.la \
-       comm/libcomm-listener.la \
+       comm/libcomm.la \
        log/liblog.la \
        $(REGEXLIB) \
        $(REPL_OBJS) \
index 49e7386c763cbcaa209d805c83a0d60eeb51c602..c25cf33044d4ed49488f66e4faa3325d80fee206 100644 (file)
 #ifndef   SQUID_PEERSELECTSTATE_H
 #define   SQUID_PEERSELECTSTATE_H
 
+#include "Array.h"
 #include "cbdata.h"
-#include "PingData.h"
+#include "comm/forward.h"
+#include "hier_code.h"
 #include "ip/Address.h"
+#include "PingData.h"
+
+class HttpRequest;
+class StoreEntry;
+
+typedef void PSC(Comm::Paths *, void *);
+
+SQUIDCEXTERN void peerSelect(Comm::Paths *, 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 @@ public:
     int direct;
     PSC *callback;
     void *callback_data;
-    FwdServer *servers;
+
+    Comm::Paths *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
@@ -74,5 +105,4 @@ private:
     CBDATA_CLASS(ps_state);
 };
 
-
 #endif /* SQUID_PEERSELECTSTATE_H */
index 9fc83837c34e9ed8ca578150bfab51b34f4f40b8..5e60b5c73638b2df0724c75d32c05c2960022a2b 100644 (file)
@@ -16,6 +16,7 @@
 #include "base/TextException.h"
 #include "ChunkedCodingParser.h"
 #include "comm.h"
+#include "comm/Connection.h"
 #include "HttpMsg.h"
 #include "HttpRequest.h"
 #include "HttpReply.h"
@@ -463,7 +464,7 @@ bool Adaptation::Icap::ModXact::doneAll() const
 
 void Adaptation::Icap::ModXact::startReading()
 {
-    Must(connection >= 0);
+    Must(haveConnection());
     Must(!reader);
     Must(!adapted.header);
     Must(!adapted.body_pipe);
@@ -621,7 +622,7 @@ void Adaptation::Icap::ModXact::bypassFailure()
     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())
@@ -1550,7 +1551,7 @@ void Adaptation::Icap::ModXact::fillPendingStatus(MemBuf &buf) const
     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)
index 6fbeb1fcc1896f95deb75f4d0897cdce0f6b461b..8f7d7bec402d70a85340681490612f7bda2ccbb1 100644 (file)
@@ -4,6 +4,8 @@
 
 #include "squid.h"
 #include "comm.h"
+#include "comm/Connection.h"
+#include "comm/ConnOpener.h"
 #include "CommCalls.h"
 #include "HttpMsg.h"
 #include "adaptation/icap/Xaction.h"
@@ -29,7 +31,7 @@ Adaptation::Icap::Xaction::Xaction(const char *aTypeName, Adaptation::Initiator
         icapRequest(NULL),
         icapReply(NULL),
         attempts(0),
-        connection(-1),
+        connection(NULL),
         theService(aService),
         commBuf(NULL), commBufSize(0),
         commEof(false),
@@ -89,23 +91,31 @@ 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);
+    connection->fd = icapPconnPool->pop(s.cfg().host.termedBuf(), s.cfg().port, NULL, client_addr, isRetriable);
+    if (connection->isOpen()) {
+        debugs(93,3, HERE << "reused pconn FD " << connection->fd);
 
         // fake the connect callback
         // TODO: can we sync call Adaptation::Icap::Xaction::noteCommConnected here instead?
         typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommConnectCbParams> Dialer;
         Dialer dialer(this, &Adaptation::Icap::Xaction::noteCommConnected);
-        dialer.params.fd = connection;
+        dialer.params.fd = connection->fd;
         dialer.params.flag = COMM_OK;
         // fake other parameters by copying from the existing connection
         connector = asyncCall(93,3, "Adaptation::Icap::Xaction::noteCommConnected", dialer);
@@ -115,32 +125,14 @@ void Adaptation::Icap::Xaction::openConnection()
 
     disableRetries(); // we only retry pconn failures
 
-    Ip::Address outgoing;
-    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<Adaptation::Icap::Xaction, CommTimeoutCbParams> TimeoutDialer;
-    AsyncCall::Pointer timeoutCall =  asyncCall(93, 5, "Adaptation::Icap::Xaction::noteCommTimedout",
-                                      TimeoutDialer(this,&Adaptation::Icap::Xaction::noteCommTimedout));
-
-    commSetTimeout(connection, TheConfig.connect_timeout(
-                       service().cfg().bypass), timeoutCall);
-
-    typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommCloseCbParams> CloseDialer;
-    closer =  asyncCall(93, 5, "Adaptation::Icap::Xaction::noteCommClosed",
-                        CloseDialer(this,&Adaptation::Icap::Xaction::noteCommClosed));
-    comm_add_close_handler(connection, closer);
-
     typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommConnectCbParams> ConnectDialer;
     connector = asyncCall(93,3, "Adaptation::Icap::Xaction::noteCommConnected",
                           ConnectDialer(this, &Adaptation::Icap::Xaction::noteCommConnected));
-    commConnectStart(connection, s.cfg().host.termedBuf(), s.cfg().port, connector);
+
+    ConnOpener *cs = new ConnOpener(connection, connector);
+    cs->setHost(s.cfg().host.termedBuf());
+    cs->connect_timeout = TheConfig.connect_timeout(service().cfg().bypass);
+    cs->start();
 }
 
 /*
@@ -159,10 +151,10 @@ Adaptation::Icap::Xaction::reusedConnection(void *data)
 
 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;
         }
 
@@ -179,34 +171,44 @@ void Adaptation::Icap::Xaction::closeConnection()
             //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(),
+            commSetTimeout(connection->fd, -1, call);
+            icapPconnPool->push(connection->fd, theService->cfg().host.termedBuf(),
                                 theService->cfg().port, NULL, client_addr);
             disableRetries();
+            connection->fd = -1; // prevent premature real closing.
         } 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 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<Adaptation::Icap::Xaction, CommCloseCbParams> 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();
 }
@@ -220,12 +222,14 @@ void Adaptation::Icap::Xaction::dieOnConnectionFailure()
 
 void Adaptation::Icap::Xaction::scheduleWrite(MemBuf &buf)
 {
+    Must(haveConnection());
+
     // comm module will free the buffer
     typedef CommCbMemFunT<Adaptation::Icap::Xaction, CommIoCbParams> Dialer;
     writer = asyncCall(93,3, "Adaptation::Icap::Xaction::noteCommWrote",
                        Dialer(this, &Adaptation::Icap::Xaction::noteCommWrote));
 
-    comm_write_mbuf(connection, &buf, writer);
+    comm_write_mbuf(connection->fd, &buf, writer);
     updateTimeout();
 }
 
@@ -299,6 +303,8 @@ bool Adaptation::Icap::Xaction::doneAll() const
 
 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?
@@ -307,19 +313,19 @@ void Adaptation::Icap::Xaction::updateTimeout()
         AsyncCall::Pointer call =  asyncCall(93, 5, "Adaptation::Icap::Xaction::noteCommTimedout",
                                              TimeoutDialer(this,&Adaptation::Icap::Xaction::noteCommTimedout));
 
-        commSetTimeout(connection,
+        commSetTimeout(connection->fd,
                        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);
+        commSetTimeout(connection->fd, -1, call);
     }
 }
 
 void Adaptation::Icap::Xaction::scheduleRead()
 {
-    Must(connection >= 0);
+    Must(haveConnection());
     Must(!reader);
     Must(readBuf.hasSpace());
 
@@ -331,7 +337,7 @@ void Adaptation::Icap::Xaction::scheduleRead()
     reader = asyncCall(93,3, "Adaptation::Icap::Xaction::noteCommRead",
                        Dialer(this, &Adaptation::Icap::Xaction::noteCommRead));
 
-    comm_read(connection, commBuf, readBuf.spaceSize(), reader);
+    comm_read(connection->fd, commBuf, readBuf.spaceSize(), reader);
     updateTimeout();
 }
 
@@ -369,7 +375,8 @@ void Adaptation::Icap::Xaction::noteCommRead(const CommIoCbParams &io)
 void Adaptation::Icap::Xaction::cancelRead()
 {
     if (reader != NULL) {
-        comm_read_cancel(connection, reader);
+        Must(haveConnection());
+        comm_read_cancel(connection->fd, reader);
         reader = NULL;
     }
 }
@@ -410,11 +417,16 @@ bool Adaptation::Icap::Xaction::doneWriting() const
 
 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()
 {
@@ -525,8 +537,8 @@ const char *Adaptation::Icap::Xaction::status() const
 
 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);
@@ -540,8 +552,8 @@ void Adaptation::Icap::Xaction::fillPendingStatus(MemBuf &buf) const
 
 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");
index 322991601996960953fca7bb92504dabdb7ecb07..988660b570310c72a813168707dee65baed636b2 100644 (file)
@@ -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"
@@ -99,6 +99,7 @@ protected:
     void openConnection();
     void closeConnection();
     void dieOnConnectionFailure();
+    bool haveConnection() const;
 
     void scheduleRead();
     void scheduleWrite(MemBuf &buf);
@@ -140,7 +141,7 @@ private:
     void maybeLog();
 
 protected:
-    int connection;     // FD of the ICAP server connection
+    Comm::ConnectionPointer connection;     ///< ICAP server connection
     Adaptation::Icap::ServiceRep::Pointer theService;
 
     /*
index 4dbdafd482d6cb9d9249480826cc808209d1feab..4ac7dbff1bc84221546798f60824282da70e25d1 100644 (file)
@@ -650,12 +650,9 @@ configDoConfigure(void)
     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);
@@ -2053,7 +2050,7 @@ parse_peer(peer ** head)
 
     p->icp.version = ICP_VERSION_CURRENT;
 
-    p->test_fd = -1;
+    p->testing_now = false;
 
 #if USE_CACHE_DIGESTS
 
index 090b000cbee8b9efdda211955b42a6abc71de517..837ddbeb764f1c7087b71afb8f0d2a45bffb4433 100644 (file)
@@ -2269,6 +2269,9 @@ LOC: Config.forward_max_tries
 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
@@ -6855,21 +6858,24 @@ DOC_START
        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).
+       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.
 
-       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.
+       A warning message will be generated if it is set to a too-high
+       value and the configured value will be over-ridden.
 
-       Note: This is in addition to the request re-forwarding which
-       takes place if Squid fails to get a satisfying response.
+       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
index ba03e748f09083a591b8f3a63d0f79408239ae9e..b01e699ba47926ad3482f26f34a90cc74d426c1d 100644 (file)
@@ -85,6 +85,7 @@
 
 #include "acl/FilledChecklist.h"
 #include "auth/UserRequest.h"
+#include "base/TextException.h"
 #include "ChunkedCodingParser.h"
 #include "client_side.h"
 #include "client_side_reply.h"
@@ -92,9 +93,8 @@
 #include "ClientRequestContext.h"
 #include "clientStream.h"
 #include "comm.h"
+#include "comm/Connection.h"
 #include "comm/ListenStateData.h"
-#include "base/TextException.h"
-#include "ConnectionDetail.h"
 #include "eui/Config.h"
 #include "fde.h"
 #include "HttpHdrContRange.h"
@@ -3085,7 +3085,7 @@ connStateCreate(const Ip::Address &peer, const Ip::Address &me, int fd, http_por
 
 /** Handle a new connection on HTTP socket. */
 void
-httpAccept(int sock, int newfd, ConnectionDetail *details,
+httpAccept(int sock, int newfd, Comm::ConnectionPointer &details,
            comm_err_t flag, int xerrno, void *data)
 {
     http_port_list *s = (http_port_list *)data;
@@ -3098,7 +3098,7 @@ httpAccept(int sock, int newfd, ConnectionDetail *details,
 
     debugs(33, 4, "httpAccept: FD " << newfd << ": accepted");
     fd_note(newfd, "client http connect");
-    connState = connStateCreate(&details->peer, &details->me, newfd, s);
+    connState = connStateCreate(&details->remote, &details->local, newfd, s);
 
     typedef CommCbMemFunT<ConnStateData, CommCloseCbParams> Dialer;
     AsyncCall::Pointer call = asyncCall(33, 5, "ConnStateData::connStateClosed",
@@ -3106,7 +3106,7 @@ httpAccept(int sock, int newfd, ConnectionDetail *details,
     comm_add_close_handler(newfd, call);
 
     if (Config.onoff.log_fqdn)
-        fqdncache_gethostbyaddr(details->peer, FQDN_LOOKUP_IF_MISS);
+        fqdncache_gethostbyaddr(details->remote, FQDN_LOOKUP_IF_MISS);
 
     typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
     AsyncCall::Pointer timeoutCall =  asyncCall(33, 5, "ConnStateData::requestTimeout",
@@ -3116,19 +3116,19 @@ httpAccept(int sock, int newfd, ConnectionDetail *details,
 #if USE_IDENT
     if (Ident::TheConfig.identLookup) {
         ACLFilledChecklist identChecklist(Ident::TheConfig.identLookup, NULL, NULL);
-        identChecklist.src_addr = details->peer;
-        identChecklist.my_addr = details->me;
+        identChecklist.src_addr = details->remote;
+        identChecklist.my_addr = details->local;
         if (identChecklist.fastCheck())
-            Ident::Start(details->me, details->peer, clientIdentDone, connState);
+            Ident::Start(details, 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);
+        if (details->remote.IsIPv4()) {
+            connState->peer_eui48.lookup(details->remote);
+        } else if (details->remote.IsIPv6()) {
+            connState->peer_eui64.lookup(details->remote);
         }
     }
 #endif
@@ -3139,7 +3139,7 @@ httpAccept(int sock, int newfd, ConnectionDetail *details,
 
     connState->readSomeData();
 
-    clientdbEstablished(details->peer, 1);
+    clientdbEstablished(details->remote, 1);
 
     incoming_sockets_accepted++;
 }
@@ -3148,7 +3148,7 @@ httpAccept(int sock, int newfd, ConnectionDetail *details,
 
 /** Create SSL connection structure and update fd_table */
 static SSL *
-httpsCreate(int newfd, ConnectionDetail *details, SSL_CTX *sslContext)
+httpsCreate(int newfd, Comm::ConnectionPointer details, SSL_CTX *sslContext)
 {
     SSL *ssl = SSL_new(sslContext);
 
@@ -3291,7 +3291,7 @@ clientNegotiateSSL(int fd, void *data)
 
 /** handle a new HTTPS connection */
 static void
-httpsAccept(int sock, int newfd, ConnectionDetail *details,
+httpsAccept(int sock, int newfd, Comm::ConnectionPointer details,
             comm_err_t flag, int xerrno, void *data)
 {
     https_port_list *s = (https_port_list *)data;
@@ -3309,7 +3309,7 @@ httpsAccept(int sock, int newfd, ConnectionDetail *details,
 
     debugs(33, 5, "httpsAccept: FD " << newfd << " accepted, starting SSL negotiation.");
     fd_note(newfd, "client https connect");
-    ConnStateData *connState = connStateCreate(details->peer, details->me,
+    ConnStateData *connState = connStateCreate(details->remote, details->local,
                                newfd, &s->http);
     typedef CommCbMemFunT<ConnStateData, CommCloseCbParams> Dialer;
     AsyncCall::Pointer call = asyncCall(33, 5, "ConnStateData::connStateClosed",
@@ -3317,7 +3317,7 @@ httpsAccept(int sock, int newfd, ConnectionDetail *details,
     comm_add_close_handler(newfd, call);
 
     if (Config.onoff.log_fqdn)
-        fqdncache_gethostbyaddr(details->peer, FQDN_LOOKUP_IF_MISS);
+        fqdncache_gethostbyaddr(details->remote, FQDN_LOOKUP_IF_MISS);
 
     typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
     AsyncCall::Pointer timeoutCall =  asyncCall(33, 5, "ConnStateData::requestTimeout",
@@ -3327,10 +3327,10 @@ httpsAccept(int sock, int newfd, ConnectionDetail *details,
 #if USE_IDENT
     if (Ident::TheConfig.identLookup) {
         ACLFilledChecklist identChecklist(Ident::TheConfig.identLookup, NULL, NULL);
-        identChecklist.src_addr = details->peer;
-        identChecklist.my_addr = details->me;
+        identChecklist.src_addr = details->remote;
+        identChecklist.my_addr = details->local;
         if (identChecklist.fastCheck())
-            Ident::Start(details->me, details->peer, clientIdentDone, connState);
+            Ident::Start(details, clientIdentDone, connState);
     }
 #endif
 
@@ -3340,7 +3340,7 @@ httpsAccept(int sock, int newfd, ConnectionDetail *details,
 
     commSetSelect(newfd, COMM_SELECT_READ, clientNegotiateSSL, connState, 0);
 
-    clientdbEstablished(details->peer, 1);
+    clientdbEstablished(details->remote, 1);
 
     incoming_sockets_accepted++;
 }
@@ -3357,10 +3357,10 @@ ConnStateData::switchToHttps()
 
     debugs(33, 5, HERE << "converting FD " << fd << " to SSL");
 
-    // fake a ConnectionDetail object; XXX: make ConnState a ConnectionDetail?
-    ConnectionDetail detail;
-    detail.me = me;
-    detail.peer = peer;
+    // fake a Comm::Connection object; XXX: make ConnState a Comm::Connection?
+    Comm::Connection detail;
+    detail.local = me;
+    detail.remote = peer;
 
     SSL_CTX *sslContext = port->sslContext;
     SSL *ssl = NULL;
index 32aafc9f67e6fa1d61720b598a9ebc4712c1a860..dbeee9bd3fbbe99633a0ec70e3c6b555050b12e1 100644 (file)
@@ -124,8 +124,6 @@ private:
 };
 
 
-class ConnectionDetail;
-
 /** A connection to a socket */
 class ConnStateData : public BodyProducer/*, public RefCountable*/
 {
index a32a71ebbc1b5b46b928125c055695d925004e09..5e3dbc73d097742ca8028d90d8f104f479f2f02c 100644 (file)
@@ -541,7 +541,7 @@ ClientRequestContext::clientAccessCheck2()
         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);
     }
 }
index 6330270bbd1055b60c0a6b53011d1ffa467f7f79..f3fde6ab78898b865154c44925ea8e03b4e089f0 100644 (file)
  */
 
 #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/ListenStateData.h"
 #include "CommIO.h"
 #include "CommRead.h"
-#include "ConnectionDetail.h"
 #include "MemBuf.h"
 #include "pconn.h"
 #include "SquidTime.h"
@@ -197,38 +198,6 @@ commio_call_callback(comm_io_callback_t *ccb)
 {
 }
 
-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
@@ -243,7 +212,6 @@ static void commSetNoLinger(int);
 static void commSetTcpNoDelay(int);
 #endif
 static void commSetTcpRcvbuf(int, int);
-static PF commConnectFree;
 static PF commHandleWrite;
 static IPH commConnectDnsHandle;
 
@@ -896,111 +864,6 @@ comm_import_opened(int fd,
      */
 }
 
-
-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 &params = GetCommParams<Params>(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)
 {
@@ -1021,198 +884,6 @@ copyFDFlags(int to, fde *F)
         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;
-    }
-    commResetSelect(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->tos)
-        comm_set_tos(fd, F->tos);
-
-#if IPV6_SPECIAL_SPLITSTACK
-    if ( F->local_addr.IsIPv6() )
-        comm_set_v6only(fd, 1);
-#endif
-
-    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");
-        commSetSelect(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)
@@ -1254,7 +925,8 @@ commSetTimeout(int fd, int timeout, PF * handler, void *data)
 }
 
 
-int commSetTimeout(int fd, int timeout, AsyncCall::Pointer &callback)
+int
+commSetTimeout(int fd, int timeout, AsyncCall::Pointer &callback)
 {
     debugs(5, 3, HERE << "FD " << fd << " timeout " << timeout);
     assert(fd >= 0);
@@ -2457,10 +2129,6 @@ DeferredRead::markCancelled()
     cancelled = true;
 }
 
-ConnectionDetail::ConnectionDetail() : me(), peer()
-{
-}
-
 int
 CommSelectEngine::checkEvents(int timeout)
 {
index 5db4996a4025d202907aa2374c60dbe15ee7e992..ffc7fd33d4749d48ae58bd737173e5c9868ee0e5 100644 (file)
@@ -4,33 +4,15 @@
 #include "squid.h"
 #include "AsyncEngine.h"
 #include "base/AsyncCall.h"
-#include "StoreIOBuffer.h"
-#include "Array.h"
+#include "CommCalls.h"
+#include "comm/comm_err_t.h"
+#include "comm/forward.h"
 #include "ip/Address.h"
+#include "StoreIOBuffer.h"
 
 #define COMMIO_FD_READCB(fd)    (&commfd_table[(fd)].readcb)
 #define COMMIO_FD_WRITECB(fd)   (&commfd_table[(fd)].writecb)
 
-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;
-
-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 */
@@ -40,13 +22,11 @@ SQUIDCEXTERN int commUnsetNonBlocking(int fd);
 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__))
+#define comm_close(x) (_comm_close((x), __FILE__, __LINE__))
 SQUIDCEXTERN void comm_reset_close(int fd);
 #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);
@@ -101,8 +81,7 @@ SQUIDCEXTERN void comm_select_init(void);
 SQUIDCEXTERN comm_err_t comm_select(int);
 SQUIDCEXTERN void comm_quick_poll_required(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 *);
diff --git a/src/comm/ConnOpener.cc b/src/comm/ConnOpener.cc
new file mode 100644 (file)
index 0000000..62b82e6
--- /dev/null
@@ -0,0 +1,186 @@
+#include "config.h"
+#include "comm/ConnOpener.h"
+#include "comm/Connection.h"
+#include "comm.h"
+#include "CommCalls.h"
+#include "fde.h"
+#include "icmp/net_db.h"
+#include "SquidTime.h"
+
+CBDATA_CLASS_INIT(ConnOpener);
+
+ConnOpener::ConnOpener(Comm::ConnectionPointer &c, AsyncCall::Pointer handler) :
+        AsyncJob("ConnOpener"),
+        connect_timeout(Config.Timeout.connect),
+        host(NULL),
+        solo(c),
+        callback(handler),
+        total_tries(0),
+        fail_retries(0),
+        connstart(0)
+{}
+
+ConnOpener::~ConnOpener()
+{
+    safe_free(host);
+    solo = NULL;
+}
+
+void
+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 *
+ConnOpener::getHost() const
+{
+    return host;
+}
+
+void
+ConnOpener::callCallback(comm_err_t status, int xerrno)
+{
+    /* remove handlers we don't want to happen now */
+    comm_remove_close_handler(solo->fd, ConnOpener::EarlyAbort, this);
+    commSetTimeout(solo->fd, -1, NULL, NULL);
+
+    typedef CommConnectCbParams Params;
+    Params &params = GetCommParams<Params>(callback);
+    params.conn = solo;
+    params.flag = status;
+    params.xerrno = xerrno;
+    ScheduleCallHere(callback);
+
+    callback = NULL;
+    delete this;
+}
+
+void
+ConnOpener::start()
+{
+    /* handle connecting to one single path */
+    if (solo->fd < 0) {
+#if USE_IPV6
+        /* outbound sockets have no need to be protocol agnostic. */
+        if (solo->local.IsIPv6() && solo->local.IsIPv4()) {
+            solo->local.SetIPv4();
+        }
+#endif
+        solo->fd = comm_openex(SOCK_STREAM, IPPROTO_TCP, solo->local, solo->flags, solo->tos, host);
+        if (solo->fd <= 0) {
+            callCallback(COMM_ERR_CONNECT, 0);
+            return;
+        }
+
+        AsyncCall::Pointer ea_call = commCbCall(5,4, "ConnOpener::EarlyAbort",
+                                                CommCloseCbPtrFun(ConnOpener::EarlyAbort, this));
+        comm_add_close_handler(solo->fd, ea_call);
+
+        AsyncCall::Pointer timeout_call = commCbCall(5,4, "ConnOpener::ConnectTimeout",
+                                                     CommTimeoutCbPtrFun(ConnOpener::ConnectTimeout, this));
+        debugs(5, 3, HERE << "FD " << solo->fd << " timeout " << connect_timeout);
+        commSetTimeout(solo->fd, connect_timeout, timeout_call);
+
+        if (connstart == 0) {
+            connstart = squid_curtime;
+        }
+    }
+
+    total_tries++;
+
+    switch (comm_connect_addr(solo->fd, solo->remote) ) {
+
+    case COMM_INPROGRESS:
+        debugs(5, 5, HERE << "FD " << solo->fd << ": COMM_INPROGRESS");
+        commSetSelect(solo->fd, COMM_SELECT_WRITE, ConnOpener::ConnectRetry, this, 0);
+        break;
+
+    case COMM_OK:
+        debugs(5, 5, HERE << "FD " << solo->fd << ": COMM_OK - 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 (solo->getPeer())
+            solo->getPeer()->stats.conn_open++;
+
+        /* 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.
+         */
+        fd_table[solo->fd].flags.open = 1;
+        solo->local.SetPort(comm_local_port(solo->fd));
+
+        if (host != NULL)
+            ipcacheMarkGoodAddr(host, solo->remote);
+        callCallback(COMM_OK, 0);
+        break;
+
+    default:
+        debugs(5, 5, HERE "FD " << solo->fd << ": * - try again");
+        fail_retries++;
+        if (host != NULL)
+            ipcacheMarkBadAddr(host, solo->remote);
+#if USE_ICMP
+        if (Config.onoff.test_reachability)
+            netdbDeleteAddrNetwork(solo->remote);
+#endif
+
+        // check for timeout FIRST.
+        if(squid_curtime - connstart > connect_timeout) {
+            debugs(5, 5, HERE << "FD " << solo->fd << ": * - ERR took too long already.");
+            callCallback(COMM_TIMEOUT, errno);
+        } else if (fail_retries < Config.connect_retries) {
+            start();
+        } else {
+            // send ERROR back to the upper layer.
+            debugs(5, 5, HERE << "FD " << solo->fd << ": * - ERR tried too many times already.");
+            callCallback(COMM_ERR_CONNECT, errno);
+        }
+    }
+}
+
+void
+ConnOpener::EarlyAbort(int fd, void *data)
+{
+    ConnOpener *cs = static_cast<ConnOpener *>(data);
+    debugs(5, 3, HERE << "FD " << fd);
+    cs->callCallback(COMM_ERR_CLOSING, errno); // NP: is closing or shutdown better?
+
+    /* TODO split cases:
+     * remote end rejecting the connection is normal and one of the other paths may be taken.
+     * squid shutting down or forcing abort on the connection attempt(s) are the only real fatal cases.
+     * we may need separate error codes to send back for these two.
+     */
+}
+
+void
+ConnOpener::Connect(void *data)
+{
+    ConnOpener *cs = static_cast<ConnOpener *>(data);
+    cs->start();
+}
+
+void
+ConnOpener::ConnectRetry(int fd, void *data)
+{
+    ConnOpener *cs = static_cast<ConnOpener *>(data);
+    cs->start();
+}
+
+void
+ConnOpener::ConnectTimeout(int fd, void *data)
+{
+    ConnOpener *cs = static_cast<ConnOpener *>(data);
+    cs->start();
+}
+
diff --git a/src/comm/ConnOpener.h b/src/comm/ConnOpener.h
new file mode 100644 (file)
index 0000000..9c4e2a6
--- /dev/null
@@ -0,0 +1,79 @@
+#ifndef _SQUID_SRC_COMM_OPENERSTATEDATA_H
+#define _SQUID_SRC_COMM_OPENERSTATEDATA_H
+
+#include "base/AsyncCall.h"
+#include "base/AsyncJob.h"
+#include "cbdata.h"
+#include "comm/comm_err_t.h"
+#include "comm/forward.h"
+
+/**
+ * Async-opener of a Comm connection.
+ */
+class ConnOpener : public AsyncJob
+{
+public:
+    /** attempt to open a connection. */
+    ConnOpener(Comm::ConnectionPointer &, AsyncCall::Pointer handler);
+
+    ~ConnOpener();
+
+    /** Actual start opening a TCP connection. */
+    void start();
+
+private:
+    /* These objects may NOT be created without connections to act on. Do not define this operator. */
+    ConnOpener(const ConnOpener &);
+    /* These objects may NOT be copied. Do not define this operator. */
+    ConnOpener operator =(const ConnOpener &c);
+
+    /**
+     * Wrapper to start the connection attempts happening.
+     */
+    static void Connect(void *data);
+
+    /** retry */
+    static void ConnectRetry(int fd, void *data);
+
+    /**
+     * Temporary close handler used during connect.
+     * Handles the case(s) when a partially setup connection gets closed early.
+     */
+    static void EarlyAbort(int fd, void *data);
+
+    /**
+     * Temporary timeout handler used during connect.
+     * Handles the case(s) when a partially setup connection gets timed out.
+     */
+    static void ConnectTimeout(int fd, void *data);
+
+    /**
+     * Connection attempt are completed. One way or the other.
+     * Pass the results back to the external handler.
+     */
+    void callCallback(comm_err_t status, int xerrno);
+
+public:
+    /**
+     * time at which to abandon the connection.
+     * the connection-done callback will be passed COMM_TIMEOUT
+     */
+    time_t connect_timeout;
+
+    void setHost(const char *);        ///< set the hostname note for this connection
+    const char * getHost(void) const;  ///< get the hostname noted for this connection
+
+private:
+    char *host;                         ///< domain name we are trying to connect to.
+
+    Comm::ConnectionPointer solo;       ///< single connection currently being opened.
+    AsyncCall::Pointer callback;        ///< handler to be called on connection completion.
+
+    int total_tries;   ///< total number of connection attempts over all destinations so far.
+    int fail_retries;  ///< number of retries current destination has been tried.
+    time_t connstart;  ///< time at which this series of connection attempts was started.
+
+    CBDATA_CLASS2(ConnOpener);
+};
+
+#endif /* _SQUID_SRC_COMM_CONNOPENER_H */
diff --git a/src/comm/Connection.cc b/src/comm/Connection.cc
new file mode 100644 (file)
index 0000000..1a64c0d
--- /dev/null
@@ -0,0 +1,69 @@
+#include "config.h"
+#include "cbdata.h"
+#include "comm.h"
+#include "comm/Connection.h"
+
+Comm::Connection::Connection() :
+        local(),
+        remote(),
+        peer_type(HIER_NONE),
+        fd(-1),
+        tos(0),
+        flags(COMM_NONBLOCKING),
+        _peer(NULL)
+{}
+
+Comm::Connection::~Connection()
+{
+    close();
+    if (_peer) {
+        cbdataReferenceDone(_peer);
+    }
+}
+
+Comm::ConnectionPointer &
+Comm::Connection::copyDetails() const
+{
+    ConnectionPointer c = new Comm::Connection;
+
+    c->local = local;
+    c->remote = remote;
+    c->peer_type = peer_type;
+    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(_peer);
+
+    return c;
+}
+
+void
+Comm::Connection::close()
+{
+    if (isOpen())
+        comm_close(fd);
+    fd = -1;
+}
+
+void
+Comm::Connection::setPeer(peer *p)
+{
+    /* set to self. nothing to do. */
+    if (_peer == p)
+        return;
+
+    /* clear any previous ptr */
+    if (_peer) {
+        cbdataReferenceDone(_peer);
+        _peer = NULL;
+    }
+
+   /* set the new one (unless it is NULL */
+   if (p) {
+        _peer = cbdataReference(p);
+   }
+}
diff --git a/src/comm/Connection.h b/src/comm/Connection.h
new file mode 100644 (file)
index 0000000..3f79d1d
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * DEBUG: section 05    Socket Functions
+ * AUTHOR: Amos Jeffries
+ * AUTHOR: Robert Collins
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ *
+ * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
+ * Copyright (c) 2010, Amos Jeffries <amosjeffries@squid-cache.org>
+ */
+
+#ifndef _SQUIDCONNECTIONDETAIL_H_
+#define _SQUIDCONNECTIONDETAIL_H_
+
+#include "hier_code.h"
+#include "ip/Address.h"
+#include "RefCount.h"
+
+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
+#define COMM_NOCLOEXEC          0x02
+#define COMM_REUSEADDR          0x04
+#define COMM_TRANSPARENT        0x08
+#define COMM_DOBIND             0x10
+
+/**
+ * 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:
+    /** standard empty connection creation */
+    Connection();
+
+    /** These objects may not be exactly duplicated. Use copyDetails() instead. */
+    Connection(const Connection &c);
+
+    /** 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;
+
+    /** These objects may not be exactly duplicated. Use clone() instead. */
+    Connection & operator =(const Connection &c);
+
+    /** Close any open socket. */
+    void close();
+
+    /** determine whether this object describes an active connection or not. */
+    bool isOpen() const { return (fd >= 0); }
+
+    /** 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 peer_type;
+
+    /** Socket used by this connection. -1 if no socket has been opened. */
+    int fd;
+
+    /** Quality of Service TOS values currently sent on this connection */
+    int tos;
+
+    /** COMM flags set on this connection */
+    int flags;
+
+    /** 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 { return _peer; }
+
+    /** alter the stored peer pointer.
+     * Perform appropriate CBDATA operations for locking the peer pointer
+     */
+    void setPeer(peer * p);
+
+private:
+    /** cache_peer data object (if any) */
+    peer *_peer;
+};
+
+}; // namespace Comm
+
+#endif
index 4e5a304831b5c74806dde63863c3f5ada73f5b95..ce3faef69400973344fcf0b1fb5c8fa856da13e3 100644 (file)
@@ -35,9 +35,9 @@
 #include "squid.h"
 #include "CommCalls.h"
 #include "comm/AcceptLimiter.h"
+#include "comm/Connection.h"
 #include "comm/comm_internal.h"
 #include "comm/ListenStateData.h"
-#include "ConnectionDetail.h"
 #include "fde.h"
 #include "protos.h"
 #include "SquidTime.h"
@@ -151,8 +151,8 @@ Comm::ListenStateData::acceptOne()
      */
 
     /* Accept a new connection */
-    ConnectionDetail connDetails;
-    int newfd = oldAccept(connDetails);
+    Connection *connDetails = new Connection();
+    int newfd = oldAccept(*connDetails);
 
     /* Check for errors */
     if (newfd < 0) {
@@ -172,7 +172,7 @@ Comm::ListenStateData::acceptOne()
     }
 
     debugs(5, 5, HERE << "accepted: FD " << fd <<
-           " newfd: " << newfd << " from: " << connDetails.peer <<
+           " newfd: " << newfd << " from: " << connDetails->remote <<
            " handler: " << theCallback);
     notify(newfd, COMM_OK, 0, connDetails);
 }
@@ -186,7 +186,7 @@ Comm::ListenStateData::acceptNext()
 }
 
 void
-Comm::ListenStateData::notify(int newfd, comm_err_t errcode, int xerrno, const ConnectionDetail &connDetails)
+Comm::ListenStateData::notify(int newfd, comm_err_t errcode, int xerrno, Comm::ConnectionPointer connDetails)
 {
     // listener socket handlers just abandon the port with COMM_ERR_CLOSING
     // it should only happen when this object is deleted...
@@ -213,17 +213,17 @@ Comm::ListenStateData::notify(int newfd, comm_err_t errcode, int xerrno, const C
  * Wait for an incoming connection on FD.
  */
 int
-Comm::ListenStateData::oldAccept(ConnectionDetail &details)
+Comm::ListenStateData::oldAccept(Comm::Connection &details)
 {
     PROF_start(comm_accept);
     statCounter.syscalls.sock.accepts++;
     int sock;
     struct addrinfo *gai = NULL;
-    details.me.InitAddrInfo(gai);
+    details.local.InitAddrInfo(gai);
 
     if ((sock = accept(fd, gai->ai_addr, &gai->ai_addrlen)) < 0) {
 
-        details.me.FreeAddrInfo(gai);
+        details.local.FreeAddrInfo(gai);
 
         PROF_stop(comm_accept);
 
@@ -239,21 +239,21 @@ Comm::ListenStateData::oldAccept(ConnectionDetail &details)
         }
     }
 
-    details.peer = *gai;
+    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;
         }
     }
 
-    details.me.InitAddrInfo(gai);
+    details.local.InitAddrInfo(gai);
 
-    details.me.SetEmpty();
+    details.local.SetEmpty();
     getsockname(sock, gai->ai_addr, &gai->ai_addrlen);
-    details.me = *gai;
+    details.local = *gai;
 
     commSetCloseOnExec(sock);
 
@@ -264,15 +264,15 @@ Comm::ListenStateData::oldAccept(ConnectionDetail &details)
     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.SetPort(details.me.GetPort());
+    details.remote.NtoA(F->ipaddr,MAX_IPSTRLEN);
+    F->remote_port = details.remote.GetPort();
+    F->local_addr.SetPort(details.local.GetPort());
 #if USE_IPV6
     F->sock_family = AF_INET;
 #else
-    F->sock_family = details.me.IsIPv4()?AF_INET:AF_INET6;
+    F->sock_family = details.local.IsIPv4()?AF_INET:AF_INET6;
 #endif
-    details.me.FreeAddrInfo(gai);
+    details.local.FreeAddrInfo(gai);
 
     commSetNonBlocking(sock);
 
index 66ed358786c465fe090d8c2c6912cdc19a4bd706..4b1dda706e8dfdfe2e8830684ac884dcc9d15aa4 100644 (file)
@@ -3,16 +3,18 @@
 
 #include "config.h"
 #include "base/AsyncCall.h"
-#include "comm.h"
+#include "comm/comm_err_t.h"
+#include "comm/forward.h"
+
 #if HAVE_MAP
 #include <map>
 #endif
 
-class ConnectionDetail;
-
 namespace Comm
 {
 
+class Connection;
+
 class ListenStateData
 {
 
@@ -23,7 +25,7 @@ public:
 
     void subscribe(AsyncCall::Pointer &call);
     void acceptNext();
-    void notify(int newfd, comm_err_t, int xerrno, const ConnectionDetail &);
+    void notify(int newfd, comm_err_t, int xerrno, Comm::ConnectionPointer);
 
     int fd;
 
@@ -42,7 +44,7 @@ private:
     static void doAccept(int fd, void *data);
 
     void acceptOne();
-    int oldAccept(ConnectionDetail &details);
+    int oldAccept(Comm::Connection &details);
 
     AsyncCall::Pointer theCallback;
     bool mayAcceptMore;
index 09cb1c107644c513b7bae3c7973666af0895a6a1..beb2111218a93616199220cdd4f2747fe99e7e96 100644 (file)
@@ -1,13 +1,22 @@
 include $(top_srcdir)/src/Common.am
 include $(top_srcdir)/src/TestHeaders.am
 
-noinst_LTLIBRARIES = libcomm-listener.la
+noinst_LTLIBRARIES = libcomm.la
 
-## Library holding listener comm socket handlers
-libcomm_listener_la_SOURCES= \
+## First group are listener comm socket handlers
+## Second group are outbound connection setup handlers
+## Third group are misc shared comm objects
+libcomm_la_SOURCES= \
        AcceptLimiter.cc \
        AcceptLimiter.h \
        ListenStateData.cc \
        ListenStateData.h \
        \
-       comm_internal.h
+       ConnOpener.cc \
+       ConnOpener.h \
+       \
+       Connection.cc \
+       Connection.h \
+       comm_err_t.h \
+       comm_internal.h \
+       forward.h
diff --git a/src/comm/comm_err_t.h b/src/comm/comm_err_t.h
new file mode 100644 (file)
index 0000000..1cad2a3
--- /dev/null
@@ -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 */
diff --git a/src/comm/forward.h b/src/comm/forward.h
new file mode 100644 (file)
index 0000000..5f0c8a7
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _SQUID_COMM_FORWARD_H
+#define _SQUID_COMM_FORWARD_H
+
+#include "Array.h"
+#include "RefCount.h"
+
+namespace Comm {
+
+class Connection;
+
+typedef RefCount<Comm::Connection> ConnectionPointer;
+
+typedef Vector<Comm::ConnectionPointer> Paths;
+
+}; // namespace Comm
+
+#endif /* _SQUID_COMM_FORWARD_H */
index a6ac3eeaecdb0f213ebe7b497392e5caa702cc69..b6725511effc0c2efa22597a30e38161f8ed9410 100644 (file)
 #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 safe_free(x)   if (x) { xxfree(x); x = NULL; }
 
 #define DISK_OK                   (0)
index c39611c0196f3475910a9154e20042b31323add7..92f677c3c0c8ffc93e4a4d47b4b2ccb0d0e704b5 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * $Id$
  *
  *
  */
 
-#include "config.h"
 #include "squid.h"
-#include "event.h"
 #include "CacheManager.h"
-#include "SquidTime.h"
-#include "Store.h"
+#include "comm/Connection.h"
+#include "comm/ConnOpener.h"
 #include "comm.h"
+#include "event.h"
 #include "fde.h"
 #include "MemBuf.h"
-
+#include "SquidTime.h"
+#include "Store.h"
 #include "wordlist.h"
 
 #if HAVE_ARPA_NAMESER_H
@@ -176,6 +175,7 @@ static void idnsParseWIN32SearchList(const char *);
 #endif
 static void idnsCacheQuery(idns_query * q);
 static void idnsSendQuery(idns_query * q);
+static CNCB idnsInitVCConnected;
 static IOCB idnsReadVCHeader;
 static void idnsDoSendQueryVC(nsvc *vc);
 
@@ -186,6 +186,7 @@ static PF idnsRead;
 static EVH idnsCheckQueue;
 static void idnsTickleQueue(void);
 static void idnsRcodeCount(int, int);
+static void idnsVCClosed(int fd, void *data);
 
 static void
 idnsAddNameserver(const char *buf)
@@ -698,18 +699,21 @@ idnsDoSendQueryVC(nsvc *vc)
 }
 
 static void
-idnsInitVCConnected(int fd, const DnsLookupDetails &, comm_err_t status, int xerrno, void *data)
+idnsInitVCConnected(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];
-        debugs(78, 1, "idnsInitVCConnected: Failed to connect to nameserver " << nameservers[vc->ns].S.NtoA(buf,MAX_IPSTRLEN) << " using TCP!");
-        comm_close(fd);
+        debugs(78, DBG_IMPORTANT, "Failed to connect to nameserver " << nameservers[vc->ns].S.NtoA(buf,MAX_IPSTRLEN) << " using TCP!");
+        conn = NULL;
         return;
     }
 
-    comm_read(fd, (char *)&vc->msglen, 2 , idnsReadVCHeader, vc);
+    vc->fd = conn->fd; // TODO: make the vc store the conn instead?
+
+    comm_add_close_handler(conn->fd, idnsVCClosed, vc);
+    comm_read(conn->fd, (char *)&vc->msglen, 2 , idnsReadVCHeader, vc);
     vc->busy = 0;
     idnsDoSendQueryVC(vc);
 }
@@ -727,37 +731,27 @@ idnsVCClosed(int fd, void *data)
 static void
 idnsInitVC(int ns)
 {
-    char buf[MAX_IPSTRLEN];
-
     nsvc *vc = cbdataAlloc(nsvc);
     nameservers[ns].vc = vc;
     vc->ns = ns;
-
-    Ip::Address addr;
-
-    if (!Config.Addrs.udp_outgoing.IsNoAddr())
-        addr = Config.Addrs.udp_outgoing;
-    else
-        addr = Config.Addrs.udp_incoming;
-
     vc->queue = new MemBuf;
-
     vc->msg = new MemBuf;
+    vc->busy = 1;
 
-    vc->fd = comm_open(SOCK_STREAM,
-                       IPPROTO_TCP,
-                       addr,
-                       COMM_NONBLOCKING,
-                       "DNS TCP Socket");
+    Comm::ConnectionPointer conn = new Comm::Connection;
 
-    if (vc->fd < 0)
-        fatal("Could not create a DNS socket");
+    if (!Config.Addrs.udp_outgoing.IsNoAddr())
+        conn->local = Config.Addrs.udp_outgoing;
+    else
+        conn->local = Config.Addrs.udp_incoming;
 
-    comm_add_close_handler(vc->fd, idnsVCClosed, vc);
+    conn->remote = nameservers[ns].S;
 
-    vc->busy = 1;
+    AsyncCall::Pointer call = commCbCall(78,3, "idnsInitVCConnected", CommConnectCbPtrFun(idnsInitVCConnected, vc));
 
-    commConnectStart(vc->fd, nameservers[ns].S.NtoA(buf,MAX_IPSTRLEN), nameservers[ns].S.GetPort(), idnsInitVCConnected, vc);
+    ConnOpener *cs = new ConnOpener(conn, call);
+    cs->setHost("DNS TCP Socket");
+    cs->start();
 }
 
 static void
index fcc5d009f4b462e6967816aef6a81cdfa20187d7..7e531a420a0934aec2dccb68e63ffa4f1c0cf164 100644 (file)
 
 
 #include "squid.h"
-#include "forward.h"
 #include "acl/FilledChecklist.h"
 #include "acl/Gadgets.h"
 #include "CacheManager.h"
+#include "comm/Connection.h"
+#include "comm/ConnOpener.h"
+#include "CommCalls.h"
 #include "event.h"
 #include "errorpage.h"
 #include "fde.h"
+#include "forward.h"
 #include "hier_code.h"
 #include "HttpReply.h"
 #include "HttpRequest.h"
 #include "MemObject.h"
 #include "pconn.h"
+#include "PeerSelectState.h"
 #include "SquidTime.h"
 #include "Store.h"
 #include "icmp/net_db.h"
 #include "ip/Intercept.h"
 
+
 static PSC fwdStartCompleteWrapper;
 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];
@@ -78,11 +80,7 @@ FwdState::abort(void* d)
     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;
-    }
-
+    fwd->paths[0]->close();
     fwd->self = NULL;
 }
 
@@ -92,7 +90,6 @@ FwdState::FwdState(int fd, StoreEntry * e, HttpRequest * r)
 {
     entry = e;
     client_fd = fd;
-    server_fd = -1;
     request = HTTPMSGLOCK(r);
     start_t = squid_curtime;
 
@@ -113,10 +110,7 @@ void FwdState::start(Pointer aSelf)
     // 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(&paths, request, entry, fwdStartCompleteWrapper, this);
 }
 
 void
@@ -162,8 +156,6 @@ FwdState::~FwdState()
     if (! flags.forward_completed)
         completed();
 
-    serversFree(&servers);
-
     HTTPMSGUNLOCK(request);
 
     if (err)
@@ -175,15 +167,14 @@ FwdState::~FwdState()
 
     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 (paths[0]->fd > -1) {
+        comm_remove_close_handler(paths[0]->fd, fwdServerClosedWrapper, this);
+        debugs(17, 3, HERE << "closing FD " << paths[0]->fd);
+        paths[0]->close();
     }
 
+    paths.clean();
+
     debugs(17, 3, HERE << "FwdState destructor done");
 }
 
@@ -226,7 +217,7 @@ FwdState::fwdStart(int client_fd, StoreEntry *entry, HttpRequest *request)
         }
     }
 
-    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
@@ -260,13 +251,6 @@ FwdState::fwdStart(int client_fd, StoreEntry *entry, HttpRequest *request)
 
     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;
-        }
-
         fwd->start(fwd);
         return;
     }
@@ -274,6 +258,22 @@ FwdState::fwdStart(int client_fd, StoreEntry *entry, HttpRequest *request)
     /* NOTREACHED */
 }
 
+void
+FwdState::startComplete()
+{
+    debugs(17, 3, HERE << entry->url() );
+
+    if (paths.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)
 {
@@ -295,10 +295,9 @@ void
 FwdState::unregister(int fd)
 {
     debugs(17, 3, HERE << entry->url()  );
-    assert(fd == server_fd);
+    assert(fd == paths[0]->fd);
     assert(fd > -1);
     comm_remove_close_handler(fd, fwdServerClosedWrapper, this);
-    server_fd = -1;
 }
 
 /**
@@ -310,9 +309,8 @@ FwdState::unregister(int fd)
 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();
@@ -321,20 +319,23 @@ FwdState::complete()
     logReplyStatus(n_tries, entry->getReply()->sline.status);
 
     if (reforward()) {
-        debugs(17, 3, "fwdComplete: re-forwarding " << entry->getReply()->sline.status << " " << e->url());
+        debugs(17, 3, HERE << "re-forwarding " << entry->getReply()->sline.status << " " << entry->url());
 
-        if (server_fd > -1)
-            unregister(server_fd);
+        if (paths[0]->fd > -1)
+            unregister(paths[0]->fd);
 
-        e->reset();
+        entry->reset();
 
-        startComplete(servers);
+        /* 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);
+        debugs(17, 3, HERE << "server FD " << paths[0]->fd << " not re-forwarding status " << entry->getReply()->sline.status);
         EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
         entry->complete();
 
-        if (server_fd < 0)
+        if (paths[0]->fd < 0)
             completed();
 
         self = NULL; // refcounted
@@ -345,10 +346,10 @@ FwdState::complete()
 /**** CALLBACK WRAPPERS ************************************************************/
 
 static void
-fwdStartCompleteWrapper(FwdServer * servers, void *data)
+fwdStartCompleteWrapper(Comm::Paths * unused, void *data)
 {
     FwdState *fwd = (FwdState *) data;
-    fwd->startComplete(servers);
+    fwd->startComplete();
 }
 
 static void
@@ -372,31 +373,13 @@ fwdNegotiateSSLWrapper(int fd, void *data)
     FwdState *fwd = (FwdState *) data;
     fwd->negotiateSSL(fd);
 }
-
 #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)
+void
+fwdConnectDoneWrapper(Comm::ConnectionPointer &conn, comm_err_t status, int xerrno, 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--;
+    fwd->connectDone(conn, status, xerrno);
 }
 
 /**** PRIVATE *****************************************************************/
@@ -487,9 +470,12 @@ FwdState::checkRetriable()
 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());
+    assert(paths[0]->fd == fd);
+
+    if (paths[0]->getPeer()) {
+        paths[0]->getPeer()->stats.conn_open--;
+    }
 
     retryOrBail();
 }
@@ -504,39 +490,22 @@ 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)");
 
-        /* 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;
-        }
+        paths.shift(); // last one failed. try another.
 
-        /* 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);
+        if (paths.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;
+            }
 
-        return;
+            connectStart();
+            return;
+        }
+        // else bail. no more paths possible to try.
     }
 
     if (!err && shutting_down) {
@@ -550,9 +519,8 @@ FwdState::retryOrBail()
 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(paths[0]->fd < 0);
     retryOrBail();
 }
 
@@ -560,7 +528,6 @@ FwdState::handleUnregisteredServerEnd()
 void
 FwdState::negotiateSSL(int fd)
 {
-    FwdServer *fs = servers;
     SSL *ssl = fd_table[fd].ssl;
     int ret;
 
@@ -592,21 +559,21 @@ FwdState::negotiateSSL(int fd)
 
             fail(anErr);
 
-            if (fs->_peer) {
-                peerConnectFailed(fs->_peer);
-                fs->_peer->stats.conn_open--;
+            if (paths[0]->getPeer()) {
+                peerConnectFailed(paths[0]->getPeer());
+                paths[0]->getPeer()->stats.conn_open--;
             }
 
-            comm_close(fd);
+            paths[0]->close();
             return;
         }
     }
 
-    if (fs->_peer && !SSL_session_reused(ssl)) {
-        if (fs->_peer->sslSession)
-            SSL_SESSION_free(fs->_peer->sslSession);
+    if (paths[0]->getPeer() && !SSL_session_reused(ssl)) {
+        if (paths[0]->getPeer()->sslSession)
+            SSL_SESSION_free(paths[0]->getPeer()->sslSession);
 
-        fs->_peer->sslSession = SSL_get1_session(ssl);
+        paths[0]->getPeer()->sslSession = SSL_get1_session(ssl);
     }
 
     dispatch();
@@ -615,11 +582,10 @@ FwdState::negotiateSSL(int fd)
 void
 FwdState::initiateSSL()
 {
-    FwdServer *fs = servers;
-    int fd = server_fd;
     SSL *ssl;
     SSL_CTX *sslContext = NULL;
-    peer *peer = fs->_peer;
+    const peer *peer = paths[0]->getPeer();
+    int fd = paths[0]->fd;
 
     if (peer) {
         assert(peer->use_ssl);
@@ -679,189 +645,162 @@ FwdState::initiateSSL()
 #endif
 
 void
-FwdState::connectDone(int aServerFD, const DnsLookupDetails &dns, comm_err_t status, int xerrno)
+FwdState::connectDone(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 *anErr = errorCon(ERR_DNS_FAIL, HTTP_SERVICE_UNAVAILABLE, request);
-
-        anErr->dnsError = dns.error;
-
-        fail(anErr);
-
-        comm_close(server_fd);
-    } else if (status != COMM_OK) {
-        assert(fs);
+    if (status != COMM_OK) {
         ErrorState *anErr = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE, request);
         anErr->xerrno = xerrno;
-
         fail(anErr);
 
-        if (fs->_peer)
-            peerConnectFailed(fs->_peer);
+        /* it might have been a timeout with a partially open link */
+        if (paths.size() > 0) {
+            if (paths[0]->getPeer())
+                peerConnectFailed(paths[0]->getPeer());
 
-        comm_close(server_fd);
-    } else {
-        debugs(17, 3, "fwdConnectDone: FD " << server_fd << ": '" << entry->url() << "'" );
+            paths[0]->close();
+        }
+        retryOrBail();
+        return;
+    }
 
-        if (fs->_peer)
-            peerConnectSucceded(fs->_peer);
+#if REDUNDANT_NOW
+    if (Config.onoff.log_ip_on_direct && paths[0]->peer_type == HIER_DIRECT)
+        updateHierarchyInfo();
+#endif
 
-#if USE_SSL
+    debugs(17, 3, "FD " << paths[0]->fd << ": '" << entry->url() << "'" );
 
-        if ((fs->_peer && fs->_peer->use_ssl) ||
-                (!fs->_peer && request->protocol == PROTO_HTTPS)) {
-            initiateSSL();
-            return;
-        }
+    comm_add_close_handler(paths[0]->fd, fwdServerClosedWrapper, this);
 
-#endif
-        dispatch();
+    if (paths[0]->getPeer())
+        peerConnectSucceded(paths[0]->getPeer());
+
+    updateHierarchyInfo();
+
+#if USE_SSL
+    if ((paths[0]->getPeer() && paths[0]->getPeer()->use_ssl) ||
+            (!paths[0]->getPeer() && request->protocol == PROTO_HTTPS)) {
+        initiateSSL();
+        return;
     }
+#endif
+
+    dispatch();
 }
 
 void
 FwdState::connectTimeout(int fd)
 {
-    FwdServer *fs = servers;
-
     debugs(17, 2, "fwdConnectTimeout: FD " << fd << ": '" << entry->url() << "'" );
-    assert(fd == server_fd);
+    assert(fd == paths[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 && paths[0]->peer_type == 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);
+        /* This marks the peer DOWN ... */
+        if (paths.size() > 0)
+            if (paths[0]->getPeer())
+                peerConnectFailed(paths[0]->getPeer());
     }
 
-    comm_close(fd);
+    paths[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);
-
-    Ip::Address outgoing;
-    unsigned short tos;
-    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;
+    Comm::ConnectionPointer conn = paths[0];
+
+    /* connection timeout */
+    int ctimeout;
+    if (conn->getPeer()) {
+        ctimeout = conn->getPeer()->connect_timeout > 0 ? conn->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 (conn->peer_type == PINNED) {
         ConnStateData *pinned_connection = request->pinnedConnection();
         assert(pinned_connection);
-        fd = pinned_connection->validatePinnedConnection(request, fs->_peer);
-        if (fd >= 0) {
+        conn->fd = pinned_connection->validatePinnedConnection(request, conn->getPeer());
+        if (conn->isOpen()) {
             pinned_connection->unpinConnection();
 #if 0
-            if (!fs->_peer)
-                fs->code = HIER_DIRECT;
+            if (!conn->getPeer())
+                conn->peer_type = 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);
+            FwdState::connectDone(conn, COMM_OK, 0);
             return;
         }
         /* Failure. Fall back on next path */
         debugs(17,2,HERE << " Pinned connection " << pinned_connection << " not valid. Releasing.");
         request->releasePinnedConnection();
-        servers = fs->next;
-        fwdServerFree(fs);
+        paths.shift();
+        conn = NULL; // maybe release the conn memory. it's not needed by us anyway.
         connectStart();
         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());
+// TODO: now that we are dealing with actual IP->IP links. should we still anchor pconn on hostname?
+//     or on the remote IP+port?
+// that could reduce the pconns per virtual server a fair amount
+// but would prevent crossover between servers hosting the one domain
+// this currently opens the possibility that conn will lie about where the FD goes.
+
+    const char *host;
+    int port;
+    if (conn->getPeer()) {
+        host = conn->getPeer()->host;
+        port = conn->getPeer()->http_port;
+        conn->fd = fwdPconnPool->pop(conn->getPeer()->name, conn->getPeer()->http_port, request->GetHost(), conn->local, checkRetriable());
     } else {
         host = request->GetHost();
         port = request->port;
-        fd = fwdPconnPool->pop(host, port, NULL, client_addr, checkRetriable());
+        conn->fd = fwdPconnPool->pop(host, port, NULL, conn->local, checkRetriable());
     }
-    if (fd >= 0) {
-        debugs(17, 3, "fwdConnectStart: reusing pconn FD " << fd);
-        server_fd = fd;
+    conn->remote.SetPort(port);
+
+    if (conn->isOpen()) {
+        debugs(17, 3, HERE << "reusing pconn FD " << conn->fd);
         n_tries++;
 
-        if (!fs->_peer)
+        if (!conn->getPeer())
             origin_tries++;
 
         updateHierarchyInfo();
 
-        comm_add_close_handler(fd, fwdServerClosedWrapper, this);
-
-        // TODO: Avoid this if %<lp is not used? F->local_port is often cached.
-        request->hier.peer_local_port = comm_local_port(fd);
+        comm_add_close_handler(conn->fd, fwdServerClosedWrapper, this);
 
         dispatch();
-
         return;
     }
 
@@ -869,98 +808,27 @@ FwdState::connectStart()
     entry->mem_obj->checkUrlChecksum();
 #endif
 
-    outgoing = getOutgoingAddr(request, fs->_peer);
-
-    tos = getOutgoingTOS(request);
-
-    debugs(17, 3, "fwdConnectStart: got outgoing addr " << outgoing << ", tos " << tos);
-
-    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, 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
+    AsyncCall::Pointer call = commCbCall(17,3, "fwdConnectDoneWrapper", CommConnectCbPtrFun(fwdConnectDoneWrapper, this));
+    ConnOpener *cs = new ConnOpener(paths[0], call);
+    cs->setHost(host);
+    cs->connect_timeout = ctimeout;
+    cs->start();
 }
 
 void
 FwdState::dispatch()
 {
-    peer *p = NULL;
     debugs(17, 3, "fwdDispatch: FD " << client_fd << ": 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);
+    assert(paths.size() > 0 && paths[0]->fd > -1);
 
-    fd_note(server_fd, entry->url());
+    fd_note(paths[0]->fd, entry->url());
 
-    fd_table[server_fd].noteUse(fwdPconnPool);
+    fd_table[paths[0]->fd].noteUse(fwdPconnPool);
 
     /*assert(!EBIT_TEST(entry->flags, ENTRY_DISPATCHED)); */
     assert(entry->ping_status != PING_WAITING);
@@ -983,10 +851,10 @@ FwdState::dispatch()
         int tos = 1;
         int tos_len = sizeof(tos);
         clientFde->upstreamTOS = 0;
-        if (setsockopt(server_fd,SOL_IP,IP_RECVTOS,&tos,tos_len)==0) {
+        if (setsockopt(paths[0]->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(paths[0]->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.
@@ -1005,18 +873,18 @@ FwdState::dispatch()
                     pbuf += CMSG_LEN(o->cmsg_len);
                 }
             } else {
-                debugs(33, 1, "ZPH: error in getsockopt(IP_PKTOPTIONS) on FD "<<server_fd<<" "<<xstrerror());
+                debugs(33, DBG_IMPORTANT, "ZPH: error in getsockopt(IP_PKTOPTIONS) on FD " << paths[0]->fd << " " << xstrerror());
             }
         } else {
-            debugs(33, 1, "ZPH: error in setsockopt(IP_RECVTOS) on FD "<<server_fd<<" "<<xstrerror());
+            debugs(33, DBG_IMPORTANT, "ZPH: error in setsockopt(IP_RECVTOS) on FD " << paths[0]->fd << " " << xstrerror());
         }
     }
 #endif
 
-    if (servers && (p = servers->_peer)) {
-        p->stats.fetches++;
-        request->peer_login = p->login;
-        request->peer_domain = p->domain;
+    if (paths.size() > 0 && paths[0]->getPeer() != NULL) {
+        paths[0]->getPeer()->stats.fetches++;
+        request->peer_login = paths[0]->getPeer()->login;
+        request->peer_domain = paths[0]->getPeer()->domain;
         httpStart(this);
     } else {
         request->peer_login = NULL;
@@ -1071,7 +939,7 @@ FwdState::dispatch()
              * transient (network) error; its a bug.
              */
             flags.dont_retry = 1;
-            comm_close(server_fd);
+            paths[0]->close();
             break;
         }
     }
@@ -1089,7 +957,6 @@ int
 FwdState::reforward()
 {
     StoreEntry *e = entry;
-    FwdServer *fs = servers;
     http_status s;
     assert(e->store_status == STORE_PENDING);
     assert(e->mem_obj);
@@ -1098,10 +965,10 @@ FwdState::reforward()
     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;
     }
 
@@ -1114,19 +981,15 @@ FwdState::reforward()
     if (request->bodyNibbled())
         return 0;
 
-    assert(fs);
+    paths.shift();
 
-    servers = fs->next;
-
-    fwdServerFree(fs);
-
-    if (servers == NULL) {
-        debugs(17, 3, "fwdReforward: No forward-servers left");
+    if (paths.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);
 }
 
@@ -1195,22 +1058,26 @@ FwdState::reforwardableStatus(http_status s)
  *  -  address of the client for which we made the connection
  */
 void
-FwdState::pconnPush(int fd, const peer *_peer, const HttpRequest *req, const char *domain, Ip::Address &client_addr)
+FwdState::pconnPush(Comm::ConnectionPointer conn, const peer *_peer, const HttpRequest *req, const char *domain, Ip::Address &client_addr)
 {
     if (_peer) {
-        fwdPconnPool->push(fd, _peer->name, _peer->http_port, domain, client_addr);
+        fwdPconnPool->push(conn->fd, _peer->name, _peer->http_port, domain, client_addr);
     } 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->fd, req->GetHost(), req->port, NULL, client_addr);
     }
+
+    /* XXX: remove this when Comm::Connection are stored in the pool
+     * this only prevents the persistent FD being closed when the
+     * Comm::Connection currently using it is destroyed.
+     */
+    conn->fd = -1;
 }
 
 void
 FwdState::initModule()
 {
-    memDataInit(MEM_FWD_SERVER, "FwdServer", sizeof(FwdServer), 0);
-
 #if WIP_FWD_LOG
 
     if (logfile)
@@ -1238,9 +1105,7 @@ FwdState::logReplyStatus(int tries, http_status status)
     if (status > HTTP_INVALID_HEADER)
         return;
 
-    assert(tries);
-
-    tries--;
+    assert(tries >= 0);
 
     if (tries > MAX_FWD_STATS_IDX)
         tries = MAX_FWD_STATS_IDX;
@@ -1248,17 +1113,6 @@ FwdState::logReplyStatus(int tries, http_status status)
     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
 
@@ -1277,53 +1131,29 @@ FwdState::updateHierarchyInfo()
 {
     assert(request);
 
-    FwdServer *fs = servers;
-    assert(fs);
+    assert(paths.size() > 0);
 
-    const char *nextHop = NULL;
+    char nextHop[256]; // 
 
-    if (fs->_peer) {
+    if (paths[0]->getPeer()) {
         // went to peer, log peer host name
-        nextHop = fs->_peer->name;
+        snprintf(nextHop,256,"%s", paths[0]->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
+            paths[0]->remote.NtoA(nextHop, 256);
     }
 
-    assert(nextHop);
-    hierarchyNote(&request->hier, fs->code, nextHop);
-}
+    request->hier.peer_local_port = paths[0]->local.GetPort();
 
-
-/**** PRIVATE NON-MEMBER FUNCTIONS ********************************************/
-
-static void
-fwdServerFree(FwdServer * fs)
-{
-    cbdataReferenceDone(fs->_peer);
-    memFree(fs, MEM_FWD_SERVER);
+    assert(nextHop[0]);
+    hierarchyNote(&request->hier, paths[0]->peer_type, nextHop);
 }
 
-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;
-}
+/**** PRIVATE NON-MEMBER FUNCTIONS ********************************************/
 
 /*
  * DPW 2007-05-19
@@ -1342,27 +1172,39 @@ aclMapTOS(acl_tos * head, ACLChecklist * ch)
     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
@@ -1374,7 +1216,18 @@ getOutgoingAddr(HttpRequest * request, struct peer *dst_peer)
         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;
+        }
+    }
 }
 
 unsigned long
index 0ac5ae90c6ac841cdaf2ab8c262bb8e5df7ac0ff..11178f1d02cd84e0009a7f8fde1c83b2aa8a2ddd 100644 (file)
@@ -7,16 +7,9 @@ class ErrorState;
 class HttpRequest;
 
 #include "comm.h"
-#include "hier_code.h"
+#include "comm/Connection.h"
 #include "ip/Address.h"
-
-class FwdServer
-{
-public:
-    peer *_peer;                /* NULL --> origin server */
-    hier_code code;
-    FwdServer *next;
-};
+#include "Array.h"
 
 class FwdState : public RefCountable
 {
@@ -26,8 +19,7 @@ public:
     static void initModule();
 
     static void fwdStart(int fd, StoreEntry *, HttpRequest *);
-    void startComplete(FwdServer *);
-    void startFail();
+    void startComplete();
     void fail(ErrorState *err);
     void unregister(int fd);
     void complete();
@@ -36,14 +28,14 @@ public:
     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(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 peer *_peer, const HttpRequest *req, const char *domain, Ip::Address &client_addr);
 
     bool dontRetry() { return flags.dont_retry; }
 
@@ -53,7 +45,7 @@ public:
 
     void ftpPasvFailed(bool val) { flags.ftp_pasv_failed = val; }
 
-    static void serversFree(FwdServer **);
+    Comm::ConnectionPointer conn() const { return paths[0]; };
 
 private:
     // hidden for safer management of self; use static fwdStart
@@ -76,8 +68,6 @@ private:
 public:
     StoreEntry *entry;
     HttpRequest *request;
-    int server_fd;
-    FwdServer *servers;
     static void abort(void*);
 
 private:
@@ -98,7 +88,8 @@ private:
         unsigned int forward_completed:1;
     } flags;
 
-    Ip::Address src; /* Client address for this connection. Needed for transparent operations. */
+    /** possible paths which may be tried (in sequence stored) */
+    Comm::Paths paths;
 
     // NP: keep this last. It plays with private/public
     CBDATA_CLASS2(FwdState);
index d8c9e7d8690c6c3e927208f5cba4433ac1e945d5..aed4d70e051e08cc9ff4beaa500e1f198e698715 100644 (file)
@@ -34,6 +34,7 @@
 
 #include "squid.h"
 #include "cbdata.h"
+#include "DnsLookupDetails.h"
 #include "event.h"
 #include "CacheManager.h"
 #include "SquidTime.h"
index b17fb2bfea8e2b164619d52672ea26679c242fbf..7d500db11edcbaecc138d3ef9d8513bd5403f5fa 100644 (file)
@@ -34,9 +34,9 @@
 
 #include "squid.h"
 #include "comm.h"
+#include "comm/ConnOpener.h"
 #include "comm/ListenStateData.h"
 #include "compat/strtoll.h"
-#include "ConnectionDetail.h"
 #include "errorpage.h"
 #include "fde.h"
 #include "forward.h"
@@ -480,7 +480,7 @@ FtpStateData::FtpStateData(FwdState *theFwdState) : AsyncJob("FtpStateData"), Se
     typedef CommCbMemFunT<FtpStateData, CommCloseCbParams> Dialer;
     AsyncCall::Pointer closer = asyncCall(9, 5, "FtpStateData::ctrlClosed",
                                           Dialer(this, &FtpStateData::ctrlClosed));
-    ctrl.opened(theFwdState->server_fd, closer);
+    ctrl.opened(theFwdState->conn()->fd, closer);
 
     if (request->method == METHOD_PUT)
         flags.put = 1;
@@ -2412,7 +2412,15 @@ ftpReadEPSV(FtpStateData* ftpState)
 
     debugs(9, 3, HERE << "connecting to " << ftpState->data.host << ", port " << ftpState->data.port);
 
-    commConnectStart(fd, ftpState->data.host, port, FtpStateData::ftpPasvCallback, ftpState);
+    Comm::ConnectionPointer conn = new Comm::Connection;
+    conn->remote = fd_table[ftpState->ctrl.fd].ipaddr; // TODO: do we have a better info source than fd_table?
+    conn->remote.SetPort(port);
+    conn->fd = fd;
+
+    AsyncCall::Pointer call = commCbCall(9,3, "FtpStateData::ftpPasvCallback", CommConnectCbPtrFun(FtpStateData::ftpPasvCallback, ftpState));
+    ConnOpener *cs = new ConnOpener(conn, call);
+    cs->setHost(ftpState->data.host);
+    cs->start();
 }
 
 /** \ingroup ServerProtocolFTPInternal
@@ -2545,10 +2553,11 @@ ftpSendPassive(FtpStateData * ftpState)
 
     /** 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,
+    int fd = comm_openex(SOCK_STREAM,
                        IPPROTO_TCP,
                        addr,
                        COMM_NONBLOCKING,
+                       0,
                        ftpState->entry->url());
 
     debugs(9, 3, HERE << "Unconnected data socket created on FD " << fd << " from " << addr);
@@ -2610,7 +2619,6 @@ ftpReadPasv(FtpStateData * ftpState)
     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);
@@ -2688,15 +2696,23 @@ ftpReadPasv(FtpStateData * ftpState)
 
     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->remote = ipaddr;
+    conn->remote.SetPort(port);
+    conn->fd = ftpState->data.fd;
+
+    AsyncCall::Pointer call = commCbCall(9,3, "FtpStateData::ftpPasvCallback", CommConnectCbPtrFun(FtpStateData::ftpPasvCallback, ftpState));
+    ConnOpener *cs = new ConnOpener(conn, call);
+    cs->setHost(ftpState->data.host);
+    cs->connect_timeout = Config.Timeout.connect;
+    cs->start();
 }
 
 void
-FtpStateData::ftpPasvCallback(int fd, const DnsLookupDetails &dns, comm_err_t status, int xerrno, void *data)
+FtpStateData::ftpPasvCallback(Comm::ConnectionPointer &conn, comm_err_t status, int xerrno, void *data)
 {
     FtpStateData *ftpState = (FtpStateData *)data;
     debugs(9, 3, HERE);
-    ftpState->request->recordLookup(dns);
 
     if (status != COMM_OK) {
         debugs(9, 2, HERE << "Failed to connect. Retrying without PASV.");
@@ -2937,16 +2953,17 @@ void FtpStateData::ftpAcceptDataConnection(const CommAcceptCbParams &io)
      * This prevents third-party hacks, but also third-party load balancing handshakes.
      */
     if (Config.Ftp.sanitycheck) {
-        io.details.peer.NtoA(ntoapeer,MAX_IPSTRLEN);
+        io.details->remote.NtoA(ntoapeer,MAX_IPSTRLEN);
 
         if (strcmp(fd_table[ctrl.fd].ipaddr, ntoapeer) != 0) {
             debugs(9, DBG_IMPORTANT,
                    "FTP data connection from unexpected server (" <<
-                   io.details.peer << "), expecting " <<
+                   io.details->remote << "), expecting " <<
                    fd_table[ctrl.fd].ipaddr);
 
-            /* close the bad soures connection down ASAP. */
-            comm_close(io.nfd);
+            /* close the bad sources connection down ASAP. */
+            Comm::ConnectionPointer nonConst = io.details;
+            nonConst->close();
 
             /* we are ony accepting once, so need to re-open the listener socket. */
             typedef CommCbMemFunT<FtpStateData, CommAcceptCbParams> acceptDialer;
@@ -2968,11 +2985,11 @@ void FtpStateData::ftpAcceptDataConnection(const CommAcceptCbParams &io)
      * Replace the Listen socket with the accepted data socket */
     data.close();
     data.opened(io.nfd, dataCloser());
-    data.port = io.details.peer.GetPort();
-    io.details.peer.NtoA(data.host,SQUIDHOSTNAMELEN);
+    data.port = io.details->remote.GetPort();
+    io.details->remote.NtoA(data.host,SQUIDHOSTNAMELEN);
 
     debugs(9, 3, "ftpAcceptDataConnection: Connected data socket on " <<
-           "FD " << io.nfd << " to " << io.details.peer << " FD table says: " <<
+           "FD " << io.nfd << " to " << io.details->remote << " FD table says: " <<
            "ctrl-peer= " << fd_table[ctrl.fd].ipaddr << ", " <<
            "data-peer= " << fd_table[data.fd].ipaddr);
 
index 293059ee46de9f449d2fcee517e3e2dc1dbb9ea3..35d695fc1060d1968a25d64cc1c19bb3dfa30641 100644 (file)
@@ -990,7 +990,6 @@ CBDATA_TYPE(GopherStateData);
 void
 gopherStart(FwdState * fwd)
 {
-    int fd = fwd->server_fd;
     StoreEntry *entry = fwd->entry;
     GopherStateData *gopherState;
     CBDATA_INIT_TYPE(GopherStateData);
@@ -1012,7 +1011,7 @@ gopherStart(FwdState * fwd)
     gopher_request_parse(fwd->request,
                          &gopherState->type_id, gopherState->request);
 
-    comm_add_close_handler(fd, gopherStateFree, gopherState);
+    comm_add_close_handler(fwd->conn()->fd, gopherStateFree, gopherState);
 
     if (((gopherState->type_id == GOPHER_INDEX) || (gopherState->type_id == GOPHER_CSO))
             && (strchr(gopherState->request, '?') == NULL)) {
@@ -1032,12 +1031,12 @@ gopherStart(FwdState * fwd)
 
         gopherToHTML(gopherState, (char *) NULL, 0);
         fwd->complete();
-        comm_close(fd);
+        fwd->conn()->close();
         return;
     }
 
-    gopherState->fd = fd;
+    gopherState->fd = fwd->conn()->fd; // TODO: save the conn() in gopher instead of the FD
     gopherState->fwd = fwd;
-    gopherSendRequest(fd, gopherState);
-    commSetTimeout(fd, Config.Timeout.read, gopherTimeout, gopherState);
+    gopherSendRequest(fwd->conn()->fd, gopherState);
+    commSetTimeout(fwd->conn()->fd, Config.Timeout.read, gopherTimeout, gopherState);
 }
index 2b2f1f683f949dab71da4991b0e5471c175b1ee9..112aaf11130138a6df7338becd441d2f2327178c 100644 (file)
@@ -86,7 +86,7 @@ HttpStateData::HttpStateData(FwdState *theFwdState) : AsyncJob("HttpStateData"),
     debugs(11,5,HERE << "HttpStateData " << this << " created");
     ignoreCacheControl = false;
     surrogateNoStore = false;
-    fd = fwd->server_fd;
+    fd = fwd->conn()->fd; // TODO: store Comm::Connection instead of FD
     readBuf = new MemBuf;
     readBuf->init();
     orig_request = HTTPMSGLOCK(fwd->request);
@@ -95,8 +95,8 @@ HttpStateData::HttpStateData(FwdState *theFwdState) : AsyncJob("HttpStateData"),
     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->conn() != NULL)
+        _peer = cbdataReference(fwd->conn()->getPeer());         /* might be NULL */
 
     if (_peer) {
         const char *url;
@@ -106,8 +106,7 @@ HttpStateData::HttpStateData(FwdState *theFwdState) : AsyncJob("HttpStateData"),
         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);
 
@@ -1361,7 +1360,7 @@ HttpStateData::processReplyBody()
                 orig_request->pinnedConnection()->pinConnection(fd, orig_request, _peer,
                         (request->flags.connection_auth != 0));
             } else {
-                fwd->pconnPush(fd, _peer, request, orig_request->GetHost(), client_addr);
+                fwd->pconnPush(fwd->conn(), _peer, request, orig_request->GetHost(), client_addr);
             }
 
             fd = -1;
index cb1e4cde5cbced6d37d664b0784347f0ed726c6b..b321bc409a171a1b3a66c3ec7b8189a63c814bf4 100644 (file)
  */
 
 #include "squid.h"
-#include "Store.h"
-#include "comm.h"
-#include "ICP.h"
-#include "HttpRequest.h"
-#include "acl/FilledChecklist.h"
-#include "acl/Acl.h"
 #include "AccessLogEntry.h"
-#include "wordlist.h"
-#include "SquidTime.h"
-#include "SwapDir.h"
+#include "acl/Acl.h"
+#include "acl/FilledChecklist.h"
+#include "comm/Connection.h"
+#include "HttpRequest.h"
 #include "icmp/net_db.h"
+#include "ICP.h"
 #include "ip/Address.h"
 #include "ipc/StartListening.h"
 #include "rfc1738.h"
+#include "Store.h"
+#include "SquidTime.h"
+#include "SwapDir.h"
+#include "wordlist.h"
 
 /// dials icpIncomingConnectionOpened call
 class IcpListeningStartedDialer: public CallDialer,
index ba9e49c8e334b82019fe012193d94c9f9b8d73c9..aa9ecc6b9624e5d865f41a31ac9a3d1c290dd8c4 100644 (file)
@@ -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"
 
@@ -129,7 +130,12 @@ IdentLookup::checkForAsync(ACLChecklist *cl)const
     if (checklist->conn() != NULL) {
         debugs(28, 3, HERE << "Doing ident lookup" );
         checklist->asyncInProgress(true);
-        Ident::Start(checklist->conn()->me, checklist->conn()->peer, LookupDone, checklist);
+        // TODO: store a Comm::Connection in either checklist or ConnStateData one day.
+        Comm::Connection cc; // IDENT will clone it's own copy for alterations.
+        cc.local = checklist->conn()->me;
+        cc.remote = checklist->conn()->peer;
+        Comm::ConnectionPointer ccp = &cc;
+        Ident::Start(ccp, LookupDone, checklist);
     } else {
         debugs(28, DBG_IMPORTANT, "IdentLookup::checkForAsync: Can't start ident lookup. No client connection" );
         checklist->currentAnswer(ACCESS_DENIED);
index 50f7a734e042551a7335b52a1d3bb83024435141..e56476460d2fa0228a23243067b9334328eed406 100644 (file)
@@ -37,6 +37,9 @@
 #if USE_IDENT
 
 #include "comm.h"
+#include "comm/Connection.h"
+#include "comm/ConnOpener.h"
+#include "CommCalls.h"
 #include "ident/Config.h"
 #include "ident/Ident.h"
 #include "MemBuf.h"
@@ -56,10 +59,7 @@ typedef struct _IdentClient {
 
 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];
 } IdentStateData;
@@ -103,7 +103,7 @@ Ident::Close(int fdnotused, void *data)
 {
     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);
@@ -113,26 +113,28 @@ void
 Ident::Timeout(int fd, void *data)
 {
     IdentStateData *state = (IdentStateData *)data;
-    debugs(30, 3, "identTimeout: FD " << fd << ", " << state->my_peer);
-
-    comm_close(fd);
+    debugs(30, 3, HERE << "FD " << fd << ", " << state->conn->remote);
+    state->conn->close();
 }
 
 void
-Ident::ConnectDone(int fd, const DnsLookupDetails &, comm_err_t status, int xerrno, void *data)
+Ident::ConnectDone(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;
@@ -140,18 +142,20 @@ Ident::ConnectDone(int fd, const DnsLookupDetails &, comm_err_t status, int xerr
 
     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());
-    comm_write_mbuf(fd, &mb, NULL, state);
-    comm_read(fd, state->buf, BUFSIZ, Ident::ReadReply, state);
-    commSetTimeout(fd, Ident::TheConfig.timeout, Ident::Timeout, state);
+              conn->remote.GetPort(),
+              conn->local.GetPort());
+    comm_write_mbuf(conn->fd, &mb, NULL, state);
+    comm_read(conn->fd, state->buf, BUFSIZ, Ident::ReadReply, state);
+    commSetTimeout(conn->fd, Ident::TheConfig.timeout, Ident::Timeout, state);
 }
 
 void
@@ -161,10 +165,11 @@ Ident::ReadReply(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, voi
     char *ident = NULL;
     char *t = NULL;
 
-    assert (buf == state->buf);
+    assert(buf == state->buf);
+    assert(fd == state->conn->fd);
 
     if (flag != COMM_OK || len <= 0) {
-        comm_close(fd);
+        state->conn->close();
         return;
     }
 
@@ -181,7 +186,7 @@ Ident::ReadReply(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, voi
     if ((t = strchr(buf, '\n')))
         *t = '\0';
 
-    debugs(30, 5, "identReadReply: FD " << fd << ": Read '" << buf << "'");
+    debugs(30, 5, HERE << "FD " << fd << ": Read '" << buf << "'");
 
     if (strstr(buf, "USERID")) {
         if ((ident = strrchr(buf, ':'))) {
@@ -190,7 +195,7 @@ Ident::ReadReply(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, voi
         }
     }
 
-    comm_close(fd);
+    state->conn->close();
 }
 
 void
@@ -213,17 +218,15 @@ CBDATA_TYPE(IdentStateData);
  * 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(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) {
@@ -234,33 +237,22 @@ Ident::Start(Ip::Address &me, Ip::Address &my_peer, IDCB * callback, void *data)
         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));
+    ConnOpener *cs = new ConnOpener(state->conn, call);
+    cs->connect_timeout = Ident::TheConfig.timeout;
+    cs->start();
 }
 
 void
index 7253a4736d262e4d95fbf3d34e5e07ccc5c8abaa..15ed12842a861d0b68e5b43a5ad0e3ae7d0c8c42 100644 (file)
@@ -14,8 +14,7 @@
 #if USE_IDENT
 
 #include "cbdata.h"
-
-#include "ip/forward.h"
+#include "comm/forward.h"
 
 namespace Ident
 {
@@ -28,7 +27,7 @@ namespace Ident
  * 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(Comm::ConnectionPointer &conn, IDCB * callback, void *cbdata);
 
 /**
  \ingroup IdentAPI
index 5336b3d12dab636241b7e82bd3de972fdbc3e659..5ecc9e2145dab1cc2b331b8fd94f085d5e655f9b 100644 (file)
@@ -31,7 +31,7 @@
  */
 
 #include "squid.h"
-#include "comm.h"
+#include "comm/Connection.h"
 #include "fde.h"
 #include "ip/Address.h"
 #include "rfc1738.h"
index 802b7a1a112c5f0ae4c9820b7403b3d5b2d28573..2f14c6dc21844e2ba4a03b7861b5269bdd92aa6a 100644 (file)
 
 #include "squid.h"
 #include "cbdata.h"
-#include "event.h"
 #include "CacheManager.h"
+#include "DnsLookupDetails.h"
+#include "event.h"
+#include "ip/Address.h"
 #include "SquidTime.h"
 #include "Store.h"
 #include "wordlist.h"
-#include "ip/Address.h"
 
 /**
  \defgroup IPCacheAPI IP Cache API
@@ -621,9 +622,9 @@ ipcacheHandleReply(void *data, rfc1035_rr * answers, int na, const char *error_m
  * 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)
index 8fef05145975344394d6af2465753c645be20cd6..c56ea0f96ed32783c0d902eca12c5a7ae5f1df4d 100644 (file)
@@ -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"
index bc83cf4df0a4160b2989a7a52781f5a527dfdb05..3310e32c1aa0d9aeac489260fe693000cc0bb21e 100644 (file)
@@ -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"
index a5704158568d037a46dc6cc757f251d1051988cc..f45a3f4dfb36544951879bf77cd88e6e1db70ab8 100644 (file)
@@ -77,7 +77,7 @@
 #include "MemPool.h"
 #include "icmp/IcmpSquid.h"
 #include "icmp/net_db.h"
-
+#include "PeerSelectState.h"
 #if USE_LOADABLE_MODULES
 #include "LoadableModules.h"
 #endif
index e0f0717fe036043d8b9ee8c7f60d45139b96cf56..81859e30f17ff5706001cf860c4da84a34e77296 100644 (file)
 #include "squid.h"
 #include "ProtoPort.h"
 #include "acl/FilledChecklist.h"
-#include "event.h"
+#include "comm/Connection.h"
+#include "comm/ConnOpener.h"
 #include "CacheManager.h"
+#include "event.h"
 #include "htcp.h"
 #include "HttpRequest.h"
 #include "ICP.h"
@@ -60,7 +62,7 @@ static void neighborAliveHtcp(peer *, const MemObject *, const htcpReplyData *);
 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);
@@ -1342,68 +1344,44 @@ peerConnectSucceded(peer * p)
         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));
+    /* 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);
 
-    fd = comm_open(SOCK_STREAM, IPPROTO_TCP, temp, COMM_NONBLOCKING, p->host);
+        p->testing_now++;
 
-    if (fd < 0)
-        return ret;
-
-    comm_add_close_handler(fd, &peerProbeClosed, p);
-    commSetTimeout(fd, ctimeout, peerProbeConnectTimeout, p);
-
-    p->test_fd = fd;
+        AsyncCall::Pointer call = commCbCall(15,3, "peerProbeConnectDone", CommConnectCbPtrFun(peerProbeConnectDone, p));
+        ConnOpener *cs = new ConnOpener(conn, call);
+        cs->connect_timeout = ctimeout;
+        cs->setHost(p->host);
+        cs->start();
+    }
 
     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(Comm::ConnectionPointer &conn, comm_err_t status, int xerrno, void *data)
 {
     peer *p = (peer*)data;
 
@@ -1413,9 +1391,8 @@ peerProbeConnectDone(int fd, const DnsLookupDetails &, comm_err_t status, int xe
         peerConnectFailedSilent(p);
     }
 
-    comm_remove_close_handler(fd, &peerProbeClosed, p);
-    comm_close(fd);
-    p->test_fd = -1;
+    conn->close();
+    p->testing_now--;
     return;
 }
 
index 4cdc429f58ef15fe6ef3a98e8bce4187277dfcb5..b38cfebefe2d6bed40ef07e450565cf714d90b21 100644 (file)
  */
 
 #include "squid.h"
+#include "acl/FilledChecklist.h"
+#include "DnsLookupDetails.h"
 #include "event.h"
-#include "PeerSelectState.h"
-#include "Store.h"
+#include "forward.h"
 #include "hier_code.h"
-#include "ICP.h"
-#include "HttpRequest.h"
-#include "acl/FilledChecklist.h"
 #include "htcp.h"
-#include "forward.h"
-#include "SquidTime.h"
+#include "HttpRequest.h"
 #include "icmp/net_db.h"
+#include "ICP.h"
+#include "PeerSelectState.h"
+#include "SquidTime.h"
+#include "Store.h"
 
 static struct {
     int timeouts;
@@ -74,6 +75,8 @@ static void peerGetSomeParent(ps_state *);
 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);
 
@@ -121,7 +124,8 @@ peerSelectIcpPing(HttpRequest * request, int direct, StoreEntry * entry)
 
 
 void
-peerSelect(HttpRequest * request,
+peerSelect(Comm::Paths * paths,
+           HttpRequest * request,
            StoreEntry * entry,
            PSC * callback,
            void *callback_data)
@@ -139,6 +143,8 @@ peerSelect(HttpRequest * request,
 
     psstate->entry = entry;
 
+    psstate->paths = paths;
+
     psstate->callback = callback;
 
     psstate->callback_data = cbdataReference(callback_data);
@@ -182,8 +188,6 @@ peerSelectCallback(ps_state * psstate)
 {
     StoreEntry *entry = psstate->entry;
     FwdServer *fs = psstate->servers;
-    PSC *callback;
-    void *cbdata;
 
     if (entry) {
         debugs(44, 3, "peerSelectCallback: " << entry->url()  );
@@ -203,17 +207,92 @@ peerSelectCallback(ps_state * psstate)
 
     psstate->ping.stop = current_time;
     psstate->request->hier.ping = psstate->ping;
-    callback = psstate->callback;
+}
+
+void
+peerSelectDnsPaths(ps_state *psstate)
+{
+    FwdServer *fs = psstate->servers;
+
+    // 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;
+    }
+
+    // done with DNS lookups. pass back to caller
+    PSC *callback = psstate->callback;
     psstate->callback = NULL;
 
+    debugs(44, 2, "Found IP destination for: " << psstate->entry->url() << "'");
+
+    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.
+        Comm::ConnectionPointer p;
+        int ip = ia->cur;
+        for (int n = 0; n < ia->count; n++, ip++) {
+            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->peer_type = fs->code;
+
+            // check for a configured outgoing address for this destination...
+            getOutgoingAddress(psstate->request, p);
+            p->tos = getOutgoingTOS(psstate->request);
+
+            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)
 {
@@ -265,7 +344,7 @@ peerSelectFoo(ps_state * ps)
     HttpRequest *request = ps->request;
     debugs(44, 3, "peerSelectFoo: '" << RequestMethodStr(request->method) << " " << request->GetHost() << "'");
 
-    /** If we don't known whether DIRECT is permitted ... */
+    /** If we don't know whether DIRECT is permitted ... */
     if (ps->direct == DIRECT_UNKNOWN) {
         if (ps->always_direct == 0 && Config.accessList.AlwaysDirect) {
             /** check always_direct; */
@@ -344,15 +423,17 @@ peerSelectFoo(ps_state * ps)
         break;
     }
 
-    peerSelectCallback(ps);
+    // resolve the possible peers
+    peerSelectDnsPaths(ps);
 }
 
-/*
+int peerAllowedToUse(const peer * p, HttpRequest * request);
+
+/**
  * peerSelectPinned
  *
- * Selects a pinned connection
+ * Selects a pinned connection.
  */
-int peerAllowedToUse(const peer * p, HttpRequest * request);
 static void
 peerSelectPinned(ps_state * ps)
 {
@@ -374,7 +455,7 @@ peerSelectPinned(ps_state * ps)
     }
 }
 
-/*
+/**
  * peerGetSomeNeighbor
  *
  * Selects a neighbor (parent or sibling) based on one of the
@@ -599,6 +680,7 @@ void
 peerSelectInit(void)
 {
     memset(&PeerStats, '\0', sizeof(PeerStats));
+    memDataInit(MEM_FWD_SERVER, "FwdServer", sizeof(FwdServer), 0);
 }
 
 static void
index dc236014666bc69f6fd851b131f7260441d2d962..258b825ee21b9559deb91e580f5df4736c0c9bce 100644 (file)
@@ -398,9 +398,6 @@ SQUIDCEXTERN int peerHTTPOkay(const peer *, HttpRequest *);
 
 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);
@@ -408,7 +405,8 @@ SQUIDCEXTERN void peerDigestNeeded(PeerDigest * pd);
 SQUIDCEXTERN void peerDigestNotePeerGone(PeerDigest * pd);
 SQUIDCEXTERN void peerDigestStatsReport(const PeerDigest * pd, StoreEntry * e);
 
-extern Ip::Address getOutgoingAddr(HttpRequest * request, struct peer *dst_peer);
+#include "comm/forward.h"
+extern void getOutgoingAddress(HttpRequest * request, Comm::ConnectionPointer conn);
 unsigned long getOutgoingTOS(HttpRequest * request);
 
 SQUIDCEXTERN void urnStart(HttpRequest *, StoreEntry *);
index 74dce91e7eecb08db832b4f246ebda3aae6ffc02..1781eedb07787be7cd3350308fb87a29edda33f0 100644 (file)
@@ -33,6 +33,7 @@
 #include "acl/FilledChecklist.h"
 #include "cache_snmp.h"
 #include "comm.h"
+#include "comm/Connection.h"
 #include "ipc/StartListening.h"
 #include "compat/strsep.h"
 #include "ip/Address.h"
index 819d63029baa19796378ab6bccbc294ebb95bde7..412b964c9b40fb1507b58b2fc879b5b5d22b1155 100644 (file)
@@ -443,6 +443,7 @@ struct SquidConfig {
     } onoff;
 
     int forward_max_tries;
+    int connect_retries;
 
     class ACL *aclList;
 
@@ -521,7 +522,6 @@ struct SquidConfig {
     char *errorStylesheet;
 
     struct {
-        int maxtries;
         int onerror;
     } retry;
 
@@ -912,7 +912,7 @@ struct peer {
     int n_addresses;
     int rr_count;
     peer *next;
-    int test_fd;
+    int testing_now;
 
     struct {
         unsigned int hash;
index a602b92a5ef9e454de707078e2edcdc3e2401f34..88b714400663f96eaa2a0fdde905a84e1f2570b8 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * $Id$
  *
  */
 
 #include "squid.h"
-#include "errorpage.h"
-#include "HttpRequest.h"
-#include "fde.h"
+#include "acl/FilledChecklist.h"
+#include "Array.h"
 #include "comm.h"
+#include "comm/Connection.h"
+#include "comm/ConnOpener.h"
+#include "client_side.h"
 #include "client_side_request.h"
-#include "acl/FilledChecklist.h"
 #if DELAY_POOLS
 #include "DelayId.h"
 #endif
-#include "client_side.h"
-#include "MemBuf.h"
+#include "errorpage.h"
+#include "fde.h"
+#include "HttpRequest.h"
 #include "http.h"
+#include "MemBuf.h"
+#include "PeerSelectState.h"
 
 class TunnelStateData
 {
@@ -65,7 +68,7 @@ public:
     char *host;                        /* either request->host or proxy host */
     u_short port;
     HttpRequest *request;
-    FwdServer *servers;
+    Comm::Paths paths;
 
     class Connection
     {
@@ -173,7 +176,7 @@ tunnelStateFree(TunnelStateData * tunnelState)
     assert(tunnelState != NULL);
     assert(tunnelState->noConnections());
     safe_free(tunnelState->url);
-    FwdState::serversFree(&tunnelState->servers);
+    tunnelState->paths.clean();
     tunnelState->host = NULL;
     HTTPMSGUNLOCK(tunnelState->request);
     delete tunnelState;
@@ -181,7 +184,7 @@ tunnelStateFree(TunnelStateData * tunnelState)
 
 TunnelStateData::Connection::~Connection()
 {
-    safe_free (buf);
+    safe_free(buf);
 }
 
 int
@@ -463,42 +466,6 @@ TunnelStateData::copyRead(Connection &from, IOCB *completion)
     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)
 {
@@ -553,52 +520,73 @@ tunnelErrorComplete(int fdnotused, void *data, size_t sizenotused)
 
 
 static void
-tunnelConnectDone(int fdnotused, const DnsLookupDetails &dns, comm_err_t status, int xerrno, void *data)
+tunnelConnectDone(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 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->peer_type, 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->peer_type, 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);
-    } else {
-        if (tunnelState->servers->_peer)
-            tunnelProxyConnected(tunnelState->server.fd(), tunnelState);
-        else {
-            tunnelConnected(tunnelState->server.fd(), tunnelState);
+        hierarchyNote(&tunnelState->request->hier, conn->peer_type, tunnelState->host);
+
+    if (status != COMM_OK) {
+        /* At this point only the TCP handshake has failed. no data has been passed.
+         * we are allowed to re-try the TCP-level connection to alternate IPs for CONNECT.
+         */
+        tunnelState->paths.shift();
+        if (status != COMM_TIMEOUT && tunnelState->paths.size() > 0) {
+            /* Try another IP of this destination host */
+            AsyncCall::Pointer call = commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone, tunnelState));
+            ConnOpener *cs = new ConnOpener(tunnelState->paths[0], call);
+            cs->setHost(tunnelState->url);
+            cs->connect_timeout = Config.Timeout.connect;
+            cs->start();
+        } 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.fd(), err);
         }
+        return;
+    }
+
+    tunnelState->server.fd(conn->fd);
+    comm_add_close_handler(tunnelState->server.fd(), tunnelServerClosed, tunnelState);
+
+    // TODO: hold the conn. drop these fields.
+    tunnelState->host = conn->getPeer() ? conn->getPeer()->host : xstrdup(request->GetHost());
+    request->peer_host = conn->getPeer() ? conn->getPeer()->host : NULL;
+    tunnelState->port = conn->remote.GetPort();
+
+    if (conn->getPeer()) {
+        tunnelState->request->peer_login = conn->getPeer()->login;
+        tunnelState->request->flags.proxying = 1;
+    } else {
+        tunnelState->request->peer_login = NULL;
+        tunnelState->request->flags.proxying = 0;
+    }
 
-        commSetTimeout(tunnelState->server.fd(),
-                       Config.Timeout.read,
-                       tunnelTimeout,
-                       tunnelState);
+    if (conn->getPeer())
+        tunnelProxyConnected(tunnelState->server.fd(), tunnelState);
+    else {
+        tunnelConnected(tunnelState->server.fd(), tunnelState);
     }
+
+    commSetTimeout(tunnelState->server.fd(), Config.Timeout.read, tunnelTimeout, tunnelState);
 }
 
 void
@@ -606,7 +594,6 @@ tunnelStart(ClientHttpRequest * http, int64_t * size_ptr, int *status_ptr)
 {
     /* Create state structure. */
     TunnelStateData *tunnelState = NULL;
-    int sock;
     ErrorState *err = NULL;
     int answer;
     int fd = http->getConn()->fd;
@@ -639,43 +626,16 @@ tunnelStart(ClientHttpRequest * http, int64_t * size_ptr, int *status_ptr)
     debugs(26, 3, "tunnelStart: '" << RequestMethodStr(request->method) << " " << url << "'");
     statCounter.server.all.requests++;
     statCounter.server.other.requests++;
-    /* Create socket. */
-    Ip::Address temp = getOutgoingAddr(request,NULL);
-    int flags = COMM_NONBLOCKING;
-    if (request->flags.spoof_client_ip) {
-        flags |= COMM_TRANSPARENT;
-    }
-    sock = comm_openex(SOCK_STREAM,
-                       IPPROTO_TCP,
-                       temp,
-                       flags,
-                       getOutgoingTOS(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;
-    }
 
     tunnelState = new TunnelStateData;
 #if DELAY_POOLS
-
     tunnelState->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(),
                            tunnelClientClosed,
                            tunnelState);
@@ -683,14 +643,12 @@ tunnelStart(ClientHttpRequest * http, int64_t * size_ptr, int *status_ptr)
                    Config.Timeout.lifetime,
                    tunnelTimeout,
                    tunnelState);
-    commSetTimeout(tunnelState->server.fd(),
-                   Config.Timeout.connect,
-                   tunnelConnectTimeout,
-                   tunnelState);
-    peerSelect(request,
+
+    peerSelect(&(tunnelState->paths), request,
                NULL,
                tunnelPeerSelectComplete,
                tunnelState);
+
     /*
      * Disable the client read handler until peer selection is complete
      * Take control away from client_side.c.
@@ -727,13 +685,12 @@ tunnelProxyConnected(int fd, void *data)
 }
 
 static void
-tunnelPeerSelectComplete(FwdServer * fs, void *data)
+tunnelPeerSelectComplete(Comm::Paths *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);
         *tunnelState->status_ptr = HTTP_SERVICE_UNAVAILABLE;
@@ -743,40 +700,11 @@ tunnelPeerSelectComplete(FwdServer * fs, void *data)
         return;
     }
 
-    tunnelState->servers = fs;
-    tunnelState->host = fs->_peer ? 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 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));
+    ConnOpener *cs = new ConnOpener(tunnelState->paths[0], call);
+    cs->setHost(tunnelState->url);
+    cs->connect_timeout = Config.Timeout.connect;
+    cs->start();
 }
 
 CBDATA_CLASS_INIT(TunnelStateData);
index 73034c75e7ed7cb6de8955f5eccd7a0a1deebdb1..c4dcb3391d3e7ffa6759a29e4f046ee8e09009dd 100644 (file)
@@ -196,8 +196,6 @@ typedef void IDCB(const char *ident, void *data);
 typedef void IPH(const ipcache_addrs *, const DnsLookupDetails &details, void *);
 typedef void IRCB(struct peer *, peer_t, protocol_t, void *, void *data);
 
-class FwdServer;
-typedef void PSC(FwdServer *, void *);
 typedef void RH(void *data, char *);
 /* in wordlist.h */
 
index 9f0f5147987feac0137ea8f5eb3a19abf80b5138..86a8fe49dc782585a7ed8ebc75553214eb94e871 100644 (file)
  *
  */
 #include "squid.h"
-#include "comm.h"
-#include "event.h"
 
 #if USE_WCCP
 
+#include "comm.h"
+#include "comm/Connection.h"
+#include "event.h"
+
 #define WCCP_PORT 2048
 #define WCCP_REVISION 0
 #define WCCP_ACTIVE_CACHES 32
index d4769339d0d2583c96024a39476c097a70543a4b..199d7e9624346f64aaae132c690282721f09a43b 100644 (file)
@@ -35,6 +35,7 @@
 #if USE_WCCPv2
 
 #include "comm.h"
+#include "comm/Connection.h"
 #include "compat/strsep.h"
 #include "event.h"
 #include "ip/Address.h"
index d7297c485817eb5df341cf99ca239fac8fa1616b..b148d3ad6bfae94c6b8dde47e30f80f5e5bace93 100644 (file)
@@ -81,7 +81,7 @@ void
 whoisStart(FwdState * fwd)
 {
     WhoisState *p;
-    int fd = fwd->server_fd;
+    int fd = fwd->conn()->fd;
     char *buf;
     size_t l;
     CBDATA_INIT_TYPE(WhoisState);