/* vim:set ts=4 sw=4 sts=4 et cin: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef nsHttpConnectionMgr_h__
#define nsHttpConnectionMgr_h__

#include "nsHttpConnection.h"
#include "nsHttpTransaction.h"
#include "nsTArray.h"
#include "nsThreadUtils.h"
#include "nsClassHashtable.h"
#include "nsDataHashtable.h"
#include "nsAutoPtr.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/Attributes.h"
#include "AlternateServices.h"
#include "ARefBase.h"

#include "nsIObserver.h"
#include "nsITimer.h"

class nsIHttpUpgradeListener;

namespace mozilla {
namespace net {
class EventTokenBucket;
class NullHttpTransaction;
struct HttpRetParams;

//-----------------------------------------------------------------------------

// message handlers have this signature
class nsHttpConnectionMgr;
typedef void (nsHttpConnectionMgr:: *nsConnEventHandler)(int32_t, ARefBase *);

class nsHttpConnectionMgr final : public nsIObserver
                                , public AltSvcCache
{
public:
    NS_DECL_THREADSAFE_ISUPPORTS
    NS_DECL_NSIOBSERVER

    // parameter names
    enum nsParamName {
        MAX_CONNECTIONS,
        MAX_PERSISTENT_CONNECTIONS_PER_HOST,
        MAX_PERSISTENT_CONNECTIONS_PER_PROXY,
        MAX_REQUEST_DELAY,
        MAX_PIPELINED_REQUESTS,
        MAX_OPTIMISTIC_PIPELINED_REQUESTS
    };

    //-------------------------------------------------------------------------
    // NOTE: functions below may only be called on the main thread.
    //-------------------------------------------------------------------------

    nsHttpConnectionMgr();

    nsresult Init(uint16_t maxConnections,
                  uint16_t maxPersistentConnectionsPerHost,
                  uint16_t maxPersistentConnectionsPerProxy,
                  uint16_t maxRequestDelay,
                  uint16_t maxPipelinedRequests,
                  uint16_t maxOptimisticPipelinedRequests);
    nsresult Shutdown();

    //-------------------------------------------------------------------------
    // NOTE: functions below may be called on any thread.
    //-------------------------------------------------------------------------

    // Schedules next pruning of dead connection to happen after
    // given time.
    void PruneDeadConnectionsAfter(uint32_t time);

    // Stops timer scheduled for next pruning of dead connections if
    // there are no more idle connections or active spdy ones
    void ConditionallyStopPruneDeadConnectionsTimer();

    // Stops timer used for the read timeout tick if there are no currently
    // active connections.
    void ConditionallyStopTimeoutTick();

    // adds a transaction to the list of managed transactions.
    nsresult AddTransaction(nsHttpTransaction *, int32_t priority);

    // called to reschedule the given transaction.  it must already have been
    // added to the connection manager via AddTransaction.
    nsresult RescheduleTransaction(nsHttpTransaction *, int32_t priority);

    // cancels a transaction w/ the given reason.
    nsresult CancelTransaction(nsHttpTransaction *, nsresult reason);
    nsresult CancelTransactions(nsHttpConnectionInfo *, nsresult reason);

    // called to force the connection manager to prune its list of idle
    // connections.
    nsresult PruneDeadConnections();

    // called to close active connections with no registered "traffic"
    nsresult PruneNoTraffic();

    // "VerifyTraffic" means marking connections now, and then check again in
    // N seconds to see if there's been any traffic and if not, kill
    // that connection.
    nsresult VerifyTraffic();

    // Close all idle persistent connections and prevent any active connections
    // from being reused. Optional connection info resets CI specific
    // information such as Happy Eyeballs history.
    nsresult DoShiftReloadConnectionCleanup(nsHttpConnectionInfo *);

    // called to get a reference to the socket transport service.  the socket
    // transport service is not available when the connection manager is down.
    nsresult GetSocketThreadTarget(nsIEventTarget **);

    // called to indicate a transaction for the connectionInfo is likely coming
    // soon. The connection manager may use this information to start a TCP
    // and/or SSL level handshake for that resource immediately so that it is
    // ready when the transaction is submitted. No obligation is taken on by the
    // connection manager, nor is the submitter obligated to actually submit a
    // real transaction for this connectionInfo.
    nsresult SpeculativeConnect(nsHttpConnectionInfo *,
                                nsIInterfaceRequestor *,
                                uint32_t caps = 0,
                                NullHttpTransaction * = nullptr);

    // called when a connection is done processing a transaction.  if the
    // connection can be reused then it will be added to the idle list, else
    // it will be closed.
    nsresult ReclaimConnection(nsHttpConnection *conn);

    // called by the main thread to execute the taketransport() logic on the
    // socket thread after a 101 response has been received and the socket
    // needs to be transferred to an expectant upgrade listener such as
    // websockets.
    nsresult CompleteUpgrade(nsAHttpConnection *aConn,
                             nsIHttpUpgradeListener *aUpgradeListener);

    // called to update a parameter after the connection manager has already
    // been initialized.
    nsresult UpdateParam(nsParamName name, uint16_t value);

    // called from main thread to post a new request token bucket
    // to the socket thread
    nsresult UpdateRequestTokenBucket(EventTokenBucket *aBucket);

    // clears the connection history mCT
    nsresult ClearConnectionHistory();

    // Pipielining Interfaces and Datatypes

    const static uint32_t kPipelineInfoTypeMask = 0xffff0000;
    const static uint32_t kPipelineInfoIDMask   = ~kPipelineInfoTypeMask;

    const static uint32_t kPipelineInfoTypeRed     = 0x00010000;
    const static uint32_t kPipelineInfoTypeBad     = 0x00020000;
    const static uint32_t kPipelineInfoTypeNeutral = 0x00040000;
    const static uint32_t kPipelineInfoTypeGood    = 0x00080000;

    enum PipelineFeedbackInfoType
    {
        // Used when an HTTP response less than 1.1 is received
        RedVersionTooLow = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0001,

        // Used when a HTTP Server response header that is on the banned from
        // pipelining list is received
        RedBannedServer = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0002,

        // Used when a response is terminated early, when it fails an
        // integrity check such as assoc-req or when a 304 contained a Last-Modified
        // differnet than the entry being validated.
        RedCorruptedContent = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0004,

        // Used when a pipeline is only partly satisfied - for instance if the
        // server closed the connection after responding to the first
        // request but left some requests unprocessed.
        RedCanceledPipeline = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0005,

        // Used when a connection that we expected to stay persistently open
        // was closed by the server. Not used when simply timed out.
        BadExplicitClose = kPipelineInfoTypeBad | 0x0003,

        // Used when there is a gap of around 400 - 1200ms in between data being
        // read from the server
        BadSlowReadMinor = kPipelineInfoTypeBad | 0x0006,

        // Used when there is a gap of > 1200ms in between data being
        // read from the server
        BadSlowReadMajor = kPipelineInfoTypeBad | 0x0007,

        // Used when a response is received that is not framed with either chunked
        // encoding or a complete content length.
        BadInsufficientFraming = kPipelineInfoTypeBad | 0x0008,

        // Used when a very large response is recevied in a potential pipelining
        // context. Large responses cause head of line blocking.
        BadUnexpectedLarge = kPipelineInfoTypeBad | 0x000B,

        // Used when a response is received that has headers that appear to support
        // pipelining.
        NeutralExpectedOK = kPipelineInfoTypeNeutral | 0x0009,

        // Used when a response is received successfully to a pipelined request.
        GoodCompletedOK = kPipelineInfoTypeGood | 0x000A
    };

    // called to provide information relevant to the pipelining manager
    // may be called from any thread
    void     PipelineFeedbackInfo(nsHttpConnectionInfo *,
                                  PipelineFeedbackInfoType info,
                                  nsHttpConnection *,
                                  uint32_t);

    void ReportFailedToProcess(nsIURI *uri);

    // Causes a large amount of connection diagnostic information to be
    // printed to the javascript console
    void PrintDiagnostics();

    //-------------------------------------------------------------------------
    // NOTE: functions below may be called only on the socket thread.
    //-------------------------------------------------------------------------

    // called to change the connection entry associated with conn from specific into
    // a wildcard (i.e. http2 proxy friendy) mapping
    void MoveToWildCardConnEntry(nsHttpConnectionInfo *specificCI,
                                 nsHttpConnectionInfo *wildcardCI,
                                 nsHttpConnection *conn);

    // called to force the transaction queue to be processed once more, giving
    // preference to the specified connection.
    nsresult ProcessPendingQ(nsHttpConnectionInfo *);
    bool     ProcessPendingQForEntry(nsHttpConnectionInfo *);

    // Try and process all pending transactions
    nsresult ProcessPendingQ();

    // This is used to force an idle connection to be closed and removed from
    // the idle connection list. It is called when the idle connection detects
    // that the network peer has closed the transport.
    nsresult CloseIdleConnection(nsHttpConnection *);

    // The connection manager needs to know when a normal HTTP connection has been
    // upgraded to SPDY because the dispatch and idle semantics are a little
    // bit different.
    void ReportSpdyConnection(nsHttpConnection *, bool usingSpdy);

    bool     SupportsPipelining(nsHttpConnectionInfo *);

    bool GetConnectionData(nsTArray<HttpRetParams> *);

    void ResetIPFamilyPreference(nsHttpConnectionInfo *);

    uint16_t MaxRequestDelay() { return mMaxRequestDelay; }

    // public, so that the SPDY/http2 seesions can activate
    void ActivateTimeoutTick();

private:
    virtual ~nsHttpConnectionMgr();

    enum PipeliningState {
        // Host has proven itself pipeline capable through past experience and
        // large pipeline depths are allowed on multiple connections.
        PS_GREEN,

        // Not enough information is available yet with this host to be certain
        // of pipeline capability. Small pipelines on a single connection are
        // allowed in order to decide whether or not to proceed to green.
        PS_YELLOW,

        // One or more bad events has happened that indicate that pipelining
        // to this host (or a particular type of transaction with this host)
        // is a bad idea. Pipelining is not currently allowed, but time and
        // other positive experiences will eventually allow it to try again.
        PS_RED
    };

    class nsHalfOpenSocket;

    // nsConnectionEntry
    //
    // mCT maps connection info hash key to nsConnectionEntry object, which
    // contains list of active and idle connections as well as the list of
    // pending transactions.
    //
    class nsConnectionEntry
    {
    public:
        explicit nsConnectionEntry(nsHttpConnectionInfo *ci);
        ~nsConnectionEntry();

        RefPtr<nsHttpConnectionInfo> mConnInfo;
        nsTArray<RefPtr<nsHttpTransaction> > mPendingQ;    // pending transaction queue
        nsTArray<RefPtr<nsHttpConnection> >  mActiveConns; // active connections
        nsTArray<RefPtr<nsHttpConnection> >  mIdleConns;   // idle persistent connections
        nsTArray<nsHalfOpenSocket*>  mHalfOpens;   // half open connections

        bool AvailableForDispatchNow();

        // calculate the number of half open sockets that have not had at least 1
        // connection complete
        uint32_t UnconnectedHalfOpens();

        // Remove a particular half open socket from the mHalfOpens array
        void RemoveHalfOpen(nsHalfOpenSocket *);

        // Pipeline depths for various states
        const static uint32_t kPipelineUnlimited  = 1024; // fully open - extended green
        const static uint32_t kPipelineOpen       = 6;    // 6 on each conn - normal green
        const static uint32_t kPipelineRestricted = 2;    // 2 on just 1 conn in yellow

        nsHttpConnectionMgr::PipeliningState PipelineState();
        void OnPipelineFeedbackInfo(
            nsHttpConnectionMgr::PipelineFeedbackInfoType info,
            nsHttpConnection *, uint32_t);
        bool SupportsPipelining();
        uint32_t MaxPipelineDepth(nsAHttpTransaction::Classifier classification);
        void CreditPenalty();

        nsHttpConnectionMgr::PipeliningState mPipelineState;

        void SetYellowConnection(nsHttpConnection *);
        void OnYellowComplete();
        uint32_t                  mYellowGoodEvents;
        uint32_t                  mYellowBadEvents;
        nsHttpConnection         *mYellowConnection;

        // initialGreenDepth is the max depth of a pipeline when you first
        // transition to green. Normally this is kPipelineOpen, but it can
        // be kPipelineUnlimited in aggressive mode.
        uint32_t                  mInitialGreenDepth;

        // greenDepth is the current max allowed depth of a pipeline when
        // in the green state. Normally this starts as kPipelineOpen and
        // grows to kPipelineUnlimited after a pipeline of depth 3 has been
        // successfully transacted.
        uint32_t                  mGreenDepth;

        // pipeliningPenalty is the current amount of penalty points this host
        // entry has earned for participating in events that are not conducive
        // to good pipelines - such as head of line blocking, canceled pipelines,
        // etc.. penalties are paid back either through elapsed time or simply
        // healthy transactions. Having penalty points means that this host is
        // not currently eligible for pipelines.
        int16_t                   mPipeliningPenalty;

        // some penalty points only apply to particular classifications of
        // transactions - this allows a server that perhaps has head of line
        // blocking problems on CGI queries to still serve JS pipelined.
        int16_t                   mPipeliningClassPenalty[nsAHttpTransaction::CLASS_MAX];

        // for calculating penalty repair credits
        TimeStamp        mLastCreditTime;

        // Spdy sometimes resolves the address in the socket manager in order
        // to re-coalesce sharded HTTP hosts. The dotted decimal address is
        // combined with the Anonymous flag from the connection information
        // to build the hash key for hosts in the same ip pool.
        //
        // When a set of hosts are coalesced together one of them is marked
        // mSpdyPreferred. The mapping is maintained in the connection mananger
        // mSpdyPreferred hash.
        //
        nsTArray<nsCString> mCoalescingKeys;

        // To have the UsingSpdy flag means some host with the same connection
        // entry has done NPN=spdy/* at some point. It does not mean every
        // connection is currently using spdy.
        bool mUsingSpdy : 1;

        bool mInPreferredHash : 1;

        // Flags to remember our happy-eyeballs decision.
        // Reset only by Ctrl-F5 reload.
        // True when we've first connected an IPv4 server for this host,
        // initially false.
        bool mPreferIPv4 : 1;
        // True when we've first connected an IPv6 server for this host,
        // initially false.
        bool mPreferIPv6 : 1;

        // True if this connection entry has initiated a socket
        bool mUsedForConnection : 1;

        // Set the IP family preference flags according the connected family
        void RecordIPFamilyPreference(uint16_t family);
        // Resets all flags to their default values
        void ResetIPFamilyPreference();
    };

public:
    static nsAHttpConnection *MakeConnectionHandle(nsHttpConnection *aWrapped);

private:

    // nsHalfOpenSocket is used to hold the state of an opening TCP socket
    // while we wait for it to establish and bind it to a connection

    class nsHalfOpenSocket final : public nsIOutputStreamCallback,
                                   public nsITransportEventSink,
                                   public nsIInterfaceRequestor,
                                   public nsITimerCallback
    {
        ~nsHalfOpenSocket();

    public:
        NS_DECL_THREADSAFE_ISUPPORTS
        NS_DECL_NSIOUTPUTSTREAMCALLBACK
        NS_DECL_NSITRANSPORTEVENTSINK
        NS_DECL_NSIINTERFACEREQUESTOR
        NS_DECL_NSITIMERCALLBACK

        nsHalfOpenSocket(nsConnectionEntry *ent,
                         nsAHttpTransaction *trans,
                         uint32_t caps);

        nsresult SetupStreams(nsISocketTransport **,
                              nsIAsyncInputStream **,
                              nsIAsyncOutputStream **,
                              bool isBackup);
        nsresult SetupPrimaryStreams();
        nsresult SetupBackupStreams();
        void     SetupBackupTimer();
        void     CancelBackupTimer();
        void     Abandon();
        double   Duration(TimeStamp epoch);
        nsISocketTransport *SocketTransport() { return mSocketTransport; }
        nsISocketTransport *BackupTransport() { return mBackupTransport; }

        nsAHttpTransaction *Transaction() { return mTransaction; }

        bool IsSpeculative() { return mSpeculative; }
        void SetSpeculative(bool val) { mSpeculative = val; }

        bool IsFromPredictor() { return mIsFromPredictor; }
        void SetIsFromPredictor(bool val) { mIsFromPredictor = val; }

        bool Allow1918() { return mAllow1918; }
        void SetAllow1918(bool val) { mAllow1918 = val; }

        bool HasConnected() { return mHasConnected; }

        void PrintDiagnostics(nsCString &log);
    private:
        nsConnectionEntry              *mEnt;
        RefPtr<nsAHttpTransaction>   mTransaction;
        bool                           mDispatchedMTransaction;
        nsCOMPtr<nsISocketTransport>   mSocketTransport;
        nsCOMPtr<nsIAsyncOutputStream> mStreamOut;
        nsCOMPtr<nsIAsyncInputStream>  mStreamIn;
        uint32_t                       mCaps;

        // mSpeculative is set if the socket was created from
        // SpeculativeConnect(). It is cleared when a transaction would normally
        // start a new connection from scratch but instead finds this one in
        // the half open list and claims it for its own use. (which due to
        // the vagaries of scheduling from the pending queue might not actually
        // match up - but it prevents a speculative connection from opening
        // more connections that are needed.)
        bool                           mSpeculative;

        // mIsFromPredictor is set if the socket originated from the network
        // Predictor. It is used to gather telemetry data on used speculative
        // connections from the predictor.
        bool                           mIsFromPredictor;

        bool                           mAllow1918;

        TimeStamp             mPrimarySynStarted;
        TimeStamp             mBackupSynStarted;

        // for syn retry
        nsCOMPtr<nsITimer>             mSynTimer;
        nsCOMPtr<nsISocketTransport>   mBackupTransport;
        nsCOMPtr<nsIAsyncOutputStream> mBackupStreamOut;
        nsCOMPtr<nsIAsyncInputStream>  mBackupStreamIn;

        // mHasConnected tracks whether one of the sockets has completed the
        // connection process. It may have completed unsuccessfully.
        bool                           mHasConnected;

        bool                           mPrimaryConnectedOK;
        bool                           mBackupConnectedOK;
    };
    friend class nsHalfOpenSocket;

    //-------------------------------------------------------------------------
    // NOTE: these members may be accessed from any thread (use mReentrantMonitor)
    //-------------------------------------------------------------------------

    ReentrantMonitor    mReentrantMonitor;
    nsCOMPtr<nsIEventTarget>     mSocketThreadTarget;

    // connection limits
    uint16_t mMaxConns;
    uint16_t mMaxPersistConnsPerHost;
    uint16_t mMaxPersistConnsPerProxy;
    uint16_t mMaxRequestDelay; // in seconds
    uint16_t mMaxPipelinedRequests;
    uint16_t mMaxOptimisticPipelinedRequests;
    Atomic<bool, mozilla::Relaxed> mIsShuttingDown;

    //-------------------------------------------------------------------------
    // NOTE: these members are only accessed on the socket transport thread
    //-------------------------------------------------------------------------

    bool     ProcessPendingQForEntry(nsConnectionEntry *, bool considerAll);
    bool     IsUnderPressure(nsConnectionEntry *ent,
                             nsHttpTransaction::Classifier classification);
    bool     AtActiveConnectionLimit(nsConnectionEntry *, uint32_t caps);
    nsresult TryDispatchTransaction(nsConnectionEntry *ent,
                                    bool onlyReusedConnection,
                                    nsHttpTransaction *trans);
    nsresult DispatchTransaction(nsConnectionEntry *,
                                 nsHttpTransaction *,
                                 nsHttpConnection *);
    nsresult DispatchAbstractTransaction(nsConnectionEntry *,
                                         nsAHttpTransaction *,
                                         uint32_t,
                                         nsHttpConnection *,
                                         int32_t);
    nsresult BuildPipeline(nsConnectionEntry *,
                           nsAHttpTransaction *,
                           nsHttpPipeline **);
    bool     RestrictConnections(nsConnectionEntry *);
    nsresult ProcessNewTransaction(nsHttpTransaction *);
    nsresult EnsureSocketThreadTarget();
    void     ClosePersistentConnections(nsConnectionEntry *ent);
    void     ReportProxyTelemetry(nsConnectionEntry *ent);
    nsresult CreateTransport(nsConnectionEntry *, nsAHttpTransaction *,
                             uint32_t, bool, bool, bool);
    void     AddActiveConn(nsHttpConnection *, nsConnectionEntry *);
    void     DecrementActiveConnCount(nsHttpConnection *);
    void     StartedConnect();
    void     RecvdConnect();

    nsConnectionEntry *GetOrCreateConnectionEntry(nsHttpConnectionInfo *,
                                                  bool allowWildCard);

    nsresult MakeNewConnection(nsConnectionEntry *ent,
                               nsHttpTransaction *trans);
    bool     AddToShortestPipeline(nsConnectionEntry *ent,
                                   nsHttpTransaction *trans,
                                   nsHttpTransaction::Classifier classification,
                                   uint16_t depthLimit);

    // Manage the preferred spdy connection entry for this address
    nsConnectionEntry *GetSpdyPreferredEnt(nsConnectionEntry *aOriginalEntry);
    nsConnectionEntry *LookupPreferredHash(nsConnectionEntry *ent);
    void               StorePreferredHash(nsConnectionEntry *ent);
    void               RemovePreferredHash(nsConnectionEntry *ent);
    nsHttpConnection  *GetSpdyPreferredConn(nsConnectionEntry *ent);
    nsDataHashtable<nsCStringHashKey, nsConnectionEntry *>   mSpdyPreferredHash;
    nsConnectionEntry *LookupConnectionEntry(nsHttpConnectionInfo *ci,
                                             nsHttpConnection *conn,
                                             nsHttpTransaction *trans);

    void               ProcessSpdyPendingQ(nsConnectionEntry *ent);

    // used to marshall events to the socket transport thread.
    nsresult PostEvent(nsConnEventHandler  handler,
                       int32_t             iparam = 0,
                       ARefBase            *vparam = nullptr);

    // message handlers
    void OnMsgShutdown             (int32_t, ARefBase *);
    void OnMsgShutdownConfirm      (int32_t, ARefBase *);
    void OnMsgNewTransaction       (int32_t, ARefBase *);
    void OnMsgReschedTransaction   (int32_t, ARefBase *);
    void OnMsgCancelTransaction    (int32_t, ARefBase *);
    void OnMsgCancelTransactions   (int32_t, ARefBase *);
    void OnMsgProcessPendingQ      (int32_t, ARefBase *);
    void OnMsgPruneDeadConnections (int32_t, ARefBase *);
    void OnMsgSpeculativeConnect   (int32_t, ARefBase *);
    void OnMsgReclaimConnection    (int32_t, ARefBase *);
    void OnMsgCompleteUpgrade      (int32_t, ARefBase *);
    void OnMsgUpdateParam          (int32_t, ARefBase *);
    void OnMsgDoShiftReloadConnectionCleanup (int32_t, ARefBase *);
    void OnMsgProcessFeedback      (int32_t, ARefBase *);
    void OnMsgProcessAllSpdyPendingQ (int32_t, ARefBase *);
    void OnMsgUpdateRequestTokenBucket (int32_t, ARefBase *);
    void OnMsgVerifyTraffic (int32_t, ARefBase *);
    void OnMsgPruneNoTraffic (int32_t, ARefBase *);

    // Total number of active connections in all of the ConnectionEntry objects
    // that are accessed from mCT connection table.
    uint16_t mNumActiveConns;
    // Total number of idle connections in all of the ConnectionEntry objects
    // that are accessed from mCT connection table.
    uint16_t mNumIdleConns;
    // Total number of spdy connections which are a subset of the active conns
    uint16_t mNumSpdyActiveConns;
    // Total number of connections in mHalfOpens ConnectionEntry objects
    // that are accessed from mCT connection table
    uint32_t mNumHalfOpenConns;

    // Holds time in seconds for next wake-up to prune dead connections.
    uint64_t mTimeOfNextWakeUp;
    // Timer for next pruning of dead connections.
    nsCOMPtr<nsITimer> mTimer;
    // Timer for pruning stalled connections after changed network.
    nsCOMPtr<nsITimer> mTrafficTimer;
    bool mPruningNoTraffic;

    // A 1s tick to call nsHttpConnection::ReadTimeoutTick on
    // active http/1 connections and check for orphaned half opens.
    // Disabled when there are no active or half open connections.
    nsCOMPtr<nsITimer> mTimeoutTick;
    bool mTimeoutTickArmed;
    uint32_t mTimeoutTickNext;

    //
    // the connection table
    //
    // this table is indexed by connection key.  each entry is a
    // nsConnectionEntry object. It is unlocked and therefore must only
    // be accessed from the socket thread.
    //
    nsClassHashtable<nsCStringHashKey, nsConnectionEntry> mCT;

    // Read Timeout Tick handlers
    void TimeoutTick();

    // For diagnostics
    void OnMsgPrintDiagnostics(int32_t, ARefBase *);

    nsCString mLogData;
};

} // namespace net
} // namespace mozilla

#endif // !nsHttpConnectionMgr_h__