netwerk/protocol/http/nsHttpConnectionMgr.h

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

michael@0 1 /* vim:set ts=4 sw=4 sts=4 et cin: */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #ifndef nsHttpConnectionMgr_h__
michael@0 7 #define nsHttpConnectionMgr_h__
michael@0 8
michael@0 9 #include "nsHttpConnection.h"
michael@0 10 #include "nsHttpTransaction.h"
michael@0 11 #include "nsTArray.h"
michael@0 12 #include "nsThreadUtils.h"
michael@0 13 #include "nsClassHashtable.h"
michael@0 14 #include "nsDataHashtable.h"
michael@0 15 #include "nsAutoPtr.h"
michael@0 16 #include "mozilla/ReentrantMonitor.h"
michael@0 17 #include "mozilla/TimeStamp.h"
michael@0 18 #include "mozilla/Attributes.h"
michael@0 19
michael@0 20 #include "nsIObserver.h"
michael@0 21 #include "nsITimer.h"
michael@0 22 #include "nsIRandomGenerator.h"
michael@0 23
michael@0 24 // We need our own optional debug define because pipelining behavior
michael@0 25 // is significantly altered by rendering speed (which is abysmal on
michael@0 26 // debug builds)
michael@0 27 #ifdef DEBUG
michael@0 28 # define WTF_DEBUG
michael@0 29 #endif
michael@0 30
michael@0 31 #ifdef WTF_DEBUG
michael@0 32 # define WTF_TEST
michael@0 33 #endif
michael@0 34
michael@0 35 class nsIHttpUpgradeListener;
michael@0 36
michael@0 37 namespace mozilla {
michael@0 38 namespace net {
michael@0 39 class EventTokenBucket;
michael@0 40 struct HttpRetParams;
michael@0 41
michael@0 42 //-----------------------------------------------------------------------------
michael@0 43
michael@0 44 class nsHttpConnectionMgr : public nsIObserver
michael@0 45 {
michael@0 46 public:
michael@0 47 NS_DECL_THREADSAFE_ISUPPORTS
michael@0 48 NS_DECL_NSIOBSERVER
michael@0 49
michael@0 50 // parameter names
michael@0 51 enum nsParamName {
michael@0 52 MAX_CONNECTIONS,
michael@0 53 MAX_PERSISTENT_CONNECTIONS_PER_HOST,
michael@0 54 MAX_PERSISTENT_CONNECTIONS_PER_PROXY,
michael@0 55 MAX_REQUEST_DELAY,
michael@0 56 MAX_PIPELINED_REQUESTS,
michael@0 57 MAX_OPTIMISTIC_PIPELINED_REQUESTS
michael@0 58 };
michael@0 59
michael@0 60 //-------------------------------------------------------------------------
michael@0 61 // NOTE: functions below may only be called on the main thread.
michael@0 62 //-------------------------------------------------------------------------
michael@0 63
michael@0 64 nsHttpConnectionMgr();
michael@0 65
michael@0 66 nsresult Init(uint16_t maxConnections,
michael@0 67 uint16_t maxPersistentConnectionsPerHost,
michael@0 68 uint16_t maxPersistentConnectionsPerProxy,
michael@0 69 uint16_t maxRequestDelay,
michael@0 70 uint16_t maxPipelinedRequests,
michael@0 71 uint16_t maxOptimisticPipelinedRequests);
michael@0 72 nsresult Shutdown();
michael@0 73
michael@0 74 //-------------------------------------------------------------------------
michael@0 75 // NOTE: functions below may be called on any thread.
michael@0 76 //-------------------------------------------------------------------------
michael@0 77
michael@0 78 // Schedules next pruning of dead connection to happen after
michael@0 79 // given time.
michael@0 80 void PruneDeadConnectionsAfter(uint32_t time);
michael@0 81
michael@0 82 // Stops timer scheduled for next pruning of dead connections if
michael@0 83 // there are no more idle connections or active spdy ones
michael@0 84 void ConditionallyStopPruneDeadConnectionsTimer();
michael@0 85
michael@0 86 // Stops timer used for the read timeout tick if there are no currently
michael@0 87 // active connections.
michael@0 88 void ConditionallyStopTimeoutTick();
michael@0 89
michael@0 90 // adds a transaction to the list of managed transactions.
michael@0 91 nsresult AddTransaction(nsHttpTransaction *, int32_t priority);
michael@0 92
michael@0 93 // called to reschedule the given transaction. it must already have been
michael@0 94 // added to the connection manager via AddTransaction.
michael@0 95 nsresult RescheduleTransaction(nsHttpTransaction *, int32_t priority);
michael@0 96
michael@0 97 // cancels a transaction w/ the given reason.
michael@0 98 nsresult CancelTransaction(nsHttpTransaction *, nsresult reason);
michael@0 99
michael@0 100 // called to force the connection manager to prune its list of idle
michael@0 101 // connections.
michael@0 102 nsresult PruneDeadConnections();
michael@0 103
michael@0 104 // Close all idle persistent connections and prevent any active connections
michael@0 105 // from being reused. Optional connection info resets CI specific
michael@0 106 // information such as Happy Eyeballs history.
michael@0 107 nsresult DoShiftReloadConnectionCleanup(nsHttpConnectionInfo *);
michael@0 108
michael@0 109 // called to get a reference to the socket transport service. the socket
michael@0 110 // transport service is not available when the connection manager is down.
michael@0 111 nsresult GetSocketThreadTarget(nsIEventTarget **);
michael@0 112
michael@0 113 // called to indicate a transaction for the connectionInfo is likely coming
michael@0 114 // soon. The connection manager may use this information to start a TCP
michael@0 115 // and/or SSL level handshake for that resource immediately so that it is
michael@0 116 // ready when the transaction is submitted. No obligation is taken on by the
michael@0 117 // connection manager, nor is the submitter obligated to actually submit a
michael@0 118 // real transaction for this connectionInfo.
michael@0 119 nsresult SpeculativeConnect(nsHttpConnectionInfo *,
michael@0 120 nsIInterfaceRequestor *,
michael@0 121 uint32_t caps = 0);
michael@0 122
michael@0 123 // called when a connection is done processing a transaction. if the
michael@0 124 // connection can be reused then it will be added to the idle list, else
michael@0 125 // it will be closed.
michael@0 126 nsresult ReclaimConnection(nsHttpConnection *conn);
michael@0 127
michael@0 128 // called by the main thread to execute the taketransport() logic on the
michael@0 129 // socket thread after a 101 response has been received and the socket
michael@0 130 // needs to be transferred to an expectant upgrade listener such as
michael@0 131 // websockets.
michael@0 132 nsresult CompleteUpgrade(nsAHttpConnection *aConn,
michael@0 133 nsIHttpUpgradeListener *aUpgradeListener);
michael@0 134
michael@0 135 // called to update a parameter after the connection manager has already
michael@0 136 // been initialized.
michael@0 137 nsresult UpdateParam(nsParamName name, uint16_t value);
michael@0 138
michael@0 139 // called from main thread to post a new request token bucket
michael@0 140 // to the socket thread
michael@0 141 nsresult UpdateRequestTokenBucket(EventTokenBucket *aBucket);
michael@0 142
michael@0 143 // Pipielining Interfaces and Datatypes
michael@0 144
michael@0 145 const static uint32_t kPipelineInfoTypeMask = 0xffff0000;
michael@0 146 const static uint32_t kPipelineInfoIDMask = ~kPipelineInfoTypeMask;
michael@0 147
michael@0 148 const static uint32_t kPipelineInfoTypeRed = 0x00010000;
michael@0 149 const static uint32_t kPipelineInfoTypeBad = 0x00020000;
michael@0 150 const static uint32_t kPipelineInfoTypeNeutral = 0x00040000;
michael@0 151 const static uint32_t kPipelineInfoTypeGood = 0x00080000;
michael@0 152
michael@0 153 enum PipelineFeedbackInfoType
michael@0 154 {
michael@0 155 // Used when an HTTP response less than 1.1 is received
michael@0 156 RedVersionTooLow = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0001,
michael@0 157
michael@0 158 // Used when a HTTP Server response header that is on the banned from
michael@0 159 // pipelining list is received
michael@0 160 RedBannedServer = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0002,
michael@0 161
michael@0 162 // Used when a response is terminated early, when it fails an
michael@0 163 // integrity check such as assoc-req or when a 304 contained a Last-Modified
michael@0 164 // differnet than the entry being validated.
michael@0 165 RedCorruptedContent = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0004,
michael@0 166
michael@0 167 // Used when a pipeline is only partly satisfied - for instance if the
michael@0 168 // server closed the connection after responding to the first
michael@0 169 // request but left some requests unprocessed.
michael@0 170 RedCanceledPipeline = kPipelineInfoTypeRed | kPipelineInfoTypeBad | 0x0005,
michael@0 171
michael@0 172 // Used when a connection that we expected to stay persistently open
michael@0 173 // was closed by the server. Not used when simply timed out.
michael@0 174 BadExplicitClose = kPipelineInfoTypeBad | 0x0003,
michael@0 175
michael@0 176 // Used when there is a gap of around 400 - 1200ms in between data being
michael@0 177 // read from the server
michael@0 178 BadSlowReadMinor = kPipelineInfoTypeBad | 0x0006,
michael@0 179
michael@0 180 // Used when there is a gap of > 1200ms in between data being
michael@0 181 // read from the server
michael@0 182 BadSlowReadMajor = kPipelineInfoTypeBad | 0x0007,
michael@0 183
michael@0 184 // Used when a response is received that is not framed with either chunked
michael@0 185 // encoding or a complete content length.
michael@0 186 BadInsufficientFraming = kPipelineInfoTypeBad | 0x0008,
michael@0 187
michael@0 188 // Used when a very large response is recevied in a potential pipelining
michael@0 189 // context. Large responses cause head of line blocking.
michael@0 190 BadUnexpectedLarge = kPipelineInfoTypeBad | 0x000B,
michael@0 191
michael@0 192 // Used when a response is received that has headers that appear to support
michael@0 193 // pipelining.
michael@0 194 NeutralExpectedOK = kPipelineInfoTypeNeutral | 0x0009,
michael@0 195
michael@0 196 // Used when a response is received successfully to a pipelined request.
michael@0 197 GoodCompletedOK = kPipelineInfoTypeGood | 0x000A
michael@0 198 };
michael@0 199
michael@0 200 // called to provide information relevant to the pipelining manager
michael@0 201 // may be called from any thread
michael@0 202 void PipelineFeedbackInfo(nsHttpConnectionInfo *,
michael@0 203 PipelineFeedbackInfoType info,
michael@0 204 nsHttpConnection *,
michael@0 205 uint32_t);
michael@0 206
michael@0 207 void ReportFailedToProcess(nsIURI *uri);
michael@0 208
michael@0 209 // Causes a large amount of connection diagnostic information to be
michael@0 210 // printed to the javascript console
michael@0 211 void PrintDiagnostics();
michael@0 212
michael@0 213 //-------------------------------------------------------------------------
michael@0 214 // NOTE: functions below may be called only on the socket thread.
michael@0 215 //-------------------------------------------------------------------------
michael@0 216
michael@0 217 // called to force the transaction queue to be processed once more, giving
michael@0 218 // preference to the specified connection.
michael@0 219 nsresult ProcessPendingQ(nsHttpConnectionInfo *);
michael@0 220 bool ProcessPendingQForEntry(nsHttpConnectionInfo *);
michael@0 221
michael@0 222 // Try and process all pending transactions
michael@0 223 nsresult ProcessPendingQ();
michael@0 224
michael@0 225 // This is used to force an idle connection to be closed and removed from
michael@0 226 // the idle connection list. It is called when the idle connection detects
michael@0 227 // that the network peer has closed the transport.
michael@0 228 nsresult CloseIdleConnection(nsHttpConnection *);
michael@0 229
michael@0 230 // The connection manager needs to know when a normal HTTP connection has been
michael@0 231 // upgraded to SPDY because the dispatch and idle semantics are a little
michael@0 232 // bit different.
michael@0 233 void ReportSpdyConnection(nsHttpConnection *, bool usingSpdy);
michael@0 234
michael@0 235 // A spdy server can supply cwnd information for the session that is used
michael@0 236 // in future sessions to speed up the opening portions of the connection.
michael@0 237 void ReportSpdyCWNDSetting(nsHttpConnectionInfo *host, uint32_t cwndValue);
michael@0 238 uint32_t GetSpdyCWNDSetting(nsHttpConnectionInfo *host);
michael@0 239
michael@0 240 bool SupportsPipelining(nsHttpConnectionInfo *);
michael@0 241
michael@0 242 bool GetConnectionData(nsTArray<HttpRetParams> *);
michael@0 243
michael@0 244 void ResetIPFamilyPreference(nsHttpConnectionInfo *);
michael@0 245
michael@0 246 private:
michael@0 247 virtual ~nsHttpConnectionMgr();
michael@0 248
michael@0 249 enum PipeliningState {
michael@0 250 // Host has proven itself pipeline capable through past experience and
michael@0 251 // large pipeline depths are allowed on multiple connections.
michael@0 252 PS_GREEN,
michael@0 253
michael@0 254 // Not enough information is available yet with this host to be certain
michael@0 255 // of pipeline capability. Small pipelines on a single connection are
michael@0 256 // allowed in order to decide whether or not to proceed to green.
michael@0 257 PS_YELLOW,
michael@0 258
michael@0 259 // One or more bad events has happened that indicate that pipelining
michael@0 260 // to this host (or a particular type of transaction with this host)
michael@0 261 // is a bad idea. Pipelining is not currently allowed, but time and
michael@0 262 // other positive experiences will eventually allow it to try again.
michael@0 263 PS_RED
michael@0 264 };
michael@0 265
michael@0 266 class nsHalfOpenSocket;
michael@0 267
michael@0 268 // nsConnectionEntry
michael@0 269 //
michael@0 270 // mCT maps connection info hash key to nsConnectionEntry object, which
michael@0 271 // contains list of active and idle connections as well as the list of
michael@0 272 // pending transactions.
michael@0 273 //
michael@0 274 class nsConnectionEntry
michael@0 275 {
michael@0 276 public:
michael@0 277 nsConnectionEntry(nsHttpConnectionInfo *ci);
michael@0 278 ~nsConnectionEntry();
michael@0 279
michael@0 280 nsHttpConnectionInfo *mConnInfo;
michael@0 281 nsTArray<nsHttpTransaction*> mPendingQ; // pending transaction queue
michael@0 282 nsTArray<nsHttpConnection*> mActiveConns; // active connections
michael@0 283 nsTArray<nsHttpConnection*> mIdleConns; // idle persistent connections
michael@0 284 nsTArray<nsHalfOpenSocket*> mHalfOpens; // half open connections
michael@0 285
michael@0 286 // calculate the number of half open sockets that have not had at least 1
michael@0 287 // connection complete
michael@0 288 uint32_t UnconnectedHalfOpens();
michael@0 289
michael@0 290 // Remove a particular half open socket from the mHalfOpens array
michael@0 291 void RemoveHalfOpen(nsHalfOpenSocket *);
michael@0 292
michael@0 293 // Pipeline depths for various states
michael@0 294 const static uint32_t kPipelineUnlimited = 1024; // fully open - extended green
michael@0 295 const static uint32_t kPipelineOpen = 6; // 6 on each conn - normal green
michael@0 296 const static uint32_t kPipelineRestricted = 2; // 2 on just 1 conn in yellow
michael@0 297
michael@0 298 nsHttpConnectionMgr::PipeliningState PipelineState();
michael@0 299 void OnPipelineFeedbackInfo(
michael@0 300 nsHttpConnectionMgr::PipelineFeedbackInfoType info,
michael@0 301 nsHttpConnection *, uint32_t);
michael@0 302 bool SupportsPipelining();
michael@0 303 uint32_t MaxPipelineDepth(nsAHttpTransaction::Classifier classification);
michael@0 304 void CreditPenalty();
michael@0 305
michael@0 306 nsHttpConnectionMgr::PipeliningState mPipelineState;
michael@0 307
michael@0 308 void SetYellowConnection(nsHttpConnection *);
michael@0 309 void OnYellowComplete();
michael@0 310 uint32_t mYellowGoodEvents;
michael@0 311 uint32_t mYellowBadEvents;
michael@0 312 nsHttpConnection *mYellowConnection;
michael@0 313
michael@0 314 // initialGreenDepth is the max depth of a pipeline when you first
michael@0 315 // transition to green. Normally this is kPipelineOpen, but it can
michael@0 316 // be kPipelineUnlimited in aggressive mode.
michael@0 317 uint32_t mInitialGreenDepth;
michael@0 318
michael@0 319 // greenDepth is the current max allowed depth of a pipeline when
michael@0 320 // in the green state. Normally this starts as kPipelineOpen and
michael@0 321 // grows to kPipelineUnlimited after a pipeline of depth 3 has been
michael@0 322 // successfully transacted.
michael@0 323 uint32_t mGreenDepth;
michael@0 324
michael@0 325 // pipeliningPenalty is the current amount of penalty points this host
michael@0 326 // entry has earned for participating in events that are not conducive
michael@0 327 // to good pipelines - such as head of line blocking, canceled pipelines,
michael@0 328 // etc.. penalties are paid back either through elapsed time or simply
michael@0 329 // healthy transactions. Having penalty points means that this host is
michael@0 330 // not currently eligible for pipelines.
michael@0 331 int16_t mPipeliningPenalty;
michael@0 332
michael@0 333 // some penalty points only apply to particular classifications of
michael@0 334 // transactions - this allows a server that perhaps has head of line
michael@0 335 // blocking problems on CGI queries to still serve JS pipelined.
michael@0 336 int16_t mPipeliningClassPenalty[nsAHttpTransaction::CLASS_MAX];
michael@0 337
michael@0 338 // for calculating penalty repair credits
michael@0 339 TimeStamp mLastCreditTime;
michael@0 340
michael@0 341 // Spdy sometimes resolves the address in the socket manager in order
michael@0 342 // to re-coalesce sharded HTTP hosts. The dotted decimal address is
michael@0 343 // combined with the Anonymous flag from the connection information
michael@0 344 // to build the hash key for hosts in the same ip pool.
michael@0 345 //
michael@0 346 // When a set of hosts are coalesced together one of them is marked
michael@0 347 // mSpdyPreferred. The mapping is maintained in the connection mananger
michael@0 348 // mSpdyPreferred hash.
michael@0 349 //
michael@0 350 nsCString mCoalescingKey;
michael@0 351
michael@0 352 // The value of a recevied SPDY settings type 5 previously received
michael@0 353 // for this connection entry and the time it was set.
michael@0 354 uint32_t mSpdyCWND;
michael@0 355 TimeStamp mSpdyCWNDTimeStamp;
michael@0 356
michael@0 357 // To have the UsingSpdy flag means some host with the same connection
michael@0 358 // entry has done NPN=spdy/* at some point. It does not mean every
michael@0 359 // connection is currently using spdy.
michael@0 360 bool mUsingSpdy;
michael@0 361
michael@0 362 // mTestedSpdy is set after NPN negotiation has occurred and we know
michael@0 363 // with confidence whether a host speaks spdy or not (which is reflected
michael@0 364 // in mUsingSpdy). Before mTestedSpdy is set, handshake parallelism is
michael@0 365 // minimized so that we can multiplex on a single spdy connection.
michael@0 366 bool mTestedSpdy;
michael@0 367
michael@0 368 bool mSpdyPreferred;
michael@0 369
michael@0 370 // Flags to remember our happy-eyeballs decision.
michael@0 371 // Reset only by Ctrl-F5 reload.
michael@0 372 // True when we've first connected an IPv4 server for this host,
michael@0 373 // initially false.
michael@0 374 bool mPreferIPv4 : 1;
michael@0 375 // True when we've first connected an IPv6 server for this host,
michael@0 376 // initially false.
michael@0 377 bool mPreferIPv6 : 1;
michael@0 378
michael@0 379 // Set the IP family preference flags according the connected family
michael@0 380 void RecordIPFamilyPreference(uint16_t family);
michael@0 381 // Resets all flags to their default values
michael@0 382 void ResetIPFamilyPreference();
michael@0 383 };
michael@0 384
michael@0 385 // nsConnectionHandle
michael@0 386 //
michael@0 387 // thin wrapper around a real connection, used to keep track of references
michael@0 388 // to the connection to determine when the connection may be reused. the
michael@0 389 // transaction (or pipeline) owns a reference to this handle. this extra
michael@0 390 // layer of indirection greatly simplifies consumer code, avoiding the
michael@0 391 // need for consumer code to know when to give the connection back to the
michael@0 392 // connection manager.
michael@0 393 //
michael@0 394 class nsConnectionHandle : public nsAHttpConnection
michael@0 395 {
michael@0 396 public:
michael@0 397 NS_DECL_THREADSAFE_ISUPPORTS
michael@0 398 NS_DECL_NSAHTTPCONNECTION(mConn)
michael@0 399
michael@0 400 nsConnectionHandle(nsHttpConnection *conn) { NS_ADDREF(mConn = conn); }
michael@0 401 virtual ~nsConnectionHandle();
michael@0 402
michael@0 403 nsHttpConnection *mConn;
michael@0 404 };
michael@0 405
michael@0 406 // nsHalfOpenSocket is used to hold the state of an opening TCP socket
michael@0 407 // while we wait for it to establish and bind it to a connection
michael@0 408
michael@0 409 class nsHalfOpenSocket MOZ_FINAL : public nsIOutputStreamCallback,
michael@0 410 public nsITransportEventSink,
michael@0 411 public nsIInterfaceRequestor,
michael@0 412 public nsITimerCallback
michael@0 413 {
michael@0 414 public:
michael@0 415 NS_DECL_THREADSAFE_ISUPPORTS
michael@0 416 NS_DECL_NSIOUTPUTSTREAMCALLBACK
michael@0 417 NS_DECL_NSITRANSPORTEVENTSINK
michael@0 418 NS_DECL_NSIINTERFACEREQUESTOR
michael@0 419 NS_DECL_NSITIMERCALLBACK
michael@0 420
michael@0 421 nsHalfOpenSocket(nsConnectionEntry *ent,
michael@0 422 nsAHttpTransaction *trans,
michael@0 423 uint32_t caps);
michael@0 424 ~nsHalfOpenSocket();
michael@0 425
michael@0 426 nsresult SetupStreams(nsISocketTransport **,
michael@0 427 nsIAsyncInputStream **,
michael@0 428 nsIAsyncOutputStream **,
michael@0 429 bool isBackup);
michael@0 430 nsresult SetupPrimaryStreams();
michael@0 431 nsresult SetupBackupStreams();
michael@0 432 void SetupBackupTimer();
michael@0 433 void CancelBackupTimer();
michael@0 434 void Abandon();
michael@0 435 double Duration(TimeStamp epoch);
michael@0 436 nsISocketTransport *SocketTransport() { return mSocketTransport; }
michael@0 437 nsISocketTransport *BackupTransport() { return mBackupTransport; }
michael@0 438
michael@0 439 nsAHttpTransaction *Transaction() { return mTransaction; }
michael@0 440
michael@0 441 bool IsSpeculative() { return mSpeculative; }
michael@0 442 void SetSpeculative(bool val) { mSpeculative = val; }
michael@0 443
michael@0 444 bool HasConnected() { return mHasConnected; }
michael@0 445
michael@0 446 void PrintDiagnostics(nsCString &log);
michael@0 447 private:
michael@0 448 nsConnectionEntry *mEnt;
michael@0 449 nsRefPtr<nsAHttpTransaction> mTransaction;
michael@0 450 nsCOMPtr<nsISocketTransport> mSocketTransport;
michael@0 451 nsCOMPtr<nsIAsyncOutputStream> mStreamOut;
michael@0 452 nsCOMPtr<nsIAsyncInputStream> mStreamIn;
michael@0 453 uint32_t mCaps;
michael@0 454
michael@0 455 // mSpeculative is set if the socket was created from
michael@0 456 // SpeculativeConnect(). It is cleared when a transaction would normally
michael@0 457 // start a new connection from scratch but instead finds this one in
michael@0 458 // the half open list and claims it for its own use. (which due to
michael@0 459 // the vagaries of scheduling from the pending queue might not actually
michael@0 460 // match up - but it prevents a speculative connection from opening
michael@0 461 // more connections that are needed.)
michael@0 462 bool mSpeculative;
michael@0 463
michael@0 464 TimeStamp mPrimarySynStarted;
michael@0 465 TimeStamp mBackupSynStarted;
michael@0 466
michael@0 467 // for syn retry
michael@0 468 nsCOMPtr<nsITimer> mSynTimer;
michael@0 469 nsCOMPtr<nsISocketTransport> mBackupTransport;
michael@0 470 nsCOMPtr<nsIAsyncOutputStream> mBackupStreamOut;
michael@0 471 nsCOMPtr<nsIAsyncInputStream> mBackupStreamIn;
michael@0 472
michael@0 473 bool mHasConnected;
michael@0 474 };
michael@0 475 friend class nsHalfOpenSocket;
michael@0 476
michael@0 477 //-------------------------------------------------------------------------
michael@0 478 // NOTE: these members may be accessed from any thread (use mReentrantMonitor)
michael@0 479 //-------------------------------------------------------------------------
michael@0 480
michael@0 481 ReentrantMonitor mReentrantMonitor;
michael@0 482 nsCOMPtr<nsIEventTarget> mSocketThreadTarget;
michael@0 483
michael@0 484 // connection limits
michael@0 485 uint16_t mMaxConns;
michael@0 486 uint16_t mMaxPersistConnsPerHost;
michael@0 487 uint16_t mMaxPersistConnsPerProxy;
michael@0 488 uint16_t mMaxRequestDelay; // in seconds
michael@0 489 uint16_t mMaxPipelinedRequests;
michael@0 490 uint16_t mMaxOptimisticPipelinedRequests;
michael@0 491 bool mIsShuttingDown;
michael@0 492
michael@0 493 //-------------------------------------------------------------------------
michael@0 494 // NOTE: these members are only accessed on the socket transport thread
michael@0 495 //-------------------------------------------------------------------------
michael@0 496
michael@0 497 static PLDHashOperator ProcessOneTransactionCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
michael@0 498 static PLDHashOperator ProcessAllTransactionsCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
michael@0 499
michael@0 500 static PLDHashOperator PruneDeadConnectionsCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
michael@0 501 static PLDHashOperator ShutdownPassCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
michael@0 502 static PLDHashOperator PurgeExcessIdleConnectionsCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
michael@0 503 static PLDHashOperator PurgeExcessSpdyConnectionsCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
michael@0 504 static PLDHashOperator ClosePersistentConnectionsCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
michael@0 505 bool ProcessPendingQForEntry(nsConnectionEntry *, bool considerAll);
michael@0 506 bool IsUnderPressure(nsConnectionEntry *ent,
michael@0 507 nsHttpTransaction::Classifier classification);
michael@0 508 bool AtActiveConnectionLimit(nsConnectionEntry *, uint32_t caps);
michael@0 509 nsresult TryDispatchTransaction(nsConnectionEntry *ent,
michael@0 510 bool onlyReusedConnection,
michael@0 511 nsHttpTransaction *trans);
michael@0 512 nsresult DispatchTransaction(nsConnectionEntry *,
michael@0 513 nsHttpTransaction *,
michael@0 514 nsHttpConnection *);
michael@0 515 nsresult DispatchAbstractTransaction(nsConnectionEntry *,
michael@0 516 nsAHttpTransaction *,
michael@0 517 uint32_t,
michael@0 518 nsHttpConnection *,
michael@0 519 int32_t);
michael@0 520 nsresult BuildPipeline(nsConnectionEntry *,
michael@0 521 nsAHttpTransaction *,
michael@0 522 nsHttpPipeline **);
michael@0 523 bool HasPipelines(nsConnectionEntry *);
michael@0 524 bool RestrictConnections(nsConnectionEntry *, bool = false);
michael@0 525 nsresult ProcessNewTransaction(nsHttpTransaction *);
michael@0 526 nsresult EnsureSocketThreadTarget();
michael@0 527 void ClosePersistentConnections(nsConnectionEntry *ent);
michael@0 528 void ReportProxyTelemetry(nsConnectionEntry *ent);
michael@0 529 nsresult CreateTransport(nsConnectionEntry *, nsAHttpTransaction *,
michael@0 530 uint32_t, bool);
michael@0 531 void AddActiveConn(nsHttpConnection *, nsConnectionEntry *);
michael@0 532 void DecrementActiveConnCount(nsHttpConnection *);
michael@0 533 void StartedConnect();
michael@0 534 void RecvdConnect();
michael@0 535
michael@0 536 nsConnectionEntry *GetOrCreateConnectionEntry(nsHttpConnectionInfo *);
michael@0 537
michael@0 538 nsresult MakeNewConnection(nsConnectionEntry *ent,
michael@0 539 nsHttpTransaction *trans);
michael@0 540 bool AddToBestPipeline(nsConnectionEntry *ent,
michael@0 541 nsHttpTransaction *trans,
michael@0 542 nsHttpTransaction::Classifier classification,
michael@0 543 uint16_t depthLimit);
michael@0 544
michael@0 545 // Manage the preferred spdy connection entry for this address
michael@0 546 nsConnectionEntry *GetSpdyPreferredEnt(nsConnectionEntry *aOriginalEntry);
michael@0 547 void RemoveSpdyPreferredEnt(nsACString &aDottedDecimal);
michael@0 548 nsHttpConnection *GetSpdyPreferredConn(nsConnectionEntry *ent);
michael@0 549 nsDataHashtable<nsCStringHashKey, nsConnectionEntry *> mSpdyPreferredHash;
michael@0 550 nsConnectionEntry *LookupConnectionEntry(nsHttpConnectionInfo *ci,
michael@0 551 nsHttpConnection *conn,
michael@0 552 nsHttpTransaction *trans);
michael@0 553
michael@0 554 void ProcessSpdyPendingQ(nsConnectionEntry *ent);
michael@0 555 static PLDHashOperator ProcessSpdyPendingQCB(
michael@0 556 const nsACString &key, nsAutoPtr<nsConnectionEntry> &ent,
michael@0 557 void *closure);
michael@0 558
michael@0 559 // message handlers have this signature
michael@0 560 typedef void (nsHttpConnectionMgr:: *nsConnEventHandler)(int32_t, void *);
michael@0 561
michael@0 562 // nsConnEvent
michael@0 563 //
michael@0 564 // subclass of nsRunnable used to marshall events to the socket transport
michael@0 565 // thread. this class is used to implement PostEvent.
michael@0 566 //
michael@0 567 class nsConnEvent;
michael@0 568 friend class nsConnEvent;
michael@0 569 class nsConnEvent : public nsRunnable
michael@0 570 {
michael@0 571 public:
michael@0 572 nsConnEvent(nsHttpConnectionMgr *mgr,
michael@0 573 nsConnEventHandler handler,
michael@0 574 int32_t iparam,
michael@0 575 void *vparam)
michael@0 576 : mMgr(mgr)
michael@0 577 , mHandler(handler)
michael@0 578 , mIParam(iparam)
michael@0 579 , mVParam(vparam)
michael@0 580 {
michael@0 581 NS_ADDREF(mMgr);
michael@0 582 }
michael@0 583
michael@0 584 NS_IMETHOD Run()
michael@0 585 {
michael@0 586 (mMgr->*mHandler)(mIParam, mVParam);
michael@0 587 return NS_OK;
michael@0 588 }
michael@0 589
michael@0 590 private:
michael@0 591 virtual ~nsConnEvent()
michael@0 592 {
michael@0 593 NS_RELEASE(mMgr);
michael@0 594 }
michael@0 595
michael@0 596 nsHttpConnectionMgr *mMgr;
michael@0 597 nsConnEventHandler mHandler;
michael@0 598 int32_t mIParam;
michael@0 599 void *mVParam;
michael@0 600 };
michael@0 601
michael@0 602 nsresult PostEvent(nsConnEventHandler handler,
michael@0 603 int32_t iparam = 0,
michael@0 604 void *vparam = nullptr);
michael@0 605
michael@0 606 // message handlers
michael@0 607 void OnMsgShutdown (int32_t, void *);
michael@0 608 void OnMsgShutdownConfirm (int32_t, void *);
michael@0 609 void OnMsgNewTransaction (int32_t, void *);
michael@0 610 void OnMsgReschedTransaction (int32_t, void *);
michael@0 611 void OnMsgCancelTransaction (int32_t, void *);
michael@0 612 void OnMsgProcessPendingQ (int32_t, void *);
michael@0 613 void OnMsgPruneDeadConnections (int32_t, void *);
michael@0 614 void OnMsgSpeculativeConnect (int32_t, void *);
michael@0 615 void OnMsgReclaimConnection (int32_t, void *);
michael@0 616 void OnMsgCompleteUpgrade (int32_t, void *);
michael@0 617 void OnMsgUpdateParam (int32_t, void *);
michael@0 618 void OnMsgDoShiftReloadConnectionCleanup (int32_t, void *);
michael@0 619 void OnMsgProcessFeedback (int32_t, void *);
michael@0 620 void OnMsgProcessAllSpdyPendingQ (int32_t, void *);
michael@0 621 void OnMsgUpdateRequestTokenBucket (int32_t, void *);
michael@0 622
michael@0 623 // Total number of active connections in all of the ConnectionEntry objects
michael@0 624 // that are accessed from mCT connection table.
michael@0 625 uint16_t mNumActiveConns;
michael@0 626 // Total number of idle connections in all of the ConnectionEntry objects
michael@0 627 // that are accessed from mCT connection table.
michael@0 628 uint16_t mNumIdleConns;
michael@0 629 // Total number of spdy connections which are a subset of the active conns
michael@0 630 uint16_t mNumSpdyActiveConns;
michael@0 631 // Total number of connections in mHalfOpens ConnectionEntry objects
michael@0 632 // that are accessed from mCT connection table
michael@0 633 uint32_t mNumHalfOpenConns;
michael@0 634
michael@0 635 // Holds time in seconds for next wake-up to prune dead connections.
michael@0 636 uint64_t mTimeOfNextWakeUp;
michael@0 637 // Timer for next pruning of dead connections.
michael@0 638 nsCOMPtr<nsITimer> mTimer;
michael@0 639
michael@0 640 // A 1s tick to call nsHttpConnection::ReadTimeoutTick on
michael@0 641 // active http/1 connections and check for orphaned half opens.
michael@0 642 // Disabled when there are no active or half open connections.
michael@0 643 nsCOMPtr<nsITimer> mTimeoutTick;
michael@0 644 bool mTimeoutTickArmed;
michael@0 645 uint32_t mTimeoutTickNext;
michael@0 646
michael@0 647 //
michael@0 648 // the connection table
michael@0 649 //
michael@0 650 // this table is indexed by connection key. each entry is a
michael@0 651 // nsConnectionEntry object. It is unlocked and therefore must only
michael@0 652 // be accessed from the socket thread.
michael@0 653 //
michael@0 654 nsClassHashtable<nsCStringHashKey, nsConnectionEntry> mCT;
michael@0 655
michael@0 656 static PLDHashOperator ReadConnectionEntry(const nsACString &key,
michael@0 657 nsAutoPtr<nsConnectionEntry> &ent,
michael@0 658 void *aArg);
michael@0 659
michael@0 660 // Read Timeout Tick handlers
michael@0 661 void ActivateTimeoutTick();
michael@0 662 void TimeoutTick();
michael@0 663 static PLDHashOperator TimeoutTickCB(const nsACString &key,
michael@0 664 nsAutoPtr<nsConnectionEntry> &ent,
michael@0 665 void *closure);
michael@0 666
michael@0 667 // For diagnostics
michael@0 668 void OnMsgPrintDiagnostics(int32_t, void *);
michael@0 669 static PLDHashOperator PrintDiagnosticsCB(const nsACString &key,
michael@0 670 nsAutoPtr<nsConnectionEntry> &ent,
michael@0 671 void *closure);
michael@0 672 nsCString mLogData;
michael@0 673 };
michael@0 674
michael@0 675 }} // namespace mozilla::net
michael@0 676
michael@0 677 #endif // !nsHttpConnectionMgr_h__

mercurial