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"
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
{
24 NS_DECL_NSISERVERSOCKETLISTENER
26 explicit ServerListener(WaitForCondition
* waiter
);
28 // Port that is got from server side will be store here.
31 RefPtr
<WaitForCondition
> mWaiter
;
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;
45 ServerListener::OnSocketAccepted(nsIServerSocket
* aServ
,
46 nsISocketTransport
* aTransport
) {
49 nsresult rv
= aTransport
->GetPeerAddr(&peerAddr
);
55 mClientPort
= PR_ntohs(peerAddr
.inet
.port
);
61 ServerListener::OnStopListening(nsIServerSocket
* aServ
, nsresult aStatus
) {
65 class ClientInputCallback
: public nsIInputStreamCallback
{
67 NS_DECL_THREADSAFE_ISUPPORTS
68 NS_DECL_NSIINPUTSTREAMCALLBACK
70 explicit ClientInputCallback(WaitForCondition
* waiter
);
73 RefPtr
<WaitForCondition
> mWaiter
;
76 virtual ~ClientInputCallback();
79 NS_IMPL_ISUPPORTS(ClientInputCallback
, nsIInputStreamCallback
)
81 ClientInputCallback::ClientInputCallback(WaitForCondition
* waiter
)
82 : mFailed(false), mWaiter(waiter
) {}
84 ClientInputCallback::~ClientInputCallback() = default;
87 ClientInputCallback::OnInputStreamReady(nsIAsyncInputStream
* aStream
) {
88 // Server doesn't send. That means if we are here, we probably have run into
91 nsresult rv
= aStream
->Available(&avail
);
99 TEST(TestBind
, MainTest
)
104 nsCOMPtr
<nsIServerSocket
> server
=
105 do_CreateInstance("@mozilla.org/network/server-socket;1");
108 nsresult rv
= server
->Init(-1, true, -1);
109 ASSERT_NS_SUCCEEDED(rv
);
112 rv
= server
->GetPort(&serverPort
);
113 ASSERT_NS_SUCCEEDED(rv
);
115 RefPtr
<WaitForCondition
> waiter
= new WaitForCondition();
118 RefPtr
<ServerListener
> serverListener
= new ServerListener(waiter
);
119 rv
= server
->AsyncListen(serverListener
);
120 ASSERT_NS_SUCCEEDED(rv
);
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
;
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
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
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);
166 // Wait for server's response or callback of input stream.
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.
173 // We are unlocked by server side, leave the loop and check
179 ASSERT_FALSE(serverListener
->mFailed
);
180 ASSERT_EQ(serverListener
->mClientPort
, bindingPort
);
182 inputStream
->Close();
184 ASSERT_TRUE(clientCallback
->mFailed
);