Backed out 4 changesets (bug 745283) for merge conflicts with bug 786419.

Backed out changeset 70bad98676c8 (bug 745283)
Backed out changeset fc08327b3d3e (bug 745283)
Backed out changeset ce19c464f5d8 (bug 745283)
Backed out changeset c6ad8ab94461 (bug 745283)

--HG--
rename : netwerk/test/unit/test_udpsocket.js => netwerk/test/unit/test_bug952927.js
This commit is contained in:
Ryan VanderMeulen 2014-08-25 13:07:14 -04:00
parent 93344ab162
commit 388cb0948b
34 changed files with 419 additions and 2175 deletions

View File

@ -1013,6 +1013,3 @@ pref("services.mobileid.server.uri", "https://msisdn.services.mozilla.com");
#ifndef XP_WIN
pref("dom.mapped_arraybuffer.enabled", true);
#endif
// UDPSocket API
pref("dom.udpsocket.enabled", true);

View File

@ -52,11 +52,6 @@ this.PermissionsTable = { geolocation: {
privileged: ALLOW_ACTION,
certified: ALLOW_ACTION
},
"udp-socket": {
app: DENY_ACTION,
privileged: ALLOW_ACTION,
certified: ALLOW_ACTION
},
"network-events": {
app: DENY_ACTION,
privileged: DENY_ACTION,

View File

@ -6,7 +6,6 @@
#include "nsINetAddr.idl"
interface nsIUDPSocketInternal;
interface nsIInputStream;
%{ C++
namespace mozilla {
@ -18,7 +17,7 @@ union NetAddr;
native NetAddr(mozilla::net::NetAddr);
[ptr] native NetAddrPtr(mozilla::net::NetAddr);
[scriptable, uuid(5bb7de5a-8766-4c13-b9ed-14e63168dabf)]
[scriptable, uuid(B47E5A0F-D384-48EF-8885-4259793D9CF0)]
interface nsIUDPSocketChild : nsISupports
{
readonly attribute unsigned short localPort;
@ -26,8 +25,7 @@ interface nsIUDPSocketChild : nsISupports
attribute AUTF8String filterName;
// Tell the chrome process to bind the UDP socket to a given local host and port
void bind(in nsIUDPSocketInternal socket, in AUTF8String host, in unsigned short port,
in bool addressReuse, in bool loopback);
void bind(in nsIUDPSocketInternal socket, in AUTF8String host, in unsigned short port);
// Tell the chrome process to perform equivalent operations to all following methods
void send(in AUTF8String host, in unsigned short port,
@ -40,28 +38,21 @@ interface nsIUDPSocketChild : nsISupports
[noscript] void sendWithAddress([const] in NetAddrPtr addr,
[const, array, size_is(byteLength)] in uint8_t bytes,
in unsigned long byteLength);
// Send input stream. This must be a buffered stream implementation.
void sendBinaryStream(in AUTF8String host, in unsigned short port, in nsIInputStream stream);
void close();
void joinMulticast(in AUTF8String multicastAddress, in AUTF8String iface);
void leaveMulticast(in AUTF8String multicastAddress, in AUTF8String iface);
};
/*
* Internal interface for callback from chrome process
*/
[scriptable, uuid(44cd9ad5-d574-4169-baf9-e1af0648a143)]
[scriptable, uuid(1E27E9B3-C1C8-4B05-A415-1A2C1A641C60)]
interface nsIUDPSocketInternal : nsISupports
{
// callback while socket is opened. localPort and localAddress is ready until this time.
void callListenerOpened();
// callback while socket is closed.
void callListenerClosed();
// callback while incoming packet is received.
void callListenerReceivedData(in AUTF8String host, in unsigned short port,
[const, array, size_is(dataLength)] in uint8_t data,
void callListenerError(in AUTF8String type, in AUTF8String message, in AUTF8String filename,
in uint32_t lineNumber, in uint32_t columnNumber);
void callListenerReceivedData(in AUTF8String type, in AUTF8String host, in unsigned short port,
[array, size_is(dataLength)] in uint8_t data,
in unsigned long dataLength);
// callback while any error happened.
void callListenerError(in AUTF8String message, in AUTF8String filename, in uint32_t lineNumber);
void callListenerVoid(in AUTF8String type);
void callListenerSent(in AUTF8String type, in nsresult status);
void updateReadyState(in AUTF8String readyState);
};

View File

@ -6,8 +6,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PNecko;
include protocol PBlob;
include InputStreamParams;
include "mozilla/net/NeckoMessageUtils.h";
include "mozilla/net/DNS.h";
@ -16,19 +14,34 @@ include "prio.h";
using mozilla::net::NetAddr from "mozilla/net/DNS.h";
using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
struct UDPError {
nsCString message;
nsCString filename;
uint32_t lineNumber;
uint32_t columnNumber;
};
struct UDPMessage {
nsCString fromAddr;
uint16_t port;
uint8_t[] data;
};
struct UDPAddressInfo {
nsCString addr;
nsCString local;
uint16_t port;
};
union UDPSocketAddr {
UDPAddressInfo;
NetAddr;
struct UDPSendResult {
nsresult value;
};
union UDPData {
uint8_t[];
InputStreamParams;
union UDPCallbackData {
void_t;
UDPMessage;
UDPAddressInfo;
UDPSendResult;
UDPError;
};
namespace mozilla {
@ -40,22 +53,13 @@ protocol PUDPSocket
manager PNecko;
parent:
Bind(UDPAddressInfo addressInfo, bool addressReuse, bool loopback);
OutgoingData(UDPData data, UDPSocketAddr addr);
JoinMulticast(nsCString multicastAddress, nsCString iface);
LeaveMulticast(nsCString multicastAddress, nsCString iface);
Data(uint8_t[] data, nsCString remoteAddress, uint16_t port);
DataWithAddress(uint8_t[] data, NetAddr addr);
Close();
RequestDelete();
child:
CallbackOpened(UDPAddressInfo addressInfo);
CallbackClosed();
CallbackReceivedData(UDPAddressInfo addressInfo, uint8_t[] data);
CallbackError(nsCString message, nsCString filename, uint32_t lineNumber);
Callback(nsCString type, UDPCallbackData data, nsCString aState);
__delete__();
};

View File

@ -1,705 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "UDPSocket.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/dom/ErrorEvent.h"
#include "mozilla/dom/UDPMessageEvent.h"
#include "mozilla/dom/UDPSocketBinding.h"
#include "mozilla/dom/UnionTypes.h"
#include "mozilla/net/DNS.h"
#include "nsComponentManagerUtils.h"
#include "nsContentUtils.h"
#include "nsIDOMFile.h"
#include "nsINetAddr.h"
#include "nsStringStream.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_CLASS(UDPSocket)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(UDPSocket, DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOpened)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mClosed)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(UDPSocket, DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOpened)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mClosed)
tmp->CloseWithReason(NS_OK);
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_ADDREF_INHERITED(UDPSocket, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(UDPSocket, DOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(UDPSocket)
NS_INTERFACE_MAP_ENTRY(nsIUDPSocketListener)
NS_INTERFACE_MAP_ENTRY(nsIUDPSocketInternal)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
/* static */ already_AddRefed<UDPSocket>
UDPSocket::Constructor(const GlobalObject& aGlobal,
const UDPOptions& aOptions,
ErrorResult& aRv)
{
nsCOMPtr<nsPIDOMWindow> ownerWindow = do_QueryInterface(aGlobal.GetAsSupports());
if (!ownerWindow) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
bool addressReuse = aOptions.mAddressReuse;
bool loopback = aOptions.mLoopback;
nsCString remoteAddress;
if (aOptions.mRemoteAddress.WasPassed()) {
remoteAddress = NS_ConvertUTF16toUTF8(aOptions.mRemoteAddress.Value());
} else {
remoteAddress.SetIsVoid(true);
}
Nullable<uint16_t> remotePort;
if (aOptions.mRemotePort.WasPassed()) {
remotePort.SetValue(aOptions.mRemotePort.Value());
if (remotePort.Value() == 0) {
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return nullptr;
}
}
nsString localAddress;
if (aOptions.mLocalAddress.WasPassed()) {
localAddress = aOptions.mLocalAddress.Value();
// check if localAddress is a valid IPv4/6 address
NS_ConvertUTF16toUTF8 address(localAddress);
PRNetAddr prAddr;
PRStatus status = PR_StringToNetAddr(address.BeginReading(), &prAddr);
if (status != PR_SUCCESS) {
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return nullptr;
}
} else {
SetDOMStringToNull(localAddress);
}
Nullable<uint16_t> localPort;
if (aOptions.mLocalPort.WasPassed()) {
localPort.SetValue(aOptions.mLocalPort.Value());
if (localPort.Value() == 0) {
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return nullptr;
}
}
nsRefPtr<UDPSocket> socket = new UDPSocket(ownerWindow, remoteAddress, remotePort);
aRv = socket->Init(localAddress, localPort, addressReuse, loopback);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return socket.forget();
}
UDPSocket::UDPSocket(nsPIDOMWindow* aOwner,
const nsCString& aRemoteAddress,
const Nullable<uint16_t>& aRemotePort)
: DOMEventTargetHelper(aOwner)
, mRemoteAddress(aRemoteAddress)
, mRemotePort(aRemotePort)
, mReadyState(SocketReadyState::Opening)
{
MOZ_ASSERT(aOwner);
MOZ_ASSERT(aOwner->IsInnerWindow());
nsIDocument* aDoc = aOwner->GetExtantDoc();
if (aDoc) {
aDoc->DisallowBFCaching();
}
}
UDPSocket::~UDPSocket()
{
CloseWithReason(NS_OK);
}
JSObject*
UDPSocket::WrapObject(JSContext* aCx)
{
return UDPSocketBinding::Wrap(aCx, this);
}
void
UDPSocket::DisconnectFromOwner()
{
DOMEventTargetHelper::DisconnectFromOwner();
CloseWithReason(NS_OK);
}
already_AddRefed<Promise>
UDPSocket::Close()
{
MOZ_ASSERT(mClosed);
nsRefPtr<Promise> promise = mClosed;
if (mReadyState == SocketReadyState::Closed) {
return promise.forget();
}
CloseWithReason(NS_OK);
return promise.forget();
}
void
UDPSocket::CloseWithReason(nsresult aReason)
{
if (mReadyState == SocketReadyState::Closed) {
return;
}
if (mOpened) {
if (mReadyState == SocketReadyState::Opening) {
// reject openedPromise with AbortError if socket is closed without error
nsresult openFailedReason = NS_FAILED(aReason) ? aReason : NS_ERROR_DOM_ABORT_ERR;
mOpened->MaybeReject(openFailedReason);
}
}
mReadyState = SocketReadyState::Closed;
if (mSocket) {
mSocket->Close();
mSocket = nullptr;
}
if (mSocketChild) {
mSocketChild->Close();
mSocketChild = nullptr;
}
if (mClosed) {
if (NS_SUCCEEDED(aReason)) {
mClosed->MaybeResolve(JS::UndefinedHandleValue);
} else {
mClosed->MaybeReject(aReason);
}
}
mPendingMcastCommands.Clear();
}
void
UDPSocket::JoinMulticastGroup(const nsAString& aMulticastGroupAddress,
ErrorResult& aRv)
{
if (mReadyState == SocketReadyState::Closed) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
if (mReadyState == SocketReadyState::Opening) {
MulticastCommand joinCommand(MulticastCommand::Join, aMulticastGroupAddress);
mPendingMcastCommands.AppendElement(joinCommand);
return;
}
MOZ_ASSERT(mSocket || mSocketChild);
NS_ConvertUTF16toUTF8 address(aMulticastGroupAddress);
if (mSocket) {
MOZ_ASSERT(!mSocketChild);
aRv = mSocket->JoinMulticast(address, EmptyCString());
NS_WARN_IF(aRv.Failed());
return;
}
MOZ_ASSERT(mSocketChild);
aRv = mSocketChild->JoinMulticast(address, EmptyCString());
NS_WARN_IF(aRv.Failed());
}
void
UDPSocket::LeaveMulticastGroup(const nsAString& aMulticastGroupAddress,
ErrorResult& aRv)
{
if (mReadyState == SocketReadyState::Closed) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
if (mReadyState == SocketReadyState::Opening) {
MulticastCommand leaveCommand(MulticastCommand::Leave, aMulticastGroupAddress);
mPendingMcastCommands.AppendElement(leaveCommand);
return;
}
MOZ_ASSERT(mSocket || mSocketChild);
nsCString address = NS_ConvertUTF16toUTF8(aMulticastGroupAddress);
if (mSocket) {
MOZ_ASSERT(!mSocketChild);
aRv = mSocket->LeaveMulticast(address, EmptyCString());
NS_WARN_IF(aRv.Failed());
return;
}
MOZ_ASSERT(mSocketChild);
aRv = mSocketChild->LeaveMulticast(address, EmptyCString());
NS_WARN_IF(aRv.Failed());
}
nsresult
UDPSocket::DoPendingMcastCommand()
{
MOZ_ASSERT(mReadyState == SocketReadyState::Open, "Multicast command can only be executed after socket opened");
for (uint32_t i = 0; i < mPendingMcastCommands.Length(); ++i) {
MulticastCommand& command = mPendingMcastCommands[i];
ErrorResult rv;
switch (command.mCommand) {
case MulticastCommand::Join: {
JoinMulticastGroup(command.mAddress, rv);
break;
}
case MulticastCommand::Leave: {
LeaveMulticastGroup(command.mAddress, rv);
break;
}
}
if (NS_WARN_IF(rv.Failed())) {
return rv.ErrorCode();
}
}
mPendingMcastCommands.Clear();
return NS_OK;
}
bool
UDPSocket::Send(const StringOrBlobOrArrayBufferOrArrayBufferView& aData,
const Optional<nsAString>& aRemoteAddress,
const Optional<Nullable<uint16_t>>& aRemotePort,
ErrorResult& aRv)
{
if (mReadyState != SocketReadyState::Open) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return false;
}
MOZ_ASSERT(mSocket || mSocketChild);
// If the remote address and port were not specified in the constructor or as arguments,
// throw InvalidAccessError.
nsCString remoteAddress;
if (aRemoteAddress.WasPassed()) {
remoteAddress = NS_ConvertUTF16toUTF8(aRemoteAddress.Value());
} else if (!mRemoteAddress.IsVoid()) {
remoteAddress = mRemoteAddress;
} else {
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return false;
}
uint16_t remotePort;
if (aRemotePort.WasPassed() && !aRemotePort.Value().IsNull()) {
remotePort = aRemotePort.Value().Value();
} else if (!mRemotePort.IsNull()) {
remotePort = mRemotePort.Value();
} else {
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return false;
}
nsCOMPtr<nsIInputStream> stream;
if (aData.IsBlob()) {
nsCOMPtr<nsIDOMBlob> blob = aData.GetAsBlob();
aRv = blob->GetInternalStream(getter_AddRefs(stream));
if (NS_WARN_IF(aRv.Failed())) {
return false;
}
} else {
nsresult rv;
nsCOMPtr<nsIStringInputStream> strStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
return false;
}
if (aData.IsString()) {
NS_ConvertUTF16toUTF8 data(aData.GetAsString());
aRv = strStream->SetData(data.BeginReading(), data.Length());
} else if (aData.IsArrayBuffer()) {
const ArrayBuffer& data = aData.GetAsArrayBuffer();
data.ComputeLengthAndData();
aRv = strStream->SetData(reinterpret_cast<const char*>(data.Data()), data.Length());
} else {
const ArrayBufferView& data = aData.GetAsArrayBufferView();
data.ComputeLengthAndData();
aRv = strStream->SetData(reinterpret_cast<const char*>(data.Data()), data.Length());
}
if (NS_WARN_IF(aRv.Failed())) {
return false;
}
stream = strStream;
}
if (mSocket) {
aRv = mSocket->SendBinaryStream(remoteAddress, remotePort, stream);
} else if (mSocketChild) {
aRv = mSocketChild->SendBinaryStream(remoteAddress, remotePort, stream);
}
if (NS_WARN_IF(aRv.Failed())) {
return false;
}
return true;
}
nsresult
UDPSocket::InitLocal(const nsAString& aLocalAddress,
const uint16_t& aLocalPort)
{
nsresult rv;
nsCOMPtr<nsIUDPSocket> sock =
do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
if (NS_FAILED(rv)) {
return rv;
}
if (aLocalAddress.IsEmpty()) {
rv = sock->Init(aLocalPort, /* loopback = */ false, mAddressReuse, /* optionalArgc = */ 1);
} else {
PRNetAddr prAddr;
PR_InitializeNetAddr(PR_IpAddrAny, aLocalPort, &prAddr);
PR_StringToNetAddr(NS_ConvertUTF16toUTF8(aLocalAddress).BeginReading(), &prAddr);
mozilla::net::NetAddr addr;
PRNetAddrToNetAddr(&prAddr, &addr);
rv = sock->InitWithAddress(&addr, mAddressReuse, /* optionalArgc = */ 1);
}
if (NS_FAILED(rv)) {
return rv;
}
rv = sock->SetMulticastLoopback(mLoopback);
if (NS_FAILED(rv)) {
return rv;
}
mSocket = sock;
// Get real local address and local port
nsCOMPtr<nsINetAddr> localAddr;
rv = mSocket->GetLocalAddr(getter_AddRefs(localAddr));
if (NS_FAILED(rv)) {
return rv;
}
nsCString localAddress;
rv = localAddr->GetAddress(localAddress);
if (NS_FAILED(rv)) {
return rv;
}
mLocalAddress = NS_ConvertUTF8toUTF16(localAddress);
uint16_t localPort;
rv = localAddr->GetPort(&localPort);
if (NS_FAILED(rv)) {
return rv;
}
mLocalPort.SetValue(localPort);
rv = mSocket->AsyncListen(this);
if (NS_FAILED(rv)) {
return rv;
}
mReadyState = SocketReadyState::Open;
rv = DoPendingMcastCommand();
if (NS_FAILED(rv)) {
return rv;
}
mOpened->MaybeResolve(JS::UndefinedHandleValue);
return NS_OK;
}
nsresult
UDPSocket::InitRemote(const nsAString& aLocalAddress,
const uint16_t& aLocalPort)
{
nsresult rv;
nsCOMPtr<nsIUDPSocketChild> sock =
do_CreateInstance("@mozilla.org/udp-socket-child;1", &rv);
if (NS_FAILED(rv)) {
return rv;
}
rv = sock->Bind(this, NS_ConvertUTF16toUTF8(aLocalAddress), aLocalPort, mAddressReuse, mLoopback);
if (NS_FAILED(rv)) {
return rv;
}
mSocketChild = sock;
return NS_OK;
}
nsresult
UDPSocket::Init(const nsString& aLocalAddress,
const Nullable<uint16_t>& aLocalPort,
const bool& aAddressReuse,
const bool& aLoopback)
{
MOZ_ASSERT(!mSocket && !mSocketChild);
mLocalAddress = aLocalAddress;
mLocalPort = aLocalPort;
mAddressReuse = aAddressReuse;
mLoopback = aLoopback;
ErrorResult rv;
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
mOpened = Promise::Create(global, rv);
if (NS_WARN_IF(rv.Failed())) {
return rv.ErrorCode();
}
mClosed = Promise::Create(global, rv);
if (NS_WARN_IF(rv.Failed())) {
return rv.ErrorCode();
}
class OpenSocketRunnable MOZ_FINAL : public nsRunnable
{
public:
OpenSocketRunnable(UDPSocket* aSocket) : mSocket(aSocket)
{ }
NS_IMETHOD Run() MOZ_OVERRIDE
{
MOZ_ASSERT(mSocket);
if (mSocket->mReadyState != SocketReadyState::Opening) {
return NS_OK;
}
uint16_t localPort = 0;
if (!mSocket->mLocalPort.IsNull()) {
localPort = mSocket->mLocalPort.Value();
}
nsresult rv;
if (XRE_GetProcessType() != GeckoProcessType_Default) {
rv = mSocket->InitRemote(mSocket->mLocalAddress, localPort);
} else {
rv = mSocket->InitLocal(mSocket->mLocalAddress, localPort);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
mSocket->CloseWithReason(NS_ERROR_DOM_NETWORK_ERR);
}
return NS_OK;
}
private:
nsRefPtr<UDPSocket> mSocket;
};
nsCOMPtr<nsIRunnable> runnable = new OpenSocketRunnable(this);
return NS_DispatchToMainThread(runnable);
}
void
UDPSocket::HandleReceivedData(const nsACString& aRemoteAddress,
const uint16_t& aRemotePort,
const uint8_t* aData,
const uint32_t& aDataLength)
{
if (mReadyState != SocketReadyState::Open) {
return;
}
if (NS_FAILED(CheckInnerWindowCorrectness())) {
return;
}
if (NS_FAILED(DispatchReceivedData(aRemoteAddress, aRemotePort, aData, aDataLength))) {
CloseWithReason(NS_ERROR_TYPE_ERR);
}
}
nsresult
UDPSocket::DispatchReceivedData(const nsACString& aRemoteAddress,
const uint16_t& aRemotePort,
const uint8_t* aData,
const uint32_t& aDataLength)
{
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(GetOwner()))) {
return NS_ERROR_FAILURE;
}
JSContext* cx = jsapi.cx();
// Copy packet data to ArrayBuffer
JS::Rooted<JSObject*> arrayBuf(cx, ArrayBuffer::Create(cx, aDataLength, aData));
if (NS_WARN_IF(!arrayBuf)) {
return NS_ERROR_FAILURE;
}
JS::Rooted<JS::Value> jsData(cx, JS::ObjectValue(*arrayBuf));
// Create DOM event
RootedDictionary<UDPMessageEventInit> init(cx);
init.mRemoteAddress = NS_ConvertUTF8toUTF16(aRemoteAddress);
init.mRemotePort = aRemotePort;
init.mData = jsData;
nsRefPtr<UDPMessageEvent> udpEvent =
UDPMessageEvent::Constructor(this, NS_LITERAL_STRING("message"), init);
if (NS_WARN_IF(!udpEvent)) {
return NS_ERROR_FAILURE;
}
udpEvent->SetTrusted(true);
nsRefPtr<AsyncEventDispatcher> asyncDispatcher = new AsyncEventDispatcher(this, udpEvent);
return asyncDispatcher->PostDOMEvent();
}
// nsIUDPSocketListener
NS_IMETHODIMP
UDPSocket::OnPacketReceived(nsIUDPSocket* aSocket, nsIUDPMessage* aMessage)
{
// nsIUDPSocketListener callbacks should be invoked on main thread.
MOZ_ASSERT(NS_IsMainThread(), "Not running on main thread");
// Create appropriate JS object for message
FallibleTArray<uint8_t>& buffer = aMessage->GetDataAsTArray();
nsCOMPtr<nsINetAddr> addr;
if (NS_WARN_IF(NS_FAILED(aMessage->GetFromAddr(getter_AddRefs(addr))))) {
return NS_OK;
}
nsCString remoteAddress;
if (NS_WARN_IF(NS_FAILED(addr->GetAddress(remoteAddress)))) {
return NS_OK;
}
uint16_t remotePort;
if (NS_WARN_IF(NS_FAILED(addr->GetPort(&remotePort)))) {
return NS_OK;
}
HandleReceivedData(remoteAddress, remotePort, buffer.Elements(), buffer.Length());
return NS_OK;
}
NS_IMETHODIMP
UDPSocket::OnStopListening(nsIUDPSocket* aSocket, nsresult aStatus)
{
// nsIUDPSocketListener callbacks should be invoked on main thread.
MOZ_ASSERT(NS_IsMainThread(), "Not running on main thread");
CloseWithReason(aStatus);
return NS_OK;
}
// nsIUDPSocketInternal
NS_IMETHODIMP
UDPSocket::CallListenerError(const nsACString& aMessage,
const nsACString& aFilename,
uint32_t aLineNumber)
{
CloseWithReason(NS_ERROR_DOM_NETWORK_ERR);
return NS_OK;
}
NS_IMETHODIMP
UDPSocket::CallListenerReceivedData(const nsACString& aRemoteAddress,
uint16_t aRemotePort,
const uint8_t* aData,
uint32_t aDataLength)
{
HandleReceivedData(aRemoteAddress, aRemotePort, aData, aDataLength);
return NS_OK;
}
NS_IMETHODIMP
UDPSocket::CallListenerOpened()
{
if (mReadyState != SocketReadyState::Opening) {
return NS_OK;
}
MOZ_ASSERT(mSocketChild);
// Get real local address and local port
nsCString localAddress;
mSocketChild->GetLocalAddress(localAddress);
mLocalAddress = NS_ConvertUTF8toUTF16(localAddress);
uint16_t localPort;
mSocketChild->GetLocalPort(&localPort);
mLocalPort.SetValue(localPort);
mReadyState = SocketReadyState::Open;
nsresult rv = DoPendingMcastCommand();
if (NS_WARN_IF(NS_FAILED(rv))) {
CloseWithReason(rv);
return NS_OK;
}
mOpened->MaybeResolve(JS::UndefinedHandleValue);
return NS_OK;
}
NS_IMETHODIMP
UDPSocket::CallListenerClosed()
{
CloseWithReason(NS_OK);
return NS_OK;
}
} // namespace dom
} // namespace mozilla

View File

@ -1,197 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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_dom_UDPSocket_h__
#define mozilla_dom_UDPSocket_h__
#include "mozilla/Attributes.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/SocketCommonBinding.h"
#include "nsIUDPSocket.h"
#include "nsIUDPSocketChild.h"
#include "nsTArray.h"
struct JSContext;
namespace mozilla {
namespace dom {
struct UDPOptions;
class StringOrBlobOrArrayBufferOrArrayBufferView;
class UDPSocket MOZ_FINAL : public DOMEventTargetHelper
, public nsIUDPSocketListener
, public nsIUDPSocketInternal
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(UDPSocket, DOMEventTargetHelper)
NS_DECL_NSIUDPSOCKETLISTENER
NS_DECL_NSIUDPSOCKETINTERNAL
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
public:
nsPIDOMWindow*
GetParentObject() const
{
return GetOwner();
}
virtual JSObject*
WrapObject(JSContext* aCx) MOZ_OVERRIDE;
virtual void
DisconnectFromOwner() MOZ_OVERRIDE;
static already_AddRefed<UDPSocket>
Constructor(const GlobalObject& aGlobal, const UDPOptions& aOptions, ErrorResult& aRv);
void
GetLocalAddress(nsString& aRetVal) const
{
aRetVal = mLocalAddress;
}
Nullable<uint16_t>
GetLocalPort() const
{
return mLocalPort;
}
void
GetRemoteAddress(nsString& aRetVal) const
{
if (mRemoteAddress.IsVoid()) {
SetDOMStringToNull(aRetVal);
return;
}
aRetVal = NS_ConvertUTF8toUTF16(mRemoteAddress);
}
Nullable<uint16_t>
GetRemotePort() const
{
return mRemotePort;
}
bool
AddressReuse() const
{
return mAddressReuse;
}
bool
Loopback() const
{
return mLoopback;
}
SocketReadyState
ReadyState() const
{
return mReadyState;
}
Promise*
Opened() const
{
return mOpened;
}
Promise*
Closed() const
{
return mClosed;
}
IMPL_EVENT_HANDLER(message)
already_AddRefed<Promise>
Close();
void
JoinMulticastGroup(const nsAString& aMulticastGroupAddress, ErrorResult& aRv);
void
LeaveMulticastGroup(const nsAString& aMulticastGroupAddress, ErrorResult& aRv);
bool
Send(const StringOrBlobOrArrayBufferOrArrayBufferView& aData,
const Optional<nsAString>& aRemoteAddress,
const Optional<Nullable<uint16_t>>& aRemotePort,
ErrorResult& aRv);
private:
UDPSocket(nsPIDOMWindow* aOwner,
const nsCString& aRemoteAddress,
const Nullable<uint16_t>& aRemotePort);
virtual ~UDPSocket();
nsresult
Init(const nsString& aLocalAddress,
const Nullable<uint16_t>& aLocalPort,
const bool& aAddressReuse,
const bool& aLoopback);
nsresult
InitLocal(const nsAString& aLocalAddress, const uint16_t& aLocalPort);
nsresult
InitRemote(const nsAString& aLocalAddress, const uint16_t& aLocalPort);
void
HandleReceivedData(const nsACString& aRemoteAddress,
const uint16_t& aRemotePort,
const uint8_t* aData,
const uint32_t& aDataLength);
nsresult
DispatchReceivedData(const nsACString& aRemoteAddress,
const uint16_t& aRemotePort,
const uint8_t* aData,
const uint32_t& aDataLength);
void
CloseWithReason(nsresult aReason);
nsresult
DoPendingMcastCommand();
nsString mLocalAddress;
Nullable<uint16_t> mLocalPort;
nsCString mRemoteAddress;
Nullable<uint16_t> mRemotePort;
bool mAddressReuse;
bool mLoopback;
SocketReadyState mReadyState;
nsRefPtr<Promise> mOpened;
nsRefPtr<Promise> mClosed;
nsCOMPtr<nsIUDPSocket> mSocket;
nsCOMPtr<nsIUDPSocketChild> mSocketChild;
struct MulticastCommand {
enum CommandType { Join, Leave };
MulticastCommand(CommandType aCommand, const nsAString& aAddress)
: mCommand(aCommand), mAddress(aAddress)
{ }
CommandType mCommand;
nsString mAddress;
};
nsTArray<MulticastCommand> mPendingMcastCommands;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_UDPSocket_h__

View File

@ -3,8 +3,6 @@
* 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;
@ -61,20 +59,17 @@ UDPSocketChild::~UDPSocketChild()
// nsIUDPSocketChild Methods
NS_IMETHODIMP
UDPSocketChild::Bind(nsIUDPSocketInternal* aSocket,
UDPSocketChild::Bind(nsIUDPSocketInternal *aSocket,
const nsACString& aHost,
uint16_t aPort,
bool aAddressReuse,
bool aLoopback)
uint16_t aPort)
{
NS_ENSURE_ARG(aSocket);
mSocket = aSocket;
AddIPDLReference();
gNeckoChild->SendPUDPSocketConstructor(this, mFilterName);
gNeckoChild->SendPUDPSocketConstructor(this, nsCString(aHost), aPort, mFilterName);
SendBind(UDPAddressInfo(nsCString(aHost), aPort), aAddressReuse, aLoopback);
return NS_OK;
}
@ -88,47 +83,11 @@ UDPSocketChild::Close()
NS_IMETHODIMP
UDPSocketChild::Send(const nsACString& aHost,
uint16_t aPort,
const uint8_t* aData,
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;
@ -136,48 +95,47 @@ UDPSocketChild::SendDataInternal(const UDPSocketAddr& aAddr,
InfallibleTArray<uint8_t> array;
array.SwapElements(fallibleArray);
SendOutgoingData(array, aAddr);
SendData(array, nsCString(aHost), aPort);
return NS_OK;
}
NS_IMETHODIMP
UDPSocketChild::SendBinaryStream(const nsACString& aHost,
uint16_t aPort,
nsIInputStream* aStream)
UDPSocketChild::SendWithAddr(nsINetAddr *aAddr,
const uint8_t *aData,
uint32_t aByteLength)
{
NS_ENSURE_ARG(aStream);
NS_ENSURE_ARG(aAddr);
NS_ENSURE_ARG(aData);
OptionalInputStreamParams stream;
nsTArray<mozilla::ipc::FileDescriptor> fds;
SerializeInputStream(aStream, stream, fds);
NetAddr addr;
aAddr->GetNetAddr(&addr);
MOZ_ASSERT(fds.IsEmpty());
SendOutgoingData(UDPData(stream), UDPSocketAddr(UDPAddressInfo(nsCString(aHost), aPort)));
return NS_OK;
return SendWithAddress(&addr, aData, aByteLength);
}
NS_IMETHODIMP
UDPSocketChild::JoinMulticast(const nsACString& aMulticastAddress,
const nsACString& aInterface)
UDPSocketChild::SendWithAddress(const NetAddr *aAddr,
const uint8_t *aData,
uint32_t aByteLength)
{
SendJoinMulticast(nsCString(aMulticastAddress), nsCString(aInterface));
NS_ENSURE_ARG(aAddr);
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);
SendDataWithAddress(array, *aAddr);
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)
UDPSocketChild::GetLocalPort(uint16_t *aLocalPort)
{
NS_ENSURE_ARG_POINTER(aLocalPort);
@ -186,14 +144,14 @@ UDPSocketChild::GetLocalPort(uint16_t* aLocalPort)
}
NS_IMETHODIMP
UDPSocketChild::GetLocalAddress(nsACString& aLocalAddress)
UDPSocketChild::GetLocalAddress(nsACString &aLocalAddress)
{
aLocalAddress = mLocalAddress;
return NS_OK;
}
NS_IMETHODIMP
UDPSocketChild::SetFilterName(const nsACString& aFilterName)
UDPSocketChild::SetFilterName(const nsACString &aFilterName)
{
if (!mFilterName.IsEmpty()) {
// filter name can only be set once.
@ -204,7 +162,7 @@ UDPSocketChild::SetFilterName(const nsACString& aFilterName)
}
NS_IMETHODIMP
UDPSocketChild::GetFilterName(nsACString& aFilterName)
UDPSocketChild::GetFilterName(nsACString &aFilterName)
{
aFilterName = mFilterName;
return NS_OK;
@ -212,44 +170,39 @@ UDPSocketChild::GetFilterName(nsACString& aFilterName)
// PUDPSocketChild Methods
bool
UDPSocketChild::RecvCallbackOpened(const UDPAddressInfo& aAddressInfo)
UDPSocketChild::RecvCallback(const nsCString &aType,
const UDPCallbackData &aData,
const nsCString &aState)
{
mLocalAddress = aAddressInfo.addr();
mLocalPort = aAddressInfo.port();
if (NS_FAILED(mSocket->UpdateReadyState(aState)))
NS_ERROR("Shouldn't fail!");
nsresult rv = mSocket->CallListenerOpened();
mozilla::unused << NS_WARN_IF(NS_FAILED(rv));
nsresult rv = NS_ERROR_FAILURE;
if (aData.type() == UDPCallbackData::Tvoid_t) {
rv = mSocket->CallListenerVoid(aType);
} else if (aData.type() == UDPCallbackData::TUDPError) {
const UDPError& err(aData.get_UDPError());
rv = mSocket->CallListenerError(aType, err.message(), err.filename(),
err.lineNumber(), err.columnNumber());
} else if (aData.type() == UDPCallbackData::TUDPMessage) {
const UDPMessage& message(aData.get_UDPMessage());
InfallibleTArray<uint8_t> data(message.data());
rv = mSocket->CallListenerReceivedData(aType, message.fromAddr(), message.port(),
data.Elements(), data.Length());
} else if (aData.type() == UDPCallbackData::TUDPAddressInfo) {
//update local address and port.
const UDPAddressInfo& addressInfo(aData.get_UDPAddressInfo());
mLocalAddress = addressInfo.local();
mLocalPort = addressInfo.port();
rv = mSocket->CallListenerVoid(aType);
} else if (aData.type() == UDPCallbackData::TUDPSendResult) {
const UDPSendResult& returnValue(aData.get_UDPSendResult());
rv = mSocket->CallListenerSent(aType, returnValue.value());
} else {
MOZ_ASSERT(false, "Invalid callback type!");
}
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,
const 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));
NS_ENSURE_SUCCESS(rv, true);
return true;
}

View File

@ -40,19 +40,10 @@ public:
UDPSocketChild();
virtual ~UDPSocketChild();
virtual bool RecvCallbackOpened(const UDPAddressInfo& aAddressInfo) MOZ_OVERRIDE;
virtual bool RecvCallbackClosed() MOZ_OVERRIDE;
virtual bool RecvCallbackReceivedData(const UDPAddressInfo& aAddressInfo,
const InfallibleTArray<uint8_t>& aData) MOZ_OVERRIDE;
virtual bool RecvCallbackError(const nsCString& aMessage,
const nsCString& aFilename,
const uint32_t& aLineNumber) MOZ_OVERRIDE;
virtual bool RecvCallback(const nsCString& aType,
const UDPCallbackData& aData,
const nsCString& aState) MOZ_OVERRIDE;
private:
nsresult SendDataInternal(const UDPSocketAddr& aAddr,
const uint8_t* aData,
const uint32_t aByteLength);
uint16_t mLocalPort;
nsCString mLocalAddress;
nsCString mFilterName;

View File

@ -9,279 +9,181 @@
#include "nsComponentManagerUtils.h"
#include "nsIUDPSocket.h"
#include "nsINetAddr.h"
#include "mozilla/AppProcessChecker.h"
#include "mozilla/unused.h"
#include "mozilla/ipc/InputStreamUtils.h"
#include "mozilla/net/DNS.h"
#include "mozilla/net/NeckoCommon.h"
#include "mozilla/net/PNeckoParent.h"
namespace mozilla {
namespace dom {
static void
FireInternalError(mozilla::net::PUDPSocketParent *aActor, uint32_t aLineNo)
{
mozilla::unused <<
aActor->SendCallback(NS_LITERAL_CSTRING("onerror"),
UDPError(NS_LITERAL_CSTRING("Internal error"),
NS_LITERAL_CSTRING(__FILE__), aLineNo, 0),
NS_LITERAL_CSTRING("connecting"));
}
static nsresult
ConvertNetAddrToString(mozilla::net::NetAddr &netAddr, nsACString *address, uint16_t *port)
{
NS_ENSURE_ARG_POINTER(address);
NS_ENSURE_ARG_POINTER(port);
*port = 0;
uint32_t bufSize = 0;
switch(netAddr.raw.family) {
case AF_INET:
*port = PR_ntohs(netAddr.inet.port);
bufSize = mozilla::net::kIPv4CStrBufSize;
break;
case AF_INET6:
*port = PR_ntohs(netAddr.inet6.port);
bufSize = mozilla::net::kIPv6CStrBufSize;
break;
default:
//impossible
MOZ_ASSERT(false, "Unexpected address family");
return NS_ERROR_INVALID_ARG;
}
address->SetCapacity(bufSize);
NetAddrToString(&netAddr, address->BeginWriting(), bufSize);
address->SetLength(strlen(address->BeginReading()));
return NS_OK;
}
NS_IMPL_ISUPPORTS(UDPSocketParent, nsIUDPSocketListener)
UDPSocketParent::~UDPSocketParent()
{
}
bool
UDPSocketParent::Init(const nsACString& aFilter)
{
if (!aFilter.IsEmpty()) {
nsAutoCString contractId(NS_NETWORK_UDP_SOCKET_FILTER_HANDLER_PREFIX);
contractId.Append(aFilter);
nsCOMPtr<nsIUDPSocketFilterHandler> filterHandler =
do_GetService(contractId.get());
if (filterHandler) {
nsresult rv = filterHandler->NewFilter(getter_AddRefs(mFilter));
if (NS_FAILED(rv)) {
printf_stderr("Cannot create filter that content specified. "
"filter name: %s, error code: %d.", aFilter.BeginReading(), rv);
return false;
}
} else {
printf_stderr("Content doesn't have a valid filter. "
"filter name: %s.", aFilter.BeginReading());
return false;
}
}
return true;
}
// PUDPSocketParent methods
bool
UDPSocketParent::RecvBind(const UDPAddressInfo& aAddressInfo,
const bool& aAddressReuse, const bool& aLoopback)
{
// We don't have browser actors in xpcshell, and hence can't run automated
// tests without this loophole.
if (net::UsingNeckoIPCSecurity() && !mFilter &&
!AssertAppProcessPermission(Manager()->Manager(), "udp-socket")) {
FireInternalError(__LINE__);
return false;
}
if (NS_FAILED(BindInternal(aAddressInfo.addr(), aAddressInfo.port(), aAddressReuse, aLoopback))) {
FireInternalError(__LINE__);
return true;
}
nsCOMPtr<nsINetAddr> localAddr;
mSocket->GetLocalAddr(getter_AddRefs(localAddr));
nsCString addr;
if (NS_FAILED(localAddr->GetAddress(addr))) {
FireInternalError(__LINE__);
return true;
}
uint16_t port;
if (NS_FAILED(localAddr->GetPort(&port))) {
FireInternalError(__LINE__);
return true;
}
mozilla::unused << SendCallbackOpened(UDPAddressInfo(addr, port));
return true;
}
nsresult
UDPSocketParent::BindInternal(const nsCString& aHost, const uint16_t& aPort,
const bool& aAddressReuse, const bool& aLoopback)
UDPSocketParent::Init(const nsCString &aHost, const uint16_t aPort)
{
nsresult rv;
NS_ASSERTION(mFilter, "No packet filter");
nsCOMPtr<nsIUDPSocket> sock =
do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
if (NS_FAILED(rv)) {
FireInternalError(this, __LINE__);
return true;
}
if (aHost.IsEmpty()) {
rv = sock->Init(aPort, false, aAddressReuse, /* optional_argc = */ 1);
rv = sock->Init(aPort, false);
} else {
PRNetAddr prAddr;
PR_InitializeNetAddr(PR_IpAddrAny, aPort, &prAddr);
PRStatus status = PR_StringToNetAddr(aHost.BeginReading(), &prAddr);
if (status != PR_SUCCESS) {
return NS_ERROR_FAILURE;
FireInternalError(this, __LINE__);
return true;
}
mozilla::net::NetAddr addr;
PRNetAddrToNetAddr(&prAddr, &addr);
rv = sock->InitWithAddress(&addr, aAddressReuse, /* optional_argc = */ 1);
rv = sock->InitWithAddress(&addr);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = sock->SetMulticastLoopback(aLoopback);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// register listener
rv = sock->AsyncListen(this);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
if (NS_FAILED(rv)) {
FireInternalError(this, __LINE__);
return true;
}
mSocket = sock;
return NS_OK;
}
net::NetAddr localAddr;
mSocket->GetAddress(&localAddr);
bool
UDPSocketParent::RecvOutgoingData(const UDPData& aData,
const UDPSocketAddr& aAddr)
{
MOZ_ASSERT(mSocket);
nsresult rv;
if (mFilter) {
// TODO, Bug 933102, filter packets that are sent with hostname.
// Until then we simply throw away packets that are sent to a hostname.
if (aAddr.type() != UDPSocketAddr::TNetAddr) {
return true;
}
// TODO, Packet filter doesn't support input stream yet.
if (aData.type() != UDPData::TArrayOfuint8_t) {
return true;
}
bool allowed;
const InfallibleTArray<uint8_t>& data(aData.get_ArrayOfuint8_t());
rv = mFilter->FilterPacket(&aAddr.get_NetAddr(), data.Elements(),
data.Length(), nsIUDPSocketFilter::SF_OUTGOING,
&allowed);
// Sending unallowed data, kill content.
if (NS_WARN_IF(NS_FAILED(rv)) || !allowed) {
return false;
}
}
switch(aData.type()) {
case UDPData::TArrayOfuint8_t:
Send(aData.get_ArrayOfuint8_t(), aAddr);
break;
case UDPData::TInputStreamParams:
Send(aData.get_InputStreamParams(), aAddr);
break;
default:
MOZ_ASSERT(false, "Invalid data type!");
return true;
}
return true;
}
void
UDPSocketParent::Send(const InfallibleTArray<uint8_t>& aData,
const UDPSocketAddr& aAddr)
{
nsresult rv;
uint32_t count;
switch(aAddr.type()) {
case UDPSocketAddr::TUDPAddressInfo: {
const UDPAddressInfo& addrInfo(aAddr.get_UDPAddressInfo());
rv = mSocket->Send(addrInfo.addr(), addrInfo.port(),
aData.Elements(), aData.Length(), &count);
break;
}
case UDPSocketAddr::TNetAddr: {
const NetAddr& addr(aAddr.get_NetAddr());
rv = mSocket->SendWithAddress(&addr, aData.Elements(),
aData.Length(), &count);
break;
}
default:
MOZ_ASSERT(false, "Invalid address type!");
return;
}
if (NS_WARN_IF(NS_FAILED(rv)) || count == 0) {
FireInternalError(__LINE__);
}
}
void
UDPSocketParent::Send(const InputStreamParams& aStream,
const UDPSocketAddr& aAddr)
{
nsTArray<mozilla::ipc::FileDescriptor> fds;
nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aStream, fds);
if (NS_WARN_IF(!stream)) {
return;
}
nsresult rv;
switch(aAddr.type()) {
case UDPSocketAddr::TUDPAddressInfo: {
const UDPAddressInfo& addrInfo(aAddr.get_UDPAddressInfo());
rv = mSocket->SendBinaryStream(addrInfo.addr(), addrInfo.port(), stream);
break;
}
case UDPSocketAddr::TNetAddr: {
const NetAddr& addr(aAddr.get_NetAddr());
rv = mSocket->SendBinaryStreamWithAddress(&addr, stream);
break;
}
default:
MOZ_ASSERT(false, "Invalid address type!");
return;
}
uint16_t port;
nsCString addr;
rv = ConvertNetAddrToString(localAddr, &addr, &port);
if (NS_FAILED(rv)) {
FireInternalError(__LINE__);
FireInternalError(this, __LINE__);
return true;
}
}
bool
UDPSocketParent::RecvJoinMulticast(const nsCString& aMulticastAddress,
const nsCString& aInterface)
{
nsresult rv = mSocket->JoinMulticast(aMulticastAddress, aInterface);
if (NS_WARN_IF(NS_FAILED(rv))) {
FireInternalError(__LINE__);
}
// register listener
mSocket->AsyncListen(this);
mozilla::unused <<
PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onopen"),
UDPAddressInfo(addr, port),
NS_LITERAL_CSTRING("connected"));
return true;
}
bool
UDPSocketParent::RecvLeaveMulticast(const nsCString& aMulticastAddress,
const nsCString& aInterface)
UDPSocketParent::RecvData(const InfallibleTArray<uint8_t> &aData,
const nsCString& aRemoteAddress,
const uint16_t& aPort)
{
nsresult rv = mSocket->LeaveMulticast(aMulticastAddress, aInterface);
NS_ENSURE_TRUE(mSocket, true);
NS_ASSERTION(mFilter, "No packet filter");
// TODO, Bug 933102, filter packets that are sent with hostname.
// Until then we simply throw away packets that are sent to a hostname.
return true;
if (NS_WARN_IF(NS_FAILED(rv))) {
FireInternalError(__LINE__);
}
#if 0
// Enable this once we have filtering working with hostname delivery.
uint32_t count;
nsresult rv = mSocket->Send(aRemoteAddress,
aPort, aData.Elements(),
aData.Length(), &count);
mozilla::unused <<
PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onsent"),
UDPSendResult(rv),
NS_LITERAL_CSTRING("connected"));
NS_ENSURE_SUCCESS(rv, true);
NS_ENSURE_TRUE(count > 0, true);
return true;
#endif
}
bool
UDPSocketParent::RecvDataWithAddress(const InfallibleTArray<uint8_t>& aData,
const mozilla::net::NetAddr& aAddr)
{
NS_ENSURE_TRUE(mSocket, true);
NS_ASSERTION(mFilter, "No packet filter");
uint32_t count;
nsresult rv;
bool allowed;
rv = mFilter->FilterPacket(&aAddr, aData.Elements(),
aData.Length(), nsIUDPSocketFilter::SF_OUTGOING,
&allowed);
// Sending unallowed data, kill content.
NS_ENSURE_SUCCESS(rv, false);
NS_ENSURE_TRUE(allowed, false);
rv = mSocket->SendWithAddress(&aAddr, aData.Elements(),
aData.Length(), &count);
mozilla::unused <<
PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onsent"),
UDPSendResult(rv),
NS_LITERAL_CSTRING("connected"));
NS_ENSURE_SUCCESS(rv, true);
NS_ENSURE_TRUE(count > 0, true);
return true;
}
bool
UDPSocketParent::RecvClose()
{
if (!mSocket) {
return true;
}
NS_ENSURE_TRUE(mSocket, true);
nsresult rv = mSocket->Close();
mSocket = nullptr;
mozilla::unused << NS_WARN_IF(NS_FAILED(rv));
NS_ENSURE_SUCCESS(rv, true);
return true;
}
@ -312,6 +214,7 @@ UDPSocketParent::OnPacketReceived(nsIUDPSocket* aSocket, nsIUDPMessage* aMessage
if (!mIPCOpen) {
return NS_OK;
}
NS_ASSERTION(mFilter, "No packet filter");
uint16_t port;
nsCString ip;
@ -326,30 +229,30 @@ UDPSocketParent::OnPacketReceived(nsIUDPSocket* aSocket, nsIUDPMessage* aMessage
const char* buffer = data.get();
uint32_t len = data.Length();
if (mFilter) {
bool allowed;
mozilla::net::NetAddr addr;
fromAddr->GetNetAddr(&addr);
nsresult rv = mFilter->FilterPacket(&addr,
(const uint8_t*)buffer, len,
nsIUDPSocketFilter::SF_INCOMING,
&allowed);
// Receiving unallowed data, drop.
if (NS_WARN_IF(NS_FAILED(rv)) || !allowed) {
return NS_OK;
}
}
bool allowed;
mozilla::net::NetAddr addr;
fromAddr->GetNetAddr(&addr);
nsresult rv = mFilter->FilterPacket(&addr,
(const uint8_t*)buffer, len,
nsIUDPSocketFilter::SF_INCOMING,
&allowed);
// Receiving unallowed data, drop.
NS_ENSURE_SUCCESS(rv, NS_OK);
NS_ENSURE_TRUE(allowed, NS_OK);
FallibleTArray<uint8_t> fallibleArray;
if (!fallibleArray.InsertElementsAt(0, buffer, len)) {
FireInternalError(__LINE__);
FireInternalError(this, __LINE__);
return NS_ERROR_OUT_OF_MEMORY;
}
InfallibleTArray<uint8_t> infallibleArray;
infallibleArray.SwapElements(fallibleArray);
// compose callback
mozilla::unused << SendCallbackReceivedData(UDPAddressInfo(ip, port), infallibleArray);
mozilla::unused <<
PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("ondata"),
UDPMessage(ip, port, infallibleArray),
NS_LITERAL_CSTRING("connected"));
return NS_OK;
}
@ -359,21 +262,13 @@ UDPSocketParent::OnStopListening(nsIUDPSocket* aSocket, nsresult aStatus)
{
// underlying socket is dead, send state update to child process
if (mIPCOpen) {
mozilla::unused << SendCallbackClosed();
mozilla::unused <<
PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onclose"),
mozilla::void_t(),
NS_LITERAL_CSTRING("closed"));
}
return NS_OK;
}
void
UDPSocketParent::FireInternalError(uint32_t aLineNo)
{
if (!mIPCOpen) {
return;
}
mozilla::unused << SendCallbackError(NS_LITERAL_CSTRING("Internal error"),
NS_LITERAL_CSTRING(__FILE__), aLineNo);
}
} // namespace dom
} // namespace mozilla

View File

@ -22,34 +22,24 @@ public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIUDPSOCKETLISTENER
UDPSocketParent() :
mIPCOpen(true) {}
explicit UDPSocketParent(nsIUDPSocketFilter* filter) :
mIPCOpen(true),
mFilter(filter) {}
bool Init(const nsACString& aFilter);
virtual bool RecvBind(const UDPAddressInfo& aAddressInfo,
const bool& aAddressReuse, const bool& aLoopback) MOZ_OVERRIDE;
virtual bool RecvOutgoingData(const UDPData& aData, const UDPSocketAddr& aAddr) MOZ_OVERRIDE;
bool Init(const nsCString& aHost, const uint16_t aPort);
virtual bool RecvClose() MOZ_OVERRIDE;
virtual bool RecvData(const InfallibleTArray<uint8_t>& aData,
const nsCString& aRemoteAddress,
const uint16_t& aPort) MOZ_OVERRIDE;
virtual bool RecvDataWithAddress( const InfallibleTArray<uint8_t>& data,
const mozilla::net::NetAddr& addr);
virtual bool RecvRequestDelete() MOZ_OVERRIDE;
virtual bool RecvJoinMulticast(const nsCString& aMulticastAddress,
const nsCString& aInterface) MOZ_OVERRIDE;
virtual bool RecvLeaveMulticast(const nsCString& aMulticastAddress,
const nsCString& aInterface) MOZ_OVERRIDE;
private:
virtual ~UDPSocketParent();
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
void Send(const InfallibleTArray<uint8_t>& aData, const UDPSocketAddr& aAddr);
void Send(const InputStreamParams& aStream, const UDPSocketAddr& aAddr);
nsresult BindInternal(const nsCString& aHost, const uint16_t& aPort,
const bool& aAddressReuse, const bool& aLoopback);
void FireInternalError(uint32_t aLineNo);
bool mIPCOpen;
nsCOMPtr<nsIUDPSocket> mSocket;

View File

@ -4,10 +4,6 @@
# 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.dom += [
'UDPSocket.h',
]
EXPORTS.mozilla.dom.network += [
'Connection.h',
'Constants.h',
@ -26,7 +22,6 @@ UNIFIED_SOURCES += [
'TCPServerSocketParent.cpp',
'TCPSocketChild.cpp',
'TCPSocketParent.cpp',
'UDPSocket.cpp',
'UDPSocketChild.cpp',
'UDPSocketParent.cpp',
]

View File

@ -1,23 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test UDPSocket BFCache</title>
</head>
<body>
<script type="application/javascript;version=1.8">
'use strict';
window.addEventListener('load', function onload() {
window.removeEventListener('load', onload);
let remotePort = parseInt(window.location.search.substring(1), 10);
let socket = new UDPSocket();
socket.addEventListener('message', function () {
socket.send('fail', '127.0.0.1', remotePort);
});
socket.opened.then(function() {
socket.send('ready', '127.0.0.1', remotePort);
});
});
</script>
</body>
</html>

View File

@ -1,7 +1,3 @@
[DEFAULT]
support-files =
file_udpsocket_iframe.html
[test_network_basics.html]
skip-if = toolkit == "gonk" || toolkit == 'android'
[test_tcpsocket_default_permissions.html]
@ -20,4 +16,3 @@ skip-if = toolkit != "gonk"
skip-if = toolkit != "gonk"
[test_networkstats_enabled_perm.html]
skip-if = toolkit != "gonk"
[test_udpsocket.html]

View File

@ -1,409 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test UDPSocket API</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<iframe id="iframe"></iframe>
<pre id="test">
<script type="application/javascript;version=1.8">
'use strict';
SimpleTest.waitForExplicitFinish();
const HELLO_WORLD = 'hlo wrld. ';
const DATA_ARRAY = [0, 255, 254, 0, 1, 2, 3, 0, 255, 255, 254, 0];
const DATA_ARRAY_BUFFER = new ArrayBuffer(DATA_ARRAY.length);
const TYPED_DATA_ARRAY = new Uint8Array(DATA_ARRAY_BUFFER);
const BIG_ARRAY = new Array(4096);
const BIG_ARRAY_BUFFER = new ArrayBuffer(BIG_ARRAY.length);
const BIG_TYPED_ARRAY = new Uint8Array(BIG_ARRAY_BUFFER);
for (let i = 0; i < BIG_ARRAY.length; i++) {
BIG_ARRAY[i] = Math.floor(Math.random() * 256);
}
TYPED_DATA_ARRAY.set(DATA_ARRAY);
BIG_TYPED_ARRAY.set(BIG_ARRAY);
function is_same_buffer(recv_data, expect_data) {
let recv_dataview = new Uint8Array(recv_data);
let expected_dataview = new Uint8Array(expect_data);
if (recv_dataview.length !== expected_dataview.length) {
return false;
}
for (let i = 0; i < recv_dataview.length; i++) {
if (recv_dataview[i] != expected_dataview[i]) {
info('discover byte differenct at ' + i);
return false;
}
}
return true;
}
function testOpen() {
info('test for creating an UDP Socket');
let socket = new UDPSocket();
is(socket.localPort, null, 'expect no local port before socket opened');
is(socket.localAddress, null, 'expect no local address before socket opened');
is(socket.remotePort, null, 'expected no default remote port');
is(socket.remoteAddress, null, 'expected no default remote address');
is(socket.readyState, 'opening', 'expected ready state = opening');
is(socket.loopback, false, 'expected no loopback');
is(socket.addressReuse, true, 'expect to reuse address');
return socket.opened.then(function() {
ok(true, 'expect openedPromise to be resolved after successful socket binding');
ok(!(socket.localPort === 0), 'expect allocated a local port');
is(socket.localAddress, '0.0.0.0', 'expect assigned to default address');
is(socket.readyState, 'open', 'expected ready state = open');
return socket;
});
}
function testSendString(socket) {
info('test for sending string data');
socket.send(HELLO_WORLD, '127.0.0.1', socket.localPort);
return new Promise(function(resolve, reject) {
socket.addEventListener('message', function recv_callback(msg) {
socket.removeEventListener('message', recv_callback);
let recvData= String.fromCharCode.apply(null, new Uint8Array(msg.data));
is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
is(recvData, HELLO_WORLD, 'expected same string data');
resolve(socket);
});
});
}
function testSendArrayBuffer(socket) {
info('test for sending ArrayBuffer');
socket.send(DATA_ARRAY_BUFFER, '127.0.0.1', socket.localPort);
return new Promise(function(resolve, reject) {
socket.addEventListener('message', function recv_callback(msg) {
socket.removeEventListener('message', recv_callback);
is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
ok(is_same_buffer(msg.data, DATA_ARRAY_BUFFER), 'expected same buffer data');
resolve(socket);
});
});
}
function testSendArrayBufferView(socket) {
info('test for sending ArrayBufferView');
socket.send(TYPED_DATA_ARRAY, '127.0.0.1', socket.localPort);
return new Promise(function(resolve, reject) {
socket.addEventListener('message', function recv_callback(msg) {
socket.removeEventListener('message', recv_callback);
is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
ok(is_same_buffer(msg.data, TYPED_DATA_ARRAY), 'expected same buffer data');
resolve(socket);
});
});
}
function testSendBlob(socket) {
info('test for sending Blob');
let blob = new Blob([HELLO_WORLD], {type : 'text/plain'});
socket.send(blob, '127.0.0.1', socket.localPort);
return new Promise(function(resolve, reject) {
socket.addEventListener('message', function recv_callback(msg) {
socket.removeEventListener('message', recv_callback);
let recvData= String.fromCharCode.apply(null, new Uint8Array(msg.data));
is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
is(recvData, HELLO_WORLD, 'expected same string data');
resolve(socket);
});
});
}
function testSendBigArray(socket) {
info('test for sending Big ArrayBuffer');
socket.send(BIG_TYPED_ARRAY, '127.0.0.1', socket.localPort);
return new Promise(function(resolve, reject) {
let byteReceived = 0;
socket.addEventListener('message', function recv_callback(msg) {
let byteBegin = byteReceived;
byteReceived += msg.data.byteLength;
is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
ok(is_same_buffer(msg.data, BIG_TYPED_ARRAY.subarray(byteBegin, byteReceived)), 'expected same buffer data [' + byteBegin+ '-' + byteReceived + ']');
if (byteReceived >= BIG_TYPED_ARRAY.length) {
socket.removeEventListener('message', recv_callback);
clearTimeout(timeout);
resolve(socket);
}
});
let timeout = setTimeout(function() {
ok(false, 'timeout for sending big array');
resolve(socket);
}, 5000);
});
}
function testSendBigBlob(socket) {
info('test for sending Big Blob');
let blob = new Blob([BIG_TYPED_ARRAY]);
socket.send(blob, '127.0.0.1', socket.localPort);
return new Promise(function(resolve, reject) {
let byteReceived = 0;
socket.addEventListener('message', function recv_callback(msg) {
let byteBegin = byteReceived;
byteReceived += msg.data.byteLength;
is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
ok(is_same_buffer(msg.data, BIG_TYPED_ARRAY.subarray(byteBegin, byteReceived)), 'expected same buffer data [' + byteBegin+ '-' + byteReceived + ']');
if (byteReceived >= BIG_TYPED_ARRAY.length) {
socket.removeEventListener('message', recv_callback);
clearTimeout(timeout);
resolve(socket);
}
});
let timeout = setTimeout(function() {
ok(false, 'timeout for sending big blob');
resolve(socket);
}, 5000);
});
}
function testUDPOptions(socket) {
info('test for UDP init options');
let remoteSocket = new UDPSocket({addressReuse: false,
loopback: true,
localAddress: '127.0.0.1',
remoteAddress: '127.0.0.1',
remotePort: socket.localPort});
is(remoteSocket.localAddress, '127.0.0.1', 'expected local address');
is(remoteSocket.remoteAddress, '127.0.0.1', 'expected remote address');
is(remoteSocket.remotePort, socket.localPort, 'expected remote port');
is(remoteSocket.addressReuse, false, 'expected address not reusable');
is(remoteSocket.loopback, true, 'expected loopback mode is on');
return remoteSocket.opened.then(function() {
remoteSocket.send(HELLO_WORLD);
return new Promise(function(resolve, reject) {
socket.addEventListener('message', function recv_callback(msg) {
socket.removeEventListener('message', recv_callback);
let recvData= String.fromCharCode.apply(null, new Uint8Array(msg.data));
is(msg.remotePort, remoteSocket.localPort, 'expected packet from ' + remoteSocket.localPort);
is(recvData, HELLO_WORLD, 'expected same string data');
resolve(socket);
});
});
});
}
function testClose(socket) {
info('test for close');
socket.close();
is(socket.readyState, 'closed', 'expect ready state to be "closed"');
try {
socket.send(HELLO_WORLD, '127.0.0.1', socket.localPort);
ok(false, 'unexpect to send successfully');
} catch (e) {
ok(true, 'expected send fail after socket closed');
}
return socket.closed.then(function() {
ok(true, 'expected closedPromise is resolved after socket.close()');
});
}
function testMulticast() {
info('test for multicast');
let socket = new UDPSocket({loopback: true});
const MCAST_ADDRESS = '224.0.0.255';
socket.joinMulticastGroup(MCAST_ADDRESS);
return socket.opened.then(function() {
socket.send(HELLO_WORLD, MCAST_ADDRESS, socket.localPort);
return new Promise(function(resolve, reject) {
socket.addEventListener('message', function recv_callback(msg) {
socket.removeEventListener('message', recv_callback);
let recvData= String.fromCharCode.apply(null, new Uint8Array(msg.data));
is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
is(recvData, HELLO_WORLD, 'expected same string data');
socket.leaveMulticastGroup(MCAST_ADDRESS);
resolve();
});
});
});
}
function testInvalidUDPOptions() {
info('test for invalid UDPOptions');
try {
let socket = new UDPSocket({localAddress: 'not-a-valid-address'});
ok(false, 'should not create an UDPSocket with an invalid localAddress');
} catch (e) {
is(e.name, 'InvalidAccessError', 'expected InvalidAccessError will be thrown if localAddress is not a valid IPv4/6 address');
}
try {
let socket = new UDPSocket({localPort: 0});
ok(false, 'should not create an UDPSocket with an invalid localPort');
} catch (e) {
is(e.name, 'InvalidAccessError', 'expected InvalidAccessError will be thrown if localPort is not a valid port number');
}
try {
let socket = new UDPSocket({remotePort: 0});
ok(false, 'should not create an UDPSocket with an invalid remotePort');
} catch (e) {
is(e.name, 'InvalidAccessError', 'expected InvalidAccessError will be thrown if localPort is not a valid port number');
}
}
function testOpenFailed() {
info('test for falied on open');
//according to RFC5737, address block 192.0.2.0/24 should not be used in both local and public contexts
let socket = new UDPSocket({localAddress: '192.0.2.0'});
return socket.opened.then(function() {
ok(false, 'should not resolve openedPromise while fail to bind socket');
}).catch(function(reason) {
is(reason.name, 'NetworkError', 'expected openedPromise to be rejected while fail to bind socket');
});
}
function testSendBeforeOpen() {
info('test for send before open');
let socket = new UDPSocket();
try {
socket.send(HELLO_WORLD, '127.0.0.1', 9);
ok(false, 'unexpect to send successfully');
} catch (e) {
ok(true, 'expected send fail before openedPromise is resolved');
}
return socket.opened;
}
function testCloseBeforeOpened() {
info('test for close socket before opened');
let socket = new UDPSocket();
socket.opened.then(function() {
ok(false, 'should not resolve openedPromise if it has already been closed');
}).catch(function(reason) {
is(reason.name, 'AbortError', 'expected openedPromise to be rejected while socket is closed during opening');
});
return socket.close().then(function() {
ok(true, 'expected closedPromise to be resolved');
}).then(socket.opened);
}
function testOpenWithoutClose() {
info('test for open without close');
let opened = [];
for (let i = 0; i < 50; i++) {
let socket = new UDPSocket();
opened.push(socket.opened);
}
return Promise.all(opened);
}
function testBFCache() {
info('test for bfcache behavior');
let socket = new UDPSocket();
return socket.opened.then(function() {
let iframe = document.getElementById('iframe');
SpecialPowers.wrap(iframe).mozbrowser = true;
iframe.src = 'file_udpsocket_iframe.html?' + socket.localPort;
return new Promise(function(resolve, reject) {
socket.addEventListener('message', function recv_callback(msg) {
socket.removeEventListener('message', recv_callback);
iframe.src = 'about:blank';
iframe.addEventListener('load', function onload() {
iframe.removeEventListener('load', onload);
socket.send(HELLO_WORLD, '127.0.0.1', msg.remotePort);
function recv_again_callback(msg) {
socket.removeEventListener('message', recv_again_callback);
ok(false, 'should not receive packet after page unload');
}
socket.addEventListener('message', recv_again_callback);
let timeout = setTimeout(function() {
socket.removeEventListener('message', recv_again_callback);
socket.close();
resolve();
}, 5000);
});
});
});
});
}
function runTest() {
testOpen()
.then(testSendString)
.then(testSendArrayBuffer)
.then(testSendArrayBufferView)
.then(testSendBlob)
.then(testSendBigArray)
.then(testSendBigBlob)
.then(testUDPOptions)
.then(testClose)
.then(testMulticast)
.then(testInvalidUDPOptions)
.then(testOpenFailed)
.then(testSendBeforeOpen)
.then(testCloseBeforeOpened)
.then(testOpenWithoutClose)
.then(testBFCache)
.then(function() {
info('test finished');
SimpleTest.finish();
});
}
window.addEventListener('load', function () {
SpecialPowers.pushPermissions([
{type: 'udp-socket', allow: true, context: document}], function() {
SpecialPowers.pushPrefEnv({
'set': [
['dom.udpsocket.enabled', true],
['browser.sessionhistory.max_total_viewers', 10]
]
}, runTest);
});
});
</script>
</pre>
</body>
</html>

View File

@ -16,7 +16,6 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' # b2g(https not working, bug
[test_power.html]
[test_systemXHR.html]
[test_tcp-socket.html]
[test_udp-socket.html]
[test_webapps-manage.html]
[test_camera.html]
disabled = disabled until bug 859593 is fixed

View File

@ -1,47 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=745283
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 745283 </title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=745283">Mozilla Bug 745283 </a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
<script type="application/javascript;version=1.8" src="file_framework.js"></script>
<script type="application/javascript;version=1.8">
function verifier(success, failure) {
try {
var socket = new UDPSocket();
if (socket) {
success("Opened socket");
} else {
failure("failed to open socket");
}
} catch (e) {
failure("Got an exception " + e);
}
}
var gData = [
{
perm: ["udp-socket"],
needParentPerm: true,
obj: "UDPSocket",
webidl: "UDPSocket",
settings: [["dom.udpsocket.enabled", true]],
verifier: verifier.toSource(),
}
]
</script>
</pre>
</body>
</html>

View File

@ -1168,10 +1168,6 @@ var interfaceNamesInGlobalScope =
{name: "TreeSelection", xbl: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
"TreeWalker",
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "UDPMessageEvent", pref: "dom.udpsocket.enabled", permission: "udp-socket"},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "UDPSocket", pref: "dom.udpsocket.enabled", permission: "udp-socket"},
// IMPORTANT: Do not change this list without review from a DOM peer!
"UIEvent",
// IMPORTANT: Do not change this list without review from a DOM peer!

View File

@ -1,16 +0,0 @@
/* -*- Mode: IDL; tab-width: 2; 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/.
*
* The origin of this IDL file is
* http://www.w3.org/2012/sysapps/tcp-udp-sockets/#readystate
*/
enum SocketReadyState {
"opening",
"open",
"closing",
"closed",
"halfclosed"
};

View File

@ -1,24 +0,0 @@
/* -*- Mode: IDL; tab-width: 2; 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/.
*
* The origin of this IDL file is
* http://www.w3.org/TR/raw-sockets/#interface-udpmessageevent
*/
//Bug 1056444: This interface should be removed after UDPSocket.input/UDPSocket.output are ready.
[Constructor(DOMString type, optional UDPMessageEventInit eventInitDict),
Pref="dom.udpsocket.enabled",
CheckPermissions="udp-socket"]
interface UDPMessageEvent : Event {
readonly attribute DOMString remoteAddress;
readonly attribute unsigned short remotePort;
readonly attribute any data;
};
dictionary UDPMessageEventInit : EventInit {
DOMString remoteAddress = "";
unsigned short remotePort = 0;
any data = null;
};

View File

@ -1,40 +0,0 @@
/* -*- Mode: IDL; tab-width: 2; 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/.
*
* The origin of this IDL file is
* http://www.w3.org/2012/sysapps/tcp-udp-sockets/#interface-udpsocket
* http://www.w3.org/2012/sysapps/tcp-udp-sockets/#dictionary-udpoptions
*/
dictionary UDPOptions {
DOMString localAddress;
unsigned short localPort;
DOMString remoteAddress;
unsigned short remotePort;
boolean addressReuse = true;
boolean loopback = false;
};
[Constructor (optional UDPOptions options),
Pref="dom.udpsocket.enabled",
CheckPermissions="udp-socket"]
interface UDPSocket : EventTarget {
readonly attribute DOMString? localAddress;
readonly attribute unsigned short? localPort;
readonly attribute DOMString? remoteAddress;
readonly attribute unsigned short? remotePort;
readonly attribute boolean addressReuse;
readonly attribute boolean loopback;
readonly attribute SocketReadyState readyState;
readonly attribute Promise<void> opened;
readonly attribute Promise<void> closed;
// readonly attribute ReadableStream input; //Bug 1056444: Stream API is not ready
// readonly attribute WriteableStream output; //Bug 1056444: Stream API is not ready
attribute EventHandler onmessage; //Bug 1056444: use event interface before Stream API is ready
Promise<void> close ();
[Throws] void joinMulticastGroup (DOMString multicastGroupAddress);
[Throws] void leaveMulticastGroup (DOMString multicastGroupAddress);
[Throws] boolean send ((DOMString or Blob or ArrayBuffer or ArrayBufferView) data, optional DOMString? remoteAddress, optional unsigned short? remotePort); //Bug 1056444: use send method before Stream API is ready
};

View File

@ -333,7 +333,6 @@ WEBIDL_FILES = [
'SharedWorker.webidl',
'SharedWorkerGlobalScope.webidl',
'SimpleGestureEvent.webidl',
'SocketCommon.webidl',
'SourceBuffer.webidl',
'SourceBufferList.webidl',
'Storage.webidl',
@ -469,8 +468,6 @@ WEBIDL_FILES = [
'TransitionEvent.webidl',
'TreeColumns.webidl',
'TreeWalker.webidl',
'UDPMessageEvent.webidl',
'UDPSocket.webidl',
'UIEvent.webidl',
'UndoManager.webidl',
'URL.webidl',
@ -679,7 +676,6 @@ GENERATED_EVENTS_WEBIDL_FILES = [
'StyleSheetApplicableStateChangeEvent.webidl',
'StyleSheetChangeEvent.webidl',
'TrackEvent.webidl',
'UDPMessageEvent.webidl',
'UserProximityEvent.webidl',
'USSDReceivedEvent.webidl',
]

View File

@ -700,13 +700,17 @@ NrSocketIpc::NrSocketIpc(const nsCOMPtr<nsIEventTarget> &main_thread)
// IUDPSocketInternal interfaces
// callback while error happened in UDP socket operation
NS_IMETHODIMP NrSocketIpc::CallListenerError(const nsACString &message,
NS_IMETHODIMP NrSocketIpc::CallListenerError(const nsACString &type,
const nsACString &message,
const nsACString &filename,
uint32_t line_number) {
uint32_t line_number,
uint32_t column_number) {
ASSERT_ON_THREAD(main_thread_);
MOZ_ASSERT(type.EqualsLiteral("onerror"));
r_log(LOG_GENERIC, LOG_ERR, "UDP socket error:%s at %s:%d",
message.BeginReading(), filename.BeginReading(), line_number );
r_log(LOG_GENERIC, LOG_ERR, "UDP socket error:%s at %s:%d:%d",
message.BeginReading(), filename.BeginReading(),
line_number, column_number);
ReentrantMonitorAutoEnter mon(monitor_);
err_ = true;
@ -716,11 +720,12 @@ NS_IMETHODIMP NrSocketIpc::CallListenerError(const nsACString &message,
}
// callback while receiving UDP packet
NS_IMETHODIMP NrSocketIpc::CallListenerReceivedData(const nsACString &host,
uint16_t port,
const uint8_t *data,
NS_IMETHODIMP NrSocketIpc::CallListenerReceivedData(const nsACString &type,
const nsACString &host,
uint16_t port, uint8_t *data,
uint32_t data_length) {
ASSERT_ON_THREAD(main_thread_);
MOZ_ASSERT(type.EqualsLiteral("ondata"));
PRNetAddr addr;
memset(&addr, 0, sizeof(addr));
@ -753,68 +758,89 @@ NS_IMETHODIMP NrSocketIpc::CallListenerReceivedData(const nsACString &host,
return NS_OK;
}
// callback while UDP socket is opened
NS_IMETHODIMP NrSocketIpc::CallListenerOpened() {
// callback while UDP socket is opened or closed
NS_IMETHODIMP NrSocketIpc::CallListenerVoid(const nsACString &type) {
ASSERT_ON_THREAD(main_thread_);
ReentrantMonitorAutoEnter mon(monitor_);
if (type.EqualsLiteral("onopen")) {
ReentrantMonitorAutoEnter mon(monitor_);
uint16_t port;
if (NS_FAILED(socket_child_->GetLocalPort(&port))) {
err_ = true;
MOZ_ASSERT(false, "Failed to get local port");
return NS_OK;
uint16_t port;
if (NS_FAILED(socket_child_->GetLocalPort(&port))) {
err_ = true;
MOZ_ASSERT(false, "Failed to get local port");
return NS_OK;
}
nsAutoCString address;
if(NS_FAILED(socket_child_->GetLocalAddress(address))) {
err_ = true;
MOZ_ASSERT(false, "Failed to get local address");
return NS_OK;
}
PRNetAddr praddr;
if (PR_SUCCESS != PR_InitializeNetAddr(PR_IpAddrAny, port, &praddr)) {
err_ = true;
MOZ_ASSERT(false, "Failed to set port in PRNetAddr");
return NS_OK;
}
if (PR_SUCCESS != PR_StringToNetAddr(address.BeginReading(), &praddr)) {
err_ = true;
MOZ_ASSERT(false, "Failed to convert local host to PRNetAddr");
return NS_OK;
}
nr_transport_addr expected_addr;
if(nr_transport_addr_copy(&expected_addr, &my_addr_)) {
err_ = true;
MOZ_ASSERT(false, "Failed to copy my_addr_");
}
if (nr_praddr_to_transport_addr(&praddr, &my_addr_, IPPROTO_UDP, 1)) {
err_ = true;
MOZ_ASSERT(false, "Failed to copy local host to my_addr_");
}
if (nr_transport_addr_cmp(&expected_addr, &my_addr_,
NR_TRANSPORT_ADDR_CMP_MODE_ADDR)) {
err_ = true;
MOZ_ASSERT(false, "Address of opened socket is not expected");
}
mon.NotifyAll();
} else if (type.EqualsLiteral("onclose")) {
// Already handled in UpdateReadyState, nothing to do here
} else {
MOZ_ASSERT(false, "Received unexpected event");
}
nsAutoCString address;
if(NS_FAILED(socket_child_->GetLocalAddress(address))) {
err_ = true;
MOZ_ASSERT(false, "Failed to get local address");
return NS_OK;
}
PRNetAddr praddr;
if (PR_SUCCESS != PR_InitializeNetAddr(PR_IpAddrAny, port, &praddr)) {
err_ = true;
MOZ_ASSERT(false, "Failed to set port in PRNetAddr");
return NS_OK;
}
if (PR_SUCCESS != PR_StringToNetAddr(address.BeginReading(), &praddr)) {
err_ = true;
MOZ_ASSERT(false, "Failed to convert local host to PRNetAddr");
return NS_OK;
}
nr_transport_addr expected_addr;
if(nr_transport_addr_copy(&expected_addr, &my_addr_)) {
err_ = true;
MOZ_ASSERT(false, "Failed to copy my_addr_");
}
if (nr_praddr_to_transport_addr(&praddr, &my_addr_, IPPROTO_UDP, 1)) {
err_ = true;
MOZ_ASSERT(false, "Failed to copy local host to my_addr_");
}
if (nr_transport_addr_cmp(&expected_addr, &my_addr_,
NR_TRANSPORT_ADDR_CMP_MODE_ADDR)) {
err_ = true;
MOZ_ASSERT(false, "Address of opened socket is not expected");
}
mon.NotifyAll();
return NS_OK;
}
// callback while UDP socket is closed
NS_IMETHODIMP NrSocketIpc::CallListenerClosed() {
// callback while UDP packet is sent
NS_IMETHODIMP NrSocketIpc::CallListenerSent(const nsACString &type,
nsresult result) {
ASSERT_ON_THREAD(main_thread_);
MOZ_ASSERT(type.EqualsLiteral("onsent"));
if (NS_FAILED(result)) {
ReentrantMonitorAutoEnter mon(monitor_);
err_ = true;
}
return NS_OK;
}
// callback for state update after every socket operation
NS_IMETHODIMP NrSocketIpc::UpdateReadyState(const nsACString &readyState) {
ASSERT_ON_THREAD(main_thread_);
ReentrantMonitorAutoEnter mon(monitor_);
MOZ_ASSERT(state_ == NR_CONNECTED || state_ == NR_CLOSING);
state_ = NR_CLOSED;
if (readyState.EqualsLiteral("closed")) {
MOZ_ASSERT(state_ == NR_CONNECTED || state_ == NR_CLOSING);
state_ = NR_CLOSED;
}
return NS_OK;
}
@ -1004,20 +1030,14 @@ void NrSocketIpc::create_m(const nsACString &host, const uint16_t port) {
if (NS_FAILED(rv)) {
err_ = true;
MOZ_ASSERT(false, "Failed to create UDPSocketChild");
mon.NotifyAll();
return;
}
socket_child_ = new nsMainThreadPtrHolder<nsIUDPSocketChild>(socketChild);
socket_child_->SetFilterName(nsCString("stun"));
if (NS_FAILED(socket_child_->Bind(this, host, port,
/* reuse = */ false,
/* loopback = */ false))) {
if (NS_FAILED(socket_child_->Bind(this, host, port))) {
err_ = true;
MOZ_ASSERT(false, "Failed to create UDP socket");
mon.NotifyAll();
return;
}
}

View File

@ -4253,6 +4253,3 @@ pref("dom.fetch.enabled", false);
// platforms; and set to 0 to disable the low-memory check altogether.
pref("camera.control.low_memory_thresholdMB", 404);
#endif
// UDPSocket API
pref("dom.udpsocket.enabled", false);

View File

@ -10,7 +10,6 @@ interface nsIUDPSocketListener;
interface nsIUDPMessage;
interface nsISocketTransport;
interface nsIOutputStream;
interface nsIInputStream;
%{ C++
#include "nsTArrayForwardDeclare.h"
@ -29,7 +28,7 @@ native NetAddr(mozilla::net::NetAddr);
*
* An interface to a UDP socket that can accept incoming connections.
*/
[scriptable, uuid(5e526cc7-a65f-42b2-b193-a6894c0253f7)]
[scriptable, uuid(3240F793-80FA-4088-987A-9C7378F0AC88)]
interface nsIUDPSocket : nsISupports
{
/**
@ -45,11 +44,8 @@ interface nsIUDPSocket : nsISupports
* local loopback interface. Otherwise, it will accept connections
* from any interface. To specify a particular network interface,
* use initWithAddress.
* @param aAddressReuse
* If true, the socket is allowed to be bound to an address that is
* already in use. Default is true.
*/
[optional_argc] void init(in long aPort, in boolean aLoopbackOnly, [optional] in boolean aAddressReuse);
void init(in long aPort, in boolean aLoopbackOnly);
/**
* initWithAddress
@ -59,11 +55,8 @@ interface nsIUDPSocket : nsISupports
*
* @param aAddr
* The address to which this UDP socket should be bound.
* @param aAddressReuse
* If true, the socket is allowed to be bound to an address that is
* already in use. Default is true.
*/
[noscript, optional_argc] void initWithAddress([const] in NetAddrPtr aAddr, [optional] in boolean aAddressReuse);
[noscript] void initWithAddress([const] in NetAddrPtr aAddr);
/**
* close
@ -92,11 +85,6 @@ interface nsIUDPSocket : nsISupports
*/
void asyncListen(in nsIUDPSocketListener aListener);
/**
* Returns the local address of this UDP socket
*/
readonly attribute nsINetAddr localAddr;
/**
* Returns the port of this UDP socket.
*/
@ -157,29 +145,6 @@ interface nsIUDPSocket : nsISupports
[const, array, size_is(dataLength)]in uint8_t data,
in unsigned long dataLength);
/**
* sendBinaryStream
*
* Send out the datagram to specified remote address and port.
*
* @param host The remote host name.
* @param port The remote port.
* @param stream The input stream to be sent. This must be a buffered stream implementation.
*/
void sendBinaryStream(in AUTF8String host, in unsigned short port,
in nsIInputStream stream);
/**
* sendBinaryStreamWithAddress
*
* Send out the datagram to specified remote address and port.
*
* @param addr The remote host address.
* @param stream The input stream to be sent. This must be a buffered stream implementation.
*/
void sendBinaryStreamWithAddress([const] in NetAddrPtr addr,
in nsIInputStream stream);
/**
* joinMulticast
*

View File

@ -31,7 +31,6 @@ using namespace mozilla::net;
using namespace mozilla;
static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID);
static const uint32_t UDP_PACKET_CHUNK_SIZE = 1400;
//-----------------------------------------------------------------------------
@ -480,7 +479,7 @@ nsUDPSocket::OnSocketReady(PRFileDesc *fd, int16_t outFlags)
nsCOMPtr<nsIAsyncInputStream> pipeIn;
nsCOMPtr<nsIAsyncOutputStream> pipeOut;
uint32_t segsize = UDP_PACKET_CHUNK_SIZE;
uint32_t segsize = 1400;
uint32_t segcount = 0;
net_ResolveSegmentParams(segsize, segcount);
nsresult rv = NS_NewPipe2(getter_AddRefs(pipeIn), getter_AddRefs(pipeOut),
@ -492,7 +491,7 @@ nsUDPSocket::OnSocketReady(PRFileDesc *fd, int16_t outFlags)
nsRefPtr<nsUDPOutputStream> os = new nsUDPOutputStream(this, mFD, prClientAddr);
rv = NS_AsyncCopy(pipeIn, os, mSts,
NS_ASYNCCOPY_VIA_READSEGMENTS, UDP_PACKET_CHUNK_SIZE);
NS_ASYNCCOPY_VIA_READSEGMENTS, 1400);
if (NS_FAILED(rv)) {
return;
@ -553,7 +552,7 @@ NS_IMPL_ISUPPORTS(nsUDPSocket, nsIUDPSocket)
//-----------------------------------------------------------------------------
NS_IMETHODIMP
nsUDPSocket::Init(int32_t aPort, bool aLoopbackOnly, bool aAddressReuse, uint8_t aOptionalArgc)
nsUDPSocket::Init(int32_t aPort, bool aLoopbackOnly)
{
NetAddr addr;
@ -568,16 +567,14 @@ nsUDPSocket::Init(int32_t aPort, bool aLoopbackOnly, bool aAddressReuse, uint8_t
else
addr.inet.ip = htonl(INADDR_ANY);
return InitWithAddress(&addr, aAddressReuse, aOptionalArgc);
return InitWithAddress(&addr);
}
NS_IMETHODIMP
nsUDPSocket::InitWithAddress(const NetAddr *aAddr, bool aAddressReuse, uint8_t aOptionalArgc)
nsUDPSocket::InitWithAddress(const NetAddr *aAddr)
{
NS_ENSURE_TRUE(mFD == nullptr, NS_ERROR_ALREADY_INITIALIZED);
bool addressReuse = (aOptionalArgc == 1) ? aAddressReuse : true;
//
// configure listening socket...
//
@ -601,7 +598,7 @@ nsUDPSocket::InitWithAddress(const NetAddr *aAddr, bool aAddressReuse, uint8_t a
// to port 0 with SO_REUSEADDR
if (port) {
opt.option = PR_SockOpt_Reuseaddr;
opt.value.reuse_addr = addressReuse;
opt.value.reuse_addr = true;
PR_SetSocketOption(mFD, &opt);
}
@ -671,17 +668,6 @@ nsUDPSocket::GetPort(int32_t *aResult)
return rv;
}
NS_IMETHODIMP
nsUDPSocket::GetLocalAddr(nsINetAddr * *aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
nsCOMPtr<nsINetAddr> result = new nsNetAddr(&mAddr);
result.forget(aResult);
return NS_OK;
}
NS_IMETHODIMP
nsUDPSocket::GetAddress(NetAddr *aResult)
{
@ -843,47 +829,6 @@ PendingSend::OnLookupComplete(nsICancelable *request,
return NS_OK;
}
class PendingSendStream : public nsIDNSListener
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIDNSLISTENER
PendingSendStream(nsUDPSocket *aSocket, uint16_t aPort,
nsIInputStream *aStream)
: mSocket(aSocket)
, mPort(aPort)
, mStream(aStream) {}
private:
virtual ~PendingSendStream() {}
nsRefPtr<nsUDPSocket> mSocket;
uint16_t mPort;
nsCOMPtr<nsIInputStream> mStream;
};
NS_IMPL_ISUPPORTS(PendingSendStream, nsIDNSListener)
NS_IMETHODIMP
PendingSendStream::OnLookupComplete(nsICancelable *request,
nsIDNSRecord *rec,
nsresult status)
{
if (NS_FAILED(status)) {
NS_WARNING("Failed to send UDP packet due to DNS lookup failure");
return NS_OK;
}
NetAddr addr;
if (NS_SUCCEEDED(rec->GetNextAddr(mPort, &addr))) {
nsresult rv = mSocket->SendBinaryStreamWithAddress(&addr, mStream);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
class SendRequestRunnable: public nsRunnable {
public:
SendRequestRunnable(nsUDPSocket *aSocket,
@ -1008,32 +953,6 @@ nsUDPSocket::SendWithAddress(const NetAddr *aAddr, const uint8_t *aData,
return NS_OK;
}
NS_IMETHODIMP
nsUDPSocket::SendBinaryStream(const nsACString &aHost, uint16_t aPort,
nsIInputStream *aStream)
{
NS_ENSURE_ARG(aStream);
nsCOMPtr<nsIDNSListener> listener = new PendingSendStream(this, aPort, aStream);
return ResolveHost(aHost, listener);
}
NS_IMETHODIMP
nsUDPSocket::SendBinaryStreamWithAddress(const NetAddr *aAddr, nsIInputStream *aStream)
{
NS_ENSURE_ARG(aAddr);
NS_ENSURE_ARG(aStream);
PRNetAddr prAddr;
PR_InitializeNetAddr(PR_IpAddrAny, 0, &prAddr);
NetAddrToPRNetAddr(aAddr, &prAddr);
nsRefPtr<nsUDPOutputStream> os = new nsUDPOutputStream(this, mFD, prAddr);
return NS_AsyncCopy(aStream, os, mSts, NS_ASYNCCOPY_VIA_READSEGMENTS,
UDP_PACKET_CHUNK_SIZE);
}
nsresult
nsUDPSocket::SetSocketOption(const PRSocketOptionData& aOpt)
{

View File

@ -236,7 +236,9 @@ NeckoChild::DeallocPTCPServerSocketChild(PTCPServerSocketChild* child)
}
PUDPSocketChild*
NeckoChild::AllocPUDPSocketChild(const nsCString& aFilter)
NeckoChild::AllocPUDPSocketChild(const nsCString& aHost,
const uint16_t& aPort,
const nsCString& aFilter)
{
NS_NOTREACHED("AllocPUDPSocket should not be called");
return nullptr;

View File

@ -51,7 +51,9 @@ protected:
const uint16_t& aBacklog,
const nsString& aBinaryType) MOZ_OVERRIDE;
virtual bool DeallocPTCPServerSocketChild(PTCPServerSocketChild*) MOZ_OVERRIDE;
virtual PUDPSocketChild* AllocPUDPSocketChild(const nsCString& aFilter) MOZ_OVERRIDE;
virtual PUDPSocketChild* AllocPUDPSocketChild(const nsCString& aHost,
const uint16_t& aPort,
const nsCString& aFilter) MOZ_OVERRIDE;
virtual bool DeallocPUDPSocketChild(PUDPSocketChild*) MOZ_OVERRIDE;
virtual PDNSRequestChild* AllocPDNSRequestChild(const nsCString& aHost,
const uint32_t& aFlags) MOZ_OVERRIDE;

View File

@ -31,6 +31,7 @@
#include "nsPrintfCString.h"
#include "nsHTMLDNSPrefetch.h"
#include "nsIAppsService.h"
#include "nsIUDPSocketFilter.h"
#include "nsEscape.h"
#include "RemoteOpenFileParent.h"
#include "SerializedLoadContext.h"
@ -444,18 +445,45 @@ NeckoParent::DeallocPTCPServerSocketParent(PTCPServerSocketParent* actor)
}
PUDPSocketParent*
NeckoParent::AllocPUDPSocketParent(const nsCString& /* unused */)
NeckoParent::AllocPUDPSocketParent(const nsCString& aHost,
const uint16_t& aPort,
const nsCString& aFilter)
{
nsRefPtr<UDPSocketParent> p = new UDPSocketParent();
UDPSocketParent* p = nullptr;
return p.forget().take();
// Only allow socket if it specifies a valid packet filter.
nsAutoCString contractId(NS_NETWORK_UDP_SOCKET_FILTER_HANDLER_PREFIX);
contractId.Append(aFilter);
if (!aFilter.IsEmpty()) {
nsCOMPtr<nsIUDPSocketFilterHandler> filterHandler =
do_GetService(contractId.get());
if (filterHandler) {
nsCOMPtr<nsIUDPSocketFilter> filter;
nsresult rv = filterHandler->NewFilter(getter_AddRefs(filter));
if (NS_SUCCEEDED(rv)) {
p = new UDPSocketParent(filter);
} else {
printf_stderr("Cannot create filter that content specified. "
"filter name: %s, error code: %d.", aFilter.get(), rv);
}
} else {
printf_stderr("Content doesn't have a valid filter. "
"filter name: %s.", aFilter.get());
}
}
NS_IF_ADDREF(p);
return p;
}
bool
NeckoParent::RecvPUDPSocketConstructor(PUDPSocketParent* aActor,
const nsCString& aHost,
const uint16_t& aPort,
const nsCString& aFilter)
{
return static_cast<UDPSocketParent*>(aActor)->Init(aFilter);
return static_cast<UDPSocketParent*>(aActor)->Init(aHost, aPort);
}
bool

View File

@ -153,8 +153,13 @@ protected:
const uint16_t& aBacklog,
const nsString& aBinaryType) MOZ_OVERRIDE;
virtual bool DeallocPTCPServerSocketParent(PTCPServerSocketParent*) MOZ_OVERRIDE;
virtual PUDPSocketParent* AllocPUDPSocketParent(const nsCString& aFilter) MOZ_OVERRIDE;
virtual bool RecvPUDPSocketConstructor(PUDPSocketParent*, const nsCString& aFilter) MOZ_OVERRIDE;
virtual PUDPSocketParent* AllocPUDPSocketParent(const nsCString& aHost,
const uint16_t& aPort,
const nsCString& aFilter) MOZ_OVERRIDE;
virtual bool RecvPUDPSocketConstructor(PUDPSocketParent*,
const nsCString& aHost,
const uint16_t& aPort,
const nsCString& aFilter) MOZ_OVERRIDE;
virtual bool DeallocPUDPSocketParent(PUDPSocketParent*) MOZ_OVERRIDE;
virtual PDNSRequestParent* AllocPDNSRequestParent(const nsCString& aHost,
const uint32_t& aFlags) MOZ_OVERRIDE;

View File

@ -69,7 +69,7 @@ parent:
PWebSocket(PBrowserOrId browser, SerializedLoadContext loadContext);
PTCPServerSocket(uint16_t localPort, uint16_t backlog, nsString binaryType);
PUDPSocket(nsCString filter);
PUDPSocket(nsCString host, uint16_t port, nsCString filter);
PDNSRequest(nsCString hostName, uint32_t flags);

View File

@ -273,7 +273,7 @@ main(int32_t argc, char *argv[])
nsRefPtr<UDPServerListener> serverListener = new UDPServerListener();
// Bind server socket to 0.0.0.0
rv = server->Init(0, false, true, 0);
rv = server->Init(0, false);
NS_ENSURE_SUCCESS(rv, -1);
int32_t serverPort;
server->GetPort(&serverPort);
@ -281,7 +281,7 @@ main(int32_t argc, char *argv[])
// Bind clinet on arbitrary port
nsRefPtr<UDPClientListener> clientListener = new UDPClientListener();
client->Init(0, false, true, 0);
client->Init(0, false);
client->AsyncListen(clientListener);
// Write data to server

View File

@ -0,0 +1,31 @@
var rawData = new Uint8Array([65,66,67,68]);
var data = String.fromCharCode.apply(null, rawData);
function UDPSocketListener(){}
UDPSocketListener.prototype = {
QueryInterface : XPCOMUtils.generateQI([Ci.nsIUDPSocketListener]),
onPacketReceived : function(aSocket, aMessage){
var mData = String.fromCharCode.apply(null, aMessage.rawData);
do_check_eq(mData, data);
do_check_eq(mData, aMessage.data);
do_test_finished();
},
onStopListening: function(aSocket, aStatus){}
};
function run_test(){
var socket = Cc["@mozilla.org/network/udp-socket;1"].createInstance(Ci.nsIUDPSocket);
socket.init(-1, true);
do_print("Port assigned : " + socket.port);
socket.asyncListen(new UDPSocketListener());
var written = socket.send("127.0.0.1", socket.port, rawData, rawData.length);
do_check_eq(written, data.length);
do_test_pending();
}

View File

@ -1,61 +0,0 @@
/* -*- Mode: Javasript; indent-tab-mode: nil; js-indent-level: 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/. */
"use strict";
const HELLO_WORLD = "Hello World";
add_test(function test_udp_message_raw_data() {
do_print("test for nsIUDPMessage.rawData");
let socket = Cc["@mozilla.org/network/udp-socket;1"].createInstance(Ci.nsIUDPSocket);
socket.init(-1, true);
do_print("Port assigned : " + socket.port);
socket.asyncListen({
QueryInterface : XPCOMUtils.generateQI([Ci.nsIUDPSocketListener]),
onPacketReceived : function(aSocket, aMessage){
let recv_data = String.fromCharCode.apply(null, aMessage.rawData);
do_check_eq(recv_data, HELLO_WORLD);
do_check_eq(recv_data, aMessage.data);
socket.close();
run_next_test();
},
onStopListening: function(aSocket, aStatus){}
});
let rawData = new Uint8Array(HELLO_WORLD.length);
for (let i = 0; i < HELLO_WORLD.length; i++) {
rawData[i] = HELLO_WORLD.charCodeAt(i);
}
let written = socket.send("127.0.0.1", socket.port, rawData, rawData.length);
do_check_eq(written, HELLO_WORLD.length);
});
add_test(function test_udp_send_stream() {
do_print("test for nsIUDPSocket.sendBinaryStream");
let socket = Cc["@mozilla.org/network/udp-socket;1"].createInstance(Ci.nsIUDPSocket);
socket.init(-1, true);
socket.asyncListen({
QueryInterface : XPCOMUtils.generateQI([Ci.nsIUDPSocketListener]),
onPacketReceived : function(aSocket, aMessage){
let recv_data = String.fromCharCode.apply(null, aMessage.rawData);
do_check_eq(recv_data, HELLO_WORLD);
socket.close();
run_next_test();
},
onStopListening: function(aSocket, aStatus){}
});
let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
stream.setData(HELLO_WORLD, HELLO_WORLD.length);
socket.sendBinaryStream("127.0.0.1", socket.port, stream);
});
function run_test(){
run_next_test();
}

View File

@ -149,7 +149,7 @@ skip-if = os == "android"
# Allocating 4GB might actually succeed on 64 bit machines
skip-if = bits != 32
[test_bug935499.js]
[test_udpsocket.js]
[test_bug952927.js]
[test_doomentry.js]
[test_cacheflags.js]
[test_cache_jar.js]