зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
2966b99504
Коммит
09f4c06235
|
@ -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(©)))
|
||||
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(©);
|
||||
}
|
||||
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',
|
||||
|
|
Загрузка…
Ссылка в новой задаче