123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* 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 "UDPSocketChild.h"
- #include "UDPSocket.h"
- #include "mozilla/Unused.h"
- #include "mozilla/ipc/InputStreamUtils.h"
- #include "mozilla/net/NeckoChild.h"
- #include "mozilla/dom/PermissionMessageUtils.h"
- #include "mozilla/ipc/BackgroundChild.h"
- #include "mozilla/ipc/PBackgroundChild.h"
- #include "mozilla/ipc/BackgroundUtils.h"
- #include "mozilla/ipc/PBackgroundSharedTypes.h"
- #include "nsIIPCBackgroundChildCreateCallback.h"
- using mozilla::net::gNeckoChild;
- namespace mozilla {
- namespace dom {
- NS_IMPL_ISUPPORTS(UDPSocketChildBase, nsIUDPSocketChild)
- UDPSocketChildBase::UDPSocketChildBase()
- : mIPCOpen(false)
- {
- }
- UDPSocketChildBase::~UDPSocketChildBase()
- {
- }
- void
- UDPSocketChildBase::ReleaseIPDLReference()
- {
- MOZ_ASSERT(mIPCOpen);
- mIPCOpen = false;
- mSocket = nullptr;
- this->Release();
- }
- void
- UDPSocketChildBase::AddIPDLReference()
- {
- MOZ_ASSERT(!mIPCOpen);
- mIPCOpen = true;
- this->AddRef();
- }
- NS_IMETHODIMP_(MozExternalRefCountType) UDPSocketChild::Release(void)
- {
- nsrefcnt refcnt = UDPSocketChildBase::Release();
- if (refcnt == 1 && mIPCOpen) {
- PUDPSocketChild::SendRequestDelete();
- return 1;
- }
- return refcnt;
- }
- UDPSocketChild::UDPSocketChild()
- :mBackgroundManager(nullptr)
- ,mLocalPort(0)
- {
- }
- UDPSocketChild::~UDPSocketChild()
- {
- }
- class UDPSocketBackgroundChildCallback final :
- public nsIIPCBackgroundChildCreateCallback
- {
- bool* mDone;
- public:
- explicit UDPSocketBackgroundChildCallback(bool* aDone)
- : mDone(aDone)
- {
- MOZ_ASSERT(!NS_IsMainThread());
- MOZ_ASSERT(mDone);
- MOZ_ASSERT(!*mDone);
- }
- NS_DECL_ISUPPORTS
- private:
- ~UDPSocketBackgroundChildCallback()
- { }
- virtual void
- ActorCreated(PBackgroundChild* aActor) override
- {
- *mDone = true;
- }
- virtual void
- ActorFailed() override
- {
- *mDone = true;
- }
- };
- NS_IMPL_ISUPPORTS(UDPSocketBackgroundChildCallback, nsIIPCBackgroundChildCreateCallback)
- nsresult
- UDPSocketChild::CreatePBackgroundSpinUntilDone()
- {
- using mozilla::ipc::BackgroundChild;
- // Spinning the event loop in MainThread would be dangerous
- MOZ_ASSERT(!NS_IsMainThread());
- MOZ_ASSERT(!BackgroundChild::GetForCurrentThread());
- bool done = false;
- nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback =
- new UDPSocketBackgroundChildCallback(&done);
- if (NS_WARN_IF(!BackgroundChild::GetOrCreateForCurrentThread(callback))) {
- return NS_ERROR_FAILURE;
- }
- nsIThread* thread = NS_GetCurrentThread();
- while (!done) {
- if (NS_WARN_IF(!NS_ProcessNextEvent(thread, true /* aMayWait */))) {
- return NS_ERROR_FAILURE;
- }
- }
- if (NS_WARN_IF(!BackgroundChild::GetForCurrentThread())) {
- return NS_ERROR_FAILURE;
- }
- return NS_OK;
- }
- // nsIUDPSocketChild Methods
- NS_IMETHODIMP
- UDPSocketChild::SetBackgroundSpinsEvents()
- {
- using mozilla::ipc::BackgroundChild;
- PBackgroundChild* existingBackgroundChild =
- BackgroundChild::GetForCurrentThread();
- // If it's not spun up yet, block until it is, and retry
- if (!existingBackgroundChild) {
- nsresult rv = CreatePBackgroundSpinUntilDone();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- existingBackgroundChild =
- BackgroundChild::GetForCurrentThread();
- MOZ_ASSERT(existingBackgroundChild);
- }
- // By now PBackground is guaranteed to be/have-been up
- mBackgroundManager = existingBackgroundChild;
- return NS_OK;
- }
- NS_IMETHODIMP
- UDPSocketChild::Bind(nsIUDPSocketInternal* aSocket,
- nsIPrincipal* aPrincipal,
- const nsACString& aHost,
- uint16_t aPort,
- bool aAddressReuse,
- bool aLoopback,
- uint32_t recvBufferSize,
- uint32_t sendBufferSize)
- {
- UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, PromiseFlatCString(aHost).get(), aPort));
- NS_ENSURE_ARG(aSocket);
- if (NS_IsMainThread()) {
- if (!gNeckoChild->SendPUDPSocketConstructor(
- this, IPC::Principal(aPrincipal), mFilterName)) {
- return NS_ERROR_FAILURE;
- }
- } else {
- if (!mBackgroundManager) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- // If we want to support a passed-in principal here we'd need to
- // convert it to a PrincipalInfo
- MOZ_ASSERT(!aPrincipal);
- if (!mBackgroundManager->SendPUDPSocketConstructor(
- this, void_t(), mFilterName)) {
- return NS_ERROR_FAILURE;
- }
- }
- mSocket = aSocket;
- AddIPDLReference();
- SendBind(UDPAddressInfo(nsCString(aHost), aPort), aAddressReuse, aLoopback,
- recvBufferSize, sendBufferSize);
- return NS_OK;
- }
- NS_IMETHODIMP
- UDPSocketChild::Connect(nsIUDPSocketInternal* aSocket, const nsACString & aHost, uint16_t aPort)
- {
- UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, PromiseFlatCString(aHost).get(), aPort));
- mSocket = aSocket;
- SendConnect(UDPAddressInfo(nsCString(aHost), aPort));
- return NS_OK;
- }
- NS_IMETHODIMP
- UDPSocketChild::Close()
- {
- SendClose();
- return NS_OK;
- }
- NS_IMETHODIMP
- UDPSocketChild::Send(const nsACString& aHost,
- uint16_t aPort,
- const uint8_t* aData,
- uint32_t aByteLength)
- {
- NS_ENSURE_ARG(aData);
- UDPSOCKET_LOG(("%s: %s:%u - %u bytes", __FUNCTION__, PromiseFlatCString(aHost).get(), aPort, aByteLength));
- return SendDataInternal(UDPSocketAddr(UDPAddressInfo(nsCString(aHost), aPort)),
- aData, aByteLength);
- }
- NS_IMETHODIMP
- UDPSocketChild::SendWithAddr(nsINetAddr* aAddr,
- const uint8_t* aData,
- uint32_t aByteLength)
- {
- NS_ENSURE_ARG(aAddr);
- NS_ENSURE_ARG(aData);
- NetAddr addr;
- aAddr->GetNetAddr(&addr);
- UDPSOCKET_LOG(("%s: %u bytes", __FUNCTION__, aByteLength));
- return SendDataInternal(UDPSocketAddr(addr), aData, aByteLength);
- }
- NS_IMETHODIMP
- UDPSocketChild::SendWithAddress(const NetAddr* aAddr,
- const uint8_t* aData,
- uint32_t aByteLength)
- {
- NS_ENSURE_ARG(aAddr);
- NS_ENSURE_ARG(aData);
- UDPSOCKET_LOG(("%s: %u bytes", __FUNCTION__, aByteLength));
- return SendDataInternal(UDPSocketAddr(*aAddr), aData, aByteLength);
- }
- nsresult
- UDPSocketChild::SendDataInternal(const UDPSocketAddr& aAddr,
- const uint8_t* aData,
- const uint32_t aByteLength)
- {
- NS_ENSURE_ARG(aData);
- FallibleTArray<uint8_t> fallibleArray;
- if (!fallibleArray.InsertElementsAt(0, aData, aByteLength, fallible)) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- InfallibleTArray<uint8_t> array;
- array.SwapElements(fallibleArray);
- SendOutgoingData(array, aAddr);
- return NS_OK;
- }
- NS_IMETHODIMP
- UDPSocketChild::SendBinaryStream(const nsACString& aHost,
- uint16_t aPort,
- nsIInputStream* aStream)
- {
- NS_ENSURE_ARG(aStream);
- OptionalInputStreamParams stream;
- nsTArray<mozilla::ipc::FileDescriptor> fds;
- SerializeInputStream(aStream, stream, fds);
- MOZ_ASSERT(fds.IsEmpty());
- UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, PromiseFlatCString(aHost).get(), aPort));
- SendOutgoingData(UDPData(stream), UDPSocketAddr(UDPAddressInfo(nsCString(aHost), aPort)));
- return NS_OK;
- }
- NS_IMETHODIMP
- UDPSocketChild::JoinMulticast(const nsACString& aMulticastAddress,
- const nsACString& aInterface)
- {
- SendJoinMulticast(nsCString(aMulticastAddress), nsCString(aInterface));
- return NS_OK;
- }
- NS_IMETHODIMP
- UDPSocketChild::LeaveMulticast(const nsACString& aMulticastAddress,
- const nsACString& aInterface)
- {
- SendLeaveMulticast(nsCString(aMulticastAddress), nsCString(aInterface));
- return NS_OK;
- }
- NS_IMETHODIMP
- UDPSocketChild::GetLocalPort(uint16_t* aLocalPort)
- {
- NS_ENSURE_ARG_POINTER(aLocalPort);
- *aLocalPort = mLocalPort;
- return NS_OK;
- }
- NS_IMETHODIMP
- UDPSocketChild::GetLocalAddress(nsACString& aLocalAddress)
- {
- aLocalAddress = mLocalAddress;
- return NS_OK;
- }
- NS_IMETHODIMP
- UDPSocketChild::SetFilterName(const nsACString& aFilterName)
- {
- if (!mFilterName.IsEmpty()) {
- // filter name can only be set once.
- return NS_ERROR_FAILURE;
- }
- mFilterName = aFilterName;
- return NS_OK;
- }
- NS_IMETHODIMP
- UDPSocketChild::GetFilterName(nsACString& aFilterName)
- {
- aFilterName = mFilterName;
- return NS_OK;
- }
- // PUDPSocketChild Methods
- bool
- UDPSocketChild::RecvCallbackOpened(const UDPAddressInfo& aAddressInfo)
- {
- mLocalAddress = aAddressInfo.addr();
- mLocalPort = aAddressInfo.port();
- UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, mLocalAddress.get(), mLocalPort));
- nsresult rv = mSocket->CallListenerOpened();
- mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
- return true;
- }
- // PUDPSocketChild Methods
- bool
- UDPSocketChild::RecvCallbackConnected(const UDPAddressInfo& aAddressInfo)
- {
- mLocalAddress = aAddressInfo.addr();
- mLocalPort = aAddressInfo.port();
- UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, mLocalAddress.get(), mLocalPort));
- nsresult rv = mSocket->CallListenerConnected();
- mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
- return true;
- }
- bool
- UDPSocketChild::RecvCallbackClosed()
- {
- nsresult rv = mSocket->CallListenerClosed();
- mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
- return true;
- }
- bool
- UDPSocketChild::RecvCallbackReceivedData(const UDPAddressInfo& aAddressInfo,
- InfallibleTArray<uint8_t>&& aData)
- {
- UDPSOCKET_LOG(("%s: %s:%u length %u", __FUNCTION__,
- aAddressInfo.addr().get(), aAddressInfo.port(), aData.Length()));
- nsresult rv = mSocket->CallListenerReceivedData(aAddressInfo.addr(), aAddressInfo.port(),
- aData.Elements(), aData.Length());
- mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
- return true;
- }
- bool
- UDPSocketChild::RecvCallbackError(const nsCString& aMessage,
- const nsCString& aFilename,
- const uint32_t& aLineNumber)
- {
- UDPSOCKET_LOG(("%s: %s:%s:%u", __FUNCTION__, aMessage.get(), aFilename.get(), aLineNumber));
- nsresult rv = mSocket->CallListenerError(aMessage, aFilename, aLineNumber);
- mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
- return true;
- }
- } // namespace dom
- } // namespace mozilla
|