Bug 745283 - Part 1: Expose nsINetAddr for the local address of nsUDPSocket and support send with InputStream. r=jduell, r=mayhemer

--HG--
rename : netwerk/test/unit/test_bug952927.js => netwerk/test/unit/test_udpsocket.js
This commit is contained in:
Shih-Chiang Chien 2014-04-21 09:33:00 +08:00
parent 2fd5c32bc6
commit 3b55c8951a
6 changed files with 189 additions and 43 deletions

View File

@ -10,6 +10,7 @@ interface nsIUDPSocketListener;
interface nsIUDPMessage;
interface nsISocketTransport;
interface nsIOutputStream;
interface nsIInputStream;
%{ C++
#include "nsTArrayForwardDeclare.h"
@ -28,7 +29,7 @@ native NetAddr(mozilla::net::NetAddr);
*
* An interface to a UDP socket that can accept incoming connections.
*/
[scriptable, uuid(3240F793-80FA-4088-987A-9C7378F0AC88)]
[scriptable, uuid(5e526cc7-a65f-42b2-b193-a6894c0253f7)]
interface nsIUDPSocket : nsISupports
{
/**
@ -44,8 +45,11 @@ 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.
*/
void init(in long aPort, in boolean aLoopbackOnly);
[optional_argc] void init(in long aPort, in boolean aLoopbackOnly, [optional] in boolean aAddressReuse);
/**
* initWithAddress
@ -55,8 +59,11 @@ 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] void initWithAddress([const] in NetAddrPtr aAddr);
[noscript, optional_argc] void initWithAddress([const] in NetAddrPtr aAddr, [optional] in boolean aAddressReuse);
/**
* close
@ -85,6 +92,11 @@ 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.
*/
@ -145,6 +157,29 @@ interface nsIUDPSocket : nsISupports
[const, array, size_is(dataLength)]in uint8_t data,
in unsigned long dataLength);
/**
* sendBinaryStream
*
* Send out the datagram to specified remote address and port.
*
* @param host The remote host name.
* @param port The remote port.
* @param stream The input stream to be sent. This must be a buffered stream implementation.
*/
void sendBinaryStream(in AUTF8String host, in unsigned short port,
in nsIInputStream stream);
/**
* sendBinaryStreamWithAddress
*
* Send out the datagram to specified remote address and port.
*
* @param addr The remote host address.
* @param stream The input stream to be sent. This must be a buffered stream implementation.
*/
void sendBinaryStreamWithAddress([const] in NetAddrPtr addr,
in nsIInputStream stream);
/**
* joinMulticast
*

View File

@ -31,6 +31,7 @@ using namespace mozilla::net;
using namespace mozilla;
static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID);
static const uint32_t UDP_PACKET_CHUNK_SIZE = 1400;
//-----------------------------------------------------------------------------
@ -479,7 +480,7 @@ nsUDPSocket::OnSocketReady(PRFileDesc *fd, int16_t outFlags)
nsCOMPtr<nsIAsyncInputStream> pipeIn;
nsCOMPtr<nsIAsyncOutputStream> pipeOut;
uint32_t segsize = 1400;
uint32_t segsize = UDP_PACKET_CHUNK_SIZE;
uint32_t segcount = 0;
net_ResolveSegmentParams(segsize, segcount);
nsresult rv = NS_NewPipe2(getter_AddRefs(pipeIn), getter_AddRefs(pipeOut),
@ -491,7 +492,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, 1400);
NS_ASYNCCOPY_VIA_READSEGMENTS, UDP_PACKET_CHUNK_SIZE);
if (NS_FAILED(rv)) {
return;
@ -552,7 +553,7 @@ NS_IMPL_ISUPPORTS(nsUDPSocket, nsIUDPSocket)
//-----------------------------------------------------------------------------
NS_IMETHODIMP
nsUDPSocket::Init(int32_t aPort, bool aLoopbackOnly)
nsUDPSocket::Init(int32_t aPort, bool aLoopbackOnly, bool aAddressReuse, uint8_t aOptionalArgc)
{
NetAddr addr;
@ -567,14 +568,16 @@ nsUDPSocket::Init(int32_t aPort, bool aLoopbackOnly)
else
addr.inet.ip = htonl(INADDR_ANY);
return InitWithAddress(&addr);
return InitWithAddress(&addr, aAddressReuse, aOptionalArgc);
}
NS_IMETHODIMP
nsUDPSocket::InitWithAddress(const NetAddr *aAddr)
nsUDPSocket::InitWithAddress(const NetAddr *aAddr, bool aAddressReuse, uint8_t aOptionalArgc)
{
NS_ENSURE_TRUE(mFD == nullptr, NS_ERROR_ALREADY_INITIALIZED);
bool addressReuse = (aOptionalArgc == 1) ? aAddressReuse : true;
//
// configure listening socket...
//
@ -598,7 +601,7 @@ nsUDPSocket::InitWithAddress(const NetAddr *aAddr)
// to port 0 with SO_REUSEADDR
if (port) {
opt.option = PR_SockOpt_Reuseaddr;
opt.value.reuse_addr = true;
opt.value.reuse_addr = addressReuse;
PR_SetSocketOption(mFD, &opt);
}
@ -668,6 +671,17 @@ 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)
{
@ -829,6 +843,47 @@ 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,
@ -953,6 +1008,32 @@ nsUDPSocket::SendWithAddress(const NetAddr *aAddr, const uint8_t *aData,
return NS_OK;
}
NS_IMETHODIMP
nsUDPSocket::SendBinaryStream(const nsACString &aHost, uint16_t aPort,
nsIInputStream *aStream)
{
NS_ENSURE_ARG(aStream);
nsCOMPtr<nsIDNSListener> listener = new PendingSendStream(this, aPort, aStream);
return ResolveHost(aHost, listener);
}
NS_IMETHODIMP
nsUDPSocket::SendBinaryStreamWithAddress(const NetAddr *aAddr, nsIInputStream *aStream)
{
NS_ENSURE_ARG(aAddr);
NS_ENSURE_ARG(aStream);
PRNetAddr prAddr;
PR_InitializeNetAddr(PR_IpAddrAny, 0, &prAddr);
NetAddrToPRNetAddr(aAddr, &prAddr);
nsRefPtr<nsUDPOutputStream> os = new nsUDPOutputStream(this, mFD, prAddr);
return NS_AsyncCopy(aStream, os, mSts, NS_ASYNCCOPY_VIA_READSEGMENTS,
UDP_PACKET_CHUNK_SIZE);
}
nsresult
nsUDPSocket::SetSocketOption(const PRSocketOptionData& aOpt)
{

View File

@ -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);
rv = server->Init(0, false, true, 0);
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);
client->Init(0, false, true, 0);
client->AsyncListen(clientListener);
// Write data to server

View File

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

View File

@ -0,0 +1,61 @@
/* -*- Mode: Javasript; indent-tab-mode: nil; js-indent-level: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const HELLO_WORLD = "Hello World";
add_test(function test_udp_message_raw_data() {
do_print("test for nsIUDPMessage.rawData");
let socket = Cc["@mozilla.org/network/udp-socket;1"].createInstance(Ci.nsIUDPSocket);
socket.init(-1, true);
do_print("Port assigned : " + socket.port);
socket.asyncListen({
QueryInterface : XPCOMUtils.generateQI([Ci.nsIUDPSocketListener]),
onPacketReceived : function(aSocket, aMessage){
let recv_data = String.fromCharCode.apply(null, aMessage.rawData);
do_check_eq(recv_data, HELLO_WORLD);
do_check_eq(recv_data, aMessage.data);
socket.close();
run_next_test();
},
onStopListening: function(aSocket, aStatus){}
});
let rawData = new Uint8Array(HELLO_WORLD.length);
for (let i = 0; i < HELLO_WORLD.length; i++) {
rawData[i] = HELLO_WORLD.charCodeAt(i);
}
let written = socket.send("127.0.0.1", socket.port, rawData, rawData.length);
do_check_eq(written, HELLO_WORLD.length);
});
add_test(function test_udp_send_stream() {
do_print("test for nsIUDPSocket.sendBinaryStream");
let socket = Cc["@mozilla.org/network/udp-socket;1"].createInstance(Ci.nsIUDPSocket);
socket.init(-1, true);
socket.asyncListen({
QueryInterface : XPCOMUtils.generateQI([Ci.nsIUDPSocketListener]),
onPacketReceived : function(aSocket, aMessage){
let recv_data = String.fromCharCode.apply(null, aMessage.rawData);
do_check_eq(recv_data, HELLO_WORLD);
socket.close();
run_next_test();
},
onStopListening: function(aSocket, aStatus){}
});
let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
stream.setData(HELLO_WORLD, HELLO_WORLD.length);
socket.sendBinaryStream("127.0.0.1", socket.port, stream);
});
function run_test(){
run_next_test();
}

View File

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