mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Backed out 4 changesets (bug 745283) for merge conflicts with bug 786419.
Backed out changeset 70bad98676c8 (bug 745283) Backed out changeset fc08327b3d3e (bug 745283) Backed out changeset ce19c464f5d8 (bug 745283) Backed out changeset c6ad8ab94461 (bug 745283) --HG-- rename : netwerk/test/unit/test_udpsocket.js => netwerk/test/unit/test_bug952927.js
This commit is contained in:
parent
93344ab162
commit
388cb0948b
@ -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,279 +9,181 @@
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIUDPSocket.h"
|
||||
#include "nsINetAddr.h"
|
||||
#include "mozilla/AppProcessChecker.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
#include "mozilla/net/DNS.h"
|
||||
#include "mozilla/net/NeckoCommon.h"
|
||||
#include "mozilla/net/PNeckoParent.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
static void
|
||||
FireInternalError(mozilla::net::PUDPSocketParent *aActor, uint32_t aLineNo)
|
||||
{
|
||||
mozilla::unused <<
|
||||
aActor->SendCallback(NS_LITERAL_CSTRING("onerror"),
|
||||
UDPError(NS_LITERAL_CSTRING("Internal error"),
|
||||
NS_LITERAL_CSTRING(__FILE__), aLineNo, 0),
|
||||
NS_LITERAL_CSTRING("connecting"));
|
||||
}
|
||||
|
||||
static nsresult
|
||||
ConvertNetAddrToString(mozilla::net::NetAddr &netAddr, nsACString *address, uint16_t *port)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(address);
|
||||
NS_ENSURE_ARG_POINTER(port);
|
||||
|
||||
*port = 0;
|
||||
uint32_t bufSize = 0;
|
||||
|
||||
switch(netAddr.raw.family) {
|
||||
case AF_INET:
|
||||
*port = PR_ntohs(netAddr.inet.port);
|
||||
bufSize = mozilla::net::kIPv4CStrBufSize;
|
||||
break;
|
||||
case AF_INET6:
|
||||
*port = PR_ntohs(netAddr.inet6.port);
|
||||
bufSize = mozilla::net::kIPv6CStrBufSize;
|
||||
break;
|
||||
default:
|
||||
//impossible
|
||||
MOZ_ASSERT(false, "Unexpected address family");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
address->SetCapacity(bufSize);
|
||||
NetAddrToString(&netAddr, address->BeginWriting(), bufSize);
|
||||
address->SetLength(strlen(address->BeginReading()));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(UDPSocketParent, nsIUDPSocketListener)
|
||||
|
||||
UDPSocketParent::~UDPSocketParent()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
UDPSocketParent::Init(const nsACString& aFilter)
|
||||
{
|
||||
if (!aFilter.IsEmpty()) {
|
||||
nsAutoCString contractId(NS_NETWORK_UDP_SOCKET_FILTER_HANDLER_PREFIX);
|
||||
contractId.Append(aFilter);
|
||||
nsCOMPtr<nsIUDPSocketFilterHandler> filterHandler =
|
||||
do_GetService(contractId.get());
|
||||
if (filterHandler) {
|
||||
nsresult rv = filterHandler->NewFilter(getter_AddRefs(mFilter));
|
||||
if (NS_FAILED(rv)) {
|
||||
printf_stderr("Cannot create filter that content specified. "
|
||||
"filter name: %s, error code: %d.", aFilter.BeginReading(), rv);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
printf_stderr("Content doesn't have a valid filter. "
|
||||
"filter name: %s.", aFilter.BeginReading());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// PUDPSocketParent methods
|
||||
|
||||
bool
|
||||
UDPSocketParent::RecvBind(const UDPAddressInfo& aAddressInfo,
|
||||
const bool& aAddressReuse, const bool& aLoopback)
|
||||
{
|
||||
// We don't have browser actors in xpcshell, and hence can't run automated
|
||||
// tests without this loophole.
|
||||
if (net::UsingNeckoIPCSecurity() && !mFilter &&
|
||||
!AssertAppProcessPermission(Manager()->Manager(), "udp-socket")) {
|
||||
FireInternalError(__LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NS_FAILED(BindInternal(aAddressInfo.addr(), aAddressInfo.port(), aAddressReuse, aLoopback))) {
|
||||
FireInternalError(__LINE__);
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsINetAddr> localAddr;
|
||||
mSocket->GetLocalAddr(getter_AddRefs(localAddr));
|
||||
|
||||
nsCString addr;
|
||||
if (NS_FAILED(localAddr->GetAddress(addr))) {
|
||||
FireInternalError(__LINE__);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t port;
|
||||
if (NS_FAILED(localAddr->GetPort(&port))) {
|
||||
FireInternalError(__LINE__);
|
||||
return true;
|
||||
}
|
||||
|
||||
mozilla::unused << SendCallbackOpened(UDPAddressInfo(addr, port));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
UDPSocketParent::BindInternal(const nsCString& aHost, const uint16_t& aPort,
|
||||
const bool& aAddressReuse, const bool& aLoopback)
|
||||
UDPSocketParent::Init(const nsCString &aHost, const uint16_t aPort)
|
||||
{
|
||||
nsresult rv;
|
||||
NS_ASSERTION(mFilter, "No packet filter");
|
||||
|
||||
nsCOMPtr<nsIUDPSocket> sock =
|
||||
do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
if (NS_FAILED(rv)) {
|
||||
FireInternalError(this, __LINE__);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aHost.IsEmpty()) {
|
||||
rv = sock->Init(aPort, false, aAddressReuse, /* optional_argc = */ 1);
|
||||
rv = sock->Init(aPort, false);
|
||||
} else {
|
||||
PRNetAddr prAddr;
|
||||
PR_InitializeNetAddr(PR_IpAddrAny, aPort, &prAddr);
|
||||
PRStatus status = PR_StringToNetAddr(aHost.BeginReading(), &prAddr);
|
||||
if (status != PR_SUCCESS) {
|
||||
return NS_ERROR_FAILURE;
|
||||
FireInternalError(this, __LINE__);
|
||||
return true;
|
||||
}
|
||||
|
||||
mozilla::net::NetAddr addr;
|
||||
PRNetAddrToNetAddr(&prAddr, &addr);
|
||||
rv = sock->InitWithAddress(&addr, aAddressReuse, /* optional_argc = */ 1);
|
||||
rv = sock->InitWithAddress(&addr);
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = sock->SetMulticastLoopback(aLoopback);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// register listener
|
||||
rv = sock->AsyncListen(this);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
if (NS_FAILED(rv)) {
|
||||
FireInternalError(this, __LINE__);
|
||||
return true;
|
||||
}
|
||||
|
||||
mSocket = sock;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
net::NetAddr localAddr;
|
||||
mSocket->GetAddress(&localAddr);
|
||||
|
||||
bool
|
||||
UDPSocketParent::RecvOutgoingData(const UDPData& aData,
|
||||
const UDPSocketAddr& aAddr)
|
||||
{
|
||||
MOZ_ASSERT(mSocket);
|
||||
|
||||
nsresult rv;
|
||||
if (mFilter) {
|
||||
// TODO, Bug 933102, filter packets that are sent with hostname.
|
||||
// Until then we simply throw away packets that are sent to a hostname.
|
||||
if (aAddr.type() != UDPSocketAddr::TNetAddr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO, Packet filter doesn't support input stream yet.
|
||||
if (aData.type() != UDPData::TArrayOfuint8_t) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool allowed;
|
||||
const InfallibleTArray<uint8_t>& data(aData.get_ArrayOfuint8_t());
|
||||
rv = mFilter->FilterPacket(&aAddr.get_NetAddr(), data.Elements(),
|
||||
data.Length(), nsIUDPSocketFilter::SF_OUTGOING,
|
||||
&allowed);
|
||||
|
||||
// Sending unallowed data, kill content.
|
||||
if (NS_WARN_IF(NS_FAILED(rv)) || !allowed) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch(aData.type()) {
|
||||
case UDPData::TArrayOfuint8_t:
|
||||
Send(aData.get_ArrayOfuint8_t(), aAddr);
|
||||
break;
|
||||
case UDPData::TInputStreamParams:
|
||||
Send(aData.get_InputStreamParams(), aAddr);
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(false, "Invalid data type!");
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
UDPSocketParent::Send(const InfallibleTArray<uint8_t>& aData,
|
||||
const UDPSocketAddr& aAddr)
|
||||
{
|
||||
nsresult rv;
|
||||
uint32_t count;
|
||||
switch(aAddr.type()) {
|
||||
case UDPSocketAddr::TUDPAddressInfo: {
|
||||
const UDPAddressInfo& addrInfo(aAddr.get_UDPAddressInfo());
|
||||
rv = mSocket->Send(addrInfo.addr(), addrInfo.port(),
|
||||
aData.Elements(), aData.Length(), &count);
|
||||
break;
|
||||
}
|
||||
case UDPSocketAddr::TNetAddr: {
|
||||
const NetAddr& addr(aAddr.get_NetAddr());
|
||||
rv = mSocket->SendWithAddress(&addr, aData.Elements(),
|
||||
aData.Length(), &count);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_ASSERT(false, "Invalid address type!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv)) || count == 0) {
|
||||
FireInternalError(__LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UDPSocketParent::Send(const InputStreamParams& aStream,
|
||||
const UDPSocketAddr& aAddr)
|
||||
{
|
||||
nsTArray<mozilla::ipc::FileDescriptor> fds;
|
||||
nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aStream, fds);
|
||||
|
||||
if (NS_WARN_IF(!stream)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
switch(aAddr.type()) {
|
||||
case UDPSocketAddr::TUDPAddressInfo: {
|
||||
const UDPAddressInfo& addrInfo(aAddr.get_UDPAddressInfo());
|
||||
rv = mSocket->SendBinaryStream(addrInfo.addr(), addrInfo.port(), stream);
|
||||
break;
|
||||
}
|
||||
case UDPSocketAddr::TNetAddr: {
|
||||
const NetAddr& addr(aAddr.get_NetAddr());
|
||||
rv = mSocket->SendBinaryStreamWithAddress(&addr, stream);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_ASSERT(false, "Invalid address type!");
|
||||
return;
|
||||
}
|
||||
uint16_t port;
|
||||
nsCString addr;
|
||||
rv = ConvertNetAddrToString(localAddr, &addr, &port);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
FireInternalError(__LINE__);
|
||||
FireInternalError(this, __LINE__);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
UDPSocketParent::RecvJoinMulticast(const nsCString& aMulticastAddress,
|
||||
const nsCString& aInterface)
|
||||
{
|
||||
nsresult rv = mSocket->JoinMulticast(aMulticastAddress, aInterface);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
FireInternalError(__LINE__);
|
||||
}
|
||||
// register listener
|
||||
mSocket->AsyncListen(this);
|
||||
mozilla::unused <<
|
||||
PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onopen"),
|
||||
UDPAddressInfo(addr, port),
|
||||
NS_LITERAL_CSTRING("connected"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
UDPSocketParent::RecvLeaveMulticast(const nsCString& aMulticastAddress,
|
||||
const nsCString& aInterface)
|
||||
UDPSocketParent::RecvData(const InfallibleTArray<uint8_t> &aData,
|
||||
const nsCString& aRemoteAddress,
|
||||
const uint16_t& aPort)
|
||||
{
|
||||
nsresult rv = mSocket->LeaveMulticast(aMulticastAddress, aInterface);
|
||||
NS_ENSURE_TRUE(mSocket, true);
|
||||
NS_ASSERTION(mFilter, "No packet filter");
|
||||
// TODO, Bug 933102, filter packets that are sent with hostname.
|
||||
// Until then we simply throw away packets that are sent to a hostname.
|
||||
return true;
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
FireInternalError(__LINE__);
|
||||
}
|
||||
#if 0
|
||||
// Enable this once we have filtering working with hostname delivery.
|
||||
uint32_t count;
|
||||
nsresult rv = mSocket->Send(aRemoteAddress,
|
||||
aPort, aData.Elements(),
|
||||
aData.Length(), &count);
|
||||
mozilla::unused <<
|
||||
PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onsent"),
|
||||
UDPSendResult(rv),
|
||||
NS_LITERAL_CSTRING("connected"));
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
NS_ENSURE_TRUE(count > 0, true);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
UDPSocketParent::RecvDataWithAddress(const InfallibleTArray<uint8_t>& aData,
|
||||
const mozilla::net::NetAddr& aAddr)
|
||||
{
|
||||
NS_ENSURE_TRUE(mSocket, true);
|
||||
NS_ASSERTION(mFilter, "No packet filter");
|
||||
|
||||
uint32_t count;
|
||||
nsresult rv;
|
||||
bool allowed;
|
||||
rv = mFilter->FilterPacket(&aAddr, aData.Elements(),
|
||||
aData.Length(), nsIUDPSocketFilter::SF_OUTGOING,
|
||||
&allowed);
|
||||
// Sending unallowed data, kill content.
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
NS_ENSURE_TRUE(allowed, false);
|
||||
|
||||
rv = mSocket->SendWithAddress(&aAddr, aData.Elements(),
|
||||
aData.Length(), &count);
|
||||
mozilla::unused <<
|
||||
PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onsent"),
|
||||
UDPSendResult(rv),
|
||||
NS_LITERAL_CSTRING("connected"));
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
NS_ENSURE_TRUE(count > 0, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
UDPSocketParent::RecvClose()
|
||||
{
|
||||
if (!mSocket) {
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(mSocket, true);
|
||||
nsresult rv = mSocket->Close();
|
||||
mSocket = nullptr;
|
||||
|
||||
mozilla::unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -312,6 +214,7 @@ UDPSocketParent::OnPacketReceived(nsIUDPSocket* aSocket, nsIUDPMessage* aMessage
|
||||
if (!mIPCOpen) {
|
||||
return NS_OK;
|
||||
}
|
||||
NS_ASSERTION(mFilter, "No packet filter");
|
||||
|
||||
uint16_t port;
|
||||
nsCString ip;
|
||||
@ -326,30 +229,30 @@ UDPSocketParent::OnPacketReceived(nsIUDPSocket* aSocket, nsIUDPMessage* aMessage
|
||||
const char* buffer = data.get();
|
||||
uint32_t len = data.Length();
|
||||
|
||||
if (mFilter) {
|
||||
bool allowed;
|
||||
mozilla::net::NetAddr addr;
|
||||
fromAddr->GetNetAddr(&addr);
|
||||
nsresult rv = mFilter->FilterPacket(&addr,
|
||||
(const uint8_t*)buffer, len,
|
||||
nsIUDPSocketFilter::SF_INCOMING,
|
||||
&allowed);
|
||||
// Receiving unallowed data, drop.
|
||||
if (NS_WARN_IF(NS_FAILED(rv)) || !allowed) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
bool allowed;
|
||||
mozilla::net::NetAddr addr;
|
||||
fromAddr->GetNetAddr(&addr);
|
||||
nsresult rv = mFilter->FilterPacket(&addr,
|
||||
(const uint8_t*)buffer, len,
|
||||
nsIUDPSocketFilter::SF_INCOMING,
|
||||
&allowed);
|
||||
// Receiving unallowed data, drop.
|
||||
NS_ENSURE_SUCCESS(rv, NS_OK);
|
||||
NS_ENSURE_TRUE(allowed, NS_OK);
|
||||
|
||||
FallibleTArray<uint8_t> fallibleArray;
|
||||
if (!fallibleArray.InsertElementsAt(0, buffer, len)) {
|
||||
FireInternalError(__LINE__);
|
||||
FireInternalError(this, __LINE__);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
InfallibleTArray<uint8_t> infallibleArray;
|
||||
infallibleArray.SwapElements(fallibleArray);
|
||||
|
||||
// compose callback
|
||||
mozilla::unused << SendCallbackReceivedData(UDPAddressInfo(ip, port), infallibleArray);
|
||||
mozilla::unused <<
|
||||
PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("ondata"),
|
||||
UDPMessage(ip, port, infallibleArray),
|
||||
NS_LITERAL_CSTRING("connected"));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -359,21 +262,13 @@ UDPSocketParent::OnStopListening(nsIUDPSocket* aSocket, nsresult aStatus)
|
||||
{
|
||||
// underlying socket is dead, send state update to child process
|
||||
if (mIPCOpen) {
|
||||
mozilla::unused << SendCallbackClosed();
|
||||
mozilla::unused <<
|
||||
PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onclose"),
|
||||
mozilla::void_t(),
|
||||
NS_LITERAL_CSTRING("closed"));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
UDPSocketParent::FireInternalError(uint32_t aLineNo)
|
||||
{
|
||||
if (!mIPCOpen) {
|
||||
return;
|
||||
}
|
||||
|
||||
mozilla::unused << SendCallbackError(NS_LITERAL_CSTRING("Internal error"),
|
||||
NS_LITERAL_CSTRING(__FILE__), aLineNo);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -22,34 +22,24 @@ public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIUDPSOCKETLISTENER
|
||||
|
||||
UDPSocketParent() :
|
||||
mIPCOpen(true) {}
|
||||
explicit UDPSocketParent(nsIUDPSocketFilter* filter) :
|
||||
mIPCOpen(true),
|
||||
mFilter(filter) {}
|
||||
|
||||
bool Init(const nsACString& aFilter);
|
||||
|
||||
virtual bool RecvBind(const UDPAddressInfo& aAddressInfo,
|
||||
const bool& aAddressReuse, const bool& aLoopback) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvOutgoingData(const UDPData& aData, const UDPSocketAddr& aAddr) MOZ_OVERRIDE;
|
||||
bool Init(const nsCString& aHost, const uint16_t aPort);
|
||||
|
||||
virtual bool RecvClose() MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvData(const InfallibleTArray<uint8_t>& aData,
|
||||
const nsCString& aRemoteAddress,
|
||||
const uint16_t& aPort) MOZ_OVERRIDE;
|
||||
virtual bool RecvDataWithAddress( const InfallibleTArray<uint8_t>& data,
|
||||
const mozilla::net::NetAddr& addr);
|
||||
virtual bool RecvRequestDelete() MOZ_OVERRIDE;
|
||||
virtual bool RecvJoinMulticast(const nsCString& aMulticastAddress,
|
||||
const nsCString& aInterface) MOZ_OVERRIDE;
|
||||
virtual bool RecvLeaveMulticast(const nsCString& aMulticastAddress,
|
||||
const nsCString& aInterface) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
virtual ~UDPSocketParent();
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
|
||||
void Send(const InfallibleTArray<uint8_t>& aData, const UDPSocketAddr& aAddr);
|
||||
void Send(const InputStreamParams& aStream, const UDPSocketAddr& aAddr);
|
||||
nsresult BindInternal(const nsCString& aHost, const uint16_t& aPort,
|
||||
const bool& aAddressReuse, const bool& aLoopback);
|
||||
|
||||
void FireInternalError(uint32_t aLineNo);
|
||||
|
||||
bool mIPCOpen;
|
||||
nsCOMPtr<nsIUDPSocket> mSocket;
|
||||
|
@ -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',
|
||||
]
|
||||
|
@ -700,13 +700,17 @@ NrSocketIpc::NrSocketIpc(const nsCOMPtr<nsIEventTarget> &main_thread)
|
||||
|
||||
// IUDPSocketInternal interfaces
|
||||
// callback while error happened in UDP socket operation
|
||||
NS_IMETHODIMP NrSocketIpc::CallListenerError(const nsACString &message,
|
||||
NS_IMETHODIMP NrSocketIpc::CallListenerError(const nsACString &type,
|
||||
const nsACString &message,
|
||||
const nsACString &filename,
|
||||
uint32_t line_number) {
|
||||
uint32_t line_number,
|
||||
uint32_t column_number) {
|
||||
ASSERT_ON_THREAD(main_thread_);
|
||||
MOZ_ASSERT(type.EqualsLiteral("onerror"));
|
||||
|
||||
r_log(LOG_GENERIC, LOG_ERR, "UDP socket error:%s at %s:%d",
|
||||
message.BeginReading(), filename.BeginReading(), line_number );
|
||||
r_log(LOG_GENERIC, LOG_ERR, "UDP socket error:%s at %s:%d:%d",
|
||||
message.BeginReading(), filename.BeginReading(),
|
||||
line_number, column_number);
|
||||
|
||||
ReentrantMonitorAutoEnter mon(monitor_);
|
||||
err_ = true;
|
||||
@ -716,11 +720,12 @@ NS_IMETHODIMP NrSocketIpc::CallListenerError(const nsACString &message,
|
||||
}
|
||||
|
||||
// callback while receiving UDP packet
|
||||
NS_IMETHODIMP NrSocketIpc::CallListenerReceivedData(const nsACString &host,
|
||||
uint16_t port,
|
||||
const uint8_t *data,
|
||||
NS_IMETHODIMP NrSocketIpc::CallListenerReceivedData(const nsACString &type,
|
||||
const nsACString &host,
|
||||
uint16_t port, uint8_t *data,
|
||||
uint32_t data_length) {
|
||||
ASSERT_ON_THREAD(main_thread_);
|
||||
MOZ_ASSERT(type.EqualsLiteral("ondata"));
|
||||
|
||||
PRNetAddr addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
@ -753,68 +758,89 @@ NS_IMETHODIMP NrSocketIpc::CallListenerReceivedData(const nsACString &host,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// callback while UDP socket is opened
|
||||
NS_IMETHODIMP NrSocketIpc::CallListenerOpened() {
|
||||
// callback while UDP socket is opened or closed
|
||||
NS_IMETHODIMP NrSocketIpc::CallListenerVoid(const nsACString &type) {
|
||||
ASSERT_ON_THREAD(main_thread_);
|
||||
ReentrantMonitorAutoEnter mon(monitor_);
|
||||
if (type.EqualsLiteral("onopen")) {
|
||||
ReentrantMonitorAutoEnter mon(monitor_);
|
||||
|
||||
uint16_t port;
|
||||
if (NS_FAILED(socket_child_->GetLocalPort(&port))) {
|
||||
err_ = true;
|
||||
MOZ_ASSERT(false, "Failed to get local port");
|
||||
return NS_OK;
|
||||
uint16_t port;
|
||||
if (NS_FAILED(socket_child_->GetLocalPort(&port))) {
|
||||
err_ = true;
|
||||
MOZ_ASSERT(false, "Failed to get local port");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoCString address;
|
||||
if(NS_FAILED(socket_child_->GetLocalAddress(address))) {
|
||||
err_ = true;
|
||||
MOZ_ASSERT(false, "Failed to get local address");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRNetAddr praddr;
|
||||
if (PR_SUCCESS != PR_InitializeNetAddr(PR_IpAddrAny, port, &praddr)) {
|
||||
err_ = true;
|
||||
MOZ_ASSERT(false, "Failed to set port in PRNetAddr");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (PR_SUCCESS != PR_StringToNetAddr(address.BeginReading(), &praddr)) {
|
||||
err_ = true;
|
||||
MOZ_ASSERT(false, "Failed to convert local host to PRNetAddr");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nr_transport_addr expected_addr;
|
||||
if(nr_transport_addr_copy(&expected_addr, &my_addr_)) {
|
||||
err_ = true;
|
||||
MOZ_ASSERT(false, "Failed to copy my_addr_");
|
||||
}
|
||||
|
||||
if (nr_praddr_to_transport_addr(&praddr, &my_addr_, IPPROTO_UDP, 1)) {
|
||||
err_ = true;
|
||||
MOZ_ASSERT(false, "Failed to copy local host to my_addr_");
|
||||
}
|
||||
|
||||
if (nr_transport_addr_cmp(&expected_addr, &my_addr_,
|
||||
NR_TRANSPORT_ADDR_CMP_MODE_ADDR)) {
|
||||
err_ = true;
|
||||
MOZ_ASSERT(false, "Address of opened socket is not expected");
|
||||
}
|
||||
|
||||
mon.NotifyAll();
|
||||
} else if (type.EqualsLiteral("onclose")) {
|
||||
// Already handled in UpdateReadyState, nothing to do here
|
||||
} else {
|
||||
MOZ_ASSERT(false, "Received unexpected event");
|
||||
}
|
||||
|
||||
nsAutoCString address;
|
||||
if(NS_FAILED(socket_child_->GetLocalAddress(address))) {
|
||||
err_ = true;
|
||||
MOZ_ASSERT(false, "Failed to get local address");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRNetAddr praddr;
|
||||
if (PR_SUCCESS != PR_InitializeNetAddr(PR_IpAddrAny, port, &praddr)) {
|
||||
err_ = true;
|
||||
MOZ_ASSERT(false, "Failed to set port in PRNetAddr");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (PR_SUCCESS != PR_StringToNetAddr(address.BeginReading(), &praddr)) {
|
||||
err_ = true;
|
||||
MOZ_ASSERT(false, "Failed to convert local host to PRNetAddr");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nr_transport_addr expected_addr;
|
||||
if(nr_transport_addr_copy(&expected_addr, &my_addr_)) {
|
||||
err_ = true;
|
||||
MOZ_ASSERT(false, "Failed to copy my_addr_");
|
||||
}
|
||||
|
||||
if (nr_praddr_to_transport_addr(&praddr, &my_addr_, IPPROTO_UDP, 1)) {
|
||||
err_ = true;
|
||||
MOZ_ASSERT(false, "Failed to copy local host to my_addr_");
|
||||
}
|
||||
|
||||
if (nr_transport_addr_cmp(&expected_addr, &my_addr_,
|
||||
NR_TRANSPORT_ADDR_CMP_MODE_ADDR)) {
|
||||
err_ = true;
|
||||
MOZ_ASSERT(false, "Address of opened socket is not expected");
|
||||
}
|
||||
|
||||
mon.NotifyAll();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// callback while UDP socket is closed
|
||||
NS_IMETHODIMP NrSocketIpc::CallListenerClosed() {
|
||||
// callback while UDP packet is sent
|
||||
NS_IMETHODIMP NrSocketIpc::CallListenerSent(const nsACString &type,
|
||||
nsresult result) {
|
||||
ASSERT_ON_THREAD(main_thread_);
|
||||
MOZ_ASSERT(type.EqualsLiteral("onsent"));
|
||||
|
||||
if (NS_FAILED(result)) {
|
||||
ReentrantMonitorAutoEnter mon(monitor_);
|
||||
err_ = true;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// callback for state update after every socket operation
|
||||
NS_IMETHODIMP NrSocketIpc::UpdateReadyState(const nsACString &readyState) {
|
||||
ASSERT_ON_THREAD(main_thread_);
|
||||
|
||||
ReentrantMonitorAutoEnter mon(monitor_);
|
||||
|
||||
MOZ_ASSERT(state_ == NR_CONNECTED || state_ == NR_CLOSING);
|
||||
state_ = NR_CLOSED;
|
||||
if (readyState.EqualsLiteral("closed")) {
|
||||
MOZ_ASSERT(state_ == NR_CONNECTED || state_ == NR_CLOSING);
|
||||
state_ = NR_CLOSED;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1004,20 +1030,14 @@ void NrSocketIpc::create_m(const nsACString &host, const uint16_t port) {
|
||||
if (NS_FAILED(rv)) {
|
||||
err_ = true;
|
||||
MOZ_ASSERT(false, "Failed to create UDPSocketChild");
|
||||
mon.NotifyAll();
|
||||
return;
|
||||
}
|
||||
|
||||
socket_child_ = new nsMainThreadPtrHolder<nsIUDPSocketChild>(socketChild);
|
||||
socket_child_->SetFilterName(nsCString("stun"));
|
||||
|
||||
if (NS_FAILED(socket_child_->Bind(this, host, port,
|
||||
/* reuse = */ false,
|
||||
/* loopback = */ false))) {
|
||||
if (NS_FAILED(socket_child_->Bind(this, host, port))) {
|
||||
err_ = true;
|
||||
MOZ_ASSERT(false, "Failed to create UDP socket");
|
||||
mon.NotifyAll();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4253,6 +4253,3 @@ pref("dom.fetch.enabled", false);
|
||||
// platforms; and set to 0 to disable the low-memory check altogether.
|
||||
pref("camera.control.low_memory_thresholdMB", 404);
|
||||
#endif
|
||||
|
||||
// UDPSocket API
|
||||
pref("dom.udpsocket.enabled", false);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -236,7 +236,9 @@ NeckoChild::DeallocPTCPServerSocketChild(PTCPServerSocketChild* child)
|
||||
}
|
||||
|
||||
PUDPSocketChild*
|
||||
NeckoChild::AllocPUDPSocketChild(const nsCString& aFilter)
|
||||
NeckoChild::AllocPUDPSocketChild(const nsCString& aHost,
|
||||
const uint16_t& aPort,
|
||||
const nsCString& aFilter)
|
||||
{
|
||||
NS_NOTREACHED("AllocPUDPSocket should not be called");
|
||||
return nullptr;
|
||||
|
@ -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"
|
||||
@ -444,18 +445,45 @@ NeckoParent::DeallocPTCPServerSocketParent(PTCPServerSocketParent* actor)
|
||||
}
|
||||
|
||||
PUDPSocketParent*
|
||||
NeckoParent::AllocPUDPSocketParent(const nsCString& /* unused */)
|
||||
NeckoParent::AllocPUDPSocketParent(const nsCString& aHost,
|
||||
const uint16_t& aPort,
|
||||
const nsCString& aFilter)
|
||||
{
|
||||
nsRefPtr<UDPSocketParent> p = new UDPSocketParent();
|
||||
UDPSocketParent* p = nullptr;
|
||||
|
||||
return p.forget().take();
|
||||
// Only allow socket if it specifies a valid packet filter.
|
||||
nsAutoCString contractId(NS_NETWORK_UDP_SOCKET_FILTER_HANDLER_PREFIX);
|
||||
contractId.Append(aFilter);
|
||||
|
||||
if (!aFilter.IsEmpty()) {
|
||||
nsCOMPtr<nsIUDPSocketFilterHandler> filterHandler =
|
||||
do_GetService(contractId.get());
|
||||
if (filterHandler) {
|
||||
nsCOMPtr<nsIUDPSocketFilter> filter;
|
||||
nsresult rv = filterHandler->NewFilter(getter_AddRefs(filter));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
p = new UDPSocketParent(filter);
|
||||
} else {
|
||||
printf_stderr("Cannot create filter that content specified. "
|
||||
"filter name: %s, error code: %d.", aFilter.get(), rv);
|
||||
}
|
||||
} else {
|
||||
printf_stderr("Content doesn't have a valid filter. "
|
||||
"filter name: %s.", aFilter.get());
|
||||
}
|
||||
}
|
||||
|
||||
NS_IF_ADDREF(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
bool
|
||||
NeckoParent::RecvPUDPSocketConstructor(PUDPSocketParent* aActor,
|
||||
const nsCString& aHost,
|
||||
const uint16_t& aPort,
|
||||
const nsCString& aFilter)
|
||||
{
|
||||
return static_cast<UDPSocketParent*>(aActor)->Init(aFilter);
|
||||
return static_cast<UDPSocketParent*>(aActor)->Init(aHost, aPort);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -153,8 +153,13 @@ protected:
|
||||
const uint16_t& aBacklog,
|
||||
const nsString& aBinaryType) MOZ_OVERRIDE;
|
||||
virtual bool DeallocPTCPServerSocketParent(PTCPServerSocketParent*) MOZ_OVERRIDE;
|
||||
virtual PUDPSocketParent* AllocPUDPSocketParent(const nsCString& aFilter) MOZ_OVERRIDE;
|
||||
virtual bool RecvPUDPSocketConstructor(PUDPSocketParent*, const nsCString& aFilter) MOZ_OVERRIDE;
|
||||
virtual PUDPSocketParent* AllocPUDPSocketParent(const nsCString& aHost,
|
||||
const uint16_t& aPort,
|
||||
const nsCString& aFilter) MOZ_OVERRIDE;
|
||||
virtual bool RecvPUDPSocketConstructor(PUDPSocketParent*,
|
||||
const nsCString& aHost,
|
||||
const uint16_t& aPort,
|
||||
const nsCString& aFilter) MOZ_OVERRIDE;
|
||||
virtual bool DeallocPUDPSocketParent(PUDPSocketParent*) MOZ_OVERRIDE;
|
||||
virtual PDNSRequestParent* AllocPDNSRequestParent(const nsCString& aHost,
|
||||
const uint32_t& aFlags) MOZ_OVERRIDE;
|
||||
|
@ -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