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

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