gecko-dev/netwerk/test/TestUDPSocket.cpp
Gabriele Svelto 5dc21d568c Bug 1600545 - Remove useless inclusions of header files generated from IDL files in modules/, netwerk/, parser/, security/, startupcache/, storage/, toolkit/, tools/, uriloader/, widget/, xpcom/ and xpfe/ r=Ehsan
The inclusions were removed with the following very crude script and the
resulting breakage was fixed up by hand. The manual fixups did either
revert the changes done by the script, replace a generic header with a more
specific one or replace a header with a forward declaration.

find . -name "*.idl" | grep -v web-platform | grep -v third_party | while read path; do
    interfaces=$(grep "^\(class\|interface\).*:.*" "$path" | cut -d' ' -f2)
    if [ -n "$interfaces" ]; then
        if [[ "$interfaces" == *$'\n'* ]]; then
          regexp="\("
          for i in $interfaces; do regexp="$regexp$i\|"; done
          regexp="${regexp%%\\\|}\)"
        else
          regexp="$interfaces"
        fi
        interface=$(basename "$path")
        rg -l "#include.*${interface%%.idl}.h" . | while read path2; do
            hits=$(grep -v "#include.*${interface%%.idl}.h" "$path2" | grep -c "$regexp" )
            if [ $hits -eq 0 ]; then
                echo "Removing ${interface} from ${path2}"
                grep -v "#include.*${interface%%.idl}.h" "$path2" > "$path2".tmp
                mv -f "$path2".tmp "$path2"
            fi
        done
    fi
done

Differential Revision: https://phabricator.services.mozilla.com/D55444

--HG--
extra : moz-landing-system : lando
2019-12-06 09:17:57 +00:00

396 lines
11 KiB
C++

