Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/test/TestBind.cpp
Line
Count
Source (jump to first uncovered line)
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/. */
4
5
#include "TestCommon.h"
6
#include "gtest/gtest.h"
7
#include "nsISocketTransportService.h"
8
#include "nsISocketTransport.h"
9
#include "nsIServerSocket.h"
10
#include "nsIAsyncInputStream.h"
11
#include "nsINetAddr.h"
12
#include "mozilla/net/DNS.h"
13
#include "prerror.h"
14
#include "nsComponentManagerUtils.h"
15
#include "nsServiceManagerUtils.h"
16
17
using namespace mozilla::net;
18
using namespace mozilla;
19
20
class ServerListener: public nsIServerSocketListener
21
{
22
public:
23
  NS_DECL_ISUPPORTS
24
  NS_DECL_NSISERVERSOCKETLISTENER
25
26
  explicit ServerListener(WaitForCondition* waiter);
27
28
  // Port that is got from server side will be store here.
29
  uint32_t mClientPort;
30
  bool mFailed;
31
  RefPtr<WaitForCondition> mWaiter;
32
private:
33
  virtual ~ServerListener();
34
};
35
36
NS_IMPL_ISUPPORTS(ServerListener, nsIServerSocketListener)
37
38
ServerListener::ServerListener(WaitForCondition* waiter)
39
  : mClientPort(-1)
40
  , mFailed(false)
41
  , mWaiter(waiter)
42
0
{
43
0
}
44
45
0
ServerListener::~ServerListener() = default;
46
47
NS_IMETHODIMP
48
ServerListener::OnSocketAccepted(nsIServerSocket *aServ,
49
                                 nsISocketTransport *aTransport)
50
0
{
51
0
  // Run on STS thread.
52
0
  NetAddr peerAddr;
53
0
  nsresult rv = aTransport->GetPeerAddr(&peerAddr);
54
0
  if (NS_FAILED(rv)) {
55
0
    mFailed = true;
56
0
    mWaiter->Notify();
57
0
    return NS_OK;
58
0
  }
59
0
  mClientPort = PR_ntohs(peerAddr.inet.port);
60
0
  mWaiter->Notify();
61
0
  return NS_OK;
62
0
}
63
64
NS_IMETHODIMP
65
ServerListener::OnStopListening(nsIServerSocket *aServ,
66
                                nsresult aStatus)
67
0
{
68
0
  return NS_OK;
69
0
}
70
71
class ClientInputCallback : public nsIInputStreamCallback
72
{
73
public:
74
  NS_DECL_THREADSAFE_ISUPPORTS
75
  NS_DECL_NSIINPUTSTREAMCALLBACK
76
77
  explicit ClientInputCallback(WaitForCondition* waiter);
78
79
  bool mFailed;
80
  RefPtr<WaitForCondition> mWaiter;
81
private:
82
  virtual ~ClientInputCallback();
83
};
84
85
NS_IMPL_ISUPPORTS(ClientInputCallback, nsIInputStreamCallback)
86
87
ClientInputCallback::ClientInputCallback(WaitForCondition* waiter)
88
  : mFailed(false)
89
  , mWaiter(waiter)
90
0
{
91
0
}
92
93
0
ClientInputCallback::~ClientInputCallback() = default;
94
95
NS_IMETHODIMP
96
ClientInputCallback::OnInputStreamReady(nsIAsyncInputStream *aStream)
97
0
{
98
0
  // Server doesn't send. That means if we are here, we probably have run into
99
0
  // an error.
100
0
  uint64_t avail;
101
0
  nsresult rv = aStream->Available(&avail);
102
0
  if (NS_FAILED(rv)) {
103
0
    mFailed = true;
104
0
  }
105
0
  mWaiter->Notify();
106
0
  return NS_OK;
107
0
}
108
109
TEST(TestBind, MainTest)
110
0
{
111
0
  //
112
0
  // Server side.
113
0
  //
114
0
  nsCOMPtr<nsIServerSocket> server = do_CreateInstance("@mozilla.org/network/server-socket;1");
115
0
  ASSERT_TRUE(server);
116
0
117
0
  nsresult rv = server->Init(-1, true, -1);
118
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
119
0
120
0
  int32_t serverPort;
121
0
  rv = server->GetPort(&serverPort);
122
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
123
0
124
0
  RefPtr<WaitForCondition> waiter = new WaitForCondition();
125
0
126
0
  // Listening.
127
0
  RefPtr<ServerListener> serverListener = new ServerListener(waiter);
128
0
  rv = server->AsyncListen(serverListener);
129
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
130
0
131
0
  //
132
0
  // Client side
133
0
  //
134
0
  uint32_t bindingPort = 20000;
135
0
  nsCOMPtr<nsISocketTransportService> sts =
136
0
    do_GetService("@mozilla.org/network/socket-transport-service;1", &rv);
137
0
  ASSERT_TRUE(NS_SUCCEEDED(rv));
138
0
139
0
  nsCOMPtr<nsIInputStream> inputStream;
140
0
  RefPtr<ClientInputCallback> clientCallback;
141
0
142
0
  for (int32_t tried = 0; tried < 100; tried++) {
143
0
    nsCOMPtr<nsISocketTransport> client;
144
0
    rv = sts->CreateTransport(nullptr, 0, NS_LITERAL_CSTRING("127.0.0.1"),
145
0
                              serverPort, nullptr, getter_AddRefs(client));
146
0
    ASSERT_TRUE(NS_SUCCEEDED(rv));
147
0
148
0
    // Bind to a port. It's possible that we are binding to a port that is
149
0
    // currently in use. If we failed to bind, we try next port.
150
0
    NetAddr bindingAddr;
151
0
    bindingAddr.inet.family = AF_INET;
152
0
    bindingAddr.inet.ip = 0;
153
0
    bindingAddr.inet.port = PR_htons(bindingPort);
154
0
    rv = client->Bind(&bindingAddr);
155
0
    ASSERT_TRUE(NS_SUCCEEDED(rv));
156
0
157
0
    // Open IO streams, to make client SocketTransport connect to server.
158
0
    clientCallback = new ClientInputCallback(waiter);
159
0
    rv = client->OpenInputStream(nsITransport::OPEN_UNBUFFERED,
160
0
                                 0, 0, getter_AddRefs(inputStream));
161
0
    ASSERT_TRUE(NS_SUCCEEDED(rv));
162
0
163
0
    nsCOMPtr<nsIAsyncInputStream> asyncInputStream = do_QueryInterface(inputStream);
164
0
    rv = asyncInputStream->AsyncWait(clientCallback, 0, 0, nullptr);
165
0
166
0
    // Wait for server's response or callback of input stream.
167
0
    waiter->Wait(1);
168
0
    if (clientCallback->mFailed) {
169
0
      // if client received error, we likely have bound a port that is in use.
170
0
      // we can try another port.
171
0
      bindingPort++;
172
0
    } else {
173
0
      // We are unlocked by server side, leave the loop and check result.
174
0
      break;
175
0
    }
176
0
  }
177
0
178
0
  ASSERT_FALSE(serverListener->mFailed);
179
0
  ASSERT_EQ(serverListener->mClientPort, bindingPort);
180
0
181
0
  inputStream->Close();
182
0
  waiter->Wait(1);
183
0
  ASSERT_TRUE(clientCallback->mFailed);
184
0
185
0
  server->Close();
186
0
}