Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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);
}
NS_IMETHODIMP TLSTransportLayer::InputStreamWrapper::StreamStatus() {
LOG(("TLSTransportLayer::InputStreamWrapper::StreamStatus [this=%p]\n",
this));
return mSocketIn->StreamStatus();
}
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();
}
NS_IMETHODIMP
TLSTransportLayer::OutputStreamWrapper::StreamStatus() {
LOG(("TLSTransportLayerOutputStream::StreamStatus [this=%p]\n", this));
return mSocketOut->StreamStatus();
}
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;
bool TLSTransportLayer::DispatchRelease() {
if (OnSocketThread()) {
return false;
}
gSocketTransportService->Dispatch(
NewNonOwningRunnableMethod("net::TLSTransportLayer::Release", this,
&TLSTransportLayer::Release),
NS_DISPATCH_NORMAL);
return true;
}
NS_IMPL_ADDREF(TLSTransportLayer)
NS_IMETHODIMP_(MozExternalRefCountType)
TLSTransportLayer::Release() {
nsrefcnt count = mRefCnt - 1;
if (DispatchRelease()) {
// Redispatched to the socket thread.
return count;
}
MOZ_ASSERT(0 != mRefCnt, "dup release");
count = --mRefCnt;
NS_LOG_RELEASE(this, count, "TLSTransportLayer");
if (0 == count) {
mRefCnt = 1;
delete (this);
return 0;
}
return count;
}
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);
}
NS_IMETHODIMP TLSTransportLayer::GetEffectiveTRRMode(
nsIRequest::TRRMode* aEffectiveTRRMode) {
if (!mSocketTransport) {
return NS_ERROR_FAILURE;
}
return mSocketTransport->GetEffectiveTRRMode(aEffectiveTRRMode);
}
NS_IMETHODIMP TLSTransportLayer::GetTrrSkipReason(
nsITRRSkipReason::value* aTrrSkipReason) {
if (!mSocketTransport) {
return NS_ERROR_FAILURE;
}
return mSocketTransport->GetTrrSkipReason(aTrrSkipReason);
}
#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