2014-10-07 13:25:54 +04:00
|
|
|
/* 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"
|
2016-11-29 21:53:48 +03:00
|
|
|
#include "gtest/gtest.h"
|
2014-10-07 13:25:54 +04:00
|
|
|
#include "nsISocketTransportService.h"
|
|
|
|
#include "nsISocketTransport.h"
|
|
|
|
#include "nsIServerSocket.h"
|
|
|
|
#include "nsIAsyncInputStream.h"
|
|
|
|
#include "mozilla/net/DNS.h"
|
|
|
|
#include "prerror.h"
|
2016-11-29 21:53:48 +03:00
|
|
|
#include "nsComponentManagerUtils.h"
|
|
|
|
#include "nsServiceManagerUtils.h"
|
2014-10-07 13:25:54 +04:00
|
|
|
|
|
|
|
using namespace mozilla::net;
|
|
|
|
using namespace mozilla;
|
|
|
|
|
|
|
|
class ServerListener : public nsIServerSocketListener {
|
|
|
|
public:
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
NS_DECL_NSISERVERSOCKETLISTENER
|
|
|
|
|
2016-11-29 21:53:48 +03:00
|
|
|
explicit ServerListener(WaitForCondition* waiter);
|
2014-10-07 13:25:54 +04:00
|
|
|
|
|
|
|
// Port that is got from server side will be store here.
|
|
|
|
uint32_t mClientPort;
|
|
|
|
bool mFailed;
|
2016-11-29 21:53:48 +03:00
|
|
|
RefPtr<WaitForCondition> mWaiter;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-10-07 13:25:54 +04:00
|
|
|
private:
|
|
|
|
virtual ~ServerListener();
|
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS(ServerListener, nsIServerSocketListener)
|
|
|
|
|
2016-11-29 21:53:48 +03:00
|
|
|
ServerListener::ServerListener(WaitForCondition* waiter)
|
2014-10-07 13:25:54 +04:00
|
|
|
: mClientPort(-1), mFailed(false), mWaiter(waiter) {}
|
|
|
|
|
2016-11-01 15:44:09 +03:00
|
|
|
ServerListener::~ServerListener() = default;
|
2014-10-07 13:25:54 +04:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
ServerListener::OnSocketAccepted(nsIServerSocket* aServ,
|
|
|
|
nsISocketTransport* aTransport) {
|
|
|
|
// Run on STS thread.
|
|
|
|
NetAddr peerAddr;
|
|
|
|
nsresult rv = aTransport->GetPeerAddr(&peerAddr);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
mFailed = true;
|
2016-11-29 21:53:48 +03:00
|
|
|
mWaiter->Notify();
|
2014-10-07 13:25:54 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
mClientPort = PR_ntohs(peerAddr.inet.port);
|
2016-11-29 21:53:48 +03:00
|
|
|
mWaiter->Notify();
|
2014-10-07 13:25:54 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
ServerListener::OnStopListening(nsIServerSocket* aServ, nsresult aStatus) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
class ClientInputCallback : public nsIInputStreamCallback {
|
|
|
|
public:
|
|
|
|
NS_DECL_THREADSAFE_ISUPPORTS
|
|
|
|
NS_DECL_NSIINPUTSTREAMCALLBACK
|
|
|
|
|
2016-11-29 21:53:48 +03:00
|
|
|
explicit ClientInputCallback(WaitForCondition* waiter);
|
2014-10-07 13:25:54 +04:00
|
|
|
|
|
|
|
bool mFailed;
|
2016-11-29 21:53:48 +03:00
|
|
|
RefPtr<WaitForCondition> mWaiter;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-10-07 13:25:54 +04:00
|
|
|
private:
|
|
|
|
virtual ~ClientInputCallback();
|
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS(ClientInputCallback, nsIInputStreamCallback)
|
|
|
|
|
2016-11-29 21:53:48 +03:00
|
|
|
ClientInputCallback::ClientInputCallback(WaitForCondition* waiter)
|
|
|
|
: mFailed(false), mWaiter(waiter) {}
|
2014-10-07 13:25:54 +04:00
|
|
|
|
2016-11-01 15:44:09 +03:00
|
|
|
ClientInputCallback::~ClientInputCallback() = default;
|
2014-10-07 13:25:54 +04:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
ClientInputCallback::OnInputStreamReady(nsIAsyncInputStream* aStream) {
|
|
|
|
// Server doesn't send. That means if we are here, we probably have run into
|
|
|
|
// an error.
|
|
|
|
uint64_t avail;
|
|
|
|
nsresult rv = aStream->Available(&avail);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
mFailed = true;
|
|
|
|
}
|
2016-11-29 21:53:48 +03:00
|
|
|
mWaiter->Notify();
|
2014-10-07 13:25:54 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2019-04-06 00:42:17 +03:00
|
|
|
TEST(TestBind, MainTest)
|
|
|
|
{
|
2014-10-07 13:25:54 +04:00
|
|
|
//
|
|
|
|
// Server side.
|
|
|
|
//
|
|
|
|
nsCOMPtr<nsIServerSocket> server =
|
|
|
|
do_CreateInstance("@mozilla.org/network/server-socket;1");
|
2016-11-29 21:53:48 +03:00
|
|
|
ASSERT_TRUE(server);
|
2014-10-07 13:25:54 +04:00
|
|
|
|
|
|
|
nsresult rv = server->Init(-1, true, -1);
|
2016-11-29 21:53:48 +03:00
|
|
|
ASSERT_TRUE(NS_SUCCEEDED(rv));
|
2014-10-07 13:25:54 +04:00
|
|
|
|
|
|
|
int32_t serverPort;
|
|
|
|
rv = server->GetPort(&serverPort);
|
2016-11-29 21:53:48 +03:00
|
|
|
ASSERT_TRUE(NS_SUCCEEDED(rv));
|
|
|
|
|
|
|
|
RefPtr<WaitForCondition> waiter = new WaitForCondition();
|
2014-10-07 13:25:54 +04:00
|
|
|
|
|
|
|
// Listening.
|
2016-11-29 21:53:48 +03:00
|
|
|
RefPtr<ServerListener> serverListener = new ServerListener(waiter);
|
2014-10-07 13:25:54 +04:00
|
|
|
rv = server->AsyncListen(serverListener);
|
2016-11-29 21:53:48 +03:00
|
|
|
ASSERT_TRUE(NS_SUCCEEDED(rv));
|
2014-10-07 13:25:54 +04:00
|
|
|
|
|
|
|
//
|
|
|
|
// Client side
|
|
|
|
//
|
|
|
|
uint32_t bindingPort = 20000;
|
|
|
|
nsCOMPtr<nsISocketTransportService> sts =
|
|
|
|
do_GetService("@mozilla.org/network/socket-transport-service;1", &rv);
|
2016-11-29 21:53:48 +03:00
|
|
|
ASSERT_TRUE(NS_SUCCEEDED(rv));
|
|
|
|
|
|
|
|
nsCOMPtr<nsIInputStream> inputStream;
|
|
|
|
RefPtr<ClientInputCallback> clientCallback;
|
2014-10-07 13:25:54 +04:00
|
|
|
|
|
|
|
for (int32_t tried = 0; tried < 100; tried++) {
|
|
|
|
nsCOMPtr<nsISocketTransport> client;
|
2019-06-13 07:21:32 +03:00
|
|
|
rv = sts->CreateTransport(nsTArray<nsCString>(),
|
|
|
|
NS_LITERAL_CSTRING("127.0.0.1"), serverPort,
|
|
|
|
nullptr, getter_AddRefs(client));
|
2016-11-29 21:53:48 +03:00
|
|
|
ASSERT_TRUE(NS_SUCCEEDED(rv));
|
2014-10-07 13:25:54 +04:00
|
|
|
|
|
|
|
// Bind to a port. It's possible that we are binding to a port that is
|
|
|
|
// currently in use. If we failed to bind, we try next port.
|
|
|
|
NetAddr bindingAddr;
|
|
|
|
bindingAddr.inet.family = AF_INET;
|
|
|
|
bindingAddr.inet.ip = 0;
|
|
|
|
bindingAddr.inet.port = PR_htons(bindingPort);
|
|
|
|
rv = client->Bind(&bindingAddr);
|
2016-11-29 21:53:48 +03:00
|
|
|
ASSERT_TRUE(NS_SUCCEEDED(rv));
|
2014-10-07 13:25:54 +04:00
|
|
|
|
|
|
|
// Open IO streams, to make client SocketTransport connect to server.
|
2016-11-29 21:53:48 +03:00
|
|
|
clientCallback = new ClientInputCallback(waiter);
|
2014-10-07 13:25:54 +04:00
|
|
|
rv = client->OpenInputStream(nsITransport::OPEN_UNBUFFERED, 0, 0,
|
|
|
|
getter_AddRefs(inputStream));
|
2016-11-29 21:53:48 +03:00
|
|
|
ASSERT_TRUE(NS_SUCCEEDED(rv));
|
|
|
|
|
2014-10-07 13:25:54 +04:00
|
|
|
nsCOMPtr<nsIAsyncInputStream> asyncInputStream =
|
|
|
|
do_QueryInterface(inputStream);
|
|
|
|
rv = asyncInputStream->AsyncWait(clientCallback, 0, 0, nullptr);
|
|
|
|
|
|
|
|
// Wait for server's response or callback of input stream.
|
2016-11-29 21:53:48 +03:00
|
|
|
waiter->Wait(1);
|
2014-10-07 13:25:54 +04:00
|
|
|
if (clientCallback->mFailed) {
|
|
|
|
// if client received error, we likely have bound a port that is in use.
|
|
|
|
// we can try another port.
|
|
|
|
bindingPort++;
|
|
|
|
} else {
|
|
|
|
// We are unlocked by server side, leave the loop and check result.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-29 21:53:48 +03:00
|
|
|
ASSERT_FALSE(serverListener->mFailed);
|
|
|
|
ASSERT_EQ(serverListener->mClientPort, bindingPort);
|
|
|
|
|
|
|
|
inputStream->Close();
|
|
|
|
waiter->Wait(1);
|
|
|
|
ASSERT_TRUE(clientCallback->mFailed);
|
|
|
|
|
|
|
|
server->Close();
|
2014-10-07 13:25:54 +04:00
|
|
|
}
|