summaryrefslogtreecommitdiffstats
path: root/netwerk/protocol/http/TLSTransportLayer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/protocol/http/TLSTransportLayer.cpp')
-rw-r--r--netwerk/protocol/http/TLSTransportLayer.cpp805
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