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/. */
5 #ifndef nsSocketTransport2_h__
6 #define nsSocketTransport2_h__
9 # define ENABLE_SOCKET_TRACING
12 #include "mozilla/Mutex.h"
13 #include "nsSocketTransportService2.h"
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"
29 #include "nsAutoPtr.h"
33 class nsIInterfaceRequestor
;
35 //-----------------------------------------------------------------------------
37 // after this short interval, we will return to PR_Poll
38 #define NS_SOCKET_CONNECT_TIMEOUT PR_MillisecondsToInterval(20)
40 //-----------------------------------------------------------------------------
45 nsresult
ErrorAccordingToNSPR(PRErrorCode errorCode
);
47 class nsSocketTransport
;
49 class nsSocketInputStream
: public nsIAsyncInputStream
{
51 NS_DECL_ISUPPORTS_INHERITED
52 NS_DECL_NSIINPUTSTREAM
53 NS_DECL_NSIASYNCINPUTSTREAM
55 explicit nsSocketInputStream(nsSocketTransport
*);
56 virtual ~nsSocketInputStream() = default;
58 bool IsReferenced() { return mReaderRefCnt
> 0; }
59 nsresult
Condition() { return mCondition
; }
60 uint64_t ByteCount() { return mByteCount
; }
62 // called by the socket transport on the socket thread...
63 void OnSocketReady(nsresult condition
);
66 nsSocketTransport
*mTransport
;
67 ThreadSafeAutoRefCnt mReaderRefCnt
;
69 // access to these is protected by mTransport->mLock
71 nsCOMPtr
<nsIInputStreamCallback
> mCallback
;
72 uint32_t mCallbackFlags
;
76 //-----------------------------------------------------------------------------
78 class nsSocketOutputStream
: public nsIAsyncOutputStream
{
80 NS_DECL_ISUPPORTS_INHERITED
81 NS_DECL_NSIOUTPUTSTREAM
82 NS_DECL_NSIASYNCOUTPUTSTREAM
84 explicit nsSocketOutputStream(nsSocketTransport
*);
85 virtual ~nsSocketOutputStream() = default;
87 bool IsReferenced() { return mWriterRefCnt
> 0; }
88 nsresult
Condition() { return mCondition
; }
89 uint64_t ByteCount() { return mByteCount
; }
91 // called by the socket transport on the socket thread...
92 void OnSocketReady(nsresult condition
);
95 static nsresult
WriteFromSegments(nsIInputStream
*, void *, const char *,
96 uint32_t offset
, uint32_t count
,
99 nsSocketTransport
*mTransport
;
100 ThreadSafeAutoRefCnt mWriterRefCnt
;
102 // access to these is protected by mTransport->mLock
104 nsCOMPtr
<nsIOutputStreamCallback
> mCallback
;
105 uint32_t mCallbackFlags
;
109 //-----------------------------------------------------------------------------
111 class nsSocketTransport final
: public nsASocketHandler
,
112 public nsISocketTransport
,
113 public nsIDNSListener
,
115 public nsIInterfaceRequestor
{
117 NS_DECL_THREADSAFE_ISUPPORTS
119 NS_DECL_NSISOCKETTRANSPORT
120 NS_DECL_NSIDNSLISTENER
122 NS_DECL_NSIINTERFACEREQUESTOR
126 // this method instructs the socket transport to open a socket of the
127 // given type(s) to the given host or proxy.
128 nsresult
Init(const char **socketTypes
, uint32_t typeCount
,
129 const nsACString
&host
, uint16_t port
,
130 const nsACString
&hostRoute
, uint16_t portRoute
,
131 nsIProxyInfo
*proxyInfo
);
133 // this method instructs the socket transport to use an already connected
134 // socket with the given address.
135 nsresult
InitWithConnectedSocket(PRFileDesc
*socketFD
, const NetAddr
*addr
);
137 // this method instructs the socket transport to use an already connected
138 // socket with the given address, and additionally supplies security info.
139 nsresult
InitWithConnectedSocket(PRFileDesc
*aSocketFD
, const NetAddr
*aAddr
,
140 nsISupports
*aSecInfo
);
143 // This method instructs the socket transport to open a socket
144 // connected to the given Unix domain address. We can only create
145 // unlayered, simple, stream sockets.
146 nsresult
InitWithFilename(const char *filename
);
148 // This method instructs the socket transport to open a socket
149 // connected to the given Unix domain address that includes abstract
150 // socket address. If using abstract socket address, first character of
151 // name parameter has to be \0.
152 // We can only create unlayered, simple, stream sockets.
153 nsresult
InitWithName(const char *name
, size_t len
);
156 // nsASocketHandler methods:
157 void OnSocketReady(PRFileDesc
*, int16_t outFlags
) override
;
158 void OnSocketDetached(PRFileDesc
*) override
;
159 void IsLocal(bool *aIsLocal
) override
;
160 void OnKeepaliveEnabledPrefChange(bool aEnabled
) final
;
162 // called when a socket event is handled
163 void OnSocketEvent(uint32_t type
, nsresult status
, nsISupports
*param
);
165 uint64_t ByteCountReceived() override
{ return mInput
.ByteCount(); }
166 uint64_t ByteCountSent() override
{ return mOutput
.ByteCount(); }
167 static void CloseSocket(PRFileDesc
*aFd
, bool aTelemetryEnabled
);
168 static void SendPRBlockingTelemetry(
169 PRIntervalTime aStart
, Telemetry::HistogramID aIDNormal
,
170 Telemetry::HistogramID aIDShutdown
,
171 Telemetry::HistogramID aIDConnectivityChange
,
172 Telemetry::HistogramID aIDLinkChange
, Telemetry::HistogramID aIDOffline
);
175 virtual ~nsSocketTransport();
182 MSG_DNS_LOOKUP_COMPLETE
,
183 MSG_RETRY_INIT_SOCKET
,
190 nsresult
PostEvent(uint32_t type
, nsresult status
= NS_OK
,
191 nsISupports
*param
= nullptr);
201 // Safer way to get and automatically release PRFileDesc objects.
202 class MOZ_STACK_CLASS PRFileDescAutoLock
{
204 explicit PRFileDescAutoLock(nsSocketTransport
*aSocketTransport
,
205 bool aAlsoDuringFastOpen
,
206 nsresult
*aConditionWhileLocked
= nullptr)
207 : mSocketTransport(aSocketTransport
), mFd(nullptr) {
208 MOZ_ASSERT(aSocketTransport
);
209 MutexAutoLock
lock(mSocketTransport
->mLock
);
210 if (aConditionWhileLocked
) {
211 *aConditionWhileLocked
= mSocketTransport
->mCondition
;
212 if (NS_FAILED(mSocketTransport
->mCondition
)) {
216 if (!aAlsoDuringFastOpen
) {
217 mFd
= mSocketTransport
->GetFD_Locked();
219 mFd
= mSocketTransport
->GetFD_LockedAlsoDuringFastOpen();
222 ~PRFileDescAutoLock() {
223 MutexAutoLock
lock(mSocketTransport
->mLock
);
225 mSocketTransport
->ReleaseFD_Locked(mFd
);
228 bool IsInitialized() { return mFd
; }
229 operator PRFileDesc
*() { return mFd
; }
230 nsresult
SetKeepaliveEnabled(bool aEnable
);
231 nsresult
SetKeepaliveVals(bool aEnabled
, int aIdleTime
, int aRetryInterval
,
235 operator PRFileDescAutoLock
*() { return nullptr; }
237 // Weak ptr to nsSocketTransport since this is a stack class only.
238 nsSocketTransport
*mSocketTransport
;
241 friend class PRFileDescAutoLock
;
243 class LockedPRFileDesc
{
245 explicit LockedPRFileDesc(nsSocketTransport
*aSocketTransport
)
246 : mSocketTransport(aSocketTransport
), mFd(nullptr) {
247 MOZ_ASSERT(aSocketTransport
);
249 ~LockedPRFileDesc() = default;
250 bool IsInitialized() { return mFd
; }
251 LockedPRFileDesc
&operator=(PRFileDesc
*aFd
) {
252 mSocketTransport
->mLock
.AssertCurrentThreadOwns();
256 operator PRFileDesc
*() {
257 if (mSocketTransport
->mAttached
) {
258 mSocketTransport
->mLock
.AssertCurrentThreadOwns();
262 bool operator==(PRFileDesc
*aFd
) {
263 mSocketTransport
->mLock
.AssertCurrentThreadOwns();
268 operator LockedPRFileDesc
*() { return nullptr; }
269 // Weak ptr to nsSocketTransport since it owns this class.
270 nsSocketTransport
*mSocketTransport
;
273 friend class LockedPRFileDesc
;
275 //-------------------------------------------------------------------------
276 // these members are "set" at initialization time and are never modified
277 // afterwards. this allows them to be safely accessed from any thread.
278 //-------------------------------------------------------------------------
284 nsCString mProxyHost
;
285 nsCString mOriginHost
;
287 nsCOMPtr
<nsIProxyInfo
> mProxyInfo
;
289 uint16_t mOriginPort
;
290 bool mProxyTransparent
;
291 bool mProxyTransparentResolvesHost
;
293 uint32_t mConnectionFlags
;
294 // When we fail to connect using a prefered IP family, we tell the consumer to
295 // reset the IP family preference on the connection entry.
296 bool mResetFamilyPreference
;
300 // The origin attributes are used to create sockets. The first party domain
301 // will eventually be used to isolate OCSP cache and is only non-empty when
302 // "privacy.firstparty.isolate" is enabled. Setting this is the only way to
303 // carry origin attributes down to NSPR layers which are final consumers.
304 // It must be set before the socket transport is built.
305 OriginAttributes mOriginAttributes
;
307 uint16_t SocketPort() {
308 return (!mProxyHost
.IsEmpty() && !mProxyTransparent
) ? mProxyPort
: mPort
;
310 const nsCString
&SocketHost() {
311 return (!mProxyHost
.IsEmpty() && !mProxyTransparent
) ? mProxyHost
: mHost
;
314 //-------------------------------------------------------------------------
315 // members accessible only on the socket transport thread:
316 // (the exception being initialization/shutdown time)
317 //-------------------------------------------------------------------------
319 // socket state vars:
320 uint32_t mState
; // STATE_??? flags
325 // this flag is used to determine if the results of a host lookup arrive
326 // recursively or not. this flag is not protected by any lock.
329 nsCOMPtr
<nsICancelable
> mDNSRequest
;
330 nsCOMPtr
<nsIDNSRecord
> mDNSRecord
;
332 nsresult mDNSLookupStatus
;
333 PRIntervalTime mDNSARequestFinished
;
334 nsCOMPtr
<nsICancelable
> mDNSTxtRequest
;
335 nsCString mDNSRecordTxt
;
339 // mNetAddr/mSelfAddr is valid from GetPeerAddr()/GetSelfAddr() once we have
340 // reached STATE_TRANSFERRING. It must not change after that.
341 void SetSocketName(PRFileDesc
*fd
);
343 NetAddr mSelfAddr
; // getsockname()
344 Atomic
<bool, Relaxed
> mNetAddrIsSet
;
345 Atomic
<bool, Relaxed
> mSelfAddrIsSet
;
347 nsAutoPtr
<NetAddr
> mBindAddr
;
349 // socket methods (these can only be called on the socket thread):
351 void SendStatus(nsresult status
);
352 nsresult
ResolveHost();
353 nsresult
BuildSocket(PRFileDesc
*&, bool &, bool &);
354 nsresult
InitiateSocket();
355 bool RecoverFromError();
357 void OnMsgInputPending() {
358 if (mState
== STATE_TRANSFERRING
)
359 mPollFlags
|= (PR_POLL_READ
| PR_POLL_EXCEPT
);
361 void OnMsgOutputPending() {
362 if (mState
== STATE_TRANSFERRING
)
363 mPollFlags
|= (PR_POLL_WRITE
| PR_POLL_EXCEPT
);
365 void OnMsgInputClosed(nsresult reason
);
366 void OnMsgOutputClosed(nsresult reason
);
368 // called when the socket is connected
369 void OnSocketConnected();
371 //-------------------------------------------------------------------------
372 // socket input/output objects. these may be accessed on any thread with
373 // the exception of some specific methods (XXX).
375 Mutex mLock
; // protects members in this section.
376 LockedPRFileDesc mFD
;
377 nsrefcnt mFDref
; // mFD is closed when mFDref goes to zero.
378 bool mFDconnected
; // mFD is available to consumer when TRUE.
379 bool mFDFastOpenInProgress
; // Fast Open is in progress, so
380 // socket available for some
383 // A delete protector reference to gSocketTransportService held for lifetime
384 // of 'this'. Sometimes used interchangably with gSocketTransportService due
386 RefPtr
<nsSocketTransportService
> mSocketTransportService
;
388 nsCOMPtr
<nsIInterfaceRequestor
> mCallbacks
;
389 nsCOMPtr
<nsITransportEventSink
> mEventSink
;
390 nsCOMPtr
<nsISupports
> mSecInfo
;
392 nsSocketInputStream mInput
;
393 nsSocketOutputStream mOutput
;
395 friend class nsSocketInputStream
;
396 friend class nsSocketOutputStream
;
398 // socket timeouts are not protected by any lock.
399 uint16_t mTimeouts
[2];
401 // linger options to use when closing
402 bool mLingerPolarity
;
403 int16_t mLingerTimeout
;
405 // QoS setting for socket
409 // mFD access methods: called with mLock held.
411 PRFileDesc
*GetFD_Locked();
412 PRFileDesc
*GetFD_LockedAlsoDuringFastOpen();
413 void ReleaseFD_Locked(PRFileDesc
*fd
);
414 bool FastOpenInProgress();
417 // stream state changes (called outside mLock):
419 void OnInputClosed(nsresult reason
) {
420 // no need to post an event if called on the socket thread
421 if (OnSocketThread())
422 OnMsgInputClosed(reason
);
424 PostEvent(MSG_INPUT_CLOSED
, reason
);
426 void OnInputPending() {
427 // no need to post an event if called on the socket thread
428 if (OnSocketThread())
431 PostEvent(MSG_INPUT_PENDING
);
433 void OnOutputClosed(nsresult reason
) {
434 // no need to post an event if called on the socket thread
435 if (OnSocketThread())
436 OnMsgOutputClosed(reason
); // XXX need to not be inside lock!
438 PostEvent(MSG_OUTPUT_CLOSED
, reason
);
440 void OnOutputPending() {
441 // no need to post an event if called on the socket thread
442 if (OnSocketThread())
443 OnMsgOutputPending();
445 PostEvent(MSG_OUTPUT_PENDING
);
448 #ifdef ENABLE_SOCKET_TRACING
449 void TraceInBuf(const char *buf
, int32_t n
);
450 void TraceOutBuf(const char *buf
, int32_t n
);
453 // Reads prefs to get default keepalive config.
454 nsresult
EnsureKeepaliveValsAreInitialized();
456 // Groups calls to fd.SetKeepaliveEnabled and fd.SetKeepaliveVals.
457 nsresult
SetKeepaliveEnabledInternal(bool aEnable
);
459 // True if keepalive has been enabled by the socket owner. Note: Keepalive
460 // must also be enabled globally for it to be enabled in TCP.
461 bool mKeepaliveEnabled
;
463 // Keepalive config (support varies by platform).
464 int32_t mKeepaliveIdleTimeS
;
465 int32_t mKeepaliveRetryIntervalS
;
466 int32_t mKeepaliveProbeCount
;
468 // A Fast Open callback.
469 TCPFastOpen
*mFastOpenCallback
;
470 bool mFastOpenLayerHasBufferedData
;
471 uint8_t mFastOpenStatus
;
472 nsresult mFirstRetryError
;
474 bool mDoNotRetryToConnect
;
478 } // namespace mozilla
480 #endif // !nsSocketTransport_h__