|
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 "TestHarness.h" |
|
7 #include "nsIUDPSocket.h" |
|
8 #include "nsISocketTransportService.h" |
|
9 #include "nsISocketTransport.h" |
|
10 #include "nsIOutputStream.h" |
|
11 #include "nsIInputStream.h" |
|
12 #include "nsINetAddr.h" |
|
13 #include "mozilla/net/DNS.h" |
|
14 #include "prerror.h" |
|
15 |
|
16 #define REQUEST 0x68656c6f |
|
17 #define RESPONSE 0x6f6c6568 |
|
18 |
|
19 #define EXPECT_SUCCESS(rv, ...) \ |
|
20 PR_BEGIN_MACRO \ |
|
21 if (NS_FAILED(rv)) { \ |
|
22 fail(__VA_ARGS__); \ |
|
23 return false; \ |
|
24 } \ |
|
25 PR_END_MACRO |
|
26 |
|
27 |
|
28 #define EXPECT_FAILURE(rv, ...) \ |
|
29 PR_BEGIN_MACRO \ |
|
30 if (NS_SUCCEEDED(rv)) { \ |
|
31 fail(__VA_ARGS__); \ |
|
32 return false; \ |
|
33 } \ |
|
34 PR_END_MACRO |
|
35 |
|
36 #define REQUIRE_EQUAL(a, b, ...) \ |
|
37 PR_BEGIN_MACRO \ |
|
38 if (a != b) { \ |
|
39 fail(__VA_ARGS__); \ |
|
40 return false; \ |
|
41 } \ |
|
42 PR_END_MACRO |
|
43 |
|
44 enum TestPhase { |
|
45 TEST_OUTPUT_STREAM, |
|
46 TEST_SEND_API, |
|
47 TEST_NONE |
|
48 }; |
|
49 |
|
50 static TestPhase phase = TEST_NONE; |
|
51 |
|
52 static bool CheckMessageContent(nsIUDPMessage *aMessage, uint32_t aExpectedContent) |
|
53 { |
|
54 nsCString data; |
|
55 aMessage->GetData(data); |
|
56 |
|
57 const char* buffer = data.get(); |
|
58 uint32_t len = data.Length(); |
|
59 |
|
60 FallibleTArray<uint8_t>& rawData = aMessage->GetDataAsTArray(); |
|
61 uint32_t rawLen = rawData.Length(); |
|
62 |
|
63 if (len != rawLen) { |
|
64 fail("Raw data length(%d) do not matches String data length(%d).", rawLen, len); |
|
65 return false; |
|
66 } |
|
67 |
|
68 for (uint32_t i = 0; i < len; i++) { |
|
69 if (buffer[i] != rawData[i]) { |
|
70 fail("Raw data(%s) do not matches String data(%s)", rawData.Elements() ,buffer); |
|
71 return false; |
|
72 } |
|
73 } |
|
74 |
|
75 uint32_t input = 0; |
|
76 for (uint32_t i = 0; i < len; i++) { |
|
77 input += buffer[i] << (8 * i); |
|
78 } |
|
79 |
|
80 if (len != sizeof(uint32_t) || input != aExpectedContent) |
|
81 { |
|
82 fail("Request 0x%x received, expected 0x%x", input, aExpectedContent); |
|
83 return false; |
|
84 } else { |
|
85 passed("Request 0x%x received as expected", input); |
|
86 return true; |
|
87 } |
|
88 } |
|
89 |
|
90 /* |
|
91 * UDPClientListener: listens for incomming UDP packets |
|
92 */ |
|
93 class UDPClientListener : public nsIUDPSocketListener |
|
94 { |
|
95 public: |
|
96 NS_DECL_THREADSAFE_ISUPPORTS |
|
97 NS_DECL_NSIUDPSOCKETLISTENER |
|
98 virtual ~UDPClientListener(); |
|
99 nsresult mResult; |
|
100 }; |
|
101 |
|
102 NS_IMPL_ISUPPORTS(UDPClientListener, nsIUDPSocketListener) |
|
103 |
|
104 UDPClientListener::~UDPClientListener() |
|
105 { |
|
106 } |
|
107 |
|
108 NS_IMETHODIMP |
|
109 UDPClientListener::OnPacketReceived(nsIUDPSocket* socket, nsIUDPMessage* message) |
|
110 { |
|
111 mResult = NS_OK; |
|
112 |
|
113 uint16_t port; |
|
114 nsCString ip; |
|
115 nsCOMPtr<nsINetAddr> fromAddr; |
|
116 message->GetFromAddr(getter_AddRefs(fromAddr)); |
|
117 fromAddr->GetPort(&port); |
|
118 fromAddr->GetAddress(ip); |
|
119 passed("Packet received on client from %s:%d", ip.get(), port); |
|
120 |
|
121 if (TEST_SEND_API == phase && CheckMessageContent(message, REQUEST)) { |
|
122 uint32_t count; |
|
123 const uint32_t data = RESPONSE; |
|
124 printf("*** Attempting to write response 0x%x to server by SendWithAddr...\n", RESPONSE); |
|
125 mResult = socket->SendWithAddr(fromAddr, (const uint8_t*)&data, |
|
126 sizeof(uint32_t), &count); |
|
127 if (mResult == NS_OK && count == sizeof(uint32_t)) { |
|
128 passed("Response written"); |
|
129 } else { |
|
130 fail("Response written"); |
|
131 } |
|
132 return NS_OK; |
|
133 } else if (TEST_OUTPUT_STREAM != phase || !CheckMessageContent(message, RESPONSE)) { |
|
134 mResult = NS_ERROR_FAILURE; |
|
135 } |
|
136 |
|
137 // Notify thread |
|
138 QuitPumpingEvents(); |
|
139 return NS_OK; |
|
140 } |
|
141 |
|
142 NS_IMETHODIMP |
|
143 UDPClientListener::OnStopListening(nsIUDPSocket*, nsresult) |
|
144 { |
|
145 QuitPumpingEvents(); |
|
146 return NS_OK; |
|
147 } |
|
148 |
|
149 /* |
|
150 * UDPServerListener: listens for incomming UDP packets |
|
151 */ |
|
152 class UDPServerListener : public nsIUDPSocketListener |
|
153 { |
|
154 public: |
|
155 NS_DECL_THREADSAFE_ISUPPORTS |
|
156 NS_DECL_NSIUDPSOCKETLISTENER |
|
157 |
|
158 virtual ~UDPServerListener(); |
|
159 |
|
160 nsresult mResult; |
|
161 }; |
|
162 |
|
163 NS_IMPL_ISUPPORTS(UDPServerListener, nsIUDPSocketListener) |
|
164 |
|
165 UDPServerListener::~UDPServerListener() |
|
166 { |
|
167 } |
|
168 |
|
169 NS_IMETHODIMP |
|
170 UDPServerListener::OnPacketReceived(nsIUDPSocket* socket, nsIUDPMessage* message) |
|
171 { |
|
172 mResult = NS_OK; |
|
173 |
|
174 uint16_t port; |
|
175 nsCString ip; |
|
176 nsCOMPtr<nsINetAddr> fromAddr; |
|
177 message->GetFromAddr(getter_AddRefs(fromAddr)); |
|
178 fromAddr->GetPort(&port); |
|
179 fromAddr->GetAddress(ip); |
|
180 passed("Packet received on server from %s:%d", ip.get(), port); |
|
181 |
|
182 if (TEST_OUTPUT_STREAM == phase && CheckMessageContent(message, REQUEST)) |
|
183 { |
|
184 nsCOMPtr<nsIOutputStream> outstream; |
|
185 message->GetOutputStream(getter_AddRefs(outstream)); |
|
186 |
|
187 uint32_t count; |
|
188 const uint32_t data = RESPONSE; |
|
189 printf("*** Attempting to write response 0x%x to client by OutputStream...\n", RESPONSE); |
|
190 mResult = outstream->Write((const char*)&data, sizeof(uint32_t), &count); |
|
191 |
|
192 if (mResult == NS_OK && count == sizeof(uint32_t)) { |
|
193 passed("Response written"); |
|
194 } else { |
|
195 fail("Response written"); |
|
196 } |
|
197 return NS_OK; |
|
198 } else if (TEST_SEND_API != phase || !CheckMessageContent(message, RESPONSE)) { |
|
199 mResult = NS_ERROR_FAILURE; |
|
200 } |
|
201 |
|
202 // Notify thread |
|
203 QuitPumpingEvents(); |
|
204 return NS_OK; |
|
205 } |
|
206 |
|
207 NS_IMETHODIMP |
|
208 UDPServerListener::OnStopListening(nsIUDPSocket*, nsresult) |
|
209 { |
|
210 QuitPumpingEvents(); |
|
211 return NS_OK; |
|
212 } |
|
213 |
|
214 /**** Main ****/ |
|
215 int |
|
216 main(int32_t argc, char *argv[]) |
|
217 { |
|
218 nsresult rv; |
|
219 ScopedXPCOM xpcom("UDP ServerSocket"); |
|
220 if (xpcom.failed()) |
|
221 return -1; |
|
222 |
|
223 // Create UDPSocket |
|
224 nsCOMPtr<nsIUDPSocket> server, client; |
|
225 server = do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv); |
|
226 NS_ENSURE_SUCCESS(rv, -1); |
|
227 client = do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv); |
|
228 NS_ENSURE_SUCCESS(rv, -1); |
|
229 |
|
230 // Create UDPServerListener to process UDP packets |
|
231 nsRefPtr<UDPServerListener> serverListener = new UDPServerListener(); |
|
232 |
|
233 // Bind server socket to 127.0.0.1 |
|
234 rv = server->Init(0, true); |
|
235 NS_ENSURE_SUCCESS(rv, -1); |
|
236 int32_t serverPort; |
|
237 server->GetPort(&serverPort); |
|
238 server->AsyncListen(serverListener); |
|
239 |
|
240 // Bind clinet on arbitrary port |
|
241 nsRefPtr<UDPClientListener> clientListener = new UDPClientListener(); |
|
242 client->Init(0, true); |
|
243 client->AsyncListen(clientListener); |
|
244 |
|
245 // Write data to server |
|
246 uint32_t count; |
|
247 const uint32_t data = REQUEST; |
|
248 |
|
249 phase = TEST_OUTPUT_STREAM; |
|
250 rv = client->Send(NS_LITERAL_CSTRING("127.0.0.1"), serverPort, (uint8_t*)&data, sizeof(uint32_t), &count); |
|
251 NS_ENSURE_SUCCESS(rv, -1); |
|
252 REQUIRE_EQUAL(count, sizeof(uint32_t), "Error"); |
|
253 passed("Request written by Send"); |
|
254 |
|
255 // Wait for server |
|
256 PumpEvents(); |
|
257 NS_ENSURE_SUCCESS(serverListener->mResult, -1); |
|
258 |
|
259 // Read response from server |
|
260 NS_ENSURE_SUCCESS(clientListener->mResult, -1); |
|
261 |
|
262 mozilla::net::NetAddr clientAddr; |
|
263 rv = client->GetAddress(&clientAddr); |
|
264 NS_ENSURE_SUCCESS(rv, -1); |
|
265 |
|
266 phase = TEST_SEND_API; |
|
267 rv = server->SendWithAddress(&clientAddr, (uint8_t*)&data, sizeof(uint32_t), &count); |
|
268 NS_ENSURE_SUCCESS(rv, -1); |
|
269 REQUIRE_EQUAL(count, sizeof(uint32_t), "Error"); |
|
270 passed("Request written by SendWithAddress"); |
|
271 |
|
272 // Wait for server |
|
273 PumpEvents(); |
|
274 NS_ENSURE_SUCCESS(serverListener->mResult, -1); |
|
275 |
|
276 // Read response from server |
|
277 NS_ENSURE_SUCCESS(clientListener->mResult, -1); |
|
278 |
|
279 // Close server |
|
280 printf("*** Attempting to close server ...\n"); |
|
281 server->Close(); |
|
282 client->Close(); |
|
283 PumpEvents(); |
|
284 passed("Server closed"); |
|
285 |
|
286 return 0; // failure is a non-zero return |
|
287 } |