LCOV - code coverage report
Current view: top level - netwerk/base - nsSocketTransport2.h (source / functions) Hit Total Coverage
Test: output.info Lines: 71 76 93.4 %
Date: 2017-07-14 16:53:18 Functions: 24 24 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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 "mozilla/Mutex.h"
      13             : #include "nsSocketTransportService2.h"
      14             : #include "nsString.h"
      15             : #include "nsCOMPtr.h"
      16             : 
      17             : #include "nsIInterfaceRequestor.h"
      18             : #include "nsISocketTransport.h"
      19             : #include "nsIAsyncInputStream.h"
      20             : #include "nsIAsyncOutputStream.h"
      21             : #include "nsIDNSListener.h"
      22             : #include "nsIClassInfo.h"
      23             : #include "TCPFastOpen.h"
      24             : #include "mozilla/net/DNS.h"
      25             : #include "nsASocketHandler.h"
      26             : #include "mozilla/Telemetry.h"
      27             : 
      28             : #include "prerror.h"
      29             : #include "nsAutoPtr.h"
      30             : 
      31             : class nsICancelable;
      32             : class nsIDNSRecord;
      33             : class nsIInterfaceRequestor;
      34             : 
      35             : //-----------------------------------------------------------------------------
      36             : 
      37             : // after this short interval, we will return to PR_Poll
      38             : #define NS_SOCKET_CONNECT_TIMEOUT PR_MillisecondsToInterval(20)
      39             : 
      40             : //-----------------------------------------------------------------------------
      41             : 
      42             : namespace mozilla {
      43             : namespace net {
      44             : 
      45             : nsresult
      46             : ErrorAccordingToNSPR(PRErrorCode errorCode);
      47             : 
      48             : class nsSocketTransport;
      49             : 
      50             : class nsSocketInputStream : public nsIAsyncInputStream
      51             : {
      52             : public:
      53             :     NS_DECL_ISUPPORTS_INHERITED
      54             :     NS_DECL_NSIINPUTSTREAM
      55             :     NS_DECL_NSIASYNCINPUTSTREAM
      56             : 
      57             :     explicit nsSocketInputStream(nsSocketTransport *);
      58             :     virtual ~nsSocketInputStream();
      59             : 
      60           3 :     bool     IsReferenced() { return mReaderRefCnt > 0; }
      61             :     nsresult Condition()    { return mCondition; }
      62          12 :     uint64_t ByteCount()    { return mByteCount; }
      63             : 
      64             :     // called by the socket transport on the socket thread...
      65             :     void OnSocketReady(nsresult condition);
      66             : 
      67             : private:
      68             :     nsSocketTransport               *mTransport;
      69             :     ThreadSafeAutoRefCnt             mReaderRefCnt;
      70             : 
      71             :     // access to these is protected by mTransport->mLock
      72             :     nsresult                         mCondition;
      73             :     nsCOMPtr<nsIInputStreamCallback> mCallback;
      74             :     uint32_t                         mCallbackFlags;
      75             :     uint64_t                         mByteCount;
      76             : };
      77             : 
      78             : //-----------------------------------------------------------------------------
      79             : 
      80             : class nsSocketOutputStream : public nsIAsyncOutputStream
      81             : {
      82             : public:
      83             :     NS_DECL_ISUPPORTS_INHERITED
      84             :     NS_DECL_NSIOUTPUTSTREAM
      85             :     NS_DECL_NSIASYNCOUTPUTSTREAM
      86             : 
      87             :     explicit nsSocketOutputStream(nsSocketTransport *);
      88             :     virtual ~nsSocketOutputStream();
      89             : 
      90           3 :     bool     IsReferenced() { return mWriterRefCnt > 0; }
      91             :     nsresult Condition()    { return mCondition; }
      92           5 :     uint64_t ByteCount()    { return mByteCount; }
      93             : 
      94             :     // called by the socket transport on the socket thread...
      95             :     void OnSocketReady(nsresult condition);
      96             : 
      97             : private:
      98             :     static nsresult WriteFromSegments(nsIInputStream *, void *,
      99             :                                       const char *, uint32_t offset,
     100             :                                       uint32_t count, uint32_t *countRead);
     101             : 
     102             :     nsSocketTransport                *mTransport;
     103             :     ThreadSafeAutoRefCnt              mWriterRefCnt;
     104             : 
     105             :     // access to these is protected by mTransport->mLock
     106             :     nsresult                          mCondition;
     107             :     nsCOMPtr<nsIOutputStreamCallback> mCallback;
     108             :     uint32_t                          mCallbackFlags;
     109             :     uint64_t                          mByteCount;
     110             : };
     111             : 
     112             : //-----------------------------------------------------------------------------
     113             : 
     114             : class nsSocketTransport final : public nsASocketHandler
     115             :                               , public nsISocketTransport
     116             :                               , public nsIDNSListener
     117             :                               , public nsIClassInfo
     118             :                               , public nsIInterfaceRequestor
     119             : {
     120             : public:
     121             :     NS_DECL_THREADSAFE_ISUPPORTS
     122             :     NS_DECL_NSITRANSPORT
     123             :     NS_DECL_NSISOCKETTRANSPORT
     124             :     NS_DECL_NSIDNSLISTENER
     125             :     NS_DECL_NSICLASSINFO
     126             :     NS_DECL_NSIINTERFACEREQUESTOR
     127             : 
     128             :     nsSocketTransport();
     129             : 
     130             :     // this method instructs the socket transport to open a socket of the
     131             :     // given type(s) to the given host or proxy.
     132             :     nsresult Init(const char **socketTypes, uint32_t typeCount,
     133             :                   const nsACString &host, uint16_t port,
     134             :                   const nsACString &hostRoute, uint16_t portRoute,
     135             :                   nsIProxyInfo *proxyInfo);
     136             : 
     137             :     // Alternative Init method for when the IP-address of the host
     138             :     // has been pre-resolved using a alternative means (e.g. FlyWeb service
     139             :     // info).
     140             :     nsresult InitPreResolved(const char **socketTypes, uint32_t typeCount,
     141             :                              const nsACString &host, uint16_t port,
     142             :                              const nsACString &hostRoute, uint16_t portRoute,
     143             :                              nsIProxyInfo *proxyInfo,
     144             :                              const mozilla::net::NetAddr* addr);
     145             : 
     146             :     // this method instructs the socket transport to use an already connected
     147             :     // socket with the given address.
     148             :     nsresult InitWithConnectedSocket(PRFileDesc *socketFD,
     149             :                                      const NetAddr *addr);
     150             : 
     151             :     // this method instructs the socket transport to use an already connected
     152             :     // socket with the given address, and additionally supplies security info.
     153             :     nsresult InitWithConnectedSocket(PRFileDesc* aSocketFD,
     154             :                                      const NetAddr* aAddr,
     155             :                                      nsISupports* aSecInfo);
     156             : 
     157             :     // This method instructs the socket transport to open a socket
     158             :     // connected to the given Unix domain address. We can only create
     159             :     // unlayered, simple, stream sockets.
     160             :     nsresult InitWithFilename(const char *filename);
     161             : 
     162             :     // nsASocketHandler methods:
     163             :     void OnSocketReady(PRFileDesc *, int16_t outFlags) override;
     164             :     void OnSocketDetached(PRFileDesc *) override;
     165             :     void IsLocal(bool *aIsLocal) override;
     166             :     void OnKeepaliveEnabledPrefChange(bool aEnabled) override final;
     167             : 
     168             :     // called when a socket event is handled
     169             :     void OnSocketEvent(uint32_t type, nsresult status, nsISupports *param);
     170             : 
     171           2 :     uint64_t ByteCountReceived() override { return mInput.ByteCount(); }
     172           2 :     uint64_t ByteCountSent() override { return mOutput.ByteCount(); }
     173             :     static void CloseSocket(PRFileDesc *aFd, bool aTelemetryEnabled);
     174             :     static void SendPRBlockingTelemetry(PRIntervalTime aStart,
     175             :         Telemetry::HistogramID aIDNormal,
     176             :         Telemetry::HistogramID aIDShutdown,
     177             :         Telemetry::HistogramID aIDConnectivityChange,
     178             :         Telemetry::HistogramID aIDLinkChange,
     179             :         Telemetry::HistogramID aIDOffline);
     180             : protected:
     181             : 
     182             :     virtual ~nsSocketTransport();
     183             :     void     CleanupTypes();
     184             : 
     185             : private:
     186             : 
     187             :     // event types
     188             :     enum {
     189             :         MSG_ENSURE_CONNECT,
     190             :         MSG_DNS_LOOKUP_COMPLETE,
     191             :         MSG_RETRY_INIT_SOCKET,
     192             :         MSG_TIMEOUT_CHANGED,
     193             :         MSG_INPUT_CLOSED,
     194             :         MSG_INPUT_PENDING,
     195             :         MSG_OUTPUT_CLOSED,
     196             :         MSG_OUTPUT_PENDING
     197             :     };
     198             :     nsresult PostEvent(uint32_t type, nsresult status = NS_OK, nsISupports *param = nullptr);
     199             : 
     200             :     enum {
     201             :         STATE_CLOSED,
     202             :         STATE_IDLE,
     203             :         STATE_RESOLVING,
     204             :         STATE_CONNECTING,
     205             :         STATE_TRANSFERRING
     206             :     };
     207             : 
     208             :     // Safer way to get and automatically release PRFileDesc objects.
     209             :     class MOZ_STACK_CLASS PRFileDescAutoLock
     210             :     {
     211             :     public:
     212           9 :       explicit PRFileDescAutoLock(nsSocketTransport *aSocketTransport,
     213             :                                   bool aAlsoDuringFastOpen,
     214             :                                   nsresult *aConditionWhileLocked = nullptr)
     215           9 :         : mSocketTransport(aSocketTransport)
     216           9 :         , mFd(nullptr)
     217             :       {
     218           9 :         MOZ_ASSERT(aSocketTransport);
     219          18 :         MutexAutoLock lock(mSocketTransport->mLock);
     220           9 :         if (aConditionWhileLocked) {
     221           1 :           *aConditionWhileLocked = mSocketTransport->mCondition;
     222           1 :           if (NS_FAILED(mSocketTransport->mCondition)) {
     223           0 :             return;
     224             :           }
     225             :         }
     226           9 :         if (!aAlsoDuringFastOpen) {
     227           1 :           mFd = mSocketTransport->GetFD_Locked();
     228             :         } else {
     229           8 :           mFd = mSocketTransport->GetFD_LockedAlsoDuringFastOpen();
     230             :         }
     231             :       }
     232          18 :       ~PRFileDescAutoLock() {
     233          18 :         MutexAutoLock lock(mSocketTransport->mLock);
     234           9 :         if (mFd) {
     235           9 :           mSocketTransport->ReleaseFD_Locked(mFd);
     236             :         }
     237           9 :       }
     238           9 :       bool IsInitialized() {
     239           9 :         return mFd;
     240             :       }
     241           1 :       operator PRFileDesc*() {
     242           1 :         return mFd;
     243             :       }
     244             :       nsresult SetKeepaliveEnabled(bool aEnable);
     245             :       nsresult SetKeepaliveVals(bool aEnabled, int aIdleTime,
     246             :                                 int aRetryInterval, int aProbeCount);
     247             :     private:
     248             :       operator PRFileDescAutoLock*() { return nullptr; }
     249             : 
     250             :       // Weak ptr to nsSocketTransport since this is a stack class only.
     251             :       nsSocketTransport *mSocketTransport;
     252             :       PRFileDesc        *mFd;
     253             :     };
     254             :     friend class PRFileDescAutoLock;
     255             : 
     256             :     class LockedPRFileDesc
     257             :     {
     258             :     public:
     259           3 :       explicit LockedPRFileDesc(nsSocketTransport *aSocketTransport)
     260           3 :         : mSocketTransport(aSocketTransport)
     261           3 :         , mFd(nullptr)
     262             :       {
     263           3 :         MOZ_ASSERT(aSocketTransport);
     264           3 :       }
     265           2 :       ~LockedPRFileDesc() {}
     266          37 :       bool IsInitialized() {
     267          37 :         return mFd;
     268             :       }
     269           5 :       LockedPRFileDesc& operator=(PRFileDesc *aFd) {
     270           5 :         mSocketTransport->mLock.AssertCurrentThreadOwns();
     271           5 :         mFd = aFd;
     272           5 :         return *this;
     273             :       }
     274          35 :       operator PRFileDesc*() {
     275          35 :         if (mSocketTransport->mAttached) {
     276          35 :           mSocketTransport->mLock.AssertCurrentThreadOwns();
     277             :         }
     278          35 :         return mFd;
     279             :       }
     280          30 :       bool operator==(PRFileDesc *aFd) {
     281          30 :         mSocketTransport->mLock.AssertCurrentThreadOwns();
     282          30 :         return mFd == aFd;
     283             :       }
     284             :     private:
     285             :       operator LockedPRFileDesc*() { return nullptr; }
     286             :       // Weak ptr to nsSocketTransport since it owns this class.
     287             :       nsSocketTransport *mSocketTransport;
     288             :       PRFileDesc        *mFd;
     289             :     };
     290             :     friend class LockedPRFileDesc;
     291             : 
     292             :     //-------------------------------------------------------------------------
     293             :     // these members are "set" at initialization time and are never modified
     294             :     // afterwards.  this allows them to be safely accessed from any thread.
     295             :     //-------------------------------------------------------------------------
     296             : 
     297             :     // socket type info:
     298             :     char       **mTypes;
     299             :     uint32_t     mTypeCount;
     300             :     nsCString    mHost;
     301             :     nsCString    mProxyHost;
     302             :     nsCString    mOriginHost;
     303             :     uint16_t     mPort;
     304             :     nsCOMPtr<nsIProxyInfo> mProxyInfo;
     305             :     uint16_t     mProxyPort;
     306             :     uint16_t     mOriginPort;
     307             :     bool mProxyTransparent;
     308             :     bool mProxyTransparentResolvesHost;
     309             :     bool mHttpsProxy;
     310             :     uint32_t     mConnectionFlags;
     311             :     bool mReuseAddrPort;
     312             : 
     313             :     // The origin attributes are used to create sockets.  The first party domain
     314             :     // will eventually be used to isolate OCSP cache and is only non-empty when
     315             :     // "privacy.firstparty.isolate" is enabled.  Setting this is the only way to
     316             :     // carry origin attributes down to NSPR layers which are final consumers.
     317             :     // It must be set before the socket transport is built.
     318             :     OriginAttributes mOriginAttributes;
     319             : 
     320           3 :     uint16_t         SocketPort() { return (!mProxyHost.IsEmpty() && !mProxyTransparent) ? mProxyPort : mPort; }
     321           6 :     const nsCString &SocketHost() { return (!mProxyHost.IsEmpty() && !mProxyTransparent) ? mProxyHost : mHost; }
     322             : 
     323             :     //-------------------------------------------------------------------------
     324             :     // members accessible only on the socket transport thread:
     325             :     //  (the exception being initialization/shutdown time)
     326             :     //-------------------------------------------------------------------------
     327             : 
     328             :     // socket state vars:
     329             :     uint32_t     mState;     // STATE_??? flags
     330             :     bool mAttached;
     331             :     bool mInputClosed;
     332             :     bool mOutputClosed;
     333             : 
     334             :     // The platform-specific network interface id that this socket
     335             :     // associated with.
     336             :     nsCString mNetworkInterfaceId;
     337             : 
     338             :     // this flag is used to determine if the results of a host lookup arrive
     339             :     // recursively or not.  this flag is not protected by any lock.
     340             :     bool mResolving;
     341             : 
     342             :     nsCOMPtr<nsICancelable> mDNSRequest;
     343             :     nsCOMPtr<nsIDNSRecord>  mDNSRecord;
     344             : 
     345             :     // mNetAddr/mSelfAddr is valid from GetPeerAddr()/GetSelfAddr() once we have
     346             :     // reached STATE_TRANSFERRING. It must not change after that.
     347             :     void                    SetSocketName(PRFileDesc *fd);
     348             :     NetAddr                 mNetAddr;
     349             :     NetAddr                 mSelfAddr; // getsockname()
     350             :     Atomic<bool, Relaxed>   mNetAddrIsSet;
     351             :     Atomic<bool, Relaxed>   mSelfAddrIsSet;
     352             :     Atomic<bool, Relaxed>   mNetAddrPreResolved;
     353             : 
     354             :     nsAutoPtr<NetAddr>      mBindAddr;
     355             : 
     356             :     // socket methods (these can only be called on the socket thread):
     357             : 
     358             :     void     SendStatus(nsresult status);
     359             :     nsresult ResolveHost();
     360             :     nsresult BuildSocket(PRFileDesc *&, bool &, bool &);
     361             :     nsresult InitiateSocket();
     362             :     bool     RecoverFromError();
     363             : 
     364           6 :     void OnMsgInputPending()
     365             :     {
     366           6 :         if (mState == STATE_TRANSFERRING)
     367           6 :             mPollFlags |= (PR_POLL_READ | PR_POLL_EXCEPT);
     368           6 :     }
     369           9 :     void OnMsgOutputPending()
     370             :     {
     371           9 :         if (mState == STATE_TRANSFERRING)
     372           2 :             mPollFlags |= (PR_POLL_WRITE | PR_POLL_EXCEPT);
     373           9 :     }
     374             :     void OnMsgInputClosed(nsresult reason);
     375             :     void OnMsgOutputClosed(nsresult reason);
     376             : 
     377             :     // called when the socket is connected
     378             :     void OnSocketConnected();
     379             : 
     380             :     //-------------------------------------------------------------------------
     381             :     // socket input/output objects.  these may be accessed on any thread with
     382             :     // the exception of some specific methods (XXX).
     383             : 
     384             :     Mutex            mLock;  // protects members in this section.
     385             :     LockedPRFileDesc mFD;
     386             :     nsrefcnt         mFDref;       // mFD is closed when mFDref goes to zero.
     387             :     bool             mFDconnected; // mFD is available to consumer when TRUE.
     388             :     bool             mFDFastOpenInProgress; // Fast Open is in progress, so
     389             :                                             // socket available for some
     390             :                                             // operations.
     391             : 
     392             :     // A delete protector reference to gSocketTransportService held for lifetime
     393             :     // of 'this'. Sometimes used interchangably with gSocketTransportService due
     394             :     // to scoping.
     395             :     RefPtr<nsSocketTransportService> mSocketTransportService;
     396             : 
     397             :     nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
     398             :     nsCOMPtr<nsITransportEventSink> mEventSink;
     399             :     nsCOMPtr<nsISupports>           mSecInfo;
     400             : 
     401             :     nsSocketInputStream  mInput;
     402             :     nsSocketOutputStream mOutput;
     403             : 
     404             :     friend class nsSocketInputStream;
     405             :     friend class nsSocketOutputStream;
     406             : 
     407             :     // socket timeouts are not protected by any lock.
     408             :     uint16_t mTimeouts[2];
     409             : 
     410             :     // QoS setting for socket
     411             :     uint8_t mQoSBits;
     412             : 
     413             :     //
     414             :     // mFD access methods: called with mLock held.
     415             :     //
     416             :     PRFileDesc *GetFD_Locked();
     417             :     PRFileDesc *GetFD_LockedAlsoDuringFastOpen();
     418             :     void        ReleaseFD_Locked(PRFileDesc *fd);
     419             :     bool FastOpenInProgress();
     420             : 
     421             :     //
     422             :     // stream state changes (called outside mLock):
     423             :     //
     424           2 :     void OnInputClosed(nsresult reason)
     425             :     {
     426             :         // no need to post an event if called on the socket thread
     427           2 :         if (OnSocketThread())
     428           2 :             OnMsgInputClosed(reason);
     429             :         else
     430           0 :             PostEvent(MSG_INPUT_CLOSED, reason);
     431           2 :     }
     432           6 :     void OnInputPending()
     433             :     {
     434             :         // no need to post an event if called on the socket thread
     435           6 :         if (OnSocketThread())
     436           6 :             OnMsgInputPending();
     437             :         else
     438           0 :             PostEvent(MSG_INPUT_PENDING);
     439           6 :     }
     440           2 :     void OnOutputClosed(nsresult reason)
     441             :     {
     442             :         // no need to post an event if called on the socket thread
     443           2 :         if (OnSocketThread())
     444           2 :             OnMsgOutputClosed(reason); // XXX need to not be inside lock!
     445             :         else
     446           0 :             PostEvent(MSG_OUTPUT_CLOSED, reason);
     447           2 :     }
     448           9 :     void OnOutputPending()
     449             :     {
     450             :         // no need to post an event if called on the socket thread
     451           9 :         if (OnSocketThread())
     452           9 :             OnMsgOutputPending();
     453             :         else
     454           0 :             PostEvent(MSG_OUTPUT_PENDING);
     455           9 :     }
     456             : 
     457             : #ifdef ENABLE_SOCKET_TRACING
     458             :     void TraceInBuf(const char *buf, int32_t n);
     459             :     void TraceOutBuf(const char *buf, int32_t n);
     460             : #endif
     461             : 
     462             :     // Reads prefs to get default keepalive config.
     463             :     nsresult EnsureKeepaliveValsAreInitialized();
     464             : 
     465             :     // Groups calls to fd.SetKeepaliveEnabled and fd.SetKeepaliveVals.
     466             :     nsresult SetKeepaliveEnabledInternal(bool aEnable);
     467             : 
     468             :     // True if keepalive has been enabled by the socket owner. Note: Keepalive
     469             :     // must also be enabled globally for it to be enabled in TCP.
     470             :     bool mKeepaliveEnabled;
     471             : 
     472             :     // Keepalive config (support varies by platform).
     473             :     int32_t mKeepaliveIdleTimeS;
     474             :     int32_t mKeepaliveRetryIntervalS;
     475             :     int32_t mKeepaliveProbeCount;
     476             : 
     477             :     // A Fast Open callback.
     478             :     TCPFastOpen *mFastOpenCallback;
     479             :     bool mFastOpenLayerHasBufferedData;
     480             : 
     481             :     bool mDoNotRetryToConnect;
     482             : };
     483             : 
     484             : } // namespace net
     485             : } // namespace mozilla
     486             : 
     487             : #endif // !nsSocketTransport_h__

Generated by: LCOV version 1.13