tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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__