Line data Source code
1 : /* This Source Code Form is subject to the terms of the Mozilla Public
2 : * License, v. 2.0. If a copy of the MPL was not distributed with this
3 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #ifndef nsSocketTransport2_h__
6 : #define nsSocketTransport2_h__
7 :
8 : #ifdef DEBUG_darinf
9 : #define ENABLE_SOCKET_TRACING
10 : #endif
11 :
12 : #include "mozilla/Mutex.h"
13 : #include "nsSocketTransportService2.h"
14 : #include "nsString.h"
15 : #include "nsCOMPtr.h"
16 :
17 : #include "nsIInterfaceRequestor.h"
18 : #include "nsISocketTransport.h"
19 : #include "nsIAsyncInputStream.h"
20 : #include "nsIAsyncOutputStream.h"
21 : #include "nsIDNSListener.h"
22 : #include "nsIClassInfo.h"
23 : #include "TCPFastOpen.h"
24 : #include "mozilla/net/DNS.h"
25 : #include "nsASocketHandler.h"
26 : #include "mozilla/Telemetry.h"
27 :
28 : #include "prerror.h"
29 : #include "nsAutoPtr.h"
30 :
31 : class nsICancelable;
32 : class nsIDNSRecord;
33 : class nsIInterfaceRequestor;
34 :
35 : //-----------------------------------------------------------------------------
36 :
37 : // after this short interval, we will return to PR_Poll
38 : #define NS_SOCKET_CONNECT_TIMEOUT PR_MillisecondsToInterval(20)
39 :
40 : //-----------------------------------------------------------------------------
41 :
42 : namespace mozilla {
43 : namespace net {
44 :
45 : nsresult
46 : ErrorAccordingToNSPR(PRErrorCode errorCode);
47 :
48 : class nsSocketTransport;
49 :
50 : class nsSocketInputStream : public nsIAsyncInputStream
51 : {
52 : public:
53 : NS_DECL_ISUPPORTS_INHERITED
54 : NS_DECL_NSIINPUTSTREAM
55 : NS_DECL_NSIASYNCINPUTSTREAM
56 :
57 : explicit nsSocketInputStream(nsSocketTransport *);
58 : virtual ~nsSocketInputStream();
59 :
60 3 : bool IsReferenced() { return mReaderRefCnt > 0; }
61 : nsresult Condition() { return mCondition; }
62 12 : uint64_t ByteCount() { return mByteCount; }
63 :
64 : // called by the socket transport on the socket thread...
65 : void OnSocketReady(nsresult condition);
66 :
67 : private:
68 : nsSocketTransport *mTransport;
69 : ThreadSafeAutoRefCnt mReaderRefCnt;
70 :
71 : // access to these is protected by mTransport->mLock
72 : nsresult mCondition;
73 : nsCOMPtr<nsIInputStreamCallback> mCallback;
74 : uint32_t mCallbackFlags;
75 : uint64_t mByteCount;
76 : };
77 :
78 : //-----------------------------------------------------------------------------
79 :
80 : class nsSocketOutputStream : public nsIAsyncOutputStream
81 : {
82 : public:
83 : NS_DECL_ISUPPORTS_INHERITED
84 : NS_DECL_NSIOUTPUTSTREAM
85 : NS_DECL_NSIASYNCOUTPUTSTREAM
86 :
87 : explicit nsSocketOutputStream(nsSocketTransport *);
88 : virtual ~nsSocketOutputStream();
89 :
90 3 : bool IsReferenced() { return mWriterRefCnt > 0; }
91 : nsresult Condition() { return mCondition; }
92 5 : uint64_t ByteCount() { return mByteCount; }
93 :
94 : // called by the socket transport on the socket thread...
95 : void OnSocketReady(nsresult condition);
96 :
97 : private:
98 : static nsresult WriteFromSegments(nsIInputStream *, void *,
99 : const char *, uint32_t offset,
100 : uint32_t count, uint32_t *countRead);
101 :
102 : nsSocketTransport *mTransport;
103 : ThreadSafeAutoRefCnt mWriterRefCnt;
104 :
105 : // access to these is protected by mTransport->mLock
106 : nsresult mCondition;
107 : nsCOMPtr<nsIOutputStreamCallback> mCallback;
108 : uint32_t mCallbackFlags;
109 : uint64_t mByteCount;
110 : };
111 :
112 : //-----------------------------------------------------------------------------
113 :
114 : class nsSocketTransport final : public nsASocketHandler
115 : , public nsISocketTransport
116 : , public nsIDNSListener
117 : , public nsIClassInfo
118 : , public nsIInterfaceRequestor
119 : {
120 : public:
121 : NS_DECL_THREADSAFE_ISUPPORTS
122 : NS_DECL_NSITRANSPORT
123 : NS_DECL_NSISOCKETTRANSPORT
124 : NS_DECL_NSIDNSLISTENER
125 : NS_DECL_NSICLASSINFO
126 : NS_DECL_NSIINTERFACEREQUESTOR
127 :
128 : nsSocketTransport();
129 :
130 : // this method instructs the socket transport to open a socket of the
131 : // given type(s) to the given host or proxy.
132 : nsresult Init(const char **socketTypes, uint32_t typeCount,
133 : const nsACString &host, uint16_t port,
134 : const nsACString &hostRoute, uint16_t portRoute,
135 : nsIProxyInfo *proxyInfo);
136 :
137 : // Alternative Init method for when the IP-address of the host
138 : // has been pre-resolved using a alternative means (e.g. FlyWeb service
139 : // info).
140 : nsresult InitPreResolved(const char **socketTypes, uint32_t typeCount,
141 : const nsACString &host, uint16_t port,
142 : const nsACString &hostRoute, uint16_t portRoute,
143 : nsIProxyInfo *proxyInfo,
144 : const mozilla::net::NetAddr* addr);
145 :
146 : // this method instructs the socket transport to use an already connected
147 : // socket with the given address.
148 : nsresult InitWithConnectedSocket(PRFileDesc *socketFD,
149 : const NetAddr *addr);
150 :
151 : // this method instructs the socket transport to use an already connected
152 : // socket with the given address, and additionally supplies security info.
153 : nsresult InitWithConnectedSocket(PRFileDesc* aSocketFD,
154 : const NetAddr* aAddr,
155 : nsISupports* aSecInfo);
156 :
157 : // This method instructs the socket transport to open a socket
158 : // connected to the given Unix domain address. We can only create
159 : // unlayered, simple, stream sockets.
160 : nsresult InitWithFilename(const char *filename);
161 :
162 : // nsASocketHandler methods:
163 : void OnSocketReady(PRFileDesc *, int16_t outFlags) override;
164 : void OnSocketDetached(PRFileDesc *) override;
165 : void IsLocal(bool *aIsLocal) override;
166 : void OnKeepaliveEnabledPrefChange(bool aEnabled) override final;
167 :
168 : // called when a socket event is handled
169 : void OnSocketEvent(uint32_t type, nsresult status, nsISupports *param);
170 :
171 2 : uint64_t ByteCountReceived() override { return mInput.ByteCount(); }
172 2 : uint64_t ByteCountSent() override { return mOutput.ByteCount(); }
173 : static void CloseSocket(PRFileDesc *aFd, bool aTelemetryEnabled);
174 : static void SendPRBlockingTelemetry(PRIntervalTime aStart,
175 : Telemetry::HistogramID aIDNormal,
176 : Telemetry::HistogramID aIDShutdown,
177 : Telemetry::HistogramID aIDConnectivityChange,
178 : Telemetry::HistogramID aIDLinkChange,
179 : Telemetry::HistogramID aIDOffline);
180 : protected:
181 :
182 : virtual ~nsSocketTransport();
183 : void CleanupTypes();
184 :
185 : private:
186 :
187 : // event types
188 : enum {
189 : MSG_ENSURE_CONNECT,
190 : MSG_DNS_LOOKUP_COMPLETE,
191 : MSG_RETRY_INIT_SOCKET,
192 : MSG_TIMEOUT_CHANGED,
193 : MSG_INPUT_CLOSED,
194 : MSG_INPUT_PENDING,
195 : MSG_OUTPUT_CLOSED,
196 : MSG_OUTPUT_PENDING
197 : };
198 : nsresult PostEvent(uint32_t type, nsresult status = NS_OK, nsISupports *param = nullptr);
199 :
200 : enum {
201 : STATE_CLOSED,
202 : STATE_IDLE,
203 : STATE_RESOLVING,
204 : STATE_CONNECTING,
205 : STATE_TRANSFERRING
206 : };
207 :
208 : // Safer way to get and automatically release PRFileDesc objects.
209 : class MOZ_STACK_CLASS PRFileDescAutoLock
210 : {
211 : public:
212 9 : explicit PRFileDescAutoLock(nsSocketTransport *aSocketTransport,
213 : bool aAlsoDuringFastOpen,
214 : nsresult *aConditionWhileLocked = nullptr)
215 9 : : mSocketTransport(aSocketTransport)
216 9 : , mFd(nullptr)
217 : {
218 9 : MOZ_ASSERT(aSocketTransport);
219 18 : MutexAutoLock lock(mSocketTransport->mLock);
220 9 : if (aConditionWhileLocked) {
221 1 : *aConditionWhileLocked = mSocketTransport->mCondition;
222 1 : if (NS_FAILED(mSocketTransport->mCondition)) {
223 0 : return;
224 : }
225 : }
226 9 : if (!aAlsoDuringFastOpen) {
227 1 : mFd = mSocketTransport->GetFD_Locked();
228 : } else {
229 8 : mFd = mSocketTransport->GetFD_LockedAlsoDuringFastOpen();
230 : }
231 : }
232 18 : ~PRFileDescAutoLock() {
233 18 : MutexAutoLock lock(mSocketTransport->mLock);
234 9 : if (mFd) {
235 9 : mSocketTransport->ReleaseFD_Locked(mFd);
236 : }
237 9 : }
238 9 : bool IsInitialized() {
239 9 : return mFd;
240 : }
241 1 : operator PRFileDesc*() {
242 1 : return mFd;
243 : }
244 : nsresult SetKeepaliveEnabled(bool aEnable);
245 : nsresult SetKeepaliveVals(bool aEnabled, int aIdleTime,
246 : int aRetryInterval, int aProbeCount);
247 : private:
248 : operator PRFileDescAutoLock*() { return nullptr; }
249 :
250 : // Weak ptr to nsSocketTransport since this is a stack class only.
251 : nsSocketTransport *mSocketTransport;
252 : PRFileDesc *mFd;
253 : };
254 : friend class PRFileDescAutoLock;
255 :
256 : class LockedPRFileDesc
257 : {
258 : public:
259 3 : explicit LockedPRFileDesc(nsSocketTransport *aSocketTransport)
260 3 : : mSocketTransport(aSocketTransport)
261 3 : , mFd(nullptr)
262 : {
263 3 : MOZ_ASSERT(aSocketTransport);
264 3 : }
265 2 : ~LockedPRFileDesc() {}
266 37 : bool IsInitialized() {
267 37 : return mFd;
268 : }
269 5 : LockedPRFileDesc& operator=(PRFileDesc *aFd) {
270 5 : mSocketTransport->mLock.AssertCurrentThreadOwns();
271 5 : mFd = aFd;
272 5 : return *this;
273 : }
274 35 : operator PRFileDesc*() {
275 35 : if (mSocketTransport->mAttached) {
276 35 : mSocketTransport->mLock.AssertCurrentThreadOwns();
277 : }
278 35 : return mFd;
279 : }
280 30 : bool operator==(PRFileDesc *aFd) {
281 30 : mSocketTransport->mLock.AssertCurrentThreadOwns();
282 30 : return mFd == aFd;
283 : }
284 : private:
285 : operator LockedPRFileDesc*() { return nullptr; }
286 : // Weak ptr to nsSocketTransport since it owns this class.
287 : nsSocketTransport *mSocketTransport;
288 : PRFileDesc *mFd;
289 : };
290 : friend class LockedPRFileDesc;
291 :
292 : //-------------------------------------------------------------------------
293 : // these members are "set" at initialization time and are never modified
294 : // afterwards. this allows them to be safely accessed from any thread.
295 : //-------------------------------------------------------------------------
296 :
297 : // socket type info:
298 : char **mTypes;
299 : uint32_t mTypeCount;
300 : nsCString mHost;
301 : nsCString mProxyHost;
302 : nsCString mOriginHost;
303 : uint16_t mPort;
304 : nsCOMPtr<nsIProxyInfo> mProxyInfo;
305 : uint16_t mProxyPort;
306 : uint16_t mOriginPort;
307 : bool mProxyTransparent;
308 : bool mProxyTransparentResolvesHost;
309 : bool mHttpsProxy;
310 : uint32_t mConnectionFlags;
311 : bool mReuseAddrPort;
312 :
313 : // The origin attributes are used to create sockets. The first party domain
314 : // will eventually be used to isolate OCSP cache and is only non-empty when
315 : // "privacy.firstparty.isolate" is enabled. Setting this is the only way to
316 : // carry origin attributes down to NSPR layers which are final consumers.
317 : // It must be set before the socket transport is built.
318 : OriginAttributes mOriginAttributes;
319 :
320 3 : uint16_t SocketPort() { return (!mProxyHost.IsEmpty() && !mProxyTransparent) ? mProxyPort : mPort; }
321 6 : const nsCString &SocketHost() { return (!mProxyHost.IsEmpty() && !mProxyTransparent) ? mProxyHost : mHost; }
322 :
323 : //-------------------------------------------------------------------------
324 : // members accessible only on the socket transport thread:
325 : // (the exception being initialization/shutdown time)
326 : //-------------------------------------------------------------------------
327 :
328 : // socket state vars:
329 : uint32_t mState; // STATE_??? flags
330 : bool mAttached;
331 : bool mInputClosed;
332 : bool mOutputClosed;
333 :
334 : // The platform-specific network interface id that this socket
335 : // associated with.
336 : nsCString mNetworkInterfaceId;
337 :
338 : // this flag is used to determine if the results of a host lookup arrive
339 : // recursively or not. this flag is not protected by any lock.
340 : bool mResolving;
341 :
342 : nsCOMPtr<nsICancelable> mDNSRequest;
343 : nsCOMPtr<nsIDNSRecord> mDNSRecord;
344 :
345 : // mNetAddr/mSelfAddr is valid from GetPeerAddr()/GetSelfAddr() once we have
346 : // reached STATE_TRANSFERRING. It must not change after that.
347 : void SetSocketName(PRFileDesc *fd);
348 : NetAddr mNetAddr;
349 : NetAddr mSelfAddr; // getsockname()
350 : Atomic<bool, Relaxed> mNetAddrIsSet;
351 : Atomic<bool, Relaxed> mSelfAddrIsSet;
352 : Atomic<bool, Relaxed> mNetAddrPreResolved;
353 :
354 : nsAutoPtr<NetAddr> mBindAddr;
355 :
356 : // socket methods (these can only be called on the socket thread):
357 :
358 : void SendStatus(nsresult status);
359 : nsresult ResolveHost();
360 : nsresult BuildSocket(PRFileDesc *&, bool &, bool &);
361 : nsresult InitiateSocket();
362 : bool RecoverFromError();
363 :
364 6 : void OnMsgInputPending()
365 : {
366 6 : if (mState == STATE_TRANSFERRING)
367 6 : mPollFlags |= (PR_POLL_READ | PR_POLL_EXCEPT);
368 6 : }
369 9 : void OnMsgOutputPending()
370 : {
371 9 : if (mState == STATE_TRANSFERRING)
372 2 : mPollFlags |= (PR_POLL_WRITE | PR_POLL_EXCEPT);
373 9 : }
374 : void OnMsgInputClosed(nsresult reason);
375 : void OnMsgOutputClosed(nsresult reason);
376 :
377 : // called when the socket is connected
378 : void OnSocketConnected();
379 :
380 : //-------------------------------------------------------------------------
381 : // socket input/output objects. these may be accessed on any thread with
382 : // the exception of some specific methods (XXX).
383 :
384 : Mutex mLock; // protects members in this section.
385 : LockedPRFileDesc mFD;
386 : nsrefcnt mFDref; // mFD is closed when mFDref goes to zero.
387 : bool mFDconnected; // mFD is available to consumer when TRUE.
388 : bool mFDFastOpenInProgress; // Fast Open is in progress, so
389 : // socket available for some
390 : // operations.
391 :
392 : // A delete protector reference to gSocketTransportService held for lifetime
393 : // of 'this'. Sometimes used interchangably with gSocketTransportService due
394 : // to scoping.
395 : RefPtr<nsSocketTransportService> mSocketTransportService;
396 :
397 : nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
398 : nsCOMPtr<nsITransportEventSink> mEventSink;
399 : nsCOMPtr<nsISupports> mSecInfo;
400 :
401 : nsSocketInputStream mInput;
402 : nsSocketOutputStream mOutput;
403 :
404 : friend class nsSocketInputStream;
405 : friend class nsSocketOutputStream;
406 :
407 : // socket timeouts are not protected by any lock.
408 : uint16_t mTimeouts[2];
409 :
410 : // QoS setting for socket
411 : uint8_t mQoSBits;
412 :
413 : //
414 : // mFD access methods: called with mLock held.
415 : //
416 : PRFileDesc *GetFD_Locked();
417 : PRFileDesc *GetFD_LockedAlsoDuringFastOpen();
418 : void ReleaseFD_Locked(PRFileDesc *fd);
419 : bool FastOpenInProgress();
420 :
421 : //
422 : // stream state changes (called outside mLock):
423 : //
424 2 : void OnInputClosed(nsresult reason)
425 : {
426 : // no need to post an event if called on the socket thread
427 2 : if (OnSocketThread())
428 2 : OnMsgInputClosed(reason);
429 : else
430 0 : PostEvent(MSG_INPUT_CLOSED, reason);
431 2 : }
432 6 : void OnInputPending()
433 : {
434 : // no need to post an event if called on the socket thread
435 6 : if (OnSocketThread())
436 6 : OnMsgInputPending();
437 : else
438 0 : PostEvent(MSG_INPUT_PENDING);
439 6 : }
440 2 : void OnOutputClosed(nsresult reason)
441 : {
442 : // no need to post an event if called on the socket thread
443 2 : if (OnSocketThread())
444 2 : OnMsgOutputClosed(reason); // XXX need to not be inside lock!
445 : else
446 0 : PostEvent(MSG_OUTPUT_CLOSED, reason);
447 2 : }
448 9 : void OnOutputPending()
449 : {
450 : // no need to post an event if called on the socket thread
451 9 : if (OnSocketThread())
452 9 : OnMsgOutputPending();
453 : else
454 0 : PostEvent(MSG_OUTPUT_PENDING);
455 9 : }
456 :
457 : #ifdef ENABLE_SOCKET_TRACING
458 : void TraceInBuf(const char *buf, int32_t n);
459 : void TraceOutBuf(const char *buf, int32_t n);
460 : #endif
461 :
462 : // Reads prefs to get default keepalive config.
463 : nsresult EnsureKeepaliveValsAreInitialized();
464 :
465 : // Groups calls to fd.SetKeepaliveEnabled and fd.SetKeepaliveVals.
466 : nsresult SetKeepaliveEnabledInternal(bool aEnable);
467 :
468 : // True if keepalive has been enabled by the socket owner. Note: Keepalive
469 : // must also be enabled globally for it to be enabled in TCP.
470 : bool mKeepaliveEnabled;
471 :
472 : // Keepalive config (support varies by platform).
473 : int32_t mKeepaliveIdleTimeS;
474 : int32_t mKeepaliveRetryIntervalS;
475 : int32_t mKeepaliveProbeCount;
476 :
477 : // A Fast Open callback.
478 : TCPFastOpen *mFastOpenCallback;
479 : bool mFastOpenLayerHasBufferedData;
480 :
481 : bool mDoNotRetryToConnect;
482 : };
483 :
484 : } // namespace net
485 : } // namespace mozilla
486 :
487 : #endif // !nsSocketTransport_h__
|