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

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.
23 const int kMaxSendBufferSize = 256 * 1024;
Wez 2012/04/20 21:37:07 This is a limit on the amount of user data; the li
Sergey Ulanov 2012/04/23 22:16:51 Right. I don't think it matters though. Normally t
Wez 2012/04/25 00:01:59 Right, so best to make it clear in the comment wha
Sergey Ulanov 2012/04/25 00:25:01 Done.
24
25 class UdpPacketSocket : public talk_base::AsyncPacketSocket {
26 public:
27 explicit UdpPacketSocket(const pp::InstanceHandle& instance);
28 virtual ~UdpPacketSocket();
29
30 // Always takes ownership of client even if initialization fails.
31 bool Init(const talk_base::SocketAddress& local_address,
32 int min_port,
33 int max_port);
34
35 // talk_base::AsyncPacketSocket interface.
36 virtual talk_base::SocketAddress GetLocalAddress() const;
37 virtual talk_base::SocketAddress GetRemoteAddress() const;
38 virtual int Send(const void* data, size_t data_size);
39 virtual int SendTo(const void* data,
40 size_t data_size,
41 const talk_base::SocketAddress& address);
42 virtual int Close();
43 virtual State GetState() const;
44 virtual int GetOption(talk_base::Socket::Option opt, int* value);
45 virtual int SetOption(talk_base::Socket::Option opt, int value);
46 virtual int GetError() const;
47 virtual void SetError(int error);
48
49 private:
50 struct PendingPacket {
51 PendingPacket(const void* buffer,
52 int buffer_size,
53 const PP_NetAddress_Private& address);
54
55 scoped_refptr<net::IOBufferWithSize> data;
56 PP_NetAddress_Private address;
57 };
58
59 void OnBindCompleted(int error);
60
61 void DoSend();
62 void OnSendCompleted(int result);
63
64 void DoRead();
65 void OnReadCompleted(int result);
66 void HandleReadResult(int result);
67
68 pp::UDPSocketPrivate socket;
Wez 2012/04/20 21:37:07 socket -> socket_
Sergey Ulanov 2012/04/23 22:16:51 Done.
69
70 State state_;
71 int error_;
72
73 talk_base::SocketAddress local_address_;
Wez 2012/04/20 21:37:07 Add a comment indicating that this is contains the
Sergey Ulanov 2012/04/23 22:16:51 Done.
74
75 // Used when the caller specified min_port_ and max_port_.
Wez 2012/04/20 21:37:07 Doesn't the caller always specify those? The key t
Sergey Ulanov 2012/04/23 22:16:51 Done.
76 uint16_t current_port_;
Wez 2012/04/20 21:37:07 nit: |current_port_| sounds like it's the port to
Sergey Ulanov 2012/04/23 22:16:51 Done.
77 uint16_t max_port_;
78
79 std::vector<char> receive_buffer_;
80
81 bool send_pending_;
82 std::list<PendingPacket> send_queue_;
83 int send_queue_size_;
84
85 DISALLOW_COPY_AND_ASSIGN(UdpPacketSocket);
86 };
87
88 UdpPacketSocket::PendingPacket::PendingPacket(
89 const void* buffer,
90 int buffer_size,
91 const PP_NetAddress_Private& address)
92 : data(new net::IOBufferWithSize(buffer_size)),
93 address(address) {
94 memcpy(data->data(), buffer, buffer_size);
95 }
96
97 UdpPacketSocket::UdpPacketSocket(const pp::InstanceHandle& instance)
98 : socket(instance),
99 state_(STATE_CLOSED),
100 error_(0),
101 current_port_(0),
102 max_port_(0),
103 send_pending_(false),
104 send_queue_size_(0) {
105 }
106
107 UdpPacketSocket::~UdpPacketSocket() {
108 }
109
110 bool SocketAddressToPpAddressWithPort(const talk_base::SocketAddress& address,
111 PP_NetAddress_Private* pp_address,
112 uint16_t port) {
113 bool result;
114 switch(address.ipaddr().family()) {
115 case AF_INET: {
116 in_addr addr = address.ipaddr().ipv4_address();
117 result = pp::NetAddressPrivate::CreateFromIPv4Address(
118 reinterpret_cast<uint8_t*>(&addr), port, pp_address);
119 break;
120 }
121 case AF_INET6: {
122 in6_addr addr = address.ipaddr().ipv6_address();
123 result = pp::NetAddressPrivate::CreateFromIPv6Address(
124 addr.s6_addr, 0, port, pp_address);
125 break;
126 }
127 default: {
128 LOG(WARNING) << "Unknown address family: " << address.ipaddr().family();
129 }
130 }
131 if (!result) {
132 LOG(WARNING) << "Failed to convert address: " << address.ToString();
133 }
134 return result;
135 }
136
137 bool SocketAddressToPpAddress(const talk_base::SocketAddress& address,
138 PP_NetAddress_Private* pp_address) {
139 return SocketAddressToPpAddressWithPort(address, pp_address, address.port());
140 }
141
142 bool PpAddressToSocketAddress(const PP_NetAddress_Private& pp_address,
143 talk_base::SocketAddress* address) {
144 uint8_t addr_storage[16];
145 bool result = pp::NetAddressPrivate::GetAddress(
146 pp_address, &addr_storage, sizeof(addr_storage));
147
148 if (result) {
149 switch (pp::NetAddressPrivate::GetFamily(pp_address)) {
150 case PP_NETADDRESSFAMILY_IPV4:
151 address->SetIP(talk_base::IPAddress(
152 *reinterpret_cast<in_addr*>(addr_storage)));
153 break;
154 case PP_NETADDRESSFAMILY_IPV6:
155 address->SetIP(talk_base::IPAddress(
156 *reinterpret_cast<in6_addr*>(addr_storage)));
157 break;
158 default:
159 result = false;
160 }
161 }
162
163 if (!result) {
164 LOG(WARNING) << "Failed to convert address: "
165 << pp::NetAddressPrivate::Describe(pp_address, true);
166 } else {
167 address->SetPort(pp::NetAddressPrivate::GetPort(pp_address));
168 }
169 return result;
170 }
171
172 bool UdpPacketSocket::Init(const talk_base::SocketAddress& local_address,
173 int min_port,
174 int max_port) {
175 if (socket.is_null()) {
176 return false;
177 }
178
179 local_address_ = local_address;
180 max_port_ = max_port;
181 current_port_ = min_port;
182
183 PP_NetAddress_Private pp_local_address;
184 if (!SocketAddressToPpAddressWithPort(local_address_, &pp_local_address,
185 current_port_)) {
186 return false;
187 }
188
189 int result = socket.Bind(&pp_local_address, PpCompletionCallback(
190 base::Bind(&UdpPacketSocket::OnBindCompleted, base::Unretained(this))));
191 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
192 state_ = STATE_BINDING;
193
194 return true;
195 }
196
197 void UdpPacketSocket::OnBindCompleted(int result) {
198 DCHECK_EQ(state_, STATE_BINDING);
199
200 if (result == PP_OK) {
201 PP_NetAddress_Private address;
202 if (socket.GetBoundAddress(&address)) {
203 PpAddressToSocketAddress(address, &local_address_);
204 } else {
205 LOG(ERROR) << "Failed to get bind address for bound socket?";
206 error_ = EINVAL;
207 return;
208 }
209 state_ = STATE_BOUND;
210 SignalAddressReady(this, local_address_);
211 DoRead();
212 return;
213 }
214
215 if (current_port_ < max_port_) {
216 // Try to bind to the next available port.
217 ++current_port_;
218 PP_NetAddress_Private pp_local_address;
219 if (SocketAddressToPpAddressWithPort(local_address_, &pp_local_address,
220 current_port_)) {
221 int result = socket.Bind(&pp_local_address, PpCompletionCallback(
222 base::Bind(&UdpPacketSocket::OnBindCompleted,
223 base::Unretained(this))));
Wez 2012/04/20 21:37:07 Hmmm, I think we'll leak a base::Callback from PpC
Sergey Ulanov 2012/04/23 22:16:51 The callbacks must be invoked with PP_ERROR_ABORTE
Wez 2012/04/25 00:01:59 If the caller deletes this object while the socket
Sergey Ulanov 2012/04/25 00:25:01 More recent version of OnBindCompleted() handles t
224 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
225 }
226 } else {
227 LOG(ERROR) << "Failed to bind UDP socket: " << result;
228 }
229 }
230
231 talk_base::SocketAddress UdpPacketSocket::GetLocalAddress() const {
232 return local_address_;
233 }
234
235 talk_base::SocketAddress UdpPacketSocket::GetRemoteAddress() const {
236 // UDP sockets are not connected - this method should never be called.
237 NOTREACHED();
238 return talk_base::SocketAddress();
239 }
240
241 int UdpPacketSocket::Send(const void* data, size_t data_size) {
242 // UDP sockets are not connected - this method should never be called.
Wez 2012/04/20 21:37:07 They _can_ be connected, in which case this and Ge
Sergey Ulanov 2012/04/23 22:16:51 UDP instances of AsyncPacketSocket are never conne
243 NOTREACHED();
244 return EWOULDBLOCK;
245 }
246
247 int UdpPacketSocket::SendTo(const void* data,
248 size_t data_size,
249 const talk_base::SocketAddress& address) {
250 if (error_ != 0) {
251 return error_;
252 }
253
254 PP_NetAddress_Private pp_address;
255 if (!SocketAddressToPpAddress(address, &pp_address)) {
256 return EINVAL;
257 }
258
259 if (send_queue_size_ >= kMaxSendBufferSize) {
260 return EWOULDBLOCK;
261 }
262
263 send_queue_.push_back(PendingPacket(data, data_size, pp_address));
264 send_queue_size_ += data_size;
265 DoSend();
266 return data_size;
267 }
268
269 int UdpPacketSocket::Close() {
270 socket.Close();
271 state_ = STATE_CLOSED;
272 return 0;
273 }
274
275 talk_base::AsyncPacketSocket::State UdpPacketSocket::GetState() const {
276 return state_;
277 }
278
279 int UdpPacketSocket::GetOption(talk_base::Socket::Option opt, int* value) {
280 return -1;
Wez 2012/04/20 21:37:07 nit: Add a // comment explaining this return code.
Sergey Ulanov 2012/04/23 22:16:51 Done.
281 }
282
283 int UdpPacketSocket::SetOption(talk_base::Socket::Option opt, int value) {
284 return -1;
285 }
286
287 int UdpPacketSocket::GetError() const {
288 return error_;
289 }
290
291 void UdpPacketSocket::SetError(int error) {
292 error_ = error;
293 }
294
295 void UdpPacketSocket::DoSend() {
296 if (send_pending_ || send_queue_.empty())
297 return;
298
299 int result = socket.SendTo(
300 send_queue_.front().data->data(), send_queue_.front().data->size(),
301 &send_queue_.front().address,
302 PpCompletionCallback(base::Bind(&UdpPacketSocket::OnSendCompleted,
303 base::Unretained(this))));
Wez 2012/04/20 21:37:07 Is the SendTo() interface actually defined to not
Sergey Ulanov 2012/04/23 22:16:51 Yes, SendTo() would return an error when another s
Wez 2012/04/25 00:01:59 Shouldn't you get PP_ERROR_IN_PROGRESS to the comp
Sergey Ulanov 2012/04/25 00:25:01 I take this back - looks like the current UDP sock
304 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
305 send_pending_ = true;
306 }
307
308 void UdpPacketSocket::OnSendCompleted(int result) {
309 if (result < 0) {
310 LOG(ERROR) << "Send failed on a UDP socket: " << result;
311 error_ = EINVAL;
312 return;
313 }
314
315 send_pending_ = false;
316 send_queue_size_ -= send_queue_.front().data->size();
317 send_queue_.pop_front();
318 DoSend();
319 }
320
321 void UdpPacketSocket::DoRead() {
322 receive_buffer_.resize(kReceiveBufferSize);
323 int result = socket.RecvFrom(
324 &receive_buffer_[0], receive_buffer_.size(),
325 PpCompletionCallback(base::Bind(&UdpPacketSocket::OnReadCompleted,
326 base::Unretained(this))));
327 DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
328 }
329
330 void UdpPacketSocket::OnReadCompleted(int result) {
331 HandleReadResult(result);
332 if (result > 0) {
333 DoRead();
334 }
335 }
336
337 void UdpPacketSocket::HandleReadResult(int result) {
338 if (result > 0) {
339 PP_NetAddress_Private pp_address;
340 if (!socket.GetRecvFromAddress(&pp_address)) {
341 LOG(ERROR) << "GetRecvFromAddress() failed after successfull RecvFrom().";
342 return;
343 }
344 talk_base::SocketAddress address;
345 if (!PpAddressToSocketAddress(pp_address, &address)) {
346 LOG(ERROR) << "Failed to covert address received from RecvFrom().";
347 return;
348 }
349 SignalReadPacket(this, &receive_buffer_[0], result, address);
Wez 2012/04/20 21:37:07 SignalReadPacket() could trigger the caller to tea
Sergey Ulanov 2012/04/23 22:16:51 It should be safe to delete the socket from a call
Wez 2012/04/25 00:01:59 Right. So if calling code deletes us from within
Sergey Ulanov 2012/04/25 00:25:01 ah, I see what you are talking about now. Actually
350 }
351 }
352
353 } // namespace
354
355 PepperPacketSocketFactory::PepperPacketSocketFactory(
356 const pp::InstanceHandle& instance)
357 : pp_instance_(instance) {
358 }
359
360 PepperPacketSocketFactory::~PepperPacketSocketFactory() {
361 }
362
363 talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateUdpSocket(
364 const talk_base::SocketAddress& local_address,
365 int min_port,
366 int max_port) {
367 scoped_ptr<UdpPacketSocket> result(new UdpPacketSocket(pp_instance_));
368 if (!result->Init(local_address, min_port, max_port))
369 return NULL;
370 return result.release();
371 }
372
373 talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateServerTcpSocket(
374 const talk_base::SocketAddress& local_address,
375 int min_port,
376 int max_port,
377 bool ssl) {
378 // Don't use TCP sockets for remoting connections.
Wez 2012/04/20 21:37:07 NOTREACHED()?
Sergey Ulanov 2012/04/23 22:16:51 Done.
379 return NULL;
380 }
381
382 talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateClientTcpSocket(
383 const talk_base::SocketAddress& local_address,
384 const talk_base::SocketAddress& remote_address,
385 const talk_base::ProxyInfo& proxy_info,
386 const std::string& user_agent,
387 bool ssl) {
388 // Don't use TCP sockets for remoting connections.
389 return NULL;
390 }
391
392 } // 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