Backed out changeset 88fbb17e3c20 (bug 1865637) for causing animation related mochite...
[gecko.git] / netwerk / test / gtest / TestBind.cpp
blob371a09fdab62c56d9b4324f032a2376ac64ce317
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "TestCommon.h"
6 #include "gtest/gtest.h"
7 #include "mozilla/gtest/MozAssertions.h"
8 #include "nsISocketTransportService.h"
9 #include "nsISocketTransport.h"
10 #include "nsIServerSocket.h"
11 #include "nsIAsyncInputStream.h"
12 #include "mozilla/net/DNS.h"
13 #include "prerror.h"
14 #include "../../base/nsSocketTransportService2.h"
15 #include "nsComponentManagerUtils.h"
16 #include "nsServiceManagerUtils.h"
18 using namespace mozilla::net;
19 using namespace mozilla;
21 class ServerListener : public nsIServerSocketListener {
22 public:
23 NS_DECL_ISUPPORTS
24 NS_DECL_NSISERVERSOCKETLISTENER
26 explicit ServerListener(WaitForCondition* waiter);
28 // Port that is got from server side will be store here.
29 uint32_t mClientPort;
30 bool mFailed;
31 RefPtr<WaitForCondition> mWaiter;
33 private:
34 virtual ~ServerListener();
37 NS_IMPL_ISUPPORTS(ServerListener, nsIServerSocketListener)
39 ServerListener::ServerListener(WaitForCondition* waiter)
40 : mClientPort(-1), mFailed(false), mWaiter(waiter) {}
42 ServerListener::~ServerListener() = default;
44 NS_IMETHODIMP
45 ServerListener::OnSocketAccepted(nsIServerSocket* aServ,
46 nsISocketTransport* aTransport) {
47 // Run on STS thread.
48 NetAddr peerAddr;
49 nsresult rv = aTransport->GetPeerAddr(&peerAddr);
50 if (NS_FAILED(rv)) {
51 mFailed = true;
52 mWaiter->Notify();
53 return NS_OK;
55 mClientPort = PR_ntohs(peerAddr.inet.port);
56 mWaiter->Notify();
57 return NS_OK;
60 NS_IMETHODIMP
61 ServerListener::OnStopListening(nsIServerSocket* aServ, nsresult aStatus) {
62 return NS_OK;
65 class ClientInputCallback : public nsIInputStreamCallback {
66 public:
67 NS_DECL_THREADSAFE_ISUPPORTS
68 NS_DECL_NSIINPUTSTREAMCALLBACK
70 explicit ClientInputCallback(WaitForCondition* waiter);
72 bool mFailed;
73 RefPtr<WaitForCondition> mWaiter;
75 private:
76 virtual ~ClientInputCallback();
79 NS_IMPL_ISUPPORTS(ClientInputCallback, nsIInputStreamCallback)
81 ClientInputCallback::ClientInputCallback(WaitForCondition* waiter)
82 : mFailed(false), mWaiter(waiter) {}
84 ClientInputCallback::~ClientInputCallback() = default;
86 NS_IMETHODIMP
87 ClientInputCallback::OnInputStreamReady(nsIAsyncInputStream* aStream) {
88 // Server doesn't send. That means if we are here, we probably have run into
89 // an error.
90 uint64_t avail;
91 nsresult rv = aStream->Available(&avail);
92 if (NS_FAILED(rv)) {
93 mFailed = true;
95 mWaiter->Notify();
96 return NS_OK;
99 TEST(TestBind, MainTest)
102 // Server side.
104 nsCOMPtr<nsIServerSocket> server =
105 do_CreateInstance("@mozilla.org/network/server-socket;1");
106 ASSERT_TRUE(server);
108 nsresult rv = server->Init(-1, true, -1);
109 ASSERT_NS_SUCCEEDED(rv);
111 int32_t serverPort;
112 rv = server->GetPort(&serverPort);
113 ASSERT_NS_SUCCEEDED(rv);
115 RefPtr<WaitForCondition> waiter = new WaitForCondition();
117 // Listening.
118 RefPtr<ServerListener> serverListener = new ServerListener(waiter);
119 rv = server->AsyncListen(serverListener);
120 ASSERT_NS_SUCCEEDED(rv);
123 // Client side
125 uint32_t bindingPort = 20000;
126 nsCOMPtr<nsISocketTransportService> service =
127 do_GetService("@mozilla.org/network/socket-transport-service;1", &rv);
128 ASSERT_NS_SUCCEEDED(rv);
130 nsCOMPtr<nsIInputStream> inputStream;
131 RefPtr<ClientInputCallback> clientCallback;
133 auto* sts = gSocketTransportService;
134 ASSERT_TRUE(sts);
135 for (int32_t tried = 0; tried < 100; tried++) {
136 NS_DispatchAndSpinEventLoopUntilComplete(
137 "test"_ns, sts, NS_NewRunnableFunction("test", [&]() {
138 nsCOMPtr<nsISocketTransport> client;
139 rv = service->CreateTransport(nsTArray<nsCString>(), "127.0.0.1"_ns,
140 serverPort, nullptr, nullptr,
141 getter_AddRefs(client));
142 ASSERT_NS_SUCCEEDED(rv);
144 // Bind to a port. It's possible that we are binding to a port
145 // that is currently in use. If we failed to bind, we try next
146 // port.
147 NetAddr bindingAddr;
148 bindingAddr.inet.family = AF_INET;
149 bindingAddr.inet.ip = 0;
150 bindingAddr.inet.port = PR_htons(bindingPort);
151 rv = client->Bind(&bindingAddr);
152 ASSERT_NS_SUCCEEDED(rv);
154 // Open IO streams, to make client SocketTransport connect to
155 // server.
156 clientCallback = new ClientInputCallback(waiter);
157 rv = client->OpenInputStream(nsITransport::OPEN_UNBUFFERED, 0, 0,
158 getter_AddRefs(inputStream));
159 ASSERT_NS_SUCCEEDED(rv);
161 nsCOMPtr<nsIAsyncInputStream> asyncInputStream =
162 do_QueryInterface(inputStream);
163 rv = asyncInputStream->AsyncWait(clientCallback, 0, 0, nullptr);
164 }));
166 // Wait for server's response or callback of input stream.
167 waiter->Wait(1);
168 if (clientCallback->mFailed) {
169 // if client received error, we likely have bound a port that is
170 // in use. we can try another port.
171 bindingPort++;
172 } else {
173 // We are unlocked by server side, leave the loop and check
174 // result.
175 break;
179 ASSERT_FALSE(serverListener->mFailed);
180 ASSERT_EQ(serverListener->mClientPort, bindingPort);
182 inputStream->Close();
183 waiter->Wait(1);
184 ASSERT_TRUE(clientCallback->mFailed);
186 server->Close();