1 /* vim:set ts=4 sw=2 sts=2 ci et: */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef nsSocketTransportService2_h__
7 #define nsSocketTransportService2_h__
8 
9 #include "nsPISocketTransportService.h"
10 #include "nsIThreadInternal.h"
11 #include "nsIRunnable.h"
12 #include "nsCOMPtr.h"
13 #include "prinrval.h"
14 #include "mozilla/Logging.h"
15 #include "prinit.h"
16 #include "nsIObserver.h"
17 #include "mozilla/LinkedList.h"
18 #include "mozilla/Maybe.h"
19 #include "mozilla/Mutex.h"
20 #include "mozilla/net/DashboardTypes.h"
21 #include "mozilla/Atomics.h"
22 #include "mozilla/TimeStamp.h"
23 #include "mozilla/Tuple.h"
24 #include "nsITimer.h"
25 #include "mozilla/UniquePtr.h"
26 #include "PollableEvent.h"
27 
28 class nsASocketHandler;
29 struct PRPollDesc;
30 class nsIPrefBranch;
31 
32 //-----------------------------------------------------------------------------
33 
34 namespace mozilla {
35 class AbstractThread;
36 namespace net {
37 
38 //
39 // set MOZ_LOG=nsSocketTransport:5
40 //
41 extern LazyLogModule gSocketTransportLog;
42 #define SOCKET_LOG(args) MOZ_LOG(gSocketTransportLog, LogLevel::Debug, args)
43 #define SOCKET_LOG1(args) MOZ_LOG(gSocketTransportLog, LogLevel::Error, args)
44 #define SOCKET_LOG_ENABLED() MOZ_LOG_TEST(gSocketTransportLog, LogLevel::Debug)
45 
46 //
47 // set MOZ_LOG=UDPSocket:5
48 //
49 extern LazyLogModule gUDPSocketLog;
50 #define UDPSOCKET_LOG(args) MOZ_LOG(gUDPSocketLog, LogLevel::Debug, args)
51 #define UDPSOCKET_LOG_ENABLED() MOZ_LOG_TEST(gUDPSocketLog, LogLevel::Debug)
52 
53 //-----------------------------------------------------------------------------
54 
55 #define NS_SOCKET_POLL_TIMEOUT PR_INTERVAL_NO_TIMEOUT
56 
57 //-----------------------------------------------------------------------------
58 
59 // These maximums are borrowed from the linux kernel.
60 static const int32_t kMaxTCPKeepIdle = 32767;  // ~9 hours.
61 static const int32_t kMaxTCPKeepIntvl = 32767;
62 static const int32_t kMaxTCPKeepCount = 127;
63 static const int32_t kDefaultTCPKeepCount =
64 #if defined(XP_WIN)
65     10;  // Hardcoded in Windows.
66 #elif defined(XP_MACOSX)
67     8;  // Hardcoded in OSX.
68 #else
69     4;  // Specifiable in Linux.
70 #endif
71 
72 class LinkedRunnableEvent final
73     : public LinkedListElement<LinkedRunnableEvent> {
74  public:
LinkedRunnableEvent(nsIRunnable * event)75   explicit LinkedRunnableEvent(nsIRunnable* event) : mEvent(event) {}
76   ~LinkedRunnableEvent() = default;
77 
TakeEvent()78   already_AddRefed<nsIRunnable> TakeEvent() { return mEvent.forget(); }
79 
80  private:
81   nsCOMPtr<nsIRunnable> mEvent;
82 };
83 
84 //-----------------------------------------------------------------------------
85 
86 class nsSocketTransportService final : public nsPISocketTransportService,
87                                        public nsISerialEventTarget,
88                                        public nsIThreadObserver,
89                                        public nsIRunnable,
90                                        public nsIObserver {
91  public:
92   NS_DECL_THREADSAFE_ISUPPORTS
93   NS_DECL_NSPISOCKETTRANSPORTSERVICE
94   NS_DECL_NSISOCKETTRANSPORTSERVICE
95   NS_DECL_NSIROUTEDSOCKETTRANSPORTSERVICE
96   NS_DECL_NSIEVENTTARGET_FULL
97   NS_DECL_NSITHREADOBSERVER
98   NS_DECL_NSIRUNNABLE
99   NS_DECL_NSIOBSERVER
100 
101   nsSocketTransportService();
102 
103   // Max Socket count may need to get initialized/used by nsHttpHandler
104   // before this class is initialized.
105   static uint32_t gMaxCount;
106   static PRCallOnceType gMaxCountInitOnce;
107   static PRStatus DiscoverMaxCount();
108 
109   bool CanAttachSocket();
110 
111   // Called by the networking dashboard on the socket thread only
112   // Fills the passed array with socket information
113   void GetSocketConnections(nsTArray<SocketInfo>*);
GetSentBytes()114   uint64_t GetSentBytes() { return mSentBytesCount; }
GetReceivedBytes()115   uint64_t GetReceivedBytes() { return mReceivedBytesCount; }
116 
117   // Returns true if keepalives are enabled in prefs.
IsKeepaliveEnabled()118   bool IsKeepaliveEnabled() { return mKeepaliveEnabledPref; }
119 
120   bool IsTelemetryEnabledAndNotSleepPhase();
MaxTimeForPrClosePref()121   PRIntervalTime MaxTimeForPrClosePref() { return mMaxTimeForPrClosePref; }
122 
IsEsniEnabled()123   bool IsEsniEnabled() {
124     return mEsniEnabled && !mTrustedMitmDetected && !mNotTrustedMitmDetected;
125   }
126 
SetNotTrustedMitmDetected()127   void SetNotTrustedMitmDetected() { mNotTrustedMitmDetected = true; }
128 
129   // According the preference value of `network.socket.forcePort` this method
130   // possibly remaps the port number passed as the arg.
131   void ApplyPortRemap(uint16_t* aPort);
132 
133   // Reads the preference string and updates (rewrites) the mPortRemapping
134   // array on the socket thread.  Returns true if the whole pref string was
135   // correctly formed.
136   bool UpdatePortRemapPreference(nsACString const& aPortMappingPref);
137 
138  protected:
139   virtual ~nsSocketTransportService();
140 
141  private:
142   //-------------------------------------------------------------------------
143   // misc (any thread)
144   //-------------------------------------------------------------------------
145 
146   nsCOMPtr<nsIThread> mThread;  // protected by mLock
147   // We create an AbstractThread for mThread thread so that we can use direct
148   // task dispatching with MozPromise, which is similar (but not identical to)
149   // the microtask semantics of JS promises.
150   RefPtr<AbstractThread> mAbstractThread;
151   UniquePtr<PollableEvent> mPollableEvent;
152 
153   // Returns mThread, protecting the get-and-addref with mLock
154   already_AddRefed<nsIThread> GetThreadSafely();
155 
156   //-------------------------------------------------------------------------
157   // initialization and shutdown (any thread)
158   //-------------------------------------------------------------------------
159 
160   Mutex mLock;
161   bool mInitialized;
162   bool mShuttingDown;
163   // indicates whether we are currently in the
164   // process of shutting down
165   bool mOffline;
166   bool mGoingOffline;
167 
168   // Detaches all sockets.
169   void Reset(bool aGuardLocals);
170 
171   nsresult ShutdownThread();
172 
173   //-------------------------------------------------------------------------
174   // socket lists (socket thread only)
175   //
176   // only "active" sockets are on the poll list.  the active list is kept
177   // in sync with the poll list such that:
178   //
179   //   mActiveList[k].mFD == mPollList[k+1].fd
180   //
181   // where k=0,1,2,...
182   //-------------------------------------------------------------------------
183 
184   struct SocketContext {
185     PRFileDesc* mFD;
186     nsASocketHandler* mHandler;
187     PRIntervalTime mPollStartEpoch;  // time we started to poll this socket
188 
189    public:
190     // Returns true iff the socket has not been signalled longer than
191     // the desired timeout (mHandler->mPollTimeout).
192     bool IsTimedOut(PRIntervalTime now) const;
193     // Engages the timeout by marking the epoch we start polling this socket.
194     // If epoch is already marked this does nothing, hence, this method can be
195     // called everytime we put this socket to poll() list with in-flags set.
196     void EnsureTimeout(PRIntervalTime now);
197     // Called after an event on a socket has been signalled to turn of the
198     // timeout calculation.
199     void DisengageTimeout();
200     // Returns the number of intervals this socket is about to timeout in,
201     // or 0 (zero) when it has already timed out.  Returns
202     // NS_SOCKET_POLL_TIMEOUT when there is no timeout set on the socket.
203     PRIntervalTime TimeoutIn(PRIntervalTime now) const;
204     // When a socket timeout is reset and later set again, it may happen
205     // that mPollStartEpoch is not reset in between.  We have to manually
206     // call this on every iteration over sockets to ensure the epoch reset.
207     void MaybeResetEpoch();
208   };
209 
210   SocketContext* mActiveList; /* mListSize entries */
211   SocketContext* mIdleList;   /* mListSize entries */
212   nsIThread* mRawThread;
213 
214   uint32_t mActiveListSize;
215   uint32_t mIdleListSize;
216   uint32_t mActiveCount;
217   uint32_t mIdleCount;
218 
219   nsresult DetachSocket(SocketContext*, SocketContext*);
220   nsresult AddToIdleList(SocketContext*);
221   nsresult AddToPollList(SocketContext*);
222   void RemoveFromIdleList(SocketContext*);
223   void RemoveFromPollList(SocketContext*);
224   void MoveToIdleList(SocketContext* sock);
225   void MoveToPollList(SocketContext* sock);
226 
227   bool GrowActiveList();
228   bool GrowIdleList();
229   void InitMaxCount();
230 
231   // Total bytes number transfered through all the sockets except active ones
232   uint64_t mSentBytesCount;
233   uint64_t mReceivedBytesCount;
234   //-------------------------------------------------------------------------
235   // poll list (socket thread only)
236   //
237   // first element of the poll list is mPollableEvent (or null if the pollable
238   // event cannot be created).
239   //-------------------------------------------------------------------------
240 
241   PRPollDesc* mPollList; /* mListSize + 1 entries */
242 
243   PRIntervalTime PollTimeout(
244       PRIntervalTime now);  // computes ideal poll timeout
245   nsresult DoPollIteration(TimeDuration* pollDuration);
246   // perfoms a single poll iteration
247   int32_t Poll(TimeDuration* pollDuration, PRIntervalTime now);
248   // calls PR_Poll.  the out param
249   // interval indicates the poll
250   // duration in seconds.
251   // pollDuration is used only for
252   // telemetry
253 
254   //-------------------------------------------------------------------------
255   // pending socket queue - see NotifyWhenCanAttachSocket
256   //-------------------------------------------------------------------------
257   AutoCleanLinkedList<LinkedRunnableEvent> mPendingSocketQueue;
258 
259   // Preference Monitor for SendBufferSize and Keepalive prefs.
260   nsresult UpdatePrefs();
261   static void UpdatePrefs(const char* aPref, void* aSelf);
262   void UpdateSendBufferPref();
263   int32_t mSendBufferSize;
264   // Number of seconds of connection is idle before first keepalive ping.
265   int32_t mKeepaliveIdleTimeS;
266   // Number of seconds between retries should keepalive pings fail.
267   int32_t mKeepaliveRetryIntervalS;
268   // Number of keepalive probes to send.
269   int32_t mKeepaliveProbeCount;
270   // True if TCP keepalive is enabled globally.
271   bool mKeepaliveEnabledPref;
272   // Timeout of pollable event signalling.
273   TimeDuration mPollableEventTimeout;
274 
275   Atomic<bool> mServingPendingQueue;
276   Atomic<int32_t, Relaxed> mMaxTimePerPollIter;
277   Atomic<PRIntervalTime, Relaxed> mMaxTimeForPrClosePref;
278   // Timestamp of the last network link change event, tracked
279   // also on child processes.
280   Atomic<PRIntervalTime, Relaxed> mLastNetworkLinkChangeTime;
281   // Preference for how long we do busy wait after network link
282   // change has been detected.
283   Atomic<PRIntervalTime, Relaxed> mNetworkLinkChangeBusyWaitPeriod;
284   // Preference for the value of timeout for poll() we use during
285   // the network link change event period.
286   Atomic<PRIntervalTime, Relaxed> mNetworkLinkChangeBusyWaitTimeout;
287 
288   // Between a computer going to sleep and waking up the PR_*** telemetry
289   // will be corrupted - so do not record it.
290   Atomic<bool, Relaxed> mSleepPhase;
291   nsCOMPtr<nsITimer> mAfterWakeUpTimer;
292 
293   // Lazily created array of forced port remappings.  The tuple members meaning
294   // is exactly:
295   // <0> the greater-or-equal port number of the range to remap
296   // <1> the less-or-equal port number of the range to remap
297   // <2> the port number to remap to, when the given port number falls to the
298   // range
299   typedef CopyableTArray<Tuple<uint16_t, uint16_t, uint16_t>> TPortRemapping;
300   Maybe<TPortRemapping> mPortRemapping;
301 
302   // Called on the socket thread to apply the mapping build on the main thread
303   // from the preference.
304   void ApplyPortRemapPreference(TPortRemapping const& portRemapping);
305 
306   void OnKeepaliveEnabledPrefChange();
307   void NotifyKeepaliveEnabledPrefChange(SocketContext* sock);
308 
309   // Socket thread only for dynamically adjusting max socket size
310 #if defined(XP_WIN)
311   void ProbeMaxCount();
312 #endif
313   bool mProbedMaxCount;
314 
315   void AnalyzeConnection(nsTArray<SocketInfo>* data, SocketContext* context,
316                          bool aActive);
317 
318   void ClosePrivateConnections();
319   void DetachSocketWithGuard(bool aGuardLocals, SocketContext* socketList,
320                              int32_t index);
321 
322   void MarkTheLastElementOfPendingQueue();
323 
324 #if defined(XP_WIN)
325   Atomic<bool> mPolling;
326   nsCOMPtr<nsITimer> mPollRepairTimer;
327   void StartPollWatchdog();
328   void DoPollRepair();
329   void StartPolling();
330   void EndPolling();
331 #endif
332 
333   void TryRepairPollableEvent();
334 
335   bool mEsniEnabled;
336   bool mTrustedMitmDetected;
337   bool mNotTrustedMitmDetected;
338 };
339 
340 extern nsSocketTransportService* gSocketTransportService;
341 bool OnSocketThread();
342 
343 }  // namespace net
344 }  // namespace mozilla
345 
346 #endif  // !nsSocketTransportService_h__
347