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
14 #include "mozilla/Mutex.h"
15 #include "nsSocketTransportService2.h"
19 #include "nsIInterfaceRequestor.h"
20 #include "nsISocketTransport.h"
21 #include "nsIAsyncInputStream.h"
22 #include "nsIAsyncOutputStream.h"
23 #include "nsIDNSListener.h"
24 #include "nsIDNSRecord.h"
25 #include "nsIClassInfo.h"
26 #include "mozilla/net/DNS.h"
27 #include "nsASocketHandler.h"
28 #include "mozilla/Telemetry.h"
35 class nsIInterfaceRequestor
;
37 //-----------------------------------------------------------------------------
39 // after this short interval, we will return to PR_Poll
40 #define NS_SOCKET_CONNECT_TIMEOUT PR_MillisecondsToInterval(20)
42 //-----------------------------------------------------------------------------
47 nsresult
ErrorAccordingToNSPR(PRErrorCode errorCode
);
49 class nsSocketInputStream
;
50 class nsSocketOutputStream
;
52 //-----------------------------------------------------------------------------
54 class nsSocketTransport final
: public nsASocketHandler
,
55 public nsISocketTransport
,
56 public nsIDNSListener
,
58 public nsIInterfaceRequestor
{
60 NS_DECL_THREADSAFE_ISUPPORTS
62 NS_DECL_NSISOCKETTRANSPORT
63 NS_DECL_NSIDNSLISTENER
65 NS_DECL_NSIINTERFACEREQUESTOR
69 // this method instructs the socket transport to open a socket of the
70 // given type(s) to the given host or proxy.
71 nsresult
Init(const nsTArray
<nsCString
>& socketTypes
, const nsACString
& host
,
72 uint16_t port
, const nsACString
& hostRoute
, uint16_t portRoute
,
73 nsIProxyInfo
* proxyInfo
, nsIDNSRecord
* dnsRecord
);
75 // this method instructs the socket transport to use an already connected
76 // socket with the given address.
77 nsresult
InitWithConnectedSocket(PRFileDesc
* socketFD
, const NetAddr
* addr
);
79 // this method instructs the socket transport to use an already connected
80 // socket with the given address, and additionally supplies the security
81 // callbacks interface requestor.
82 nsresult
InitWithConnectedSocket(PRFileDesc
* aFD
, const NetAddr
* aAddr
,
83 nsIInterfaceRequestor
* aCallbacks
);
86 // This method instructs the socket transport to open a socket
87 // connected to the given Unix domain address. We can only create
88 // unlayered, simple, stream sockets.
89 nsresult
InitWithFilename(const char* filename
);
91 // This method instructs the socket transport to open a socket
92 // connected to the given Unix domain address that includes abstract
93 // socket address. If using abstract socket address, first character of
94 // name parameter has to be \0.
95 // We can only create unlayered, simple, stream sockets.
96 nsresult
InitWithName(const char* name
, size_t len
);
99 // nsASocketHandler methods:
100 void OnSocketReady(PRFileDesc
*, int16_t outFlags
) override
;
101 void OnSocketDetached(PRFileDesc
*) override
;
102 void IsLocal(bool* aIsLocal
) override
;
103 void OnKeepaliveEnabledPrefChange(bool aEnabled
) final
;
105 // called when a socket event is handled
106 void OnSocketEvent(uint32_t type
, nsresult status
, nsISupports
* param
,
107 std::function
<void()>&& task
);
109 uint64_t ByteCountReceived() override
;
110 uint64_t ByteCountSent() override
;
111 static void CloseSocket(PRFileDesc
* aFd
, bool aTelemetryEnabled
);
112 static void SendPRBlockingTelemetry(
113 PRIntervalTime aStart
, Telemetry::HistogramID aIDNormal
,
114 Telemetry::HistogramID aIDShutdown
,
115 Telemetry::HistogramID aIDConnectivityChange
,
116 Telemetry::HistogramID aIDLinkChange
, Telemetry::HistogramID aIDOffline
);
119 virtual ~nsSocketTransport();
125 MSG_DNS_LOOKUP_COMPLETE
,
126 MSG_RETRY_INIT_SOCKET
,
133 nsresult
PostEvent(uint32_t type
, nsresult status
= NS_OK
,
134 nsISupports
* param
= nullptr,
135 std::function
<void()>&& task
= nullptr);
145 // Safer way to get and automatically release PRFileDesc objects.
146 class MOZ_STACK_CLASS PRFileDescAutoLock
{
148 explicit PRFileDescAutoLock(nsSocketTransport
* aSocketTransport
,
149 nsresult
* aConditionWhileLocked
= nullptr)
150 : mSocketTransport(aSocketTransport
), mFd(nullptr) {
151 MOZ_ASSERT(aSocketTransport
);
152 MutexAutoLock
lock(mSocketTransport
->mLock
);
153 if (aConditionWhileLocked
) {
154 *aConditionWhileLocked
= mSocketTransport
->mCondition
;
155 if (NS_FAILED(mSocketTransport
->mCondition
)) {
159 mFd
= mSocketTransport
->GetFD_Locked();
161 ~PRFileDescAutoLock() {
162 MutexAutoLock
lock(mSocketTransport
->mLock
);
164 mSocketTransport
->ReleaseFD_Locked(mFd
);
167 bool IsInitialized() { return mFd
; }
168 operator PRFileDesc
*() { return mFd
; }
169 nsresult
SetKeepaliveEnabled(bool aEnable
);
170 nsresult
SetKeepaliveVals(bool aEnabled
, int aIdleTime
, int aRetryInterval
,
174 operator PRFileDescAutoLock
*() { return nullptr; }
176 // Weak ptr to nsSocketTransport since this is a stack class only.
177 nsSocketTransport
* mSocketTransport
;
180 friend class PRFileDescAutoLock
;
182 class LockedPRFileDesc
{
184 explicit LockedPRFileDesc(nsSocketTransport
* aSocketTransport
)
185 : mSocketTransport(aSocketTransport
), mFd(nullptr) {
186 MOZ_ASSERT(aSocketTransport
);
188 ~LockedPRFileDesc() = default;
189 bool IsInitialized() { return mFd
; }
190 LockedPRFileDesc
& operator=(PRFileDesc
* aFd
) {
191 mSocketTransport
->mLock
.AssertCurrentThreadOwns();
195 operator PRFileDesc
*() {
196 if (mSocketTransport
->mAttached
) {
197 mSocketTransport
->mLock
.AssertCurrentThreadOwns();
201 bool operator==(PRFileDesc
* aFd
) {
202 mSocketTransport
->mLock
.AssertCurrentThreadOwns();
207 operator LockedPRFileDesc
*() { return nullptr; }
208 // Weak ptr to nsSocketTransport since it owns this class.
209 nsSocketTransport
* mSocketTransport
;
212 friend class LockedPRFileDesc
;
214 //-------------------------------------------------------------------------
215 // these members are "set" at initialization time and are never modified
216 // afterwards. this allows them to be safely accessed from any thread.
217 //-------------------------------------------------------------------------
220 nsTArray
<nsCString
> mTypes
;
222 nsCString mProxyHost
;
223 nsCString mOriginHost
;
225 nsCOMPtr
<nsIProxyInfo
> mProxyInfo
;
226 uint16_t mProxyPort
{0};
227 uint16_t mOriginPort
{0};
228 bool mProxyTransparent
{false};
229 bool mProxyTransparentResolvesHost
{false};
230 bool mHttpsProxy
{false};
231 uint32_t mConnectionFlags
{0};
232 // When we fail to connect using a prefered IP family, we tell the consumer to
233 // reset the IP family preference on the connection entry.
234 bool mResetFamilyPreference
{false};
235 uint32_t mTlsFlags
{0};
236 bool mReuseAddrPort
{false};
238 // The origin attributes are used to create sockets. The first party domain
239 // will eventually be used to isolate OCSP cache and is only non-empty when
240 // "privacy.firstparty.isolate" is enabled. Setting this is the only way to
241 // carry origin attributes down to NSPR layers which are final consumers.
242 // It must be set before the socket transport is built.
243 OriginAttributes mOriginAttributes
;
245 uint16_t SocketPort() {
246 return (!mProxyHost
.IsEmpty() && !mProxyTransparent
) ? mProxyPort
: mPort
;
248 const nsCString
& SocketHost() {
249 return (!mProxyHost
.IsEmpty() && !mProxyTransparent
) ? mProxyHost
: mHost
;
252 Atomic
<bool> mInputClosed
{true};
253 Atomic
<bool> mOutputClosed
{true};
255 //-------------------------------------------------------------------------
256 // members accessible only on the socket transport thread:
257 // (the exception being initialization/shutdown time)
258 //-------------------------------------------------------------------------
260 // socket state vars:
261 uint32_t mState
{STATE_CLOSED
}; // STATE_??? flags
262 bool mAttached
{false};
264 // this flag is used to determine if the results of a host lookup arrive
265 // recursively or not. this flag is not protected by any lock.
266 bool mResolving
{false};
268 nsCOMPtr
<nsICancelable
> mDNSRequest
;
269 nsCOMPtr
<nsIDNSAddrRecord
> mDNSRecord
;
271 nsCString mEchConfig
;
272 bool mEchConfigUsed
= false;
273 bool mResolvedByTRR
{false};
274 nsIRequest::TRRMode mEffectiveTRRMode
{nsIRequest::TRR_DEFAULT_MODE
};
275 nsITRRSkipReason::value mTRRSkipReason
{nsITRRSkipReason::TRR_UNSET
};
277 nsCOMPtr
<nsISupports
> mInputCopyContext
;
278 nsCOMPtr
<nsISupports
> mOutputCopyContext
;
280 // mNetAddr/mSelfAddr is valid from GetPeerAddr()/GetSelfAddr() once we have
281 // reached STATE_TRANSFERRING. It must not change after that.
282 void SetSocketName(PRFileDesc
* fd
);
284 NetAddr mSelfAddr
; // getsockname()
285 Atomic
<bool, Relaxed
> mNetAddrIsSet
{false};
286 Atomic
<bool, Relaxed
> mSelfAddrIsSet
{false};
288 UniquePtr
<NetAddr
> mBindAddr
;
290 // socket methods (these can only be called on the socket thread):
292 void SendStatus(nsresult status
);
293 nsresult
ResolveHost();
294 nsresult
BuildSocket(PRFileDesc
*&, bool&, bool&);
295 nsresult
InitiateSocket();
296 bool RecoverFromError();
298 void OnMsgInputPending() {
299 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
300 if (mState
== STATE_TRANSFERRING
) {
301 mPollFlags
|= (PR_POLL_READ
| PR_POLL_EXCEPT
);
304 void OnMsgOutputPending() {
305 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
306 if (mState
== STATE_TRANSFERRING
) {
307 mPollFlags
|= (PR_POLL_WRITE
| PR_POLL_EXCEPT
);
310 void OnMsgInputClosed(nsresult reason
);
311 void OnMsgOutputClosed(nsresult reason
);
313 // called when the socket is connected
314 void OnSocketConnected();
316 //-------------------------------------------------------------------------
317 // socket input/output objects. these may be accessed on any thread with
318 // the exception of some specific methods (XXX).
320 // protects members in this section.
321 Mutex mLock
{"nsSocketTransport.mLock"};
322 LockedPRFileDesc mFD
MOZ_GUARDED_BY(mLock
);
323 // mFD is closed when mFDref goes to zero.
324 nsrefcnt mFDref
MOZ_GUARDED_BY(mLock
){0};
325 // mFD is available to consumer when TRUE.
326 bool mFDconnected
MOZ_GUARDED_BY(mLock
){false};
328 // A delete protector reference to gSocketTransportService held for lifetime
329 // of 'this'. Sometimes used interchangably with gSocketTransportService due
331 RefPtr
<nsSocketTransportService
> mSocketTransportService
;
333 nsCOMPtr
<nsIInterfaceRequestor
> mCallbacks
;
334 nsCOMPtr
<nsITransportEventSink
> mEventSink
;
335 nsCOMPtr
<nsITLSSocketControl
> mTLSSocketControl
;
337 UniquePtr
<nsSocketInputStream
> mInput
;
338 UniquePtr
<nsSocketOutputStream
> mOutput
;
340 friend class nsSocketInputStream
;
341 friend class nsSocketOutputStream
;
343 // socket timeouts are protected by mLock.
344 uint16_t mTimeouts
[2]{0};
346 // linger options to use when closing
347 bool mLingerPolarity
{false};
348 int16_t mLingerTimeout
{0};
350 // QoS setting for socket
351 uint8_t mQoSBits
{0x00};
354 // mFD access methods: called with mLock held.
356 PRFileDesc
* GetFD_Locked() MOZ_REQUIRES(mLock
);
357 void ReleaseFD_Locked(PRFileDesc
* fd
) MOZ_REQUIRES(mLock
);
360 // stream state changes (called outside mLock):
362 void OnInputClosed(nsresult reason
) {
363 // no need to post an event if called on the socket thread
364 if (OnSocketThread()) {
365 OnMsgInputClosed(reason
);
367 PostEvent(MSG_INPUT_CLOSED
, reason
);
370 void OnInputPending() {
371 // no need to post an event if called on the socket thread
372 if (OnSocketThread()) {
375 PostEvent(MSG_INPUT_PENDING
);
378 void OnOutputClosed(nsresult reason
) {
379 // no need to post an event if called on the socket thread
380 if (OnSocketThread()) {
381 OnMsgOutputClosed(reason
); // XXX need to not be inside lock!
383 PostEvent(MSG_OUTPUT_CLOSED
, reason
);
386 void OnOutputPending() {
387 // no need to post an event if called on the socket thread
388 if (OnSocketThread()) {
389 OnMsgOutputPending();
391 PostEvent(MSG_OUTPUT_PENDING
);
395 #ifdef ENABLE_SOCKET_TRACING
396 void TraceInBuf(const char* buf
, int32_t n
);
397 void TraceOutBuf(const char* buf
, int32_t n
);
400 // Reads prefs to get default keepalive config.
401 nsresult
EnsureKeepaliveValsAreInitialized();
403 // Groups calls to fd.SetKeepaliveEnabled and fd.SetKeepaliveVals.
404 nsresult
SetKeepaliveEnabledInternal(bool aEnable
);
406 // True if keepalive has been enabled by the socket owner. Note: Keepalive
407 // must also be enabled globally for it to be enabled in TCP.
408 bool mKeepaliveEnabled
{false};
410 // Keepalive config (support varies by platform).
411 int32_t mKeepaliveIdleTimeS
{-1};
412 int32_t mKeepaliveRetryIntervalS
{-1};
413 int32_t mKeepaliveProbeCount
{-1};
415 Atomic
<bool> mDoNotRetryToConnect
{false};
417 // Whether the port remapping has already been applied. We definitely want to
418 // prevent duplicate calls in case of chaining remapping.
419 bool mPortRemappingApplied
= false;
421 bool mExternalDNSResolution
= false;
422 bool mRetryDnsIfPossible
= false;
425 class nsSocketInputStream
: public nsIAsyncInputStream
{
427 NS_DECL_ISUPPORTS_INHERITED
428 NS_DECL_NSIINPUTSTREAM
429 NS_DECL_NSIASYNCINPUTSTREAM
431 explicit nsSocketInputStream(nsSocketTransport
*);
432 virtual ~nsSocketInputStream() = default;
434 // nsSocketTransport holds a ref to us
435 bool IsReferenced() { return mReaderRefCnt
> 0; }
436 nsresult
Condition() {
437 MutexAutoLock
lock(mTransport
->mLock
);
440 uint64_t ByteCount() {
441 MutexAutoLock
lock(mTransport
->mLock
);
444 uint64_t ByteCount(MutexAutoLock
&) MOZ_NO_THREAD_SAFETY_ANALYSIS
{
448 // called by the socket transport on the socket thread...
449 void OnSocketReady(nsresult condition
);
452 nsSocketTransport
* mTransport
;
453 ThreadSafeAutoRefCnt mReaderRefCnt
{0};
455 // access to these should be protected by mTransport->mLock but we
456 // can't order things to allow using MOZ_GUARDED_BY().
457 nsresult mCondition
MOZ_GUARDED_BY(mTransport
->mLock
){NS_OK
};
458 nsCOMPtr
<nsIInputStreamCallback
> mCallback
MOZ_GUARDED_BY(mTransport
->mLock
);
459 uint32_t mCallbackFlags
MOZ_GUARDED_BY(mTransport
->mLock
){0};
460 uint64_t mByteCount
MOZ_GUARDED_BY(mTransport
->mLock
){0};
463 //-----------------------------------------------------------------------------
465 class nsSocketOutputStream
: public nsIAsyncOutputStream
{
467 NS_DECL_ISUPPORTS_INHERITED
468 NS_DECL_NSIOUTPUTSTREAM
469 NS_DECL_NSIASYNCOUTPUTSTREAM
471 explicit nsSocketOutputStream(nsSocketTransport
*);
472 virtual ~nsSocketOutputStream() = default;
474 // nsSocketTransport holds a ref to us
475 bool IsReferenced() { return mWriterRefCnt
> 0; }
476 nsresult
Condition() {
477 MutexAutoLock
lock(mTransport
->mLock
);
480 uint64_t ByteCount() {
481 MutexAutoLock
lock(mTransport
->mLock
);
484 uint64_t ByteCount(MutexAutoLock
&) MOZ_NO_THREAD_SAFETY_ANALYSIS
{
488 // called by the socket transport on the socket thread...
489 void OnSocketReady(nsresult condition
);
492 static nsresult
WriteFromSegments(nsIInputStream
*, void*, const char*,
493 uint32_t offset
, uint32_t count
,
494 uint32_t* countRead
);
496 nsSocketTransport
* mTransport
;
497 ThreadSafeAutoRefCnt mWriterRefCnt
{0};
499 // access to these should be protected by mTransport->mLock but we
500 // can't order things to allow using MOZ_GUARDED_BY().
501 nsresult mCondition
MOZ_GUARDED_BY(mTransport
->mLock
){NS_OK
};
502 nsCOMPtr
<nsIOutputStreamCallback
> mCallback
MOZ_GUARDED_BY(mTransport
->mLock
);
503 uint32_t mCallbackFlags
MOZ_GUARDED_BY(mTransport
->mLock
){0};
504 uint64_t mByteCount
MOZ_GUARDED_BY(mTransport
->mLock
){0};
508 } // namespace mozilla
510 #endif // !nsSocketTransport_h__