nsSocketTransport2.h (17110B)
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/. */ 4 5 #ifndef nsSocketTransport2_h__ 6 #define nsSocketTransport2_h__ 7 8 #ifdef DEBUG_darinf 9 # define ENABLE_SOCKET_TRACING 10 #endif 11 12 #include <functional> 13 14 #include "mozilla/Mutex.h" 15 #include "nsSocketTransportService2.h" 16 #include "nsString.h" 17 #include "nsCOMPtr.h" 18 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/glean/NetwerkMetrics.h" 27 #include "mozilla/net/DNS.h" 28 #include "nsASocketHandler.h" 29 30 #include "prerror.h" 31 #include "ssl.h" 32 33 class nsICancelable; 34 class nsIDNSRecord; 35 class nsIInterfaceRequestor; 36 37 //----------------------------------------------------------------------------- 38 39 // after this short interval, we will return to PR_Poll 40 #define NS_SOCKET_CONNECT_TIMEOUT PR_MillisecondsToInterval(20) 41 42 //----------------------------------------------------------------------------- 43 44 namespace mozilla { 45 namespace net { 46 47 nsresult ErrorAccordingToNSPR(PRErrorCode errorCode); 48 49 class nsSocketInputStream; 50 class nsSocketOutputStream; 51 52 //----------------------------------------------------------------------------- 53 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 66 67 nsSocketTransport(); 68 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); 74 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); 78 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); 84 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); 90 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 98 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; 104 105 // called when a socket event is handled 106 void OnSocketEvent(uint32_t type, nsresult status, nsISupports* param, 107 std::function<void()>&& task); 108 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, 114 const glean::impl::TimingDistributionMetric& aMetricNormal, 115 const glean::impl::TimingDistributionMetric& aMetricShutdown, 116 const glean::impl::TimingDistributionMetric& aMetricConnectivityChange, 117 const glean::impl::TimingDistributionMetric& aMetricLinkChange, 118 const glean::impl::TimingDistributionMetric& aMetricOffline); 119 120 protected: 121 virtual ~nsSocketTransport(); 122 123 private: 124 // event types 125 enum { 126 MSG_ENSURE_CONNECT, 127 MSG_DNS_LOOKUP_COMPLETE, 128 MSG_RETRY_INIT_SOCKET, 129 MSG_TIMEOUT_CHANGED, 130 MSG_INPUT_CLOSED, 131 MSG_INPUT_PENDING, 132 MSG_OUTPUT_CLOSED, 133 MSG_OUTPUT_PENDING 134 }; 135 nsresult PostEvent(uint32_t type, nsresult status = NS_OK, 136 nsISupports* param = nullptr, 137 std::function<void()>&& task = nullptr); 138 139 enum { 140 STATE_CLOSED, 141 STATE_IDLE, 142 STATE_RESOLVING, 143 STATE_CONNECTING, 144 STATE_TRANSFERRING 145 }; 146 147 // Safer way to get and automatically release PRFileDesc objects. 148 class MOZ_STACK_CLASS PRFileDescAutoLock { 149 public: 150 explicit PRFileDescAutoLock(nsSocketTransport* aSocketTransport, 151 nsresult* aConditionWhileLocked = nullptr) 152 : mSocketTransport(aSocketTransport), mFd(nullptr) { 153 MOZ_ASSERT(aSocketTransport); 154 MutexAutoLock lock(mSocketTransport->mLock); 155 if (aConditionWhileLocked) { 156 *aConditionWhileLocked = mSocketTransport->mCondition; 157 if (NS_FAILED(mSocketTransport->mCondition)) { 158 return; 159 } 160 } 161 mFd = mSocketTransport->GetFD_Locked(); 162 } 163 ~PRFileDescAutoLock() { 164 MutexAutoLock lock(mSocketTransport->mLock); 165 if (mFd) { 166 mSocketTransport->ReleaseFD_Locked(mFd); 167 } 168 } 169 bool IsInitialized() { return mFd; } 170 operator PRFileDesc*() { return mFd; } 171 nsresult SetKeepaliveEnabled(bool aEnable); 172 nsresult SetKeepaliveVals(bool aEnabled, int aIdleTime, int aRetryInterval, 173 int aProbeCount); 174 175 private: 176 operator PRFileDescAutoLock*() { return nullptr; } 177 178 // Weak ptr to nsSocketTransport since this is a stack class only. 179 nsSocketTransport* mSocketTransport; 180 PRFileDesc* mFd; 181 }; 182 friend class PRFileDescAutoLock; 183 184 class LockedPRFileDesc { 185 public: 186 explicit LockedPRFileDesc(nsSocketTransport* aSocketTransport) 187 : mSocketTransport(aSocketTransport), mFd(nullptr) { 188 MOZ_ASSERT(aSocketTransport); 189 } 190 ~LockedPRFileDesc() = default; 191 bool IsInitialized() { return mFd; } 192 LockedPRFileDesc& operator=(PRFileDesc* aFd) { 193 mSocketTransport->mLock.AssertCurrentThreadOwns(); 194 mFd = aFd; 195 return *this; 196 } 197 operator PRFileDesc*() { 198 if (mSocketTransport->mAttached) { 199 mSocketTransport->mLock.AssertCurrentThreadOwns(); 200 } 201 return mFd; 202 } 203 bool operator==(PRFileDesc* aFd) { 204 mSocketTransport->mLock.AssertCurrentThreadOwns(); 205 return mFd == aFd; 206 } 207 208 private: 209 operator LockedPRFileDesc*() { return nullptr; } 210 // Weak ptr to nsSocketTransport since it owns this class. 211 nsSocketTransport* mSocketTransport; 212 PRFileDesc* mFd; 213 }; 214 friend class LockedPRFileDesc; 215 216 //------------------------------------------------------------------------- 217 // these members are "set" at initialization time and are never modified 218 // afterwards. this allows them to be safely accessed from any thread. 219 //------------------------------------------------------------------------- 220 221 // socket type info: 222 nsTArray<nsCString> mTypes; 223 nsCString mHost; 224 nsCString mProxyHost; 225 nsCString mOriginHost; 226 uint16_t mPort{0}; 227 nsCOMPtr<nsIProxyInfo> mProxyInfo; 228 uint16_t mProxyPort{0}; 229 uint16_t mOriginPort{0}; 230 bool mProxyTransparent{false}; 231 bool mProxyTransparentResolvesHost{false}; 232 bool mHttpsProxy{false}; 233 uint32_t mConnectionFlags{0}; 234 // When we fail to connect using a prefered IP family, we tell the consumer to 235 // reset the IP family preference on the connection entry. 236 bool mResetFamilyPreference{false}; 237 uint32_t mTlsFlags{0}; 238 bool mReuseAddrPort{false}; 239 240 // The origin attributes are used to create sockets. The first party domain 241 // will eventually be used to isolate OCSP cache and is only non-empty when 242 // "privacy.firstparty.isolate" is enabled. Setting this is the only way to 243 // carry origin attributes down to NSPR layers which are final consumers. 244 // It must be set before the socket transport is built. 245 OriginAttributes mOriginAttributes; 246 247 uint16_t SocketPort() { 248 return (!mProxyHost.IsEmpty() && !mProxyTransparent) ? mProxyPort : mPort; 249 } 250 const nsCString& SocketHost() { 251 return (!mProxyHost.IsEmpty() && !mProxyTransparent) ? mProxyHost : mHost; 252 } 253 254 Atomic<bool> mInputClosed{true}; 255 Atomic<bool> mOutputClosed{true}; 256 257 //------------------------------------------------------------------------- 258 // members accessible only on the socket transport thread: 259 // (the exception being initialization/shutdown time) 260 //------------------------------------------------------------------------- 261 262 // socket state vars: 263 uint32_t mState{STATE_CLOSED}; // STATE_??? flags 264 bool mAttached{false}; 265 266 // this flag is used to determine if the results of a host lookup arrive 267 // recursively or not. this flag is not protected by any lock. 268 bool mResolving{false}; 269 270 nsCOMPtr<nsICancelable> mDNSRequest; 271 nsCOMPtr<nsIDNSAddrRecord> mDNSRecord; 272 273 nsCString mEchConfig; 274 bool mEchConfigUsed = false; 275 bool mResolvedByTRR{false}; 276 nsIRequest::TRRMode mEffectiveTRRMode{nsIRequest::TRR_DEFAULT_MODE}; 277 nsITRRSkipReason::value mTRRSkipReason{nsITRRSkipReason::TRR_UNSET}; 278 279 nsCOMPtr<nsISupports> mInputCopyContext; 280 nsCOMPtr<nsISupports> mOutputCopyContext; 281 282 // mNetAddr/mSelfAddr is valid from GetPeerAddr()/GetSelfAddr() once we have 283 // reached STATE_TRANSFERRING. It must not change after that. 284 void SetSocketName(PRFileDesc* fd); 285 NetAddr mNetAddr; 286 NetAddr mSelfAddr; // getsockname() 287 Atomic<bool, Relaxed> mNetAddrIsSet{false}; 288 Atomic<bool, Relaxed> mSelfAddrIsSet{false}; 289 290 UniquePtr<NetAddr> mBindAddr; 291 292 // socket methods (these can only be called on the socket thread): 293 294 void SendStatus(nsresult status); 295 nsresult ResolveHost(); 296 nsresult BuildSocket(PRFileDesc*&, bool&, bool&); 297 nsresult InitiateSocket(); 298 bool RecoverFromError(); 299 300 void OnMsgInputPending() { 301 MOZ_ASSERT(OnSocketThread(), "not on socket thread"); 302 if (mState == STATE_TRANSFERRING) { 303 mPollFlags |= (PR_POLL_READ | PR_POLL_EXCEPT); 304 } 305 } 306 void OnMsgOutputPending() { 307 MOZ_ASSERT(OnSocketThread(), "not on socket thread"); 308 if (mState == STATE_TRANSFERRING) { 309 mPollFlags |= (PR_POLL_WRITE | PR_POLL_EXCEPT); 310 } 311 } 312 void OnMsgInputClosed(nsresult reason); 313 void OnMsgOutputClosed(nsresult reason); 314 315 // called when the socket is connected 316 void OnSocketConnected(); 317 318 //------------------------------------------------------------------------- 319 // socket input/output objects. these may be accessed on any thread with 320 // the exception of some specific methods (XXX). 321 322 // protects members in this section. 323 Mutex mLock{"nsSocketTransport.mLock"}; 324 LockedPRFileDesc mFD MOZ_GUARDED_BY(mLock); 325 // mFD is closed when mFDref goes to zero. 326 nsrefcnt mFDref MOZ_GUARDED_BY(mLock){0}; 327 // mFD is available to consumer when TRUE. 328 bool mFDconnected MOZ_GUARDED_BY(mLock){false}; 329 330 // A delete protector reference to gSocketTransportService held for lifetime 331 // of 'this'. Sometimes used interchangably with gSocketTransportService due 332 // to scoping. 333 RefPtr<nsSocketTransportService> mSocketTransportService; 334 335 nsCOMPtr<nsIInterfaceRequestor> mCallbacks; 336 nsCOMPtr<nsITransportEventSink> mEventSink; 337 nsCOMPtr<nsITLSSocketControl> mTLSSocketControl; 338 339 UniquePtr<nsSocketInputStream> mInput; 340 UniquePtr<nsSocketOutputStream> mOutput; 341 342 friend class nsSocketInputStream; 343 friend class nsSocketOutputStream; 344 345 // socket timeouts are protected by mLock. 346 uint16_t mTimeouts[2]{0}; 347 348 // linger options to use when closing 349 bool mLingerPolarity{false}; 350 int16_t mLingerTimeout{0}; 351 352 // QoS setting for socket 353 uint8_t mQoSBits{0x00}; 354 355 // 356 // mFD access methods: called with mLock held. 357 // 358 PRFileDesc* GetFD_Locked() MOZ_REQUIRES(mLock); 359 void ReleaseFD_Locked(PRFileDesc* fd) MOZ_REQUIRES(mLock); 360 361 // 362 // stream state changes (called outside mLock): 363 // 364 void OnInputClosed(nsresult reason) { 365 // no need to post an event if called on the socket thread 366 if (OnSocketThread()) { 367 OnMsgInputClosed(reason); 368 } else { 369 PostEvent(MSG_INPUT_CLOSED, reason); 370 } 371 } 372 void OnInputPending() { 373 // no need to post an event if called on the socket thread 374 if (OnSocketThread()) { 375 OnMsgInputPending(); 376 } else { 377 PostEvent(MSG_INPUT_PENDING); 378 } 379 } 380 void OnOutputClosed(nsresult reason) { 381 // no need to post an event if called on the socket thread 382 if (OnSocketThread()) { 383 OnMsgOutputClosed(reason); // XXX need to not be inside lock! 384 } else { 385 PostEvent(MSG_OUTPUT_CLOSED, reason); 386 } 387 } 388 void OnOutputPending() { 389 // no need to post an event if called on the socket thread 390 if (OnSocketThread()) { 391 OnMsgOutputPending(); 392 } else { 393 PostEvent(MSG_OUTPUT_PENDING); 394 } 395 } 396 397 #ifdef ENABLE_SOCKET_TRACING 398 void TraceInBuf(const char* buf, int32_t n); 399 void TraceOutBuf(const char* buf, int32_t n); 400 #endif 401 402 // Reads prefs to get default keepalive config. 403 nsresult EnsureKeepaliveValsAreInitialized(); 404 405 // Groups calls to fd.SetKeepaliveEnabled and fd.SetKeepaliveVals. 406 nsresult SetKeepaliveEnabledInternal(bool aEnable); 407 408 // True if keepalive has been enabled by the socket owner. Note: Keepalive 409 // must also be enabled globally for it to be enabled in TCP. 410 bool mKeepaliveEnabled{false}; 411 412 // Keepalive config (support varies by platform). 413 int32_t mKeepaliveIdleTimeS{-1}; 414 int32_t mKeepaliveRetryIntervalS{-1}; 415 int32_t mKeepaliveProbeCount{-1}; 416 417 Atomic<bool> mDoNotRetryToConnect{false}; 418 419 // Whether the port remapping has already been applied. We definitely want to 420 // prevent duplicate calls in case of chaining remapping. 421 bool mPortRemappingApplied = false; 422 423 bool mExternalDNSResolution = false; 424 bool mRetryDnsIfPossible = false; 425 }; 426 427 class nsSocketInputStream : public nsIAsyncInputStream { 428 public: 429 NS_DECL_ISUPPORTS_INHERITED 430 NS_DECL_NSIINPUTSTREAM 431 NS_DECL_NSIASYNCINPUTSTREAM 432 433 explicit nsSocketInputStream(nsSocketTransport*); 434 virtual ~nsSocketInputStream() = default; 435 436 // nsSocketTransport holds a ref to us 437 bool IsReferenced() { return mReaderRefCnt > 0; } 438 nsresult Condition() { 439 MutexAutoLock lock(mTransport->mLock); 440 return mCondition; 441 } 442 uint64_t ByteCount() { 443 MutexAutoLock lock(mTransport->mLock); 444 return mByteCount; 445 } 446 uint64_t ByteCount(MutexAutoLock&) MOZ_NO_THREAD_SAFETY_ANALYSIS { 447 return mByteCount; 448 } 449 450 // called by the socket transport on the socket thread... 451 void OnSocketReady(nsresult condition); 452 453 private: 454 nsSocketTransport* mTransport; 455 ThreadSafeAutoRefCnt mReaderRefCnt{0}; 456 457 // access to these should be protected by mTransport->mLock but we 458 // can't order things to allow using MOZ_GUARDED_BY(). 459 nsresult mCondition MOZ_GUARDED_BY(mTransport->mLock){NS_OK}; 460 nsCOMPtr<nsIInputStreamCallback> mCallback MOZ_GUARDED_BY(mTransport->mLock); 461 uint32_t mCallbackFlags MOZ_GUARDED_BY(mTransport->mLock){0}; 462 uint64_t mByteCount MOZ_GUARDED_BY(mTransport->mLock){0}; 463 }; 464 465 //----------------------------------------------------------------------------- 466 467 class nsSocketOutputStream : public nsIAsyncOutputStream { 468 public: 469 NS_DECL_ISUPPORTS_INHERITED 470 NS_DECL_NSIOUTPUTSTREAM 471 NS_DECL_NSIASYNCOUTPUTSTREAM 472 473 explicit nsSocketOutputStream(nsSocketTransport*); 474 virtual ~nsSocketOutputStream() = default; 475 476 // nsSocketTransport holds a ref to us 477 bool IsReferenced() { return mWriterRefCnt > 0; } 478 nsresult Condition() { 479 MutexAutoLock lock(mTransport->mLock); 480 return mCondition; 481 } 482 uint64_t ByteCount() { 483 MutexAutoLock lock(mTransport->mLock); 484 return mByteCount; 485 } 486 uint64_t ByteCount(MutexAutoLock&) MOZ_NO_THREAD_SAFETY_ANALYSIS { 487 return mByteCount; 488 } 489 490 // called by the socket transport on the socket thread... 491 void OnSocketReady(nsresult condition); 492 493 private: 494 static nsresult WriteFromSegments(nsIInputStream*, void*, const char*, 495 uint32_t offset, uint32_t count, 496 uint32_t* countRead); 497 498 nsSocketTransport* mTransport; 499 ThreadSafeAutoRefCnt mWriterRefCnt{0}; 500 501 // access to these should be protected by mTransport->mLock but we 502 // can't order things to allow using MOZ_GUARDED_BY(). 503 nsresult mCondition MOZ_GUARDED_BY(mTransport->mLock){NS_OK}; 504 nsCOMPtr<nsIOutputStreamCallback> mCallback MOZ_GUARDED_BY(mTransport->mLock); 505 uint32_t mCallbackFlags MOZ_GUARDED_BY(mTransport->mLock){0}; 506 uint64_t mByteCount MOZ_GUARDED_BY(mTransport->mLock){0}; 507 }; 508 509 } // namespace net 510 } // namespace mozilla 511 512 #endif // !nsSocketTransport_h__