/* 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 "TestCommon.h"
#include "gtest/gtest.h"
#include "nsIUDPSocket.h"
#include "nsISocketTransport.h"
#include "nsIOutputStream.h"
#include "nsINetAddr.h"
#include "nsITimer.h"
#include "nsContentUtils.h"
#include "mozilla/net/DNS.h"
#include "prerror.h"
#define REQUEST 0x68656c6f
#define RESPONSE 0x6f6c6568
#define MULTICAST_TIMEOUT 2000
enum TestPhase { TEST_OUTPUT_STREAM, TEST_SEND_API, TEST_MULTICAST, TEST_NONE };
static TestPhase phase = TEST_NONE;
static bool CheckMessageContent(nsIUDPMessage* aMessage,
uint32_t aExpectedContent) {
nsCString data;
aMessage->GetData(data);
const char* buffer = data.get();
uint32_t len = data.Length();
FallibleTArray<uint8_t>& rawData = aMessage->GetDataAsTArray();
uint32_t rawLen = rawData.Length();
if (len != rawLen) {
ADD_FAILURE() << "Raw data length " << rawLen
<< " does not match String data length " << len;
return false;
}
for (uint32_t i = 0; i < len; i++) {
if (buffer[i] != rawData[i]) {
ADD_FAILURE();
return false;
}
}
uint32_t input = 0;
for (uint32_t i = 0; i < len; i++) {
input += buffer[i] << (8 * i);
}
if (len != sizeof(uint32_t)) {
ADD_FAILURE() << "Message length mismatch, expected " << sizeof(uint32_t)
<< " got " << len;
return false;
}
if (input != aExpectedContent) {
ADD_FAILURE() << "Message content mismatch, expected 0x" << std::hex
<< aExpectedContent << " got 0x" << input;
return false;
}
return true;
}
/*
* UDPClientListener: listens for incomming UDP packets
*/
class UDPClientListener : public nsIUDPSocketListener {
protected:
virtual ~UDPClientListener();
public:
explicit UDPClientListener(WaitForCondition* waiter) : mWaiter(waiter) {}
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIUDPSOCKETLISTENER
nsresult mResult = NS_ERROR_FAILURE;
RefPtr<WaitForCondition> mWaiter;
};
NS_IMPL_ISUPPORTS(UDPClientListener, nsIUDPSocketListener)
UDPClientListener::~UDPClientListener() = default;
NS_IMETHODIMP
UDPClientListener::OnPacketReceived(nsIUDPSocket* socket,
nsIUDPMessage* message) {
mResult = NS_OK;
uint16_t port;
nsCString ip;
nsCOMPtr<nsINetAddr> fromAddr;
message->GetFromAddr(getter_AddRefs(fromAddr));
fromAddr->GetPort(&port);
fromAddr->GetAddress(ip);
if (TEST_SEND_API == phase && CheckMessageContent(message, REQUEST)) {
uint32_t count;
nsTArray<uint8_t> data;
const uint32_t dataBuffer = RESPONSE;
data.AppendElements((const uint8_t*)&dataBuffer, sizeof(uint32_t));
mResult = socket->SendWithAddr(fromAddr, data, &count);
if (mResult == NS_OK && count == sizeof(uint32_t)) {
SUCCEED();
} else {
ADD_FAILURE();
}
return NS_OK;
} else if (TEST_OUTPUT_STREAM != phase ||
!CheckMessageContent(message, RESPONSE)) {
mResult = NS_ERROR_FAILURE;
}
// Notify thread
mWaiter->Notify();
return NS_OK;
}
NS_IMETHODIMP
UDPClientListener::OnStopListening(nsIUDPSocket*, nsresult) {
mWaiter->Notify();
return NS_OK;
}
/*
* UDPServerListener: listens for incomming UDP packets
*/
class UDPServerListener : public nsIUDPSocketListener {
protected:
virtual ~UDPServerListener();
public:
explicit UDPServerListener(WaitForCondition* waiter) : mWaiter(waiter) {}
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIUDPSOCKETLISTENER
nsresult mResult = NS_ERROR_FAILURE;
RefPtr<WaitForCondition> mWaiter;
};
NS_IMPL_ISUPPORTS(UDPServerListener, nsIUDPSocketListener)
UDPServerListener::~UDPServerListener() = default;
NS_IMETHODIMP
UDPServerListener::OnPacketReceived(nsIUDPSocket* socket,
nsIUDPMessage* message) {
mResult = NS_OK;
uint16_t port;
nsCString ip;
nsCOMPtr<nsINetAddr> fromAddr;
message->GetFromAddr(getter_AddRefs(fromAddr));
fromAddr->GetPort(&port);
fromAddr->GetAddress(ip);
SUCCEED();
if (TEST_OUTPUT_STREAM == phase && CheckMessageContent(message, REQUEST)) {
nsCOMPtr<nsIOutputStream> outstream;
message->GetOutputStream(getter_AddRefs(outstream));
uint32_t count;
const uint32_t data = RESPONSE;
mResult = outstream->Write((const char*)&data, sizeof(uint32_t), &count);
if (mResult == NS_OK && count == sizeof(uint32_t)) {
SUCCEED();
} else {
ADD_FAILURE();
}
return NS_OK;
} else if (TEST_MULTICAST == phase && CheckMessageContent(message, REQUEST)) {
mResult = NS_OK;
} else if (TEST_SEND_API != phase ||
!CheckMessageContent(message, RESPONSE)) {
mResult = NS_ERROR_FAILURE;
}
// Notify thread
mWaiter->Notify();
return NS_OK;
}
NS_IMETHODIMP
UDPServerListener::OnStopListening(nsIUDPSocket*, nsresult) {
mWaiter->Notify();
return NS_OK;
}
/**
* Multicast timer callback: detects delivery failure
*/
class MulticastTimerCallback : public nsITimerCallback {
protected:
virtual ~MulticastTimerCallback();
public:
explicit MulticastTimerCallback(WaitForCondition* waiter)
: mResult(NS_ERROR_NOT_INITIALIZED), mWaiter(waiter) {}
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSITIMERCALLBACK
nsresult mResult;
RefPtr<WaitForCondition> mWaiter;
};
NS_IMPL_ISUPPORTS(MulticastTimerCallback, nsITimerCallback)
MulticastTimerCallback::~MulticastTimerCallback() = default;
NS_IMETHODIMP
MulticastTimerCallback::Notify(nsITimer* timer) {
if (TEST_MULTICAST != phase) {
return NS_OK;
}
// Multicast ping failed
printf("Multicast ping timeout expired\n");
mResult = NS_ERROR_FAILURE;
mWaiter->Notify();
return NS_OK;
}
/**** Main ****/
TEST(TestUDPSocket, TestUDPSocketMain)
{
nsresult rv;
// Create UDPSocket
nsCOMPtr<nsIUDPSocket> server, client;
server = do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
ASSERT_TRUE(NS_SUCCEEDED(rv));
client = do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
ASSERT_TRUE(NS_SUCCEEDED(rv));
RefPtr<WaitForCondition> waiter = new WaitForCondition();
// Create UDPServerListener to process UDP packets
RefPtr<UDPServerListener> serverListener = new UDPServerListener(waiter);
nsCOMPtr<nsIPrincipal> systemPrincipal = nsContentUtils::GetSystemPrincipal();
// Bind server socket to 0.0.0.0
rv = server->Init(0, false, systemPrincipal, true, 0);
ASSERT_TRUE(NS_SUCCEEDED(rv));
int32_t serverPort;
server->GetPort(&serverPort);
server->AsyncListen(serverListener);
// Bind clinet on arbitrary port
RefPtr<UDPClientListener> clientListener = new UDPClientListener(waiter);
client->Init(0, false, systemPrincipal, true, 0);
client->AsyncListen(clientListener);
// Write data to server
uint32_t count;
nsTArray<uint8_t> data;
const uint32_t dataBuffer = REQUEST;
data.AppendElements((const uint8_t*)&dataBuffer, sizeof(uint32_t));
phase = TEST_OUTPUT_STREAM;
rv = client->Send(NS_LITERAL_CSTRING("127.0.0.1"), serverPort, data, &count);
ASSERT_TRUE(NS_SUCCEEDED(rv));
EXPECT_EQ(count, sizeof(uint32_t));
// Wait for server
waiter->Wait(1);
ASSERT_TRUE(NS_SUCCEEDED(serverListener->mResult));
// Read response from server
ASSERT_TRUE(NS_SUCCEEDED(clientListener->mResult));
mozilla::net::NetAddr clientAddr;
rv = client->GetAddress(&clientAddr);
ASSERT_TRUE(NS_SUCCEEDED(rv));
// The client address is 0.0.0.0, but Windows won't receive packets there, so
// use 127.0.0.1 explicitly
clientAddr.inet.ip = PR_htonl(127 << 24 | 1);
phase = TEST_SEND_API;
rv = server->SendWithAddress(&clientAddr, data, &count);
ASSERT_TRUE(NS_SUCCEEDED(rv));
EXPECT_EQ(count, sizeof(uint32_t));
// Wait for server
waiter->Wait(1);
ASSERT_TRUE(NS_SUCCEEDED(serverListener->mResult));
// Read response from server
ASSERT_TRUE(NS_SUCCEEDED(clientListener->mResult));
// Setup timer to detect multicast failure
nsCOMPtr<nsITimer> timer = NS_NewTimer();
ASSERT_TRUE(timer);
RefPtr<MulticastTimerCallback> timerCb = new MulticastTimerCallback(waiter);
// Join multicast group
printf("Joining multicast group\n");
phase = TEST_MULTICAST;
mozilla::net::NetAddr multicastAddr;
multicastAddr.inet.family = AF_INET;
multicastAddr.inet.ip = PR_htonl(224 << 24 | 255);
multicastAddr.inet.port = PR_htons(serverPort);
rv = server->JoinMulticastAddr(multicastAddr, nullptr);
ASSERT_TRUE(NS_SUCCEEDED(rv));
// Send multicast ping
timerCb->mResult = NS_OK;
timer->InitWithCallback(timerCb, MULTICAST_TIMEOUT, nsITimer::TYPE_ONE_SHOT);
rv = client->SendWithAddress(&multicastAddr, data, &count);
ASSERT_TRUE(NS_SUCCEEDED(rv));
EXPECT_EQ(count, sizeof(uint32_t));
// Wait for server to receive successfully
waiter->Wait(1);
ASSERT_TRUE(NS_SUCCEEDED(serverListener->mResult));
ASSERT_TRUE(NS_SUCCEEDED(timerCb->mResult));
timer->Cancel();
// Disable multicast loopback
printf("Disable multicast loopback\n");
client->SetMulticastLoopback(false);
server->SetMulticastLoopback(false);
// Send multicast ping
timerCb->mResult = NS_OK;
timer->InitWithCallback(timerCb, MULTICAST_TIMEOUT, nsITimer::TYPE_ONE_SHOT);
rv = client->SendWithAddress(&multicastAddr, data, &count);
ASSERT_TRUE(NS_SUCCEEDED(rv));
EXPECT_EQ(count, sizeof(uint32_t));
// Wait for server to fail to receive
waiter->Wait(1);
ASSERT_FALSE(NS_SUCCEEDED(timerCb->mResult));
timer->Cancel();
// Reset state
client->SetMulticastLoopback(true);
server->SetMulticastLoopback(true);
// Change multicast interface
mozilla::net::NetAddr loopbackAddr;
loopbackAddr.inet.family = AF_INET;
loopbackAddr.inet.ip = PR_htonl(INADDR_LOOPBACK);
client->SetMulticastInterfaceAddr(loopbackAddr);
// Send multicast ping
timerCb->mResult = NS_OK;
timer->InitWithCallback(timerCb, MULTICAST_TIMEOUT, nsITimer::TYPE_ONE_SHOT);
rv = client->SendWithAddress(&multicastAddr, data, &count);
ASSERT_TRUE(NS_SUCCEEDED(rv));
EXPECT_EQ(count, sizeof(uint32_t));
// Wait for server to fail to receive
waiter->Wait(1);
ASSERT_FALSE(NS_SUCCEEDED(timerCb->mResult));
timer->Cancel();
// Reset state
mozilla::net::NetAddr anyAddr;
anyAddr.inet.family = AF_INET;
anyAddr.inet.ip = PR_htonl(INADDR_ANY);
client->SetMulticastInterfaceAddr(anyAddr);
// Leave multicast group
rv = server->LeaveMulticastAddr(multicastAddr, nullptr);
ASSERT_TRUE(NS_SUCCEEDED(rv));
// Send multicast ping
timerCb->mResult = NS_OK;
timer->InitWithCallback(timerCb, MULTICAST_TIMEOUT, nsITimer::TYPE_ONE_SHOT);
rv = client->SendWithAddress(&multicastAddr, data, &count);
ASSERT_TRUE(NS_SUCCEEDED(rv));
EXPECT_EQ(count, sizeof(uint32_t));
// Wait for server to fail to receive
waiter->Wait(1);
ASSERT_FALSE(NS_SUCCEEDED(timerCb->mResult));
timer->Cancel();
goto close; // suppress warning about unused label
close:
// Close server
server->Close();
client->Close();
// Wait for client and server to see closing
waiter->Wait(2);
}