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