/* 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 TLSTransportLayer_h__ #define TLSTransportLayer_h__ #include "nsSocketTransportService2.h" #include "nsIInterfaceRequestor.h" #include "nsISocketTransport.h" #include "nsIAsyncInputStream.h" #include "nsIAsyncOutputStream.h" #include "prio.h" namespace mozilla::net { // TLSTransportLayer will provide a secondary TLS layer. It will be added as a // layer between nsHttpConnection and nsSocketTransport. // The mSocketTransport, mSocketIn, and mSocketOut of nsHttpConnection will be // replaced by TLSTransportLayer. // // The input path of reading data from a socket is shown below. // nsHttpConnection::OnSocketReadable // nsHttpConnection::OnWriteSegment // nsHttpConnection::mSocketIn->Read // TLSTransportLayer::InputStreamWrapper::Read // TLSTransportLayer::InputInternal // TLSTransportLayer::InputStreamWrapper::ReadDirectly // nsSocketInputStream::Read // // The output path of writing data to a socket is shown below. // nsHttpConnection::OnSocketWritable // nsHttpConnection::OnReadSegment // TLSTransportLayer::OutputStreamWrapper::Write // TLSTransportLayer::OutputInternal // TLSTransportLayer::OutputStreamWrapper::WriteDirectly // nsSocketOutputStream::Write // 9d6a3bc6-1f90-41d0-9b02-33ccd169052b #define NS_TLSTRANSPORTLAYER_IID \ { \ 0x9d6a3bc6, 0x1f90, 0x41d0, { \ 0x9b, 0x02, 0x33, 0xcc, 0xd1, 0x69, 0x05, 0x2b \ } \ } class TLSTransportLayer final : public nsISocketTransport, public nsIInputStreamCallback, public nsIOutputStreamCallback { public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_TLSTRANSPORTLAYER_IID) NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSITRANSPORT NS_DECL_NSISOCKETTRANSPORT NS_DECL_NSIINPUTSTREAMCALLBACK NS_DECL_NSIOUTPUTSTREAMCALLBACK explicit TLSTransportLayer(nsISocketTransport* aTransport, nsIAsyncInputStream* aInputStream, nsIAsyncOutputStream* aOutputStream, nsIInputStreamCallback* aOwner); bool Init(const char* aTLSHost, int32_t aTLSPort); already_AddRefed GetInputStreamWrapper() { nsCOMPtr stream = &mSocketInWrapper; return stream.forget(); } already_AddRefed GetOutputStreamWrapper() { nsCOMPtr stream = &mSocketOutWrapper; return stream.forget(); } bool HasDataToRecv(); void ReleaseOwner() { mOwner = nullptr; } private: class InputStreamWrapper : public nsIAsyncInputStream { public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIINPUTSTREAM NS_DECL_NSIASYNCINPUTSTREAM explicit InputStreamWrapper(nsIAsyncInputStream* aInputStream, TLSTransportLayer* aTransport); nsresult ReadDirectly(char* buf, uint32_t count, uint32_t* countRead); nsresult Status() { return mStatus; } void SetStatus(nsresult aStatus) { mStatus = aStatus; } private: friend class TLSTransportLayer; virtual ~InputStreamWrapper() = default; nsresult ReturnDataFromBuffer(char* buf, uint32_t count, uint32_t* countRead); nsCOMPtr mSocketIn; nsresult mStatus{NS_OK}; // The lifetime of InputStreamWrapper and OutputStreamWrapper are bound to // TLSTransportLayer, so using |mTransport| as a raw pointer should be safe. TLSTransportLayer* MOZ_OWNING_REF mTransport; }; class OutputStreamWrapper : public nsIAsyncOutputStream { public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIOUTPUTSTREAM NS_DECL_NSIASYNCOUTPUTSTREAM explicit OutputStreamWrapper(nsIAsyncOutputStream* aOutputStream, TLSTransportLayer* aTransport); nsresult WriteDirectly(const char* buf, uint32_t count, uint32_t* countWritten); nsresult Status() { return mStatus; } void SetStatus(nsresult aStatus) { mStatus = aStatus; } private: friend class TLSTransportLayer; virtual ~OutputStreamWrapper() = default; static nsresult WriteFromSegments(nsIInputStream*, void*, const char*, uint32_t offset, uint32_t count, uint32_t* countRead); nsCOMPtr mSocketOut; nsresult mStatus{NS_OK}; TLSTransportLayer* MOZ_OWNING_REF mTransport; }; virtual ~TLSTransportLayer(); nsISocketTransport* Transport() { return mSocketTransport; } int32_t OutputInternal(const char* aBuf, int32_t aAmount); int32_t InputInternal(char* aBuf, int32_t aAmount); static PRStatus GetPeerName(PRFileDesc* fd, PRNetAddr* addr); static PRStatus GetSocketOption(PRFileDesc* fd, PRSocketOptionData* aOpt); static PRStatus SetSocketOption(PRFileDesc* fd, const PRSocketOptionData* data); static int32_t Write(PRFileDesc* fd, const void* buf, int32_t amount); static int32_t Read(PRFileDesc* fd, void* buf, int32_t amount); static int32_t Send(PRFileDesc* fd, const void* buf, int32_t amount, int flags, PRIntervalTime timeout); static int32_t Recv(PRFileDesc* fd, void* buf, int32_t amount, int flags, PRIntervalTime timeout); static PRStatus Close(PRFileDesc* fd); static int16_t Poll(PRFileDesc* fd, int16_t in_flags, int16_t* out_flags); nsCOMPtr mSocketTransport; InputStreamWrapper mSocketInWrapper; OutputStreamWrapper mSocketOutWrapper; nsCOMPtr mTLSSocketControl; nsCOMPtr mInputCallback; nsCOMPtr mOutputCallback; PRFileDesc* mFD{nullptr}; nsCOMPtr mOwner; }; NS_DEFINE_STATIC_IID_ACCESSOR(TLSTransportLayer, NS_TLSTRANSPORTLAYER_IID) } // namespace mozilla::net inline nsISupports* ToSupports(mozilla::net::TLSTransportLayer* aTransport) { return static_cast(aTransport); } #endif