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. | |
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 | |
OLD | NEW |