mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Backed out 4 changesets (bug 745283) for conflicting with the backout of bug 786419 a=backout
Backed out changeset a1af198d91bd (bug 745283) Backed out changeset 9fc6f4275bbb (bug 745283) Backed out changeset 37c10c9f2a4d (bug 745283) Backed out changeset bc0ab47e8ac7 (bug 745283) --HG-- rename : netwerk/test/unit/test_udpsocket.js => netwerk/test/unit/test_bug952927.js
This commit is contained in:
parent
8017b23648
commit
98851f79ce
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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__();
|
||||
};
|
||||
|
||||
|
@ -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
|
@ -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__
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -9,11 +9,8 @@
|
||||
#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 "nsNetUtil.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
@ -22,10 +19,52 @@
|
||||
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()
|
||||
UDPSocketParent::UDPSocketParent(nsIUDPSocketFilter *filter)
|
||||
: mIPCOpen(true)
|
||||
, mFilter(filter)
|
||||
{
|
||||
mObserver = new mozilla::net::OfflineObserver(this);
|
||||
}
|
||||
@ -37,30 +76,6 @@ 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;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
UDPSocketParent::GetAppId()
|
||||
{
|
||||
@ -104,236 +119,125 @@ UDPSocketParent::OfflineNotification(nsISupports *aSubject)
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -364,6 +268,7 @@ UDPSocketParent::OnPacketReceived(nsIUDPSocket* aSocket, nsIUDPMessage* aMessage
|
||||
if (!mIPCOpen) {
|
||||
return NS_OK;
|
||||
}
|
||||
NS_ASSERTION(mFilter, "No packet filter");
|
||||
|
||||
uint16_t port;
|
||||
nsCString ip;
|
||||
@ -378,30 +283,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;
|
||||
}
|
||||
@ -411,21 +316,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
|
||||
|
@ -24,22 +24,17 @@ public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIUDPSOCKETLISTENER
|
||||
|
||||
explicit UDPSocketParent();
|
||||
explicit UDPSocketParent(nsIUDPSocketFilter* 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;
|
||||
|
||||
virtual nsresult OfflineNotification(nsISupports *) MOZ_OVERRIDE;
|
||||
virtual uint32_t GetAppId() MOZ_OVERRIDE;
|
||||
@ -47,12 +42,6 @@ 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;
|
||||
|
@ -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',
|
||||
]
|
||||
|
@ -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>
|
@ -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]
|
||||
|
@ -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>
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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!
|
||||
|
@ -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"
|
||||
};
|
@ -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;
|
||||
};
|
@ -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
|
||||
};
|
@ -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',
|
||||
]
|
||||
|
@ -705,13 +705,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;
|
||||
@ -721,11 +725,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));
|
||||
@ -758,68 +763,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;
|
||||
}
|
||||
@ -1009,20 +1035,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4256,6 +4256,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);
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -237,7 +237,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;
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
@ -451,18 +452,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
|
||||
|
@ -156,8 +156,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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
31
netwerk/test/unit/test_bug952927.js
Normal file
31
netwerk/test/unit/test_bug952927.js
Normal 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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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]
|
||||
|
Loading…
Reference in New Issue
Block a user