Bug 1861709 replace AudioCallbackDriver::ThreadRunning() assertions that mean to...
[gecko.git] / netwerk / base / nsSocketTransport2.h
blobcafa679404e03e950d711a2d01e600b5caf616ed
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__
8 #ifdef DEBUG_darinf
9 # define ENABLE_SOCKET_TRACING
10 #endif
12 #include <functional>
14 #include "mozilla/Mutex.h"
15 #include "nsSocketTransportService2.h"
16 #include "nsString.h"
17 #include "nsCOMPtr.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"
30 #include "prerror.h"
31 #include "ssl.h"
33 class nsICancelable;
34 class nsIDNSRecord;
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 //-----------------------------------------------------------------------------
44 namespace mozilla {
45 namespace net {
47 nsresult ErrorAccordingToNSPR(PRErrorCode errorCode);
49 class nsSocketTransport;
51 class nsSocketInputStream : public nsIAsyncInputStream {
52 public:
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);
67 private:
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 {
81 public:
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);
96 private:
97 static nsresult WriteFromSegments(nsIInputStream*, void*, const char*,
98 uint32_t offset, uint32_t count,
99 uint32_t* countRead);
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,
116 public nsIClassInfo,
117 public nsIInterfaceRequestor {
118 public:
119 NS_DECL_THREADSAFE_ISUPPORTS
120 NS_DECL_NSITRANSPORT
121 NS_DECL_NSISOCKETTRANSPORT
122 NS_DECL_NSIDNSLISTENER
123 NS_DECL_NSICLASSINFO
124 NS_DECL_NSIINTERFACEREQUESTOR
126 nsSocketTransport();
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);
144 #ifdef XP_UNIX
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);
156 #endif
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);
177 protected:
178 virtual ~nsSocketTransport();
180 private:
181 // event types
182 enum {
183 MSG_ENSURE_CONNECT,
184 MSG_DNS_LOOKUP_COMPLETE,
185 MSG_RETRY_INIT_SOCKET,
186 MSG_TIMEOUT_CHANGED,
187 MSG_INPUT_CLOSED,
188 MSG_INPUT_PENDING,
189 MSG_OUTPUT_CLOSED,
190 MSG_OUTPUT_PENDING
192 nsresult PostEvent(uint32_t type, nsresult status = NS_OK,
193 nsISupports* param = nullptr,
194 std::function<void()>&& task = nullptr);
196 enum {
197 STATE_CLOSED,
198 STATE_IDLE,
199 STATE_RESOLVING,
200 STATE_CONNECTING,
201 STATE_TRANSFERRING
204 // Safer way to get and automatically release PRFileDesc objects.
205 class MOZ_STACK_CLASS PRFileDescAutoLock {
206 public:
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)) {
215 return;
218 mFd = mSocketTransport->GetFD_Locked();
220 ~PRFileDescAutoLock() {
221 MutexAutoLock lock(mSocketTransport->mLock);
222 if (mFd) {
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,
230 int aProbeCount);
232 private:
233 operator PRFileDescAutoLock*() { return nullptr; }
235 // Weak ptr to nsSocketTransport since this is a stack class only.
236 nsSocketTransport* mSocketTransport;
237 PRFileDesc* mFd;
239 friend class PRFileDescAutoLock;
241 class LockedPRFileDesc {
242 public:
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();
251 mFd = aFd;
252 return *this;
254 operator PRFileDesc*() {
255 if (mSocketTransport->mAttached) {
256 mSocketTransport->mLock.AssertCurrentThreadOwns();
258 return mFd;
260 bool operator==(PRFileDesc* aFd) {
261 mSocketTransport->mLock.AssertCurrentThreadOwns();
262 return mFd == aFd;
265 private:
266 operator LockedPRFileDesc*() { return nullptr; }
267 // Weak ptr to nsSocketTransport since it owns this class.
268 nsSocketTransport* mSocketTransport;
269 PRFileDesc* mFd;
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 //-------------------------------------------------------------------------
278 // socket type info:
279 nsTArray<nsCString> mTypes;
280 nsCString mHost;
281 nsCString mProxyHost;
282 nsCString mOriginHost;
283 uint16_t mPort{0};
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);
342 NetAddr mNetAddr;
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
387 // to scoping.
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);
423 } else {
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()) {
430 OnMsgInputPending();
431 } else {
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!
439 } else {
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();
447 } else {
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);
455 #endif
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;
482 } // namespace net
483 } // namespace mozilla
485 #endif // !nsSocketTransport_h__