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 nsSocketTransport
;
51 class nsSocketInputStream
: public nsIAsyncInputStream
{
53 NS_DECL_ISUPPORTS_INHERITED
54 NS_DECL_NSIINPUTSTREAM
55 NS_DECL_NSIASYNCINPUTSTREAM
57 explicit nsSocketInputStream(nsSocketTransport
*);
58 virtual ~nsSocketInputStream() = default;
60 bool IsReferenced() { return mReaderRefCnt
> 0; }
61 nsresult
Condition() { return mCondition
; }
62 uint64_t ByteCount() { return mByteCount
; }
64 // called by the socket transport on the socket thread...
65 void OnSocketReady(nsresult condition
);
68 nsSocketTransport
* mTransport
;
69 ThreadSafeAutoRefCnt mReaderRefCnt
{0};
71 // access to these is protected by mTransport->mLock
72 nsresult mCondition
{NS_OK
};
73 nsCOMPtr
<nsIInputStreamCallback
> mCallback
;
74 uint32_t mCallbackFlags
{0};
75 uint64_t mByteCount
{0};
78 //-----------------------------------------------------------------------------
80 class nsSocketOutputStream
: public nsIAsyncOutputStream
{
82 NS_DECL_ISUPPORTS_INHERITED
83 NS_DECL_NSIOUTPUTSTREAM
84 NS_DECL_NSIASYNCOUTPUTSTREAM
86 explicit nsSocketOutputStream(nsSocketTransport
*);
87 virtual ~nsSocketOutputStream() = default;
89 bool IsReferenced() { return mWriterRefCnt
> 0; }
90 nsresult
Condition() { return mCondition
; }
91 uint64_t ByteCount() { return mByteCount
; }
93 // called by the socket transport on the socket thread...
94 void OnSocketReady(nsresult condition
);
97 static nsresult
WriteFromSegments(nsIInputStream
*, void*, const char*,
98 uint32_t offset
, uint32_t count
,
101 nsSocketTransport
* mTransport
;
102 ThreadSafeAutoRefCnt mWriterRefCnt
{0};
104 // access to these is protected by mTransport->mLock
105 nsresult mCondition
{NS_OK
};
106 nsCOMPtr
<nsIOutputStreamCallback
> mCallback
;
107 uint32_t mCallbackFlags
{0};
108 uint64_t mByteCount
{0};
111 //-----------------------------------------------------------------------------
113 class nsSocketTransport final
: public nsASocketHandler
,
114 public nsISocketTransport
,
115 public nsIDNSListener
,
117 public nsIInterfaceRequestor
{
119 NS_DECL_THREADSAFE_ISUPPORTS
121 NS_DECL_NSISOCKETTRANSPORT
122 NS_DECL_NSIDNSLISTENER
124 NS_DECL_NSIINTERFACEREQUESTOR
128 // this method instructs the socket transport to open a socket of the
129 // given type(s) to the given host or proxy.
130 nsresult
Init(const nsTArray
<nsCString
>& socketTypes
, const nsACString
& host
,
131 uint16_t port
, const nsACString
& hostRoute
, uint16_t portRoute
,
132 nsIProxyInfo
* proxyInfo
, nsIDNSRecord
* dnsRecord
);
134 // this method instructs the socket transport to use an already connected
135 // socket with the given address.
136 nsresult
InitWithConnectedSocket(PRFileDesc
* socketFD
, const NetAddr
* addr
);
138 // this method instructs the socket transport to use an already connected
139 // socket with the given address, and additionally supplies the security
140 // callbacks interface requestor.
141 nsresult
InitWithConnectedSocket(PRFileDesc
* aFD
, const NetAddr
* aAddr
,
142 nsIInterfaceRequestor
* aCallbacks
);
145 // This method instructs the socket transport to open a socket
146 // connected to the given Unix domain address. We can only create
147 // unlayered, simple, stream sockets.
148 nsresult
InitWithFilename(const char* filename
);
150 // This method instructs the socket transport to open a socket
151 // connected to the given Unix domain address that includes abstract
152 // socket address. If using abstract socket address, first character of
153 // name parameter has to be \0.
154 // We can only create unlayered, simple, stream sockets.
155 nsresult
InitWithName(const char* name
, size_t len
);
158 // nsASocketHandler methods:
159 void OnSocketReady(PRFileDesc
*, int16_t outFlags
) override
;
160 void OnSocketDetached(PRFileDesc
*) override
;
161 void IsLocal(bool* aIsLocal
) override
;
162 void OnKeepaliveEnabledPrefChange(bool aEnabled
) final
;
164 // called when a socket event is handled
165 void OnSocketEvent(uint32_t type
, nsresult status
, nsISupports
* param
,
166 std::function
<void()>&& task
);
168 uint64_t ByteCountReceived() override
{ return mInput
.ByteCount(); }
169 uint64_t ByteCountSent() override
{ return mOutput
.ByteCount(); }
170 static void CloseSocket(PRFileDesc
* aFd
, bool aTelemetryEnabled
);
171 static void SendPRBlockingTelemetry(
172 PRIntervalTime aStart
, Telemetry::HistogramID aIDNormal
,
173 Telemetry::HistogramID aIDShutdown
,
174 Telemetry::HistogramID aIDConnectivityChange
,
175 Telemetry::HistogramID aIDLinkChange
, Telemetry::HistogramID aIDOffline
);
178 virtual ~nsSocketTransport();
184 MSG_DNS_LOOKUP_COMPLETE
,
185 MSG_RETRY_INIT_SOCKET
,
192 nsresult
PostEvent(uint32_t type
, nsresult status
= NS_OK
,
193 nsISupports
* param
= nullptr,
194 std::function
<void()>&& task
= nullptr);
204 // Safer way to get and automatically release PRFileDesc objects.
205 class MOZ_STACK_CLASS PRFileDescAutoLock
{
207 explicit PRFileDescAutoLock(nsSocketTransport
* aSocketTransport
,
208 nsresult
* aConditionWhileLocked
= nullptr)
209 : mSocketTransport(aSocketTransport
), mFd(nullptr) {
210 MOZ_ASSERT(aSocketTransport
);
211 MutexAutoLock
lock(mSocketTransport
->mLock
);
212 if (aConditionWhileLocked
) {
213 *aConditionWhileLocked
= mSocketTransport
->mCondition
;
214 if (NS_FAILED(mSocketTransport
->mCondition
)) {
218 mFd
= mSocketTransport
->GetFD_Locked();
220 ~PRFileDescAutoLock() {
221 MutexAutoLock
lock(mSocketTransport
->mLock
);
223 mSocketTransport
->ReleaseFD_Locked(mFd
);
226 bool IsInitialized() { return mFd
; }
227 operator PRFileDesc
*() { return mFd
; }
228 nsresult
SetKeepaliveEnabled(bool aEnable
);
229 nsresult
SetKeepaliveVals(bool aEnabled
, int aIdleTime
, int aRetryInterval
,
233 operator PRFileDescAutoLock
*() { return nullptr; }
235 // Weak ptr to nsSocketTransport since this is a stack class only.
236 nsSocketTransport
* mSocketTransport
;
239 friend class PRFileDescAutoLock
;
241 class LockedPRFileDesc
{
243 explicit LockedPRFileDesc(nsSocketTransport
* aSocketTransport
)
244 : mSocketTransport(aSocketTransport
), mFd(nullptr) {
245 MOZ_ASSERT(aSocketTransport
);
247 ~LockedPRFileDesc() = default;
248 bool IsInitialized() { return mFd
; }
249 LockedPRFileDesc
& operator=(PRFileDesc
* aFd
) {
250 mSocketTransport
->mLock
.AssertCurrentThreadOwns();
254 operator PRFileDesc
*() {
255 if (mSocketTransport
->mAttached
) {
256 mSocketTransport
->mLock
.AssertCurrentThreadOwns();
260 bool operator==(PRFileDesc
* aFd
) {
261 mSocketTransport
->mLock
.AssertCurrentThreadOwns();
266 operator LockedPRFileDesc
*() { return nullptr; }
267 // Weak ptr to nsSocketTransport since it owns this class.
268 nsSocketTransport
* mSocketTransport
;
271 friend class LockedPRFileDesc
;
273 //-------------------------------------------------------------------------
274 // these members are "set" at initialization time and are never modified
275 // afterwards. this allows them to be safely accessed from any thread.
276 //-------------------------------------------------------------------------
279 nsTArray
<nsCString
> mTypes
;
281 nsCString mProxyHost
;
282 nsCString mOriginHost
;
284 nsCOMPtr
<nsIProxyInfo
> mProxyInfo
;
285 uint16_t mProxyPort
{0};
286 uint16_t mOriginPort
{0};
287 bool mProxyTransparent
{false};
288 bool mProxyTransparentResolvesHost
{false};
289 bool mHttpsProxy
{false};
290 uint32_t mConnectionFlags
{0};
291 // When we fail to connect using a prefered IP family, we tell the consumer to
292 // reset the IP family preference on the connection entry.
293 bool mResetFamilyPreference
{false};
294 uint32_t mTlsFlags
{0};
295 bool mReuseAddrPort
{false};
297 // The origin attributes are used to create sockets. The first party domain
298 // will eventually be used to isolate OCSP cache and is only non-empty when
299 // "privacy.firstparty.isolate" is enabled. Setting this is the only way to
300 // carry origin attributes down to NSPR layers which are final consumers.
301 // It must be set before the socket transport is built.
302 OriginAttributes mOriginAttributes
;
304 uint16_t SocketPort() {
305 return (!mProxyHost
.IsEmpty() && !mProxyTransparent
) ? mProxyPort
: mPort
;
307 const nsCString
& SocketHost() {
308 return (!mProxyHost
.IsEmpty() && !mProxyTransparent
) ? mProxyHost
: mHost
;
311 Atomic
<bool> mInputClosed
{true};
312 Atomic
<bool> mOutputClosed
{true};
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_CLOSED
}; // STATE_??? flags
321 bool mAttached
{false};
323 // this flag is used to determine if the results of a host lookup arrive
324 // recursively or not. this flag is not protected by any lock.
325 bool mResolving
{false};
327 nsCOMPtr
<nsICancelable
> mDNSRequest
;
328 nsCOMPtr
<nsIDNSAddrRecord
> mDNSRecord
;
330 nsCString mEchConfig
;
331 bool mEchConfigUsed
= false;
332 bool mResolvedByTRR
{false};
333 nsIRequest::TRRMode mEffectiveTRRMode
{nsIRequest::TRR_DEFAULT_MODE
};
334 nsITRRSkipReason::value mTRRSkipReason
{nsITRRSkipReason::TRR_UNSET
};
336 nsCOMPtr
<nsISupports
> mInputCopyContext
;
337 nsCOMPtr
<nsISupports
> mOutputCopyContext
;
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
{false};
345 Atomic
<bool, Relaxed
> mSelfAddrIsSet
{false};
347 UniquePtr
<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 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
359 if (mState
== STATE_TRANSFERRING
) {
360 mPollFlags
|= (PR_POLL_READ
| PR_POLL_EXCEPT
);
363 void OnMsgOutputPending() {
364 MOZ_ASSERT(OnSocketThread(), "not on socket thread");
365 if (mState
== STATE_TRANSFERRING
) {
366 mPollFlags
|= (PR_POLL_WRITE
| PR_POLL_EXCEPT
);
369 void OnMsgInputClosed(nsresult reason
);
370 void OnMsgOutputClosed(nsresult reason
);
372 // called when the socket is connected
373 void OnSocketConnected();
375 //-------------------------------------------------------------------------
376 // socket input/output objects. these may be accessed on any thread with
377 // the exception of some specific methods (XXX).
379 // protects members in this section.
380 Mutex mLock MOZ_UNANNOTATED
{"nsSocketTransport.mLock"};
381 LockedPRFileDesc mFD
;
382 nsrefcnt mFDref
{0}; // mFD is closed when mFDref goes to zero.
383 bool mFDconnected
{false}; // mFD is available to consumer when TRUE.
385 // A delete protector reference to gSocketTransportService held for lifetime
386 // of 'this'. Sometimes used interchangably with gSocketTransportService due
388 RefPtr
<nsSocketTransportService
> mSocketTransportService
;
390 nsCOMPtr
<nsIInterfaceRequestor
> mCallbacks
;
391 nsCOMPtr
<nsITransportEventSink
> mEventSink
;
392 nsCOMPtr
<nsITLSSocketControl
> mTLSSocketControl
;
394 nsSocketInputStream mInput
;
395 nsSocketOutputStream mOutput
;
397 friend class nsSocketInputStream
;
398 friend class nsSocketOutputStream
;
400 // socket timeouts are protected by mLock.
401 uint16_t mTimeouts
[2]{0};
403 // linger options to use when closing
404 bool mLingerPolarity
{false};
405 int16_t mLingerTimeout
{0};
407 // QoS setting for socket
408 uint8_t mQoSBits
{0x00};
411 // mFD access methods: called with mLock held.
413 PRFileDesc
* GetFD_Locked();
414 void ReleaseFD_Locked(PRFileDesc
* fd
);
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
);
427 void OnInputPending() {
428 // no need to post an event if called on the socket thread
429 if (OnSocketThread()) {
432 PostEvent(MSG_INPUT_PENDING
);
435 void OnOutputClosed(nsresult reason
) {
436 // no need to post an event if called on the socket thread
437 if (OnSocketThread()) {
438 OnMsgOutputClosed(reason
); // XXX need to not be inside lock!
440 PostEvent(MSG_OUTPUT_CLOSED
, reason
);
443 void OnOutputPending() {
444 // no need to post an event if called on the socket thread
445 if (OnSocketThread()) {
446 OnMsgOutputPending();
448 PostEvent(MSG_OUTPUT_PENDING
);
452 #ifdef ENABLE_SOCKET_TRACING
453 void TraceInBuf(const char* buf
, int32_t n
);
454 void TraceOutBuf(const char* buf
, int32_t n
);
457 // Reads prefs to get default keepalive config.
458 nsresult
EnsureKeepaliveValsAreInitialized();
460 // Groups calls to fd.SetKeepaliveEnabled and fd.SetKeepaliveVals.
461 nsresult
SetKeepaliveEnabledInternal(bool aEnable
);
463 // True if keepalive has been enabled by the socket owner. Note: Keepalive
464 // must also be enabled globally for it to be enabled in TCP.
465 bool mKeepaliveEnabled
{false};
467 // Keepalive config (support varies by platform).
468 int32_t mKeepaliveIdleTimeS
{-1};
469 int32_t mKeepaliveRetryIntervalS
{-1};
470 int32_t mKeepaliveProbeCount
{-1};
472 Atomic
<bool> mDoNotRetryToConnect
{false};
474 // Whether the port remapping has already been applied. We definitely want to
475 // prevent duplicate calls in case of chaining remapping.
476 bool mPortRemappingApplied
= false;
478 bool mExternalDNSResolution
= false;
479 bool mRetryDnsIfPossible
= false;
483 } // namespace mozilla
485 #endif // !nsSocketTransport_h__