OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 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/client/plugin/pepper_packet_socket_factory.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/logging.h" | |
9 #include "net/base/io_buffer.h" | |
10 #include "ppapi/cpp/private/net_address_private.h" | |
11 #include "ppapi/cpp/private/udp_socket_private.h" | |
12 #include "remoting/client/plugin/pepper_util.h" | |
13 #include "third_party/libjingle/source/talk/base/asyncpacketsocket.h" | |
14 | |
15 namespace remoting { | |
16 | |
17 namespace { | |
18 | |
19 // Size of the buffer to allocate for RecvFrom(). | |
20 const int kReceiveBufferSize = 65536; | |
21 | |
22 // Maximum amount of data in the send buffers. This is necessary to | |
23 // prevent form out-of-memory crashes when the UDP API stops sending | |
Wez
2012/04/25 01:05:33
nit: Suggest "This prevents OOM crashes if the cal
Sergey Ulanov
2012/04/25 01:21:57
Done.
| |
24 // data. Normally this maximum should never be reached. | |
25 const int kMaxSendBufferSize = 256 * 1024; | |
26 | |
27 class UdpPacketSocket : public talk_base::AsyncPacketSocket { | |
28 public: | |
29 explicit UdpPacketSocket(const pp::InstanceHandle& instance); | |
30 virtual ~UdpPacketSocket(); | |
31 | |
32 // Always takes ownership of client even if initialization fails. | |
Wez
2012/04/25 01:05:33
Not sure what this means?
Sergey Ulanov
2012/04/25 01:21:57
Removed comment - it was copy-pasted from IpcPacke
| |
33 bool Init(const talk_base::SocketAddress& local_address, | |
34 int min_port, | |
35 int max_port); | |
36 | |
37 // talk_base::AsyncPacketSocket interface. | |
38 virtual talk_base::SocketAddress GetLocalAddress() const; | |
39 virtual talk_base::SocketAddress GetRemoteAddress() const; | |
40 virtual int Send(const void* data, size_t data_size); | |
41 virtual int SendTo(const void* data, | |
42 size_t data_size, | |
43 const talk_base::SocketAddress& address); | |
44 virtual int Close(); | |
45 virtual State GetState() const; | |
46 virtual int GetOption(talk_base::Socket::Option opt, int* value); | |
47 virtual int SetOption(talk_base::Socket::Option opt, int value); | |
48 virtual int GetError() const; | |
49 virtual void SetError(int error); | |
50 | |
51 private: | |
52 struct PendingPacket { | |
53 PendingPacket(const void* buffer, | |
54 int buffer_size, | |
55 const PP_NetAddress_Private& address); | |
56 | |
57 scoped_refptr<net::IOBufferWithSize> data; | |
58 PP_NetAddress_Private address; | |
59 }; | |
60 | |
61 void OnBindCompleted(int error); | |
62 | |
63 void DoSend(); | |
64 void OnSendCompleted(int result); | |
65 | |
66 void DoRead(); | |
67 void OnReadCompleted(int result); | |
68 void HandleReadResult(int result); | |
69 | |
70 pp::UDPSocketPrivate socket_; | |
71 | |
72 State state_; | |
73 int error_; | |
74 | |
75 talk_base::SocketAddress local_address_; | |
76 | |
77 // Used to scan ports when part range is specified. Set to 0 when | |
Wez
2012/04/25 01:05:33
typo: part -> port
Sergey Ulanov
2012/04/25 01:21:57
Done.
| |
78 // the port range is not specified. | |
79 uint16_t min_port_; | |
80 uint16_t max_port_; | |
81 | |
82 std::vector<char> receive_buffer_; | |
83 | |
84 bool send_pending_; | |
85 std::list<PendingPacket> send_queue_; | |
86 int send_queue_size_; | |
87 | |
88 DISALLOW_COPY_AND_ASSIGN(UdpPacketSocket); | |
89 }; | |
90 | |
91 UdpPacketSocket::PendingPacket::PendingPacket( | |
92 const void* buffer, | |
93 int buffer_size, | |
94 const PP_NetAddress_Private& address) | |
95 : data(new net::IOBufferWithSize(buffer_size)), | |
96 address(address) { | |
97 memcpy(data->data(), buffer, buffer_size); | |
98 } | |
99 | |
100 UdpPacketSocket::UdpPacketSocket(const pp::InstanceHandle& instance) | |
101 : socket_(instance), | |
102 state_(STATE_CLOSED), | |
103 error_(0), | |
104 min_port_(0), | |
105 max_port_(0), | |
106 send_pending_(false), | |
107 send_queue_size_(0) { | |
108 } | |
109 | |
110 UdpPacketSocket::~UdpPacketSocket() { | |
111 Close(); | |
112 } | |
113 | |
114 bool SocketAddressToPpAddressWithPort(const talk_base::SocketAddress& address, | |
115 PP_NetAddress_Private* pp_address, | |
116 uint16_t port) { | |
117 bool result; | |
Wez
2012/04/25 01:05:33
Initialize result. Surprised clang didn't catch th
Sergey Ulanov
2012/04/25 01:21:57
Done.
| |
118 switch(address.ipaddr().family()) { | |
119 case AF_INET: { | |
120 in_addr addr = address.ipaddr().ipv4_address(); | |
121 result = pp::NetAddressPrivate::CreateFromIPv4Address( | |
122 reinterpret_cast<uint8_t*>(&addr), port, pp_address); | |
123 break; | |
124 } | |
125 case AF_INET6: { | |
126 in6_addr addr = address.ipaddr().ipv6_address(); | |
127 result = pp::NetAddressPrivate::CreateFromIPv6Address( | |
128 addr.s6_addr, 0, port, pp_address); | |
129 break; | |
130 } | |
131 default: { | |
132 LOG(WARNING) << "Unknown address family: " << address.ipaddr().family(); | |
133 } | |
134 } | |
135 if (!result) { | |
136 LOG(WARNING) << "Failed to convert address: " << address.ToString(); | |
137 } | |
138 return result; | |
139 } | |
140 | |
141 bool SocketAddressToPpAddress(const talk_base::SocketAddress& address, | |
142 PP_NetAddress_Private* pp_address) { | |
143 return SocketAddressToPpAddressWithPort(address, pp_address, address.port()); | |
144 } | |
145 | |
146 bool PpAddressToSocketAddress(const PP_NetAddress_Private& pp_address, | |
147 talk_base::SocketAddress* address) { | |
148 uint8_t addr_storage[16]; | |
149 bool result = pp::NetAddressPrivate::GetAddress( | |
150 pp_address, &addr_storage, sizeof(addr_storage)); | |
151 | |
152 if (result) { | |
153 switch (pp::NetAddressPrivate::GetFamily(pp_address)) { | |
154 case PP_NETADDRESSFAMILY_IPV4: | |
155 address->SetIP(talk_base::IPAddress( | |
156 *reinterpret_cast<in_addr*>(addr_storage))); | |
157 break; | |
158 case PP_NETADDRESSFAMILY_IPV6: | |
159 address->SetIP(talk_base::IPAddress( | |
160 *reinterpret_cast<in6_addr*>(addr_storage))); | |
161 break; | |
162 default: | |
163 result = false; | |
164 } | |
165 } | |
166 | |
167 if (!result) { | |
168 LOG(WARNING) << "Failed to convert address: " | |
169 << pp::NetAddressPrivate::Describe(pp_address, true); | |
170 } else { | |
171 address->SetPort(pp::NetAddressPrivate::GetPort(pp_address)); | |
172 } | |
173 return result; | |
174 } | |
175 | |
176 bool UdpPacketSocket::Init(const talk_base::SocketAddress& local_address, | |
177 int min_port, | |
178 int max_port) { | |
179 if (socket_.is_null()) { | |
180 return false; | |
181 } | |
182 | |
183 local_address_ = local_address; | |
184 max_port_ = max_port; | |
185 min_port_ = min_port; | |
186 | |
187 PP_NetAddress_Private pp_local_address; | |
188 if (!SocketAddressToPpAddressWithPort(local_address_, &pp_local_address, | |
189 min_port_)) { | |
190 return false; | |
191 } | |
192 | |
193 int result = socket_.Bind(&pp_local_address, PpCompletionCallback( | |
194 base::Bind(&UdpPacketSocket::OnBindCompleted, base::Unretained(this)))); | |
195 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); | |
196 state_ = STATE_BINDING; | |
197 | |
198 return true; | |
199 } | |
200 | |
201 void UdpPacketSocket::OnBindCompleted(int result) { | |
202 DCHECK(state_ == STATE_BINDING || state_ == STATE_CLOSED); | |
203 | |
204 if (result == PP_ERROR_ABORTED) { | |
205 // Socket is being destroyed while binding. | |
206 return; | |
207 } | |
208 | |
209 if (result == PP_OK) { | |
210 PP_NetAddress_Private address; | |
211 if (socket_.GetBoundAddress(&address)) { | |
212 PpAddressToSocketAddress(address, &local_address_); | |
213 } else { | |
214 LOG(ERROR) << "Failed to get bind address for bound socket?"; | |
215 error_ = EINVAL; | |
216 return; | |
217 } | |
218 state_ = STATE_BOUND; | |
219 SignalAddressReady(this, local_address_); | |
220 DoRead(); | |
221 return; | |
222 } | |
223 | |
224 if (min_port_ < max_port_) { | |
225 // Try to bind to the next available port. | |
226 ++min_port_; | |
227 PP_NetAddress_Private pp_local_address; | |
228 if (SocketAddressToPpAddressWithPort(local_address_, &pp_local_address, | |
229 min_port_)) { | |
230 int result = socket_.Bind(&pp_local_address, PpCompletionCallback( | |
231 base::Bind(&UdpPacketSocket::OnBindCompleted, | |
232 base::Unretained(this)))); | |
233 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); | |
234 } | |
235 } else { | |
236 LOG(ERROR) << "Failed to bind UDP socket: " << result; | |
237 } | |
238 } | |
239 | |
240 talk_base::SocketAddress UdpPacketSocket::GetLocalAddress() const { | |
241 return local_address_; | |
Wez
2012/04/25 01:05:33
nit: Check state_?
Sergey Ulanov
2012/04/25 01:21:57
Done.
| |
242 } | |
243 | |
244 talk_base::SocketAddress UdpPacketSocket::GetRemoteAddress() const { | |
245 // UDP sockets are not connected - this method should never be called. | |
246 NOTREACHED(); | |
247 return talk_base::SocketAddress(); | |
248 } | |
249 | |
250 int UdpPacketSocket::Send(const void* data, size_t data_size) { | |
251 // UDP sockets are not connected - this method should never be called. | |
252 NOTREACHED(); | |
253 return EWOULDBLOCK; | |
254 } | |
255 | |
256 int UdpPacketSocket::SendTo(const void* data, | |
257 size_t data_size, | |
258 const talk_base::SocketAddress& address) { | |
259 if (error_ != 0) { | |
Wez
2012/04/25 01:05:33
Check the state_ here?
Sergey Ulanov
2012/04/25 01:21:57
Done.
| |
260 return error_; | |
261 } | |
262 | |
263 PP_NetAddress_Private pp_address; | |
264 if (!SocketAddressToPpAddress(address, &pp_address)) { | |
265 return EINVAL; | |
266 } | |
267 | |
268 if (send_queue_size_ >= kMaxSendBufferSize) { | |
269 return EWOULDBLOCK; | |
270 } | |
271 | |
272 send_queue_.push_back(PendingPacket(data, data_size, pp_address)); | |
273 send_queue_size_ += data_size; | |
274 DoSend(); | |
275 return data_size; | |
276 } | |
277 | |
278 int UdpPacketSocket::Close() { | |
279 state_ = STATE_CLOSED; | |
280 socket_.Close(); | |
281 return 0; | |
282 } | |
283 | |
284 talk_base::AsyncPacketSocket::State UdpPacketSocket::GetState() const { | |
285 return state_; | |
286 } | |
287 | |
288 int UdpPacketSocket::GetOption(talk_base::Socket::Option opt, int* value) { | |
289 // Options are not supported for Pepper UDP sockets. | |
290 return -1; | |
291 } | |
292 | |
293 int UdpPacketSocket::SetOption(talk_base::Socket::Option opt, int value) { | |
294 // Options are not supported for Pepper UDP sockets. | |
295 return -1; | |
296 } | |
297 | |
298 int UdpPacketSocket::GetError() const { | |
299 return error_; | |
300 } | |
301 | |
302 void UdpPacketSocket::SetError(int error) { | |
303 error_ = error; | |
304 } | |
305 | |
306 void UdpPacketSocket::DoSend() { | |
307 if (send_pending_ || send_queue_.empty()) | |
308 return; | |
309 | |
310 int result = socket_.SendTo( | |
311 send_queue_.front().data->data(), send_queue_.front().data->size(), | |
312 &send_queue_.front().address, | |
313 PpCompletionCallback(base::Bind(&UdpPacketSocket::OnSendCompleted, | |
314 base::Unretained(this)))); | |
315 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); | |
316 send_pending_ = true; | |
317 } | |
318 | |
319 void UdpPacketSocket::OnSendCompleted(int result) { | |
320 send_pending_ = false; | |
321 | |
322 if (result < 0) { | |
323 if (result != PP_ERROR_ABORTED) { | |
324 LOG(ERROR) << "Send failed on a UDP socket: " << result; | |
325 } | |
326 error_ = EINVAL; | |
327 return; | |
328 } | |
329 | |
330 send_queue_size_ -= send_queue_.front().data->size(); | |
331 send_queue_.pop_front(); | |
332 DoSend(); | |
333 } | |
334 | |
335 void UdpPacketSocket::DoRead() { | |
336 receive_buffer_.resize(kReceiveBufferSize); | |
337 int result = socket_.RecvFrom( | |
338 &receive_buffer_[0], receive_buffer_.size(), | |
339 PpCompletionCallback(base::Bind(&UdpPacketSocket::OnReadCompleted, | |
340 base::Unretained(this)))); | |
341 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); | |
342 } | |
343 | |
344 void UdpPacketSocket::OnReadCompleted(int result) { | |
345 HandleReadResult(result); | |
346 if (result > 0) { | |
347 DoRead(); | |
348 } | |
349 } | |
350 | |
351 void UdpPacketSocket::HandleReadResult(int result) { | |
352 if (result > 0) { | |
353 PP_NetAddress_Private pp_address; | |
354 if (!socket_.GetRecvFromAddress(&pp_address)) { | |
355 LOG(ERROR) << "GetRecvFromAddress() failed after successfull RecvFrom()."; | |
356 return; | |
357 } | |
358 talk_base::SocketAddress address; | |
359 if (!PpAddressToSocketAddress(pp_address, &address)) { | |
360 LOG(ERROR) << "Failed to covert address received from RecvFrom()."; | |
361 return; | |
362 } | |
363 SignalReadPacket(this, &receive_buffer_[0], result, address); | |
364 } else if (result != PP_ERROR_ABORTED) { | |
365 LOG(ERROR) << "Received error when reading from UDP socket: " << result; | |
366 } | |
367 } | |
368 | |
369 } // namespace | |
370 | |
371 PepperPacketSocketFactory::PepperPacketSocketFactory( | |
372 const pp::InstanceHandle& instance) | |
373 : pp_instance_(instance) { | |
374 } | |
375 | |
376 PepperPacketSocketFactory::~PepperPacketSocketFactory() { | |
377 } | |
378 | |
379 talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateUdpSocket( | |
380 const talk_base::SocketAddress& local_address, | |
381 int min_port, | |
382 int max_port) { | |
383 scoped_ptr<UdpPacketSocket> result(new UdpPacketSocket(pp_instance_)); | |
384 if (!result->Init(local_address, min_port, max_port)) | |
385 return NULL; | |
386 return result.release(); | |
387 } | |
388 | |
389 talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateServerTcpSocket( | |
390 const talk_base::SocketAddress& local_address, | |
391 int min_port, | |
392 int max_port, | |
393 bool ssl) { | |
394 // Don't use TCP sockets for remoting connections. | |
Wez
2012/04/25 01:05:33
nit: "We don't use..."
Sergey Ulanov
2012/04/25 01:21:57
Done.
| |
395 NOTREACHED(); | |
396 return NULL; | |
397 } | |
398 | |
399 talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateClientTcpSocket( | |
400 const talk_base::SocketAddress& local_address, | |
401 const talk_base::SocketAddress& remote_address, | |
402 const talk_base::ProxyInfo& proxy_info, | |
403 const std::string& user_agent, | |
404 bool ssl) { | |
405 // Don't use TCP sockets for remoting connections. | |
Wez
2012/04/25 01:05:33
nit: Here too.
Sergey Ulanov
2012/04/25 01:21:57
Done.
| |
406 NOTREACHED(); | |
407 return NULL; | |
408 } | |
409 | |
410 } // namespace remoting | |
OLD | NEW |