diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /dom/media/webrtc/transport/ipc | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/media/webrtc/transport/ipc')
19 files changed, 1966 insertions, 0 deletions
diff --git a/dom/media/webrtc/transport/ipc/NrIceStunAddrMessageUtils.h b/dom/media/webrtc/transport/ipc/NrIceStunAddrMessageUtils.h new file mode 100644 index 0000000000..34ec46726e --- /dev/null +++ b/dom/media/webrtc/transport/ipc/NrIceStunAddrMessageUtils.h @@ -0,0 +1,54 @@ +/* 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_NrIceStunAddrMessageUtils_h +#define mozilla_net_NrIceStunAddrMessageUtils_h + +// forward declare NrIceStunAddr for --disable-webrtc builds where +// the header will not be available. +namespace mozilla { +class NrIceStunAddr; +} // namespace mozilla + +#include "ipc/IPCMessageUtils.h" +#ifdef MOZ_WEBRTC +# include "transport/nricestunaddr.h" +#endif + +namespace IPC { + +template <> +struct ParamTraits<mozilla::NrIceStunAddr> { + static void Write(MessageWriter* aWriter, + const mozilla::NrIceStunAddr& aParam) { +#ifdef MOZ_WEBRTC + const size_t bufSize = aParam.SerializationBufferSize(); + char* buffer = new char[bufSize]; + aParam.Serialize(buffer, bufSize); + aWriter->WriteBytes((void*)buffer, bufSize); + delete[] buffer; +#endif + } + + static bool Read(MessageReader* aReader, mozilla::NrIceStunAddr* aResult) { +#ifdef MOZ_WEBRTC + const size_t bufSize = aResult->SerializationBufferSize(); + char* buffer = new char[bufSize]; + bool result = aReader->ReadBytesInto((void*)buffer, bufSize); + + if (result) { + result = result && (NS_OK == aResult->Deserialize(buffer, bufSize)); + } + delete[] buffer; + + return result; +#else + return false; +#endif + } +}; + +} // namespace IPC + +#endif // mozilla_net_NrIceStunAddrMessageUtils_h diff --git a/dom/media/webrtc/transport/ipc/PStunAddrsParams.h b/dom/media/webrtc/transport/ipc/PStunAddrsParams.h new file mode 100644 index 0000000000..315925609d --- /dev/null +++ b/dom/media/webrtc/transport/ipc/PStunAddrsParams.h @@ -0,0 +1,33 @@ +/* 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 PStunAddrsParams_h +#define PStunAddrsParams_h + +#include "mozilla/Maybe.h" +#include "nsTArray.h" + +#ifdef MOZ_WEBRTC +# include "transport/nricestunaddr.h" +#endif + +namespace mozilla { +namespace net { + +// Need to define typedef in .h file--can't seem to in ipdl.h file? +#ifdef MOZ_WEBRTC +typedef nsTArray<NrIceStunAddr> NrIceStunAddrArray; +#else +// a "dummy" typedef for --disabled-webrtc builds when the definition +// for NrIceStunAddr is not available (otherwise we get complaints +// about missing definitions for contructor and destructor) +typedef nsTArray<int> NrIceStunAddrArray; +#endif + +typedef Maybe<nsCString> MaybeNsCString; + +} // namespace net +} // namespace mozilla + +#endif // PStunAddrsParams_h diff --git a/dom/media/webrtc/transport/ipc/PStunAddrsRequest.ipdl b/dom/media/webrtc/transport/ipc/PStunAddrsRequest.ipdl new file mode 100644 index 0000000000..c775f73f99 --- /dev/null +++ b/dom/media/webrtc/transport/ipc/PStunAddrsRequest.ipdl @@ -0,0 +1,35 @@ +/* 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; + +using mozilla::net::NrIceStunAddrArray from "mozilla/net/PStunAddrsParams.h"; +using mozilla::net::MaybeNsCString from "mozilla/net/PStunAddrsParams.h"; + +include "mozilla/net/NrIceStunAddrMessageUtils.h"; + +namespace mozilla { +namespace net { + +[ManualDealloc, ChildImpl=virtual, ParentImpl=virtual] +async protocol PStunAddrsRequest +{ + manager PNecko; + +parent: + async GetStunAddrs(); + + async RegisterMDNSHostname(nsCString hostname, nsCString address); + async QueryMDNSHostname(nsCString hostname); + async UnregisterMDNSHostname(nsCString hostname); + + async __delete__(); + +child: + async OnMDNSQueryComplete(nsCString hostname, MaybeNsCString address); + async OnStunAddrsAvailable(NrIceStunAddrArray iceStunAddrs); +}; + +} // namespace net +} // namespace mozilla diff --git a/dom/media/webrtc/transport/ipc/PWebrtcTCPSocket.ipdl b/dom/media/webrtc/transport/ipc/PWebrtcTCPSocket.ipdl new file mode 100644 index 0000000000..3bc2a89828 --- /dev/null +++ b/dom/media/webrtc/transport/ipc/PWebrtcTCPSocket.ipdl @@ -0,0 +1,42 @@ +/* -*- 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 protocol PSocketProcess; + +include WebrtcProxyConfig; + +using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h"; + +namespace mozilla { +namespace net { + +[ManualDealloc, ChildImpl=virtual, ParentImpl=virtual] +async protocol PWebrtcTCPSocket +{ + manager PNecko or PSocketProcess; + +parent: + async AsyncOpen(nsCString aHost, + int32_t aPort, + nsCString aLocalAddress, + int32_t aLocalPort, + bool aUseTls, + WebrtcProxyConfig? aProxyConfig); + async Write(uint8_t[] aWriteData); + async Close(); + +child: + async OnClose(nsresult aReason); + async OnConnected(nsCString aProxyType); + async OnRead(uint8_t[] aReadData); + + async __delete__(); +}; + +} // namespace net +} // namespace mozilla diff --git a/dom/media/webrtc/transport/ipc/StunAddrsRequestChild.cpp b/dom/media/webrtc/transport/ipc/StunAddrsRequestChild.cpp new file mode 100644 index 0000000000..057fcbd330 --- /dev/null +++ b/dom/media/webrtc/transport/ipc/StunAddrsRequestChild.cpp @@ -0,0 +1,45 @@ +/* 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 "StunAddrsRequestChild.h" + +#include "mozilla/net/NeckoChild.h" +#include "nsISerialEventTarget.h" + +using namespace mozilla::ipc; + +namespace mozilla::net { + +StunAddrsRequestChild::StunAddrsRequestChild(StunAddrsListener* listener) + : mListener(listener) { + gNeckoChild->SendPStunAddrsRequestConstructor(this); + // IPDL holds a reference until IPDL channel gets destroyed + AddIPDLReference(); +} + +mozilla::ipc::IPCResult StunAddrsRequestChild::RecvOnMDNSQueryComplete( + const nsACString& hostname, const Maybe<nsCString>& address) { + if (mListener) { + mListener->OnMDNSQueryComplete(PromiseFlatCString(hostname), address); + } + return IPC_OK(); +} + +mozilla::ipc::IPCResult StunAddrsRequestChild::RecvOnStunAddrsAvailable( + const NrIceStunAddrArray& addrs) { + if (mListener) { + mListener->OnStunAddrsAvailable(addrs); + } + return IPC_OK(); +} + +void StunAddrsRequestChild::Cancel() { mListener = nullptr; } + +NS_IMPL_ADDREF(StunAddrsRequestChild) +NS_IMPL_RELEASE(StunAddrsRequestChild) + +NS_IMPL_ADDREF(StunAddrsListener) +NS_IMPL_RELEASE(StunAddrsListener) + +} // namespace mozilla::net diff --git a/dom/media/webrtc/transport/ipc/StunAddrsRequestChild.h b/dom/media/webrtc/transport/ipc/StunAddrsRequestChild.h new file mode 100644 index 0000000000..f487f52baf --- /dev/null +++ b/dom/media/webrtc/transport/ipc/StunAddrsRequestChild.h @@ -0,0 +1,64 @@ +/* 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_StunAddrsRequestChild_h +#define mozilla_net_StunAddrsRequestChild_h + +#include "mozilla/net/PStunAddrsRequestChild.h" + +class nsISerialEventTarget; + +namespace mozilla::net { + +class StunAddrsListener { + public: + virtual void OnMDNSQueryComplete(const nsCString& hostname, + const Maybe<nsCString>& address) = 0; + virtual void OnStunAddrsAvailable(const NrIceStunAddrArray& addrs) = 0; + + NS_IMETHOD_(MozExternalRefCountType) AddRef(); + NS_IMETHOD_(MozExternalRefCountType) Release(); + + protected: + virtual ~StunAddrsListener() = default; + + ThreadSafeAutoRefCnt mRefCnt; + NS_DECL_OWNINGTHREAD +}; + +class StunAddrsRequestChild final : public PStunAddrsRequestChild { + friend class PStunAddrsRequestChild; + + public: + explicit StunAddrsRequestChild(StunAddrsListener* listener); + + NS_IMETHOD_(MozExternalRefCountType) AddRef(); + NS_IMETHOD_(MozExternalRefCountType) Release(); + + // Not sure why AddIPDLReference & ReleaseIPDLReference don't come + // from PStunAddrsRequestChild since the IPC plumbing seem to + // expect this. + void AddIPDLReference() { AddRef(); } + void ReleaseIPDLReference() { Release(); } + + void Cancel(); + + protected: + virtual ~StunAddrsRequestChild() = default; + + virtual mozilla::ipc::IPCResult RecvOnMDNSQueryComplete( + const nsACString& aHostname, const Maybe<nsCString>& aAddress) override; + + virtual mozilla::ipc::IPCResult RecvOnStunAddrsAvailable( + const NrIceStunAddrArray& addrs) override; + + RefPtr<StunAddrsListener> mListener; + + ThreadSafeAutoRefCnt mRefCnt; + NS_DECL_OWNINGTHREAD +}; + +} // namespace mozilla::net + +#endif // mozilla_net_StunAddrsRequestChild_h diff --git a/dom/media/webrtc/transport/ipc/StunAddrsRequestParent.cpp b/dom/media/webrtc/transport/ipc/StunAddrsRequestParent.cpp new file mode 100644 index 0000000000..23ef6dea73 --- /dev/null +++ b/dom/media/webrtc/transport/ipc/StunAddrsRequestParent.cpp @@ -0,0 +1,262 @@ +/* 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 "StunAddrsRequestParent.h" + +#include "../runnable_utils.h" +#include "mozilla/StaticPtr.h" +#include "nsIThread.h" +#include "nsNetUtil.h" + +#include "transport/nricectx.h" +#include "transport/nricemediastream.h" // needed only for including nricectx.h +#include "transport/nricestunaddr.h" + +#include "../mdns_service/mdns_service.h" + +extern "C" { +#include "local_addr.h" +} + +using namespace mozilla::ipc; + +namespace mozilla::net { + +static void mdns_service_resolved(void* cb, const char* hostname, + const char* addr) { + StunAddrsRequestParent* self = static_cast<StunAddrsRequestParent*>(cb); + self->OnQueryComplete(nsCString(hostname), Some(nsCString(addr))); +} + +void mdns_service_timedout(void* cb, const char* hostname) { + StunAddrsRequestParent* self = static_cast<StunAddrsRequestParent*>(cb); + self->OnQueryComplete(nsCString(hostname), Nothing()); +} + +StunAddrsRequestParent::StunAddrsRequestParent() : mIPCClosed(false) { + NS_GetMainThread(getter_AddRefs(mMainThread)); + + nsresult res; + mSTSThread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &res); + MOZ_ASSERT(mSTSThread); +} + +StunAddrsRequestParent::~StunAddrsRequestParent() { + ASSERT_ON_THREAD(mMainThread); +} + +mozilla::ipc::IPCResult StunAddrsRequestParent::RecvGetStunAddrs() { + ASSERT_ON_THREAD(mMainThread); + + if (mIPCClosed) { + return IPC_OK(); + } + + RUN_ON_THREAD(mSTSThread, + WrapRunnable(RefPtr<StunAddrsRequestParent>(this), + &StunAddrsRequestParent::GetStunAddrs_s), + NS_DISPATCH_NORMAL); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult StunAddrsRequestParent::RecvRegisterMDNSHostname( + const nsACString& aHostname, const nsACString& aAddress) { + ASSERT_ON_THREAD(mMainThread); + + if (mIPCClosed) { + return IPC_OK(); + } + + if (mSharedMDNSService) { + mSharedMDNSService->RegisterHostname(aHostname.BeginReading(), + aAddress.BeginReading()); + } + + return IPC_OK(); +} + +mozilla::ipc::IPCResult StunAddrsRequestParent::RecvQueryMDNSHostname( + const nsACString& aHostname) { + ASSERT_ON_THREAD(mMainThread); + + if (mIPCClosed) { + return IPC_OK(); + } + + if (mSharedMDNSService) { + mSharedMDNSService->QueryHostname(this, aHostname.BeginReading()); + } + + return IPC_OK(); +} + +mozilla::ipc::IPCResult StunAddrsRequestParent::RecvUnregisterMDNSHostname( + const nsACString& aHostname) { + ASSERT_ON_THREAD(mMainThread); + + if (mIPCClosed) { + return IPC_OK(); + } + + if (mSharedMDNSService) { + mSharedMDNSService->UnregisterHostname(aHostname.BeginReading()); + } + + return IPC_OK(); +} + +mozilla::ipc::IPCResult StunAddrsRequestParent::Recv__delete__() { + // see note below in ActorDestroy + mIPCClosed = true; + return IPC_OK(); +} + +void StunAddrsRequestParent::OnQueryComplete(const nsACString& hostname, + const Maybe<nsCString>& address) { + RUN_ON_THREAD(mMainThread, + WrapRunnable(RefPtr<StunAddrsRequestParent>(this), + &StunAddrsRequestParent::OnQueryComplete_m, + nsCString(hostname), address), + NS_DISPATCH_NORMAL); +} + +void StunAddrsRequestParent::ActorDestroy(ActorDestroyReason why) { + // We may still have refcount>0 if we haven't made it through + // GetStunAddrs_s and SendStunAddrs_m yet, but child process + // has crashed. We must not send any more msgs to child, or + // IPDL will kill chrome process, too. + mIPCClosed = true; + + // We need to stop the mDNS service here to ensure that we don't + // end up with any messages queued for the main thread after the + // destructors run. Because of Bug 1569311, all of the + // StunAddrsRequestParent instances end up being destroyed one + // after the other, so it is ok to free the shared service when + // the first one is destroyed rather than waiting for the last one. + // If this behaviour changes, we would potentially end up starting + // and stopping instances repeatedly and should add a refcount and + // a way of cancelling pending queries to avoid churn in that case. + if (mSharedMDNSService) { + mSharedMDNSService = nullptr; + } +} + +void StunAddrsRequestParent::GetStunAddrs_s() { + ASSERT_ON_THREAD(mSTSThread); + + // get the stun addresses while on STS thread + NrIceStunAddrArray addrs = NrIceCtx::GetStunAddrs(); + + if (mIPCClosed) { + return; + } + + // in order to return the result over IPC, we need to be on main thread + RUN_ON_THREAD( + mMainThread, + WrapRunnable(RefPtr<StunAddrsRequestParent>(this), + &StunAddrsRequestParent::SendStunAddrs_m, std::move(addrs)), + NS_DISPATCH_NORMAL); +} + +void StunAddrsRequestParent::SendStunAddrs_m(const NrIceStunAddrArray& addrs) { + ASSERT_ON_THREAD(mMainThread); + + if (mIPCClosed) { + // nothing to do: child probably crashed + return; + } + + // This means that the mDNS service will continue running until shutdown + // once started. The StunAddrsRequestParent destructor does not run until + // shutdown anyway (see Bug 1569311), so there is not much we can do about + // this here. One option would be to add a check if there are no hostnames + // registered after UnregisterHostname is called, and if so, stop the mDNS + // service at that time (see Bug 1569955.) + if (!mSharedMDNSService) { + std::ostringstream o; + char buffer[16]; + for (auto& addr : addrs) { + if (addr.localAddr().addr.ip_version == NR_IPV4 && + !nr_transport_addr_is_loopback(&addr.localAddr().addr)) { + nr_transport_addr_get_addrstring(&addr.localAddr().addr, buffer, 16); + o << buffer << ";"; + } + } + std::string addrstring = o.str(); + if (!addrstring.empty()) { + mSharedMDNSService = new MDNSServiceWrapper(addrstring); + } + } + + // send the new addresses back to the child + Unused << SendOnStunAddrsAvailable(addrs); +} + +void StunAddrsRequestParent::OnQueryComplete_m( + const nsACString& hostname, const Maybe<nsCString>& address) { + ASSERT_ON_THREAD(mMainThread); + + if (mIPCClosed) { + // nothing to do: child probably crashed + return; + } + + // send the hostname and address back to the child + Unused << SendOnMDNSQueryComplete(hostname, address); +} + +StaticRefPtr<StunAddrsRequestParent::MDNSServiceWrapper> + StunAddrsRequestParent::mSharedMDNSService; + +NS_IMPL_ADDREF(StunAddrsRequestParent) +NS_IMPL_RELEASE(StunAddrsRequestParent) + +StunAddrsRequestParent::MDNSServiceWrapper::MDNSServiceWrapper( + const std::string& ifaddr) + : ifaddr(ifaddr) {} + +void StunAddrsRequestParent::MDNSServiceWrapper::RegisterHostname( + const char* hostname, const char* address) { + StartIfRequired(); + if (mMDNSService) { + mdns_service_register_hostname(mMDNSService, hostname, address); + } +} + +void StunAddrsRequestParent::MDNSServiceWrapper::QueryHostname( + void* data, const char* hostname) { + StartIfRequired(); + if (mMDNSService) { + mdns_service_query_hostname(mMDNSService, data, mdns_service_resolved, + mdns_service_timedout, hostname); + } +} + +void StunAddrsRequestParent::MDNSServiceWrapper::UnregisterHostname( + const char* hostname) { + StartIfRequired(); + if (mMDNSService) { + mdns_service_unregister_hostname(mMDNSService, hostname); + } +} + +StunAddrsRequestParent::MDNSServiceWrapper::~MDNSServiceWrapper() { + if (mMDNSService) { + mdns_service_stop(mMDNSService); + mMDNSService = nullptr; + } +} + +void StunAddrsRequestParent::MDNSServiceWrapper::StartIfRequired() { + if (!mMDNSService) { + mMDNSService = mdns_service_start(ifaddr.c_str()); + } +} + +NS_IMPL_ADDREF(StunAddrsRequestParent::MDNSServiceWrapper) +NS_IMPL_RELEASE(StunAddrsRequestParent::MDNSServiceWrapper) + +} // namespace mozilla::net diff --git a/dom/media/webrtc/transport/ipc/StunAddrsRequestParent.h b/dom/media/webrtc/transport/ipc/StunAddrsRequestParent.h new file mode 100644 index 0000000000..33e71abbc7 --- /dev/null +++ b/dom/media/webrtc/transport/ipc/StunAddrsRequestParent.h @@ -0,0 +1,82 @@ +/* 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_StunAddrsRequestParent_h +#define mozilla_net_StunAddrsRequestParent_h + +#include "mozilla/net/PStunAddrsRequestParent.h" + +struct MDNSService; + +namespace mozilla::net { + +class StunAddrsRequestParent : public PStunAddrsRequestParent { + friend class PStunAddrsRequestParent; + + public: + StunAddrsRequestParent(); + + NS_IMETHOD_(MozExternalRefCountType) AddRef(); + NS_IMETHOD_(MozExternalRefCountType) Release(); + + mozilla::ipc::IPCResult Recv__delete__() override; + + void OnQueryComplete(const nsACString& hostname, + const Maybe<nsCString>& address); + + protected: + virtual ~StunAddrsRequestParent(); + + virtual mozilla::ipc::IPCResult RecvGetStunAddrs() override; + virtual mozilla::ipc::IPCResult RecvRegisterMDNSHostname( + const nsACString& hostname, const nsACString& address) override; + virtual mozilla::ipc::IPCResult RecvQueryMDNSHostname( + const nsACString& hostname) override; + virtual mozilla::ipc::IPCResult RecvUnregisterMDNSHostname( + const nsACString& hostname) override; + virtual void ActorDestroy(ActorDestroyReason why) override; + + nsCOMPtr<nsIThread> mMainThread; + nsCOMPtr<nsISerialEventTarget> mSTSThread; + + void GetStunAddrs_s(); + void SendStunAddrs_m(const NrIceStunAddrArray& addrs); + + void OnQueryComplete_m(const nsACString& hostname, + const Maybe<nsCString>& address); + + ThreadSafeAutoRefCnt mRefCnt; + NS_DECL_OWNINGTHREAD + + private: + bool mIPCClosed; // true if IPDL channel has been closed (child crash) + + class MDNSServiceWrapper { + public: + explicit MDNSServiceWrapper(const std::string& ifaddr); + void RegisterHostname(const char* hostname, const char* address); + void QueryHostname(void* data, const char* hostname); + void UnregisterHostname(const char* hostname); + + NS_IMETHOD_(MozExternalRefCountType) AddRef(); + NS_IMETHOD_(MozExternalRefCountType) Release(); + + protected: + ThreadSafeAutoRefCnt mRefCnt; + NS_DECL_OWNINGTHREAD + + private: + virtual ~MDNSServiceWrapper(); + void StartIfRequired(); + + std::string ifaddr; + MDNSService* mMDNSService = nullptr; + }; + + static StaticRefPtr<MDNSServiceWrapper> mSharedMDNSService; +}; + +} // namespace mozilla::net + +#endif // mozilla_net_StunAddrsRequestParent_h diff --git a/dom/media/webrtc/transport/ipc/WebrtcProxyConfig.ipdlh b/dom/media/webrtc/transport/ipc/WebrtcProxyConfig.ipdlh new file mode 100644 index 0000000000..e93e82a6a3 --- /dev/null +++ b/dom/media/webrtc/transport/ipc/WebrtcProxyConfig.ipdlh @@ -0,0 +1,23 @@ +/* -*- 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/. */ + +using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h"; +include NeckoChannelParams; + +namespace mozilla { +namespace net { + +struct WebrtcProxyConfig { + TabId tabId; + nsCString alpn; + LoadInfoArgs loadInfoArgs; + bool forceProxy; +}; + +} // namespace net +} // namespace mozilla + diff --git a/dom/media/webrtc/transport/ipc/WebrtcTCPSocket.cpp b/dom/media/webrtc/transport/ipc/WebrtcTCPSocket.cpp new file mode 100644 index 0000000000..447b4cc741 --- /dev/null +++ b/dom/media/webrtc/transport/ipc/WebrtcTCPSocket.cpp @@ -0,0 +1,785 @@ +/* -*- 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 "WebrtcTCPSocket.h" + +#include "nsHttpChannel.h" +#include "nsIChannel.h" +#include "nsIClassOfService.h" +#include "nsIContentPolicy.h" +#include "nsIIOService.h" +#include "nsILoadInfo.h" +#include "nsIProtocolProxyService.h" +#include "nsIURIMutator.h" +#include "nsICookieJarSettings.h" +#include "nsProxyRelease.h" +#include "nsString.h" +#include "mozilla/dom/ContentProcessManager.h" +#include "mozilla/dom/BrowserParent.h" +#include "nsISocketTransportService.h" +#include "nsICancelable.h" +#include "nsSocketTransportService2.h" + +#include "WebrtcTCPSocketCallback.h" +#include "WebrtcTCPSocketLog.h" + +namespace mozilla::net { + +class WebrtcTCPData { + public: + explicit WebrtcTCPData(nsTArray<uint8_t>&& aData) : mData(std::move(aData)) { + MOZ_COUNT_CTOR(WebrtcTCPData); + } + + MOZ_COUNTED_DTOR(WebrtcTCPData) + + const nsTArray<uint8_t>& GetData() const { return mData; } + + private: + nsTArray<uint8_t> mData; +}; + +NS_IMPL_ISUPPORTS(WebrtcTCPSocket, nsIAuthPromptProvider, + nsIHttpUpgradeListener, nsIInputStreamCallback, + nsIInterfaceRequestor, nsIOutputStreamCallback, + nsIRequestObserver, nsIStreamListener, + nsIProtocolProxyCallback) + +WebrtcTCPSocket::WebrtcTCPSocket(WebrtcTCPSocketCallback* aCallbacks) + : mProxyCallbacks(aCallbacks), + mClosed(false), + mOpened(false), + mWriteOffset(0), + mAuthProvider(nullptr), + mTransport(nullptr), + mSocketIn(nullptr), + mSocketOut(nullptr) { + LOG(("WebrtcTCPSocket::WebrtcTCPSocket %p\n", this)); + mMainThread = GetMainThreadSerialEventTarget(); + mSocketThread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID); + MOZ_RELEASE_ASSERT(mMainThread, "no main thread"); + MOZ_RELEASE_ASSERT(mSocketThread, "no socket thread"); +} + +WebrtcTCPSocket::~WebrtcTCPSocket() { + LOG(("WebrtcTCPSocket::~WebrtcTCPSocket %p\n", this)); + + NS_ProxyRelease("WebrtcTCPSocket::CleanUpAuthProvider", mMainThread, + mAuthProvider.forget()); +} + +void WebrtcTCPSocket::SetTabId(dom::TabId aTabId) { + MOZ_ASSERT(NS_IsMainThread()); + dom::ContentProcessManager* cpm = dom::ContentProcessManager::GetSingleton(); + if (cpm) { + dom::ContentParentId cpId = cpm->GetTabProcessId(aTabId); + mAuthProvider = cpm->GetBrowserParentByProcessAndTabId(cpId, aTabId); + } +} + +nsresult WebrtcTCPSocket::Write(nsTArray<uint8_t>&& aWriteData) { + LOG(("WebrtcTCPSocket::Write %p\n", this)); + MOZ_ASSERT(NS_IsMainThread()); + nsresult rv = mSocketThread->Dispatch(NewRunnableMethod<nsTArray<uint8_t>&&>( + "WebrtcTCPSocket::Write", this, &WebrtcTCPSocket::EnqueueWrite_s, + std::move(aWriteData))); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to dispatch to STS"); + + return rv; +} + +nsresult WebrtcTCPSocket::Close() { + LOG(("WebrtcTCPSocket::Close %p\n", this)); + + CloseWithReason(NS_OK); + + return NS_OK; +} + +void WebrtcTCPSocket::CloseWithReason(nsresult aReason) { + LOG(("WebrtcTCPSocket::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; + + DebugOnly<nsresult> rv = + mSocketThread->Dispatch(NewRunnableMethod<nsresult>( + "WebrtcTCPSocket::CloseWithReason", this, + &WebrtcTCPSocket::CloseWithReason, aReason)); + + // This was MOZ_ALWAYS_SUCCEEDS, but that now uses NS_WARNING_ASSERTION. + // In order to convert this back to MOZ_ALWAYS_SUCCEEDS we would need + // OnSocketThread to return true if we're shutting down and doing the + // "running all of STS's queued events on main" thing. + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to dispatch to STS"); + + 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("WebrtcTCPSocket::CleanUpAuthProvider", mMainThread, + mAuthProvider.forget()); + InvokeOnClose(aReason); +} + +nsresult WebrtcTCPSocket::Open( + const nsACString& aHost, const int& aPort, const nsACString& aLocalAddress, + const int& aLocalPort, bool aUseTls, + const Maybe<net::WebrtcProxyConfig>& aProxyConfig) { + LOG(("WebrtcTCPSocket::Open %p remote-host=%s local-addr=%s local-port=%d", + this, PromiseFlatCString(aHost).get(), + PromiseFlatCString(aLocalAddress).get(), aLocalPort)); + MOZ_ASSERT(NS_IsMainThread()); + + if (NS_WARN_IF(mOpened)) { + LOG(("WebrtcTCPSocket %p: TCP socket already open\n", this)); + CloseWithReason(NS_ERROR_FAILURE); + return NS_ERROR_FAILURE; + } + + mOpened = true; + const nsLiteralCString schemePrefix = aUseTls ? "https://"_ns : "http://"_ns; + nsAutoCString spec(schemePrefix); + + bool ipv6Literal = aHost.Find(":") != kNotFound; + if (ipv6Literal) { + spec += "["; + spec += aHost; + spec += "]"; + } else { + spec += aHost; + } + + nsresult rv = NS_MutateURI(NS_STANDARDURLMUTATOR_CONTRACTID) + .SetSpec(spec) + .SetPort(aPort) + .Finalize(mURI); + + if (NS_WARN_IF(NS_FAILED(rv))) { + CloseWithReason(NS_ERROR_FAILURE); + return NS_ERROR_FAILURE; + } + + mTls = aUseTls; + mLocalAddress = aLocalAddress; + mLocalPort = aLocalPort; + mProxyConfig = aProxyConfig; + + if (!mProxyConfig.isSome()) { + OpenWithoutHttpProxy(nullptr); + return NS_OK; + } + + // We need to figure out whether a proxy needs to be used for mURI before + // we can start on establishing a connection. + rv = DoProxyConfigLookup(); + + if (NS_WARN_IF(NS_FAILED(rv))) { + CloseWithReason(rv); + } + + return rv; +} + +nsresult WebrtcTCPSocket::DoProxyConfigLookup() { + MOZ_ASSERT(NS_IsMainThread()); + nsresult rv; + nsCOMPtr<nsIProtocolProxyService> pps = + do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + nsCOMPtr<nsIChannel> channel; + rv = NS_NewChannel(getter_AddRefs(channel), mURI, + nsContentUtils::GetSystemPrincipal(), + nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL, + nsIContentPolicy::TYPE_OTHER); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = pps->AsyncResolve(channel, + nsIProtocolProxyService::RESOLVE_PREFER_HTTPS_PROXY | + nsIProtocolProxyService::RESOLVE_ALWAYS_TUNNEL, + this, nullptr, getter_AddRefs(mProxyRequest)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // We pick back up in OnProxyAvailable + + return NS_OK; +} + +NS_IMETHODIMP WebrtcTCPSocket::OnProxyAvailable(nsICancelable* aRequest, + nsIChannel* aChannel, + nsIProxyInfo* aProxyinfo, + nsresult aResult) { + MOZ_ASSERT(NS_IsMainThread()); + mProxyRequest = nullptr; + + if (NS_SUCCEEDED(aResult) && aProxyinfo) { + nsresult rv = aProxyinfo->GetType(mProxyType); + if (NS_WARN_IF(NS_FAILED(rv))) { + CloseWithReason(rv); + return rv; + } + + if (mProxyType == "http" || mProxyType == "https") { + rv = OpenWithHttpProxy(); + if (NS_WARN_IF(NS_FAILED(rv))) { + CloseWithReason(rv); + } + return rv; + } + + if (mProxyType == "socks" || mProxyType == "socks4" || + mProxyType == "direct") { + OpenWithoutHttpProxy(aProxyinfo); + return NS_OK; + } + } + + OpenWithoutHttpProxy(nullptr); + + return NS_OK; +} + +void WebrtcTCPSocket::OpenWithoutHttpProxy(nsIProxyInfo* aSocksProxyInfo) { + if (!OnSocketThread()) { + DebugOnly<nsresult> rv = + mSocketThread->Dispatch(NewRunnableMethod<nsCOMPtr<nsIProxyInfo>>( + "WebrtcTCPSocket::OpenWithoutHttpProxy", this, + &WebrtcTCPSocket::OpenWithoutHttpProxy, aSocksProxyInfo)); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to dispatch to STS"); + return; + } + + LOG(("WebrtcTCPSocket::OpenWithoutHttpProxy %p\n", this)); + + if (mClosed) { + return; + } + + if (NS_WARN_IF(mProxyConfig.isSome() && mProxyConfig->forceProxy() && + !aSocksProxyInfo)) { + CloseWithReason(NS_ERROR_FAILURE); + return; + } + + nsCString host; + int32_t port; + + nsresult rv = mURI->GetHost(host); + if (NS_WARN_IF(NS_FAILED(rv))) { + CloseWithReason(rv); + return; + } + + rv = mURI->GetPort(&port); + if (NS_WARN_IF(NS_FAILED(rv))) { + CloseWithReason(rv); + return; + } + + AutoTArray<nsCString, 1> socketTypes; + if (mTls) { + socketTypes.AppendElement("ssl"_ns); + } + + nsCOMPtr<nsISocketTransportService> sts = + do_GetService("@mozilla.org/network/socket-transport-service;1"); + rv = sts->CreateTransport(socketTypes, host, port, aSocksProxyInfo, nullptr, + getter_AddRefs(mTransport)); + if (NS_WARN_IF(NS_FAILED(rv))) { + CloseWithReason(rv); + return; + } + + mTransport->SetReuseAddrPort(true); + + PRNetAddr prAddr; + if (NS_WARN_IF(PR_SUCCESS != + PR_InitializeNetAddr(PR_IpAddrAny, mLocalPort, &prAddr))) { + CloseWithReason(NS_ERROR_FAILURE); + return; + } + + if (NS_WARN_IF(PR_SUCCESS != + PR_StringToNetAddr(mLocalAddress.BeginReading(), &prAddr))) { + CloseWithReason(NS_ERROR_FAILURE); + return; + } + + mozilla::net::NetAddr addr(&prAddr); + rv = mTransport->Bind(&addr); + if (NS_WARN_IF(NS_FAILED(rv))) { + CloseWithReason(rv); + return; + } + + // Binding to a V4 address is not sufficient to cause this socket to use + // V4, and the same goes for V6. So, we disable as needed here. + uint32_t flags = 0; + if (addr.raw.family == AF_INET) { + flags |= nsISocketTransport::DISABLE_IPV6; + } else if (addr.raw.family == AF_INET6) { + flags |= nsISocketTransport::DISABLE_IPV4; + } else { + MOZ_CRASH(); + } + + mTransport->SetConnectionFlags(flags); + + nsCOMPtr<nsIInputStream> socketIn; + rv = mTransport->OpenInputStream(0, 0, 0, getter_AddRefs(socketIn)); + if (NS_WARN_IF(NS_FAILED(rv))) { + CloseWithReason(rv); + return; + } + mSocketIn = do_QueryInterface(socketIn); + if (NS_WARN_IF(!mSocketIn)) { + CloseWithReason(NS_ERROR_NULL_POINTER); + return; + } + + nsCOMPtr<nsIOutputStream> socketOut; + rv = mTransport->OpenOutputStream(nsITransport::OPEN_UNBUFFERED, 0, 0, + getter_AddRefs(socketOut)); + if (NS_WARN_IF(NS_FAILED(rv))) { + CloseWithReason(rv); + return; + } + mSocketOut = do_QueryInterface(socketOut); + if (NS_WARN_IF(!mSocketOut)) { + CloseWithReason(NS_ERROR_NULL_POINTER); + return; + } + + FinishOpen(); +} + +nsresult WebrtcTCPSocket::OpenWithHttpProxy() { + MOZ_ASSERT(NS_IsMainThread(), "not on main thread"); + LOG(("WebrtcTCPSocket::OpenWithHttpProxy %p\n", this)); + nsresult rv; + nsCOMPtr<nsIIOService> ioService; + ioService = do_GetService(NS_IOSERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) { + LOG(("WebrtcTCPSocket %p: io service missing\n", this)); + return rv; + } + + nsCOMPtr<nsILoadInfo> loadInfo; + Maybe<net::LoadInfoArgs> loadInfoArgs = Some(mProxyConfig->loadInfoArgs()); + + // FIXME: We don't know the remote type of the process which provided these + // LoadInfoArgs. Pass in `NOT_REMOTE_TYPE` as the origin process to blindly + // accept whatever value was passed by the other side for now, as we aren't + // using it for security checks here. + // If this code ever starts checking the triggering remote type, this needs to + // be changed. + rv = ipc::LoadInfoArgsToLoadInfo(loadInfoArgs, NOT_REMOTE_TYPE, + getter_AddRefs(loadInfo)); + if (NS_FAILED(rv)) { + LOG(("WebrtcTCPSocket %p: could not init load info\n", this)); + 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->NewChannelFromURIWithProxyFlags( + mURI, nullptr, + // Proxy flags are overridden by SetConnectOnly() + 0, loadInfo->LoadingNode(), loadInfo->GetLoadingPrincipal(), + loadInfo->TriggeringPrincipal(), + 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_SEC_CONTEXT_IS_NULL, + nsIContentPolicy::TYPE_PROXIED_WEBRTC_MEDIA, + getter_AddRefs(localChannel)); + if (NS_FAILED(rv)) { + LOG(("WebrtcTCPSocket %p: bad open channel\n", this)); + return rv; + } + + nsCOMPtr<nsILoadInfo> channelLoadInfo = localChannel->LoadInfo(); + nsCOMPtr<nsICookieJarSettings> cookieJarSettings; + loadInfo->GetCookieJarSettings(getter_AddRefs(cookieJarSettings)); + channelLoadInfo->SetCookieJarSettings(cookieJarSettings); + + RefPtr<nsHttpChannel> httpChannel; + CallQueryInterface(localChannel, httpChannel.StartAssignment()); + + if (!httpChannel) { + LOG(("WebrtcTCPSocket %p: not an http channel\n", this)); + 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(("WebrtcTCPSocket %p: could not set class of service\n", this)); + return NS_ERROR_FAILURE; + } + + rv = httpChannel->HTTPUpgrade(mProxyConfig->alpn(), this); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + rv = httpChannel->SetConnectOnly(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = httpChannel->AsyncOpen(this); + + if (NS_FAILED(rv)) { + LOG(("WebrtcTCPSocket %p: cannot async open\n", this)); + return rv; + } + + // This picks back up in OnTransportAvailable once we have connected to the + // proxy, and performed the http upgrade to switch the proxy into passthrough + // mode. + + return NS_OK; +} + +void WebrtcTCPSocket::EnqueueWrite_s(nsTArray<uint8_t>&& aWriteData) { + LOG(("WebrtcTCPSocket::EnqueueWrite %p\n", this)); + MOZ_ASSERT(OnSocketThread(), "not on socket thread"); + + if (mClosed) { + return; + } + + mWriteQueue.emplace_back(std::move(aWriteData)); + + if (mSocketOut) { + mSocketOut->AsyncWait(this, 0, 0, nullptr); + } +} + +void WebrtcTCPSocket::InvokeOnClose(nsresult aReason) { + LOG(("WebrtcTCPSocket::InvokeOnClose %p\n", this)); + + if (!NS_IsMainThread()) { + MOZ_ALWAYS_SUCCEEDS(mMainThread->Dispatch( + NewRunnableMethod<nsresult>("WebrtcTCPSocket::InvokeOnClose", this, + &WebrtcTCPSocket::InvokeOnClose, aReason))); + return; + } + + MOZ_ASSERT(mProxyCallbacks, "webrtc TCP callback should be non-null"); + + if (mProxyRequest) { + mProxyRequest->Cancel(aReason); + mProxyRequest = nullptr; + } + + mProxyCallbacks->OnClose(aReason); + mProxyCallbacks = nullptr; +} + +void WebrtcTCPSocket::InvokeOnConnected() { + LOG(("WebrtcTCPSocket::InvokeOnConnected %p\n", this)); + + if (!NS_IsMainThread()) { + MOZ_ALWAYS_SUCCEEDS(mMainThread->Dispatch( + NewRunnableMethod("WebrtcTCPSocket::InvokeOnConnected", this, + &WebrtcTCPSocket::InvokeOnConnected))); + return; + } + + MOZ_ASSERT(mProxyCallbacks, "webrtc TCP callback should be non-null"); + + mProxyCallbacks->OnConnected(mProxyType); +} + +void WebrtcTCPSocket::InvokeOnRead(nsTArray<uint8_t>&& aReadData) { + LOG(("WebrtcTCPSocket::InvokeOnRead %p count=%zu\n", this, + aReadData.Length())); + + if (!NS_IsMainThread()) { + MOZ_ALWAYS_SUCCEEDS( + mMainThread->Dispatch(NewRunnableMethod<nsTArray<uint8_t>&&>( + "WebrtcTCPSocket::InvokeOnRead", this, + &WebrtcTCPSocket::InvokeOnRead, std::move(aReadData)))); + return; + } + + MOZ_ASSERT(mProxyCallbacks, "webrtc TCP callback should be non-null"); + + mProxyCallbacks->OnRead(std::move(aReadData)); +} + +// nsIHttpUpgradeListener +NS_IMETHODIMP +WebrtcTCPSocket::OnTransportAvailable(nsISocketTransport* aTransport, + nsIAsyncInputStream* aSocketIn, + nsIAsyncOutputStream* aSocketOut) { + // This is called only in the http proxy case, once we have connected to the + // http proxy and performed the http upgrade to switch it over to passthrough + // mode. That process is started async by OpenWithHttpProxy. + LOG(("WebrtcTCPSocket::OnTransportAvailable %p\n", this)); + MOZ_ASSERT(OnSocketThread(), "not on socket thread"); + MOZ_ASSERT(!mTransport, + "already called transport available on webrtc TCP socket"); + + // 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(("WebrtcTCPSocket::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; + } + + FinishOpen(); + return NS_OK; +} + +void WebrtcTCPSocket::FinishOpen() { + MOZ_ASSERT(OnSocketThread()); + // mTransport, mSocketIn, and mSocketOut are all set. We may have set them in + // OnTransportAvailable (in the http/https proxy case), or in + // OpenWithoutHttpProxy. From here on out, this class functions the same for + // these two cases. + + mSocketIn->AsyncWait(this, 0, 0, nullptr); + + InvokeOnConnected(); +} + +NS_IMETHODIMP +WebrtcTCPSocket::OnUpgradeFailed(nsresult aErrorCode) { + LOG(("WebrtcTCPSocket::OnUpgradeFailed %p\n", this)); + MOZ_ASSERT(OnSocketThread(), "not on socket thread"); + MOZ_ASSERT(!mTransport, + "already called transport available on webrtc TCP socket"); + + if (mClosed) { + LOG(("WebrtcTCPSocket::OnUpgradeFailed %p closed\n", this)); + return NS_OK; + } + + CloseWithReason(aErrorCode); + + return NS_OK; +} + +NS_IMETHODIMP +WebrtcTCPSocket::OnWebSocketConnectionAvailable( + WebSocketConnectionBase* aConnection) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +// nsIRequestObserver (from nsIStreamListener) +NS_IMETHODIMP +WebrtcTCPSocket::OnStartRequest(nsIRequest* aRequest) { + LOG(("WebrtcTCPSocket::OnStartRequest %p\n", this)); + + return NS_OK; +} + +NS_IMETHODIMP +WebrtcTCPSocket::OnStopRequest(nsIRequest* aRequest, nsresult aStatusCode) { + LOG(("WebrtcTCPSocket::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 +WebrtcTCPSocket::OnDataAvailable(nsIRequest* aRequest, + nsIInputStream* aInputStream, uint64_t aOffset, + uint32_t aCount) { + LOG(("WebrtcTCPSocket::OnDataAvailable %p count=%u\n", this, aCount)); + MOZ_ASSERT(0, "unreachable data available"); + return NS_OK; +} + +// nsIInputStreamCallback +NS_IMETHODIMP +WebrtcTCPSocket::OnInputStreamReady(nsIAsyncInputStream* in) { + LOG(("WebrtcTCPSocket::OnInputStreamReady %p unwritten=%zu\n", this, + CountUnwrittenBytes())); + MOZ_ASSERT(OnSocketThread(), "not on socket thread"); + MOZ_ASSERT(!mClosed, "webrtc TCP socket closed"); + MOZ_ASSERT(mTransport, "webrtc TCP socket 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(("WebrtcTCPSocket::OnInputStreamReady %p failed %u\n", this, + static_cast<uint32_t>(rv))); + CloseWithReason(rv); + return rv; + } + + // base stream closed + if (count == 0) { + LOG(("WebrtcTCPSocket::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 +WebrtcTCPSocket::OnOutputStreamReady(nsIAsyncOutputStream* out) { + LOG(("WebrtcTCPSocket::OnOutputStreamReady %p unwritten=%zu\n", this, + CountUnwrittenBytes())); + MOZ_ASSERT(OnSocketThread(), "not on socket thread"); + MOZ_ASSERT(!mClosed, "webrtc TCP socket closed"); + MOZ_ASSERT(mTransport, "webrtc TCP socket not connected"); + MOZ_ASSERT(mSocketOut == out, "wrong output stream"); + + while (!mWriteQueue.empty()) { + const WebrtcTCPData& 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(("WebrtcTCPSocket::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 +WebrtcTCPSocket::GetInterface(const nsIID& iid, void** result) { + LOG(("WebrtcTCPSocket::GetInterface %p\n", this)); + + return QueryInterface(iid, result); +} + +size_t WebrtcTCPSocket::CountUnwrittenBytes() const { + size_t count = 0; + + for (const WebrtcTCPData& data : mWriteQueue) { + count += data.GetData().Length(); + } + + MOZ_ASSERT(count >= mWriteOffset, "offset exceeds write buffer length"); + + count -= mWriteOffset; + + return count; +} + +} // namespace mozilla::net diff --git a/dom/media/webrtc/transport/ipc/WebrtcTCPSocket.h b/dom/media/webrtc/transport/ipc/WebrtcTCPSocket.h new file mode 100644 index 0000000000..632ba47d32 --- /dev/null +++ b/dom/media/webrtc/transport/ipc/WebrtcTCPSocket.h @@ -0,0 +1,104 @@ +/* -*- 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_tcp_socket_h__ +#define webrtc_tcp_socket_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" +#include "nsIProtocolProxyCallback.h" +#include "mozilla/net/WebrtcProxyConfig.h" + +class nsISocketTransport; + +namespace mozilla::net { + +class WebrtcTCPSocketCallback; +class WebrtcTCPData; + +class WebrtcTCPSocket : public nsIHttpUpgradeListener, + public nsIStreamListener, + public nsIInputStreamCallback, + public nsIOutputStreamCallback, + public nsIInterfaceRequestor, + public nsIAuthPromptProvider, + public nsIProtocolProxyCallback { + 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) + NS_DECL_NSIPROTOCOLPROXYCALLBACK + + explicit WebrtcTCPSocket(WebrtcTCPSocketCallback* aCallbacks); + + void SetTabId(dom::TabId aTabId); + nsresult Open(const nsACString& aHost, const int& aPort, + const nsACString& aLocalAddress, const int& aLocalPort, + bool aUseTls, + const Maybe<net::WebrtcProxyConfig>& aProxyConfig); + nsresult Write(nsTArray<uint8_t>&& aBytes); + nsresult Close(); + + size_t CountUnwrittenBytes() const; + + protected: + virtual ~WebrtcTCPSocket(); + + // protected for gtests + virtual void InvokeOnClose(nsresult aReason); + virtual void InvokeOnConnected(); + virtual void InvokeOnRead(nsTArray<uint8_t>&& aReadData); + + RefPtr<WebrtcTCPSocketCallback> mProxyCallbacks; + + private: + bool mClosed; + bool mOpened; + nsCOMPtr<nsIURI> mURI; + bool mTls = false; + Maybe<WebrtcProxyConfig> mProxyConfig; + nsCString mLocalAddress; + uint16_t mLocalPort = 0; + nsCString mProxyType; + + nsresult DoProxyConfigLookup(); + nsresult OpenWithHttpProxy(); + void OpenWithoutHttpProxy(nsIProxyInfo* aSocksProxyInfo); + void FinishOpen(); + void EnqueueWrite_s(nsTArray<uint8_t>&& aWriteData); + + void CloseWithReason(nsresult aReason); + + size_t mWriteOffset; + std::list<WebrtcTCPData> 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; + nsCOMPtr<nsICancelable> mProxyRequest; +}; + +} // namespace mozilla::net + +#endif // webrtc_tcp_socket_h__ diff --git a/dom/media/webrtc/transport/ipc/WebrtcTCPSocketCallback.h b/dom/media/webrtc/transport/ipc/WebrtcTCPSocketCallback.h new file mode 100644 index 0000000000..1929e55ac2 --- /dev/null +++ b/dom/media/webrtc/transport/ipc/WebrtcTCPSocketCallback.h @@ -0,0 +1,28 @@ +/* -*- 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_tcp_socket_callback_h__ +#define webrtc_tcp_socket_callback_h__ + +#include "nsTArray.h" + +namespace mozilla::net { + +class WebrtcTCPSocketCallback { + public: + NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING + + virtual void OnClose(nsresult aReason) = 0; + virtual void OnConnected(const nsACString& aProxyType) = 0; + virtual void OnRead(nsTArray<uint8_t>&& aReadData) = 0; + + protected: + virtual ~WebrtcTCPSocketCallback() = default; +}; + +} // namespace mozilla::net + +#endif // webrtc_tcp_socket_callback_h__ diff --git a/dom/media/webrtc/transport/ipc/WebrtcTCPSocketChild.cpp b/dom/media/webrtc/transport/ipc/WebrtcTCPSocketChild.cpp new file mode 100644 index 0000000000..52d1ba8ab2 --- /dev/null +++ b/dom/media/webrtc/transport/ipc/WebrtcTCPSocketChild.cpp @@ -0,0 +1,96 @@ +/* -*- 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 "WebrtcTCPSocketChild.h" + +#include "mozilla/net/NeckoChild.h" +#include "mozilla/net/SocketProcessChild.h" + +#include "LoadInfo.h" + +#include "WebrtcTCPSocketLog.h" +#include "WebrtcTCPSocketCallback.h" + +using namespace mozilla::ipc; + +namespace mozilla::net { + +mozilla::ipc::IPCResult WebrtcTCPSocketChild::RecvOnClose( + const nsresult& aReason) { + LOG(("WebrtcTCPSocketChild::RecvOnClose %p\n", this)); + + MOZ_ASSERT(mProxyCallbacks, "webrtc TCP callbacks should be non-null"); + mProxyCallbacks->OnClose(aReason); + mProxyCallbacks = nullptr; + + return IPC_OK(); +} + +mozilla::ipc::IPCResult WebrtcTCPSocketChild::RecvOnConnected( + const nsACString& aProxyType) { + LOG(("WebrtcTCPSocketChild::RecvOnConnected %p\n", this)); + + MOZ_ASSERT(mProxyCallbacks, "webrtc TCP callbacks should be non-null"); + mProxyCallbacks->OnConnected(aProxyType); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult WebrtcTCPSocketChild::RecvOnRead( + nsTArray<uint8_t>&& aReadData) { + LOG(("WebrtcTCPSocketChild::RecvOnRead %p\n", this)); + + MOZ_ASSERT(mProxyCallbacks, "webrtc TCP callbacks should be non-null"); + mProxyCallbacks->OnRead(std::move(aReadData)); + + return IPC_OK(); +} + +WebrtcTCPSocketChild::WebrtcTCPSocketChild( + WebrtcTCPSocketCallback* aProxyCallbacks) + : mProxyCallbacks(aProxyCallbacks) { + MOZ_COUNT_CTOR(WebrtcTCPSocketChild); + + LOG(("WebrtcTCPSocketChild::WebrtcTCPSocketChild %p\n", this)); +} + +WebrtcTCPSocketChild::~WebrtcTCPSocketChild() { + MOZ_COUNT_DTOR(WebrtcTCPSocketChild); + + LOG(("WebrtcTCPSocketChild::~WebrtcTCPSocketChild %p\n", this)); +} + +void WebrtcTCPSocketChild::AsyncOpen( + const nsACString& aHost, const int& aPort, const nsACString& aLocalAddress, + const int& aLocalPort, bool aUseTls, + const std::shared_ptr<NrSocketProxyConfig>& aProxyConfig) { + LOG(("WebrtcTCPSocketChild::AsyncOpen %p %s:%d\n", this, + PromiseFlatCString(aHost).get(), aPort)); + + MOZ_ASSERT(NS_IsMainThread(), "not main thread"); + + AddIPDLReference(); + + Maybe<net::WebrtcProxyConfig> proxyConfig; + Maybe<dom::TabId> tabId; + if (aProxyConfig) { + proxyConfig = Some(aProxyConfig->GetConfig()); + tabId = Some(proxyConfig->tabId()); + } + + if (IsNeckoChild()) { + // We're on a content process + gNeckoChild->SendPWebrtcTCPSocketConstructor(this, tabId); + } else if (IsSocketProcessChild()) { + // We're on a socket process + SocketProcessChild::GetSingleton()->SendPWebrtcTCPSocketConstructor(this, + tabId); + } + + SendAsyncOpen(aHost, aPort, aLocalAddress, aLocalPort, aUseTls, proxyConfig); +} + +} // namespace mozilla::net diff --git a/dom/media/webrtc/transport/ipc/WebrtcTCPSocketChild.h b/dom/media/webrtc/transport/ipc/WebrtcTCPSocketChild.h new file mode 100644 index 0000000000..638ffcaac3 --- /dev/null +++ b/dom/media/webrtc/transport/ipc/WebrtcTCPSocketChild.h @@ -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 mozilla_net_WebrtcTCPSocketChild_h +#define mozilla_net_WebrtcTCPSocketChild_h + +#include "mozilla/net/PWebrtcTCPSocketChild.h" +#include "mozilla/dom/ipc/IdType.h" +#include "transport/nr_socket_proxy_config.h" + +namespace mozilla::net { + +class WebrtcTCPSocketCallback; + +class WebrtcTCPSocketChild : public PWebrtcTCPSocketChild { + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebrtcTCPSocketChild) + + mozilla::ipc::IPCResult RecvOnClose(const nsresult& aReason) override; + + mozilla::ipc::IPCResult RecvOnConnected( + const nsACString& aProxyType) override; + + mozilla::ipc::IPCResult RecvOnRead(nsTArray<uint8_t>&& aReadData) override; + + explicit WebrtcTCPSocketChild(WebrtcTCPSocketCallback* aProxyCallbacks); + + void AsyncOpen(const nsACString& aHost, const int& aPort, + const nsACString& aLocalAddress, const int& aLocalPort, + bool aUseTls, + const std::shared_ptr<NrSocketProxyConfig>& aProxyConfig); + + void AddIPDLReference() { AddRef(); } + void ReleaseIPDLReference() { Release(); } + + protected: + virtual ~WebrtcTCPSocketChild(); + + RefPtr<WebrtcTCPSocketCallback> mProxyCallbacks; +}; + +} // namespace mozilla::net + +#endif // mozilla_net_WebrtcTCPSocketChild_h diff --git a/dom/media/webrtc/transport/ipc/WebrtcTCPSocketLog.cpp b/dom/media/webrtc/transport/ipc/WebrtcTCPSocketLog.cpp new file mode 100644 index 0000000000..a6b0dcdb75 --- /dev/null +++ b/dom/media/webrtc/transport/ipc/WebrtcTCPSocketLog.cpp @@ -0,0 +1,11 @@ +/* -*- 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 "WebrtcTCPSocketLog.h" + +namespace mozilla::net { +LazyLogModule webrtcTCPSocketLog("WebrtcTCPSocket"); +} // namespace mozilla::net diff --git a/dom/media/webrtc/transport/ipc/WebrtcTCPSocketLog.h b/dom/media/webrtc/transport/ipc/WebrtcTCPSocketLog.h new file mode 100644 index 0000000000..72d3d0064b --- /dev/null +++ b/dom/media/webrtc/transport/ipc/WebrtcTCPSocketLog.h @@ -0,0 +1,20 @@ +/* -*- 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_tcp_socket_log_h__ +#define webrtc_tcp_socket_log_h__ + +#include "mozilla/Logging.h" + +namespace mozilla::net { +extern LazyLogModule webrtcTCPSocketLog; +} // namespace mozilla::net + +#undef LOG +#define LOG(args) \ + MOZ_LOG(mozilla::net::webrtcTCPSocketLog, mozilla::LogLevel::Debug, args) + +#endif // webrtc_tcp_socket_log_h__ diff --git a/dom/media/webrtc/transport/ipc/WebrtcTCPSocketParent.cpp b/dom/media/webrtc/transport/ipc/WebrtcTCPSocketParent.cpp new file mode 100644 index 0000000000..0df8962757 --- /dev/null +++ b/dom/media/webrtc/transport/ipc/WebrtcTCPSocketParent.cpp @@ -0,0 +1,122 @@ +/* -*- 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 "WebrtcTCPSocketParent.h" + +#include "mozilla/net/NeckoParent.h" + +#include "WebrtcTCPSocket.h" +#include "WebrtcTCPSocketLog.h" + +using namespace mozilla::dom; +using namespace mozilla::ipc; + +namespace mozilla::net { + +mozilla::ipc::IPCResult WebrtcTCPSocketParent::RecvAsyncOpen( + const nsACString& aHost, const int& aPort, const nsACString& aLocalAddress, + const int& aLocalPort, const bool& aUseTls, + const Maybe<WebrtcProxyConfig>& aProxyConfig) { + LOG(("WebrtcTCPSocketParent::RecvAsyncOpen %p to %s:%d\n", this, + PromiseFlatCString(aHost).get(), aPort)); + + MOZ_ASSERT(mChannel, "webrtc TCP socket should be non-null"); + if (!mChannel) { + return IPC_FAIL(this, "Called with null channel."); + } + + mChannel->Open(aHost, aPort, aLocalAddress, aLocalPort, aUseTls, + aProxyConfig); + + return IPC_OK(); +} + +mozilla::ipc::IPCResult WebrtcTCPSocketParent::RecvWrite( + nsTArray<uint8_t>&& aWriteData) { + LOG(("WebrtcTCPSocketParent::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 WebrtcTCPSocketParent::RecvClose() { + LOG(("WebrtcTCPSocketParent::RecvClose %p\n", this)); + + CleanupChannel(); + + IProtocol* mgr = Manager(); + if (!Send__delete__(this)) { + return IPC_FAIL_NO_REASON(mgr); + } + + return IPC_OK(); +} + +void WebrtcTCPSocketParent::ActorDestroy(ActorDestroyReason aWhy) { + LOG(("WebrtcTCPSocketParent::ActorDestroy %p for %d\n", this, aWhy)); + + CleanupChannel(); +} + +WebrtcTCPSocketParent::WebrtcTCPSocketParent(const Maybe<dom::TabId>& aTabId) { + MOZ_COUNT_CTOR(WebrtcTCPSocketParent); + + LOG(("WebrtcTCPSocketParent::WebrtcTCPSocketParent %p\n", this)); + + mChannel = new WebrtcTCPSocket(this); + if (aTabId.isSome()) { + mChannel->SetTabId(*aTabId); + } +} + +WebrtcTCPSocketParent::~WebrtcTCPSocketParent() { + MOZ_COUNT_DTOR(WebrtcTCPSocketParent); + + LOG(("WebrtcTCPSocketParent::~WebrtcTCPSocketParent %p\n", this)); + + CleanupChannel(); +} + +// WebrtcTCPSocketCallback +void WebrtcTCPSocketParent::OnClose(nsresult aReason) { + LOG(("WebrtcTCPSocketParent::OnClose %p\n", this)); + + if (mChannel) { + Unused << SendOnClose(aReason); + } + + CleanupChannel(); +} + +void WebrtcTCPSocketParent::OnRead(nsTArray<uint8_t>&& aReadData) { + LOG(("WebrtcTCPSocketParent::OnRead %p %zu\n", this, aReadData.Length())); + + if (mChannel && !SendOnRead(std::move(aReadData))) { + CleanupChannel(); + } +} + +void WebrtcTCPSocketParent::OnConnected(const nsACString& aProxyType) { + LOG(("WebrtcTCPSocketParent::OnConnected %p\n", this)); + + if (mChannel && !SendOnConnected(aProxyType)) { + CleanupChannel(); + } +} + +void WebrtcTCPSocketParent::CleanupChannel() { + if (mChannel) { + mChannel->Close(); + mChannel = nullptr; + } +} + +} // namespace mozilla::net diff --git a/dom/media/webrtc/transport/ipc/WebrtcTCPSocketParent.h b/dom/media/webrtc/transport/ipc/WebrtcTCPSocketParent.h new file mode 100644 index 0000000000..df4462609d --- /dev/null +++ b/dom/media/webrtc/transport/ipc/WebrtcTCPSocketParent.h @@ -0,0 +1,59 @@ +/* -*- 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_WebrtcTCPSocketParent_h +#define mozilla_net_WebrtcTCPSocketParent_h + +#include "mozilla/net/PWebrtcTCPSocketParent.h" + +#include "WebrtcTCPSocketCallback.h" + +class nsIAuthPromptProvider; + +namespace mozilla::net { + +class WebrtcTCPSocket; + +class WebrtcTCPSocketParent : public PWebrtcTCPSocketParent, + public WebrtcTCPSocketCallback { + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebrtcTCPSocketParent, override) + + mozilla::ipc::IPCResult RecvAsyncOpen( + const nsACString& aHost, const int& aPort, + const nsACString& aLocalAddress, const int& aLocalPort, + const bool& aUseTls, + const Maybe<WebrtcProxyConfig>& aProxyConfig) override; + + mozilla::ipc::IPCResult RecvWrite(nsTArray<uint8_t>&& aWriteData) override; + + mozilla::ipc::IPCResult RecvClose() override; + + void ActorDestroy(ActorDestroyReason aWhy) override; + + explicit WebrtcTCPSocketParent(const Maybe<dom::TabId>& aTabId); + + // WebrtcTCPSocketCallback + void OnClose(nsresult aReason) override; + void OnConnected(const nsACString& aProxyType) override; + void OnRead(nsTArray<uint8_t>&& bytes) override; + + void AddIPDLReference() { AddRef(); } + void ReleaseIPDLReference() { Release(); } + + protected: + virtual ~WebrtcTCPSocketParent(); + + private: + void CleanupChannel(); + + // Indicates that IPC is open. + RefPtr<WebrtcTCPSocket> mChannel; +}; + +} // namespace mozilla::net + +#endif // mozilla_net_WebrtcTCPSocketParent_h diff --git a/dom/media/webrtc/transport/ipc/moz.build b/dom/media/webrtc/transport/ipc/moz.build new file mode 100644 index 0000000000..a2a72bb624 --- /dev/null +++ b/dom/media/webrtc/transport/ipc/moz.build @@ -0,0 +1,54 @@ +# 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/. + +EXPORTS.mozilla.net += [ + "NrIceStunAddrMessageUtils.h", + "PStunAddrsParams.h", + "StunAddrsRequestChild.h", + "StunAddrsRequestParent.h", + "WebrtcTCPSocket.h", + "WebrtcTCPSocketCallback.h", + "WebrtcTCPSocketChild.h", + "WebrtcTCPSocketParent.h", +] + +UNIFIED_SOURCES += [ + "StunAddrsRequestChild.cpp", + "StunAddrsRequestParent.cpp", + "WebrtcTCPSocket.cpp", + "WebrtcTCPSocketChild.cpp", + "WebrtcTCPSocketLog.cpp", + "WebrtcTCPSocketParent.cpp", +] + +IPDL_SOURCES += [ + "PStunAddrsRequest.ipdl", + "PWebrtcTCPSocket.ipdl", + "WebrtcProxyConfig.ipdlh", +] + +include("/ipc/chromium/chromium-config.mozbuild") + +FINAL_LIBRARY = "xul" + +DEFINES["R_DEFINED_INT2"] = "int16_t" +DEFINES["R_DEFINED_UINT2"] = "uint16_t" +DEFINES["R_DEFINED_INT4"] = "int32_t" +DEFINES["R_DEFINED_UINT4"] = "uint32_t" +# These are defined to avoid a conflict between typedefs in winsock2.h and +# r_types.h. This is safe because these types are unused by the code here, +# but still deeply unfortunate. There is similar code in the win32 version of +# csi_platform.h, but that trick does not work here, even if that file is +# directly included. +DEFINES["R_DEFINED_INT8"] = "int8_t" +DEFINES["R_DEFINED_UINT8"] = "uint8_t" + +LOCAL_INCLUDES += [ + "/dom/media/webrtc/jsapi", + "/dom/media/webrtc/transport/third_party/nICEr/src/net", + "/dom/media/webrtc/transport/third_party/nrappkit/src/util/libekr", + "/media/webrtc", + "/netwerk/base", + "/netwerk/protocol/http", +] |