Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(155)

Side by Side Diff: remoting/client/plugin/pepper_packet_socket_factory.cc

Issue 10121002: Implement PepperPacketSocketFactory. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « remoting/client/plugin/pepper_packet_socket_factory.h ('k') | remoting/remoting.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « remoting/client/plugin/pepper_packet_socket_factory.h ('k') | remoting/remoting.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698