dom/network/UDPSocketChild.cpp
author Kyle Huey <khuey@kylehuey.com>
Fri, 16 Jan 2015 11:58:52 -0800
changeset 251432 f498989ed56f3d5b4fae5e2bd1a0ca0c0f99014e
parent 237557 8ebe9660d12eb15ee8e6226223c95304f35df859
child 261388 a1d51e3fea63060a607372b24870d00a9596327c
permissions -rw-r--r--
Bug 1121673: Use move references in IPDL. r=bent

/* 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 "mozilla/unused.h"
#include "mozilla/ipc/InputStreamUtils.h"
#include "mozilla/net/NeckoChild.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()
:mLocalPort(0)
{
}

UDPSocketChild::~UDPSocketChild()
{
}

// nsIUDPSocketChild Methods

NS_IMETHODIMP
UDPSocketChild::Bind(nsIUDPSocketInternal* aSocket,
                     const nsACString& aHost,
                     uint16_t aPort,
                     bool aAddressReuse,
                     bool aLoopback)
{
  NS_ENSURE_ARG(aSocket);

  mSocket = aSocket;
  AddIPDLReference();

  gNeckoChild->SendPUDPSocketConstructor(this, mFilterName);

  SendBind(UDPAddressInfo(nsCString(aHost), aPort), aAddressReuse, aLoopback);
  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);

  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);

  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);

  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)) {
    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());

  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();

  nsresult rv = mSocket->CallListenerOpened();
  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)
{
  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)
{
  nsresult rv = mSocket->CallListenerError(aMessage, aFilename, aLineNumber);
  mozilla::unused << NS_WARN_IF(NS_FAILED(rv));

  return true;
}

} // namespace dom
} // namespace mozilla