Bug 1875768 - Call the appropriate postfork handler on MacOS r=glandium
[gecko.git] / netwerk / base / nsSocketTransport2.h
blob7dd94abac7e730c6fc367d038b48a6998ec8508a
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 nsSocketInputStream;
50 class nsSocketOutputStream;
52 //-----------------------------------------------------------------------------
54 class nsSocketTransport final : public nsASocketHandler,
55 public nsISocketTransport,
56 public nsIDNSListener,
57 public nsIClassInfo,
58 public nsIInterfaceRequestor {
59 public:
60 NS_DECL_THREADSAFE_ISUPPORTS
61 NS_DECL_NSITRANSPORT
62 NS_DECL_NSISOCKETTRANSPORT
63 NS_DECL_NSIDNSLISTENER
64 NS_DECL_NSICLASSINFO
65 NS_DECL_NSIINTERFACEREQUESTOR
67 nsSocketTransport();
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);
85 #ifdef XP_UNIX
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);
97 #endif
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);
118 protected:
119 virtual ~nsSocketTransport();
121 private:
122 // event types
123 enum {
124 MSG_ENSURE_CONNECT,
125 MSG_DNS_LOOKUP_COMPLETE,
126 MSG_RETRY_INIT_SOCKET,
127 MSG_TIMEOUT_CHANGED,
128 MSG_INPUT_CLOSED,
129 MSG_INPUT_PENDING,
130 MSG_OUTPUT_CLOSED,
131 MSG_OUTPUT_PENDING
133 nsresult PostEvent(uint32_t type, nsresult status = NS_OK,
134 nsISupports* param = nullptr,
135 std::function<void()>&& task = nullptr);
137 enum {
138 STATE_CLOSED,
139 STATE_IDLE,
140 STATE_RESOLVING,
141 STATE_CONNECTING,
142 STATE_TRANSFERRING
145 // Safer way to get and automatically release PRFileDesc objects.
146 class MOZ_STACK_CLASS PRFileDescAutoLock {
147 public:
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)) {
156 return;
159 mFd = mSocketTransport->GetFD_Locked();
161 ~PRFileDescAutoLock() {
162 MutexAutoLock lock(mSocketTransport->mLock);
163 if (mFd) {
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,
171 int aProbeCount);
173 private:
174 operator PRFileDescAutoLock*() { return nullptr; }
176 // Weak ptr to nsSocketTransport since this is a stack class only.
177 nsSocketTransport* mSocketTransport;
178 PRFileDesc* mFd;
180 friend class PRFileDescAutoLock;
182 class LockedPRFileDesc {
183 public:
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();
192 mFd = aFd;
193 return *this;
195 operator PRFileDesc*() {
196 if (mSocketTransport->mAttached) {
197 mSocketTransport->mLock.AssertCurrentThreadOwns();
199 return mFd;
201 bool operator==(PRFileDesc* aFd) {
202 mSocketTransport->mLock.AssertCurrentThreadOwns();
203 return mFd == aFd;
206 private:
207 operator LockedPRFileDesc*() { return nullptr; }
208 // Weak ptr to nsSocketTransport since it owns this class.
209 nsSocketTransport* mSocketTransport;
210 PRFileDesc* mFd;
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 //-------------------------------------------------------------------------
219 // socket type info:
220 nsTArray<nsCString> mTypes;
221 nsCString mHost;
222 nsCString mProxyHost;
223 nsCString mOriginHost;
224 uint16_t mPort{0};
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);
283 NetAddr mNetAddr;
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
330 // to scoping.
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);
366 } else {
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()) {
373 OnMsgInputPending();
374 } else {
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!
382 } else {
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();
390 } else {
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);
398 #endif
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 {
426 public:
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);
438 return mCondition;
440 uint64_t ByteCount() {
441 MutexAutoLock lock(mTransport->mLock);
442 return mByteCount;
444 uint64_t ByteCount(MutexAutoLock&) MOZ_NO_THREAD_SAFETY_ANALYSIS {
445 return mByteCount;
448 // called by the socket transport on the socket thread...
449 void OnSocketReady(nsresult condition);
451 private:
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 {
466 public:
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);
478 return mCondition;
480 uint64_t ByteCount() {
481 MutexAutoLock lock(mTransport->mLock);
482 return mByteCount;
484 uint64_t ByteCount(MutexAutoLock&) MOZ_NO_THREAD_SAFETY_ANALYSIS {
485 return mByteCount;
488 // called by the socket transport on the socket thread...
489 void OnSocketReady(nsresult condition);
491 private:
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};
507 } // namespace net
508 } // namespace mozilla
510 #endif // !nsSocketTransport_h__