1 : /* vim:set ts=4 sw=4 sts=4 et cin: */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 2002
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Darin Fisher <darin@netscape.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #ifndef nsHttpConnectionMgr_h__
40 : #define nsHttpConnectionMgr_h__
41 :
42 : #include "nsHttpConnectionInfo.h"
43 : #include "nsHttpConnection.h"
44 : #include "nsHttpTransaction.h"
45 : #include "nsTArray.h"
46 : #include "nsThreadUtils.h"
47 : #include "nsClassHashtable.h"
48 : #include "nsDataHashtable.h"
49 : #include "nsAutoPtr.h"
50 : #include "mozilla/ReentrantMonitor.h"
51 : #include "nsISocketTransportService.h"
52 :
53 : #include "nsIObserver.h"
54 : #include "nsITimer.h"
55 : #include "nsIX509Cert3.h"
56 :
57 : class nsHttpPipeline;
58 :
59 : //-----------------------------------------------------------------------------
60 :
61 : class nsHttpConnectionMgr : public nsIObserver
62 : {
63 : public:
64 : NS_DECL_ISUPPORTS
65 : NS_DECL_NSIOBSERVER
66 :
67 : // parameter names
68 : enum nsParamName {
69 : MAX_CONNECTIONS,
70 : MAX_CONNECTIONS_PER_HOST,
71 : MAX_CONNECTIONS_PER_PROXY,
72 : MAX_PERSISTENT_CONNECTIONS_PER_HOST,
73 : MAX_PERSISTENT_CONNECTIONS_PER_PROXY,
74 : MAX_REQUEST_DELAY,
75 : MAX_PIPELINED_REQUESTS
76 : };
77 :
78 : //-------------------------------------------------------------------------
79 : // NOTE: functions below may only be called on the main thread.
80 : //-------------------------------------------------------------------------
81 :
82 : nsHttpConnectionMgr();
83 :
84 : nsresult Init(PRUint16 maxConnections,
85 : PRUint16 maxConnectionsPerHost,
86 : PRUint16 maxConnectionsPerProxy,
87 : PRUint16 maxPersistentConnectionsPerHost,
88 : PRUint16 maxPersistentConnectionsPerProxy,
89 : PRUint16 maxRequestDelay,
90 : PRUint16 maxPipelinedRequests);
91 : nsresult Shutdown();
92 :
93 : //-------------------------------------------------------------------------
94 : // NOTE: functions below may be called on any thread.
95 : //-------------------------------------------------------------------------
96 :
97 : // Schedules next pruning of dead connection to happen after
98 : // given time.
99 : void PruneDeadConnectionsAfter(PRUint32 time);
100 :
101 : // Stops timer scheduled for next pruning of dead connections if
102 : // there are no more idle connections or active spdy ones
103 : void ConditionallyStopPruneDeadConnectionsTimer();
104 :
105 : // Stops timer used for the read timeout tick if there are no currently
106 : // active connections.
107 : void ConditionallyStopReadTimeoutTick();
108 :
109 : // adds a transaction to the list of managed transactions.
110 : nsresult AddTransaction(nsHttpTransaction *, PRInt32 priority);
111 :
112 : // called to reschedule the given transaction. it must already have been
113 : // added to the connection manager via AddTransaction.
114 : nsresult RescheduleTransaction(nsHttpTransaction *, PRInt32 priority);
115 :
116 : // cancels a transaction w/ the given reason.
117 : nsresult CancelTransaction(nsHttpTransaction *, nsresult reason);
118 :
119 : // called to force the connection manager to prune its list of idle
120 : // connections.
121 : nsresult PruneDeadConnections();
122 :
123 : // Close all idle persistent connections and prevent any active connections
124 : // from being reused.
125 : nsresult ClosePersistentConnections();
126 :
127 : // called to get a reference to the socket transport service. the socket
128 : // transport service is not available when the connection manager is down.
129 : nsresult GetSocketThreadTarget(nsIEventTarget **);
130 :
131 : // called when a connection is done processing a transaction. if the
132 : // connection can be reused then it will be added to the idle list, else
133 : // it will be closed.
134 : nsresult ReclaimConnection(nsHttpConnection *conn);
135 :
136 : // called to update a parameter after the connection manager has already
137 : // been initialized.
138 : nsresult UpdateParam(nsParamName name, PRUint16 value);
139 :
140 : // Lookup/Cancel HTTP->SPDY redirections
141 : bool GetSpdyAlternateProtocol(nsACString &key);
142 : void ReportSpdyAlternateProtocol(nsHttpConnection *);
143 : void RemoveSpdyAlternateProtocol(nsACString &key);
144 :
145 : //-------------------------------------------------------------------------
146 : // NOTE: functions below may be called only on the socket thread.
147 : //-------------------------------------------------------------------------
148 :
149 : // removes the next transaction for the specified connection from the
150 : // pending transaction queue.
151 : void AddTransactionToPipeline(nsHttpPipeline *);
152 :
153 : // called to force the transaction queue to be processed once more, giving
154 : // preference to the specified connection.
155 : nsresult ProcessPendingQ(nsHttpConnectionInfo *);
156 :
157 : // This is used to force an idle connection to be closed and removed from
158 : // the idle connection list. It is called when the idle connection detects
159 : // that the network peer has closed the transport.
160 : nsresult CloseIdleConnection(nsHttpConnection *);
161 :
162 : // The connection manager needs to know when a normal HTTP connection has been
163 : // upgraded to SPDY because the dispatch and idle semantics are a little
164 : // bit different.
165 : void ReportSpdyConnection(nsHttpConnection *, bool usingSpdy);
166 :
167 : private:
168 : virtual ~nsHttpConnectionMgr();
169 : class nsHalfOpenSocket;
170 :
171 : // nsConnectionEntry
172 : //
173 : // mCT maps connection info hash key to nsConnectionEntry object, which
174 : // contains list of active and idle connections as well as the list of
175 : // pending transactions.
176 : //
177 : struct nsConnectionEntry
178 : {
179 291 : nsConnectionEntry(nsHttpConnectionInfo *ci)
180 : : mConnInfo(ci),
181 : mUsingSpdy(false),
182 : mTestedSpdy(false),
183 291 : mSpdyPreferred(false)
184 : {
185 291 : NS_ADDREF(mConnInfo);
186 291 : }
187 : ~nsConnectionEntry();
188 :
189 : nsHttpConnectionInfo *mConnInfo;
190 : nsTArray<nsHttpTransaction*> mPendingQ; // pending transaction queue
191 : nsTArray<nsHttpConnection*> mActiveConns; // active connections
192 : nsTArray<nsHttpConnection*> mIdleConns; // idle persistent connections
193 : nsTArray<nsHalfOpenSocket*> mHalfOpens;
194 :
195 : // Spdy sometimes resolves the address in the socket manager in order
196 : // to re-coalesce sharded HTTP hosts. The dotted decimal address is
197 : // combined with the Anonymous flag from the connection information
198 : // to build the hash key for hosts in the same ip pool.
199 : //
200 : // When a set of hosts are coalesced together one of them is marked
201 : // mSpdyPreferred. The mapping is maintained in the connection mananger
202 : // mSpdyPreferred hash.
203 : //
204 : nsCString mCoalescingKey;
205 :
206 : // To have the UsingSpdy flag means some host with the same connection
207 : // entry has done NPN=spdy/2 at some point. It does not mean every
208 : // connection is currently using spdy.
209 : bool mUsingSpdy;
210 :
211 : // mTestedSpdy is set after NPN negotiation has occurred and we know
212 : // with confidence whether a host speaks spdy or not (which is reflected
213 : // in mUsingSpdy). Before mTestedSpdy is set, handshake parallelism is
214 : // minimized so that we can multiplex on a single spdy connection.
215 : bool mTestedSpdy;
216 :
217 : bool mSpdyPreferred;
218 : };
219 :
220 : // nsConnectionHandle
221 : //
222 : // thin wrapper around a real connection, used to keep track of references
223 : // to the connection to determine when the connection may be reused. the
224 : // transaction (or pipeline) owns a reference to this handle. this extra
225 : // layer of indirection greatly simplifies consumer code, avoiding the
226 : // need for consumer code to know when to give the connection back to the
227 : // connection manager.
228 : //
229 : class nsConnectionHandle : public nsAHttpConnection
230 : {
231 : public:
232 : NS_DECL_ISUPPORTS
233 : NS_DECL_NSAHTTPCONNECTION
234 :
235 2975 : nsConnectionHandle(nsHttpConnection *conn) { NS_ADDREF(mConn = conn); }
236 : virtual ~nsConnectionHandle();
237 :
238 : nsHttpConnection *mConn;
239 : };
240 :
241 : // nsHalfOpenSocket is used to hold the state of an opening TCP socket
242 : // while we wait for it to establish and bind it to a connection
243 :
244 : class nsHalfOpenSocket : public nsIOutputStreamCallback,
245 : public nsITransportEventSink,
246 : public nsIInterfaceRequestor,
247 : public nsITimerCallback
248 : {
249 : public:
250 : NS_DECL_ISUPPORTS
251 : NS_DECL_NSIOUTPUTSTREAMCALLBACK
252 : NS_DECL_NSITRANSPORTEVENTSINK
253 : NS_DECL_NSIINTERFACEREQUESTOR
254 : NS_DECL_NSITIMERCALLBACK
255 :
256 : nsHalfOpenSocket(nsConnectionEntry *ent,
257 : nsHttpTransaction *trans);
258 : ~nsHalfOpenSocket();
259 :
260 : nsresult SetupStreams(nsISocketTransport **,
261 : nsIAsyncInputStream **,
262 : nsIAsyncOutputStream **,
263 : bool isBackup);
264 : nsresult SetupPrimaryStreams();
265 : nsresult SetupBackupStreams();
266 : void SetupBackupTimer();
267 : void CancelBackupTimer();
268 : void Abandon();
269 :
270 110 : nsHttpTransaction *Transaction() { return mTransaction; }
271 :
272 : private:
273 : nsConnectionEntry *mEnt;
274 : nsRefPtr<nsHttpTransaction> mTransaction;
275 : nsCOMPtr<nsISocketTransport> mSocketTransport;
276 : nsCOMPtr<nsIAsyncOutputStream> mStreamOut;
277 : nsCOMPtr<nsIAsyncInputStream> mStreamIn;
278 :
279 : // for syn retry
280 : nsCOMPtr<nsITimer> mSynTimer;
281 : nsCOMPtr<nsISocketTransport> mBackupTransport;
282 : nsCOMPtr<nsIAsyncOutputStream> mBackupStreamOut;
283 : nsCOMPtr<nsIAsyncInputStream> mBackupStreamIn;
284 : };
285 : friend class nsHalfOpenSocket;
286 :
287 : //-------------------------------------------------------------------------
288 : // NOTE: these members may be accessed from any thread (use mReentrantMonitor)
289 : //-------------------------------------------------------------------------
290 :
291 : PRInt32 mRef;
292 : mozilla::ReentrantMonitor mReentrantMonitor;
293 : nsCOMPtr<nsIEventTarget> mSocketThreadTarget;
294 :
295 : // connection limits
296 : PRUint16 mMaxConns;
297 : PRUint16 mMaxConnsPerHost;
298 : PRUint16 mMaxConnsPerProxy;
299 : PRUint16 mMaxPersistConnsPerHost;
300 : PRUint16 mMaxPersistConnsPerProxy;
301 : PRUint16 mMaxRequestDelay; // in seconds
302 : PRUint16 mMaxPipelinedRequests;
303 :
304 : bool mIsShuttingDown;
305 :
306 : //-------------------------------------------------------------------------
307 : // NOTE: these members are only accessed on the socket transport thread
308 : //-------------------------------------------------------------------------
309 :
310 : static PLDHashOperator ProcessOneTransactionCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
311 :
312 : static PLDHashOperator PruneDeadConnectionsCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
313 : static PLDHashOperator ShutdownPassCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
314 : static PLDHashOperator PurgeExcessIdleConnectionsCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
315 : static PLDHashOperator ClosePersistentConnectionsCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
316 : bool ProcessPendingQForEntry(nsConnectionEntry *);
317 : bool AtActiveConnectionLimit(nsConnectionEntry *, PRUint8 caps);
318 : void GetConnection(nsConnectionEntry *, nsHttpTransaction *,
319 : bool, nsHttpConnection **);
320 : nsresult DispatchTransaction(nsConnectionEntry *, nsHttpTransaction *,
321 : PRUint8 caps, nsHttpConnection *);
322 : bool BuildPipeline(nsConnectionEntry *, nsAHttpTransaction *, nsHttpPipeline **);
323 : nsresult ProcessNewTransaction(nsHttpTransaction *);
324 : nsresult EnsureSocketThreadTargetIfOnline();
325 : void ClosePersistentConnections(nsConnectionEntry *ent);
326 : nsresult CreateTransport(nsConnectionEntry *, nsHttpTransaction *);
327 : void AddActiveConn(nsHttpConnection *, nsConnectionEntry *);
328 : void StartedConnect();
329 : void RecvdConnect();
330 :
331 : // Manage the preferred spdy connection entry for this address
332 : nsConnectionEntry *GetSpdyPreferredEnt(nsConnectionEntry *aOriginalEntry);
333 : void RemoveSpdyPreferredEnt(nsACString &aDottedDecimal);
334 : nsHttpConnection *GetSpdyPreferredConn(nsConnectionEntry *ent);
335 : nsDataHashtable<nsCStringHashKey, nsConnectionEntry *> mSpdyPreferredHash;
336 : nsConnectionEntry *LookupConnectionEntry(nsHttpConnectionInfo *ci,
337 : nsHttpConnection *conn,
338 : nsHttpTransaction *trans);
339 :
340 : void ProcessSpdyPendingQ(nsConnectionEntry *ent);
341 : void ProcessAllSpdyPendingQ();
342 : static PLDHashOperator ProcessSpdyPendingQCB(
343 : const nsACString &key, nsAutoPtr<nsConnectionEntry> &ent,
344 : void *closure);
345 :
346 : // message handlers have this signature
347 : typedef void (nsHttpConnectionMgr:: *nsConnEventHandler)(PRInt32, void *);
348 :
349 : // nsConnEvent
350 : //
351 : // subclass of nsRunnable used to marshall events to the socket transport
352 : // thread. this class is used to implement PostEvent.
353 : //
354 : class nsConnEvent;
355 : friend class nsConnEvent;
356 : class nsConnEvent : public nsRunnable
357 : {
358 : public:
359 7041 : nsConnEvent(nsHttpConnectionMgr *mgr,
360 : nsConnEventHandler handler,
361 : PRInt32 iparam,
362 : void *vparam)
363 : : mMgr(mgr)
364 : , mHandler(handler)
365 : , mIParam(iparam)
366 7041 : , mVParam(vparam)
367 : {
368 7041 : NS_ADDREF(mMgr);
369 7041 : }
370 :
371 7041 : NS_IMETHOD Run()
372 : {
373 7041 : (mMgr->*mHandler)(mIParam, mVParam);
374 7041 : return NS_OK;
375 : }
376 :
377 : private:
378 14082 : virtual ~nsConnEvent()
379 14082 : {
380 7041 : NS_RELEASE(mMgr);
381 28164 : }
382 :
383 : nsHttpConnectionMgr *mMgr;
384 : nsConnEventHandler mHandler;
385 : PRInt32 mIParam;
386 : void *mVParam;
387 : };
388 :
389 : nsresult PostEvent(nsConnEventHandler handler,
390 : PRInt32 iparam = 0,
391 : void *vparam = nsnull);
392 :
393 : // message handlers
394 : void OnMsgShutdown (PRInt32, void *);
395 : void OnMsgNewTransaction (PRInt32, void *);
396 : void OnMsgReschedTransaction (PRInt32, void *);
397 : void OnMsgCancelTransaction (PRInt32, void *);
398 : void OnMsgProcessPendingQ (PRInt32, void *);
399 : void OnMsgPruneDeadConnections (PRInt32, void *);
400 : void OnMsgReclaimConnection (PRInt32, void *);
401 : void OnMsgUpdateParam (PRInt32, void *);
402 : void OnMsgClosePersistentConnections (PRInt32, void *);
403 :
404 : // Total number of active connections in all of the ConnectionEntry objects
405 : // that are accessed from mCT connection table.
406 : PRUint16 mNumActiveConns;
407 : // Total number of idle connections in all of the ConnectionEntry objects
408 : // that are accessed from mCT connection table.
409 : PRUint16 mNumIdleConns;
410 :
411 : // Holds time in seconds for next wake-up to prune dead connections.
412 : PRUint64 mTimeOfNextWakeUp;
413 : // Timer for next pruning of dead connections.
414 : nsCOMPtr<nsITimer> mTimer;
415 :
416 : // A 1s tick to call nsHttpConnection::ReadTimeoutTick on
417 : // active http/1 connections. Disabled when there are no
418 : // active connections.
419 : nsCOMPtr<nsITimer> mReadTimeoutTick;
420 : bool mReadTimeoutTickArmed;
421 :
422 : //
423 : // the connection table
424 : //
425 : // this table is indexed by connection key. each entry is a
426 : // nsConnectionEntry object.
427 : //
428 : nsClassHashtable<nsCStringHashKey, nsConnectionEntry> mCT;
429 :
430 : // mAlternateProtocolHash is used only for spdy/2 upgrades for now
431 : // protected by the monitor
432 : nsTHashtable<nsCStringHashKey> mAlternateProtocolHash;
433 : static PLDHashOperator TrimAlternateProtocolHash(nsCStringHashKey *entry,
434 : void *closure);
435 : // Read Timeout Tick handlers
436 : void ActivateTimeoutTick();
437 : void ReadTimeoutTick();
438 : static PLDHashOperator ReadTimeoutTickCB(const nsACString &key,
439 : nsAutoPtr<nsConnectionEntry> &ent,
440 : void *closure);
441 : };
442 :
443 : #endif // !nsHttpConnectionMgr_h__
|