netwerk/base/src/nsSocketTransport2.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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 "mozilla/Mutex.h"
    13 #include "nsSocketTransportService2.h"
    14 #include "nsString.h"
    15 #include "nsCOMPtr.h"
    17 #include "nsISocketTransport.h"
    18 #include "nsIAsyncInputStream.h"
    19 #include "nsIAsyncOutputStream.h"
    20 #include "nsIDNSListener.h"
    21 #include "nsIClassInfo.h"
    22 #include "mozilla/net/DNS.h"
    23 #include "nsASocketHandler.h"
    25 #include "prerror.h"
    26 #include "nsAutoPtr.h"
    28 class nsSocketTransport;
    29 class nsICancelable;
    30 class nsIDNSRecord;
    31 class nsIInterfaceRequestor;
    33 nsresult
    34 ErrorAccordingToNSPR(PRErrorCode errorCode);
    36 //-----------------------------------------------------------------------------
    38 // after this short interval, we will return to PR_Poll
    39 #define NS_SOCKET_CONNECT_TIMEOUT PR_MillisecondsToInterval(20)
    41 //-----------------------------------------------------------------------------
    43 class nsSocketInputStream : public nsIAsyncInputStream
    44 {
    45 public:
    46     NS_DECL_ISUPPORTS_INHERITED
    47     NS_DECL_NSIINPUTSTREAM
    48     NS_DECL_NSIASYNCINPUTSTREAM
    50     nsSocketInputStream(nsSocketTransport *);
    51     virtual ~nsSocketInputStream();
    53     bool     IsReferenced() { return mReaderRefCnt > 0; }
    54     nsresult Condition()    { return mCondition; }
    55     uint64_t ByteCount()    { return mByteCount; }
    57     // called by the socket transport on the socket thread...
    58     void OnSocketReady(nsresult condition);
    60 private:
    61     nsSocketTransport               *mTransport;
    62     mozilla::ThreadSafeAutoRefCnt    mReaderRefCnt;
    64     // access to these is protected by mTransport->mLock
    65     nsresult                         mCondition;
    66     nsCOMPtr<nsIInputStreamCallback> mCallback;
    67     uint32_t                         mCallbackFlags;
    68     uint64_t                         mByteCount;
    69 };
    71 //-----------------------------------------------------------------------------
    73 class nsSocketOutputStream : public nsIAsyncOutputStream
    74 {
    75 public:
    76     NS_DECL_ISUPPORTS_INHERITED
    77     NS_DECL_NSIOUTPUTSTREAM
    78     NS_DECL_NSIASYNCOUTPUTSTREAM
    80     nsSocketOutputStream(nsSocketTransport *);
    81     virtual ~nsSocketOutputStream();
    83     bool     IsReferenced() { return mWriterRefCnt > 0; }
    84     nsresult Condition()    { return mCondition; }
    85     uint64_t ByteCount()    { return mByteCount; }
    87     // called by the socket transport on the socket thread...
    88     void OnSocketReady(nsresult condition); 
    90 private:
    91     static NS_METHOD WriteFromSegments(nsIInputStream *, void *,
    92                                        const char *, uint32_t offset,
    93                                        uint32_t count, uint32_t *countRead);
    95     nsSocketTransport                *mTransport;
    96     mozilla::ThreadSafeAutoRefCnt     mWriterRefCnt;
    98     // access to these is protected by mTransport->mLock
    99     nsresult                          mCondition;
   100     nsCOMPtr<nsIOutputStreamCallback> mCallback;
   101     uint32_t                          mCallbackFlags;
   102     uint64_t                          mByteCount;
   103 };
   105 //-----------------------------------------------------------------------------
   107 class nsSocketTransport : public nsASocketHandler
   108                         , public nsISocketTransport
   109                         , public nsIDNSListener
   110                         , public nsIClassInfo
   111 {
   112     typedef mozilla::Mutex Mutex;
   114 public:
   115     NS_DECL_THREADSAFE_ISUPPORTS
   116     NS_DECL_NSITRANSPORT
   117     NS_DECL_NSISOCKETTRANSPORT
   118     NS_DECL_NSIDNSLISTENER
   119     NS_DECL_NSICLASSINFO
   121     nsSocketTransport();
   123     // this method instructs the socket transport to open a socket of the
   124     // given type(s) to the given host or proxy.
   125     nsresult Init(const char **socketTypes, uint32_t typeCount,
   126                   const nsACString &host, uint16_t port,
   127                   nsIProxyInfo *proxyInfo);
   129     // this method instructs the socket transport to use an already connected
   130     // socket with the given address.
   131     nsresult InitWithConnectedSocket(PRFileDesc *socketFD,
   132                                      const mozilla::net::NetAddr *addr);
   134     // This method instructs the socket transport to open a socket
   135     // connected to the given Unix domain address. We can only create
   136     // unlayered, simple, stream sockets.
   137     nsresult InitWithFilename(const char *filename);
   139     // nsASocketHandler methods:
   140     void OnSocketReady(PRFileDesc *, int16_t outFlags);
   141     void OnSocketDetached(PRFileDesc *);
   142     void IsLocal(bool *aIsLocal);
   143     void OnKeepaliveEnabledPrefChange(bool aEnabled) MOZ_OVERRIDE MOZ_FINAL;
   145     // called when a socket event is handled
   146     void OnSocketEvent(uint32_t type, nsresult status, nsISupports *param);
   148     uint64_t ByteCountReceived() { return mInput.ByteCount(); }
   149     uint64_t ByteCountSent() { return mOutput.ByteCount(); }
   150 protected:
   152     virtual ~nsSocketTransport();
   154 private:
   156     // event types
   157     enum {
   158         MSG_ENSURE_CONNECT,
   159         MSG_DNS_LOOKUP_COMPLETE,
   160         MSG_RETRY_INIT_SOCKET,
   161         MSG_TIMEOUT_CHANGED,
   162         MSG_INPUT_CLOSED,
   163         MSG_INPUT_PENDING,
   164         MSG_OUTPUT_CLOSED,
   165         MSG_OUTPUT_PENDING
   166     };
   167     nsresult PostEvent(uint32_t type, nsresult status = NS_OK, nsISupports *param = nullptr);
   169     enum {
   170         STATE_CLOSED,
   171         STATE_IDLE,
   172         STATE_RESOLVING,
   173         STATE_CONNECTING,
   174         STATE_TRANSFERRING,
   175         STATE_SENDINGGET,
   176         STATE_SENTGET
   177     };
   179     // Safer way to get and automatically release PRFileDesc objects.
   180     class MOZ_STACK_CLASS PRFileDescAutoLock
   181     {
   182     public:
   183       typedef mozilla::MutexAutoLock MutexAutoLock;
   185       PRFileDescAutoLock(nsSocketTransport *aSocketTransport,
   186                          nsresult *aConditionWhileLocked = nullptr)
   187         : mSocketTransport(aSocketTransport)
   188         , mFd(nullptr)
   189       {
   190         MOZ_ASSERT(aSocketTransport);
   191         MutexAutoLock lock(mSocketTransport->mLock);
   192         if (aConditionWhileLocked) {
   193           *aConditionWhileLocked = mSocketTransport->mCondition;
   194           if (NS_FAILED(mSocketTransport->mCondition)) {
   195             return;
   196           }
   197         }
   198         mFd = mSocketTransport->GetFD_Locked();
   199       }
   200       ~PRFileDescAutoLock() {
   201         MutexAutoLock lock(mSocketTransport->mLock);
   202         if (mFd) {
   203           mSocketTransport->ReleaseFD_Locked(mFd);
   204         }
   205       }
   206       bool IsInitialized() {
   207         return mFd;
   208       }
   209       operator PRFileDesc*() {
   210         return mFd;
   211       }
   212       nsresult SetKeepaliveEnabled(bool aEnable);
   213       nsresult SetKeepaliveVals(bool aEnabled, int aIdleTime,
   214                                 int aRetryInterval, int aProbeCount);
   215     private:
   216       operator PRFileDescAutoLock*() { return nullptr; }
   218       // Weak ptr to nsSocketTransport since this is a stack class only.
   219       nsSocketTransport *mSocketTransport;
   220       PRFileDesc        *mFd;
   221     };
   222     friend class PRFileDescAutoLock;
   224     class LockedPRFileDesc
   225     {
   226     public:
   227       LockedPRFileDesc(nsSocketTransport *aSocketTransport)
   228         : mSocketTransport(aSocketTransport)
   229         , mFd(nullptr)
   230       {
   231         MOZ_ASSERT(aSocketTransport);
   232       }
   233       ~LockedPRFileDesc() {}
   234       bool IsInitialized() {
   235         return mFd;
   236       }
   237       LockedPRFileDesc& operator=(PRFileDesc *aFd) {
   238         mSocketTransport->mLock.AssertCurrentThreadOwns();
   239         mFd = aFd;
   240         return *this;
   241       }
   242       operator PRFileDesc*() {
   243         if (mSocketTransport->mAttached) {
   244           mSocketTransport->mLock.AssertCurrentThreadOwns();
   245         }
   246         return mFd;
   247       }
   248       bool operator==(PRFileDesc *aFd) {
   249         mSocketTransport->mLock.AssertCurrentThreadOwns();
   250         return mFd == aFd;
   251       }
   252     private:
   253       operator LockedPRFileDesc*() { return nullptr; }
   254       // Weak ptr to nsSocketTransport since it owns this class.
   255       nsSocketTransport *mSocketTransport;
   256       PRFileDesc        *mFd;
   257     };
   258     friend class LockedPRFileDesc;
   260     //-------------------------------------------------------------------------
   261     // these members are "set" at initialization time and are never modified
   262     // afterwards.  this allows them to be safely accessed from any thread.
   263     //-------------------------------------------------------------------------
   265     // socket type info:
   266     char       **mTypes;
   267     uint32_t     mTypeCount;
   268     nsCString    mHost;
   269     uint16_t     mPort;
   270     bool         mHttpsProxy;
   272     nsCOMPtr<nsIProxyInfo> mProxyInfo;
   273     bool         mProxyUse;
   274     bool         mProxyTransparent;
   275     bool         mProxyTransparentResolvesHost;
   276     uint32_t     mConnectionFlags;
   278     uint16_t         SocketPort();
   279     const nsCString &SocketHost();
   280     nsCString        mProxyHostCache; // for SocketHost() only
   282     //-------------------------------------------------------------------------
   283     // members accessible only on the socket transport thread:
   284     //  (the exception being initialization/shutdown time)
   285     //-------------------------------------------------------------------------
   287     // socket state vars:
   288     uint32_t     mState;     // STATE_??? flags
   289     bool mAttached;
   290     bool mInputClosed;
   291     bool mOutputClosed;
   293     // this flag is used to determine if the results of a host lookup arrive
   294     // recursively or not.  this flag is not protected by any lock.
   295     bool mResolving;
   297     nsCOMPtr<nsICancelable> mDNSRequest;
   298     nsCOMPtr<nsIDNSRecord>  mDNSRecord;
   300     // mNetAddr is valid from GetPeerAddr() once we have
   301     // reached STATE_TRANSFERRING. It must not change after that.
   302     mozilla::net::NetAddr   mNetAddr;
   303     bool                    mNetAddrIsSet;
   305     // socket methods (these can only be called on the socket thread):
   307     void     SendStatus(nsresult status);
   308     nsresult ResolveHost();
   309     nsresult BuildSocket(PRFileDesc *&, bool &, bool &); 
   310     nsresult InitiateSocket();
   311     bool     RecoverFromError();
   313     void OnMsgInputPending()
   314     {
   315         if (mState == STATE_TRANSFERRING)
   316             mPollFlags |= (PR_POLL_READ | PR_POLL_EXCEPT);
   317     }
   318     void OnMsgOutputPending()
   319     {
   320         if (mState == STATE_TRANSFERRING)
   321             mPollFlags |= (PR_POLL_WRITE | PR_POLL_EXCEPT);
   322     }
   323     void OnMsgInputClosed(nsresult reason);
   324     void OnMsgOutputClosed(nsresult reason);
   326     // called when the socket is connected
   327     void OnSocketConnected();
   329     //-------------------------------------------------------------------------
   330     // socket input/output objects.  these may be accessed on any thread with
   331     // the exception of some specific methods (XXX).
   333     Mutex            mLock;  // protects members in this section.
   334     LockedPRFileDesc mFD;
   335     nsrefcnt         mFDref;       // mFD is closed when mFDref goes to zero.
   336     bool             mFDconnected; // mFD is available to consumer when TRUE.
   338     // A delete protector reference to gSocketTransportService held for lifetime
   339     // of 'this'. Sometimes used interchangably with gSocketTransportService due
   340     // to scoping.
   341     nsRefPtr<nsSocketTransportService> mSocketTransportService;
   343     nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
   344     nsCOMPtr<nsITransportEventSink> mEventSink;
   345     nsCOMPtr<nsISupports>           mSecInfo;
   347     nsSocketInputStream  mInput;
   348     nsSocketOutputStream mOutput;
   350     friend class nsSocketInputStream;
   351     friend class nsSocketOutputStream;
   353     // socket timeouts are not protected by any lock.
   354     uint16_t mTimeouts[2];
   356     // QoS setting for socket
   357     uint8_t mQoSBits;
   359     //
   360     // mFD access methods: called with mLock held.
   361     //
   362     PRFileDesc *GetFD_Locked();
   363     void        ReleaseFD_Locked(PRFileDesc *fd);
   365     //
   366     // stream state changes (called outside mLock):
   367     //
   368     void OnInputClosed(nsresult reason)
   369     {
   370         // no need to post an event if called on the socket thread
   371         if (PR_GetCurrentThread() == gSocketThread)
   372             OnMsgInputClosed(reason);
   373         else
   374             PostEvent(MSG_INPUT_CLOSED, reason);
   375     }
   376     void OnInputPending()
   377     {
   378         // no need to post an event if called on the socket thread
   379         if (PR_GetCurrentThread() == gSocketThread)
   380             OnMsgInputPending();
   381         else
   382             PostEvent(MSG_INPUT_PENDING);
   383     }
   384     void OnOutputClosed(nsresult reason)
   385     {
   386         // no need to post an event if called on the socket thread
   387         if (PR_GetCurrentThread() == gSocketThread)
   388             OnMsgOutputClosed(reason); // XXX need to not be inside lock!
   389         else
   390             PostEvent(MSG_OUTPUT_CLOSED, reason);
   391     }
   392     void OnOutputPending()
   393     {
   394         // no need to post an event if called on the socket thread
   395         if (PR_GetCurrentThread() == gSocketThread)
   396             OnMsgOutputPending();
   397         else
   398             PostEvent(MSG_OUTPUT_PENDING);
   399     }
   401 #ifdef ENABLE_SOCKET_TRACING
   402     void TraceInBuf(const char *buf, int32_t n);
   403     void TraceOutBuf(const char *buf, int32_t n);
   404 #endif
   406     // Reads prefs to get default keepalive config.
   407     nsresult EnsureKeepaliveValsAreInitialized();
   409     // Groups calls to fd.SetKeepaliveEnabled and fd.SetKeepaliveVals.
   410     nsresult SetKeepaliveEnabledInternal(bool aEnable);
   412     // True if keepalive has been enabled by the socket owner. Note: Keepalive
   413     // must also be enabled globally for it to be enabled in TCP.
   414     bool mKeepaliveEnabled;
   416     // Keepalive config (support varies by platform).
   417     int32_t mKeepaliveIdleTimeS;
   418     int32_t mKeepaliveRetryIntervalS;
   419     int32_t mKeepaliveProbeCount;
   420 };
   422 #endif // !nsSocketTransport_h__

mercurial