diff options
Diffstat (limited to 'netwerk/protocol/http/TLSTransportLayer.cpp')
-rw-r--r-- | netwerk/protocol/http/TLSTransportLayer.cpp | 805 |
1 files changed, 805 insertions, 0 deletions
diff --git a/netwerk/protocol/http/TLSTransportLayer.cpp b/netwerk/protocol/http/TLSTransportLayer.cpp new file mode 100644 index 0000000000..67177182c9 --- /dev/null +++ b/netwerk/protocol/http/TLSTransportLayer.cpp @@ -0,0 +1,805 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=4 sw=2 et cindent: */ +/* 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/. */ + +// HttpLog.h should generally be included first +#include "HttpLog.h" + +#include "Http2StreamTunnel.h" +#include "TLSTransportLayer.h" +#include "nsISocketProvider.h" +#include "nsITLSSocketControl.h" +#include "nsQueryObject.h" +#include "nsSocketProviderService.h" +#include "nsSocketTransport2.h" + +namespace mozilla::net { + +//----------------------------------------------------------------------------- +// TLSTransportLayerInputStream impl +//----------------------------------------------------------------------------- + +NS_IMPL_QUERY_INTERFACE(TLSTransportLayer::InputStreamWrapper, nsIInputStream, + nsIAsyncInputStream) + +NS_IMETHODIMP_(MozExternalRefCountType) +TLSTransportLayer::InputStreamWrapper::AddRef() { return mTransport->AddRef(); } + +NS_IMETHODIMP_(MozExternalRefCountType) +TLSTransportLayer::InputStreamWrapper::Release() { + return mTransport->Release(); +} + +TLSTransportLayer::InputStreamWrapper::InputStreamWrapper( + nsIAsyncInputStream* aInputStream, TLSTransportLayer* aTransport) + : mSocketIn(aInputStream), mTransport(aTransport) {} + +NS_IMETHODIMP +TLSTransportLayer::InputStreamWrapper::Close() { + LOG(("TLSTransportLayer::InputStreamWrapper::Close [this=%p]\n", this)); + return mSocketIn->Close(); +} + +NS_IMETHODIMP TLSTransportLayer::InputStreamWrapper::Available( + uint64_t* avail) { + LOG(("TLSTransportLayer::InputStreamWrapper::Available [this=%p]\n", this)); + return mSocketIn->Available(avail); +} + +nsresult TLSTransportLayer::InputStreamWrapper::ReadDirectly( + char* buf, uint32_t count, uint32_t* countRead) { + LOG(("TLSTransportLayer::InputStreamWrapper::ReadDirectly [this=%p]\n", + this)); + return mSocketIn->Read(buf, count, countRead); +} + +NS_IMETHODIMP +TLSTransportLayer::InputStreamWrapper::Read(char* buf, uint32_t count, + uint32_t* countRead) { + LOG(("TLSTransportLayer::InputStreamWrapper::Read [this=%p]\n", this)); + + *countRead = 0; + + if (NS_FAILED(mStatus)) { + return (mStatus == NS_BASE_STREAM_CLOSED) ? NS_OK : mStatus; + } + + int32_t bytesRead = PR_Read(mTransport->mFD, buf, count); + if (bytesRead > 0) { + *countRead = bytesRead; + } else if (bytesRead < 0) { + PRErrorCode code = PR_GetError(); + if (code == PR_WOULD_BLOCK_ERROR) { + LOG(( + "TLSTransportLayer::InputStreamWrapper::Read %p PR_Read would block ", + this)); + return NS_BASE_STREAM_WOULD_BLOCK; + } + // If reading from the socket succeeded (NS_SUCCEEDED(mStatus)), + // but the nss layer encountered an error remember the error. + if (NS_SUCCEEDED(mStatus)) { + mStatus = ErrorAccordingToNSPR(code); + LOG(("TLSTransportLayer::InputStreamWrapper::Read %p nss error %" PRIx32 + ".\n", + this, static_cast<uint32_t>(mStatus))); + } + } + + if (NS_SUCCEEDED(mStatus) && !bytesRead) { + LOG( + ("TLSTransportLayer::InputStreamWrapper::Read %p " + "Second layer of TLS stripping results in STREAM_CLOSED\n", + this)); + mStatus = NS_BASE_STREAM_CLOSED; + } + + LOG(("TLSTransportLayer::InputStreamWrapper::Read %p rv=%" PRIx32 + " didread=%d " + "2 layers of ssl stripped to plaintext\n", + this, static_cast<uint32_t>(mStatus), bytesRead)); + return mStatus; +} + +NS_IMETHODIMP +TLSTransportLayer::InputStreamWrapper::ReadSegments(nsWriteSegmentFun writer, + void* closure, + uint32_t count, + uint32_t* countRead) { + LOG(("TLSTransportLayer::InputStreamWrapper::ReadSegments [this=%p]\n", + this)); + return mSocketIn->ReadSegments(writer, closure, count, countRead); +} + +NS_IMETHODIMP +TLSTransportLayer::InputStreamWrapper::IsNonBlocking(bool* nonblocking) { + return mSocketIn->IsNonBlocking(nonblocking); +} + +NS_IMETHODIMP +TLSTransportLayer::InputStreamWrapper::CloseWithStatus(nsresult reason) { + LOG( + ("TLSTransportLayer::InputStreamWrapper::CloseWithStatus [this=%p " + "reason=%" PRIx32 "]\n", + this, static_cast<uint32_t>(reason))); + return mSocketIn->CloseWithStatus(reason); +} + +NS_IMETHODIMP +TLSTransportLayer::InputStreamWrapper::AsyncWait( + nsIInputStreamCallback* callback, uint32_t flags, uint32_t amount, + nsIEventTarget* target) { + LOG( + ("TLSTransportLayer::InputStreamWrapper::AsyncWait [this=%p, " + "callback=%p]\n", + this, callback)); + mTransport->mInputCallback = callback; + // Don't bother to call PR_POLL when |callback| is NULL. We call |AsyncWait| + // directly to null out the underlying callback. + if (!callback) { + return mSocketIn->AsyncWait(nullptr, 0, 0, nullptr); + } + + PRPollDesc pd; + pd.fd = mTransport->mFD; + pd.in_flags = PR_POLL_READ | PR_POLL_EXCEPT; + // Only run PR_Poll on the socket thread. Also, make sure this lives at least + // as long as that operation. + auto DoPoll = [self = RefPtr{this}, pd(pd)]() mutable { + int32_t rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + LOG(("TLSTransportLayer::InputStreamWrapper::AsyncWait rv=%d", rv)); + }; + if (OnSocketThread()) { + DoPoll(); + } else { + gSocketTransportService->Dispatch(NS_NewRunnableFunction( + "TLSTransportLayer::InputStreamWrapper::AsyncWait", DoPoll)); + } + return NS_OK; +} + +//----------------------------------------------------------------------------- +// TLSTransportLayerOutputStream impl +//----------------------------------------------------------------------------- + +NS_IMPL_QUERY_INTERFACE(TLSTransportLayer::OutputStreamWrapper, nsIOutputStream, + nsIAsyncOutputStream) + +NS_IMETHODIMP_(MozExternalRefCountType) +TLSTransportLayer::OutputStreamWrapper::AddRef() { + return mTransport->AddRef(); +} + +NS_IMETHODIMP_(MozExternalRefCountType) +TLSTransportLayer::OutputStreamWrapper::Release() { + return mTransport->Release(); +} + +TLSTransportLayer::OutputStreamWrapper::OutputStreamWrapper( + nsIAsyncOutputStream* aOutputStream, TLSTransportLayer* aTransport) + : mSocketOut(aOutputStream), mTransport(aTransport) {} + +NS_IMETHODIMP +TLSTransportLayer::OutputStreamWrapper::Close() { + LOG(("TLSTransportLayer::OutputStreamWrapper::Close [this=%p]\n", this)); + return mSocketOut->Close(); +} + +NS_IMETHODIMP +TLSTransportLayer::OutputStreamWrapper::Flush() { + LOG(("TLSTransportLayerOutputStream::Flush [this=%p]\n", this)); + return mSocketOut->Flush(); +} + +nsresult TLSTransportLayer::OutputStreamWrapper::WriteDirectly( + const char* buf, uint32_t count, uint32_t* countWritten) { + LOG( + ("TLSTransportLayer::OutputStreamWrapper::WriteDirectly [this=%p " + "count=%u]\n", + this, count)); + return mSocketOut->Write(buf, count, countWritten); +} + +NS_IMETHODIMP +TLSTransportLayer::OutputStreamWrapper::Write(const char* buf, uint32_t count, + uint32_t* countWritten) { + LOG(("TLSTransportLayer::OutputStreamWrapper::Write [this=%p count=%u]\n", + this, count)); + + *countWritten = 0; + + if (NS_FAILED(mStatus)) { + return (mStatus == NS_BASE_STREAM_CLOSED) ? NS_OK : mStatus; + } + + int32_t written = PR_Write(mTransport->mFD, buf, count); + LOG( + ("TLSTransportLayer::OutputStreamWrapper::Write %p PRWrite(%d) = %d " + "%d\n", + this, count, written, PR_GetError() == PR_WOULD_BLOCK_ERROR)); + + if (written > 0) { + *countWritten = written; + } else if (written < 0) { + PRErrorCode code = PR_GetError(); + if (code == PR_WOULD_BLOCK_ERROR) { + LOG( + ("TLSTransportLayer::OutputStreamWrapper::Write %p PRWrite would " + "block ", + this)); + return NS_BASE_STREAM_WOULD_BLOCK; + } + + // Writing to the socket succeeded, but failed in nss layer. + if (NS_SUCCEEDED(mStatus)) { + mStatus = ErrorAccordingToNSPR(code); + } + } + + return mStatus; +} + +NS_IMETHODIMP +TLSTransportLayer::OutputStreamWrapper::WriteSegments(nsReadSegmentFun reader, + void* closure, + uint32_t count, + uint32_t* countRead) { + return mSocketOut->WriteSegments(reader, closure, count, countRead); +} + +// static +nsresult TLSTransportLayer::OutputStreamWrapper::WriteFromSegments( + nsIInputStream* input, void* closure, const char* fromSegment, + uint32_t offset, uint32_t count, uint32_t* countRead) { + OutputStreamWrapper* self = (OutputStreamWrapper*)closure; + return self->Write(fromSegment, count, countRead); +} + +NS_IMETHODIMP +TLSTransportLayer::OutputStreamWrapper::WriteFrom(nsIInputStream* stream, + uint32_t count, + uint32_t* countRead) { + return stream->ReadSegments(WriteFromSegments, this, count, countRead); +} + +NS_IMETHODIMP +TLSTransportLayer::OutputStreamWrapper::IsNonBlocking(bool* nonblocking) { + return mSocketOut->IsNonBlocking(nonblocking); +} + +NS_IMETHODIMP +TLSTransportLayer::OutputStreamWrapper::CloseWithStatus(nsresult reason) { + LOG(("OutputStreamWrapper::CloseWithStatus [this=%p reason=%" PRIx32 "]\n", + this, static_cast<uint32_t>(reason))); + return mSocketOut->CloseWithStatus(reason); +} + +NS_IMETHODIMP +TLSTransportLayer::OutputStreamWrapper::AsyncWait( + nsIOutputStreamCallback* callback, uint32_t flags, uint32_t amount, + nsIEventTarget* target) { + LOG( + ("TLSTransportLayer::OutputStreamWrapper::AsyncWait [this=%p, " + "mOutputCallback=%p " + "callback=%p]\n", + this, mTransport->mOutputCallback.get(), callback)); + mTransport->mOutputCallback = callback; + // Don't bother to call PR_POLL when |callback| is NULL. We call |AsyncWait| + // directly to null out the underlying callback. + if (!callback) { + return mSocketOut->AsyncWait(nullptr, 0, 0, nullptr); + } + + PRPollDesc pd; + pd.fd = mTransport->mFD; + pd.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT; + int32_t rv = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); + LOG(("TLSTransportLayer::OutputStreamWrapper::AsyncWait rv=%d", rv)); + return NS_OK; +} + +//----------------------------------------------------------------------------- +// TLSTransportLayer impl +//----------------------------------------------------------------------------- + +static PRDescIdentity sTLSTransportLayerIdentity; +static PRIOMethods sTLSTransportLayerMethods; +static PRIOMethods* sTLSTransportLayerMethodsPtr = nullptr; + +NS_IMPL_ADDREF(TLSTransportLayer) +NS_IMPL_RELEASE(TLSTransportLayer) +NS_INTERFACE_MAP_BEGIN(TLSTransportLayer) + NS_INTERFACE_MAP_ENTRY(nsISocketTransport) + NS_INTERFACE_MAP_ENTRY(nsITransport) + NS_INTERFACE_MAP_ENTRY(nsIInputStreamCallback) + NS_INTERFACE_MAP_ENTRY(nsIOutputStreamCallback) + NS_INTERFACE_MAP_ENTRY_CONCRETE(TLSTransportLayer) +NS_INTERFACE_MAP_END + +TLSTransportLayer::TLSTransportLayer(nsISocketTransport* aTransport, + nsIAsyncInputStream* aInputStream, + nsIAsyncOutputStream* aOutputStream, + nsIInputStreamCallback* aOwner) + : mSocketTransport(aTransport), + mSocketInWrapper(aInputStream, this), + mSocketOutWrapper(aOutputStream, this), + mOwner(aOwner) { + MOZ_ASSERT(OnSocketThread(), "not on socket thread"); + LOG(("TLSTransportLayer ctor this=[%p]", this)); +} + +TLSTransportLayer::~TLSTransportLayer() { + MOZ_ASSERT(OnSocketThread(), "not on socket thread"); + LOG(("TLSTransportLayer dtor this=[%p]", this)); + if (mFD) { + PR_Close(mFD); + mFD = nullptr; + } + mTLSSocketControl = nullptr; +} + +bool TLSTransportLayer::Init(const char* aTLSHost, int32_t aTLSPort) { + LOG(("TLSTransportLayer::Init this=[%p]", this)); + nsCOMPtr<nsISocketProvider> provider; + nsCOMPtr<nsISocketProviderService> spserv = + nsSocketProviderService::GetOrCreate(); + if (!spserv) { + return false; + } + + spserv->GetSocketProvider("ssl", getter_AddRefs(provider)); + if (!provider) { + return false; + } + + // Install an NSPR layer to handle getpeername() with a failure. This is kind + // of silly, but the default one used by the pipe asserts when called and the + // nss code calls it to see if we are connected to a real socket or not. + if (!sTLSTransportLayerMethodsPtr) { + // one time initialization + sTLSTransportLayerIdentity = PR_GetUniqueIdentity("TLSTransportLayer"); + sTLSTransportLayerMethods = *PR_GetDefaultIOMethods(); + sTLSTransportLayerMethods.getpeername = GetPeerName; + sTLSTransportLayerMethods.getsocketoption = GetSocketOption; + sTLSTransportLayerMethods.setsocketoption = SetSocketOption; + sTLSTransportLayerMethods.read = Read; + sTLSTransportLayerMethods.write = Write; + sTLSTransportLayerMethods.send = Send; + sTLSTransportLayerMethods.recv = Recv; + sTLSTransportLayerMethods.close = Close; + sTLSTransportLayerMethods.poll = Poll; + sTLSTransportLayerMethodsPtr = &sTLSTransportLayerMethods; + } + + mFD = PR_CreateIOLayerStub(sTLSTransportLayerIdentity, + &sTLSTransportLayerMethods); + if (!mFD) { + return false; + } + + mFD->secret = reinterpret_cast<PRFilePrivate*>(this); + + return NS_SUCCEEDED(provider->AddToSocket( + PR_AF_INET, aTLSHost, aTLSPort, nullptr, OriginAttributes(), 0, 0, mFD, + getter_AddRefs(mTLSSocketControl))); +} + +NS_IMETHODIMP +TLSTransportLayer::OnInputStreamReady(nsIAsyncInputStream* in) { + nsCOMPtr<nsIInputStreamCallback> callback = std::move(mInputCallback); + if (callback) { + return callback->OnInputStreamReady(&mSocketInWrapper); + } + return NS_OK; +} + +NS_IMETHODIMP +TLSTransportLayer::OnOutputStreamReady(nsIAsyncOutputStream* out) { + nsCOMPtr<nsIOutputStreamCallback> callback = std::move(mOutputCallback); + nsresult rv = NS_OK; + if (callback) { + rv = callback->OnOutputStreamReady(&mSocketOutWrapper); + + RefPtr<OutputStreamTunnel> tunnel = do_QueryObject(out); + if (tunnel) { + tunnel->MaybeSetRequestDone(callback); + } + } + return rv; +} + +NS_IMETHODIMP +TLSTransportLayer::SetKeepaliveEnabled(bool aKeepaliveEnabled) { + if (!mSocketTransport) { + return NS_ERROR_FAILURE; + } + return mSocketTransport->SetKeepaliveEnabled(aKeepaliveEnabled); +} + +NS_IMETHODIMP +TLSTransportLayer::SetKeepaliveVals(int32_t keepaliveIdleTime, + int32_t keepaliveRetryInterval) { + if (!mSocketTransport) { + return NS_ERROR_FAILURE; + } + return mSocketTransport->SetKeepaliveVals(keepaliveIdleTime, + keepaliveRetryInterval); +} + +NS_IMETHODIMP +TLSTransportLayer::GetSecurityCallbacks( + nsIInterfaceRequestor** aSecurityCallbacks) { + if (!mSocketTransport) { + return NS_ERROR_FAILURE; + } + return mSocketTransport->GetSecurityCallbacks(aSecurityCallbacks); +} + +NS_IMETHODIMP +TLSTransportLayer::SetSecurityCallbacks( + nsIInterfaceRequestor* aSecurityCallbacks) { + if (!mSocketTransport) { + return NS_ERROR_FAILURE; + } + + return mSocketTransport->SetSecurityCallbacks(aSecurityCallbacks); +} + +NS_IMETHODIMP +TLSTransportLayer::OpenInputStream(uint32_t aFlags, uint32_t aSegmentSize, + uint32_t aSegmentCount, + nsIInputStream** _retval) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +TLSTransportLayer::OpenOutputStream(uint32_t aFlags, uint32_t aSegmentSize, + uint32_t aSegmentCount, + nsIOutputStream** _retval) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +TLSTransportLayer::Close(nsresult aReason) { + LOG(("TLSTransportLayer::Close [this=%p reason=%" PRIx32 "]\n", this, + static_cast<uint32_t>(aReason))); + + mInputCallback = nullptr; + mOutputCallback = nullptr; + if (mSocketTransport) { + mSocketTransport->Close(aReason); + mSocketTransport = nullptr; + } + mSocketInWrapper.AsyncWait(nullptr, 0, 0, nullptr); + mSocketOutWrapper.AsyncWait(nullptr, 0, 0, nullptr); + + if (mOwner) { + RefPtr<TLSTransportLayer> self = this; + Unused << NS_DispatchToCurrentThread(NS_NewRunnableFunction( + "TLSTransportLayer::Close", [self{std::move(self)}]() { + nsCOMPtr<nsIInputStreamCallback> inputCallback = + std::move(self->mOwner); + if (inputCallback) { + // This is hack. We need to make + // nsHttpConnection::OnInputStreamReady be called, so + // nsHttpConnection::CloseTransaction can be called to release the + // transaction. + Unused << inputCallback->OnInputStreamReady( + &self->mSocketInWrapper); + } + })); + } + + return NS_OK; +} + +NS_IMETHODIMP +TLSTransportLayer::SetEventSink(nsITransportEventSink* aSink, + nsIEventTarget* aEventTarget) { + if (!mSocketTransport) { + return NS_ERROR_FAILURE; + } + return mSocketTransport->SetEventSink(aSink, aEventTarget); +} + +NS_IMETHODIMP +TLSTransportLayer::Bind(NetAddr* aLocalAddr) { + if (!mSocketTransport) { + return NS_ERROR_FAILURE; + } + return mSocketTransport->Bind(aLocalAddr); +} + +NS_IMETHODIMP +TLSTransportLayer::GetEchConfigUsed(bool* aEchConfigUsed) { + if (!mSocketTransport) { + return NS_ERROR_FAILURE; + } + return mSocketTransport->GetEchConfigUsed(aEchConfigUsed); +} + +NS_IMETHODIMP +TLSTransportLayer::SetEchConfig(const nsACString& aEchConfig) { + if (!mSocketTransport) { + return NS_ERROR_FAILURE; + } + return mSocketTransport->SetEchConfig(aEchConfig); +} + +NS_IMETHODIMP +TLSTransportLayer::ResolvedByTRR(bool* aResolvedByTRR) { + if (!mSocketTransport) { + return NS_ERROR_FAILURE; + } + return mSocketTransport->ResolvedByTRR(aResolvedByTRR); +} + +#define FWD_TS_PTR(fx, ts) \ + NS_IMETHODIMP \ + TLSTransportLayer::fx(ts* arg) { \ + if (!mSocketTransport) return NS_ERROR_FAILURE; \ + return mSocketTransport->fx(arg); \ + } + +#define FWD_TS_ADDREF(fx, ts) \ + NS_IMETHODIMP \ + TLSTransportLayer::fx(ts** arg) { \ + if (!mSocketTransport) return NS_ERROR_FAILURE; \ + return mSocketTransport->fx(arg); \ + } + +#define FWD_TS(fx, ts) \ + NS_IMETHODIMP \ + TLSTransportLayer::fx(ts arg) { \ + if (!mSocketTransport) return NS_ERROR_FAILURE; \ + return mSocketTransport->fx(arg); \ + } + +FWD_TS_PTR(GetKeepaliveEnabled, bool); +FWD_TS_PTR(GetSendBufferSize, uint32_t); +FWD_TS(SetSendBufferSize, uint32_t); +FWD_TS_PTR(GetPort, int32_t); +FWD_TS_PTR(GetPeerAddr, mozilla::net::NetAddr); +FWD_TS_PTR(GetSelfAddr, mozilla::net::NetAddr); +FWD_TS_ADDREF(GetScriptablePeerAddr, nsINetAddr); +FWD_TS_ADDREF(GetScriptableSelfAddr, nsINetAddr); +FWD_TS_PTR(IsAlive, bool); +FWD_TS_PTR(GetConnectionFlags, uint32_t); +FWD_TS(SetConnectionFlags, uint32_t); +FWD_TS(SetIsPrivate, bool); +FWD_TS_PTR(GetTlsFlags, uint32_t); +FWD_TS(SetTlsFlags, uint32_t); +FWD_TS_PTR(GetRecvBufferSize, uint32_t); +FWD_TS(SetRecvBufferSize, uint32_t); +FWD_TS_PTR(GetResetIPFamilyPreference, bool); + +nsresult TLSTransportLayer::GetTlsSocketControl( + nsITLSSocketControl** tlsSocketControl) { + if (!mTLSSocketControl) { + return NS_ERROR_ABORT; + } + + *tlsSocketControl = do_AddRef(mTLSSocketControl).take(); + return NS_OK; +} + +nsresult TLSTransportLayer::GetOriginAttributes( + mozilla::OriginAttributes* aOriginAttributes) { + if (!mSocketTransport) { + return NS_ERROR_FAILURE; + } + return mSocketTransport->GetOriginAttributes(aOriginAttributes); +} + +nsresult TLSTransportLayer::SetOriginAttributes( + const mozilla::OriginAttributes& aOriginAttributes) { + if (!mSocketTransport) { + return NS_ERROR_FAILURE; + } + return mSocketTransport->SetOriginAttributes(aOriginAttributes); +} + +NS_IMETHODIMP +TLSTransportLayer::GetScriptableOriginAttributes( + JSContext* aCx, JS::MutableHandle<JS::Value> aOriginAttributes) { + if (!mSocketTransport) { + return NS_ERROR_FAILURE; + } + return mSocketTransport->GetScriptableOriginAttributes(aCx, + aOriginAttributes); +} + +NS_IMETHODIMP +TLSTransportLayer::SetScriptableOriginAttributes( + JSContext* aCx, JS::Handle<JS::Value> aOriginAttributes) { + if (!mSocketTransport) { + return NS_ERROR_FAILURE; + } + return mSocketTransport->SetScriptableOriginAttributes(aCx, + aOriginAttributes); +} + +NS_IMETHODIMP +TLSTransportLayer::GetHost(nsACString& aHost) { + if (!mSocketTransport) { + return NS_ERROR_FAILURE; + } + return mSocketTransport->GetHost(aHost); +} + +NS_IMETHODIMP +TLSTransportLayer::GetTimeout(uint32_t aType, uint32_t* _retval) { + if (!mSocketTransport) { + return NS_ERROR_FAILURE; + } + return mSocketTransport->GetTimeout(aType, _retval); +} + +NS_IMETHODIMP +TLSTransportLayer::SetTimeout(uint32_t aType, uint32_t aValue) { + if (!mSocketTransport) { + return NS_ERROR_FAILURE; + } + return mSocketTransport->SetTimeout(aType, aValue); +} + +NS_IMETHODIMP +TLSTransportLayer::SetReuseAddrPort(bool aReuseAddrPort) { + if (!mSocketTransport) { + return NS_ERROR_FAILURE; + } + return mSocketTransport->SetReuseAddrPort(aReuseAddrPort); +} + +NS_IMETHODIMP +TLSTransportLayer::SetLinger(bool aPolarity, int16_t aTimeout) { + if (!mSocketTransport) { + return NS_ERROR_FAILURE; + } + return mSocketTransport->SetLinger(aPolarity, aTimeout); +} + +NS_IMETHODIMP +TLSTransportLayer::GetQoSBits(uint8_t* aQoSBits) { + if (!mSocketTransport) { + return NS_ERROR_FAILURE; + } + return mSocketTransport->GetQoSBits(aQoSBits); +} + +NS_IMETHODIMP +TLSTransportLayer::SetQoSBits(uint8_t aQoSBits) { + if (!mSocketTransport) { + return NS_ERROR_FAILURE; + } + return mSocketTransport->SetQoSBits(aQoSBits); +} + +NS_IMETHODIMP +TLSTransportLayer::GetRetryDnsIfPossible(bool* aRetry) { + if (!mSocketTransport) { + return NS_ERROR_FAILURE; + } + return mSocketTransport->GetRetryDnsIfPossible(aRetry); +} + +NS_IMETHODIMP +TLSTransportLayer::GetStatus(nsresult* aStatus) { + if (!mSocketTransport) { + return NS_ERROR_FAILURE; + } + return mSocketTransport->GetStatus(aStatus); +} + +int32_t TLSTransportLayer::OutputInternal(const char* aBuf, int32_t aAmount) { + LOG(("TLSTransportLayer::OutputInternal %p %d", this, aAmount)); + + uint32_t outCountWrite = 0; + nsresult rv = mSocketOutWrapper.WriteDirectly(aBuf, aAmount, &outCountWrite); + if (NS_FAILED(rv)) { + if (rv == NS_BASE_STREAM_WOULD_BLOCK) { + PR_SetError(PR_WOULD_BLOCK_ERROR, 0); + } else { + PR_SetError(PR_UNKNOWN_ERROR, 0); + } + return -1; + } + + return outCountWrite; +} + +int32_t TLSTransportLayer::InputInternal(char* aBuf, int32_t aAmount) { + LOG(("TLSTransportLayer::InputInternal aAmount=%d\n", aAmount)); + + uint32_t outCountRead = 0; + nsresult rv = mSocketInWrapper.ReadDirectly(aBuf, aAmount, &outCountRead); + if (NS_FAILED(rv)) { + if (rv == NS_BASE_STREAM_WOULD_BLOCK) { + PR_SetError(PR_WOULD_BLOCK_ERROR, 0); + } else { + PR_SetError(PR_UNKNOWN_ERROR, 0); + } + return -1; + } + return outCountRead; +} + +PRStatus TLSTransportLayer::GetPeerName(PRFileDesc* aFD, PRNetAddr* addr) { + TLSTransportLayer* self = reinterpret_cast<TLSTransportLayer*>(aFD->secret); + NetAddr peeraddr; + if (NS_FAILED(self->Transport()->GetPeerAddr(&peeraddr))) { + return PR_FAILURE; + } + NetAddrToPRNetAddr(&peeraddr, addr); + return PR_SUCCESS; +} + +PRStatus TLSTransportLayer::GetSocketOption(PRFileDesc* aFD, + PRSocketOptionData* aOpt) { + if (aOpt->option == PR_SockOpt_Nonblocking) { + aOpt->value.non_blocking = PR_TRUE; + return PR_SUCCESS; + } + return PR_FAILURE; +} + +PRStatus TLSTransportLayer::SetSocketOption(PRFileDesc* aFD, + const PRSocketOptionData* aOpt) { + return PR_FAILURE; +} + +PRStatus TLSTransportLayer::Close(PRFileDesc* aFD) { return PR_SUCCESS; } + +int32_t TLSTransportLayer::Write(PRFileDesc* aFD, const void* aBuf, + int32_t aAmount) { + TLSTransportLayer* self = reinterpret_cast<TLSTransportLayer*>(aFD->secret); + return self->OutputInternal(static_cast<const char*>(aBuf), aAmount); +} + +int32_t TLSTransportLayer::Send(PRFileDesc* aFD, const void* aBuf, + int32_t aAmount, int, PRIntervalTime) { + return Write(aFD, aBuf, aAmount); +} + +int32_t TLSTransportLayer::Read(PRFileDesc* aFD, void* aBuf, int32_t aAmount) { + TLSTransportLayer* self = reinterpret_cast<TLSTransportLayer*>(aFD->secret); + return self->InputInternal(static_cast<char*>(aBuf), aAmount); +} + +int32_t TLSTransportLayer::Recv(PRFileDesc* aFD, void* aBuf, int32_t aAmount, + int, PRIntervalTime) { + return Read(aFD, aBuf, aAmount); +} + +int16_t TLSTransportLayer::Poll(PRFileDesc* fd, int16_t in_flags, + int16_t* out_flags) { + LOG(("TLSTransportLayer::Poll fd=%p inf_flags=%d\n", fd, (int)in_flags)); + *out_flags = in_flags; + + TLSTransportLayer* self = reinterpret_cast<TLSTransportLayer*>(fd->secret); + if (!self) { + return 0; + } + + if (in_flags & PR_POLL_READ) { + self->mSocketInWrapper.mSocketIn->AsyncWait(self, 0, 0, nullptr); + } else if (in_flags & PR_POLL_WRITE) { + self->mSocketOutWrapper.mSocketOut->AsyncWait(self, 0, 0, nullptr); + } + + return in_flags; +} + +bool TLSTransportLayer::HasDataToRecv() { + MOZ_ASSERT(OnSocketThread(), "not on socket thread"); + if (!mFD) { + return false; + } + int32_t n = 0; + char c; + n = PR_Recv(mFD, &c, 1, PR_MSG_PEEK, 0); + return n > 0; +} + +} // namespace mozilla::net |