michael@0: /* vim:set ts=4 sw=4 sts=4 ci et: */ 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 nsSocketTransportService2_h__ michael@0: #define nsSocketTransportService2_h__ michael@0: michael@0: #include "nsPISocketTransportService.h" michael@0: #include "nsIThreadInternal.h" michael@0: #include "nsIRunnable.h" michael@0: #include "nsEventQueue.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "prinrval.h" michael@0: #include "prlog.h" michael@0: #include "prinit.h" michael@0: #include "nsIObserver.h" michael@0: #include "mozilla/Mutex.h" michael@0: #include "mozilla/net/DashboardTypes.h" michael@0: michael@0: class nsASocketHandler; michael@0: struct PRPollDesc; michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: #if defined(PR_LOGGING) michael@0: // michael@0: // set NSPR_LOG_MODULES=nsSocketTransport:5 michael@0: // michael@0: extern PRLogModuleInfo *gSocketTransportLog; michael@0: #endif michael@0: #define SOCKET_LOG(args) PR_LOG(gSocketTransportLog, PR_LOG_DEBUG, args) michael@0: #define SOCKET_LOG_ENABLED() PR_LOG_TEST(gSocketTransportLog, PR_LOG_DEBUG) michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: #define NS_SOCKET_POLL_TIMEOUT PR_INTERVAL_NO_TIMEOUT michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: namespace mozilla { michael@0: namespace net { michael@0: // These maximums are borrowed from the linux kernel. michael@0: static const int32_t kMaxTCPKeepIdle = 32767; // ~9 hours. michael@0: static const int32_t kMaxTCPKeepIntvl = 32767; michael@0: static const int32_t kMaxTCPKeepCount = 127; michael@0: static const int32_t kDefaultTCPKeepCount = michael@0: #if defined (XP_WIN) michael@0: 10; // Hardcoded in Windows. michael@0: #elif defined (XP_MACOSX) michael@0: 8; // Hardcoded in OSX. michael@0: #else michael@0: 4; // Specifiable in Linux. michael@0: #endif michael@0: } michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: class nsSocketTransportService : public nsPISocketTransportService michael@0: , public nsIEventTarget michael@0: , public nsIThreadObserver michael@0: , public nsIRunnable michael@0: , public nsIObserver michael@0: { michael@0: typedef mozilla::Mutex Mutex; michael@0: michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSPISOCKETTRANSPORTSERVICE michael@0: NS_DECL_NSISOCKETTRANSPORTSERVICE michael@0: NS_DECL_NSIEVENTTARGET michael@0: NS_DECL_NSITHREADOBSERVER michael@0: NS_DECL_NSIRUNNABLE michael@0: NS_DECL_NSIOBSERVER michael@0: michael@0: nsSocketTransportService(); michael@0: michael@0: // Max Socket count may need to get initialized/used by nsHttpHandler michael@0: // before this class is initialized. michael@0: static uint32_t gMaxCount; michael@0: static PRCallOnceType gMaxCountInitOnce; michael@0: static PRStatus DiscoverMaxCount(); michael@0: michael@0: // michael@0: // the number of sockets that can be attached at any given time is michael@0: // limited. this is done because some operating systems (e.g., Win9x) michael@0: // limit the number of sockets that can be created by an application. michael@0: // AttachSocket will fail if the limit is exceeded. consumers should michael@0: // call CanAttachSocket and check the result before creating a socket. michael@0: // michael@0: bool CanAttachSocket() { michael@0: return mActiveCount + mIdleCount < gMaxCount; michael@0: } michael@0: michael@0: // Called by the networking dashboard on the socket thread only michael@0: // Fills the passed array with socket information michael@0: void GetSocketConnections(nsTArray *); michael@0: uint64_t GetSentBytes() { return mSentBytesCount; } michael@0: uint64_t GetReceivedBytes() { return mReceivedBytesCount; } michael@0: michael@0: // Returns true if keepalives are enabled in prefs. michael@0: bool IsKeepaliveEnabled() { return mKeepaliveEnabledPref; } michael@0: protected: michael@0: michael@0: virtual ~nsSocketTransportService(); michael@0: michael@0: private: michael@0: michael@0: //------------------------------------------------------------------------- michael@0: // misc (any thread) michael@0: //------------------------------------------------------------------------- michael@0: michael@0: nsCOMPtr mThread; // protected by mLock michael@0: PRFileDesc *mThreadEvent; michael@0: // protected by mLock. mThreadEvent may change michael@0: // if the old pollable event is broken. only michael@0: // the socket thread may change mThreadEvent; michael@0: // it needs to lock mLock only when it changes michael@0: // mThreadEvent. other threads don't change michael@0: // mThreadEvent; they need to lock mLock michael@0: // whenever they access mThreadEvent. michael@0: bool mAutodialEnabled; michael@0: // pref to control autodial code michael@0: michael@0: // Returns mThread, protecting the get-and-addref with mLock michael@0: already_AddRefed GetThreadSafely(); michael@0: michael@0: //------------------------------------------------------------------------- michael@0: // initialization and shutdown (any thread) michael@0: //------------------------------------------------------------------------- michael@0: michael@0: Mutex mLock; michael@0: bool mInitialized; michael@0: bool mShuttingDown; michael@0: // indicates whether we are currently in the michael@0: // process of shutting down michael@0: bool mOffline; michael@0: bool mGoingOffline; michael@0: michael@0: // Detaches all sockets. michael@0: void Reset(bool aGuardLocals); michael@0: michael@0: //------------------------------------------------------------------------- michael@0: // socket lists (socket thread only) michael@0: // michael@0: // only "active" sockets are on the poll list. the active list is kept michael@0: // in sync with the poll list such that: michael@0: // michael@0: // mActiveList[k].mFD == mPollList[k+1].fd michael@0: // michael@0: // where k=0,1,2,... michael@0: //------------------------------------------------------------------------- michael@0: michael@0: struct SocketContext michael@0: { michael@0: PRFileDesc *mFD; michael@0: nsASocketHandler *mHandler; michael@0: uint16_t mElapsedTime; // time elapsed w/o activity michael@0: }; michael@0: michael@0: SocketContext *mActiveList; /* mListSize entries */ michael@0: SocketContext *mIdleList; /* mListSize entries */ michael@0: michael@0: uint32_t mActiveListSize; michael@0: uint32_t mIdleListSize; michael@0: uint32_t mActiveCount; michael@0: uint32_t mIdleCount; michael@0: michael@0: nsresult DetachSocket(SocketContext *, SocketContext *); michael@0: nsresult AddToIdleList(SocketContext *); michael@0: nsresult AddToPollList(SocketContext *); michael@0: void RemoveFromIdleList(SocketContext *); michael@0: void RemoveFromPollList(SocketContext *); michael@0: void MoveToIdleList(SocketContext *sock); michael@0: void MoveToPollList(SocketContext *sock); michael@0: michael@0: bool GrowActiveList(); michael@0: bool GrowIdleList(); michael@0: void InitMaxCount(); michael@0: michael@0: // Total bytes number transfered through all the sockets except active ones michael@0: uint64_t mSentBytesCount; michael@0: uint64_t mReceivedBytesCount; michael@0: //------------------------------------------------------------------------- michael@0: // poll list (socket thread only) michael@0: // michael@0: // first element of the poll list is mThreadEvent (or null if the pollable michael@0: // event cannot be created). michael@0: //------------------------------------------------------------------------- michael@0: michael@0: PRPollDesc *mPollList; /* mListSize + 1 entries */ michael@0: michael@0: PRIntervalTime PollTimeout(); // computes ideal poll timeout michael@0: nsresult DoPollIteration(bool wait); michael@0: // perfoms a single poll iteration michael@0: int32_t Poll(bool wait, uint32_t *interval); michael@0: // calls PR_Poll. the out param michael@0: // interval indicates the poll michael@0: // duration in seconds. michael@0: michael@0: //------------------------------------------------------------------------- michael@0: // pending socket queue - see NotifyWhenCanAttachSocket michael@0: //------------------------------------------------------------------------- michael@0: michael@0: nsEventQueue mPendingSocketQ; // queue of nsIRunnable objects michael@0: michael@0: // Preference Monitor for SendBufferSize and Keepalive prefs. michael@0: nsresult UpdatePrefs(); michael@0: int32_t mSendBufferSize; michael@0: // Number of seconds of connection is idle before first keepalive ping. michael@0: int32_t mKeepaliveIdleTimeS; michael@0: // Number of seconds between retries should keepalive pings fail. michael@0: int32_t mKeepaliveRetryIntervalS; michael@0: // Number of keepalive probes to send. michael@0: int32_t mKeepaliveProbeCount; michael@0: // True if TCP keepalive is enabled globally. michael@0: bool mKeepaliveEnabledPref; michael@0: michael@0: void OnKeepaliveEnabledPrefChange(); michael@0: void NotifyKeepaliveEnabledPrefChange(SocketContext *sock); michael@0: michael@0: // Socket thread only for dynamically adjusting max socket size michael@0: #if defined(XP_WIN) michael@0: void ProbeMaxCount(); michael@0: #endif michael@0: bool mProbedMaxCount; michael@0: michael@0: void AnalyzeConnection(nsTArray *data, michael@0: SocketContext *context, bool aActive); michael@0: michael@0: void ClosePrivateConnections(); michael@0: void DetachSocketWithGuard(bool aGuardLocals, michael@0: SocketContext *socketList, michael@0: int32_t index); michael@0: }; michael@0: michael@0: extern nsSocketTransportService *gSocketTransportService; michael@0: extern PRThread *gSocketThread; michael@0: michael@0: #endif // !nsSocketTransportService_h__