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

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
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 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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698