Bug 1203503 - part 2. replace proxy tunnel with new ipc-based tunnel r+bwc, r+mayhemer

This replaces the tunnel using a new nr_socket implementation.  Proxy detection
code is still done in the peer connction.  However, the result is only used to
detect a proxy.  The result is unused.  Address resolution is done by necko code
in the parent process.  The new socket wraps a WebrtcProxyChannel which uses
necko to handle proxy negotiation.  This has a happy side effect of enabling all
authentication modes that necko already supports for http proxies.

This adds a protocol for Necko to manage, WebrtcProxyChannel.  This new protocol
serves as a pipe for a CONNECT tunnel.  It is only used in WebRtc and not built
in no WebRtc builds.

--HG--
extra : rebase_source : a951841f95eaaa0562886cf76b405b01f1adf70e
extra : intermediate-source : 5c3da21957fc80b07188bc8a405437b858027a22
extra : source : 594a32883463ab051677ba06e22fa6d062b4b4a9
This commit is contained in:
Paul Vitale 2018-06-05 12:10:16 -05:00
Родитель 2966b99504
Коммит 09f4c06235
40 изменённых файлов: 3048 добавлений и 1156 удалений

Просмотреть файл

@ -0,0 +1,155 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
/* 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/. */
#include "WebrtcProxyChannelWrapper.h"
#include "mozilla/net/WebrtcProxyChannelChild.h"
#include "nsIEventTarget.h"
#include "nsNetCID.h"
#include "nsProxyRelease.h"
#include "nr_socket_proxy_config.h"
namespace mozilla {
namespace net {
using std::shared_ptr;
WebrtcProxyChannelWrapper::WebrtcProxyChannelWrapper(
WebrtcProxyChannelCallback* aCallbacks)
: mProxyCallbacks(aCallbacks)
, mWebrtcProxyChannel(nullptr)
, mMainThread(nullptr)
, mSocketThread(nullptr)
{
mMainThread = GetMainThreadEventTarget();
mSocketThread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID);
MOZ_RELEASE_ASSERT(mMainThread, "no main thread");
MOZ_RELEASE_ASSERT(mSocketThread, "no socket thread");
}
WebrtcProxyChannelWrapper::~WebrtcProxyChannelWrapper()
{
MOZ_ASSERT(!mWebrtcProxyChannel, "webrtc proxy channel non-null");
// If we're never opened then we never get an OnClose from our parent process.
// We need to release our callbacks here safely.
NS_ProxyRelease("WebrtcProxyChannelWrapper::CleanUpCallbacks",
mSocketThread,
mProxyCallbacks.forget());
}
void
WebrtcProxyChannelWrapper::AsyncOpen(
const nsCString& aHost,
const int& aPort,
const shared_ptr<NrSocketProxyConfig>& aConfig)
{
if (!NS_IsMainThread()) {
MOZ_ALWAYS_SUCCEEDS(mMainThread->Dispatch(
NewRunnableMethod<const nsCString,
const int,
const shared_ptr<NrSocketProxyConfig>>(
"WebrtcProxyChannelWrapper::AsyncOpen",
this,
&WebrtcProxyChannelWrapper::AsyncOpen,
aHost,
aPort,
aConfig)));
return;
}
MOZ_ASSERT(!mWebrtcProxyChannel, "wrapper already open");
mWebrtcProxyChannel = new WebrtcProxyChannelChild(this);
mWebrtcProxyChannel->AsyncOpen(aHost,
aPort,
aConfig->GetBrowser(),
nsContentUtils::GetSystemPrincipal(),
aConfig->GetAlpn());
}
void
WebrtcProxyChannelWrapper::SendWrite(nsTArray<uint8_t>&& aReadData)
{
if (!NS_IsMainThread()) {
MOZ_ALWAYS_SUCCEEDS(mMainThread->Dispatch(
NewRunnableMethod<nsTArray<uint8_t>&&>(
"WebrtcProxyChannelWrapper::SendWrite",
this,
&WebrtcProxyChannelWrapper::SendWrite,
std::move(aReadData))));
return;
}
MOZ_ASSERT(mWebrtcProxyChannel, "webrtc proxy channel should be non-null");
mWebrtcProxyChannel->SendWrite(aReadData);
}
void
WebrtcProxyChannelWrapper::Close()
{
if (!NS_IsMainThread()) {
MOZ_ALWAYS_SUCCEEDS(mMainThread->Dispatch(
NewRunnableMethod("WebrtcProxyChannelWrapper::Close",
this,
&WebrtcProxyChannelWrapper::Close)));
return;
}
// We're only open if we have a channel. Also Close() should be idempotent.
if (mWebrtcProxyChannel) {
RefPtr<WebrtcProxyChannelChild> child = mWebrtcProxyChannel;
mWebrtcProxyChannel = nullptr;
child->SendClose();
}
}
void
WebrtcProxyChannelWrapper::OnClose(nsresult aReason)
{
MOZ_ASSERT(NS_IsMainThread(), "not on main thread");
MOZ_ASSERT(mProxyCallbacks, "webrtc proxy callbacks should be non-null");
MOZ_ALWAYS_SUCCEEDS(mSocketThread->Dispatch(
NewRunnableMethod<nsresult>("WebrtcProxyChannelWrapper::OnClose",
mProxyCallbacks,
&WebrtcProxyChannelCallback::OnClose,
aReason)));
NS_ProxyRelease("WebrtcProxyChannelWrapper::CleanUpCallbacks",
mSocketThread,
mProxyCallbacks.forget());
}
void
WebrtcProxyChannelWrapper::OnRead(nsTArray<uint8_t>&& aReadData)
{
MOZ_ASSERT(NS_IsMainThread(), "not on main thread");
MOZ_ASSERT(mProxyCallbacks, "webrtc proxy callbacks should be non-null");
MOZ_ALWAYS_SUCCEEDS(mSocketThread->Dispatch(
NewRunnableMethod<nsTArray<uint8_t>&&>(
"WebrtcProxyChannelWrapper::OnRead",
mProxyCallbacks,
&WebrtcProxyChannelCallback::OnRead,
std::move(aReadData))));
}
void
WebrtcProxyChannelWrapper::OnConnected()
{
MOZ_ASSERT(NS_IsMainThread(), "not on main thread");
MOZ_ASSERT(mProxyCallbacks, "webrtc proxy callbacks should be non-null");
MOZ_ALWAYS_SUCCEEDS(mSocketThread->Dispatch(
NewRunnableMethod("WebrtcProxyChannelWrapper::OnConnected",
mProxyCallbacks,
&WebrtcProxyChannelCallback::OnConnected)));
}
} // namespace net
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,69 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
/* 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 webrtc_proxy_channel_wrapper__
#define webrtc_proxy_channel_wrapper__
#include <memory>
#include "nsCOMPtr.h"
#include "nsTArray.h"
#include "mozilla/net/WebrtcProxyChannelCallback.h"
class nsIEventTarget;
namespace mozilla {
class NrSocketProxyConfig;
namespace net {
class WebrtcProxyChannelChild;
/**
* WebrtcProxyChannelWrapper is a protector class for mtransport and IPDL.
* mtransport and IPDL cannot include headers from each other due to conflicting
* typedefs. Also it helps users by dispatching calls to the appropriate thread
* based on mtransport's and IPDL's threading requirements.
*
* WebrtcProxyChannelWrapper is only used in the child process.
* WebrtcProxyChannelWrapper does not dispatch for the parent process.
* WebrtcProxyChannelCallback calls are dispatched to the STS thread.
* IPDL calls are dispatched to the main thread.
*/
class WebrtcProxyChannelWrapper : public WebrtcProxyChannelCallback
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebrtcProxyChannelWrapper, override)
explicit WebrtcProxyChannelWrapper(WebrtcProxyChannelCallback* aCallbacks);
virtual void AsyncOpen(const nsCString& aHost,
const int& aPort,
const std::shared_ptr<NrSocketProxyConfig>& aConfig);
virtual void SendWrite(nsTArray<uint8_t>&& aReadData);
virtual void Close();
// WebrtcProxyChannelCallback
virtual void OnClose(nsresult aReason) override;
virtual void OnConnected() override;
virtual void OnRead(nsTArray<uint8_t>&& aReadData) override;
protected:
RefPtr<WebrtcProxyChannelCallback> mProxyCallbacks;
RefPtr<WebrtcProxyChannelChild> mWebrtcProxyChannel;
nsCOMPtr<nsIEventTarget> mMainThread;
nsCOMPtr<nsIEventTarget> mSocketThread;
virtual ~WebrtcProxyChannelWrapper();
};
} // namespace net
} // namespace mozilla
#endif // webrtc_proxy_channel_wrapper__

Просмотреть файл

