123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 |
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #ifndef nsSocketTransport2_h__
- #define nsSocketTransport2_h__
- #ifdef DEBUG_darinf
- #define ENABLE_SOCKET_TRACING
- #endif
- #include "mozilla/Mutex.h"
- #include "nsSocketTransportService2.h"
- #include "nsString.h"
- #include "nsCOMPtr.h"
- #include "nsIInterfaceRequestor.h"
- #include "nsISocketTransport.h"
- #include "nsIAsyncInputStream.h"
- #include "nsIAsyncOutputStream.h"
- #include "nsIDNSListener.h"
- #include "nsIClassInfo.h"
- #include "mozilla/net/DNS.h"
- #include "nsASocketHandler.h"
- #include "prerror.h"
- #include "nsAutoPtr.h"
- class nsICancelable;
- class nsIDNSRecord;
- class nsIInterfaceRequestor;
- //-----------------------------------------------------------------------------
- // after this short interval, we will return to PR_Poll
- #define NS_SOCKET_CONNECT_TIMEOUT PR_MillisecondsToInterval(20)
- //-----------------------------------------------------------------------------
- namespace mozilla {
- namespace net {
- nsresult
- ErrorAccordingToNSPR(PRErrorCode errorCode);
- class nsSocketTransport;
- class nsSocketInputStream : public nsIAsyncInputStream
- {
- public:
- NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_NSIINPUTSTREAM
- NS_DECL_NSIASYNCINPUTSTREAM
- explicit nsSocketInputStream(nsSocketTransport *);
- virtual ~nsSocketInputStream();
- bool IsReferenced() { return mReaderRefCnt > 0; }
- nsresult Condition() { return mCondition; }
- uint64_t ByteCount() { return mByteCount; }
- // called by the socket transport on the socket thread...
- void OnSocketReady(nsresult condition);
- private:
- nsSocketTransport *mTransport;
- ThreadSafeAutoRefCnt mReaderRefCnt;
- // access to these is protected by mTransport->mLock
- nsresult mCondition;
- nsCOMPtr<nsIInputStreamCallback> mCallback;
- uint32_t mCallbackFlags;
- uint64_t mByteCount;
- };
- //-----------------------------------------------------------------------------
- class nsSocketOutputStream : public nsIAsyncOutputStream
- {
- public:
- NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_NSIOUTPUTSTREAM
- NS_DECL_NSIASYNCOUTPUTSTREAM
- explicit nsSocketOutputStream(nsSocketTransport *);
- virtual ~nsSocketOutputStream();
- bool IsReferenced() { return mWriterRefCnt > 0; }
- nsresult Condition() { return mCondition; }
- uint64_t ByteCount() { return mByteCount; }
- // called by the socket transport on the socket thread...
- void OnSocketReady(nsresult condition);
- private:
- static nsresult WriteFromSegments(nsIInputStream *, void *,
- const char *, uint32_t offset,
- uint32_t count, uint32_t *countRead);
- nsSocketTransport *mTransport;
- ThreadSafeAutoRefCnt mWriterRefCnt;
- // access to these is protected by mTransport->mLock
- nsresult mCondition;
- nsCOMPtr<nsIOutputStreamCallback> mCallback;
- uint32_t mCallbackFlags;
- uint64_t mByteCount;
- };
- //-----------------------------------------------------------------------------
- class nsSocketTransport final : public nsASocketHandler
- , public nsISocketTransport
- , public nsIDNSListener
- , public nsIClassInfo
- , public nsIInterfaceRequestor
- {
- public:
- NS_DECL_THREADSAFE_ISUPPORTS
- NS_DECL_NSITRANSPORT
- NS_DECL_NSISOCKETTRANSPORT
- NS_DECL_NSIDNSLISTENER
- NS_DECL_NSICLASSINFO
- NS_DECL_NSIINTERFACEREQUESTOR
- nsSocketTransport();
- // this method instructs the socket transport to open a socket of the
- // given type(s) to the given host or proxy.
- nsresult Init(const char **socketTypes, uint32_t typeCount,
- const nsACString &host, uint16_t port,
- const nsACString &hostRoute, uint16_t portRoute,
- nsIProxyInfo *proxyInfo);
- // Alternative Init method for when the IP-address of the host
- // has been pre-resolved using a alternative means (e.g. FlyWeb service
- // info).
- nsresult InitPreResolved(const char **socketTypes, uint32_t typeCount,
- const nsACString &host, uint16_t port,
- const nsACString &hostRoute, uint16_t portRoute,
- nsIProxyInfo *proxyInfo,
- const mozilla::net::NetAddr* addr);
- // this method instructs the socket transport to use an already connected
- // socket with the given address.
- nsresult InitWithConnectedSocket(PRFileDesc *socketFD,
- const NetAddr *addr);
- // this method instructs the socket transport to use an already connected
- // socket with the given address, and additionally supplies security info.
- nsresult InitWithConnectedSocket(PRFileDesc* aSocketFD,
- const NetAddr* aAddr,
- nsISupports* aSecInfo);
- // This method instructs the socket transport to open a socket
- // connected to the given Unix domain address. We can only create
- // unlayered, simple, stream sockets.
- nsresult InitWithFilename(const char *filename);
- // nsASocketHandler methods:
- void OnSocketReady(PRFileDesc *, int16_t outFlags) override;
- void OnSocketDetached(PRFileDesc *) override;
- void IsLocal(bool *aIsLocal) override;
- void OnKeepaliveEnabledPrefChange(bool aEnabled) override final;
- // called when a socket event is handled
- void OnSocketEvent(uint32_t type, nsresult status, nsISupports *param);
- uint64_t ByteCountReceived() override { return mInput.ByteCount(); }
- uint64_t ByteCountSent() override { return mOutput.ByteCount(); }
- static void CloseSocket(PRFileDesc *aFd);
- protected:
- virtual ~nsSocketTransport();
- void CleanupTypes();
- private:
- // event types
- enum {
- MSG_ENSURE_CONNECT,
- MSG_DNS_LOOKUP_COMPLETE,
- MSG_RETRY_INIT_SOCKET,
- MSG_TIMEOUT_CHANGED,
- MSG_INPUT_CLOSED,
- MSG_INPUT_PENDING,
- MSG_OUTPUT_CLOSED,
- MSG_OUTPUT_PENDING
- };
- nsresult PostEvent(uint32_t type, nsresult status = NS_OK, nsISupports *param = nullptr);
- enum {
- STATE_CLOSED,
- STATE_IDLE,
- STATE_RESOLVING,
- STATE_CONNECTING,
- STATE_TRANSFERRING
- };
- // Safer way to get and automatically release PRFileDesc objects.
- class MOZ_STACK_CLASS PRFileDescAutoLock
- {
- public:
- explicit PRFileDescAutoLock(nsSocketTransport *aSocketTransport,
- nsresult *aConditionWhileLocked = nullptr)
- : mSocketTransport(aSocketTransport)
- , mFd(nullptr)
- {
- MOZ_ASSERT(aSocketTransport);
- MutexAutoLock lock(mSocketTransport->mLock);
- if (aConditionWhileLocked) {
- *aConditionWhileLocked = mSocketTransport->mCondition;
- if (NS_FAILED(mSocketTransport->mCondition)) {
- return;
- }
- }
- mFd = mSocketTransport->GetFD_Locked();
- }
- ~PRFileDescAutoLock() {
- MutexAutoLock lock(mSocketTransport->mLock);
- if (mFd) {
- mSocketTransport->ReleaseFD_Locked(mFd);
- }
- }
- bool IsInitialized() {
- return mFd;
- }
- operator PRFileDesc*() {
- return mFd;
- }
- nsresult SetKeepaliveEnabled(bool aEnable);
- nsresult SetKeepaliveVals(bool aEnabled, int aIdleTime,
- int aRetryInterval, int aProbeCount);
- private:
- operator PRFileDescAutoLock*() { return nullptr; }
- // Weak ptr to nsSocketTransport since this is a stack class only.
- nsSocketTransport *mSocketTransport;
- PRFileDesc *mFd;
- };
- friend class PRFileDescAutoLock;
- class LockedPRFileDesc
- {
- public:
- explicit LockedPRFileDesc(nsSocketTransport *aSocketTransport)
- : mSocketTransport(aSocketTransport)
- , mFd(nullptr)
- {
- MOZ_ASSERT(aSocketTransport);
- }
- ~LockedPRFileDesc() {}
- bool IsInitialized() {
- return mFd;
- }
- LockedPRFileDesc& operator=(PRFileDesc *aFd) {
- mSocketTransport->mLock.AssertCurrentThreadOwns();
- mFd = aFd;
- return *this;
- }
- operator PRFileDesc*() {
- if (mSocketTransport->mAttached) {
- mSocketTransport->mLock.AssertCurrentThreadOwns();
- }
- return mFd;
- }
- bool operator==(PRFileDesc *aFd) {
- mSocketTransport->mLock.AssertCurrentThreadOwns();
- return mFd == aFd;
- }
- private:
- operator LockedPRFileDesc*() { return nullptr; }
- // Weak ptr to nsSocketTransport since it owns this class.
- nsSocketTransport *mSocketTransport;
- PRFileDesc *mFd;
- };
- friend class LockedPRFileDesc;
- //-------------------------------------------------------------------------
- // these members are "set" at initialization time and are never modified
- // afterwards. this allows them to be safely accessed from any thread.
- //-------------------------------------------------------------------------
- // socket type info:
- char **mTypes;
- uint32_t mTypeCount;
- nsCString mHost;
- nsCString mProxyHost;
- nsCString mOriginHost;
- uint16_t mPort;
- nsCOMPtr<nsIProxyInfo> mProxyInfo;
- uint16_t mProxyPort;
- uint16_t mOriginPort;
- bool mProxyTransparent;
- bool mProxyTransparentResolvesHost;
- bool mHttpsProxy;
- uint32_t mConnectionFlags;
- // The origin attributes are used to create sockets. The first party domain
- // will eventually be used to isolate OCSP cache and is only non-empty when
- // "privacy.firstparty.isolate" is enabled. Setting this is the only way to
- // carry origin attributes down to NSPR layers which are final consumers.
- // It must be set before the socket transport is built.
- NeckoOriginAttributes mOriginAttributes;
-
- uint16_t SocketPort() { return (!mProxyHost.IsEmpty() && !mProxyTransparent) ? mProxyPort : mPort; }
- const nsCString &SocketHost() { return (!mProxyHost.IsEmpty() && !mProxyTransparent) ? mProxyHost : mHost; }
- Atomic<bool> mInputClosed{true};
- Atomic<bool> mOutputClosed{true};
- //-------------------------------------------------------------------------
- // members accessible only on the socket transport thread:
- // (the exception being initialization/shutdown time)
- //-------------------------------------------------------------------------
- // socket state vars:
- uint32_t mState; // STATE_??? flags
- bool mAttached;
- // The platform-specific network interface id that this socket
- // associated with.
- nsCString mNetworkInterfaceId;
- // this flag is used to determine if the results of a host lookup arrive
- // recursively or not. this flag is not protected by any lock.
- bool mResolving;
- nsCOMPtr<nsICancelable> mDNSRequest;
- nsCOMPtr<nsIDNSRecord> mDNSRecord;
- // mNetAddr/mSelfAddr is valid from GetPeerAddr()/GetSelfAddr() once we have
- // reached STATE_TRANSFERRING. It must not change after that.
- void SetSocketName(PRFileDesc *fd);
- NetAddr mNetAddr;
- NetAddr mSelfAddr; // getsockname()
- Atomic<bool, Relaxed> mNetAddrIsSet;
- Atomic<bool, Relaxed> mSelfAddrIsSet;
- Atomic<bool, Relaxed> mNetAddrPreResolved;
- nsAutoPtr<NetAddr> mBindAddr;
- // socket methods (these can only be called on the socket thread):
- void SendStatus(nsresult status);
- nsresult ResolveHost();
- nsresult BuildSocket(PRFileDesc *&, bool &, bool &);
- nsresult InitiateSocket();
- bool RecoverFromError();
- void OnMsgInputPending()
- {
- if (mState == STATE_TRANSFERRING)
- mPollFlags |= (PR_POLL_READ | PR_POLL_EXCEPT);
- }
- void OnMsgOutputPending()
- {
- if (mState == STATE_TRANSFERRING)
- mPollFlags |= (PR_POLL_WRITE | PR_POLL_EXCEPT);
- }
- void OnMsgInputClosed(nsresult reason);
- void OnMsgOutputClosed(nsresult reason);
- // called when the socket is connected
- void OnSocketConnected();
- //-------------------------------------------------------------------------
- // socket input/output objects. these may be accessed on any thread with
- // the exception of some specific methods (XXX).
- Mutex mLock; // protects members in this section.
- LockedPRFileDesc mFD;
- nsrefcnt mFDref; // mFD is closed when mFDref goes to zero.
- bool mFDconnected; // mFD is available to consumer when TRUE.
- // A delete protector reference to gSocketTransportService held for lifetime
- // of 'this'. Sometimes used interchangably with gSocketTransportService due
- // to scoping.
- RefPtr<nsSocketTransportService> mSocketTransportService;
- nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
- nsCOMPtr<nsITransportEventSink> mEventSink;
- nsCOMPtr<nsISupports> mSecInfo;
- nsSocketInputStream mInput;
- nsSocketOutputStream mOutput;
- friend class nsSocketInputStream;
- friend class nsSocketOutputStream;
- // socket timeouts are not protected by any lock.
- uint16_t mTimeouts[2];
- // QoS setting for socket
- uint8_t mQoSBits;
- //
- // mFD access methods: called with mLock held.
- //
- PRFileDesc *GetFD_Locked();
- void ReleaseFD_Locked(PRFileDesc *fd);
- //
- // stream state changes (called outside mLock):
- //
- void OnInputClosed(nsresult reason)
- {
- // no need to post an event if called on the socket thread
- if (PR_GetCurrentThread() == gSocketThread)
- OnMsgInputClosed(reason);
- else
- PostEvent(MSG_INPUT_CLOSED, reason);
- }
- void OnInputPending()
- {
- // no need to post an event if called on the socket thread
- if (PR_GetCurrentThread() == gSocketThread)
- OnMsgInputPending();
- else
- PostEvent(MSG_INPUT_PENDING);
- }
- void OnOutputClosed(nsresult reason)
- {
- // no need to post an event if called on the socket thread
- if (PR_GetCurrentThread() == gSocketThread)
- OnMsgOutputClosed(reason); // XXX need to not be inside lock!
- else
- PostEvent(MSG_OUTPUT_CLOSED, reason);
- }
- void OnOutputPending()
- {
- // no need to post an event if called on the socket thread
- if (PR_GetCurrentThread() == gSocketThread)
- OnMsgOutputPending();
- else
- PostEvent(MSG_OUTPUT_PENDING);
- }
- #ifdef ENABLE_SOCKET_TRACING
- void TraceInBuf(const char *buf, int32_t n);
- void TraceOutBuf(const char *buf, int32_t n);
- #endif
- // Reads prefs to get default keepalive config.
- nsresult EnsureKeepaliveValsAreInitialized();
- // Groups calls to fd.SetKeepaliveEnabled and fd.SetKeepaliveVals.
- nsresult SetKeepaliveEnabledInternal(bool aEnable);
- // True if keepalive has been enabled by the socket owner. Note: Keepalive
- // must also be enabled globally for it to be enabled in TCP.
- bool mKeepaliveEnabled;
- // Keepalive config (support varies by platform).
- int32_t mKeepaliveIdleTimeS;
- int32_t mKeepaliveRetryIntervalS;
- int32_t mKeepaliveProbeCount;
- Atomic<bool> mDoNotRetryToConnect{false};
- };
- } // namespace net
- } // namespace mozilla
- #endif // !nsSocketTransport_h__
|