michael@0: /* vim:set ts=4 sw=4 sts=4 et cin: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef nsHttpConnectionMgr_h__ michael@0: #define nsHttpConnectionMgr_h__ michael@0: michael@0: #include "nsHttpConnection.h" michael@0: #include "nsHttpTransaction.h" michael@0: #include "nsTArray.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "nsClassHashtable.h" michael@0: #include "nsDataHashtable.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "mozilla/ReentrantMonitor.h" michael@0: #include "mozilla/TimeStamp.h" michael@0: #include "mozilla/Attributes.h" michael@0: michael@0: #include "nsIObserver.h" michael@0: #include "nsITimer.h" michael@0: #include "nsIRandomGenerator.h" michael@0: michael@0: // We need our own optional debug define because pipelining behavior michael@0: // is significantly altered by rendering speed (which is abysmal on michael@0: // debug builds) michael@0: #ifdef DEBUG michael@0: # define WTF_DEBUG michael@0: #endif michael@0: michael@0: #ifdef WTF_DEBUG michael@0: # define WTF_TEST michael@0: #endif michael@0: michael@0: class nsIHttpUpgradeListener; michael@0: michael@0: namespace mozilla { michael@0: namespace net { michael@0: class EventTokenBucket; michael@0: struct HttpRetParams; michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: class nsHttpConnectionMgr : public nsIObserver michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSIOBSERVER michael@0: michael@0: // parameter names michael@0: enum nsParamName { michael@0: MAX_CONNECTIONS, michael@0: MAX_PERSISTENT_CONNECTIONS_PER_HOST, michael@0: MAX_PERSISTENT_CONNECTIONS_PER_PROXY, michael@0: MAX_REQUEST_DELAY, michael@0: MAX_PIPELINED_REQUESTS, michael@0: MAX_OPTIMISTIC_PIPELINED_REQUESTS michael@0: }; michael@0: michael@0: //------------------------------------------------------------------------- michael@0: // NOTE: functions below may only be called on the main thread. michael@0: //------------------------------------------------------------------------- michael@0: michael@0: nsHttpConnectionMgr(); michael@0: michael@0: nsresult Init(uint16_t maxConnections, michael@0: uint16_t maxPersistentConnectionsPerHost, michael@0: uint16_t maxPersistentConnectionsPerProxy, michael@0: uint16_t maxRequestDelay, michael@0: uint16_t maxPipelinedRequests, michael@0: uint16_t maxOptimisticPipelinedRequests); michael@0: nsresult Shutdown(); michael@0: michael@0: //------------------------------------------------------------------------- michael@0: // NOTE: functions below may be called on any thread. michael@0: //------------------------------------------------------------------------- michael@0: michael@0: // Schedules next pruning of dead connection to happen after michael@0: // given time. michael@0: void PruneDeadConnectionsAfter(uint32_t time); michael@0: michael@0: // Stops timer scheduled for next pruning of dead connections if michael@0: // there are no more idle connections or active spdy ones michael@0: void ConditionallyStopPruneDeadConnectionsTimer(); michael@0: michael@0: // Stops timer used for the read timeout tick if there are no currently michael@0: // active connections. michael@0: void ConditionallyStopTimeoutTick(); michael@0: michael@0: // adds a transaction to the list of managed transactions. michael@0: nsresult AddTransaction(nsHttpTransaction *, int32_t priority); michael@0: michael@0: // called to reschedule the given transaction. it must already have been michael@0: // added to the connection manager via AddTransaction. michael@0: nsresult RescheduleTransaction(nsHttpTransaction *, int32_t priority); michael@0: michael@0: // cancels a transaction w/ the given reason. michael@0: nsresult CancelTransaction(nsHttpTransaction *, nsresult reason); michael@0: michael@0: // called to force the connection manager to prune its list of idle michael@0: // connections. michael@0: nsresult PruneDeadConnections(); michael@0: michael@0: // Close all idle persistent connections and prevent any active connections michael@0: // from being reused. Optional connection info resets CI specific michael@0: // information such as Happy Eyeballs history. michael@0: nsresult DoShiftReloadConnectionCleanup(nsHttpConnectionInfo *); michael@0: michael@0: // called to get a reference to the socket transport service. the socket michael@0: // transport service is not available when the connection manager is down. michael@0: nsresult GetSocketThreadTarget(nsIEventTarget **); michael@0: michael@0: // called to indicate a transaction for the connectionInfo is likely coming michael@0: // soon. The connection manager may use this information to start a TCP michael@0: // and/or SSL level handshake for that resource immediately so that it is michael@0: // ready when the transaction is submitted. No obligation is taken on by the michael@0: // connection manager, nor is the submitter obligated to actually submit a michael@0: // real transaction for this connectionInfo. michael@0: nsresult SpeculativeConnect(nsHttpConnectionInfo *, michael@0: nsIInterfaceRequestor *, michael@0: uint32_t caps = 0); michael@0: michael@0: // called when a connection is done processing a transaction. if the michael@0: // connection can be reused then it will be added to the idle list, else michael@0: // it will be closed. michael@0: nsresult ReclaimConnection(nsHttpConnection *conn); michael@0: michael@0: // called by the main thread to execute the taketransport() logic on the michael@0: // socket thread after a 101 response has been received and the socket michael@0: // needs to be transferred to an expectant upgrade listener such as michael@0: // websockets. michael@0: nsresult CompleteUpgrade(nsAHttpConnection *aConn, michael@0: nsIHttpUpgradeListener *aUpgradeListener); michael@0: michael@0: // called to update a parameter after the connection manager has already michael@0: // been initialized. michael@0: nsresult UpdateParam(nsParamName name, uint16_t value); michael@0: michael@0: // called from main thread to post a new request token bucket michael@0: // to the socket thread michael@0: nsresult UpdateRequestTokenBucket(EventTokenBucket *aBucket); michael@0: michael@0: // Pipielining Interfaces and Datatypes michael@0: michael@0: const static uint32_t kPipelineInfoTypeMask = 0xffff0000; michael@0: const static uint32_t kPipelineInfoIDMask = ~kPipelineInfoTypeMask; michael@0: michael@0: const static uint32_t kPipelineInfoTypeRed = 0x00010000; michael@0: const static uint32_t kPipelineInfoTypeBad = 0x00020000; michael@0: const static uint32_t kPipelineInfoTypeNeutral = 0x00040000; michael@0: const static uint32_t kPipelineInfoTypeGood = 0x00080000; michael@0: michael@0: enum PipelineFeedbackInfoType michael@0: { michael@0: // Used when an HTTP response less than 1.1 is received michael@0: RedVersionTooLow = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0001, michael@0: michael@0: // Used when a HTTP Server response header that is on the banned from michael@0: // pipelining list is received michael@0: RedBannedServer = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0002, michael@0: michael@0: // Used when a response is terminated early, when it fails an michael@0: // integrity check such as assoc-req or when a 304 contained a Last-Modified michael@0: // differnet than the entry being validated. michael@0: RedCorruptedContent = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0004, michael@0: michael@0: // Used when a pipeline is only partly satisfied - for instance if the michael@0: // server closed the connection after responding to the first michael@0: // request but left some requests unprocessed. michael@0: RedCanceledPipeline = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0005, michael@0: michael@0: // Used when a connection that we expected to stay persistently open michael@0: // was closed by the server. Not used when simply timed out. michael@0: BadExplicitClose = kPipelineInfoTypeBad | 0x0003, michael@0: michael@0: // Used when there is a gap of around 400 - 1200ms in between data being michael@0: // read from the server michael@0: BadSlowReadMinor = kPipelineInfoTypeBad | 0x0006, michael@0: michael@0: // Used when there is a gap of > 1200ms in between data being michael@0: // read from the server michael@0: BadSlowReadMajor = kPipelineInfoTypeBad | 0x0007, michael@0: michael@0: // Used when a response is received that is not framed with either chunked michael@0: // encoding or a complete content length. michael@0: BadInsufficientFraming = kPipelineInfoTypeBad | 0x0008, michael@0: michael@0: // Used when a very large response is recevied in a potential pipelining michael@0: // context. Large responses cause head of line blocking. michael@0: BadUnexpectedLarge = kPipelineInfoTypeBad | 0x000B, michael@0: michael@0: // Used when a response is received that has headers that appear to support michael@0: // pipelining. michael@0: NeutralExpectedOK = kPipelineInfoTypeNeutral | 0x0009, michael@0: michael@0: // Used when a response is received successfully to a pipelined request. michael@0: GoodCompletedOK = kPipelineInfoTypeGood | 0x000A michael@0: }; michael@0: michael@0: // called to provide information relevant to the pipelining manager michael@0: // may be called from any thread michael@0: void PipelineFeedbackInfo(nsHttpConnectionInfo *, michael@0: PipelineFeedbackInfoType info, michael@0: nsHttpConnection *, michael@0: uint32_t); michael@0: michael@0: void ReportFailedToProcess(nsIURI *uri); michael@0: michael@0: // Causes a large amount of connection diagnostic information to be michael@0: // printed to the javascript console michael@0: void PrintDiagnostics(); michael@0: michael@0: //------------------------------------------------------------------------- michael@0: // NOTE: functions below may be called only on the socket thread. michael@0: //------------------------------------------------------------------------- michael@0: michael@0: // called to force the transaction queue to be processed once more, giving michael@0: // preference to the specified connection. michael@0: nsresult ProcessPendingQ(nsHttpConnectionInfo *); michael@0: bool ProcessPendingQForEntry(nsHttpConnectionInfo *); michael@0: michael@0: // Try and process all pending transactions michael@0: nsresult ProcessPendingQ(); michael@0: michael@0: // This is used to force an idle connection to be closed and removed from michael@0: // the idle connection list. It is called when the idle connection detects michael@0: // that the network peer has closed the transport. michael@0: nsresult CloseIdleConnection(nsHttpConnection *); michael@0: michael@0: // The connection manager needs to know when a normal HTTP connection has been michael@0: // upgraded to SPDY because the dispatch and idle semantics are a little michael@0: // bit different. michael@0: void ReportSpdyConnection(nsHttpConnection *, bool usingSpdy); michael@0: michael@0: // A spdy server can supply cwnd information for the session that is used michael@0: // in future sessions to speed up the opening portions of the connection. michael@0: void ReportSpdyCWNDSetting(nsHttpConnectionInfo *host, uint32_t cwndValue); michael@0: uint32_t GetSpdyCWNDSetting(nsHttpConnectionInfo *host); michael@0: michael@0: bool SupportsPipelining(nsHttpConnectionInfo *); michael@0: michael@0: bool GetConnectionData(nsTArray *); michael@0: michael@0: void ResetIPFamilyPreference(nsHttpConnectionInfo *); michael@0: michael@0: private: michael@0: virtual ~nsHttpConnectionMgr(); michael@0: michael@0: enum PipeliningState { michael@0: // Host has proven itself pipeline capable through past experience and michael@0: // large pipeline depths are allowed on multiple connections. michael@0: PS_GREEN, michael@0: michael@0: // Not enough information is available yet with this host to be certain michael@0: // of pipeline capability. Small pipelines on a single connection are michael@0: // allowed in order to decide whether or not to proceed to green. michael@0: PS_YELLOW, michael@0: michael@0: // One or more bad events has happened that indicate that pipelining michael@0: // to this host (or a particular type of transaction with this host) michael@0: // is a bad idea. Pipelining is not currently allowed, but time and michael@0: // other positive experiences will eventually allow it to try again. michael@0: PS_RED michael@0: }; michael@0: michael@0: class nsHalfOpenSocket; michael@0: michael@0: // nsConnectionEntry michael@0: // michael@0: // mCT maps connection info hash key to nsConnectionEntry object, which michael@0: // contains list of active and idle connections as well as the list of michael@0: // pending transactions. michael@0: // michael@0: class nsConnectionEntry michael@0: { michael@0: public: michael@0: nsConnectionEntry(nsHttpConnectionInfo *ci); michael@0: ~nsConnectionEntry(); michael@0: michael@0: nsHttpConnectionInfo *mConnInfo; michael@0: nsTArray mPendingQ; // pending transaction queue michael@0: nsTArray mActiveConns; // active connections michael@0: nsTArray mIdleConns; // idle persistent connections michael@0: nsTArray mHalfOpens; // half open connections michael@0: michael@0: // calculate the number of half open sockets that have not had at least 1 michael@0: // connection complete michael@0: uint32_t UnconnectedHalfOpens(); michael@0: michael@0: // Remove a particular half open socket from the mHalfOpens array michael@0: void RemoveHalfOpen(nsHalfOpenSocket *); michael@0: michael@0: // Pipeline depths for various states michael@0: const static uint32_t kPipelineUnlimited = 1024; // fully open - extended green michael@0: const static uint32_t kPipelineOpen = 6; // 6 on each conn - normal green michael@0: const static uint32_t kPipelineRestricted = 2; // 2 on just 1 conn in yellow michael@0: michael@0: nsHttpConnectionMgr::PipeliningState PipelineState(); michael@0: void OnPipelineFeedbackInfo( michael@0: nsHttpConnectionMgr::PipelineFeedbackInfoType info, michael@0: nsHttpConnection *, uint32_t); michael@0: bool SupportsPipelining(); michael@0: uint32_t MaxPipelineDepth(nsAHttpTransaction::Classifier classification); michael@0: void CreditPenalty(); michael@0: michael@0: nsHttpConnectionMgr::PipeliningState mPipelineState; michael@0: michael@0: void SetYellowConnection(nsHttpConnection *); michael@0: void OnYellowComplete(); michael@0: uint32_t mYellowGoodEvents; michael@0: uint32_t mYellowBadEvents; michael@0: nsHttpConnection *mYellowConnection; michael@0: michael@0: // initialGreenDepth is the max depth of a pipeline when you first michael@0: // transition to green. Normally this is kPipelineOpen, but it can michael@0: // be kPipelineUnlimited in aggressive mode. michael@0: uint32_t mInitialGreenDepth; michael@0: michael@0: // greenDepth is the current max allowed depth of a pipeline when michael@0: // in the green state. Normally this starts as kPipelineOpen and michael@0: // grows to kPipelineUnlimited after a pipeline of depth 3 has been michael@0: // successfully transacted. michael@0: uint32_t mGreenDepth; michael@0: michael@0: // pipeliningPenalty is the current amount of penalty points this host michael@0: // entry has earned for participating in events that are not conducive michael@0: // to good pipelines - such as head of line blocking, canceled pipelines, michael@0: // etc.. penalties are paid back either through elapsed time or simply michael@0: // healthy transactions. Having penalty points means that this host is michael@0: // not currently eligible for pipelines. michael@0: int16_t mPipeliningPenalty; michael@0: michael@0: // some penalty points only apply to particular classifications of michael@0: // transactions - this allows a server that perhaps has head of line michael@0: // blocking problems on CGI queries to still serve JS pipelined. michael@0: int16_t mPipeliningClassPenalty[nsAHttpTransaction::CLASS_MAX]; michael@0: michael@0: // for calculating penalty repair credits michael@0: TimeStamp mLastCreditTime; michael@0: michael@0: // Spdy sometimes resolves the address in the socket manager in order michael@0: // to re-coalesce sharded HTTP hosts. The dotted decimal address is michael@0: // combined with the Anonymous flag from the connection information michael@0: // to build the hash key for hosts in the same ip pool. michael@0: // michael@0: // When a set of hosts are coalesced together one of them is marked michael@0: // mSpdyPreferred. The mapping is maintained in the connection mananger michael@0: // mSpdyPreferred hash. michael@0: // michael@0: nsCString mCoalescingKey; michael@0: michael@0: // The value of a recevied SPDY settings type 5 previously received michael@0: // for this connection entry and the time it was set. michael@0: uint32_t mSpdyCWND; michael@0: TimeStamp mSpdyCWNDTimeStamp; michael@0: michael@0: // To have the UsingSpdy flag means some host with the same connection michael@0: // entry has done NPN=spdy/* at some point. It does not mean every michael@0: // connection is currently using spdy. michael@0: bool mUsingSpdy; michael@0: michael@0: // mTestedSpdy is set after NPN negotiation has occurred and we know michael@0: // with confidence whether a host speaks spdy or not (which is reflected michael@0: // in mUsingSpdy). Before mTestedSpdy is set, handshake parallelism is michael@0: // minimized so that we can multiplex on a single spdy connection. michael@0: bool mTestedSpdy; michael@0: michael@0: bool mSpdyPreferred; michael@0: michael@0: // Flags to remember our happy-eyeballs decision. michael@0: // Reset only by Ctrl-F5 reload. michael@0: // True when we've first connected an IPv4 server for this host, michael@0: // initially false. michael@0: bool mPreferIPv4 : 1; michael@0: // True when we've first connected an IPv6 server for this host, michael@0: // initially false. michael@0: bool mPreferIPv6 : 1; michael@0: michael@0: // Set the IP family preference flags according the connected family michael@0: void RecordIPFamilyPreference(uint16_t family); michael@0: // Resets all flags to their default values michael@0: void ResetIPFamilyPreference(); michael@0: }; michael@0: michael@0: // nsConnectionHandle michael@0: // michael@0: // thin wrapper around a real connection, used to keep track of references michael@0: // to the connection to determine when the connection may be reused. the michael@0: // transaction (or pipeline) owns a reference to this handle. this extra michael@0: // layer of indirection greatly simplifies consumer code, avoiding the michael@0: // need for consumer code to know when to give the connection back to the michael@0: // connection manager. michael@0: // michael@0: class nsConnectionHandle : public nsAHttpConnection michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSAHTTPCONNECTION(mConn) michael@0: michael@0: nsConnectionHandle(nsHttpConnection *conn) { NS_ADDREF(mConn = conn); } michael@0: virtual ~nsConnectionHandle(); michael@0: michael@0: nsHttpConnection *mConn; michael@0: }; michael@0: michael@0: // nsHalfOpenSocket is used to hold the state of an opening TCP socket michael@0: // while we wait for it to establish and bind it to a connection michael@0: michael@0: class nsHalfOpenSocket MOZ_FINAL : public nsIOutputStreamCallback, michael@0: public nsITransportEventSink, michael@0: public nsIInterfaceRequestor, michael@0: public nsITimerCallback michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSIOUTPUTSTREAMCALLBACK michael@0: NS_DECL_NSITRANSPORTEVENTSINK michael@0: NS_DECL_NSIINTERFACEREQUESTOR michael@0: NS_DECL_NSITIMERCALLBACK michael@0: michael@0: nsHalfOpenSocket(nsConnectionEntry *ent, michael@0: nsAHttpTransaction *trans, michael@0: uint32_t caps); michael@0: ~nsHalfOpenSocket(); michael@0: michael@0: nsresult SetupStreams(nsISocketTransport **, michael@0: nsIAsyncInputStream **, michael@0: nsIAsyncOutputStream **, michael@0: bool isBackup); michael@0: nsresult SetupPrimaryStreams(); michael@0: nsresult SetupBackupStreams(); michael@0: void SetupBackupTimer(); michael@0: void CancelBackupTimer(); michael@0: void Abandon(); michael@0: double Duration(TimeStamp epoch); michael@0: nsISocketTransport *SocketTransport() { return mSocketTransport; } michael@0: nsISocketTransport *BackupTransport() { return mBackupTransport; } michael@0: michael@0: nsAHttpTransaction *Transaction() { return mTransaction; } michael@0: michael@0: bool IsSpeculative() { return mSpeculative; } michael@0: void SetSpeculative(bool val) { mSpeculative = val; } michael@0: michael@0: bool HasConnected() { return mHasConnected; } michael@0: michael@0: void PrintDiagnostics(nsCString &log); michael@0: private: michael@0: nsConnectionEntry *mEnt; michael@0: nsRefPtr mTransaction; michael@0: nsCOMPtr mSocketTransport; michael@0: nsCOMPtr mStreamOut; michael@0: nsCOMPtr mStreamIn; michael@0: uint32_t mCaps; michael@0: michael@0: // mSpeculative is set if the socket was created from michael@0: // SpeculativeConnect(). It is cleared when a transaction would normally michael@0: // start a new connection from scratch but instead finds this one in michael@0: // the half open list and claims it for its own use. (which due to michael@0: // the vagaries of scheduling from the pending queue might not actually michael@0: // match up - but it prevents a speculative connection from opening michael@0: // more connections that are needed.) michael@0: bool mSpeculative; michael@0: michael@0: TimeStamp mPrimarySynStarted; michael@0: TimeStamp mBackupSynStarted; michael@0: michael@0: // for syn retry michael@0: nsCOMPtr mSynTimer; michael@0: nsCOMPtr mBackupTransport; michael@0: nsCOMPtr mBackupStreamOut; michael@0: nsCOMPtr mBackupStreamIn; michael@0: michael@0: bool mHasConnected; michael@0: }; michael@0: friend class nsHalfOpenSocket; michael@0: michael@0: //------------------------------------------------------------------------- michael@0: // NOTE: these members may be accessed from any thread (use mReentrantMonitor) michael@0: //------------------------------------------------------------------------- michael@0: michael@0: ReentrantMonitor mReentrantMonitor; michael@0: nsCOMPtr mSocketThreadTarget; michael@0: michael@0: // connection limits michael@0: uint16_t mMaxConns; michael@0: uint16_t mMaxPersistConnsPerHost; michael@0: uint16_t mMaxPersistConnsPerProxy; michael@0: uint16_t mMaxRequestDelay; // in seconds michael@0: uint16_t mMaxPipelinedRequests; michael@0: uint16_t mMaxOptimisticPipelinedRequests; michael@0: bool mIsShuttingDown; michael@0: michael@0: //------------------------------------------------------------------------- michael@0: // NOTE: these members are only accessed on the socket transport thread michael@0: //------------------------------------------------------------------------- michael@0: michael@0: static PLDHashOperator ProcessOneTransactionCB(const nsACString &, nsAutoPtr &, void *); michael@0: static PLDHashOperator ProcessAllTransactionsCB(const nsACString &, nsAutoPtr &, void *); michael@0: michael@0: static PLDHashOperator PruneDeadConnectionsCB(const nsACString &, nsAutoPtr &, void *); michael@0: static PLDHashOperator ShutdownPassCB(const nsACString &, nsAutoPtr &, void *); michael@0: static PLDHashOperator PurgeExcessIdleConnectionsCB(const nsACString &, nsAutoPtr &, void *); michael@0: static PLDHashOperator PurgeExcessSpdyConnectionsCB(const nsACString &, nsAutoPtr &, void *); michael@0: static PLDHashOperator ClosePersistentConnectionsCB(const nsACString &, nsAutoPtr &, void *); michael@0: bool ProcessPendingQForEntry(nsConnectionEntry *, bool considerAll); michael@0: bool IsUnderPressure(nsConnectionEntry *ent, michael@0: nsHttpTransaction::Classifier classification); michael@0: bool AtActiveConnectionLimit(nsConnectionEntry *, uint32_t caps); michael@0: nsresult TryDispatchTransaction(nsConnectionEntry *ent, michael@0: bool onlyReusedConnection, michael@0: nsHttpTransaction *trans); michael@0: nsresult DispatchTransaction(nsConnectionEntry *, michael@0: nsHttpTransaction *, michael@0: nsHttpConnection *); michael@0: nsresult DispatchAbstractTransaction(nsConnectionEntry *, michael@0: nsAHttpTransaction *, michael@0: uint32_t, michael@0: nsHttpConnection *, michael@0: int32_t); michael@0: nsresult BuildPipeline(nsConnectionEntry *, michael@0: nsAHttpTransaction *, michael@0: nsHttpPipeline **); michael@0: bool HasPipelines(nsConnectionEntry *); michael@0: bool RestrictConnections(nsConnectionEntry *, bool = false); michael@0: nsresult ProcessNewTransaction(nsHttpTransaction *); michael@0: nsresult EnsureSocketThreadTarget(); michael@0: void ClosePersistentConnections(nsConnectionEntry *ent); michael@0: void ReportProxyTelemetry(nsConnectionEntry *ent); michael@0: nsresult CreateTransport(nsConnectionEntry *, nsAHttpTransaction *, michael@0: uint32_t, bool); michael@0: void AddActiveConn(nsHttpConnection *, nsConnectionEntry *); michael@0: void DecrementActiveConnCount(nsHttpConnection *); michael@0: void StartedConnect(); michael@0: void RecvdConnect(); michael@0: michael@0: nsConnectionEntry *GetOrCreateConnectionEntry(nsHttpConnectionInfo *); michael@0: michael@0: nsresult MakeNewConnection(nsConnectionEntry *ent, michael@0: nsHttpTransaction *trans); michael@0: bool AddToBestPipeline(nsConnectionEntry *ent, michael@0: nsHttpTransaction *trans, michael@0: nsHttpTransaction::Classifier classification, michael@0: uint16_t depthLimit); michael@0: michael@0: // Manage the preferred spdy connection entry for this address michael@0: nsConnectionEntry *GetSpdyPreferredEnt(nsConnectionEntry *aOriginalEntry); michael@0: void RemoveSpdyPreferredEnt(nsACString &aDottedDecimal); michael@0: nsHttpConnection *GetSpdyPreferredConn(nsConnectionEntry *ent); michael@0: nsDataHashtable mSpdyPreferredHash; michael@0: nsConnectionEntry *LookupConnectionEntry(nsHttpConnectionInfo *ci, michael@0: nsHttpConnection *conn, michael@0: nsHttpTransaction *trans); michael@0: michael@0: void ProcessSpdyPendingQ(nsConnectionEntry *ent); michael@0: static PLDHashOperator ProcessSpdyPendingQCB( michael@0: const nsACString &key, nsAutoPtr &ent, michael@0: void *closure); michael@0: michael@0: // message handlers have this signature michael@0: typedef void (nsHttpConnectionMgr:: *nsConnEventHandler)(int32_t, void *); michael@0: michael@0: // nsConnEvent michael@0: // michael@0: // subclass of nsRunnable used to marshall events to the socket transport michael@0: // thread. this class is used to implement PostEvent. michael@0: // michael@0: class nsConnEvent; michael@0: friend class nsConnEvent; michael@0: class nsConnEvent : public nsRunnable michael@0: { michael@0: public: michael@0: nsConnEvent(nsHttpConnectionMgr *mgr, michael@0: nsConnEventHandler handler, michael@0: int32_t iparam, michael@0: void *vparam) michael@0: : mMgr(mgr) michael@0: , mHandler(handler) michael@0: , mIParam(iparam) michael@0: , mVParam(vparam) michael@0: { michael@0: NS_ADDREF(mMgr); michael@0: } michael@0: michael@0: NS_IMETHOD Run() michael@0: { michael@0: (mMgr->*mHandler)(mIParam, mVParam); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: virtual ~nsConnEvent() michael@0: { michael@0: NS_RELEASE(mMgr); michael@0: } michael@0: michael@0: nsHttpConnectionMgr *mMgr; michael@0: nsConnEventHandler mHandler; michael@0: int32_t mIParam; michael@0: void *mVParam; michael@0: }; michael@0: michael@0: nsresult PostEvent(nsConnEventHandler handler, michael@0: int32_t iparam = 0, michael@0: void *vparam = nullptr); michael@0: michael@0: // message handlers michael@0: void OnMsgShutdown (int32_t, void *); michael@0: void OnMsgShutdownConfirm (int32_t, void *); michael@0: void OnMsgNewTransaction (int32_t, void *); michael@0: void OnMsgReschedTransaction (int32_t, void *); michael@0: void OnMsgCancelTransaction (int32_t, void *); michael@0: void OnMsgProcessPendingQ (int32_t, void *); michael@0: void OnMsgPruneDeadConnections (int32_t, void *); michael@0: void OnMsgSpeculativeConnect (int32_t, void *); michael@0: void OnMsgReclaimConnection (int32_t, void *); michael@0: void OnMsgCompleteUpgrade (int32_t, void *); michael@0: void OnMsgUpdateParam (int32_t, void *); michael@0: void OnMsgDoShiftReloadConnectionCleanup (int32_t, void *); michael@0: void OnMsgProcessFeedback (int32_t, void *); michael@0: void OnMsgProcessAllSpdyPendingQ (int32_t, void *); michael@0: void OnMsgUpdateRequestTokenBucket (int32_t, void *); michael@0: michael@0: // Total number of active connections in all of the ConnectionEntry objects michael@0: // that are accessed from mCT connection table. michael@0: uint16_t mNumActiveConns; michael@0: // Total number of idle connections in all of the ConnectionEntry objects michael@0: // that are accessed from mCT connection table. michael@0: uint16_t mNumIdleConns; michael@0: // Total number of spdy connections which are a subset of the active conns michael@0: uint16_t mNumSpdyActiveConns; michael@0: // Total number of connections in mHalfOpens ConnectionEntry objects michael@0: // that are accessed from mCT connection table michael@0: uint32_t mNumHalfOpenConns; michael@0: michael@0: // Holds time in seconds for next wake-up to prune dead connections. michael@0: uint64_t mTimeOfNextWakeUp; michael@0: // Timer for next pruning of dead connections. michael@0: nsCOMPtr mTimer; michael@0: michael@0: // A 1s tick to call nsHttpConnection::ReadTimeoutTick on michael@0: // active http/1 connections and check for orphaned half opens. michael@0: // Disabled when there are no active or half open connections. michael@0: nsCOMPtr mTimeoutTick; michael@0: bool mTimeoutTickArmed; michael@0: uint32_t mTimeoutTickNext; michael@0: michael@0: // michael@0: // the connection table michael@0: // michael@0: // this table is indexed by connection key. each entry is a michael@0: // nsConnectionEntry object. It is unlocked and therefore must only michael@0: // be accessed from the socket thread. michael@0: // michael@0: nsClassHashtable mCT; michael@0: michael@0: static PLDHashOperator ReadConnectionEntry(const nsACString &key, michael@0: nsAutoPtr &ent, michael@0: void *aArg); michael@0: michael@0: // Read Timeout Tick handlers michael@0: void ActivateTimeoutTick(); michael@0: void TimeoutTick(); michael@0: static PLDHashOperator TimeoutTickCB(const nsACString &key, michael@0: nsAutoPtr &ent, michael@0: void *closure); michael@0: michael@0: // For diagnostics michael@0: void OnMsgPrintDiagnostics(int32_t, void *); michael@0: static PLDHashOperator PrintDiagnosticsCB(const nsACString &key, michael@0: nsAutoPtr &ent, michael@0: void *closure); michael@0: nsCString mLogData; michael@0: }; michael@0: michael@0: }} // namespace mozilla::net michael@0: michael@0: #endif // !nsHttpConnectionMgr_h__