@ -10,6 +10,7 @@ EXPORTS.mtransport += [
'../dtlsidentity.h',
'../m_cpp_utils.h',
'../mediapacket.h',
'../nr_socket_proxy_config.h',
'../nricectx.h',
'../nricemediastream.h',
'../nriceresolverfake.h',
@ -36,7 +37,8 @@ include('/tools/fuzzing/libfuzzer-config.mozbuild')
# These files cannot be built in unified mode because of the redefinition of
# getLogModule, UNIMPLEMENTED, nr_socket_long_term_violation_time,
# nr_socket_short_term_violation_time.
# nr_socket_short_term_violation_time, nrappkit/IPDL typedef conflicts in
# PBrowserOrId and WebrtcProxyChannelChild.
SOURCES += mtransport_cppsrcs
FINAL_LIBRARY = 'xul'

Просмотреть файл

@ -7,6 +7,8 @@
mtransport_lcppsrcs = [
'dtlsidentity.cpp',
'mediapacket.cpp',
'nr_socket_proxy.cpp',
'nr_socket_proxy_config.cpp',
'nr_socket_prsock.cpp',
'nr_timer.cpp',
'nricectx.cpp',
@ -27,6 +29,7 @@ mtransport_lcppsrcs = [
'transportlayerlog.cpp',
'transportlayerloopback.cpp',
'transportlayersrtp.cpp',
'WebrtcProxyChannelWrapper.cpp',
]
mtransport_cppsrcs = [

Просмотреть файл

@ -0,0 +1,36 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
/* 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/. */
include protocol PNecko;
include NeckoChannelParams;
namespace mozilla {
namespace net {
async protocol PWebrtcProxyChannel
{
manager PNecko;
parent:
async AsyncOpen(nsCString aHost,
int32_t aPort,
OptionalLoadInfoArgs aLoadInfoArgs,
nsCString aAlpn);
async Write(uint8_t[] aWriteData);
async Close();
child:
async OnClose(nsresult aReason);
async OnConnected();
async OnRead(uint8_t[] aReadData);
async __delete__();
};
} // namespace net
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,549 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
/* 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/. */
#include "WebrtcProxyChannel.h"
#include "nsHttpChannel.h"
#include "nsIChannel.h"
#include "nsIClassOfService.h"
#include "nsIContentPolicy.h"
#include "nsIEventTarget.h"
#include "nsIIOService.h"
#include "nsILoadInfo.h"
#include "nsIProtocolProxyService.h"
#include "nsIURIMutator.h"
#include "nsProxyRelease.h"
#include "nsString.h"
#include "WebrtcProxyChannelCallback.h"
#include "WebrtcProxyLog.h"
namespace mozilla {
namespace net {
class WebrtcProxyData
{
public:
explicit WebrtcProxyData(nsTArray<uint8_t>&& aData)
: mData(aData)
{
MOZ_COUNT_CTOR(WebrtcProxyData);
}
~WebrtcProxyData()
{
MOZ_COUNT_DTOR(WebrtcProxyData);
}
const nsTArray<uint8_t>& GetData() const
{
return mData;
}
private:
nsTArray<uint8_t> mData;
};
NS_IMPL_ISUPPORTS(WebrtcProxyChannel,
nsIAuthPromptProvider,
nsIHttpUpgradeListener,
nsIInputStreamCallback,
nsIInterfaceRequestor,
nsIOutputStreamCallback,
nsIRequestObserver,
nsIStreamListener)
WebrtcProxyChannel::WebrtcProxyChannel(nsIAuthPromptProvider* aAuthProvider,
WebrtcProxyChannelCallback* aCallbacks)
: mProxyCallbacks(aCallbacks)
, mClosed(false)
, mOpened(false)
, mWriteOffset(0)
, mAuthProvider(aAuthProvider)
, mTransport(nullptr)
, mSocketIn(nullptr)
, mSocketOut(nullptr)
{
LOG(("WebrtcProxyChannel::WebrtcProxyChannel %p\n", this));
mMainThread = GetMainThreadEventTarget();
mSocketThread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID);
MOZ_RELEASE_ASSERT(mMainThread, "no main thread");
MOZ_RELEASE_ASSERT(mSocketThread, "no socket thread");
}
WebrtcProxyChannel::~WebrtcProxyChannel()
{
LOG(("WebrtcProxyChannel::~WebrtcProxyChannel %p\n", this));
NS_ProxyRelease("WebrtcProxyChannel::CleanUpAuthProvider",
mMainThread,
mAuthProvider.forget());
}
nsresult
WebrtcProxyChannel::Write(nsTArray<uint8_t>&& aWriteData)
{
LOG(("WebrtcProxyChannel::Write %p\n", this));
MOZ_ALWAYS_SUCCEEDS(mSocketThread->Dispatch(
NewRunnableMethod<nsTArray<uint8_t>&&>("WebrtcProxyChannel::Write",
this,
&WebrtcProxyChannel::EnqueueWrite_s,
std::move(aWriteData))));
return NS_OK;
}
nsresult
WebrtcProxyChannel::Close()
{
LOG(("WebrtcProxyChannel::Close %p\n", this));
CloseWithReason(NS_OK);
return NS_OK;
}
void
WebrtcProxyChannel::CloseWithReason(nsresult aReason)
{
LOG(("WebrtcProxyChannel::CloseWithReason %p reason=%u\n",
this,
static_cast<uint32_t>(aReason)));
if (!OnSocketThread()) {
MOZ_ASSERT(NS_IsMainThread(), "not on main thread");
// Let's pretend we got an open even if we didn't to prevent an Open later.
mOpened = true;
MOZ_ALWAYS_SUCCEEDS(mSocketThread->Dispatch(
NewRunnableMethod<nsresult>("WebrtcProxyChannel::CloseWithReason",
this,
&WebrtcProxyChannel::CloseWithReason,
aReason)));
return;
}
if (mClosed) {
return;
}
mClosed = true;
if (mSocketIn) {
mSocketIn->AsyncWait(nullptr, 0, 0, nullptr);
mSocketIn = nullptr;
}
if (mSocketOut) {
mSocketOut->AsyncWait(nullptr, 0, 0, nullptr);
mSocketOut = nullptr;
}
if (mTransport) {
mTransport->Close(NS_BASE_STREAM_CLOSED);
mTransport = nullptr;
}
NS_ProxyRelease("WebrtcProxyChannel::CleanUpAuthProvider",
mMainThread,
mAuthProvider.forget());
InvokeOnClose(aReason);
}
nsresult WebrtcProxyChannel::Open(const nsCString& aHost,
const int& aPort,
nsILoadInfo* aLoadInfo,
const nsCString& aAlpn)
{
LOG(("WebrtcProxyChannel::AsyncOpen %p\n", this));
if (mOpened) {
LOG(("WebrtcProxyChannel %p: proxy channel already open\n", this));
CloseWithReason(NS_ERROR_FAILURE);
return NS_ERROR_FAILURE;
}
mOpened = true;
nsresult rv;
nsCString spec = NS_LITERAL_CSTRING("http://") + aHost;
nsCOMPtr<nsIURI> uri;
rv = NS_MutateURI(NS_STANDARDURLMUTATOR_CONTRACTID)
.SetSpec(spec)
.SetPort(aPort)
.Finalize(uri);
if (NS_FAILED(rv)) {
LOG(("WebrtcProxyChannel %p: bad proxy connect uri set\n", this));
CloseWithReason(rv);
return rv;
}
nsCOMPtr<nsIIOService> ioService;
ioService = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
LOG(("WebrtcProxyChannel %p: io service missing\n", this));
CloseWithReason(rv);
return rv;
}
// -need to always tunnel since we're using a proxy
// -there shouldn't be an opportunity to send cookies, but explicitly disallow
// them anyway.
// -the previous proxy tunnel didn't support redirects e.g. 307. don't need to
// introduce new behavior. can't follow redirects on connect anyway.
nsCOMPtr<nsIChannel> localChannel;
rv = ioService->NewChannelFromURIWithProxyFlags2(
uri,
nullptr,
// Proxy flags are overridden by SetConnectOnly()
0,
aLoadInfo->LoadingNode(),
aLoadInfo->LoadingPrincipal(),
aLoadInfo->TriggeringPrincipal(),
nsILoadInfo::SEC_DONT_FOLLOW_REDIRECTS |
nsILoadInfo::SEC_COOKIES_OMIT |
// We need this flag to allow loads from any origin since this channel
// is being used to CONNECT to an HTTP proxy.
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
nsIContentPolicy::TYPE_OTHER,
getter_AddRefs(localChannel));
if (NS_FAILED(rv)) {
LOG(("WebrtcProxyChannel %p: bad open channel\n", this));
CloseWithReason(rv);
return rv;
}
RefPtr<nsHttpChannel> httpChannel;
CallQueryInterface(localChannel, httpChannel.StartAssignment());
if (!httpChannel) {
LOG(("WebrtcProxyChannel %p: not an http channel\n", this));
CloseWithReason(NS_ERROR_FAILURE);
return NS_ERROR_FAILURE;
}
httpChannel->SetNotificationCallbacks(this);
// don't block webrtc proxy setup with other requests
// often more than one of these channels will be created all at once by ICE
nsCOMPtr<nsIClassOfService> cos = do_QueryInterface(localChannel);
if (cos) {
cos->AddClassFlags(nsIClassOfService::Unblocked |
nsIClassOfService::DontThrottle);
} else {
LOG(("WebrtcProxyChannel %p: could not set class of service\n", this));
CloseWithReason(NS_ERROR_FAILURE);
return NS_ERROR_FAILURE;
}
rv = httpChannel->HTTPUpgrade(aAlpn, this);
NS_ENSURE_SUCCESS(rv, rv);
rv = httpChannel->SetConnectOnly();
NS_ENSURE_SUCCESS(rv, rv);
rv = NS_MaybeOpenChannelUsingAsyncOpen2(httpChannel, this);
if (NS_FAILED(rv)) {
LOG(("WebrtcProxyChannel %p: cannot async open\n", this));
CloseWithReason(rv);
return rv;
}
return NS_OK;
}
void
WebrtcProxyChannel::EnqueueWrite_s(nsTArray<uint8_t>&& aWriteData)
{
LOG(("WebrtcProxyChannel::EnqueueWrite %p\n", this));
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
MOZ_ASSERT(!mClosed, "webrtc proxy channel closed");
mWriteQueue.emplace_back(std::move(aWriteData));
if (mSocketOut) {
mSocketOut->AsyncWait(this, 0, 0, nullptr);
}
}
void
WebrtcProxyChannel::InvokeOnClose(nsresult aReason)
{
LOG(("WebrtcProxyChannel::InvokeOnClose %p\n", this));
if (!NS_IsMainThread()) {
MOZ_ALWAYS_SUCCEEDS(mMainThread->Dispatch(
NewRunnableMethod<nsresult>("WebrtcProxyChannel::InvokeOnClose",
this,
&WebrtcProxyChannel::InvokeOnClose,
aReason)));
return;
}
MOZ_ASSERT(mProxyCallbacks, "webrtc proxy callback should be non-null");
mProxyCallbacks->OnClose(aReason);
mProxyCallbacks = nullptr;
}
void
WebrtcProxyChannel::InvokeOnConnected()
{
LOG(("WebrtcProxyChannel::InvokeOnConnected %p\n", this));
if (!NS_IsMainThread()) {
MOZ_ALWAYS_SUCCEEDS(mMainThread->Dispatch(
NewRunnableMethod("WebrtcProxyChannel::InvokeOnConnected",
this,
&WebrtcProxyChannel::InvokeOnConnected)));
return;
}
MOZ_ASSERT(mProxyCallbacks, "webrtc proxy callback should be non-null");
mProxyCallbacks->OnConnected();
}
void
WebrtcProxyChannel::InvokeOnRead(nsTArray<uint8_t>&& aReadData)
{
LOG(("WebrtcProxyChannel::InvokeOnRead %p count=%zu\n",
this,
aReadData.Length()));
if (!NS_IsMainThread()) {
MOZ_ALWAYS_SUCCEEDS(mMainThread->Dispatch(
NewRunnableMethod<nsTArray<uint8_t>&&>(
"WebrtcProxyChannel::InvokeOnRead",
this,
&WebrtcProxyChannel::InvokeOnRead,
std::move(aReadData))));
return;
}
MOZ_ASSERT(mProxyCallbacks, "webrtc proxy callback should be non-null");
mProxyCallbacks->OnRead(std::move(aReadData));
}
// nsIHttpUpgradeListener
NS_IMETHODIMP
WebrtcProxyChannel::OnTransportAvailable(nsISocketTransport* aTransport,
nsIAsyncInputStream* aSocketIn,
nsIAsyncOutputStream* aSocketOut)
{
LOG(("WebrtcProxyChannel::OnTransportAvailable %p\n", this));
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
MOZ_ASSERT(!mTransport, "already called transport available on webrtc proxy");
// Cancel any pending callbacks. The caller doesn't always cancel these
// awaits. We need to make sure they don't get them.
aSocketIn->AsyncWait(nullptr, 0, 0, nullptr);
aSocketOut->AsyncWait(nullptr, 0, 0, nullptr);
if (mClosed) {
LOG(("WebrtcProxyChannel::OnTransportAvailable %p closed\n", this));
return NS_OK;
}
mTransport = aTransport;
mSocketIn = aSocketIn;
mSocketOut = aSocketOut;
// pulled from nr_socket_prsock.cpp
uint32_t minBufferSize = 256 * 1024;
nsresult rv = mTransport->SetSendBufferSize(minBufferSize);
if (NS_FAILED(rv)) {
LOG(("WebrtcProxyChannel::OnTransportAvailable %p send failed\n", this));
CloseWithReason(rv);
return rv;
}
rv = mTransport->SetRecvBufferSize(minBufferSize);
if (NS_FAILED(rv)) {
LOG(("WebrtcProxyChannel::OnTransportAvailable %p recv failed\n", this));
CloseWithReason(rv);
return rv;
}
mSocketIn->AsyncWait(this, 0, 0, nullptr);
InvokeOnConnected();
return NS_OK;
}
// nsIRequestObserver (from nsIStreamListener)
NS_IMETHODIMP
WebrtcProxyChannel::OnStartRequest(nsIRequest* aRequest,
nsISupports* aContext)
{
LOG(("WebrtcProxyChannel::OnStartRequest %p\n", this));
return NS_OK;
}
NS_IMETHODIMP
WebrtcProxyChannel::OnStopRequest(nsIRequest* aRequest,
nsISupports* aContext,
nsresult aStatusCode)
{
LOG(("WebrtcProxyChannel::OnStopRequest %p status=%u\n",
this,
static_cast<uint32_t>(aStatusCode)));
// see nsHttpChannel::ProcessFailedProxyConnect for most error codes
if (NS_FAILED(aStatusCode)) {
CloseWithReason(aStatusCode);
return aStatusCode;
}
return NS_OK;
}
// nsIStreamListener
NS_IMETHODIMP
WebrtcProxyChannel::OnDataAvailable(nsIRequest* aRequest,
nsISupports* aContext,
nsIInputStream* aInputStream,
uint64_t aOffset,
uint32_t aCount)
{
LOG(("WebrtcProxyChannel::OnDataAvailable %p count=%u\n", this, aCount));
MOZ_ASSERT(0, "unreachable data available");
return NS_OK;
}
// nsIInputStreamCallback
NS_IMETHODIMP
WebrtcProxyChannel::OnInputStreamReady(nsIAsyncInputStream* in)
{
LOG(("WebrtcProxyChannel::OnInputStreamReady %p unwritten=%zu\n",
this,
CountUnwrittenBytes()));
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
MOZ_ASSERT(!mClosed, "webrtc proxy channel closed");
MOZ_ASSERT(mTransport, "webrtc proxy channel not connected");
MOZ_ASSERT(mSocketIn == in, "wrong input stream");
char buffer[9216];
uint32_t remainingCapacity = sizeof(buffer);
uint32_t read = 0;
while(remainingCapacity > 0) {
uint32_t count = 0;
nsresult rv = mSocketIn->Read(buffer + read, remainingCapacity, &count);
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
break;
}
if (NS_FAILED(rv)) {
LOG(("WebrtcProxyChannel::OnInputStreamReady %p failed %u\n",
this,
static_cast<uint32_t>(rv)));
CloseWithReason(rv);
return rv;
}
// base stream closed
if (count == 0) {
LOG(("WebrtcProxyChannel::OnInputStreamReady %p connection closed\n",
this));
CloseWithReason(NS_ERROR_FAILURE);
return NS_OK;
}
remainingCapacity -= count;
read += count;
}
if (read > 0) {
nsTArray<uint8_t> array(read);
array.AppendElements(buffer, read);
InvokeOnRead(std::move(array));
}
mSocketIn->AsyncWait(this, 0, 0, nullptr);
return NS_OK;
}
// nsIOutputStreamCallback
NS_IMETHODIMP
WebrtcProxyChannel::OnOutputStreamReady(nsIAsyncOutputStream* out)
{
LOG(("WebrtcProxyChannel::OnOutputStreamReady %p unwritten=%zu\n",
this,
CountUnwrittenBytes()));
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
MOZ_ASSERT(!mClosed, "webrtc proxy channel closed");
MOZ_ASSERT(mTransport, "webrtc proxy channel not connected");
MOZ_ASSERT(mSocketOut == out, "wrong output stream");
while(!mWriteQueue.empty()) {
const WebrtcProxyData& data = mWriteQueue.front();
char* buffer = reinterpret_cast<char*>(
const_cast<uint8_t*>(data.GetData().Elements())) + mWriteOffset;
uint32_t toWrite = data.GetData().Length() - mWriteOffset;
uint32_t wrote = 0;
nsresult rv = mSocketOut->Write(buffer, toWrite, &wrote);
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
mSocketOut->AsyncWait(this, 0, 0, nullptr);
return NS_OK;
}
if(NS_FAILED(rv)) {
LOG(("WebrtcProxyChannel::OnOutputStreamReady %p failed %u\n",
this,
static_cast<uint32_t>(rv)));
CloseWithReason(rv);
return NS_OK;
}
mWriteOffset += wrote;
if (toWrite == wrote) {
mWriteOffset = 0;
mWriteQueue.pop_front();
}
}
return NS_OK;
}
// nsIInterfaceRequestor
NS_IMETHODIMP
WebrtcProxyChannel::GetInterface(const nsIID& iid, void** result)
{
LOG(("WebrtcProxyChannel::GetInterface %p\n", this));
return QueryInterface(iid, result);
}
size_t
WebrtcProxyChannel::CountUnwrittenBytes() const
{
size_t count = 0;
for(const WebrtcProxyData& data : mWriteQueue) {
count += data.GetData().Length();
}
MOZ_ASSERT(count >= mWriteOffset, "offset exceeds write buffer length");
count -= mWriteOffset;
return count;
}
} // namespace net
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,94 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
/* 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 webrtc_proxy_channel_h__
#define webrtc_proxy_channel_h__
#include <list>
#include "nsCOMPtr.h"
#include "nsIAsyncInputStream.h"
#include "nsIAsyncOutputStream.h"
#include "nsIAuthPromptProvider.h"
#include "nsIHttpChannelInternal.h"
#include "nsIInterfaceRequestor.h"
#include "nsIStreamListener.h"
#include "nsStringFwd.h"
#include "nsTArray.h"
class nsILoadInfo;
class nsISocketTransport;
namespace mozilla {
namespace net {
class WebrtcProxyChannelCallback;
class WebrtcProxyData;
class WebrtcProxyChannel : public nsIHttpUpgradeListener,
public nsIStreamListener,
public nsIInputStreamCallback,
public nsIOutputStreamCallback,
public nsIInterfaceRequestor,
public nsIAuthPromptProvider
{
public:
NS_DECL_NSIHTTPUPGRADELISTENER
NS_DECL_NSIINPUTSTREAMCALLBACK
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSIOUTPUTSTREAMCALLBACK
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_THREADSAFE_ISUPPORTS
NS_FORWARD_SAFE_NSIAUTHPROMPTPROVIDER(mAuthProvider)
WebrtcProxyChannel(nsIAuthPromptProvider* aAuthProvider,
WebrtcProxyChannelCallback* aProxyCallbacks);
nsresult Open(const nsCString& aHost,
const int& aPort,
nsILoadInfo* aLoadInfo,
const nsCString& aAlpn);
nsresult Write(nsTArray<uint8_t>&& aBytes);
nsresult Close();
size_t CountUnwrittenBytes() const;
protected:
virtual ~WebrtcProxyChannel();
// protected for gtests
virtual void InvokeOnClose(nsresult aReason);
virtual void InvokeOnConnected();
virtual void InvokeOnRead(nsTArray<uint8_t>&& aReadData);
RefPtr<WebrtcProxyChannelCallback> mProxyCallbacks;
private:
bool mClosed;
bool mOpened;
void EnqueueWrite_s(nsTArray<uint8_t>&& aWriteData);
void CloseWithReason(nsresult aReason);
size_t mWriteOffset;
std::list<WebrtcProxyData> mWriteQueue;
nsCOMPtr<nsIAuthPromptProvider> mAuthProvider;
// Indicates that the channel is CONNECTed
nsCOMPtr<nsISocketTransport> mTransport;
nsCOMPtr<nsIAsyncInputStream> mSocketIn;
nsCOMPtr<nsIAsyncOutputStream> mSocketOut;
nsCOMPtr<nsIEventTarget> mMainThread;
nsCOMPtr<nsIEventTarget> mSocketThread;
};
} // namespace net
} // namespace mozilla
#endif // webrtc_proxy_channel_h__

Просмотреть файл

@ -0,0 +1,31 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
/* 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 webrtc_proxy_channel_callback_h__
#define webrtc_proxy_channel_callback_h__
#include "nsTArray.h"
namespace mozilla {
namespace net {
class WebrtcProxyChannelCallback
{
public:
NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
virtual void OnClose(nsresult aReason) = 0;
virtual void OnConnected() = 0;
virtual void OnRead(nsTArray<uint8_t>&& aReadData) = 0;
protected:
virtual ~WebrtcProxyChannelCallback() = default;
};
} // namespace net
} // namespace mozilla
#endif // webrtc_proxy_channel_callback_h__

Просмотреть файл

@ -0,0 +1,106 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
/* 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/. */
#include "WebrtcProxyChannelChild.h"
#include "mozilla/dom/PBrowserOrId.h"
#include "mozilla/net/NeckoChild.h"
#include "LoadInfo.h"
#include "WebrtcProxyLog.h"
#include "WebrtcProxyChannelCallback.h"
using namespace mozilla::ipc;
using mozilla::dom::PBrowserOrId;
namespace mozilla {
namespace net {
mozilla::ipc::IPCResult
WebrtcProxyChannelChild::RecvOnClose(const nsresult& aReason)
{
LOG(("WebrtcProxyChannelChild::RecvOnClose %p\n", this));
MOZ_ASSERT(mProxyCallbacks, "webrtc proxy callbacks should be non-null");
mProxyCallbacks->OnClose(aReason);
mProxyCallbacks = nullptr;
return IPC_OK();
}
mozilla::ipc::IPCResult
WebrtcProxyChannelChild::RecvOnConnected()
{
LOG(("WebrtcProxyChannelChild::RecvOnConnected %p\n", this));
MOZ_ASSERT(mProxyCallbacks, "webrtc proxy callbacks should be non-null");
mProxyCallbacks->OnConnected();
return IPC_OK();
}
mozilla::ipc::IPCResult
WebrtcProxyChannelChild::RecvOnRead(nsTArray<uint8_t>&& aReadData)
{
LOG(("WebrtcProxyChannelChild::RecvOnRead %p\n", this));
MOZ_ASSERT(mProxyCallbacks, "webrtc proxy callbacks should be non-null");
mProxyCallbacks->OnRead(std::move(aReadData));
return IPC_OK();
}
WebrtcProxyChannelChild::WebrtcProxyChannelChild(
WebrtcProxyChannelCallback* aProxyCallbacks)
: mProxyCallbacks(aProxyCallbacks)
{
MOZ_COUNT_CTOR(WebrtcProxyChannelChild);
LOG(("WebrtcProxyChannelChild::WebrtcProxyChannelChild %p\n", this));
}
WebrtcProxyChannelChild::~WebrtcProxyChannelChild()
{
MOZ_COUNT_DTOR(WebrtcProxyChannelChild);
LOG(("WebrtcProxyChannelChild::~WebrtcProxyChannelChild %p\n", this));
}
void
WebrtcProxyChannelChild::AsyncOpen(const nsCString& aHost,
const int& aPort,
const PBrowserOrId& aBrowser,
nsIPrincipal* aLoadingPrincipal,
const nsCString& aAlpn)
{
LOG(("WebrtcProxyChannelChild::AsyncOpen %p %s:%d\n",
this,
aHost.get(),
aPort));
MOZ_ASSERT(NS_IsMainThread(), "not main thread");
AddIPDLReference();
gNeckoChild->SetEventTargetForActor(this, GetMainThreadEventTarget());
gNeckoChild->SendPWebrtcProxyChannelConstructor(this, aBrowser);
nsCOMPtr<nsILoadInfo> loadInfo = new LoadInfo(aLoadingPrincipal,
nullptr,
nullptr,
0,
0);
OptionalLoadInfoArgs loadInfoArgs;
MOZ_ALWAYS_SUCCEEDS(LoadInfoToLoadInfoArgs(loadInfo, &loadInfoArgs));
SendAsyncOpen(aHost, aPort, loadInfoArgs, aAlpn);
}
} // namespace net
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,56 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
/* 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 mozilla_net_WebrtcProxyChannelChild_h
#define mozilla_net_WebrtcProxyChannelChild_h
#include "mozilla/net/PWebrtcProxyChannelChild.h"
namespace mozilla {
namespace dom {
class PBrowserOrId;
} // namespace dom
namespace net {
class WebrtcProxyChannelCallback;
class WebrtcProxyChannelChild : public PWebrtcProxyChannelChild
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebrtcProxyChannelChild)
mozilla::ipc::IPCResult
RecvOnClose(const nsresult& aReason) override;
mozilla::ipc::IPCResult
RecvOnConnected() override;
mozilla::ipc::IPCResult
RecvOnRead(nsTArray<uint8_t>&& aReadData) override;
explicit WebrtcProxyChannelChild(WebrtcProxyChannelCallback* aProxyCallbacks);
void AsyncOpen(const nsCString& aHost,
const int& aPort,
const dom::PBrowserOrId& aBrowser,
nsIPrincipal* aLoadingPrincipal,
const nsCString& aAlpn);
void AddIPDLReference() { AddRef(); }
void ReleaseIPDLReference() { Release(); }
protected:
virtual ~WebrtcProxyChannelChild();
RefPtr<WebrtcProxyChannelCallback> mProxyCallbacks;
};
} // namespace net
} // namespace mozilla
#endif // mozilla_net_WebrtcProxyChannelChild_h

Просмотреть файл

@ -0,0 +1,149 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
/* 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/. */
#include "WebrtcProxyChannelParent.h"
#include "mozilla/net/NeckoParent.h"
#include "WebrtcProxyChannel.h"
#include "WebrtcProxyLog.h"
using namespace mozilla::dom;
using namespace mozilla::ipc;
namespace mozilla {
namespace net {
mozilla::ipc::IPCResult
WebrtcProxyChannelParent::RecvAsyncOpen(
const nsCString& aHost,
const int& aPort,
const OptionalLoadInfoArgs& aLoadInfoArgs,
const nsCString& aAlpn)
{
LOG(("WebrtcProxyChannelParent::RecvAsyncOpen %p to %s:%d\n",
this,
aHost.get(),
aPort));
nsresult rv;
nsCOMPtr<nsILoadInfo> loadInfo;
rv = LoadInfoArgsToLoadInfo(aLoadInfoArgs, getter_AddRefs(loadInfo));
if (NS_FAILED(rv)) {
IProtocol* mgr = Manager();
OnClose(rv);
return IPC_FAIL_NO_REASON(mgr);
}
MOZ_ASSERT(mChannel, "webrtc proxy channel should be non-null");
mChannel->Open(aHost, aPort, loadInfo, aAlpn);
return IPC_OK();
}
mozilla::ipc::IPCResult
WebrtcProxyChannelParent::RecvWrite(nsTArray<uint8_t>&& aWriteData)
{
LOG(("WebrtcProxyChannelParent::RecvWrite %p for %zu\n",
this,
aWriteData.Length()));
// Need to check this here in case there are Writes in the queue after OnClose
if (mChannel) {
mChannel->Write(std::move(aWriteData));
}
return IPC_OK();
}
mozilla::ipc::IPCResult
WebrtcProxyChannelParent::RecvClose()
{
LOG(("WebrtcProxyChannelParent::RecvClose %p\n", this));
CleanupChannel();
IProtocol* mgr = Manager();
if (!Send__delete__(this)) {
return IPC_FAIL_NO_REASON(mgr);
}
return IPC_OK();
}
void
WebrtcProxyChannelParent::ActorDestroy(ActorDestroyReason aWhy)
{
LOG(("WebrtcProxyChannelParent::ActorDestroy %p for %d\n", this, aWhy));
CleanupChannel();
}
WebrtcProxyChannelParent::WebrtcProxyChannelParent(
nsIAuthPromptProvider* aAuthProvider)
{
MOZ_COUNT_CTOR(WebrtcProxyChannelParent);
LOG(("WebrtcProxyChannelParent::WebrtcProxyChannelParent %p\n", this));
mChannel = new WebrtcProxyChannel(aAuthProvider, this);
}
WebrtcProxyChannelParent::~WebrtcProxyChannelParent()
{
MOZ_COUNT_DTOR(WebrtcProxyChannelParent);
LOG(("WebrtcProxyChannelParent::~WebrtcProxyChannelParent %p\n", this));
CleanupChannel();
}
// WebrtcProxyChannelCallback
void
WebrtcProxyChannelParent::OnClose(nsresult aReason)
{
LOG(("WebrtcProxyChannelParent::OnClose %p\n", this));
if (mChannel) {
Unused << SendOnClose(aReason);
}
CleanupChannel();
}
void
WebrtcProxyChannelParent::OnRead(nsTArray<uint8_t>&& aReadData)
{
LOG(("WebrtcProxyChannelParent::OnRead %p %zu\n", this, aReadData.Length()));
if(mChannel && !SendOnRead(std::move(aReadData))) {
CleanupChannel();
}
}
void
WebrtcProxyChannelParent::OnConnected()
{
LOG(("WebrtcProxyChannelParent::OnConnected %p\n", this));
if(mChannel && !SendOnConnected()) {
CleanupChannel();
}
}
void
WebrtcProxyChannelParent::CleanupChannel()
{
if (mChannel) {
mChannel->Close();
mChannel = nullptr;
}
}
} // namespace net
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,65 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
/* 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 mozilla_net_WebrtcProxyChannelParent_h
#define mozilla_net_WebrtcProxyChannelParent_h
#include "mozilla/net/PWebrtcProxyChannelParent.h"
#include "WebrtcProxyChannelCallback.h"
class nsIAuthPromptProvider;
namespace mozilla {
namespace net {
class WebrtcProxyChannel;
class WebrtcProxyChannelParent : public PWebrtcProxyChannelParent,
public WebrtcProxyChannelCallback
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebrtcProxyChannelParent, override)
mozilla::ipc::IPCResult
RecvAsyncOpen(const nsCString& aHost,
const int& aPort,
const OptionalLoadInfoArgs& aLoadInfoArgs,
const nsCString& aAlpn) override;
mozilla::ipc::IPCResult
RecvWrite(nsTArray<uint8_t>&& aWriteData) override;
mozilla::ipc::IPCResult
RecvClose() override;
void
ActorDestroy(ActorDestroyReason aWhy) override;
explicit WebrtcProxyChannelParent(nsIAuthPromptProvider* aAuthProvider);
// WebrtcProxyChannelCallback
void OnClose(nsresult aReason) override;
void OnConnected() override;
void OnRead(nsTArray<uint8_t>&& bytes) override;
void AddIPDLReference() { AddRef(); }
void ReleaseIPDLReference() { Release(); }
protected:
virtual ~WebrtcProxyChannelParent();
private:
void CleanupChannel();
// Indicates that IPC is open.
RefPtr<WebrtcProxyChannel> mChannel;
};
} // namespace net
} // namespace mozilla
#endif // mozilla_net_WebrtcProxyChannelParent_h

Просмотреть файл

@ -0,0 +1,13 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
/* 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/. */
#include "WebrtcProxyLog.h"
namespace mozilla {
namespace net {
LazyLogModule webrtcProxyLog("webrtcProxy");
} // namespace net
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,21 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
/* 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 webrtc_proxy_log_h__
#define webrtc_proxy_log_h__
#include "mozilla/Logging.h"
namespace mozilla {
namespace net {
extern LazyLogModule webrtcProxyLog;
} // namespace net
} // namespace mozilla
#undef LOG
#define LOG(args) MOZ_LOG(mozilla::net::webrtcProxyLog, mozilla::LogLevel::Debug, args)
#endif // webrtc_proxy_log_h__

Просмотреть файл

@ -7,18 +7,31 @@ EXPORTS.mozilla.net += [
'PStunAddrsParams.h',
'StunAddrsRequestChild.h',
'StunAddrsRequestParent.h',
'WebrtcProxyChannel.h',
'WebrtcProxyChannelCallback.h',
'WebrtcProxyChannelChild.h',
'WebrtcProxyChannelParent.h',
]
UNIFIED_SOURCES += [
'StunAddrsRequestChild.cpp',
'StunAddrsRequestParent.cpp',
'WebrtcProxyChannel.cpp',
'WebrtcProxyChannelChild.cpp',
'WebrtcProxyChannelParent.cpp',
'WebrtcProxyLog.cpp',
]
IPDL_SOURCES += [
'PStunAddrsRequest.ipdl',
'PWebrtcProxyChannel.ipdl',
]
include("/ipc/chromium/chromium-config.mozbuild")
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'/netwerk/base',
'/netwerk/protocol/http',
]

Просмотреть файл

@ -0,0 +1,343 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
/* 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/. */
/*
Copyright (c) 2007, Adobe Systems, Incorporated
Copyright (c) 2013, Mozilla
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Adobe Systems, Network Resonance, Mozilla nor
the names of its contributors may be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "nr_socket_proxy.h"
#include "mozilla/ErrorNames.h"
#include "WebrtcProxyChannelWrapper.h"
namespace mozilla
{
using namespace net;
using std::shared_ptr;
class NrSocketProxyData
{
public:
explicit NrSocketProxyData(nsTArray<uint8_t>&& aData)
: mData(aData)
{
MOZ_COUNT_CTOR(NrSocketProxyData);
}
~NrSocketProxyData()
{
MOZ_COUNT_DTOR(NrSocketProxyData);
}
const nsTArray<uint8_t>& GetData() const
{
return mData;
}
private:
nsTArray<uint8_t> mData;
};
NrSocketProxy::NrSocketProxy(const shared_ptr<NrSocketProxyConfig>& aConfig)
: mClosed(false)
, mReadOffset(0)
, mConfig(aConfig)
, mWebrtcProxyChannel(nullptr)
{
r_log(LOG_GENERIC,LOG_DEBUG,"NrSocketProxy::NrSocketProxy %p\n", this);
MOZ_ASSERT(mConfig, "config should not be null");
}
NrSocketProxy::~NrSocketProxy()
{
r_log(LOG_GENERIC,LOG_DEBUG,"NrSocketProxy::~NrSocketProxy %p\n", this);
MOZ_ASSERT(!mWebrtcProxyChannel, "webrtc proxy channel not null");
}
int
NrSocketProxy::create(nr_transport_addr* aAddr)
{
int32_t port;
nsCString host;
// Sanity check
if (nr_transport_addr_get_addrstring_and_port(aAddr, &host, &port)) {
return R_FAILED;
}
if (nr_transport_addr_copy(&my_addr_, aAddr)) {
return R_FAILED;
}
return 0;
}
int
NrSocketProxy::connect(nr_transport_addr* aAddr)
{
r_log(LOG_GENERIC,LOG_DEBUG,"NrSocketProxy::Connect %p\n", this);
nsCString host;
int port;
if (nr_transport_addr_get_addrstring_and_port(aAddr, &host, &port)) {
return R_FAILED;
}
mWebrtcProxyChannel = new WebrtcProxyChannelWrapper(this);
mWebrtcProxyChannel->AsyncOpen(host, port, mConfig);
// trigger nr_socket_buffered to set write/read callback
return R_WOULDBLOCK;
}
void
NrSocketProxy::close()
{
r_log(LOG_GENERIC,LOG_DEBUG,"NrSocketProxy::Close %p\n", this);
if (mClosed) {
return;
}
mClosed = true;
// We're not always open at this point.
if (mWebrtcProxyChannel) {
mWebrtcProxyChannel->Close();
mWebrtcProxyChannel = nullptr;
}
}
int
NrSocketProxy::write(const void* aBuffer, size_t aCount, size_t* aWrote)
{
r_log(LOG_GENERIC,LOG_DEBUG,
"NrSocketProxy::Write %p count=%zu\n",
this,
aCount);
if (mClosed) {
return R_FAILED;
}
if (!aWrote) {
return R_FAILED;
}
*aWrote = aCount;
if (aCount > 0) {
nsTArray<uint8_t> writeData;
writeData.SetLength(aCount);
memcpy(writeData.Elements(), aBuffer, aCount);
mWebrtcProxyChannel->SendWrite(std::move(writeData));
}
return 0;
}
int
NrSocketProxy::read(void* aBuffer, size_t aCount, size_t* aRead)
{
r_log(LOG_GENERIC,LOG_DEBUG,"NrSocketProxy::Read %p\n", this);
if (mClosed) {
return R_FAILED;
}
if (!aRead) {
return R_FAILED;
}
*aRead = 0;
if (mReadQueue.empty()) {
return R_WOULDBLOCK;
}
while(aCount > 0 && !mReadQueue.empty()) {
const NrSocketProxyData& data = mReadQueue.front();
size_t remainingCount = data.GetData().Length() - mReadOffset;
size_t amountToCopy = std::min(aCount, remainingCount);
char* buffer = static_cast<char*>(aBuffer) + (*aRead);
memcpy(buffer, data.GetData().Elements() + mReadOffset, amountToCopy);
mReadOffset += amountToCopy;
*aRead += amountToCopy;
aCount -= amountToCopy;
if (remainingCount == amountToCopy) {
mReadOffset = 0;
mReadQueue.pop_front();
}
}
return 0;
}
int
NrSocketProxy::getaddr(nr_transport_addr* aAddr)
{
r_log(LOG_GENERIC,LOG_DEBUG,"NrSocketProxy::GetAddr %p\n", this);
return nr_transport_addr_copy(aAddr, &my_addr_);
}
int
NrSocketProxy::sendto(const void* aBuffer,
size_t aCount,
int aFlags,
nr_transport_addr* aAddr)
{
// never call this
MOZ_ASSERT(0);
return R_FAILED;
}
int
NrSocketProxy::recvfrom(void* aBuffer,
size_t aCount,
size_t* aRead,
int aFlags,
nr_transport_addr* aAddr)
{
// never call this
MOZ_ASSERT(0);
return R_FAILED;
}
int
NrSocketProxy::listen(int aBacklog)
{
return R_INTERNAL;
}
int
NrSocketProxy::accept(nr_transport_addr* aAddr, nr_socket** aSocket)
{
return R_INTERNAL;
}
// WebrtcProxyChannelCallback
void
NrSocketProxy::OnClose(nsresult aReason)
{
nsCString errorName;
GetErrorName(aReason, errorName);
r_log(LOG_GENERIC,LOG_ERR,
"NrSocketProxy::OnClose %p reason=%u name=%s\n",
this,
static_cast<uint32_t>(aReason),
errorName.get());
close();
DoCallbacks();
}
void
NrSocketProxy::OnConnected()
{
r_log(LOG_GENERIC,LOG_DEBUG,"NrSocketProxy::OnConnected %p\n", this);
DoCallbacks();
}
void
NrSocketProxy::OnRead(nsTArray<uint8_t>&& aReadData)
{
r_log(LOG_GENERIC,LOG_DEBUG,
"NrSocketProxy::OnRead %p read=%zu\n",
this,
aReadData.Length());
mReadQueue.emplace_back(std::move(aReadData));
DoCallbacks();
}
void
NrSocketProxy::DoCallbacks()
{
size_t lastCount = -1;
size_t currentCount = 0;
while ((poll_flags() & PR_POLL_READ) != 0 &&
// Make sure whatever is reading knows we're closed. This doesn't need
// to happen for writes since ICE doesn't like a failing writable.
(mClosed || (currentCount = CountUnreadBytes()) > 0) &&
lastCount != currentCount) {
fire_callback(NR_ASYNC_WAIT_READ);
lastCount = currentCount;
}
// We're always ready to write after we're connected. The parent process will
// buffer writes for us.
if (!mClosed && mWebrtcProxyChannel && (poll_flags() & PR_POLL_WRITE) != 0) {
fire_callback(NR_ASYNC_WAIT_WRITE);
}
}
size_t
NrSocketProxy::CountUnreadBytes() const
{
size_t count = 0;
for(const NrSocketProxyData& data : mReadQueue) {
count += data.GetData().Length();
}
MOZ_ASSERT(count >= mReadOffset, "offset exceeds read buffer length");
count -= mReadOffset;
return count;
}
void
NrSocketProxy::AssignChannel_DoNotUse(WebrtcProxyChannelWrapper* aWrapper) {
mWebrtcProxyChannel = aWrapper;
}
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,128 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
/* 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/. */
/*
Copyright (c) 2007, Adobe Systems, Incorporated
Copyright (c) 2013, Mozilla
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Adobe Systems, Network Resonance, Mozilla nor
the names of its contributors may be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef nr_socket_proxy_h__
#define nr_socket_proxy_h__
#include <list>
#include "mozilla/net/WebrtcProxyChannelCallback.h"
#include "nsTArray.h"
extern "C" {
#include "nr_api.h"
#include "nr_socket.h"
#include "transport_addr.h"
}
#include "nr_socket_prsock.h"
namespace mozilla
{
using namespace net;
namespace net
{
class WebrtcProxyChannelWrapper;
} // namespace net
class NrSocketProxyData;
class NrSocketProxyConfig;
class NrSocketProxy : public NrSocketBase,
public WebrtcProxyChannelCallback
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NrSocketProxy, override)
explicit NrSocketProxy(const std::shared_ptr<NrSocketProxyConfig>& aConfig);
// NrSocketBase
int create(nr_transport_addr *aAddr) override;
int connect(nr_transport_addr *aAddr) override;
void close() override;
int write(const void* aBuffer,
size_t aCount,
size_t* aWrote) override;
int read(void* aBuffer, size_t aCount, size_t* aRead) override;
int getaddr(nr_transport_addr* aAddr) override;
int sendto(const void* aBuffer,
size_t aCount,
int aFlags,
nr_transport_addr* aAddr) override;
int recvfrom(void* aBuffer,
size_t aCount,
size_t* aRead,
int aFlags,
nr_transport_addr* aAddr) override;
int listen(int aBacklog) override;
int accept(nr_transport_addr* aAddr, nr_socket** aSocket) override;
// WebrtcProxyChannelCallback
void OnClose(nsresult aReason) override;
void OnConnected() override;
void OnRead(nsTArray<uint8_t>&& aReadData) override;
size_t CountUnreadBytes() const;
// for gtests
void AssignChannel_DoNotUse(WebrtcProxyChannelWrapper* aWrapper);
protected:
virtual ~NrSocketProxy();
private:
void DoCallbacks();
bool mClosed;
size_t mReadOffset;
std::list<NrSocketProxyData> mReadQueue;
std::shared_ptr<NrSocketProxyConfig> mConfig;
RefPtr<WebrtcProxyChannelWrapper> mWebrtcProxyChannel;
};
} // namespace mozilla
#endif // nr_socket_proxy_h__

Просмотреть файл

@ -0,0 +1,44 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
/* 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/. */
#include "nr_socket_proxy_config.h"
#include "mozilla/dom/PBrowserOrId.h"
namespace mozilla
{
class NrSocketProxyConfig::Private {
public:
dom::PBrowserOrId mBrowser;
nsCString mAlpn;
};
NrSocketProxyConfig::NrSocketProxyConfig(const dom::PBrowserOrId& aBrowser,
const nsCString& aAlpn)
: mPrivate(new Private({aBrowser, aAlpn}))
{}
NrSocketProxyConfig::NrSocketProxyConfig(NrSocketProxyConfig&& aOrig)
: mPrivate(std::move(aOrig.mPrivate))
{}
NrSocketProxyConfig::~NrSocketProxyConfig()
{}
const dom::PBrowserOrId&
NrSocketProxyConfig::GetBrowser() const
{
return mPrivate->mBrowser;
}
const nsCString&
NrSocketProxyConfig::GetAlpn() const
{
return mPrivate->mAlpn;
}
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,47 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
/* 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 nr_socket_proxy_config__
#define nr_socket_proxy_config__
#include <memory>
#include "nsString.h"
class nsIPrincipal;
namespace mozilla
{
namespace dom
{
class PBrowserOrId;
}
class NrSocketProxyConfig
{
public:
NrSocketProxyConfig(const dom::PBrowserOrId& aBrowser,
const nsCString& aAlpn);
// We need to actually write the default impl ourselves, because the compiler
// needs to know how to destroy mPrivate in case an exception is thrown, even
// though we disable exceptions in our build.
NrSocketProxyConfig(NrSocketProxyConfig&& aOrig);
~NrSocketProxyConfig();
const dom::PBrowserOrId& GetBrowser() const;
const nsCString& GetAlpn() const;
private:
// PBrowserOrId includes stuff that conflicts with nICEr includes.
// Make it possible to include this header file without tripping over this
// problem.
class Private;
std::unique_ptr<Private> mPrivate;
};
} // namespace mozilla
#endif // nr_socket_proxy_config__

Просмотреть файл

@ -139,6 +139,7 @@ nrappkit copyright:
#include "mozilla/dom/network/TCPSocketChild.h"
#include "mozilla/dom/network/UDPSocketChild.h"
#include "nr_socket_proxy.h"
#ifdef LOG_TEMP_INFO
#define LOG_INFO LOG_TEMP_INFO
@ -2153,7 +2154,9 @@ static nr_socket_vtbl nr_socket_local_vtbl={
/* static */
int
NrSocketBase::CreateSocket(nr_transport_addr *addr, RefPtr<NrSocketBase> *sock)
NrSocketBase::CreateSocket(nr_transport_addr *addr,
RefPtr<NrSocketBase> *sock,
const std::shared_ptr<NrSocketProxyConfig>& config)
{
int r, _status;
@ -2167,10 +2170,12 @@ NrSocketBase::CreateSocket(nr_transport_addr *addr, RefPtr<NrSocketBase> *sock)
break;
case IPPROTO_TCP:
#if defined(MOZILLA_INTERNAL_API)
{
if (!config) {
nsCOMPtr<nsIThread> main_thread;
NS_GetMainThread(getter_AddRefs(main_thread));
*sock = new NrTcpSocketIpc(main_thread.get());
} else {
*sock = new NrSocketProxy(config);
}
#else
ABORT(R_REJECTED);
@ -2191,33 +2196,6 @@ abort:
return _status;
}
int nr_socket_local_create(void *obj, nr_transport_addr *addr, nr_socket **sockp) {
RefPtr<NrSocketBase> sock;
int r, _status;
r = NrSocketBase::CreateSocket(addr, &sock);
if (r) {
ABORT(r);
}
r = nr_socket_create_int(static_cast<void *>(sock),
sock->vtbl(), sockp);
if (r)
ABORT(r);
_status = 0;
{
// We will release this reference in destroy(), not exactly the normal
// ownership model, but it is what it is.
NrSocketBase* dummy = sock.forget().take();
(void)dummy;
}
abort:
return _status;
}
static int nr_socket_local_destroy(void **objp) {
if(!objp || !*objp)

Просмотреть файл

@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef nr_socket_prsock__
#define nr_socket_prsock__
#include <memory>
#include <queue>
#include "nspr.h"
@ -75,6 +76,7 @@ typedef struct nr_socket_ nr_socket;
#if defined(MOZILLA_INTERNAL_API)
namespace mozilla {
class NrSocketProxyConfig;
namespace dom {
class TCPSocketChild;
}
@ -98,7 +100,9 @@ public:
// Factory method; will create either an NrSocket, NrUdpSocketIpc, or
// NrTcpSocketIpc as appropriate.
static int CreateSocket(nr_transport_addr *addr, RefPtr<NrSocketBase> *sock);
static int CreateSocket(nr_transport_addr *addr,
RefPtr<NrSocketBase> *sock,
const std::shared_ptr<NrSocketProxyConfig>& config);
// the nr_socket APIs
virtual int create(nr_transport_addr *addr) = 0;

Просмотреть файл

@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string>
#include <vector>
#include "nr_socket_proxy_config.h"
#include "mozilla/Telemetry.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Unused.h"
@ -79,7 +80,6 @@ extern "C" {
#include "nr_crypto.h"
#include "nr_socket.h"
#include "nr_socket_local.h"
#include "nr_proxy_tunnel.h"
#include "stun_client_ctx.h"
#include "stun_reg.h"
#include "stun_server_ctx.h"
@ -100,6 +100,8 @@ extern "C" {
namespace mozilla {
using std::shared_ptr;
TimeStamp nr_socket_short_term_violation_time() {
return NrSocketBase::short_term_violation_time();
}
@ -116,6 +118,15 @@ const char kNrIceTransportTls[] = "tls";
static bool initialized = false;
static int noop(void** obj) {
return 0;
}
static nr_socket_factory_vtbl ctx_socket_factory_vtbl = {
nr_socket_local_create,
noop
};
// Implement NSPR-based crypto algorithms
static int nr_crypto_nss_random_bytes(UCHAR *buf, size_t len) {
UniquePK11SlotInfo slot(PK11_GetInternalSlot());
@ -288,7 +299,8 @@ NrIceCtx::NrIceCtx(const std::string& name, Policy policy)
ice_handler_(nullptr),
trickle_(true),
policy_(policy),
nat_ (nullptr) {
nat_ (nullptr),
proxy_config_(nullptr) {
}
/* static */
@ -611,6 +623,19 @@ NrIceCtx::Initialize()
return false;
}
// override default factory to capture optional proxy config when creating
// sockets.
nr_socket_factory* factory;
r = nr_socket_factory_create_int(this,
&ctx_socket_factory_vtbl,
&factory);
if (r) {
MOZ_MTLOG(LogLevel::Error, "Couldn't create ctx socket factory.");
return false;
}
nr_ice_ctx_set_socket_factory(ctx_, factory);
nr_interface_prioritizer *prioritizer = CreateInterfacePrioritizer();
if (!prioritizer) {
MOZ_MTLOG(LogLevel::Error, "Couldn't create interface prioritizer.");
@ -780,6 +805,7 @@ NrIceStats NrIceCtx::Destroy() {
ice_handler_vtbl_ = nullptr;
ice_handler_ = nullptr;
proxy_config_ = nullptr;
streams_.clear();
return stats;
@ -875,43 +901,8 @@ nsresult NrIceCtx::SetResolver(nr_resolver *resolver) {
return NS_OK;
}
nsresult NrIceCtx::SetProxyServer(const NrIceProxyServer& proxy_server) {
int r,_status;
nr_proxy_tunnel_config *config = nullptr;
nr_socket_wrapper_factory *wrapper = nullptr;
if ((r = nr_proxy_tunnel_config_create(&config))) {
ABORT(r);
}
if ((r = nr_proxy_tunnel_config_set_proxy(config,
proxy_server.host().c_str(),
proxy_server.port()))) {
ABORT(r);
}
if ((r = nr_proxy_tunnel_config_set_resolver(config, ctx_->resolver))) {
ABORT(r);
}
if ((r = nr_socket_wrapper_factory_proxy_tunnel_create(config, &wrapper))) {
MOZ_MTLOG(LogLevel::Error, "Couldn't create proxy tunnel wrapper.");
ABORT(r);
}
// nr_ice_ctx will own the wrapper after this call
if ((r = nr_ice_ctx_set_turn_tcp_socket_wrapper(ctx_, wrapper))) {
MOZ_MTLOG(ML_ERROR, "Couldn't set proxy for '" << name_ << "': " << r);
ABORT(r);
}
_status = 0;
abort:
nr_proxy_tunnel_config_destroy(&config);
if (_status) {
nr_socket_wrapper_factory_destroy(&wrapper);
return NS_ERROR_FAILURE;
}
nsresult NrIceCtx::SetProxyServer(NrSocketProxyConfig&& config) {
proxy_config_.reset(new NrSocketProxyConfig(std::move(config)));
return NS_OK;
}
@ -1170,3 +1161,40 @@ void nr_ice_compute_codeword(char *buf, int len,char *codeword) {
PL_Base64Encode(reinterpret_cast<char*>(&c), 3, codeword);
codeword[4] = 0;
}
int nr_socket_local_create(void *obj,
nr_transport_addr *addr,
nr_socket **sockp)
{
using namespace mozilla;
RefPtr<NrSocketBase> sock;
int r, _status;
shared_ptr<NrSocketProxyConfig> config = nullptr;
if (obj) {
config = static_cast<NrIceCtx*>(obj)->GetProxyConfig();
}
r = NrSocketBase::CreateSocket(addr, &sock, config);
if (r) {
ABORT(r);
}
r = nr_socket_create_int(static_cast<void *>(sock),
sock->vtbl(), sockp);
if (r)
ABORT(r);
_status = 0;
{
// We will release this reference in destroy(), not exactly the normal
// ownership model, but it is what it is.
NrSocketBase* dummy = sock.forget().take();
(void)dummy;
}
abort:
return _status;
}

Просмотреть файл

@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef nricectx_h__
#define nricectx_h__
#include <memory>
#include <string>
#include <vector>
#include <map>
@ -86,6 +87,8 @@ typedef void* NR_SOCKET;
namespace mozilla {
class NrSocketProxyConfig;
// Timestamps set whenever a packet is dropped due to global rate limiting
// (see nr_socket_prsock.cpp)
TimeStamp nr_socket_short_term_violation_time();
@ -175,25 +178,6 @@ class NrIceTurnServer : public NrIceStunServer {
std::vector<unsigned char> password_;
};
class NrIceProxyServer {
public:
NrIceProxyServer(const std::string& host, uint16_t port,
const std::string& alpn) :
host_(host), port_(port), alpn_(alpn) {
}
NrIceProxyServer() : NrIceProxyServer("", 0, "") {}
const std::string& host() const { return host_; }
uint16_t port() const { return port_; }
const std::string& alpn() const { return alpn_; }
private:
std::string host_;
uint16_t port_;
std::string alpn_;
};
class TestNat;
class NrIceStats {
@ -331,7 +315,10 @@ class NrIceCtx {
// Provide the proxy address. Must be called before
// StartGathering.
nsresult SetProxyServer(const NrIceProxyServer& proxy_server);
nsresult SetProxyServer(NrSocketProxyConfig&& config);
const std::shared_ptr<NrSocketProxyConfig>& GetProxyConfig()
{ return proxy_config_; }
void SetCtxFlags(bool default_route_only, bool proxy_only);
@ -415,6 +402,7 @@ private:
nsCOMPtr<nsIEventTarget> sts_target_; // The thread to run on
Policy policy_;
RefPtr<TestNat> nat_;
std::shared_ptr<NrSocketProxyConfig> proxy_config_;
};

Просмотреть файл

@ -4,6 +4,8 @@
# 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/.
include("/ipc/chromium/chromium-config.mozbuild")
if CONFIG['OS_TARGET'] != 'WINNT':
SOURCES += [
'buffered_stun_socket_unittest.cpp',
@ -21,6 +23,7 @@ if CONFIG['OS_TARGET'] != 'WINNT':
'TestSyncRunnable.cpp',
'transport_unittests.cpp',
'turn_unittest.cpp',
'webrtcproxychannel_unittest.cpp',
]
if CONFIG['MOZ_SCTP']:

Просмотреть файл

@ -6,20 +6,14 @@
// Original authors: ekr@rtfm.com; ryan@tokbox.com
#include <iostream>
#include <vector>
#include <numeric>
extern "C" {
#include "nr_api.h"
#include "nr_socket.h"
#include "nr_proxy_tunnel.h"
#include "transport_addr.h"
#include "stun.h"
}
#include "mozilla/dom/PBrowserOrId.h"
#include "dummysocket.h"
#include "nr_socket_prsock.h"
#include "nriceresolverfake.h"
#include "nr_socket_proxy.h"
#include "nr_socket_proxy_config.h"
#include "WebrtcProxyChannelWrapper.h"
#define GTEST_HAS_RTTI 0
#include "gtest/gtest.h"
@ -27,313 +21,284 @@ extern "C" {
using namespace mozilla;
const std::string kRemoteAddr = "192.0.2.133";
const uint16_t kRemotePort = 3333;
// update TestReadMultipleSizes if you change this
const std::string kHelloMessage = "HELLO IS IT ME YOU'RE LOOKING FOR?";
const std::string kProxyHost = "example.com";
const std::string kProxyAddr = "192.0.2.134";
const uint16_t kProxyPort = 9999;
typedef mozilla::dom::PBrowserOrId PBrowserOrId;
const std::string kHelloMessage = "HELLO";
const std::string kGarbageMessage = "xxxxxxxxxx";
std::string connect_message(const std::string &host, uint16_t port, const std::string &alpn, const std::string &tail) {
std::stringstream ss;
ss << "CONNECT " << host << ":" << port << " HTTP/1.0\r\n";
if (!alpn.empty()) {
ss << "ALPN: " << alpn << "\r\n";
}
ss << "\r\n" << tail;
return ss.str();
}
std::string connect_response(int code, const std::string &tail = "") {
std::stringstream ss;
ss << "HTTP/1.0 " << code << "\r\n\r\n" << tail;
return ss.str();
}
class DummyResolver {
class NrSocketProxyTest : public MtransportTest {
public:
DummyResolver() {
vtbl_ = new nr_resolver_vtbl;
vtbl_->destroy = &DummyResolver::destroy;
vtbl_->resolve = &DummyResolver::resolve;
vtbl_->cancel = &DummyResolver::cancel;
nr_resolver_create_int((void *)this, vtbl_, &resolver_);
}
~DummyResolver() {
nr_resolver_destroy(&resolver_);
delete vtbl_;
}
static int destroy(void **objp) {
return 0;
}
static int resolve(void *obj,
nr_resolver_resource *resource,
int (*cb)(void *cb_arg, nr_transport_addr *addr),
void *cb_arg,
void **handle) {
nr_transport_addr addr;
nr_str_port_to_transport_addr(
(char *)kProxyAddr.c_str(), kProxyPort, IPPROTO_TCP, &addr);
cb(cb_arg, &addr);
return 0;
}
static int cancel(void *obj, void *handle) {
return 0;
}
nr_resolver *get_nr_resolver() {
return resolver_;
}
private:
nr_resolver_vtbl *vtbl_;
nr_resolver *resolver_;
};
class ProxyTunnelSocketTest : public MtransportTest {
public:
ProxyTunnelSocketTest()
: socket_impl_(nullptr),
nr_socket_(nullptr) {}
~ProxyTunnelSocketTest() {
nr_socket_destroy(&nr_socket_);
nr_proxy_tunnel_config_destroy(&config_);
}
NrSocketProxyTest()
: mSProxy(nullptr)
, nr_socket_(nullptr)
, mEmptyArray(0)
, mReadChunkSize(0)
, mReadChunkSizeIncrement(1)
, mReadAllowance(-1)
, mConnected(false) {}
void SetUp() override {
MtransportTest::SetUp();
nr_resolver_ = resolver_impl_.get_nr_resolver();
int r = nr_str_port_to_transport_addr(
(char *)kRemoteAddr.c_str(), kRemotePort, IPPROTO_TCP, &remote_addr_);
nsCString alpn = NS_LITERAL_CSTRING("webrtc");
std::shared_ptr<NrSocketProxyConfig> config;
config.reset(new NrSocketProxyConfig(PBrowserOrId(), alpn));
// config is never used but must be non-null
mSProxy = new NrSocketProxy(config);
int r = nr_socket_create_int((void*)mSProxy.get(),
mSProxy->vtbl(),
&nr_socket_);
ASSERT_EQ(0, r);
r = nr_str_port_to_transport_addr(
(char *)kProxyAddr.c_str(), kProxyPort, IPPROTO_TCP, &proxy_addr_);
ASSERT_EQ(0, r);
nr_proxy_tunnel_config_create(&config_);
nr_proxy_tunnel_config_set_resolver(config_, nr_resolver_);
nr_proxy_tunnel_config_set_proxy(config_, kProxyAddr.c_str(), kProxyPort);
Configure();
// fake calling AsyncOpen() due to IPC calls. must be non-null
mSProxy->AssignChannel_DoNotUse(new WebrtcProxyChannelWrapper(nullptr));
}
// This reconfigures the socket with the updated information in config_.
void Configure() {
if (nr_socket_) {
EXPECT_EQ(0, nr_socket_destroy(&nr_socket_));
EXPECT_EQ(nullptr, nr_socket_);
void TearDown() override {
mSProxy->close();
}
static void readable_cb(NR_SOCKET s, int how, void *cb_arg) {
NrSocketProxyTest* test = (NrSocketProxyTest*) cb_arg;
size_t capacity = std::min(test->mReadChunkSize, test->mReadAllowance);
nsTArray<uint8_t> array(capacity);
size_t read;
nr_socket_read(test->nr_socket_,
(char*)array.Elements(),
array.Capacity(),
&read,
0);
ASSERT_TRUE(read <= array.Capacity());
ASSERT_TRUE(test->mReadAllowance >= read);
array.SetLength(read);
test->mData.AppendElements(array);
test->mReadAllowance -= read;
// We may read more bytes each time we're called. This way we can ensure we
// consume buffers partially and across multiple buffers.
test->mReadChunkSize += test->mReadChunkSizeIncrement;
if (test->mReadAllowance > 0) {
NR_ASYNC_WAIT(s, how, &NrSocketProxyTest::readable_cb, cb_arg);
}
RefPtr<DummySocket> dummy(new DummySocket());
int r = nr_socket_proxy_tunnel_create(
config_,
dummy->get_nr_socket(),
&nr_socket_);
ASSERT_EQ(0, r);
socket_impl_ = dummy.forget(); // Now owned by nr_socket_.
}
void Connect(int expectedReturn = 0) {
int r = nr_socket_connect(nr_socket_, &remote_addr_);
EXPECT_EQ(expectedReturn, r);
size_t written = 0;
r = nr_socket_write(nr_socket_, kHelloMessage.c_str(), kHelloMessage.size(), &written, 0);
EXPECT_EQ(0, r);
EXPECT_EQ(kHelloMessage.size(), written);
static void writable_cb(NR_SOCKET s, int how, void *cb_arg) {
NrSocketProxyTest* test = (NrSocketProxyTest*) cb_arg;
test->mConnected = true;
}
nr_socket *socket() { return nr_socket_; }
const std::string DataString() {
return std::string((char*)mData.Elements(), mData.Length());
}
protected:
RefPtr<DummySocket> socket_impl_;
DummyResolver resolver_impl_;
RefPtr<NrSocketProxy> mSProxy;
nr_socket *nr_socket_;
nr_resolver *nr_resolver_;
nr_proxy_tunnel_config *config_;
nr_transport_addr proxy_addr_;
nr_transport_addr remote_addr_;
nsTArray<uint8_t> mData;
nsTArray<uint8_t> mEmptyArray;
uint32_t mReadChunkSize;
uint32_t mReadChunkSizeIncrement;
uint32_t mReadAllowance;
bool mConnected;
};
TEST_F(ProxyTunnelSocketTest, TestCreate) {
TEST_F(NrSocketProxyTest, TestCreate) {
}
TEST_F(ProxyTunnelSocketTest, TestConnectProxyAddress) {
int r = nr_socket_connect(nr_socket_, &remote_addr_);
ASSERT_EQ(0, r);
TEST_F(NrSocketProxyTest, TestConnected) {
ASSERT_TRUE(!mConnected);
ASSERT_EQ(0, nr_transport_addr_cmp(socket_impl_->get_connect_addr(), &proxy_addr_,
NR_TRANSPORT_ADDR_CMP_MODE_ALL));
NR_ASYNC_WAIT(mSProxy,
NR_ASYNC_WAIT_WRITE,
&NrSocketProxyTest::writable_cb,
this);
// still not connected just registered for writes...
ASSERT_TRUE(!mConnected);
mSProxy->OnConnected();
ASSERT_TRUE(mConnected);
}
// TODO: Reenable once bug 1251212 is fixed
TEST_F(ProxyTunnelSocketTest, DISABLED_TestConnectProxyRequest) {
Connect();
TEST_F(NrSocketProxyTest, TestRead) {
nsTArray<uint8_t> array;
array.AppendElements(kHelloMessage.c_str(), kHelloMessage.length());
std::string msg = connect_message(kRemoteAddr, kRemotePort, "", kHelloMessage);
socket_impl_->CheckWriteBuffer(reinterpret_cast<const uint8_t *>(msg.c_str()), msg.size());
NR_ASYNC_WAIT(mSProxy,
NR_ASYNC_WAIT_READ,
&NrSocketProxyTest::readable_cb,
this);
// this will read 0 bytes here
mSProxy->OnRead(std::move(array));
ASSERT_EQ(kHelloMessage.length(), mSProxy->CountUnreadBytes());
// callback is still set but terminated due to 0 byte read
// start callbacks again (first read is 0 then 1,2,3,...)
mSProxy->OnRead(std::move(mEmptyArray));
ASSERT_EQ(kHelloMessage.length(), mData.Length());
ASSERT_EQ(kHelloMessage, DataString());
}
// TODO: Reenable once bug 1251212 is fixed
TEST_F(ProxyTunnelSocketTest, DISABLED_TestAlpnConnect) {
const std::string alpn = "this,is,alpn";
int r = nr_proxy_tunnel_config_set_alpn(config_, alpn.c_str());
EXPECT_EQ(0, r);
TEST_F(NrSocketProxyTest, TestReadConstantConsumeSize) {
std::string data;
Configure();
Connect();
// triangle number
const int kCount = 32;
std::string msg = connect_message(kRemoteAddr, kRemotePort, alpn, kHelloMessage);
socket_impl_->CheckWriteBuffer(reinterpret_cast<const uint8_t *>(msg.c_str()), msg.size());
// ~17kb
// triangle number formula n*(n+1)/2
for(int i = 0; i < kCount * (kCount + 1) / 2; ++i) {
data += kHelloMessage;
}
// decreasing buffer sizes
for(int i = 0, start = 0; i < kCount; ++i) {
int length = (kCount - i) * kHelloMessage.length();
nsTArray<uint8_t> array;
array.AppendElements(data.c_str() + start, length);
start += length;
mSProxy->OnRead(std::move(array));
}
ASSERT_EQ(data.length(), mSProxy->CountUnreadBytes());
// read same amount each callback
mReadChunkSize = 128;
mReadChunkSizeIncrement = 0;
NR_ASYNC_WAIT(mSProxy,
NR_ASYNC_WAIT_READ,
&NrSocketProxyTest::readable_cb,
this);
ASSERT_EQ(data.length(), mSProxy->CountUnreadBytes());
// start callbacks
mSProxy->OnRead(std::move(mEmptyArray));
ASSERT_EQ(data.length(), mData.Length());
ASSERT_EQ(data, DataString());
}
// TODO: Reenable once bug 1251212 is fixed
TEST_F(ProxyTunnelSocketTest, DISABLED_TestNullAlpnConnect) {
int r = nr_proxy_tunnel_config_set_alpn(config_, nullptr);
EXPECT_EQ(0, r);
Configure();
Connect();
std::string msg = connect_message(kRemoteAddr, kRemotePort, "", kHelloMessage);
socket_impl_->CheckWriteBuffer(reinterpret_cast<const uint8_t *>(msg.c_str()), msg.size());
}
// TODO: Reenable once bug 1251212 is fixed
TEST_F(ProxyTunnelSocketTest, DISABLED_TestConnectProxyHostRequest) {
nr_proxy_tunnel_config_set_proxy(config_, kProxyHost.c_str(), kProxyPort);
Configure();
// Because kProxyHost is a domain name and not an IP address,
// nr_socket_connect will need to resolve an IP address before continuing. It
// does that, and assumes that resolving the IP will take some time, so it
// returns R_WOULDBLOCK.
//
// However, In this test setup, the resolution happens inline immediately, so
// nr_socket_connect is called recursively on the inner socket in
// nr_socket_proxy_tunnel_resolved_cb. That also completes. Thus, the socket
// is actually successfully connected after this call, even though
// nr_socket_connect reports an error.
//
// Arguably nr_socket_proxy_tunnel_connect() is busted, because it shouldn't
// report an error when it doesn't need any further assistance from the
// calling code, but that's pretty minor.
Connect(R_WOULDBLOCK);
std::string msg = connect_message(kRemoteAddr, kRemotePort, "", kHelloMessage);
socket_impl_->CheckWriteBuffer(reinterpret_cast<const uint8_t *>(msg.c_str()), msg.size());
}
// TODO: Reenable once bug 1251212 is fixed
TEST_F(ProxyTunnelSocketTest, DISABLED_TestConnectProxyWrite) {
Connect();
socket_impl_->ClearWriteBuffer();
size_t written = 0;
int r = nr_socket_write(nr_socket_, kHelloMessage.c_str(), kHelloMessage.size(), &written, 0);
EXPECT_EQ(0, r);
EXPECT_EQ(kHelloMessage.size(), written);
socket_impl_->CheckWriteBuffer(reinterpret_cast<const uint8_t *>(kHelloMessage.c_str()),
kHelloMessage.size());
}
TEST_F(ProxyTunnelSocketTest, TestConnectProxySuccessResponse) {
int r = nr_socket_connect(nr_socket_, &remote_addr_);
ASSERT_EQ(0, r);
std::string resp = connect_response(200, kHelloMessage);
socket_impl_->SetReadBuffer(reinterpret_cast<const uint8_t *>(resp.c_str()), resp.size());
TEST_F(NrSocketProxyTest, TestReadNone) {
char buf[4096];
size_t read = 0;
r = nr_socket_read(nr_socket_, buf, sizeof(buf), &read, 0);
ASSERT_EQ(0, r);
int r = nr_socket_read(nr_socket_, buf, sizeof(buf), &read, 0);
ASSERT_EQ(kHelloMessage.size(), read);
ASSERT_EQ(0, memcmp(buf, kHelloMessage.c_str(), kHelloMessage.size()));
}
TEST_F(ProxyTunnelSocketTest, TestConnectProxyRead) {
int r = nr_socket_connect(nr_socket_, &remote_addr_);
ASSERT_EQ(0, r);
std::string resp = connect_response(200, kHelloMessage);
socket_impl_->SetReadBuffer(reinterpret_cast<const uint8_t *>(resp.c_str()), resp.size());
char buf[4096];
size_t read = 0;
r = nr_socket_read(nr_socket_, buf, sizeof(buf), &read, 0);
ASSERT_EQ(0, r);
socket_impl_->ClearReadBuffer();
socket_impl_->SetReadBuffer(reinterpret_cast<const uint8_t *>(kHelloMessage.c_str()),
kHelloMessage.size());
r = nr_socket_read(nr_socket_, buf, sizeof(buf), &read, 0);
ASSERT_EQ(0, r);
ASSERT_EQ(kHelloMessage.size(), read);
ASSERT_EQ(0, memcmp(buf, kHelloMessage.c_str(), kHelloMessage.size()));
}
TEST_F(ProxyTunnelSocketTest, TestConnectProxyReadNone) {
int r = nr_socket_connect(nr_socket_, &remote_addr_);
ASSERT_EQ(0, r);
std::string resp = connect_response(200);
socket_impl_->SetReadBuffer(reinterpret_cast<const uint8_t *>(resp.c_str()), resp.size());
char buf[4096];
size_t read = 0;
r = nr_socket_read(nr_socket_, buf, sizeof(buf), &read, 0);
ASSERT_EQ(R_WOULDBLOCK, r);
socket_impl_->ClearReadBuffer();
socket_impl_->SetReadBuffer(reinterpret_cast<const uint8_t *>(kHelloMessage.c_str()),
kHelloMessage.size());
nsTArray<uint8_t> array;
array.AppendElements(kHelloMessage.c_str(), kHelloMessage.length());
mSProxy->OnRead(std::move(array));
ASSERT_EQ(kHelloMessage.length(), mSProxy->CountUnreadBytes());
r = nr_socket_read(nr_socket_, buf, sizeof(buf), &read, 0);
ASSERT_EQ(0, r);
ASSERT_EQ(kHelloMessage.length(), read);
ASSERT_EQ(kHelloMessage, std::string(buf, read));
}
TEST_F(ProxyTunnelSocketTest, TestConnectProxyFailResponse) {
int r = nr_socket_connect(nr_socket_, &remote_addr_);
ASSERT_EQ(0, r);
TEST_F(NrSocketProxyTest, TestReadMultipleSizes) {
using namespace std;
std::string resp = connect_response(500, kHelloMessage);
socket_impl_->SetReadBuffer(reinterpret_cast<const uint8_t *>(resp.c_str()), resp.size());
string data;
// 515 * kHelloMessage.length() == 17510
const size_t kCount = 515;
// randomly generated numbers, sums to 17510, 20 numbers
vector<int> varyingSizes = { 404, 622, 1463, 1597, 1676, 389, 389, 1272, 781,
81, 1030, 1450, 256, 812, 1571, 29, 1045, 911, 643, 1089 };
char buf[4096];
size_t read = 0;
r = nr_socket_read(nr_socket_, buf, sizeof(buf), &read, 0);
ASSERT_NE(0, r);
// changing varyingSizes or the test message breaks this so check here
ASSERT_EQ(kCount, 17510 / kHelloMessage.length());
ASSERT_EQ(17510, accumulate(varyingSizes.begin(), varyingSizes.end(), 0));
// ~17kb
for(size_t i = 0; i < kCount; ++i) {
data += kHelloMessage;
}
nsTArray<uint8_t> array;
array.AppendElements(data.c_str(), data.length());
for(int amountToRead : varyingSizes) {
nsTArray<uint8_t> buffer;
buffer.AppendElements(array.Elements(), amountToRead);
array.RemoveElementsAt(0, amountToRead);
mSProxy->OnRead(std::move(buffer));
}
ASSERT_EQ(data.length(), mSProxy->CountUnreadBytes());
// don't need to read 0 on the first read, so start at 1 and keep going
mReadChunkSize = 1;
NR_ASYNC_WAIT(mSProxy,
NR_ASYNC_WAIT_READ,
&NrSocketProxyTest::readable_cb,
this);
// start callbacks
mSProxy->OnRead(std::move(mEmptyArray));
ASSERT_EQ(data.length(), mData.Length());
ASSERT_EQ(data, DataString());
}
TEST_F(ProxyTunnelSocketTest, TestConnectProxyGarbageResponse) {
int r = nr_socket_connect(nr_socket_, &remote_addr_);
ASSERT_EQ(0, r);
TEST_F(NrSocketProxyTest, TestReadConsumeReadDrain) {
std::string data;
// ~26kb total; should be even
const int kCount = 512;
socket_impl_->SetReadBuffer(reinterpret_cast<const uint8_t *>(kGarbageMessage.c_str()),
kGarbageMessage.size());
// there's some division by 2 here so check that kCount is even
ASSERT_EQ(0, kCount % 2);
char buf[4096];
size_t read = 0;
r = nr_socket_read(nr_socket_, buf, sizeof(buf), &read, 0);
ASSERT_EQ(0ul, read);
for(int i = 0; i < kCount; ++i) {
data += kHelloMessage;
nsTArray<uint8_t> array;
array.AppendElements(kHelloMessage.c_str(), kHelloMessage.length());
mSProxy->OnRead(std::move(array));
}
// read half at first
mReadAllowance = kCount / 2 * kHelloMessage.length();
// start by reading 1 byte
mReadChunkSize = 1;
NR_ASYNC_WAIT(mSProxy,
NR_ASYNC_WAIT_READ,
&NrSocketProxyTest::readable_cb,
this);
mSProxy->OnRead(std::move(mEmptyArray));
ASSERT_EQ(data.length() / 2, mSProxy->CountUnreadBytes());
ASSERT_EQ(data.length() / 2, mData.Length());
// fill read buffer back up
for(int i = 0; i < kCount / 2; ++i) {
data += kHelloMessage;
nsTArray<uint8_t> array;
array.AppendElements(kHelloMessage.c_str(), kHelloMessage.length());
mSProxy->OnRead(std::move(array));
}
// remove read limit
mReadAllowance = -1;
// used entire read allowance so we need to setup a new await
NR_ASYNC_WAIT(mSProxy,
NR_ASYNC_WAIT_READ,
&NrSocketProxyTest::readable_cb,
this);
// start callbacks
mSProxy->OnRead(std::move(mEmptyArray));
ASSERT_EQ(data.length(), mData.Length());
ASSERT_EQ(data, DataString());
}

Просмотреть файл

@ -0,0 +1,707 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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/. */
#include <algorithm>
#include <mutex>
#include "mozilla/net/WebrtcProxyChannel.h"
#include "mozilla/net/WebrtcProxyChannelCallback.h"
#include "nsISocketTransport.h"
#define GTEST_HAS_RTTI 0
#include "gtest/gtest.h"
#include "gtest/Helpers.h"
#include "gtest_utils.h"
static const uint32_t kDefaultTestTimeout = 2000;
static const char kReadData[] = "Hello, World!";
static const size_t kReadDataLength = sizeof(kReadData) - 1;
static const std::string kReadDataString = std::string(kReadData,
kReadDataLength);
static int kDataLargeOuterLoopCount = 128;
static int kDataLargeInnerLoopCount = 1024;
namespace mozilla {
using namespace net;
using namespace testing;
class WebrtcProxyChannelTestCallback;
class FakeSocketTransportProvider : public nsISocketTransport
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
// nsISocketTransport
NS_IMETHOD GetHost(nsACString & aHost) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD GetPort(int32_t *aPort) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD GetScriptableOriginAttributes(JSContext* cx, JS::MutableHandleValue aOriginAttributes) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD SetScriptableOriginAttributes(JSContext* cx, JS::HandleValue aOriginAttributes) override { MOZ_ASSERT(false); return NS_OK; }
virtual nsresult GetOriginAttributes(mozilla::OriginAttributes *_retval) override { MOZ_ASSERT(false); return NS_OK; }
virtual nsresult SetOriginAttributes(const mozilla::OriginAttributes & aOriginAttrs) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD GetPeerAddr(mozilla::net::NetAddr *_retval) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD GetSelfAddr(mozilla::net::NetAddr *_retval) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD Bind(mozilla::net::NetAddr *aLocalAddr) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD GetScriptablePeerAddr(nsINetAddr * *_retval) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD GetScriptableSelfAddr(nsINetAddr * *_retval) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD GetSecurityInfo(nsISupports * *aSecurityInfo) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD GetSecurityCallbacks(nsIInterfaceRequestor * *aSecurityCallbacks) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD SetSecurityCallbacks(nsIInterfaceRequestor *aSecurityCallbacks) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD IsAlive(bool *_retval) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD GetTimeout(uint32_t aType, uint32_t *_retval) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD SetTimeout(uint32_t aType, uint32_t aValue) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD SetReuseAddrPort(bool reuseAddrPort) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD GetConnectionFlags(uint32_t *aConnectionFlags) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD SetConnectionFlags(uint32_t aConnectionFlags) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD GetTlsFlags(uint32_t *aTlsFlags) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD SetTlsFlags(uint32_t aTlsFlags) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD GetQoSBits(uint8_t *aQoSBits) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD SetQoSBits(uint8_t aQoSBits) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD GetRecvBufferSize(uint32_t *aRecvBufferSize) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD GetSendBufferSize(uint32_t *aSendBufferSize) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD GetKeepaliveEnabled(bool *aKeepaliveEnabled) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD SetKeepaliveEnabled(bool aKeepaliveEnabled) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD SetKeepaliveVals(int32_t keepaliveIdleTime, int32_t keepaliveRetryInterval) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD SetFastOpenCallback(mozilla::net::TCPFastOpen *aFastOpen) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD GetFirstRetryError(nsresult *aFirstRetryError) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD GetResetIPFamilyPreference(bool *aResetIPFamilyPreference) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD GetEsniUsed(bool *aEsniUsed) override { MOZ_ASSERT(false); return NS_OK; }
// nsITransport
NS_IMETHOD OpenInputStream(uint32_t aFlags, uint32_t aSegmentSize, uint32_t aSegmentCount, nsIInputStream * *_retval) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD OpenOutputStream(uint32_t aFlags, uint32_t aSegmentSize, uint32_t aSegmentCount, nsIOutputStream * *_retval) override { MOZ_ASSERT(false); return NS_OK; }
NS_IMETHOD SetEventSink(nsITransportEventSink *aSink, nsIEventTarget *aEventTarget) override { MOZ_ASSERT(false); return NS_OK; }
// fake except for these methods which are OK to call
// nsISocketTransport
NS_IMETHOD SetRecvBufferSize(uint32_t aRecvBufferSize) override
{ return NS_OK; }
NS_IMETHOD SetSendBufferSize(uint32_t aSendBufferSize) override
{ return NS_OK; }
// nsITransport
NS_IMETHOD Close(nsresult aReason) override { return NS_OK; }
protected:
virtual ~FakeSocketTransportProvider() = default;
};
NS_IMPL_ISUPPORTS(FakeSocketTransportProvider,
nsISocketTransport,
nsITransport)
// Implements some common elements to WebrtcProxyChannelTestOutputStream and
// WebrtcProxyChannelTestInputStream.
class WebrtcProxyChannelTestStream
{
public:
WebrtcProxyChannelTestStream();
void Fail() { mMustFail = true; }
size_t DataLength();
template <typename T> void AppendElements(const T* aBuffer, size_t aLength);
protected:
virtual ~WebrtcProxyChannelTestStream() = default;
nsTArray<uint8_t> mData;
std::mutex mDataMutex;
bool mMustFail;
};
WebrtcProxyChannelTestStream::WebrtcProxyChannelTestStream()
: mMustFail(false) {}
template <typename T>
void
WebrtcProxyChannelTestStream::AppendElements(const T* aBuffer, size_t aLength)
{
std::lock_guard<std::mutex> guard(mDataMutex);
mData.AppendElements(aBuffer, aLength);
}
size_t
WebrtcProxyChannelTestStream::DataLength()
{
std::lock_guard<std::mutex> guard(mDataMutex);
return mData.Length();
}
class WebrtcProxyChannelTestInputStream : public nsIAsyncInputStream,
public WebrtcProxyChannelTestStream
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIASYNCINPUTSTREAM
NS_DECL_NSIINPUTSTREAM
WebrtcProxyChannelTestInputStream()
: mMaxReadSize(1024 * 1024)
, mAllowCallbacks(false) {}
void DoCallback();
void CallCallback(const nsCOMPtr<nsIInputStreamCallback>& aCallback);
void AllowCallbacks() { mAllowCallbacks = true; }
size_t mMaxReadSize;
protected:
virtual ~WebrtcProxyChannelTestInputStream() = default;
private:
nsCOMPtr<nsIInputStreamCallback> mCallback;
nsCOMPtr<nsIEventTarget> mCallbackTarget;
bool mAllowCallbacks;
};
NS_IMPL_ISUPPORTS(WebrtcProxyChannelTestInputStream,
nsIAsyncInputStream,
nsIInputStream)
nsresult
WebrtcProxyChannelTestInputStream::AsyncWait(nsIInputStreamCallback *aCallback,
uint32_t aFlags,
uint32_t aRequestedCount,
nsIEventTarget *aEventTarget)
{
MOZ_ASSERT(!aEventTarget, "no event target should be set");
mCallback = aCallback;
mCallbackTarget = NS_GetCurrentThread();
if (mAllowCallbacks && DataLength() > 0) {
DoCallback();
}
return NS_OK;
}
nsresult
WebrtcProxyChannelTestInputStream::CloseWithStatus(nsresult aStatus)
{
return Close();
}
nsresult
WebrtcProxyChannelTestInputStream::Close()
{
return NS_OK;
}
nsresult
WebrtcProxyChannelTestInputStream::Available(uint64_t* aAvailable)
{
*aAvailable = DataLength();
return NS_OK;
}
nsresult
WebrtcProxyChannelTestInputStream::Read(char* aBuffer,
uint32_t aCount,
uint32_t* aRead)
{
std::lock_guard<std::mutex> guard(mDataMutex);
if (mMustFail) {
return NS_ERROR_FAILURE;
}
*aRead = std::min({ (size_t)aCount, mData.Length(), mMaxReadSize });
memcpy(aBuffer, mData.Elements(), *aRead);
mData.RemoveElementsAt(0, *aRead);
return *aRead > 0 ? NS_OK : NS_BASE_STREAM_WOULD_BLOCK;
}
nsresult
WebrtcProxyChannelTestInputStream::ReadSegments(nsWriteSegmentFun aWriter,
void *aClosure,
uint32_t aCount,
uint32_t *_retval)
{
MOZ_ASSERT(false);
return NS_OK;
}
nsresult
WebrtcProxyChannelTestInputStream::IsNonBlocking(bool* aIsNonBlocking)
{
*aIsNonBlocking = true;
return NS_OK;
}
void
WebrtcProxyChannelTestInputStream::CallCallback(
const nsCOMPtr<nsIInputStreamCallback>& aCallback)
{
aCallback->OnInputStreamReady(this);
}
void
WebrtcProxyChannelTestInputStream::DoCallback()
{
if (mCallback) {
mCallbackTarget->Dispatch(
NewRunnableMethod<const nsCOMPtr<nsIInputStreamCallback>&>(
"WebrtcProxyChannelTestInputStream::DoCallback",
this,
&WebrtcProxyChannelTestInputStream::CallCallback,
std::move(mCallback)));
mCallbackTarget = nullptr;
}
}
class WebrtcProxyChannelTestOutputStream : public nsIAsyncOutputStream,
public WebrtcProxyChannelTestStream
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIASYNCOUTPUTSTREAM
NS_DECL_NSIOUTPUTSTREAM
WebrtcProxyChannelTestOutputStream()
: mMaxWriteSize(1024 * 1024) {}
void DoCallback();
void CallCallback(const nsCOMPtr<nsIOutputStreamCallback>& aCallback);
const std::string DataString();
uint32_t mMaxWriteSize;
protected:
virtual ~WebrtcProxyChannelTestOutputStream() = default;
private:
nsCOMPtr<nsIOutputStreamCallback> mCallback;
nsCOMPtr<nsIEventTarget> mCallbackTarget;
};
NS_IMPL_ISUPPORTS(WebrtcProxyChannelTestOutputStream,
nsIAsyncOutputStream,
nsIOutputStream)
nsresult
WebrtcProxyChannelTestOutputStream::AsyncWait(
nsIOutputStreamCallback *aCallback,
uint32_t aFlags,
uint32_t aRequestedCount,
nsIEventTarget *aEventTarget)
{
MOZ_ASSERT(!aEventTarget, "no event target should be set");
mCallback = aCallback;
mCallbackTarget = NS_GetCurrentThread();
return NS_OK;
}
nsresult
WebrtcProxyChannelTestOutputStream::CloseWithStatus(nsresult aStatus)
{
return Close();
}
nsresult
WebrtcProxyChannelTestOutputStream::Close()
{
return NS_OK;
}
nsresult
WebrtcProxyChannelTestOutputStream::Flush()
{
return NS_OK;
}
nsresult
WebrtcProxyChannelTestOutputStream::Write(const char* aBuffer,
uint32_t aCount,
uint32_t* aWrote)
{
if (mMustFail) {
return NS_ERROR_FAILURE;
}
*aWrote = std::min(aCount, mMaxWriteSize);
AppendElements(aBuffer, *aWrote);
return NS_OK;
}
nsresult
WebrtcProxyChannelTestOutputStream::WriteSegments(nsReadSegmentFun aReader,
void *aClosure,
uint32_t aCount,
uint32_t *_retval)
{
MOZ_ASSERT(false);
return NS_OK;
}
nsresult
WebrtcProxyChannelTestOutputStream::WriteFrom(
nsIInputStream *aFromStream,
uint32_t aCount,
uint32_t *_retval)
{
MOZ_ASSERT(false);
return NS_OK;
}
nsresult
WebrtcProxyChannelTestOutputStream::IsNonBlocking(bool* aIsNonBlocking)
{
*aIsNonBlocking = true;
return NS_OK;
}
void
WebrtcProxyChannelTestOutputStream::CallCallback(
const nsCOMPtr<nsIOutputStreamCallback>& aCallback)
{
aCallback->OnOutputStreamReady(this);
}
void
WebrtcProxyChannelTestOutputStream::DoCallback()
{
if (mCallback) {
mCallbackTarget->Dispatch(
NewRunnableMethod<const nsCOMPtr<nsIOutputStreamCallback>&>(
"WebrtcProxyChannelTestOutputStream::CallCallback",
this,
&WebrtcProxyChannelTestOutputStream::CallCallback,
std::move(mCallback)));
mCallbackTarget = nullptr;
}
}
const std::string
WebrtcProxyChannelTestOutputStream::DataString()
{
std::lock_guard<std::mutex> guard(mDataMutex);
return std::string((char*)mData.Elements(), mData.Length());
}
// Fake as in not the real WebrtcProxyChannel but real enough
class FakeWebrtcProxyChannel : public WebrtcProxyChannel
{
public:
explicit FakeWebrtcProxyChannel(WebrtcProxyChannelCallback* aCallback)
: WebrtcProxyChannel(nullptr, aCallback) {}
protected:
virtual ~FakeWebrtcProxyChannel() = default;
void InvokeOnClose(nsresult aReason) override;
void InvokeOnConnected() override;
void InvokeOnRead(nsTArray<uint8_t>&& aReadData) override;
};
void
FakeWebrtcProxyChannel::InvokeOnClose(nsresult aReason)
{
mProxyCallbacks->OnClose(aReason);
}
void
FakeWebrtcProxyChannel::InvokeOnConnected()
{
mProxyCallbacks->OnConnected();
}
void
FakeWebrtcProxyChannel::InvokeOnRead(nsTArray<uint8_t>&& aReadData)
{
mProxyCallbacks->OnRead(std::move(aReadData));
}
class WebrtcProxyChannelTest : public MtransportTest
{
public:
WebrtcProxyChannelTest()
: MtransportTest()
, mSocketThread(nullptr)
, mSocketTransport(nullptr)
, mInputStream(nullptr)
, mOutputStream(nullptr)
, mChannel(nullptr)
, mCallback(nullptr)
, mOnCloseCalled(false)
, mOnConnectedCalled(false) {}
// WebrtcProxyChannelCallback forwards from mCallback
void OnClose(nsresult aReason);
void OnConnected();
void OnRead(nsTArray<uint8_t>&& aReadData);
void SetUp() override;
void TearDown() override;
void DoTransportAvailable();
const std::string ReadDataAsString();
const std::string GetDataLarge();
nsCOMPtr<nsIEventTarget> mSocketThread;
nsCOMPtr<nsISocketTransport> mSocketTransport;
RefPtr<WebrtcProxyChannelTestInputStream> mInputStream;
RefPtr<WebrtcProxyChannelTestOutputStream> mOutputStream;
RefPtr<FakeWebrtcProxyChannel> mChannel;
RefPtr<WebrtcProxyChannelTestCallback> mCallback;
bool mOnCloseCalled;
bool mOnConnectedCalled;
size_t ReadDataLength();
template<typename T> void AppendReadData(const T* aBuffer, size_t aLength);
private:
nsTArray<uint8_t> mReadData;
std::mutex mReadDataMutex;
};
class WebrtcProxyChannelTestCallback : public WebrtcProxyChannelCallback
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebrtcProxyChannelTestCallback,
override)
explicit WebrtcProxyChannelTestCallback(WebrtcProxyChannelTest* aTest)
: mTest(aTest) {}
// WebrtcProxyChannelCallback
void OnClose(nsresult aReason) override;
void OnConnected() override;
void OnRead(nsTArray<uint8_t>&& aReadData) override;
protected:
virtual ~WebrtcProxyChannelTestCallback() = default;
private:
WebrtcProxyChannelTest* mTest;
};
void
WebrtcProxyChannelTest::SetUp()
{
nsresult rv;
// WebrtcProxyChannel's threading model is the same as mtransport
// all socket operations are done on the socket thread
// callbacks are invoked on the main thread
mSocketThread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
ASSERT_TRUE(NS_SUCCEEDED(rv));
mSocketTransport = new FakeSocketTransportProvider();
mInputStream = new WebrtcProxyChannelTestInputStream();
mOutputStream = new WebrtcProxyChannelTestOutputStream();
mCallback = new WebrtcProxyChannelTestCallback(this);
mChannel = new FakeWebrtcProxyChannel(mCallback.get());
}
void
WebrtcProxyChannelTest::TearDown()
{
}
// WebrtcProxyChannelCallback
void
WebrtcProxyChannelTest::OnRead(nsTArray<uint8_t>&& aReadData)
{
AppendReadData(aReadData.Elements(), aReadData.Length());
}
void
WebrtcProxyChannelTest::OnConnected()
{
mOnConnectedCalled = true;
}
void
WebrtcProxyChannelTest::OnClose(nsresult aReason)
{
mOnCloseCalled = true;
}
void
WebrtcProxyChannelTest::DoTransportAvailable()
{
if (!mSocketThread->IsOnCurrentThread()) {
mSocketThread->Dispatch(
NS_NewRunnableFunction(
"DoTransportAvailable",
[this]() -> void {
nsresult rv;
rv = mChannel->OnTransportAvailable(mSocketTransport,
mInputStream,
mOutputStream);
ASSERT_EQ(NS_OK, rv);
}));
} else {
// should always be called on the main thread
MOZ_ASSERT(0);
}
}
const std::string
WebrtcProxyChannelTest::ReadDataAsString()
{
std::lock_guard<std::mutex> guard(mReadDataMutex);
return std::string((char*)mReadData.Elements(), mReadData.Length());
}
const std::string
WebrtcProxyChannelTest::GetDataLarge()
{
std::string data;
for(int i = 0; i < kDataLargeOuterLoopCount * kDataLargeInnerLoopCount; ++i) {
data += kReadData;
}
return data;
}
template<typename T>
void
WebrtcProxyChannelTest::AppendReadData(const T* aBuffer, size_t aLength)
{
std::lock_guard<std::mutex> guard(mReadDataMutex);
mReadData.AppendElements(aBuffer, aLength);
}
size_t
WebrtcProxyChannelTest::ReadDataLength()
{
std::lock_guard<std::mutex> guard(mReadDataMutex);
return mReadData.Length();
}
void
WebrtcProxyChannelTestCallback::OnClose(nsresult aReason)
{
mTest->OnClose(aReason);
}
void
WebrtcProxyChannelTestCallback::OnConnected()
{
mTest->OnConnected();
}
void
WebrtcProxyChannelTestCallback::OnRead(nsTArray<uint8_t>&& aReadData)
{
mTest->OnRead(std::move(aReadData));
}
} // namespace mozilla
typedef mozilla::WebrtcProxyChannelTest WebrtcProxyChannelTest;
TEST_F(WebrtcProxyChannelTest, SetUp) {}
TEST_F(WebrtcProxyChannelTest, TransportAvailable) {
DoTransportAvailable();
ASSERT_TRUE_WAIT(mOnConnectedCalled, kDefaultTestTimeout);
}
TEST_F(WebrtcProxyChannelTest, Read) {
DoTransportAvailable();
ASSERT_TRUE_WAIT(mOnConnectedCalled, kDefaultTestTimeout);
mInputStream->AppendElements(kReadData, kReadDataLength);
mInputStream->DoCallback();
ASSERT_TRUE_WAIT(ReadDataAsString() == kReadDataString, kDefaultTestTimeout);
}
TEST_F(WebrtcProxyChannelTest, Write) {
DoTransportAvailable();
ASSERT_TRUE_WAIT(mOnConnectedCalled, kDefaultTestTimeout);
nsTArray<uint8_t> data;
data.AppendElements(kReadData, kReadDataLength);
mChannel->Write(std::move(data));
ASSERT_TRUE_WAIT(mChannel->CountUnwrittenBytes() == kReadDataLength,
kDefaultTestTimeout);
mOutputStream->DoCallback();
ASSERT_TRUE_WAIT(mOutputStream->DataString() == kReadDataString,
kDefaultTestTimeout);
}
TEST_F(WebrtcProxyChannelTest, ReadFail) {
DoTransportAvailable();
ASSERT_TRUE_WAIT(mOnConnectedCalled, kDefaultTestTimeout);
mInputStream->AppendElements(kReadData, kReadDataLength);
mInputStream->Fail();
mInputStream->DoCallback();
ASSERT_TRUE_WAIT(mOnCloseCalled, kDefaultTestTimeout);
ASSERT_EQ(0U, ReadDataLength());
}
TEST_F(WebrtcProxyChannelTest, WriteFail) {
DoTransportAvailable();
ASSERT_TRUE_WAIT(mOnConnectedCalled, kDefaultTestTimeout);
nsTArray<uint8_t> array;
array.AppendElements(kReadData, kReadDataLength);
mChannel->Write(std::move(array));
ASSERT_TRUE_WAIT(mChannel->CountUnwrittenBytes() == kReadDataLength,
kDefaultTestTimeout);
mOutputStream->Fail();
mOutputStream->DoCallback();
ASSERT_TRUE_WAIT(mOnCloseCalled, kDefaultTestTimeout);
ASSERT_EQ(0U, mOutputStream->DataLength());
}
TEST_F(WebrtcProxyChannelTest, ReadLarge) {
DoTransportAvailable();
ASSERT_TRUE_WAIT(mOnConnectedCalled, kDefaultTestTimeout);
const std::string data = GetDataLarge();
mInputStream->AppendElements(data.c_str(), data.length());
// make sure reading loops more than once
mInputStream->mMaxReadSize = 3072;
mInputStream->AllowCallbacks();
mInputStream->DoCallback();
ASSERT_TRUE_WAIT(ReadDataAsString() == data, kDefaultTestTimeout);
}
TEST_F(WebrtcProxyChannelTest, WriteLarge) {
DoTransportAvailable();
ASSERT_TRUE_WAIT(mOnConnectedCalled, kDefaultTestTimeout);
const std::string data = GetDataLarge();
for(int i = 0; i < kDataLargeOuterLoopCount; ++i) {
nsTArray<uint8_t> array;
int chunkSize = kReadDataString.length() * kDataLargeInnerLoopCount;
int offset = i * chunkSize;
array.AppendElements(data.c_str() + offset, chunkSize);
mChannel->Write(std::move(array));
}
ASSERT_TRUE_WAIT(mChannel->CountUnwrittenBytes() == data.length(),
kDefaultTestTimeout);
// make sure writing loops more than once per write request
mOutputStream->mMaxWriteSize = 1024;
mOutputStream->DoCallback();
ASSERT_TRUE_WAIT(mOutputStream->DataString() == data, kDefaultTestTimeout);
}

Просмотреть файл

@ -237,7 +237,7 @@ RefPtr<NrSocketBase> TestNrSocket::create_external_socket(
}
RefPtr<NrSocketBase> external_socket;
r = NrSocketBase::CreateSocket(&nat_external_addr, &external_socket);
r = NrSocketBase::CreateSocket(&nat_external_addr, &external_socket, nullptr);
if (r) {
r_log(LOG_GENERIC,LOG_CRIT, "%s: Failure in NrSocket::create: %d",
@ -253,7 +253,7 @@ int TestNrSocket::create(nr_transport_addr *addr) {
tls_ = true;
}
return NrSocketBase::CreateSocket(addr, &internal_socket_);
return NrSocketBase::CreateSocket(addr, &internal_socket_, nullptr);
}
int TestNrSocket::getaddr(nr_transport_addr *addrp) {

Просмотреть файл

@ -67,8 +67,6 @@
"./src/net/nr_resolver.h",
"./src/net/nr_socket_wrapper.c",
"./src/net/nr_socket_wrapper.h",
"./src/net/nr_proxy_tunnel.c",
"./src/net/nr_proxy_tunnel.h",
"./src/net/nr_socket.c",
"./src/net/nr_socket.h",
#"./src/net/nr_socket_local.c",

Просмотреть файл

@ -1,686 +0,0 @@
/*
Copyright (c) 2007, Adobe Systems, Incorporated
Copyright (c) 2013, Mozilla
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Adobe Systems, Network Resonance, Mozilla nor
the names of its contributors may be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <nr_api.h>
#include <assert.h>
#include "nr_proxy_tunnel.h"
#define MAX_HTTP_CONNECT_ADDR_SIZE 256
#define MAX_HTTP_CONNECT_BUFFER_SIZE 1024
#define MAX_ALPN_LENGTH 64
#ifndef CRLF
#define CRLF "\r\n"
#endif
#define END_HEADERS CRLF CRLF
typedef enum {
PROXY_TUNNEL_NONE=0,
PROXY_TUNNEL_REQUESTED,
PROXY_TUNNEL_CONNECTED,
PROXY_TUNNEL_CLOSED,
PROXY_TUNNEL_FAILED
} nr_socket_proxy_tunnel_state;
typedef struct nr_socket_proxy_tunnel_ {
nr_proxy_tunnel_config *config;
nr_socket *inner;
nr_transport_addr remote_addr;
nr_socket_proxy_tunnel_state state;
char buffer[MAX_HTTP_CONNECT_BUFFER_SIZE];
size_t buffered_bytes;
void *resolver_handle;
} nr_socket_proxy_tunnel;
typedef struct nr_socket_wrapper_factory_proxy_tunnel_ {
nr_proxy_tunnel_config *config;
} nr_socket_wrapper_factory_proxy_tunnel;
static int nr_socket_proxy_tunnel_destroy(void **objpp);
static int nr_socket_proxy_tunnel_getfd(void *obj, NR_SOCKET *fd);
static int nr_socket_proxy_tunnel_getaddr(void *obj, nr_transport_addr *addrp);
static int nr_socket_proxy_tunnel_connect(void *sock, nr_transport_addr *addr);
static int nr_socket_proxy_tunnel_write(void *obj, const void *msg, size_t len, size_t *written);
static int nr_socket_proxy_tunnel_read(void *obj, void * restrict buf, size_t maxlen, size_t *len);
static int nr_socket_proxy_tunnel_close(void *obj);
int nr_proxy_tunnel_config_copy(nr_proxy_tunnel_config *config, nr_proxy_tunnel_config **copypp);
int nr_socket_wrapper_factory_proxy_tunnel_wrap(void *obj,
nr_socket *inner,
nr_socket **socketpp);
int nr_socket_wrapper_factory_proxy_tunnel_destroy(void **objpp);
static nr_socket_vtbl nr_socket_proxy_tunnel_vtbl={
1,
nr_socket_proxy_tunnel_destroy,
0,
0,
nr_socket_proxy_tunnel_getfd,
nr_socket_proxy_tunnel_getaddr,
nr_socket_proxy_tunnel_connect,
nr_socket_proxy_tunnel_write,
nr_socket_proxy_tunnel_read,
nr_socket_proxy_tunnel_close
};
static int send_http_connect(nr_socket_proxy_tunnel *sock)
{
int r, _status;
int port;
int printed;
char addr[MAX_HTTP_CONNECT_ADDR_SIZE];
char mesg[MAX_HTTP_CONNECT_ADDR_SIZE + MAX_ALPN_LENGTH + 128];
size_t offset = 0;
size_t bytes_sent;
r_log(LOG_GENERIC,LOG_DEBUG,"send_http_connect");
if ((r=nr_transport_addr_get_port(&sock->remote_addr, &port))) {
ABORT(r);
}
if ((r=nr_transport_addr_get_addrstring(&sock->remote_addr, addr, sizeof(addr)))) {
ABORT(r);
}
printed = snprintf(mesg + offset, sizeof(mesg) - offset,
"CONNECT %s:%d HTTP/1.0", addr, port);
offset += printed;
if (printed < 0 || (offset >= sizeof(mesg))) {
ABORT(R_FAILED);
}
if (sock->config->alpn) {
printed = snprintf(mesg + offset, sizeof(mesg) - offset,
CRLF "ALPN: %s", sock->config->alpn);
offset += printed;
if (printed < 0 || (offset >= sizeof(mesg))) {
ABORT(R_FAILED);
}
}
if (offset + sizeof(END_HEADERS) >= sizeof(mesg)) {
ABORT(R_FAILED);
}
memcpy(mesg + offset, END_HEADERS, strlen(END_HEADERS));
offset += strlen(END_HEADERS);
if ((r=nr_socket_write(sock->inner, mesg, offset, &bytes_sent, 0))) {
ABORT(r);
}
if (bytes_sent < offset) {
/* TODO(bug 1116583): buffering and wait for */
r_log(LOG_GENERIC,LOG_DEBUG,"send_http_connect should be buffering %lu", (unsigned long)bytes_sent);
ABORT(R_IO_ERROR);
}
sock->state = PROXY_TUNNEL_REQUESTED;
_status = 0;
abort:
return(_status);
}
static char *find_http_terminator(char *response, size_t len)
{
char *term = response;
char *end = response + len;
int N = strlen(END_HEADERS);
for (; term = memchr(term, '\r', end - term); ++term) {
if (end - term >= N && memcmp(term, END_HEADERS, N) == 0) {
return term;
}
}
return NULL;
}
static int parse_http_response(char *begin, char *end, unsigned int *status)
{
size_t len = end - begin;
char response[MAX_HTTP_CONNECT_BUFFER_SIZE + 1];
// len should *never* be greater than nr_socket_proxy_tunnel::buffered_bytes.
// Which in turn should never be greater nr_socket_proxy_tunnel::buffer size.
assert(len <= MAX_HTTP_CONNECT_BUFFER_SIZE);
if (len > MAX_HTTP_CONNECT_BUFFER_SIZE) {
return R_BAD_DATA;
}
memcpy(response, begin, len);
response[len] = '\0';
// http://www.rfc-editor.org/rfc/rfc7230.txt
// status-line = HTTP-version SP status-code SP reason-phrase CRLF
// HTTP-version = HTTP-name "/" DIGIT "." DIGIT
// HTTP-name = "HTTP" ; "HTTP", case-sensitive
// status-code = 3DIGIT
if (sscanf(response, "HTTP/%*u.%*u %u", status) != 1) {
r_log(LOG_GENERIC,LOG_WARNING,"parse_http_response failed to find status (%s)", response);
return R_BAD_DATA;
}
return 0;
}
static int nr_socket_proxy_tunnel_destroy(void **objpp)
{
nr_socket_proxy_tunnel *sock;
r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_destroy");
if (!objpp || !*objpp)
return 0;
sock = (nr_socket_proxy_tunnel *)*objpp;
*objpp = 0;
if (sock->resolver_handle) {
nr_resolver_cancel(sock->config->resolver, sock->resolver_handle);
}
nr_proxy_tunnel_config_destroy(&sock->config);
nr_socket_destroy(&sock->inner);
RFREE(sock);
return 0;
}
static int nr_socket_proxy_tunnel_getfd(void *obj, NR_SOCKET *fd)
{
nr_socket_proxy_tunnel *sock = (nr_socket_proxy_tunnel *)obj;
r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_getfd");
return nr_socket_getfd(sock->inner, fd);
}
static int nr_socket_proxy_tunnel_getaddr(void *obj, nr_transport_addr *addrp)
{
nr_socket_proxy_tunnel *sock = (nr_socket_proxy_tunnel *)obj;
r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_getaddr");
return nr_socket_getaddr(sock->inner, addrp);
}
static int nr_socket_proxy_tunnel_resolved_cb(void *obj, nr_transport_addr *proxy_addr)
{
int r, _status;
nr_socket_proxy_tunnel *sock = (nr_socket_proxy_tunnel*)obj;
r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_resolved_cb");
/* Mark the socket resolver as completed */
sock->resolver_handle = 0;
if (proxy_addr) {
r_log(LOG_GENERIC,LOG_DEBUG,"Resolved proxy address %s -> %s",
sock->config->proxy_host, proxy_addr->as_string);
}
else {
r_log(LOG_GENERIC,LOG_WARNING,"Failed to resolve proxy %s",
sock->config->proxy_host);
/* TODO: Mozilla bug 1241758: because of the callback the return value goes
* nowhere, so we can't mark the candidate as failed, so everything depends
* on the overall timeouts in this case. */
sock->state = PROXY_TUNNEL_FAILED;
ABORT(R_NOT_FOUND);
}
if ((r=nr_socket_connect(sock->inner, proxy_addr))) {
ABORT(r);
}
_status = 0;
abort:
return(_status);
}
int nr_socket_proxy_tunnel_connect(void *obj, nr_transport_addr *addr)
{
int r, _status;
int has_addr;
nr_socket_proxy_tunnel *sock = (nr_socket_proxy_tunnel*)obj;
nr_proxy_tunnel_config *config = sock->config;
nr_transport_addr proxy_addr, local_addr;
nr_resolver_resource resource;
if ((r=nr_transport_addr_copy(&sock->remote_addr, addr))) {
ABORT(r);
}
assert(config->proxy_host);
/* Check if the proxy_host is already an IP address */
has_addr = !nr_str_port_to_transport_addr(config->proxy_host,
config->proxy_port, IPPROTO_TCP, &proxy_addr);
r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_connect: %s", config->proxy_host);
if (!has_addr && !config->resolver) {
r_log(LOG_GENERIC,LOG_ERR,"nr_socket_proxy_tunnel_connect name resolver not configured");
ABORT(R_NOT_FOUND);
}
if (!has_addr) {
resource.domain_name=config->proxy_host;
resource.port=config->proxy_port;
resource.stun_turn=NR_RESOLVE_PROTOCOL_TURN;
resource.transport_protocol=IPPROTO_TCP;
if ((r=nr_socket_getaddr(sock->inner, &local_addr))) {
r_log(LOG_GENERIC,LOG_ERR,"nr_socket_proxy_tunnel_connect failed to get local address");
ABORT(r);
}
switch(local_addr.ip_version) {
case NR_IPV4:
resource.address_family=AF_INET;
break;
case NR_IPV6:
resource.address_family=AF_INET6;
break;
default:
ABORT(R_BAD_ARGS);
}
r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_connect: nr_resolver_resolve");
if ((r=nr_resolver_resolve(config->resolver, &resource,
nr_socket_proxy_tunnel_resolved_cb, (void *)sock, &sock->resolver_handle))) {
r_log(LOG_GENERIC,LOG_ERR,"Could not invoke DNS resolver");
ABORT(r);
}
ABORT(R_WOULDBLOCK);
}
if ((r=nr_socket_connect(sock->inner, &proxy_addr))) {
ABORT(r);
}
_status=0;
abort:
return(_status);
}
int nr_socket_proxy_tunnel_write(void *obj, const void *msg, size_t len,
size_t *written)
{
int r, _status;
nr_socket_proxy_tunnel *sock = (nr_socket_proxy_tunnel*)obj;
r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_write");
if (sock->state >= PROXY_TUNNEL_CLOSED) {
return R_FAILED;
}
if (sock->state == PROXY_TUNNEL_NONE) {
if ((r=send_http_connect(sock))) {
ABORT(r);
}
}
if (sock->state != PROXY_TUNNEL_CONNECTED) {
return R_WOULDBLOCK;
}
if ((r=nr_socket_write(sock->inner, msg, len, written, 0))) {
ABORT(r);
}
_status=0;
abort:
return(_status);
}
int nr_socket_proxy_tunnel_read(void *obj, void * restrict buf, size_t maxlen,
size_t *len)
{
int r, _status;
char *ptr, *http_term;
size_t bytes_read, available_buffer_len, maxlen_int;
size_t pending;
nr_socket_proxy_tunnel *sock = (nr_socket_proxy_tunnel*)obj;
unsigned int http_status;
r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_read");
*len = 0;
if (sock->state >= PROXY_TUNNEL_CLOSED) {
return R_FAILED;
}
if (sock->state == PROXY_TUNNEL_CONNECTED) {
return nr_socket_read(sock->inner, buf, maxlen, len, 0);
}
if (sock->buffered_bytes >= sizeof(sock->buffer)) {
r_log(LOG_GENERIC,LOG_ERR,"buffer filled waiting for CONNECT response");
assert(sock->buffered_bytes == sizeof(sock->buffer));
ABORT(R_INTERNAL);
}
/* Do not read more than maxlen bytes */
available_buffer_len = sizeof(sock->buffer) - sock->buffered_bytes;
maxlen_int = maxlen < available_buffer_len ? maxlen : available_buffer_len;
if ((r=nr_socket_read(sock->inner, sock->buffer + sock->buffered_bytes,
maxlen_int, &bytes_read, 0))) {
ABORT(r);
}
sock->buffered_bytes += bytes_read;
if (http_term = find_http_terminator(sock->buffer, sock->buffered_bytes)) {
if ((r = parse_http_response(sock->buffer, http_term, &http_status))) {
ABORT(r);
}
/* TODO (bug 1115934): Handle authentication challenges. */
if (http_status < 200 || http_status >= 300) {
r_log(LOG_GENERIC,LOG_ERR,"nr_socket_proxy_tunnel_read unable to connect %u",
http_status);
ABORT(R_FAILED);
}
sock->state = PROXY_TUNNEL_CONNECTED;
ptr = http_term + strlen(END_HEADERS);
pending = sock->buffered_bytes - (ptr - sock->buffer);
if (pending == 0) {
ABORT(R_WOULDBLOCK);
}
assert(pending <= maxlen);
*len = pending;
memcpy(buf, ptr, *len);
}
_status=0;
abort:
if (_status && _status != R_WOULDBLOCK) {
sock->state = PROXY_TUNNEL_FAILED;
}
return(_status);
}
int nr_socket_proxy_tunnel_close(void *obj)
{
nr_socket_proxy_tunnel *sock = (nr_socket_proxy_tunnel*)obj;
r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_close");
if (sock->resolver_handle) {
nr_resolver_cancel(sock->config->resolver, sock->resolver_handle);
sock->resolver_handle = 0;
}
sock->state = PROXY_TUNNEL_CLOSED;
return nr_socket_close(sock->inner);
}
int nr_proxy_tunnel_config_create(nr_proxy_tunnel_config **configpp)
{
int _status;
nr_proxy_tunnel_config *configp=0;
r_log(LOG_GENERIC,LOG_DEBUG,"nr_proxy_tunnel_config_create");
if (!(configp=RCALLOC(sizeof(nr_proxy_tunnel_config))))
ABORT(R_NO_MEMORY);
*configpp=configp;
_status=0;
abort:
return(_status);
}
int nr_proxy_tunnel_config_destroy(nr_proxy_tunnel_config **configpp)
{
nr_proxy_tunnel_config *configp;
r_log(LOG_GENERIC,LOG_DEBUG,"nr_proxy_tunnel_config_destroy");
if (!configpp || !*configpp)
return 0;
configp = *configpp;
*configpp = 0;
RFREE(configp->proxy_host);
RFREE(configp->alpn);
RFREE(configp);
return 0;
}
int nr_proxy_tunnel_config_set_proxy(nr_proxy_tunnel_config *config,
const char *host, UINT2 port)
{
char *hostdup;
r_log(LOG_GENERIC,LOG_DEBUG,"nr_proxy_tunnel_config_set_proxy %s %d", host, port);
if (!host) {
return R_BAD_ARGS;
}
if (!(hostdup = r_strdup(host))) {
return R_NO_MEMORY;
}
if (config->proxy_host) {
RFREE(config->proxy_host);
}
config->proxy_host = hostdup;
config->proxy_port = port;
return 0;
}
int nr_proxy_tunnel_config_set_resolver(nr_proxy_tunnel_config *config,
nr_resolver *resolver)
{
r_log(LOG_GENERIC,LOG_DEBUG,"nr_proxy_tunnel_config_set_resolver");
config->resolver = resolver;
return 0;
}
int nr_proxy_tunnel_config_set_alpn(nr_proxy_tunnel_config *config,
const char *alpn)
{
r_log(LOG_GENERIC,LOG_DEBUG,"nr_proxy_tunnel_config_set_alpn");
if (alpn && (strlen(alpn) > MAX_ALPN_LENGTH)) {
return R_BAD_ARGS;
}
if (config->alpn) {
RFREE(config->alpn);
}
config->alpn = NULL;
if (alpn) {
char *alpndup = r_strdup(alpn);
if (!alpndup) {
return R_NO_MEMORY;
}
config->alpn = alpndup;
}
return 0;
}
int nr_proxy_tunnel_config_copy(nr_proxy_tunnel_config *config, nr_proxy_tunnel_config **copypp)
{
int r,_status;
nr_proxy_tunnel_config *copy = 0;
if ((r=nr_proxy_tunnel_config_create(&copy)))
ABORT(r);
if ((r=nr_proxy_tunnel_config_set_proxy(copy, config->proxy_host, config->proxy_port)))
ABORT(r);
if ((r=nr_proxy_tunnel_config_set_resolver(copy, config->resolver)))
ABORT(r);
if ((r=nr_proxy_tunnel_config_set_alpn(copy, config->alpn)))
ABORT(r);
*copypp = copy;
_status=0;
abort:
if (_status) {
nr_proxy_tunnel_config_destroy(&copy);
}
return(_status);
}
int nr_socket_proxy_tunnel_create(nr_proxy_tunnel_config *config,
nr_socket *inner,
nr_socket **socketpp)
{
int r, _status;
nr_socket_proxy_tunnel *sock=0;
void *sockv;
r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_create");
if (!config) {
ABORT(R_BAD_ARGS);
}
if (!(sock=RCALLOC(sizeof(nr_socket_proxy_tunnel)))) {
ABORT(R_NO_MEMORY);
}
sock->inner = inner;
if ((r=nr_proxy_tunnel_config_copy(config, &sock->config)))
ABORT(r);
if ((r=nr_socket_create_int(sock, &nr_socket_proxy_tunnel_vtbl, socketpp))) {
ABORT(r);
}
r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_created");
_status=0;
abort:
if (_status) {
sockv = sock;
nr_socket_proxy_tunnel_destroy(&sockv);
}
return(_status);
}
int nr_socket_wrapper_factory_proxy_tunnel_wrap(void *obj,
nr_socket *inner,
nr_socket **socketpp)
{
nr_socket_wrapper_factory_proxy_tunnel *wrapper = (nr_socket_wrapper_factory_proxy_tunnel *)obj;
r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_wrapper_factory_proxy_tunnel_wrap");
return nr_socket_proxy_tunnel_create(wrapper->config, inner, socketpp);
}
int nr_socket_wrapper_factory_proxy_tunnel_destroy(void **objpp) {
nr_socket_wrapper_factory_proxy_tunnel *wrapper;
r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_wrapper_factory_proxy_tunnel_destroy");
if (!objpp || !*objpp)
return 0;
wrapper = (nr_socket_wrapper_factory_proxy_tunnel *)*objpp;
*objpp = 0;
nr_proxy_tunnel_config_destroy(&wrapper->config);
RFREE(wrapper);
return 0;
}
static nr_socket_wrapper_factory_vtbl proxy_tunnel_wrapper_vtbl = {
nr_socket_wrapper_factory_proxy_tunnel_wrap,
nr_socket_wrapper_factory_proxy_tunnel_destroy
};
int nr_socket_wrapper_factory_proxy_tunnel_create(nr_proxy_tunnel_config *config,
nr_socket_wrapper_factory **factory) {
int r,_status;
nr_socket_wrapper_factory_proxy_tunnel *wrapper=0;
void *wrapperv;
r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_wrapper_factory_proxy_tunnel_create");
if (!(wrapper=RCALLOC(sizeof(nr_socket_wrapper_factory_proxy_tunnel))))
ABORT(R_NO_MEMORY);
if ((r=nr_proxy_tunnel_config_copy(config, &wrapper->config)))
ABORT(r);
if ((r=nr_socket_wrapper_factory_create_int(wrapper, &proxy_tunnel_wrapper_vtbl, factory)))
ABORT(r);
_status=0;
abort:
if (_status) {
wrapperv = wrapper;
nr_socket_wrapper_factory_proxy_tunnel_destroy(&wrapperv);
}
return(_status);
}

Просмотреть файл

@ -1,70 +0,0 @@
/*
Copyright (c) 2007, Adobe Systems, Incorporated
Copyright (c) 2013, Mozilla
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Adobe Systems, Network Resonance, Mozilla nor
the names of its contributors may be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _nr_proxy_tunnel_h
#define _nr_proxy_tunnel_h
#include "nr_socket.h"
#include "nr_resolver.h"
#include "nr_socket_wrapper.h"
typedef struct nr_proxy_tunnel_config_ {
nr_resolver *resolver;
char *proxy_host;
UINT2 proxy_port;
char *alpn;
} nr_proxy_tunnel_config;
int nr_proxy_tunnel_config_create(nr_proxy_tunnel_config **config);
int nr_proxy_tunnel_config_destroy(nr_proxy_tunnel_config **config);
int nr_proxy_tunnel_config_set_proxy(nr_proxy_tunnel_config *config,
const char* host, UINT2 port);
int nr_proxy_tunnel_config_set_resolver(nr_proxy_tunnel_config *config,
nr_resolver *resolver);
int nr_proxy_tunnel_config_set_alpn(nr_proxy_tunnel_config *config,
const char *alpn);
int nr_socket_proxy_tunnel_create(nr_proxy_tunnel_config *config,
nr_socket *inner,
nr_socket **socketpp);
int nr_socket_wrapper_factory_proxy_tunnel_create(nr_proxy_tunnel_config *config,
nr_socket_wrapper_factory **factory);
#endif

Просмотреть файл

@ -267,12 +267,9 @@ MediaTransportHandler::Destroy()
}
nsresult
MediaTransportHandler::SetProxyServer(const std::string& aProxyHost,
uint16_t aProxyPort,
const std::string& aAlpnProtocols)
MediaTransportHandler::SetProxyServer(NrSocketProxyConfig&& aProxyConfig)
{
NrIceProxyServer proxyServer(aProxyHost, aProxyPort, aAlpnProtocols);
return mIceCtx->SetProxyServer(proxyServer);
return mIceCtx->SetProxyServer(std::move(aProxyConfig));
}
void

Просмотреть файл

@ -61,9 +61,7 @@ class MediaTransportHandler : public MediaTransportBase,
// We will probably be able to move the proxy lookup stuff into
// this class once we move mtransport to its own process.
nsresult SetProxyServer(const std::string& aProxyHost,
uint16_t aProxyPort,
const std::string& aAlpnProtocols);
nsresult SetProxyServer(NrSocketProxyConfig&& aProxyConfig);
void EnsureProvisionalTransport(const std::string& aTransportId,
const std::string& aLocalUfrag,

Просмотреть файл

@ -4,6 +4,7 @@
#include "CSFLog.h"
#include "nr_socket_proxy_config.h"
#include "MediaPipelineFilter.h"
#include "MediaPipeline.h"
#include "PeerConnectionImpl.h"
@ -20,9 +21,13 @@
#include "nsIContentPolicy.h"
#include "nsIProxyInfo.h"
#include "nsIProtocolProxyService.h"
#include "nsIPrincipal.h"
#include "nsProxyRelease.h"
#include "nsIScriptGlobalObject.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/PBrowserOrId.h"
#include "mozilla/dom/TabChild.h"
#include "MediaManager.h"
#include "WebrtcGmpVideoCodec.h"
@ -64,25 +69,10 @@ PeerConnectionMedia::ProtocolProxyQueryHandler::SetProxyOnPcm(
nsIProxyInfo& proxyinfo)
{
CSFLogInfo(LOGTAG, "%s: Had proxyinfo", __FUNCTION__);
nsresult rv;
nsCString httpsProxyHost;
int32_t httpsProxyPort;
rv = proxyinfo.GetHost(httpsProxyHost);
if (NS_FAILED(rv)) {
CSFLogError(LOGTAG, "%s: Failed to get proxy server host", __FUNCTION__);
return;
}
rv = proxyinfo.GetPort(&httpsProxyPort);
if (NS_FAILED(rv)) {
CSFLogError(LOGTAG, "%s: Failed to get proxy server port", __FUNCTION__);
return;
}
assert(httpsProxyPort >= 0 && httpsProxyPort < (1 << 16));
pcm_->mProxyHost = httpsProxyHost.get();
pcm_->mProxyPort = static_cast<uint16_t>(httpsProxyPort);
nsCString alpn = NS_LITERAL_CSTRING("webrtc,c-webrtc");
PBrowserOrId browser = TabChild::GetFrom(pcm_->GetWindow());
pcm_->mProxyConfig.reset(new NrSocketProxyConfig(browser, alpn));
}
NS_IMPL_ISUPPORTS(PeerConnectionMedia::ProtocolProxyQueryHandler, nsIProtocolProxyCallback)
@ -116,6 +106,7 @@ PeerConnectionMedia::PeerConnectionMedia(PeerConnectionImpl *parent)
mMainThread(mParent->GetMainThread()),
mSTSThread(mParent->GetSTSThread()),
mProxyResolveCompleted(false),
mProxyConfig(nullptr),
mLocalAddrsCompleted(false) {
}
@ -491,14 +482,14 @@ PeerConnectionMedia::GatherIfReady() {
void
PeerConnectionMedia::EnsureIceGathering_s(bool aDefaultRouteOnly) {
if (!mProxyHost.empty()) {
if (mProxyConfig) {
// Note that this could check if PrivacyRequested() is set on the PC and
// remove "webrtc" from the ALPN list. But that would only work if the PC
// was constructed with a peerIdentity constraint, not when isolated
// streams are added. If we ever need to signal to the proxy that the
// media is isolated, then we would need to restructure this code.
mTransportHandler->SetProxyServer(
mProxyHost, mProxyPort, "webrtc,c-webrtc");
mTransportHandler->SetProxyServer(std::move(*mProxyConfig));
mProxyConfig.reset();
}
// Make sure we don't call StartIceGathering if we're in e10s mode
@ -854,4 +845,9 @@ PeerConnectionMedia::AnyCodecHasPluginID(uint64_t aPluginID)
return false;
}
nsPIDOMWindowInner*
PeerConnectionMedia::GetWindow() const
{
return mParent->GetWindow();
}
} // namespace mozilla

Просмотреть файл

@ -126,6 +126,8 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
return mTransceivers;
}
nsPIDOMWindowInner* GetWindow() const;
void AlpnNegotiated_s(const std::string& aAlpn);
static void AlpnNegotiated_m(const std::string& aParentHandle,
const std::string& aAlpn);
@ -247,9 +249,8 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
// Used to track the state of the request.
bool mProxyResolveCompleted;
// Used to store the result of the request.
std::string mProxyHost;
uint16_t mProxyPort;
// Used to track proxy existence and socket proxy configuration.
std::unique_ptr<NrSocketProxyConfig> mProxyConfig;
// Used to cancel incoming stun addrs response
RefPtr<net::StunAddrsRequestChild> mStunAddrsRequest;

Просмотреть файл

@ -26,6 +26,7 @@
#include "mozilla/net/TrackingDummyChannelChild.h"
#ifdef MOZ_WEBRTC
#include "mozilla/net/StunAddrsRequestChild.h"
#include "mozilla/net/WebrtcProxyChannelChild.h"
#endif
#include "SerializedLoadContext.h"
@ -114,6 +115,26 @@ NeckoChild::DeallocPStunAddrsRequestChild(PStunAddrsRequestChild* aActor)
return true;
}
PWebrtcProxyChannelChild*
NeckoChild::AllocPWebrtcProxyChannelChild(const PBrowserOrId& browser)
{
// We don't allocate here: instead we always use IPDL constructor that takes
// an existing object
MOZ_ASSERT_UNREACHABLE("AllocPWebrtcProxyChannelChild should not be called on"
" child");
return nullptr;
}
bool
NeckoChild::DeallocPWebrtcProxyChannelChild(PWebrtcProxyChannelChild* aActor)
{
#ifdef MOZ_WEBRTC
WebrtcProxyChannelChild* child = static_cast<WebrtcProxyChannelChild*>(aActor);
child->ReleaseIPDLReference();
#endif
return true;
}
PAltDataOutputStreamChild*
NeckoChild::AllocPAltDataOutputStreamChild(
const nsCString& type,

Просмотреть файл

@ -34,6 +34,11 @@ protected:
virtual bool
DeallocPStunAddrsRequestChild(PStunAddrsRequestChild* aActor) override;
virtual PWebrtcProxyChannelChild* AllocPWebrtcProxyChannelChild(
const PBrowserOrId& browser) override;
virtual bool
DeallocPWebrtcProxyChannelChild(PWebrtcProxyChannelChild* aActor) override;
virtual PAltDataOutputStreamChild* AllocPAltDataOutputStreamChild(const nsCString& type, const int64_t& predictedSize, PHttpChannelChild* channel) override;
virtual bool DeallocPAltDataOutputStreamChild(PAltDataOutputStreamChild* aActor) override;

Просмотреть файл

@ -30,6 +30,7 @@
#include "mozilla/net/TrackingDummyChannelParent.h"
#ifdef MOZ_WEBRTC
#include "mozilla/net/StunAddrsRequestParent.h"
#include "mozilla/net/WebrtcProxyChannelParent.h"
#endif
#include "mozilla/dom/ChromeUtils.h"
#include "mozilla/dom/ContentParent.h"
@ -350,6 +351,29 @@ NeckoParent::DeallocPStunAddrsRequestParent(PStunAddrsRequestParent* aActor)
return true;
}
PWebrtcProxyChannelParent*
NeckoParent::AllocPWebrtcProxyChannelParent(const PBrowserOrId& aBrowser)
{
#ifdef MOZ_WEBRTC
RefPtr<TabParent> tab = TabParent::GetFrom(aBrowser.get_PBrowserParent());
WebrtcProxyChannelParent* parent = new WebrtcProxyChannelParent(tab);
parent->AddRef();
return parent;
#else
return nullptr;
#endif
}
bool
NeckoParent::DeallocPWebrtcProxyChannelParent(PWebrtcProxyChannelParent* aActor)
{
#ifdef MOZ_WEBRTC
WebrtcProxyChannelParent* parent = static_cast<WebrtcProxyChannelParent*>(aActor);
parent->Release();
#endif
return true;
}
PAltDataOutputStreamParent*
NeckoParent::AllocPAltDataOutputStreamParent(
const nsCString& type,

Просмотреть файл

@ -108,6 +108,12 @@ protected:
virtual bool
DeallocPStunAddrsRequestParent(PStunAddrsRequestParent* aActor) override;
virtual PWebrtcProxyChannelParent* AllocPWebrtcProxyChannelParent(
const PBrowserOrId& aBrowser) override;
virtual bool
DeallocPWebrtcProxyChannelParent(PWebrtcProxyChannelParent* aActor)
override;
virtual PAltDataOutputStreamParent* AllocPAltDataOutputStreamParent(
const nsCString& type, const int64_t& predictedSize, PHttpChannelParent* channel) override;
virtual bool DeallocPAltDataOutputStreamParent(

Просмотреть файл

@ -27,6 +27,7 @@ include protocol PParentToChildStream; //FIXME: bug #792908
include protocol PStunAddrsRequest;
include protocol PFileChannel;
include protocol PTrackingDummyChannel;
include protocol PWebrtcProxyChannel;
include IPCStream;
include URIParams;
@ -65,6 +66,7 @@ nested(upto inside_cpow) sync protocol PNecko
manages PAltDataOutputStream;
manages PStunAddrsRequest;
manages PTrackingDummyChannel;
manages PWebrtcProxyChannel;
parent:
async __delete__();
@ -133,6 +135,8 @@ parent:
async PStunAddrsRequest();
async PWebrtcProxyChannel(PBrowserOrId browser);
/**
* WebExtension-specific remote resource loading
*/

Просмотреть файл

@ -34,6 +34,7 @@ IPDL_SOURCES = [
if not CONFIG['MOZ_WEBRTC']:
IPDL_SOURCES += [
'../../media/mtransport/ipc/PStunAddrsRequest.ipdl',
'../../media/mtransport/ipc/PWebrtcProxyChannel.ipdl',
]
EXPORTS.mozilla.net += [
'../../media/mtransport/ipc/NrIceStunAddrMessageUtils.h',