]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Code fixes from second audit
authorAmos Jeffries <squid3@treenet.co.nz>
Mon, 19 Jul 2010 13:18:06 +0000 (01:18 +1200)
committerAmos Jeffries <squid3@treenet.co.nz>
Mon, 19 Jul 2010 13:18:06 +0000 (01:18 +1200)
15 files changed:
src/adaptation/icap/Xaction.cc
src/comm/ConnOpener.cc
src/comm/ConnOpener.h
src/comm/Connection.cc
src/comm/Connection.h
src/comm/ListenStateData.h
src/forward.cc
src/forward.h
src/ftp.cc
src/gopher.cc
src/http.cc
src/ident/AclIdent.cc
src/peer_select.cc
src/tunnel.cc
src/whois.cc

index c16782fe04fd63c77966d9500a7d72a44218045f..6f743b22475ac83cf74491498b5a1b1fad345624 100644 (file)
@@ -180,6 +180,7 @@ void Adaptation::Icap::Xaction::closeConnection()
             debugs(93,3, HERE << "closing pconn" << status());
             // comm_close will clear timeout
             connection->close();
+            connection = NULL;
         }
 
         writer = NULL;
index 4a8f97eaa5aa9b7881d6ea8d6ab304fe15766c30..706e7539cbd9f55c04c6d68b4d12f04ffe3ca74a 100644 (file)
@@ -17,64 +17,57 @@ namespace Comm {
 
 Comm::ConnOpener::ConnOpener(Comm::ConnectionPointer &c, AsyncCall::Pointer &handler, time_t ctimeout) :
         AsyncJob("Comm::ConnOpener"),
-        connect_timeout(ctimeout),
-        host(NULL),
-        solo(c),
-        callback(handler),
-        total_tries(0),
-        fail_retries(0),
-        connstart(0)
-{
-    memset(&calls, 0, sizeof(calls));
-}
+        host_(NULL),
+        conn_(c),
+        callback_(handler),
+        totalTries_(0),
+        failRetries_(0),
+        connectTimeout_(ctimeout),
+        connStart_(0)
+{}
 
 Comm::ConnOpener::~ConnOpener()
 {
-    safe_free(host);
-    solo = NULL;
-    calls.earlyabort = NULL;
-    calls.timeout = NULL;
+    safe_free(host_);
 }
 
 bool
 Comm::ConnOpener::doneAll() const
 {
-    // is the conn to be opened still waiting?
-    if (solo != NULL) {
-        debugs(5, 6, HERE << " Comm::ConnOpener::doneAll() ? NO. 'solo' is still set");
+    // is the conn_ to be opened still waiting?
+    if (conn_ != NULL) {
         return false;
     }
 
     // is the callback still to be called?
-    if (callback != NULL) {
-        debugs(5, 6, HERE << " Comm::ConnOpener::doneAll() ? NO. callback is still set");
+    if (callback_ != NULL) {
         return false;
     }
 
-    debugs(5, 6, HERE << " Comm::ConnOpener::doneAll() ? YES.");
-    return true;
+    return AsyncJob::doneAll();
 }
 
 void
 Comm::ConnOpener::swanSong()
 {
     // cancel any event watchers
-    if (calls.earlyabort != NULL) {
-        calls.earlyabort->cancel("Comm::ConnOpener::swanSong");
-        calls.earlyabort = NULL;
+    // done here to get the "swanSong" mention in cancel debugging.
+    if (calls_.earlyAbort_ != NULL) {
+        calls_.earlyAbort_->cancel("Comm::ConnOpener::swanSong");
+        calls_.earlyAbort_ = NULL;
     }
-    if (calls.timeout != NULL) {
-        calls.timeout->cancel("Comm::ConnOpener::swanSong");
-        calls.timeout = NULL;
+    if (calls_.timeout_ != NULL) {
+        calls_.timeout_->cancel("Comm::ConnOpener::swanSong");
+        calls_.timeout_ = NULL;
     }
 
     // recover what we can from the job
-    if (solo != NULL && solo->fd > -1) {
+    if (conn_ != NULL && conn_->isOpen()) {
         // it never reached fully open, so abort the FD
-        close(solo->fd);
-        fd_table[solo->fd].flags.open = 0;
+        conn_->close();
+        fd_table[conn_->fd].flags.open = 0;
         // inform the caller
-        callCallback(COMM_ERR_CONNECT, 0);
+        doneConnecting(COMM_ERR_CONNECT, 0);
     }
 }
 
@@ -82,110 +75,113 @@ void
 Comm::ConnOpener::setHost(const char * new_host)
 {
     // unset and erase if already set.
-    if (host != NULL)
-        safe_free(host);
+    if (host_ != NULL)
+        safe_free(host_);
 
     // set the new one if given.
     if (new_host != NULL)
-        host = xstrdup(new_host);
+        host_ = xstrdup(new_host);
 }
 
 const char *
 Comm::ConnOpener::getHost() const
 {
-    return host;
+    return host_;
 }
 
+/**
+ * Connection attempt are completed. One way or the other.
+ * Pass the results back to the external handler.
+ */
 void
-Comm::ConnOpener::callCallback(comm_err_t status, int xerrno)
+Comm::ConnOpener::doneConnecting(comm_err_t status, int xerrno)
 {
     /* remove handlers we don't want to happen anymore */
-    if (solo != NULL && solo->fd > 0) {
-        if (calls.earlyabort != NULL) {
-            comm_remove_close_handler(solo->fd, calls.earlyabort);
-            calls.earlyabort->cancel("Comm::ConnOpener completed.");
-            calls.earlyabort = NULL;
+    if (conn_ != NULL && conn_->isOpen()) {
+        if (calls_.earlyAbort_ != NULL) {
+            comm_remove_close_handler(conn_->fd, calls_.earlyAbort_);
+            calls_.earlyAbort_->cancel("Comm::ConnOpener completed.");
+            calls_.earlyAbort_ = NULL;
         }
-        if (calls.timeout != NULL) {
-            commSetTimeout(solo->fd, -1, NULL, NULL);
-            calls.timeout->cancel("Comm::ConnOpener completed.");
-            calls.timeout = NULL;
+        if (calls_.timeout_ != NULL) {
+            commSetTimeout(conn_->fd, -1, NULL, NULL);
+            calls_.timeout_->cancel("Comm::ConnOpener completed.");
+            calls_.timeout_ = NULL;
         }
     }
 
-    if (callback != NULL) {
+    if (callback_ != NULL) {
         typedef CommConnectCbParams Params;
-        Params &params = GetCommParams<Params>(callback);
-        params.conn = solo;
+        Params &params = GetCommParams<Params>(callback_);
+        params.conn = conn_;
         params.flag = status;
         params.xerrno = xerrno;
-        ScheduleCallHere(callback);
-        callback = NULL;
+        ScheduleCallHere(callback_);
+        callback_ = NULL;
     }
 
     /* ensure cleared local state, we are done. */
-    solo = NULL;
-
-    assert(doneAll());
+    conn_ = NULL;
 }
 
+/** Actual start opening a TCP connection. */
 void
 Comm::ConnOpener::start()
 {
-    Must(solo != NULL);
+    Must(conn_ != NULL);
 
-    /* handle connecting to one single path */
-    if (solo->fd < 0) {
+    /* get a socket open ready for connecting with */
+    if (!conn_->isOpen()) {
 #if USE_IPV6
         /* outbound sockets have no need to be protocol agnostic. */
-        if (solo->local.IsIPv6() && solo->local.IsIPv4()) {
-            solo->local.SetIPv4();
+        if (conn_->remote.IsIPv4()) {
+            conn_->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);
+        conn_->fd = comm_openex(SOCK_STREAM, IPPROTO_TCP, conn_->local, conn_->flags, conn_->tos, host_);
+        if (!conn_->isOpen()) {
+            doneConnecting(COMM_ERR_CONNECT, 0);
             return;
         }
 
-        if (calls.earlyabort == NULL) {
+        if (calls_.earlyAbort_ == NULL) {
             typedef CommCbMemFunT<Comm::ConnOpener, CommConnectCbParams> Dialer;
-            calls.earlyabort = asyncCall(5, 4, "Comm::ConnOpener::earlyAbort",
+            calls_.earlyAbort_ = asyncCall(5, 4, "Comm::ConnOpener::earlyAbort",
                                          Dialer(this, &Comm::ConnOpener::earlyAbort));
         }
-        comm_add_close_handler(solo->fd, calls.earlyabort);
+        comm_add_close_handler(conn_->fd, calls_.earlyAbort_);
 
-        if (calls.timeout == NULL) {
+        if (calls_.timeout_ == NULL) {
             typedef CommCbMemFunT<Comm::ConnOpener, CommTimeoutCbParams> Dialer;
-            calls.timeout = asyncCall(5, 4, "Comm::ConnOpener::timeout",
+            calls_.timeout_ = asyncCall(5, 4, "Comm::ConnOpener::timeout",
                                       Dialer(this, &Comm::ConnOpener::timeout));
         }
-        debugs(5, 3, HERE << "FD " << solo->fd << " timeout " << connect_timeout);
-        commSetTimeout(solo->fd, connect_timeout, calls.timeout);
+        debugs(5, 3, HERE << "FD " << conn_->fd << " timeout " << connectTimeout_);
+        commSetTimeout(conn_->fd, connectTimeout_, calls_.timeout_);
 
-        if (connstart == 0) {
-            connstart = squid_curtime;
+        if (connStart_ == 0) {
+            connStart_ = squid_curtime;
         }
     }
 
-    total_tries++;
+    totalTries_++;
 
-    switch (comm_connect_addr(solo->fd, solo->remote) ) {
+    switch (comm_connect_addr(conn_->fd, conn_->remote) ) {
 
     case COMM_INPROGRESS:
         // 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);
+        if(squid_curtime - connStart_ > connectTimeout_) {
+            debugs(5, 5, HERE << "FD " << conn_->fd << ": * - ERR took too long already.");
+            doneConnecting(COMM_TIMEOUT, errno);
             return;
         } else {
-            debugs(5, 5, HERE << "FD " << solo->fd << ": COMM_INPROGRESS");
-            commSetSelect(solo->fd, COMM_SELECT_WRITE, Comm::ConnOpener::ConnectRetry, this, 0);
+            debugs(5, 5, HERE << "FD " << conn_->fd << ": COMM_INPROGRESS");
+            commSetSelect(conn_->fd, COMM_SELECT_WRITE, Comm::ConnOpener::ConnectRetry, this, 0);
         }
         break;
 
     case COMM_OK:
-        debugs(5, 5, HERE << "FD " << solo->fd << ": COMM_OK - connected");
+        debugs(5, 5, HERE << "FD " << conn_->fd << ": COMM_OK - connected");
 
         /*
          * stats.conn_open is used to account for the number of
@@ -193,68 +189,81 @@ Comm::ConnOpener::start()
          * 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++;
+        if (conn_->getPeer())
+            conn_->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.
          *       Also, legacy code still depends on comm_local_port() with no access to Comm::Connection
          *       when those are done comm_local_port can become one of our member functions to do the below.
          */
-        fd_table[solo->fd].flags.open = 1;
-        solo->local.SetPort(comm_local_port(solo->fd));
-        if (solo->local.IsAnyAddr()) {
-            solo->local = fd_table[solo->fd].local_addr;
+        fd_table[conn_->fd].flags.open = 1;
+        conn_->local.SetPort(comm_local_port(conn_->fd));
+        if (conn_->local.IsAnyAddr()) {
+            conn_->local = fd_table[conn_->fd].local_addr;
         }
 
-        if (host != NULL)
-            ipcacheMarkGoodAddr(host, solo->remote);
-        callCallback(COMM_OK, 0);
+        if (host_ != NULL)
+            ipcacheMarkGoodAddr(host_, conn_->remote);
+        doneConnecting(COMM_OK, 0);
         break;
 
     default:
-        debugs(5, 5, HERE "FD " << solo->fd << ": * - try again");
-        fail_retries++;
-        if (host != NULL)
-            ipcacheMarkBadAddr(host, solo->remote);
+        debugs(5, 5, HERE "FD " << conn_->fd << ": * - try again");
+        failRetries_++;
+        if (host_ != NULL)
+            ipcacheMarkBadAddr(host_, conn_->remote);
 #if USE_ICMP
         if (Config.onoff.test_reachability)
-            netdbDeleteAddrNetwork(solo->remote);
+            netdbDeleteAddrNetwork(conn_->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) {
+        if(squid_curtime - connStart_ > connectTimeout_) {
+            debugs(5, 5, HERE << "FD " << conn_->fd << ": * - ERR took too long already.");
+            doneConnecting(COMM_TIMEOUT, errno);
+        } else if (failRetries_ < 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);
+            debugs(5, 5, HERE << "FD " << conn_->fd << ": * - ERR tried too many times already.");
+            doneConnecting(COMM_ERR_CONNECT, errno);
         }
     }
 }
 
+/** Abort connection attempt.
+ * Handles the case(s) when a partially setup connection gets closed early.
+ */
 void
 Comm::ConnOpener::earlyAbort(const CommConnectCbParams &io)
 {
     debugs(5, 3, HERE << "FD " << io.conn->fd);
-    callCallback(COMM_ERR_CLOSING, io.xerrno); // NP: is closing or shutdown better?
+    doneConnecting(COMM_ERR_CLOSING, io.xerrno); // NP: is closing or shutdown better?
 }
 
+/** Make an FD connection attempt.
+ * Handles the case(s) when a partially setup connection gets closed early.
+ */
 void
 Comm::ConnOpener::connect(const CommConnectCbParams &unused)
 {
     start();
 }
 
+/**
+ * Handles the case(s) when a partially setup connection gets timed out.
+ * NP: When commSetTimeout accepts generic CommCommonCbParams this can die.
+ */
 void
 Comm::ConnOpener::timeout(const CommTimeoutCbParams &unused)
 {
     start();
 }
 
+/* Legacy Wrapper for the retry event after COMM_INPROGRESS
+ * TODO: As soon as comm IO accepts Async calls we can use a ConnOpener::connect call
+ */
 void
 Comm::ConnOpener::ConnectRetry(int fd, void *data)
 {
index 9060728042589f8f642a80f80a2b18ab6041bba1..42da32eddfdfb5a8001c9942e73e3be371c03ce0 100644 (file)
@@ -15,17 +15,12 @@ namespace Comm {
  */
 class ConnOpener : public AsyncJob
 {
-public:
-    // ****** AsynJob API implementation ******
-
-    /** Actual start opening a TCP connection. */
-    void start();
-
-    virtual bool doneAll() const;
+protected:
+    virtual void start();
     virtual void swanSong();
 
 public:
-    // ****** ConnOpener API iplementation ******
+    virtual bool doneAll() const;
 
     /** attempt to open a connection. */
     ConnOpener(Comm::ConnectionPointer &, AsyncCall::Pointer &handler, time_t connect_timeout);
@@ -38,55 +33,36 @@ 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);
+    ConnOpener operator =(const ConnOpener &c);
 
-    /** Make an FD connection attempt.
-     * Handles the case(s) when a partially setup connection gets closed early.
-     */
     void connect(const CommConnectCbParams &unused);
-
-    /** Abort connection attempt.
-     * Handles the case(s) when a partially setup connection gets closed early.
-     */
     void earlyAbort(const CommConnectCbParams &);
-
-    /**
-     * Handles the case(s) when a partially setup connection gets timed out.
-     * NP: When commSetTimeout accepts generic CommCommonCbParams this can die.
-     */
     void timeout(const CommTimeoutCbParams &unused);
-
-    /**
-     * 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);
-
-    // Legacy Wrapper for the retry event after COMM_INPROGRESS
-    // As soon as comm IO accepts Async calls we can use a ConnOpener::connect call
+    void doneConnecting(comm_err_t status, int xerrno);
     static void ConnectRetry(int fd, void *data);
 
 private:
+    char *host_;                         ///< domain name we are trying to connect to.
+    Comm::ConnectionPointer conn_;       ///< single connection currently being opened.
+    AsyncCall::Pointer callback_;        ///< handler to be called on connection completion.
+
+    int totalTries_;   ///< total number of connection attempts over all destinations so far.
+    int failRetries_;  ///< number of retries current destination has been tried.
+
     /**
      * time at which to abandon the connection.
      * the connection-done callback will be passed COMM_TIMEOUT
      */
-    time_t connect_timeout;
-
-    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.
+    time_t connectTimeout_;
 
-    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.
+    /// time at which this series of connection attempts was started.
+    time_t connStart_;
 
     /// handles to calls which we may need to cancel.
-    struct _calls {
-        AsyncCall::Pointer earlyabort;
-        AsyncCall::Pointer timeout;
-    } calls;
+    struct Calls {
+        AsyncCall::Pointer earlyAbort_;
+        AsyncCall::Pointer timeout_;
+    } calls_;
 
     CBDATA_CLASS2(ConnOpener);
 };
index 1a64c0d6a9f389c8534979db1f6164086ff486a1..0bcf2290849654691a192af0643e7e3bc0d9959b 100644 (file)
@@ -6,7 +6,7 @@
 Comm::Connection::Connection() :
         local(),
         remote(),
-        peer_type(HIER_NONE),
+        peerType(HIER_NONE),
         fd(-1),
         tos(0),
         flags(COMM_NONBLOCKING),
@@ -16,9 +16,7 @@ Comm::Connection::Connection() :
 Comm::Connection::~Connection()
 {
     close();
-    if (_peer) {
-        cbdataReferenceDone(_peer);
-    }
+    cbdataReferenceDone(_peer);
 }
 
 Comm::ConnectionPointer &
@@ -28,7 +26,7 @@ Comm::Connection::copyDetails() const
 
     c->local = local;
     c->remote = remote;
-    c->peer_type = peer_type;
+    c->peerType = peerType;
     c->tos = tos;
     c->flags = flags;
  
@@ -44,9 +42,10 @@ Comm::Connection::copyDetails() const
 void
 Comm::Connection::close()
 {
-    if (isOpen())
+    if (isOpen()) {
         comm_close(fd);
-    fd = -1;
+        fd = -1;
+    }
 }
 
 void
index 3f79d1d1c5d692350d7e66f4455cc917c06bae9c..c32901a3f0fb42f727cecff71cb2dd119ce2dd18 100644 (file)
@@ -77,9 +77,6 @@ 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();
 
@@ -88,15 +85,31 @@ public:
      */
     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); }
 
+    /** 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:
+    /** These objects may not be exactly duplicated. Use copyDetails() instead. */
+    Connection(const Connection &c);
+
+    /** These objects may not be exactly duplicated. Use copyDetails() instead. */
+    Connection & operator =(const Connection &c);
+
+public:
     /** Address/Port for the Squid end of a TCP link. */
     Ip::Address local;
 
@@ -104,7 +117,7 @@ public:
     Ip::Address remote;
 
     /** Hierarchy code for this connection link */
-    hier_code peer_type;
+    hier_code peerType;
 
     /** Socket used by this connection. -1 if no socket has been opened. */
     int fd;
@@ -115,17 +128,6 @@ public:
     /** 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;
index 4b1dda706e8dfdfe2e8830684ac884dcc9d15aa4..7d578e444db4d9d24e5080e34fd214557b437e18 100644 (file)
@@ -13,8 +13,6 @@
 namespace Comm
 {
 
-class Connection;
-
 class ListenStateData
 {
 
index c3e49b7679a2dd314a2374c5beba123fd9f70183..837d654449ffcf7dee684f0bff7fc7bde09a95f4 100644 (file)
@@ -80,8 +80,8 @@ 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->paths.size() > 0 && fwd->paths[0]->isOpen()) {
-        comm_remove_close_handler(fwd->paths[0]->fd, fwdServerClosedWrapper, fwd);
+    if (fwd->isServerConnectionOpen()) {
+        comm_remove_close_handler(fwd->serverConnection()->fd, fwdServerClosedWrapper, fwd);
     }
     fwd->paths.clean();
     fwd->self = NULL;
@@ -170,10 +170,10 @@ FwdState::~FwdState()
 
     entry = NULL;
 
-    if (paths.size() > 0 && paths[0]->isOpen()) {
-        comm_remove_close_handler(paths[0]->fd, fwdServerClosedWrapper, this);
-        debugs(17, 3, HERE << "closing FD " << paths[0]->fd);
-        paths[0]->close();
+    if (isServerConnectionOpen()) {
+        comm_remove_close_handler(serverConnection()->fd, fwdServerClosedWrapper, this);
+        debugs(17, 3, HERE << "closing FD " << serverConnection()->fd);
+        serverConnection()->close();
     }
 
     paths.clean();
@@ -295,12 +295,23 @@ FwdState::fail(ErrorState * errorState)
  * Frees fwdState without closing FD or generating an abort
  */
 void
+FwdState::unregister(Comm::ConnectionPointer conn)
+{
+    debugs(17, 3, HERE << entry->url() );
+    assert(serverConnection() == conn);
+    assert(conn->isOpen());
+    comm_remove_close_handler(conn->fd, fwdServerClosedWrapper, this);
+}
+
+// Legacy method to be removed in favor of the above as soon as possible
+void
 FwdState::unregister(int fd)
 {
-    debugs(17, 3, HERE << entry->url()  );
-    assert(fd == paths[0]->fd);
+    debugs(17, 3, HERE << entry->url() );
+    assert(fd == serverConnection()->fd);
     assert(fd > -1);
     comm_remove_close_handler(fd, fwdServerClosedWrapper, this);
+    serverConnection()->fd = -1;
 }
 
 /**
@@ -324,8 +335,8 @@ FwdState::complete()
     if (reforward()) {
         debugs(17, 3, HERE << "re-forwarding " << entry->getReply()->sline.status << " " << entry->url());
 
-        if (paths[0]->fd > -1)
-            unregister(paths[0]->fd);
+        if (isServerConnectionOpen())
+            unregister(serverConnection());
 
         entry->reset();
 
@@ -334,11 +345,11 @@ FwdState::complete()
          */
         connectStart();
     } else {
-        debugs(17, 3, HERE << "server FD " << paths[0]->fd << " not re-forwarding status " << entry->getReply()->sline.status);
+        debugs(17, 3, HERE << "server FD " << serverConnection()->fd << " not re-forwarding status " << entry->getReply()->sline.status);
         EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
         entry->complete();
 
-        if (paths[0]->fd < 0)
+        if (!isServerConnectionOpen())
             completed();
 
         self = NULL; // refcounted
@@ -476,10 +487,10 @@ void
 FwdState::serverClosed(int fd)
 {
     debugs(17, 2, HERE << "FD " << fd << " " << entry->url());
-    assert(paths[0]->fd == fd);
+    assert(serverConnection()->fd == fd);
 
-    if (paths[0]->getPeer()) {
-        paths[0]->getPeer()->stats.conn_open--;
+    if (serverConnection()->getPeer()) {
+        serverConnection()->getPeer()->stats.conn_open--;
     }
 
     retryOrBail();
@@ -525,7 +536,7 @@ void
 FwdState::handleUnregisteredServerEnd()
 {
     debugs(17, 2, HERE << "self=" << self << " err=" << err << ' ' << entry->url());
-    assert(paths[0]->fd < 0);
+    assert(!isServerConnectionOpen());
     retryOrBail();
 }
 
@@ -564,21 +575,21 @@ FwdState::negotiateSSL(int fd)
 
             fail(anErr);
 
-            if (paths[0]->getPeer()) {
-                peerConnectFailed(paths[0]->getPeer());
-                paths[0]->getPeer()->stats.conn_open--;
+            if (serverConnection()->getPeer()) {
+                peerConnectFailed(serverConnection()->getPeer());
+                serverConnection()->getPeer()->stats.conn_open--;
             }
 
-            paths[0]->close();
+            serverConnection()->close();
             return;
         }
     }
 
-    if (paths[0]->getPeer() && !SSL_session_reused(ssl)) {
-        if (paths[0]->getPeer()->sslSession)
-            SSL_SESSION_free(paths[0]->getPeer()->sslSession);
+    if (serverConnection()->getPeer() && !SSL_session_reused(ssl)) {
+        if (serverConnection()->getPeer()->sslSession)
+            SSL_SESSION_free(serverConnection()->getPeer()->sslSession);
 
-        paths[0]->getPeer()->sslSession = SSL_get1_session(ssl);
+        serverConnection()->getPeer()->sslSession = SSL_get1_session(ssl);
     }
 
     dispatch();
@@ -589,8 +600,8 @@ FwdState::initiateSSL()
 {
     SSL *ssl;
     SSL_CTX *sslContext = NULL;
-    const peer *peer = paths[0]->getPeer();
-    int fd = paths[0]->fd;
+    const peer *peer = serverConnection()->getPeer();
+    int fd = serverConnection()->fd;
 
     if (peer) {
         assert(peer->use_ssl);
@@ -659,32 +670,32 @@ FwdState::connectDone(Comm::ConnectionPointer &conn, comm_err_t status, int xerr
 
         /* it might have been a timeout with a partially open link */
         if (paths.size() > 0) {
-            if (paths[0]->getPeer())
-                peerConnectFailed(paths[0]->getPeer());
+            if (serverConnection()->getPeer())
+                peerConnectFailed(serverConnection()->getPeer());
 
-            paths[0]->close();
+            serverConnection()->close();
         }
         retryOrBail();
         return;
     }
 
 #if REDUNDANT_NOW
-    if (Config.onoff.log_ip_on_direct && paths[0]->peer_type == HIER_DIRECT)
+    if (Config.onoff.log_ip_on_direct && serverConnection()->peerType == HIER_DIRECT)
         updateHierarchyInfo();
 #endif
 
-    debugs(17, 3, "FD " << paths[0]->fd << ": '" << entry->url() << "'" );
+    debugs(17, 3, "FD " << serverConnection()->fd << ": '" << entry->url() << "'" );
 
-    comm_add_close_handler(paths[0]->fd, fwdServerClosedWrapper, this);
+    comm_add_close_handler(serverConnection()->fd, fwdServerClosedWrapper, this);
 
-    if (paths[0]->getPeer())
-        peerConnectSucceded(paths[0]->getPeer());
+    if (serverConnection()->getPeer())
+        peerConnectSucceded(serverConnection()->getPeer());
 
     updateHierarchyInfo();
 
 #if USE_SSL
-    if ((paths[0]->getPeer() && paths[0]->getPeer()->use_ssl) ||
-            (!paths[0]->getPeer() && request->protocol == PROTO_HTTPS)) {
+    if ((serverConnection()->getPeer() && serverConnection()->getPeer()->use_ssl) ||
+            (!serverConnection()->getPeer() && request->protocol == PROTO_HTTPS)) {
         initiateSSL();
         return;
     }
@@ -697,9 +708,9 @@ void
 FwdState::connectTimeout(int fd)
 {
     debugs(17, 2, "fwdConnectTimeout: FD " << fd << ": '" << entry->url() << "'" );
-    assert(fd == paths[0]->fd);
+    assert(fd == serverConnection()->fd);
 
-    if (Config.onoff.log_ip_on_direct && paths[0]->peer_type == HIER_DIRECT)
+    if (Config.onoff.log_ip_on_direct && serverConnection()->peerType == HIER_DIRECT)
         updateHierarchyInfo();
 
     if (entry->isEmpty()) {
@@ -709,11 +720,11 @@ FwdState::connectTimeout(int fd)
 
         /* This marks the peer DOWN ... */
         if (paths.size() > 0)
-            if (paths[0]->getPeer())
-                peerConnectFailed(paths[0]->getPeer());
+            if (serverConnection()->getPeer())
+                peerConnectFailed(serverConnection()->getPeer());
     }
 
-    paths[0]->close();
+    serverConnection()->close();
 }
 
 /**
@@ -729,12 +740,11 @@ FwdState::connectStart()
     if (n_tries == 0) // first attempt
         request->hier.first_conn_start = current_time;
 
-    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;
+    if (serverConnection()->getPeer()) {
+        ctimeout = serverConnection()->getPeer()->connect_timeout > 0 ?
+                   serverConnection()->getPeer()->connect_timeout : Config.Timeout.peer_connect;
     } else {
         ctimeout = Config.Timeout.connect;
     }
@@ -748,21 +758,22 @@ FwdState::connectStart()
         ctimeout = ftimeout;
 
     request->flags.pinned = 0;
-    if (conn->peer_type == PINNED) {
+    if (serverConnection()->peerType == PINNED) {
         ConnStateData *pinned_connection = request->pinnedConnection();
         assert(pinned_connection);
-        conn->fd = pinned_connection->validatePinnedConnection(request, conn->getPeer());
-        if (conn->isOpen()) {
+        serverConnection()->fd = pinned_connection->validatePinnedConnection(request, serverConnection()->getPeer());
+        if (isServerConnectionOpen()) {
             pinned_connection->unpinConnection();
 #if 0
-            if (!conn->getPeer())
-                conn->peer_type = HIER_DIRECT;
+            if (!serverConnection()->getPeer())
+                serverConnection()->peerType = HIER_DIRECT;
 #endif
             n_tries++;
             request->flags.pinned = 1;
             if (pinned_connection->pinnedAuth())
                 request->flags.auth = 1;
             updateHierarchyInfo();
+            Comm::ConnectionPointer conn = serverConnection();
             FwdState::connectDone(conn, COMM_OK, 0);
             return;
         }
@@ -770,7 +781,6 @@ FwdState::connectStart()
         debugs(17,2,HERE << " Pinned connection " << pinned_connection << " not valid. Releasing.");
         request->releasePinnedConnection();
         paths.shift();
-        conn = NULL; // maybe release the conn memory. it's not needed by us anyway.
         connectStart();
         return;
     }
@@ -783,27 +793,30 @@ FwdState::connectStart()
 
     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());
+    if (serverConnection()->getPeer()) {
+        host = serverConnection()->getPeer()->host;
+        port = serverConnection()->getPeer()->http_port;
+        serverConnection()->fd = fwdPconnPool->pop(serverConnection()->getPeer()->name,
+                                                   serverConnection()->getPeer()->http_port,
+                                                   request->GetHost(), serverConnection()->local,
+                                                   checkRetriable());
     } else {
         host = request->GetHost();
         port = request->port;
-        conn->fd = fwdPconnPool->pop(host, port, NULL, conn->local, checkRetriable());
+        serverConnection()->fd = fwdPconnPool->pop(host, port, NULL, serverConnection()->local, checkRetriable());
     }
-    conn->remote.SetPort(port);
+    serverConnection()->remote.SetPort(port);
 
-    if (conn->isOpen()) {
-        debugs(17, 3, HERE << "reusing pconn FD " << conn->fd);
+    if (isServerConnectionOpen()) {
+        debugs(17, 3, HERE << "reusing pconn FD " << serverConnection()->fd);
         n_tries++;
 
-        if (!conn->getPeer())
+        if (!serverConnection()->getPeer())
             origin_tries++;
 
         updateHierarchyInfo();
 
-        comm_add_close_handler(conn->fd, fwdServerClosedWrapper, this);
+        comm_add_close_handler(serverConnection()->fd, fwdServerClosedWrapper, this);
 
         dispatch();
         return;
@@ -814,7 +827,8 @@ FwdState::connectStart()
 #endif
 
     AsyncCall::Pointer call = commCbCall(17,3, "fwdConnectDoneWrapper", CommConnectCbPtrFun(fwdConnectDoneWrapper, this));
-    Comm::ConnOpener *cs = new Comm::ConnOpener(paths[0], call, ctimeout);
+    Comm::ConnectionPointer conn = serverConnection();
+    Comm::ConnOpener *cs = new Comm::ConnOpener(conn, call, ctimeout);
     cs->setHost(host);
     AsyncJob::AsyncStart(cs);
 }
@@ -828,11 +842,11 @@ FwdState::dispatch()
      * is attached to something and will be deallocated when server_fd
      * is closed.
      */
-    assert(paths.size() > 0 && paths[0]->fd > -1);
+    assert(isServerConnectionOpen());
 
-    fd_note(paths[0]->fd, entry->url());
+    fd_note(serverConnection()->fd, entry->url());
 
-    fd_table[paths[0]->fd].noteUse(fwdPconnPool);
+    fd_table[serverConnection()->fd].noteUse(fwdPconnPool);
 
     /*assert(!EBIT_TEST(entry->flags, ENTRY_DISPATCHED)); */
     assert(entry->ping_status != PING_WAITING);
@@ -855,10 +869,10 @@ FwdState::dispatch()
         int tos = 1;
         int tos_len = sizeof(tos);
         clientFde->upstreamTOS = 0;
-        if (setsockopt(paths[0]->fd,SOL_IP,IP_RECVTOS,&tos,tos_len)==0) {
+        if (setsockopt(serverConnection()->fd, SOL_IP, IP_RECVTOS, &tos, tos_len)==0) {
             unsigned char buf[512];
             int len = 512;
-            if (getsockopt(paths[0]->fd,SOL_IP,IP_PKTOPTIONS,buf,(socklen_t*)&len) == 0) {
+            if (getsockopt(serverConnection()->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.
@@ -877,18 +891,18 @@ FwdState::dispatch()
                     pbuf += CMSG_LEN(o->cmsg_len);
                 }
             } else {
-                debugs(33, DBG_IMPORTANT, "ZPH: error in getsockopt(IP_PKTOPTIONS) on FD " << paths[0]->fd << " " << xstrerror());
+                debugs(33, DBG_IMPORTANT, "ZPH: error in getsockopt(IP_PKTOPTIONS) on FD " << serverConnection()->fd << " " << xstrerror());
             }
         } else {
-            debugs(33, DBG_IMPORTANT, "ZPH: error in setsockopt(IP_RECVTOS) on FD " << paths[0]->fd << " " << xstrerror());
+            debugs(33, DBG_IMPORTANT, "ZPH: error in setsockopt(IP_RECVTOS) on FD " << serverConnection()->fd << " " << xstrerror());
         }
     }
 #endif
 
-    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;
+    if (serverConnection()->getPeer() != NULL) {
+        serverConnection()->getPeer()->stats.fetches++;
+        request->peer_login = serverConnection()->getPeer()->login;
+        request->peer_domain = serverConnection()->getPeer()->domain;
         httpStart(this);
     } else {
         request->peer_login = NULL;
@@ -943,7 +957,7 @@ FwdState::dispatch()
              * transient (network) error; its a bug.
              */
             flags.dont_retry = 1;
-            paths[0]->close();
+            serverConnection()->close();
             break;
         }
     }
@@ -1137,23 +1151,23 @@ FwdState::updateHierarchyInfo()
 
     assert(paths.size() > 0);
 
-    char nextHop[256]; // 
+    char nextHop[256];
 
-    if (paths[0]->getPeer()) {
+    if (serverConnection()->getPeer()) {
         // went to peer, log peer host name
-        snprintf(nextHop,256,"%s", paths[0]->getPeer()->name);
+        snprintf(nextHop,256,"%s", serverConnection()->getPeer()->name);
     } else {
         // went DIRECT, must honor log_ip_on_direct
         if (!Config.onoff.log_ip_on_direct)
             snprintf(nextHop,256,"%s",request->GetHost()); // domain name
         else
-            paths[0]->remote.NtoA(nextHop, 256);
+            serverConnection()->remote.NtoA(nextHop, 256);
     }
 
-    request->hier.peer_local_port = paths[0]->local.GetPort();
+    request->hier.peer_local_port = serverConnection()->local.GetPort();
 
     assert(nextHop[0]);
-    hierarchyNote(&request->hier, paths[0]->peer_type, nextHop);
+    hierarchyNote(&request->hier, serverConnection()->peerType, nextHop);
 }
 
 
index 11178f1d02cd84e0009a7f8fde1c83b2aa8a2ddd..8af66c41dcceb44722544e01243bfb4b3179fce1 100644 (file)
@@ -21,6 +21,7 @@ public:
     static void fwdStart(int fd, StoreEntry *, HttpRequest *);
     void startComplete();
     void fail(ErrorState *err);
+    void unregister(Comm::ConnectionPointer conn);
     void unregister(int fd);
     void complete();
     void handleUnregisteredServerEnd();
@@ -45,7 +46,11 @@ public:
 
     void ftpPasvFailed(bool val) { flags.ftp_pasv_failed = val; }
 
-    Comm::ConnectionPointer conn() const { return paths[0]; };
+    /** return a ConnectionPointer to the current server connection (may or may not be open) */
+    Comm::ConnectionPointer serverConnection() const { assert(paths.size() > 0); return paths[0]; };
+
+    /** test if the current server connection is open */
+    bool isServerConnectionOpen() const { return (paths.size() > 0 && serverConnection()->isOpen()); };
 
 private:
     // hidden for safer management of self; use static fwdStart
@@ -88,7 +93,7 @@ private:
         unsigned int forward_completed:1;
     } flags;
 
-    /** possible paths which may be tried (in sequence stored) */
+    /** connections to open, in order, until successful */
     Comm::Paths paths;
 
     // NP: keep this last. It plays with private/public
index f949ddeec1195ad71eeec0f908746e94dbed496c..bdc6699a3500325bea18eaa59ceb4fce50fa216c 100644 (file)
@@ -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->conn()->fd, closer);
+    ctrl.opened(theFwdState->serverConnection()->fd, closer);
 
     if (request->method == METHOD_PUT)
         flags.put = 1;
index 35d695fc1060d1968a25d64cc1c19bb3dfa30641..1d495092b581ea25d629cba1d3e465c800a21173 100644 (file)
@@ -1011,7 +1011,7 @@ gopherStart(FwdState * fwd)
     gopher_request_parse(fwd->request,
                          &gopherState->type_id, gopherState->request);
 
-    comm_add_close_handler(fwd->conn()->fd, gopherStateFree, gopherState);
+    comm_add_close_handler(fwd->serverConnection()->fd, gopherStateFree, gopherState);
 
     if (((gopherState->type_id == GOPHER_INDEX) || (gopherState->type_id == GOPHER_CSO))
             && (strchr(gopherState->request, '?') == NULL)) {
@@ -1031,12 +1031,11 @@ gopherStart(FwdState * fwd)
 
         gopherToHTML(gopherState, (char *) NULL, 0);
         fwd->complete();
-        fwd->conn()->close();
         return;
     }
 
-    gopherState->fd = fwd->conn()->fd; // TODO: save the conn() in gopher instead of the FD
+    gopherState->fd = fwd->serverConnection()->fd; // TODO: save the serverConnection() in gopher instead of the FD
     gopherState->fwd = fwd;
-    gopherSendRequest(fwd->conn()->fd, gopherState);
-    commSetTimeout(fwd->conn()->fd, Config.Timeout.read, gopherTimeout, gopherState);
+    gopherSendRequest(fwd->serverConnection()->fd, gopherState);
+    commSetTimeout(fwd->serverConnection()->fd, Config.Timeout.read, gopherTimeout, gopherState);
 }
index 112aaf11130138a6df7338becd441d2f2327178c..ec3d29538ebd4b6ddda69c5b3a360a727b7fc000 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->conn()->fd; // TODO: store Comm::Connection instead of FD
+    fd = fwd->serverConnection()->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->conn() != NULL)
-        _peer = cbdataReference(fwd->conn()->getPeer());         /* might be NULL */
+    if (fwd->serverConnection() != NULL)
+        _peer = cbdataReference(fwd->serverConnection()->getPeer());         /* might be NULL */
 
     if (_peer) {
         const char *url;
@@ -162,6 +162,8 @@ HttpStateData::~HttpStateData()
 
     HTTPMSGUNLOCK(orig_request);
 
+    cbdataReferenceDone(_peer);
+
     debugs(11,5, HERE << "HttpStateData " << this << " destroyed; FD " << fd);
 }
 
@@ -1360,7 +1362,7 @@ HttpStateData::processReplyBody()
                 orig_request->pinnedConnection()->pinConnection(fd, orig_request, _peer,
                         (request->flags.connection_auth != 0));
             } else {
-                fwd->pconnPush(fwd->conn(), _peer, request, orig_request->GetHost(), client_addr);
+                fwd->pconnPush(fwd->serverConnection(), _peer, request, orig_request->GetHost(), client_addr);
             }
 
             fd = -1;
index aa9ecc6b9624e5d865f41a31ac9a3d1c290dd8c4..7cc1a7bc71cb252301de9097ab0d3c600a24ecd9 100644 (file)
@@ -131,11 +131,10 @@ IdentLookup::checkForAsync(ACLChecklist *cl)const
         debugs(28, 3, HERE << "Doing ident lookup" );
         checklist->asyncInProgress(true);
         // 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);
+        Comm::ConnectionPointer cc = new Comm::Connection;
+        cc->local = checklist->conn()->me;
+        cc->remote = checklist->conn()->peer;
+        Ident::Start(cc, LookupDone, checklist);
     } else {
         debugs(28, DBG_IMPORTANT, "IdentLookup::checkForAsync: Can't start ident lookup. No client connection" );
         checklist->currentAnswer(ACCESS_DENIED);
index b38cfebefe2d6bed40ef07e450565cf714d90b21..5bac2340e1768561497db1642a2ee27c4f657685 100644 (file)
@@ -250,9 +250,10 @@ peerSelectDnsResults(const ipcache_addrs *ia, const DnsLookupDetails &details, v
         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++) {
+            Comm::ConnectionPointer p;
+
             if (ip >= ia->count) ip = 0; // looped back to zero.
 
             // Enforce forward_max_tries configuration.
@@ -273,7 +274,7 @@ peerSelectDnsResults(const ipcache_addrs *ia, const DnsLookupDetails &details, v
                 p->remote.SetPort(fs->_peer->http_port);
             else
                 p->remote.SetPort(psstate->request->port);
-            p->peer_type = fs->code;
+            p->peerType = fs->code;
 
             // check for a configured outgoing address for this destination...
             getOutgoingAddress(psstate->request, p);
index e69307e05047277000ab81e6d9e884c51068888c..e1b9f75b6ba543fe9fc9b1a0c9d736eb77a09c50 100644 (file)
@@ -533,11 +533,11 @@ tunnelConnectDone(Comm::ConnectionPointer &conn, comm_err_t status, int xerrno,
 #endif
 
     if (conn != NULL && conn->getPeer())
-        hierarchyNote(&tunnelState->request->hier, conn->peer_type, conn->getPeer()->host);
+        hierarchyNote(&tunnelState->request->hier, conn->peerType, conn->getPeer()->host);
     else if (Config.onoff.log_ip_on_direct)
-        hierarchyNote(&tunnelState->request->hier, conn->peer_type, fd_table[conn->fd].ipaddr);
+        hierarchyNote(&tunnelState->request->hier, conn->peerType, fd_table[conn->fd].ipaddr);
     else
-        hierarchyNote(&tunnelState->request->hier, conn->peer_type, tunnelState->host);
+        hierarchyNote(&tunnelState->request->hier, conn->peerType, tunnelState->host);
 
     if (status != COMM_OK) {
         /* At this point only the TCP handshake has failed. no data has been passed.
index b148d3ad6bfae94c6b8dde47e30f80f5e5bace93..28abe7ef08ecd4381800268664ddabc8a9df9710 100644 (file)
@@ -81,7 +81,7 @@ void
 whoisStart(FwdState * fwd)
 {
     WhoisState *p;
-    int fd = fwd->conn()->fd;
+    int fd = fwd->serverConnection()->fd;
     char *buf;
     size_t l;
     CBDATA_INIT_TYPE(WhoisState);