OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "remoting/test/fake_socket_factory.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/callback.h" | |
9 #include "base/location.h" | |
10 #include "base/rand_util.h" | |
11 #include "base/single_thread_task_runner.h" | |
12 #include "base/thread_task_runner_handle.h" | |
13 #include "net/base/io_buffer.h" | |
14 #include "remoting/test/leaky_bucket.h" | |
15 #include "third_party/libjingle/source/talk/base/asyncpacketsocket.h" | |
16 | |
17 namespace remoting { | |
18 | |
19 namespace { | |
20 | |
21 double GetNormalRandom(double average, double variance) { | |
22 // Based on Box-Muller transform, see | |
23 // http://en.wikipedia.org/wiki/Box_Muller_transform . | |
24 return average + | |
25 variance * sqrt(-2.0 * log(1.0 - base::RandDouble())) * | |
rmsousa
2014/08/12 20:42:10
This should be named stddev. variance is stddev^2
Sergey Ulanov
2014/08/16 00:03:34
Done.
| |
26 cos(base::RandDouble() * 2.0 * M_PI); | |
27 } | |
28 | |
29 class FakeUdpSocket : public talk_base::AsyncPacketSocket { | |
30 public: | |
31 FakeUdpSocket(FakePacketSocketFactory* factory, | |
32 scoped_refptr<FakeNetworkDispatcher> dispatcher, | |
33 const talk_base::SocketAddress& local_address); | |
34 virtual ~FakeUdpSocket(); | |
35 | |
36 void ReceivePacket(const talk_base::SocketAddress& from, | |
37 const talk_base::SocketAddress& to, | |
38 const scoped_refptr<net::IOBuffer>& data, | |
39 int data_size); | |
40 | |
41 // talk_base::AsyncPacketSocket interface. | |
42 virtual talk_base::SocketAddress GetLocalAddress() const OVERRIDE; | |
43 virtual talk_base::SocketAddress GetRemoteAddress() const OVERRIDE; | |
44 virtual int Send(const void* data, size_t data_size, | |
45 const talk_base::PacketOptions& options) OVERRIDE; | |
46 virtual int SendTo(const void* data, size_t data_size, | |
47 const talk_base::SocketAddress& address, | |
48 const talk_base::PacketOptions& options) OVERRIDE; | |
49 virtual int Close() OVERRIDE; | |
50 virtual State GetState() const OVERRIDE; | |
51 virtual int GetOption(talk_base::Socket::Option option, int* value) OVERRIDE; | |
52 virtual int SetOption(talk_base::Socket::Option option, int value) OVERRIDE; | |
53 virtual int GetError() const OVERRIDE; | |
54 virtual void SetError(int error) OVERRIDE; | |
55 | |
56 private: | |
57 FakePacketSocketFactory* factory_; | |
58 scoped_refptr<FakeNetworkDispatcher> dispatcher_; | |
59 talk_base::SocketAddress local_address_; | |
60 State state_; | |
61 | |
62 DISALLOW_COPY_AND_ASSIGN(FakeUdpSocket); | |
63 }; | |
64 | |
65 FakeUdpSocket::FakeUdpSocket(FakePacketSocketFactory* factory, | |
66 scoped_refptr<FakeNetworkDispatcher> dispatcher, | |
67 const talk_base::SocketAddress& local_address) | |
68 : factory_(factory), | |
69 dispatcher_(dispatcher), | |
70 local_address_(local_address), | |
71 state_(STATE_BOUND) { | |
72 } | |
73 | |
74 FakeUdpSocket::~FakeUdpSocket() { | |
75 factory_->OnSocketDestroyed(local_address_.port()); | |
76 } | |
77 | |
78 void FakeUdpSocket::ReceivePacket(const talk_base::SocketAddress& from, | |
79 const talk_base::SocketAddress& to, | |
80 const scoped_refptr<net::IOBuffer>& data, | |
81 int data_size) { | |
82 SignalReadPacket( | |
83 this, data->data(), data_size, from, talk_base::CreatePacketTime(0)); | |
84 } | |
85 | |
86 talk_base::SocketAddress FakeUdpSocket::GetLocalAddress() const { | |
87 return local_address_; | |
88 } | |
89 | |
90 talk_base::SocketAddress FakeUdpSocket::GetRemoteAddress() const { | |
91 NOTREACHED(); | |
92 return talk_base::SocketAddress(); | |
93 } | |
94 | |
95 int FakeUdpSocket::Send(const void* data, size_t data_size, | |
96 const talk_base::PacketOptions& options) { | |
97 NOTREACHED(); | |
98 return EINVAL; | |
99 } | |
100 | |
101 int FakeUdpSocket::SendTo(const void* data, size_t data_size, | |
102 const talk_base::SocketAddress& address, | |
103 const talk_base::PacketOptions& options) { | |
104 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(data_size); | |
105 memcpy(buffer->data(), data, data_size); | |
106 dispatcher_->DeliverPacket(local_address_, address, buffer, data_size); | |
107 return data_size; | |
108 } | |
109 | |
110 int FakeUdpSocket::Close() { | |
111 state_ = STATE_CLOSED; | |
112 return 0; | |
113 } | |
114 | |
115 talk_base::AsyncPacketSocket::State FakeUdpSocket::GetState() const { | |
116 return state_; | |
117 } | |
118 | |
119 int FakeUdpSocket::GetOption(talk_base::Socket::Option option, int* value) { | |
120 NOTIMPLEMENTED(); | |
121 return -1; | |
122 } | |
123 | |
124 int FakeUdpSocket::SetOption(talk_base::Socket::Option option, int value) { | |
125 NOTIMPLEMENTED(); | |
126 return -1; | |
127 } | |
128 | |
129 int FakeUdpSocket::GetError() const { | |
130 return 0; | |
131 } | |
132 | |
133 void FakeUdpSocket::SetError(int error) { | |
134 NOTREACHED(); | |
135 } | |
136 | |
137 } // namespace | |
138 | |
139 FakePacketSocketFactory::PendingPacket::PendingPacket() | |
140 : data_size(0) { | |
141 } | |
142 | |
143 FakePacketSocketFactory::PendingPacket::PendingPacket( | |
144 const talk_base::SocketAddress& from, | |
145 const talk_base::SocketAddress& to, | |
146 const scoped_refptr<net::IOBuffer>& data, | |
147 int data_size) | |
148 : from(from), to(to), data(data), data_size(data_size) { | |
149 } | |
150 | |
151 FakePacketSocketFactory::PendingPacket::~PendingPacket() { | |
152 } | |
153 | |
154 FakePacketSocketFactory::FakePacketSocketFactory( | |
155 FakeNetworkDispatcher* dispatcher) | |
156 : task_runner_(base::ThreadTaskRunnerHandle::Get()), | |
157 dispatcher_(dispatcher), | |
158 address_(dispatcher_->AllocateAddress()), | |
159 out_of_order_rate_(0.0), | |
160 next_port_(1000), | |
rmsousa
2014/08/12 20:42:10
nit: 1024 (if the intention is to emulate unix "hi
Sergey Ulanov
2014/08/16 00:03:34
Done.
| |
161 weak_factory_(this) { | |
162 dispatcher_->AddNode(this); | |
163 } | |
164 | |
165 FakePacketSocketFactory::~FakePacketSocketFactory() { | |
166 CHECK(udp_sockets_.empty()); | |
167 dispatcher_->RemoveNode(this); | |
168 } | |
169 | |
170 void FakePacketSocketFactory::OnSocketDestroyed(int port) { | |
171 DCHECK(task_runner_->BelongsToCurrentThread()); | |
172 udp_sockets_.erase(port); | |
173 } | |
174 | |
175 void FakePacketSocketFactory::SetBandwidth(int bandwidth, int max_buffer) { | |
176 DCHECK(task_runner_->BelongsToCurrentThread()); | |
177 if (bandwidth <= 0) { | |
178 leaky_bucket_.reset(); | |
179 } else { | |
180 leaky_bucket_.reset(new LeakyBucket(max_buffer, bandwidth)); | |
181 } | |
182 } | |
183 | |
184 void FakePacketSocketFactory::SetLatency(base::TimeDelta average, | |
185 base::TimeDelta variance) { | |
186 DCHECK(task_runner_->BelongsToCurrentThread()); | |
187 latency_average_ = average; | |
188 latency_variance_ = variance; | |
189 } | |
190 | |
191 talk_base::AsyncPacketSocket* FakePacketSocketFactory::CreateUdpSocket( | |
192 const talk_base::SocketAddress& local_address, | |
193 int min_port, int max_port) { | |
194 DCHECK(task_runner_->BelongsToCurrentThread()); | |
195 | |
196 int port = -1; | |
197 if (min_port > 0 && max_port > 0) { | |
198 for (int i = min_port; i <= max_port; ++i) { | |
199 if (udp_sockets_.find(i) == udp_sockets_.end()) { | |
200 port = i; | |
201 break; | |
202 } | |
203 } | |
204 if (port < 0) | |
205 return NULL; | |
206 } else { | |
207 do { | |
208 port = next_port_; | |
209 next_port_ = (next_port_ == 65535) ? 1000 : next_port_ + 1; | |
rmsousa
2014/08/12 20:42:10
nit: 1024 here as well (probably should define a c
Sergey Ulanov
2014/08/16 00:03:34
Done.
| |
210 } while (udp_sockets_.find(port) != udp_sockets_.end()); | |
211 } | |
212 | |
213 CHECK(local_address.ipaddr() == address_); | |
214 | |
215 FakeUdpSocket* result = | |
216 new FakeUdpSocket(this, dispatcher_, | |
217 talk_base::SocketAddress(local_address.ipaddr(), port)); | |
218 | |
219 udp_sockets_[port] = | |
220 base::Bind(&FakeUdpSocket::ReceivePacket, base::Unretained(result)); | |
221 | |
222 return result; | |
223 } | |
224 | |
225 talk_base::AsyncPacketSocket* FakePacketSocketFactory::CreateServerTcpSocket( | |
226 const talk_base::SocketAddress& local_address, | |
227 int min_port, int max_port, | |
228 int opts) { | |
229 return NULL; | |
230 } | |
231 | |
232 talk_base::AsyncPacketSocket* FakePacketSocketFactory::CreateClientTcpSocket( | |
233 const talk_base::SocketAddress& local_address, | |
234 const talk_base::SocketAddress& remote_address, | |
235 const talk_base::ProxyInfo& proxy_info, | |
236 const std::string& user_agent, | |
237 int opts) { | |
238 return NULL; | |
239 } | |
240 | |
241 talk_base::AsyncResolverInterface* | |
242 FakePacketSocketFactory::CreateAsyncResolver() { | |
243 return NULL; | |
244 } | |
245 | |
246 const scoped_refptr<base::SingleThreadTaskRunner>& | |
247 FakePacketSocketFactory::GetThread() const { | |
248 return task_runner_; | |
249 } | |
250 | |
251 const talk_base::IPAddress& FakePacketSocketFactory::GetAddress() const { | |
252 return address_; | |
253 } | |
254 | |
255 void FakePacketSocketFactory::ReceivePacket( | |
256 const talk_base::SocketAddress& from, | |
257 const talk_base::SocketAddress& to, | |
258 const scoped_refptr<net::IOBuffer>& data, | |
259 int data_size) { | |
260 DCHECK(task_runner_->BelongsToCurrentThread()); | |
261 DCHECK(to.ipaddr() == address_); | |
262 | |
263 base::TimeDelta delay; | |
264 | |
265 if (leaky_bucket_) { | |
266 delay = leaky_bucket_->AddPacket(data_size); | |
267 if (delay.is_max()) { | |
268 // Drop the packet. | |
269 return; | |
270 } | |
271 } | |
272 | |
273 if (latency_average_ > base::TimeDelta()) { | |
274 delay += base::TimeDelta::FromMillisecondsD( | |
275 GetNormalRandom(latency_average_.InMillisecondsF(), | |
276 latency_variance_.InMillisecondsF())); | |
277 } | |
278 if (delay < base::TimeDelta()) | |
279 delay = base::TimeDelta(); | |
280 | |
281 PendingPacket packet(from, to, data, data_size); | |
282 pending_packets_.push_back(packet); | |
283 task_runner_->PostDelayedTask( | |
284 FROM_HERE, | |
285 base::Bind(&FakePacketSocketFactory::DoReceivePacket, | |
rmsousa
2014/08/12 20:42:10
This is a bit weird - since delay has a random com
Sergey Ulanov
2014/08/16 00:03:34
Yes, that's by design. I actually implemented it w
| |
286 weak_factory_.GetWeakPtr()), | |
287 delay); | |
288 } | |
289 | |
290 void FakePacketSocketFactory::DoReceivePacket() { | |
291 DCHECK(task_runner_->BelongsToCurrentThread()); | |
292 | |
293 PendingPacket packet; | |
294 if (pending_packets_.size() > 1 && base::RandDouble() < out_of_order_rate_) { | |
295 std::list<PendingPacket>::iterator it = pending_packets_.begin(); | |
296 ++it; | |
297 packet = *it; | |
298 pending_packets_.erase(it); | |
299 } else { | |
300 packet = pending_packets_.front(); | |
301 pending_packets_.pop_front(); | |
302 } | |
303 | |
304 UdpSocketsMap::iterator iter = udp_sockets_.find(packet.to.port()); | |
305 if (iter == udp_sockets_.end()) { | |
306 // Invalid port number. | |
307 return; | |
308 } | |
309 | |
310 iter->second.Run(packet.from, packet.to, packet.data, packet.data_size); | |
311 } | |
312 | |
313 } // namespace remoting | |
OLD | NEW |