/src/mozilla-central/media/mtransport/test/stunserver.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
5 | | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | // Original author: ekr@rtfm.com |
8 | | |
9 | | /* |
10 | | Original code from nICEr and nrappkit. |
11 | | |
12 | | nICEr copyright: |
13 | | |
14 | | Copyright (c) 2007, Adobe Systems, Incorporated |
15 | | All rights reserved. |
16 | | |
17 | | Redistribution and use in source and binary forms, with or without |
18 | | modification, are permitted provided that the following conditions are |
19 | | met: |
20 | | |
21 | | * Redistributions of source code must retain the above copyright |
22 | | notice, this list of conditions and the following disclaimer. |
23 | | |
24 | | * Redistributions in binary form must reproduce the above copyright |
25 | | notice, this list of conditions and the following disclaimer in the |
26 | | documentation and/or other materials provided with the distribution. |
27 | | |
28 | | * Neither the name of Adobe Systems, Network Resonance nor the names of its |
29 | | contributors may be used to endorse or promote products derived from |
30 | | this software without specific prior written permission. |
31 | | |
32 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
33 | | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
34 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
35 | | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
36 | | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
37 | | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
38 | | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
39 | | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
40 | | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
41 | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
42 | | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
43 | | |
44 | | |
45 | | nrappkit copyright: |
46 | | |
47 | | Copyright (C) 2001-2003, Network Resonance, Inc. |
48 | | Copyright (C) 2006, Network Resonance, Inc. |
49 | | All Rights Reserved |
50 | | |
51 | | Redistribution and use in source and binary forms, with or without |
52 | | modification, are permitted provided that the following conditions |
53 | | are met: |
54 | | |
55 | | 1. Redistributions of source code must retain the above copyright |
56 | | notice, this list of conditions and the following disclaimer. |
57 | | 2. Redistributions in binary form must reproduce the above copyright |
58 | | notice, this list of conditions and the following disclaimer in the |
59 | | documentation and/or other materials provided with the distribution. |
60 | | 3. Neither the name of Network Resonance, Inc. nor the name of any |
61 | | contributors to this software may be used to endorse or promote |
62 | | products derived from this software without specific prior written |
63 | | permission. |
64 | | |
65 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' |
66 | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
67 | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
68 | | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
69 | | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
70 | | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
71 | | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
72 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
73 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
74 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
75 | | POSSIBILITY OF SUCH DAMAGE. |
76 | | |
77 | | |
78 | | ekr@rtfm.com Thu Dec 20 20:14:49 2001 |
79 | | */ |
80 | | #include "logging.h" |
81 | | #include "mozilla/UniquePtr.h" |
82 | | #include "mozilla/Unused.h" |
83 | | #include "mediapacket.h" |
84 | | |
85 | | // mozilla/utils.h defines this as well |
86 | | #ifdef UNIMPLEMENTED |
87 | | #undef UNIMPLEMENTED |
88 | | #endif |
89 | | |
90 | | extern "C" { |
91 | | #include "nr_api.h" |
92 | | #include "async_wait.h" |
93 | | #include "async_timer.h" |
94 | | #include "nr_socket.h" |
95 | | #include "nr_socket_local.h" |
96 | | #include "transport_addr.h" |
97 | | #include "addrs.h" |
98 | | #include "local_addr.h" |
99 | | #include "stun_util.h" |
100 | | #include "registry.h" |
101 | | #include "nr_socket_buffered_stun.h" |
102 | | } |
103 | | |
104 | | #include "stunserver.h" |
105 | | |
106 | | #include <string> |
107 | | |
108 | | MOZ_MTLOG_MODULE("stunserver"); |
109 | | |
110 | | namespace mozilla { |
111 | | |
112 | | // Wrapper nr_socket which allows us to lie to the stun server about the |
113 | | // IP address. |
114 | | struct nr_socket_wrapped { |
115 | | nr_socket *sock_; |
116 | | nr_transport_addr addr_; |
117 | | }; |
118 | | |
119 | 0 | static int nr_socket_wrapped_destroy(void **objp) { |
120 | 0 | if (!objp || !*objp) |
121 | 0 | return 0; |
122 | 0 | |
123 | 0 | nr_socket_wrapped *wrapped = static_cast<nr_socket_wrapped *>(*objp); |
124 | 0 | *objp = nullptr; |
125 | 0 |
|
126 | 0 | delete wrapped; |
127 | 0 |
|
128 | 0 | return 0; |
129 | 0 | } |
130 | | |
131 | | static int nr_socket_wrapped_sendto(void *obj, const void *msg, size_t len, int flags, |
132 | 0 | nr_transport_addr *addr) { |
133 | 0 | nr_socket_wrapped *wrapped = static_cast<nr_socket_wrapped *>(obj); |
134 | 0 |
|
135 | 0 | return nr_socket_sendto(wrapped->sock_, msg, len, flags, &wrapped->addr_); |
136 | 0 | } |
137 | | |
138 | | static int nr_socket_wrapped_recvfrom(void *obj, void * restrict buf, size_t maxlen, |
139 | 0 | size_t *len, int flags, nr_transport_addr *addr) { |
140 | 0 | nr_socket_wrapped *wrapped = static_cast<nr_socket_wrapped *>(obj); |
141 | 0 |
|
142 | 0 | return nr_socket_recvfrom(wrapped->sock_, buf, maxlen, len, flags, addr); |
143 | 0 | } |
144 | | |
145 | 0 | static int nr_socket_wrapped_getfd(void *obj, NR_SOCKET *fd) { |
146 | 0 | nr_socket_wrapped *wrapped = static_cast<nr_socket_wrapped *>(obj); |
147 | 0 |
|
148 | 0 | return nr_socket_getfd(wrapped->sock_, fd); |
149 | 0 | } |
150 | | |
151 | 0 | static int nr_socket_wrapped_getaddr(void *obj, nr_transport_addr *addrp) { |
152 | 0 | nr_socket_wrapped *wrapped = static_cast<nr_socket_wrapped *>(obj); |
153 | 0 |
|
154 | 0 | return nr_socket_getaddr(wrapped->sock_, addrp); |
155 | 0 | } |
156 | | |
157 | 0 | static int nr_socket_wrapped_close(void *obj) { |
158 | 0 | MOZ_CRASH(); |
159 | 0 | } |
160 | | |
161 | 0 | static int nr_socket_wrapped_set_send_addr(nr_socket *sock, nr_transport_addr *addr) { |
162 | 0 | nr_socket_wrapped *wrapped = static_cast<nr_socket_wrapped *>(sock->obj); |
163 | 0 |
|
164 | 0 | return nr_transport_addr_copy(&wrapped->addr_, addr); |
165 | 0 | } |
166 | | |
167 | | static nr_socket_vtbl nr_socket_wrapped_vtbl = { |
168 | | 2, |
169 | | nr_socket_wrapped_destroy, |
170 | | nr_socket_wrapped_sendto, |
171 | | nr_socket_wrapped_recvfrom, |
172 | | nr_socket_wrapped_getfd, |
173 | | nr_socket_wrapped_getaddr, |
174 | | nullptr, |
175 | | nullptr, |
176 | | nullptr, |
177 | | nr_socket_wrapped_close, |
178 | | nullptr, |
179 | | nullptr |
180 | | }; |
181 | | |
182 | 0 | int nr_socket_wrapped_create(nr_socket *inner, nr_socket **outp) { |
183 | 0 | auto wrapped = MakeUnique<nr_socket_wrapped>(); |
184 | 0 |
|
185 | 0 | wrapped->sock_ = inner; |
186 | 0 |
|
187 | 0 | int r = nr_socket_create_int(wrapped.get(), &nr_socket_wrapped_vtbl, outp); |
188 | 0 | if (r) |
189 | 0 | return r; |
190 | 0 | |
191 | 0 | Unused << wrapped.release(); |
192 | 0 | return 0; |
193 | 0 | } |
194 | | |
195 | | |
196 | | // Instance static. |
197 | | // Note: Calling Create() at static init time is not going to be safe, since |
198 | | // we have no reason to expect this will be initted to a nullptr yet. |
199 | | TestStunServer *TestStunServer::instance; |
200 | | TestStunTcpServer *TestStunTcpServer::instance; |
201 | | TestStunServer *TestStunServer::instance6; |
202 | | TestStunTcpServer *TestStunTcpServer::instance6; |
203 | | uint16_t TestStunServer::instance_port = 3478; |
204 | | uint16_t TestStunTcpServer::instance_port = 3478; |
205 | | |
206 | 0 | TestStunServer::~TestStunServer() { |
207 | 0 | // TODO(ekr@rtfm.com): Put this on the right thread. |
208 | 0 |
|
209 | 0 | // Unhook callback from our listen socket. |
210 | 0 | if (listen_sock_) { |
211 | 0 | NR_SOCKET fd; |
212 | 0 | if (!nr_socket_getfd(listen_sock_, &fd)) { |
213 | 0 | NR_ASYNC_CANCEL(fd, NR_ASYNC_WAIT_READ); |
214 | 0 | } |
215 | 0 | } |
216 | 0 |
|
217 | 0 | // Free up stun context and network resources |
218 | 0 | nr_stun_server_ctx_destroy(&stun_server_); |
219 | 0 | nr_socket_destroy(&listen_sock_); |
220 | 0 | nr_socket_destroy(&send_sock_); |
221 | 0 |
|
222 | 0 | // Make sure we aren't still waiting on a deferred response timer to pop |
223 | 0 | if (timer_handle_) |
224 | 0 | NR_async_timer_cancel(timer_handle_); |
225 | 0 |
|
226 | 0 | delete response_addr_; |
227 | 0 | } |
228 | | |
229 | 0 | int TestStunServer::SetInternalPort(nr_local_addr *addr, uint16_t port) { |
230 | 0 | if (nr_transport_addr_set_port(&addr->addr, port)) { |
231 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't set port"); |
232 | 0 | return R_INTERNAL; |
233 | 0 | } |
234 | 0 |
|
235 | 0 | if (nr_transport_addr_fmt_addr_string(&addr->addr)) { |
236 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't re-set addr string"); |
237 | 0 | return R_INTERNAL; |
238 | 0 | } |
239 | 0 |
|
240 | 0 | return 0; |
241 | 0 | } |
242 | | |
243 | 0 | int TestStunServer::TryOpenListenSocket(nr_local_addr *addr, uint16_t port) { |
244 | 0 |
|
245 | 0 | int r = SetInternalPort(addr, port); |
246 | 0 |
|
247 | 0 | if (r) |
248 | 0 | return r; |
249 | 0 | |
250 | 0 | if (nr_socket_local_create(nullptr, &addr->addr, &listen_sock_)) { |
251 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't create listen socket"); |
252 | 0 | return R_ALREADY; |
253 | 0 | } |
254 | 0 |
|
255 | 0 | return 0; |
256 | 0 | } |
257 | | |
258 | 0 | int TestStunServer::Initialize(int address_family) { |
259 | 0 | static const size_t max_addrs = 100; |
260 | 0 | nr_local_addr addrs[max_addrs]; |
261 | 0 | int addr_ct; |
262 | 0 | int r; |
263 | 0 | int i; |
264 | 0 |
|
265 | 0 | r = nr_stun_find_local_addresses(addrs, max_addrs, &addr_ct); |
266 | 0 | if (r) { |
267 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't retrieve addresses"); |
268 | 0 | return R_INTERNAL; |
269 | 0 | } |
270 | 0 |
|
271 | 0 | // removes duplicates and, based on prefs, loopback and link_local addrs |
272 | 0 | r = nr_stun_filter_local_addresses(addrs, &addr_ct); |
273 | 0 | if (r) { |
274 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't filter addresses"); |
275 | 0 | return R_INTERNAL; |
276 | 0 | } |
277 | 0 |
|
278 | 0 | if (addr_ct < 1) { |
279 | 0 | MOZ_MTLOG(ML_ERROR, "No local addresses"); |
280 | 0 | return R_INTERNAL; |
281 | 0 | } |
282 | 0 |
|
283 | 0 | for (i = 0; i < addr_ct; ++i) { |
284 | 0 | if (addrs[i].addr.addr->sa_family == address_family) { |
285 | 0 | break; |
286 | 0 | } |
287 | 0 | } |
288 | 0 |
|
289 | 0 | if (i == addr_ct) { |
290 | 0 | MOZ_MTLOG(ML_ERROR, "No local addresses of the configured IP version"); |
291 | 0 | return R_INTERNAL; |
292 | 0 | } |
293 | 0 |
|
294 | 0 | int tries = 100; |
295 | 0 | while (tries--) { |
296 | 0 | // Bind on configured port (default 3478) |
297 | 0 | r = TryOpenListenSocket(&addrs[i], instance_port); |
298 | 0 | // We interpret R_ALREADY to mean the addr is probably in use. Try another. |
299 | 0 | // Otherwise, it either worked or it didn't, and we check below. |
300 | 0 | if (r != R_ALREADY) { |
301 | 0 | break; |
302 | 0 | } |
303 | 0 | ++instance_port; |
304 | 0 | } |
305 | 0 |
|
306 | 0 | if (r) { |
307 | 0 | return R_INTERNAL; |
308 | 0 | } |
309 | 0 |
|
310 | 0 | r = nr_socket_wrapped_create(listen_sock_, &send_sock_); |
311 | 0 | if (r) { |
312 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't create send socket"); |
313 | 0 | return R_INTERNAL; |
314 | 0 | } |
315 | 0 |
|
316 | 0 | r = nr_stun_server_ctx_create(const_cast<char *>("Test STUN server"), |
317 | 0 | send_sock_, |
318 | 0 | &stun_server_); |
319 | 0 | if (r) { |
320 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't create STUN server"); |
321 | 0 | return R_INTERNAL; |
322 | 0 | } |
323 | 0 |
|
324 | 0 | // Cache the address and port. |
325 | 0 | char addr_string[INET6_ADDRSTRLEN]; |
326 | 0 | r = nr_transport_addr_get_addrstring(&addrs[i].addr, addr_string, |
327 | 0 | sizeof(addr_string)); |
328 | 0 | if (r) { |
329 | 0 | MOZ_MTLOG(ML_ERROR, "Failed to convert listen addr to a string representation"); |
330 | 0 | return R_INTERNAL; |
331 | 0 | } |
332 | 0 |
|
333 | 0 | listen_addr_ = addr_string; |
334 | 0 | listen_port_ = instance_port; |
335 | 0 |
|
336 | 0 | return 0; |
337 | 0 | } |
338 | | |
339 | 0 | UniquePtr<TestStunServer> TestStunServer::Create(int address_family) { |
340 | 0 | NR_reg_init(NR_REG_MODE_LOCAL); |
341 | 0 |
|
342 | 0 | UniquePtr<TestStunServer> server(new TestStunServer()); |
343 | 0 |
|
344 | 0 | if (server->Initialize(address_family)) |
345 | 0 | return nullptr; |
346 | 0 | |
347 | 0 | NR_SOCKET fd; |
348 | 0 | int r = nr_socket_getfd(server->listen_sock_, &fd); |
349 | 0 | if (r) { |
350 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't get fd"); |
351 | 0 | return nullptr; |
352 | 0 | } |
353 | 0 |
|
354 | 0 | NR_ASYNC_WAIT(fd, NR_ASYNC_WAIT_READ, &TestStunServer::readable_cb, server.get()); |
355 | 0 |
|
356 | 0 | return server; |
357 | 0 | } |
358 | | |
359 | 0 | void TestStunServer::ConfigurePort(uint16_t port) { |
360 | 0 | instance_port = port; |
361 | 0 | } |
362 | | |
363 | 0 | TestStunServer* TestStunServer::GetInstance(int address_family) { |
364 | 0 | switch (address_family) { |
365 | 0 | case AF_INET: |
366 | 0 | if (!instance) |
367 | 0 | instance = Create(address_family).release(); |
368 | 0 |
|
369 | 0 | MOZ_ASSERT(instance); |
370 | 0 | return instance; |
371 | 0 | case AF_INET6: |
372 | 0 | if (!instance6) |
373 | 0 | instance6 = Create(address_family).release(); |
374 | 0 |
|
375 | 0 | return instance6; |
376 | 0 | default: |
377 | 0 | MOZ_CRASH(); |
378 | 0 | } |
379 | 0 | } |
380 | | |
381 | 0 | void TestStunServer::ShutdownInstance() { |
382 | 0 | delete instance; |
383 | 0 | instance = nullptr; |
384 | 0 | delete instance6; |
385 | 0 | instance6 = nullptr; |
386 | 0 | } |
387 | | |
388 | | |
389 | | struct DeferredStunOperation { |
390 | | DeferredStunOperation(TestStunServer *server, |
391 | | const char *data, size_t len, |
392 | | nr_transport_addr *addr, |
393 | | nr_socket *sock) : |
394 | | server_(server), |
395 | | buffer_(), |
396 | 0 | sock_(sock) { |
397 | 0 | buffer_.Copy(reinterpret_cast<const uint8_t *>(data), len); |
398 | 0 | nr_transport_addr_copy(&addr_, addr); |
399 | 0 | } |
400 | | |
401 | | TestStunServer *server_; |
402 | | MediaPacket buffer_; |
403 | | nr_transport_addr addr_; |
404 | | nr_socket *sock_; |
405 | | }; |
406 | | |
407 | 0 | void TestStunServer::Process(const uint8_t *msg, size_t len, nr_transport_addr *addr, nr_socket *sock) { |
408 | 0 |
|
409 | 0 | if (!sock) { |
410 | 0 | sock = send_sock_; |
411 | 0 | } |
412 | 0 |
|
413 | 0 | // Set the wrapped address so that the response goes to the right place. |
414 | 0 | nr_socket_wrapped_set_send_addr(sock, addr); |
415 | 0 |
|
416 | 0 | nr_stun_server_process_request(stun_server_, sock, |
417 | 0 | const_cast<char *>(reinterpret_cast<const char *>(msg)), |
418 | 0 | len, |
419 | 0 | response_addr_ ? |
420 | 0 | response_addr_ : addr, |
421 | 0 | NR_STUN_AUTH_RULE_OPTIONAL); |
422 | 0 | } |
423 | | |
424 | 0 | void TestStunServer::process_cb(NR_SOCKET s, int how, void *cb_arg) { |
425 | 0 | DeferredStunOperation *op = static_cast<DeferredStunOperation *>(cb_arg); |
426 | 0 | op->server_->timer_handle_ = nullptr; |
427 | 0 | op->server_->Process(op->buffer_.data(), op->buffer_.len(), &op->addr_, op->sock_); |
428 | 0 |
|
429 | 0 | delete op; |
430 | 0 | } |
431 | | |
432 | 0 | nr_socket* TestStunServer::GetReceivingSocket(NR_SOCKET s) { |
433 | 0 | return listen_sock_; |
434 | 0 | } |
435 | | |
436 | 0 | nr_socket* TestStunServer::GetSendingSocket(nr_socket *sock) { |
437 | 0 | return send_sock_; |
438 | 0 | } |
439 | | |
440 | 0 | void TestStunServer::readable_cb(NR_SOCKET s, int how, void *cb_arg) { |
441 | 0 | TestStunServer *server = static_cast<TestStunServer*>(cb_arg); |
442 | 0 |
|
443 | 0 | char message[max_stun_message_size]; |
444 | 0 | size_t message_len; |
445 | 0 | nr_transport_addr addr; |
446 | 0 | nr_socket *recv_sock = server->GetReceivingSocket(s); |
447 | 0 | if (!recv_sock) { |
448 | 0 | MOZ_MTLOG(ML_ERROR, "Failed to lookup receiving socket"); |
449 | 0 | return; |
450 | 0 | } |
451 | 0 | nr_socket *send_sock = server->GetSendingSocket(recv_sock); |
452 | 0 |
|
453 | 0 | /* Re-arm. */ |
454 | 0 | NR_ASYNC_WAIT(s, NR_ASYNC_WAIT_READ, &TestStunServer::readable_cb, server); |
455 | 0 |
|
456 | 0 | if (nr_socket_recvfrom(recv_sock, message, sizeof(message), |
457 | 0 | &message_len, 0, &addr)) { |
458 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't read STUN message"); |
459 | 0 | return; |
460 | 0 | } |
461 | 0 |
|
462 | 0 | MOZ_MTLOG(ML_DEBUG, "Received data of length " << message_len); |
463 | 0 |
|
464 | 0 | // If we have initial dropping set, check at this point. |
465 | 0 | std::string key(addr.as_string); |
466 | 0 |
|
467 | 0 | if (server->received_ct_.count(key) == 0) { |
468 | 0 | server->received_ct_[key] = 0; |
469 | 0 | } |
470 | 0 |
|
471 | 0 | ++server->received_ct_[key]; |
472 | 0 |
|
473 | 0 | if (!server->active_ || (server->received_ct_[key] <= server->initial_ct_)) { |
474 | 0 | MOZ_MTLOG(ML_DEBUG, "Dropping message #" |
475 | 0 | << server->received_ct_[key] << " from " << key); |
476 | 0 | return; |
477 | 0 | } |
478 | 0 |
|
479 | 0 | if (server->delay_ms_) { |
480 | 0 | NR_ASYNC_TIMER_SET(server->delay_ms_, |
481 | 0 | process_cb, |
482 | 0 | new DeferredStunOperation( |
483 | 0 | server, |
484 | 0 | message, message_len, |
485 | 0 | &addr, send_sock), |
486 | 0 | &server->timer_handle_); |
487 | 0 | } else { |
488 | 0 | server->Process(reinterpret_cast<const uint8_t *>(message), message_len, |
489 | 0 | &addr, send_sock); |
490 | 0 | } |
491 | 0 | } |
492 | | |
493 | 0 | void TestStunServer::SetActive(bool active) { |
494 | 0 | active_ = active; |
495 | 0 | } |
496 | | |
497 | 0 | void TestStunServer::SetDelay(uint32_t delay_ms) { |
498 | 0 | delay_ms_ = delay_ms; |
499 | 0 | } |
500 | | |
501 | 0 | void TestStunServer::SetDropInitialPackets(uint32_t count) { |
502 | 0 | initial_ct_ = count; |
503 | 0 | } |
504 | | |
505 | 0 | nsresult TestStunServer::SetResponseAddr(nr_transport_addr *addr) { |
506 | 0 | delete response_addr_; |
507 | 0 |
|
508 | 0 | response_addr_ = new nr_transport_addr(); |
509 | 0 |
|
510 | 0 | int r = nr_transport_addr_copy(response_addr_, addr); |
511 | 0 | if (r) |
512 | 0 | return NS_ERROR_FAILURE; |
513 | 0 | |
514 | 0 | return NS_OK; |
515 | 0 | } |
516 | | |
517 | | nsresult TestStunServer::SetResponseAddr(const std::string& addr, |
518 | 0 | uint16_t port) { |
519 | 0 | nr_transport_addr addr2; |
520 | 0 |
|
521 | 0 | int r = nr_str_port_to_transport_addr(addr.c_str(), |
522 | 0 | port, IPPROTO_UDP, |
523 | 0 | &addr2); |
524 | 0 | if (r) |
525 | 0 | return NS_ERROR_FAILURE; |
526 | 0 | |
527 | 0 | return SetResponseAddr(&addr2); |
528 | 0 | } |
529 | | |
530 | 0 | void TestStunServer::Reset() { |
531 | 0 | delay_ms_ = 0; |
532 | 0 | if (timer_handle_) { |
533 | 0 | NR_async_timer_cancel(timer_handle_); |
534 | 0 | timer_handle_ = nullptr; |
535 | 0 | } |
536 | 0 | delete response_addr_; |
537 | 0 | response_addr_ = nullptr; |
538 | 0 | received_ct_.clear(); |
539 | 0 | } |
540 | | |
541 | | |
542 | | // TestStunTcpServer |
543 | | |
544 | 0 | void TestStunTcpServer::ConfigurePort(uint16_t port) { |
545 | 0 | instance_port = port; |
546 | 0 | } |
547 | | |
548 | 0 | TestStunTcpServer* TestStunTcpServer::GetInstance(int address_family) { |
549 | 0 | switch (address_family) { |
550 | 0 | case AF_INET: |
551 | 0 | if (!instance) |
552 | 0 | instance = Create(address_family).release(); |
553 | 0 |
|
554 | 0 | MOZ_ASSERT(instance); |
555 | 0 | return instance; |
556 | 0 | case AF_INET6: |
557 | 0 | if (!instance6) |
558 | 0 | instance6 = Create(address_family).release(); |
559 | 0 |
|
560 | 0 | return instance6; |
561 | 0 | default: |
562 | 0 | MOZ_CRASH(); |
563 | 0 | } |
564 | 0 | } |
565 | | |
566 | 0 | void TestStunTcpServer::ShutdownInstance() { |
567 | 0 | delete instance; |
568 | 0 | instance = nullptr; |
569 | 0 | delete instance6; |
570 | 0 | instance6 = nullptr; |
571 | 0 | } |
572 | | |
573 | 0 | int TestStunTcpServer::TryOpenListenSocket(nr_local_addr *addr, uint16_t port) { |
574 | 0 |
|
575 | 0 | addr->addr.protocol=IPPROTO_TCP; |
576 | 0 |
|
577 | 0 | int r = SetInternalPort(addr, port); |
578 | 0 |
|
579 | 0 | if (r) |
580 | 0 | return r; |
581 | 0 | |
582 | 0 | nr_socket *sock; |
583 | 0 | if (nr_socket_local_create(nullptr, &addr->addr, &sock)) { |
584 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't create listen tcp socket"); |
585 | 0 | return R_ALREADY; |
586 | 0 | } |
587 | 0 |
|
588 | 0 | if (nr_socket_buffered_stun_create(sock, 2048, TURN_TCP_FRAMING, &listen_sock_)) { |
589 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't create listen tcp socket"); |
590 | 0 | return R_ALREADY; |
591 | 0 | } |
592 | 0 |
|
593 | 0 | if(nr_socket_listen(listen_sock_, 10)) { |
594 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't listen on socket"); |
595 | 0 | return R_ALREADY; |
596 | 0 | } |
597 | 0 |
|
598 | 0 | return 0; |
599 | 0 | } |
600 | | |
601 | 0 | nr_socket* TestStunTcpServer::GetReceivingSocket(NR_SOCKET s) { |
602 | 0 | return connections_[s]; |
603 | 0 | } |
604 | | |
605 | 0 | nr_socket* TestStunTcpServer::GetSendingSocket(nr_socket *sock) { |
606 | 0 | return sock; |
607 | 0 | } |
608 | | |
609 | 0 | void TestStunTcpServer::accept_cb(NR_SOCKET s, int how, void *cb_arg) { |
610 | 0 | TestStunTcpServer *server = static_cast<TestStunTcpServer*>(cb_arg); |
611 | 0 | nr_socket *newsock, *bufsock, *wrapsock; |
612 | 0 | nr_transport_addr remote_addr; |
613 | 0 | NR_SOCKET fd; |
614 | 0 |
|
615 | 0 | /* rearm */ |
616 | 0 | NR_ASYNC_WAIT(s, NR_ASYNC_WAIT_READ, &TestStunTcpServer::accept_cb, cb_arg); |
617 | 0 |
|
618 | 0 | /* accept */ |
619 | 0 | if (nr_socket_accept(server->listen_sock_, &remote_addr, &newsock)) { |
620 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't accept incoming tcp connection"); |
621 | 0 | return; |
622 | 0 | } |
623 | 0 |
|
624 | 0 | if(nr_socket_buffered_stun_create(newsock, 2048, TURN_TCP_FRAMING, &bufsock)) { |
625 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't create connected tcp socket"); |
626 | 0 | nr_socket_destroy(&newsock); |
627 | 0 | return; |
628 | 0 | } |
629 | 0 |
|
630 | 0 | nr_socket_buffered_set_connected_to(bufsock, &remote_addr); |
631 | 0 |
|
632 | 0 | if(nr_socket_wrapped_create(bufsock, &wrapsock)) { |
633 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't wrap connected tcp socket"); |
634 | 0 | nr_socket_destroy(&bufsock); |
635 | 0 | return; |
636 | 0 | } |
637 | 0 |
|
638 | 0 | if(nr_socket_getfd(wrapsock, &fd)) { |
639 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't get fd from connected tcp socket"); |
640 | 0 | nr_socket_destroy(&wrapsock); |
641 | 0 | return; |
642 | 0 | } |
643 | 0 |
|
644 | 0 | server->connections_[fd] = wrapsock; |
645 | 0 |
|
646 | 0 | NR_ASYNC_WAIT(fd, NR_ASYNC_WAIT_READ, &TestStunServer::readable_cb, server); |
647 | 0 | } |
648 | | |
649 | 0 | UniquePtr<TestStunTcpServer> TestStunTcpServer::Create(int address_family) { |
650 | 0 | NR_reg_init(NR_REG_MODE_LOCAL); |
651 | 0 |
|
652 | 0 | UniquePtr<TestStunTcpServer> server(new TestStunTcpServer()); |
653 | 0 |
|
654 | 0 | if (server->Initialize(address_family)) { |
655 | 0 | return nullptr; |
656 | 0 | } |
657 | 0 | |
658 | 0 | NR_SOCKET fd; |
659 | 0 | if(nr_socket_getfd(server->listen_sock_, &fd)) { |
660 | 0 | MOZ_MTLOG(ML_ERROR, "Couldn't get tcp fd"); |
661 | 0 | return nullptr; |
662 | 0 | } |
663 | 0 |
|
664 | 0 | NR_ASYNC_WAIT(fd, NR_ASYNC_WAIT_READ, &TestStunTcpServer::accept_cb, server.get()); |
665 | 0 |
|
666 | 0 | return server; |
667 | 0 | } |
668 | | |
669 | 0 | TestStunTcpServer::~TestStunTcpServer() { |
670 | 0 | for (auto it = connections_.begin(); it != connections_.end();) { |
671 | 0 | NR_ASYNC_CANCEL(it->first, NR_ASYNC_WAIT_READ); |
672 | 0 | nr_socket_destroy(&it->second); |
673 | 0 | connections_.erase(it++); |
674 | 0 | } |
675 | 0 | } |
676 | | |
677 | | } // close namespace |