/src/mozilla-central/media/mtransport/test_nr_socket.h
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 | | */ |
8 | | |
9 | | /* |
10 | | Based partially on 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 | | |
81 | | // Original author: bcampen@mozilla.com [:bwc] |
82 | | |
83 | | #ifndef test_nr_socket__ |
84 | | #define test_nr_socket__ |
85 | | |
86 | | extern "C" { |
87 | | #include "transport_addr.h" |
88 | | } |
89 | | |
90 | | #include "nr_socket_prsock.h" |
91 | | |
92 | | extern "C" { |
93 | | #include "nr_socket.h" |
94 | | } |
95 | | |
96 | | #include <set> |
97 | | #include <vector> |
98 | | #include <map> |
99 | | #include <list> |
100 | | #include <string> |
101 | | |
102 | | #include "mozilla/UniquePtr.h" |
103 | | #include "prinrval.h" |
104 | | #include "mediapacket.h" |
105 | | |
106 | | namespace mozilla { |
107 | | |
108 | | class TestNrSocket; |
109 | | |
110 | | /** |
111 | | * A group of TestNrSockets that behave as if they were behind the same NAT. |
112 | | * @note We deliberately avoid addref/release of TestNrSocket here to avoid |
113 | | * masking lifetime errors elsewhere. |
114 | | */ |
115 | | class TestNat { |
116 | | public: |
117 | | |
118 | | /** |
119 | | * This allows TestNat traffic to be passively inspected. |
120 | | * If a non-zero (error) value is returned, the packet will be dropped, |
121 | | * allowing for tests to extend how packet manipulation is done by |
122 | | * TestNat with having to modify TestNat itself. |
123 | | */ |
124 | | class NatDelegate { |
125 | | public: |
126 | | virtual int on_read(TestNat *nat, void *buf, size_t maxlen, size_t *len) = 0; |
127 | | virtual int on_sendto(TestNat *nat, const void *msg, size_t len, |
128 | | int flags, nr_transport_addr *to) = 0; |
129 | | virtual int on_write(TestNat *nat, const void *msg, size_t len, size_t *written) = 0; |
130 | | }; |
131 | | |
132 | | typedef enum { |
133 | | /** For mapping, one port is used for all destinations. |
134 | | * For filtering, allow any external address/port. */ |
135 | | ENDPOINT_INDEPENDENT, |
136 | | |
137 | | /** For mapping, one port for each destination address (for any port). |
138 | | * For filtering, allow incoming traffic from addresses that outgoing |
139 | | * traffic has been sent to. */ |
140 | | ADDRESS_DEPENDENT, |
141 | | |
142 | | /** For mapping, one port for each destination address/port. |
143 | | * For filtering, allow incoming traffic only from addresses/ports that |
144 | | * outgoing traffic has been sent to. */ |
145 | | PORT_DEPENDENT, |
146 | | } NatBehavior; |
147 | | |
148 | | TestNat() : |
149 | | enabled_(false), |
150 | | filtering_type_(ENDPOINT_INDEPENDENT), |
151 | | mapping_type_(ENDPOINT_INDEPENDENT), |
152 | | mapping_timeout_(30000), |
153 | | allow_hairpinning_(false), |
154 | | refresh_on_ingress_(false), |
155 | | block_udp_(false), |
156 | | block_stun_(false), |
157 | | block_tcp_(false), |
158 | | delay_stun_resp_ms_(0), |
159 | | nat_delegate_(nullptr), |
160 | 0 | sockets_() {} |
161 | | |
162 | | bool has_port_mappings() const; |
163 | | |
164 | | // Helps determine whether we're hairpinning |
165 | | bool is_my_external_tuple(const nr_transport_addr &addr) const; |
166 | | bool is_an_internal_tuple(const nr_transport_addr &addr) const; |
167 | | |
168 | | int create_socket_factory(nr_socket_factory **factorypp); |
169 | | |
170 | 0 | void insert_socket(TestNrSocket *socket) { |
171 | 0 | sockets_.insert(socket); |
172 | 0 | } |
173 | | |
174 | 0 | void erase_socket(TestNrSocket *socket) { |
175 | 0 | sockets_.erase(socket); |
176 | 0 | } |
177 | | |
178 | | NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestNat); |
179 | | |
180 | | static NatBehavior ToNatBehavior(const std::string& type); |
181 | | |
182 | | bool enabled_; |
183 | | TestNat::NatBehavior filtering_type_; |
184 | | TestNat::NatBehavior mapping_type_; |
185 | | uint32_t mapping_timeout_; |
186 | | bool allow_hairpinning_; |
187 | | bool refresh_on_ingress_; |
188 | | bool block_udp_; |
189 | | bool block_stun_; |
190 | | bool block_tcp_; |
191 | | /* Note: this can only delay a single response so far (bug 1253657) */ |
192 | | uint32_t delay_stun_resp_ms_; |
193 | | |
194 | | NatDelegate* nat_delegate_; |
195 | | |
196 | | private: |
197 | | std::set<TestNrSocket*> sockets_; |
198 | | |
199 | 0 | ~TestNat(){} |
200 | | }; |
201 | | |
202 | | /** |
203 | | * Subclass of NrSocketBase that can simulate things like being behind a NAT, |
204 | | * packet loss, latency, packet rewriting, etc. Also exposes some stuff that |
205 | | * assists in diagnostics. |
206 | | * This is accomplished by wrapping an "internal" socket (that handles traffic |
207 | | * behind the NAT), and a collection of "external" sockets (that handle traffic |
208 | | * into/out of the NAT) |
209 | | */ |
210 | | class TestNrSocket : public NrSocketBase { |
211 | | public: |
212 | | explicit TestNrSocket(TestNat *nat); |
213 | | |
214 | | bool has_port_mappings() const; |
215 | | bool is_my_external_tuple(const nr_transport_addr &addr) const; |
216 | | |
217 | | // Overrides of NrSocketBase |
218 | | int create(nr_transport_addr *addr) override; |
219 | | int sendto(const void *msg, size_t len, |
220 | | int flags, nr_transport_addr *to) override; |
221 | | int recvfrom(void * buf, size_t maxlen, |
222 | | size_t *len, int flags, |
223 | | nr_transport_addr *from) override; |
224 | | int getaddr(nr_transport_addr *addrp) override; |
225 | | void close() override; |
226 | | int connect(nr_transport_addr *addr) override; |
227 | | int write(const void *msg, size_t len, size_t *written) override; |
228 | | int read(void *buf, size_t maxlen, size_t *len) override; |
229 | | |
230 | | int listen(int backlog) override; |
231 | | int accept(nr_transport_addr *addrp, nr_socket **sockp) override; |
232 | | int async_wait(int how, NR_async_cb cb, void *cb_arg, |
233 | | char *function, int line) override; |
234 | | int cancel(int how) override; |
235 | | |
236 | | // Need override since this is virtual in NrSocketBase |
237 | | NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestNrSocket, override) |
238 | | |
239 | | private: |
240 | | virtual ~TestNrSocket(); |
241 | | |
242 | | class UdpPacket { |
243 | | public: |
244 | | UdpPacket(const void *msg, size_t len, const nr_transport_addr &addr) : |
245 | 0 | buffer_(new MediaPacket) { |
246 | 0 | buffer_->Copy(static_cast<const uint8_t*>(msg), len); |
247 | 0 | // TODO(bug 1170299): Remove const_cast when no longer necessary |
248 | 0 | nr_transport_addr_copy(&remote_address_, |
249 | 0 | const_cast<nr_transport_addr*>(&addr)); |
250 | 0 | } |
251 | | |
252 | | nr_transport_addr remote_address_; |
253 | | UniquePtr<MediaPacket> buffer_; |
254 | | |
255 | | NS_INLINE_DECL_THREADSAFE_REFCOUNTING(UdpPacket); |
256 | | private: |
257 | 0 | ~UdpPacket(){} |
258 | | }; |
259 | | |
260 | | class PortMapping { |
261 | | public: |
262 | | PortMapping(const nr_transport_addr &remote_address, |
263 | | const RefPtr<NrSocketBase> &external_socket); |
264 | | |
265 | | int sendto(const void *msg, size_t len, const nr_transport_addr &to); |
266 | | int async_wait(int how, NR_async_cb cb, void *cb_arg, |
267 | | char *function, int line); |
268 | | int cancel(int how); |
269 | | int send_from_queue(); |
270 | | NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PortMapping); |
271 | | |
272 | | PRIntervalTime last_used_; |
273 | | RefPtr<NrSocketBase> external_socket_; |
274 | | // For non-symmetric, most of the data here doesn't matter |
275 | | nr_transport_addr remote_address_; |
276 | | |
277 | | private: |
278 | 0 | ~PortMapping() { |
279 | 0 | external_socket_->close(); |
280 | 0 | } |
281 | | |
282 | | // If external_socket_ returns E_WOULDBLOCK, we don't want to propagate |
283 | | // that to the code using the TestNrSocket. We can also perhaps use this |
284 | | // to help simulate things like latency. |
285 | | std::list<RefPtr<UdpPacket>> send_queue_; |
286 | | }; |
287 | | |
288 | | struct DeferredPacket { |
289 | | DeferredPacket(TestNrSocket *sock, |
290 | | const void *data, size_t len, |
291 | | int flags, |
292 | | nr_transport_addr *addr, |
293 | | RefPtr<NrSocketBase> internal_socket) : |
294 | | socket_(sock), |
295 | | buffer_(), |
296 | | flags_(flags), |
297 | 0 | internal_socket_(internal_socket) { |
298 | 0 | buffer_.Copy(reinterpret_cast<const uint8_t *>(data), len); |
299 | 0 | nr_transport_addr_copy(&to_, addr); |
300 | 0 | } |
301 | | |
302 | | TestNrSocket *socket_; |
303 | | MediaPacket buffer_; |
304 | | int flags_; |
305 | | nr_transport_addr to_; |
306 | | RefPtr<NrSocketBase> internal_socket_; |
307 | | }; |
308 | | |
309 | | bool is_port_mapping_stale(const PortMapping &port_mapping) const; |
310 | | bool allow_ingress(const nr_transport_addr &from, |
311 | | PortMapping **port_mapping_used) const; |
312 | | void destroy_stale_port_mappings(); |
313 | | |
314 | | static void socket_readable_callback(void *real_sock_v, |
315 | | int how, |
316 | | void *test_sock_v); |
317 | | void on_socket_readable(NrSocketBase *external_or_internal_socket); |
318 | | void fire_readable_callback(); |
319 | | |
320 | | static void port_mapping_tcp_passthrough_callback(void *ext_sock_v, |
321 | | int how, |
322 | | void *test_sock_v); |
323 | | void cancel_port_mapping_async_wait(int how); |
324 | | |
325 | | static void port_mapping_writeable_callback(void *ext_sock_v, |
326 | | int how, |
327 | | void *test_sock_v); |
328 | | void write_to_port_mapping(NrSocketBase *external_socket); |
329 | | bool is_tcp_connection_behind_nat() const; |
330 | | |
331 | | PortMapping* get_port_mapping(const nr_transport_addr &remote_addr, |
332 | | TestNat::NatBehavior filter) const; |
333 | | PortMapping* create_port_mapping( |
334 | | const nr_transport_addr &remote_addr, |
335 | | const RefPtr<NrSocketBase> &external_socket) const; |
336 | | RefPtr<NrSocketBase> create_external_socket( |
337 | | const nr_transport_addr &remote_addr) const; |
338 | | |
339 | | static void process_delayed_cb(NR_SOCKET s, int how, void *cb_arg); |
340 | | |
341 | | RefPtr<NrSocketBase> readable_socket_; |
342 | | // The socket for the "internal" address; used to talk to stuff behind the |
343 | | // same nat. |
344 | | RefPtr<NrSocketBase> internal_socket_; |
345 | | RefPtr<TestNat> nat_; |
346 | | bool tls_; |
347 | | // Since our comparison logic is different depending on what kind of NAT |
348 | | // we simulate, and the STL does not make it very easy to switch out the |
349 | | // comparison function at runtime, and these lists are going to be very |
350 | | // small anyway, we just brute-force it. |
351 | | std::list<RefPtr<PortMapping>> port_mappings_; |
352 | | |
353 | | void *timer_handle_; |
354 | | }; |
355 | | |
356 | | } // namespace mozilla |
357 | | |
358 | | #endif // test_nr_socket__ |
359 | | |