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.
5 #include "content/renderer/p2p/ipc_socket_factory.h"
7 #include "base/compiler_specific.h"
8 #include "base/message_loop.h"
9 #include "base/message_loop_proxy.h"
10 #include "content/renderer/p2p/socket_client.h"
11 #include "content/renderer/p2p/socket_dispatcher.h"
12 #include "jingle/glue/utils.h"
13 #include "third_party/libjingle/source/talk/base/asyncpacketsocket.h"
19 // IpcPacketSocket implements talk_base::AsyncPacketSocket interface
20 // using P2PSocketClient that works over IPC-channel. It must be used
21 // on the thread it was created.
22 class IpcPacketSocket
: public talk_base::AsyncPacketSocket
,
23 public P2PSocketClient::Delegate
{
26 virtual ~IpcPacketSocket();
28 // Always takes ownership of client even if initialization fails.
29 bool Init(P2PSocketType type
, P2PSocketClient
* client
,
30 const talk_base::SocketAddress
& local_address
,
31 const talk_base::SocketAddress
& remote_address
);
33 // talk_base::AsyncPacketSocket interface.
34 virtual talk_base::SocketAddress
GetLocalAddress() const;
35 virtual talk_base::SocketAddress
GetRemoteAddress() const;
36 virtual int Send(const void *pv
, size_t cb
);
37 virtual int SendTo(const void *pv
, size_t cb
,
38 const talk_base::SocketAddress
& addr
);
40 virtual State
GetState() const;
41 virtual int GetOption(talk_base::Socket::Option opt
, int* value
);
42 virtual int SetOption(talk_base::Socket::Option opt
, int value
);
43 virtual int GetError() const;
44 virtual void SetError(int error
);
46 // P2PSocketClient::Delegate implementation.
47 virtual void OnOpen(const net::IPEndPoint
& address
) OVERRIDE
;
48 virtual void OnIncomingTcpConnection(const net::IPEndPoint
& address
,
49 P2PSocketClient
* client
) OVERRIDE
;
50 virtual void OnError();
51 virtual void OnDataReceived(const net::IPEndPoint
& address
,
52 const std::vector
<char>& data
) OVERRIDE
;
63 void InitAcceptedTcp(P2PSocketClient
* client
,
64 const talk_base::SocketAddress
& local_address
,
65 const talk_base::SocketAddress
& remote_address
);
69 // Message loop on which this socket was created and being used.
70 MessageLoop
* message_loop_
;
72 // Corresponding P2P socket client.
73 scoped_refptr
<P2PSocketClient
> client_
;
75 // Local address is allocated by the browser process, and the
76 // renderer side doesn't know the address until it receives OnOpen()
77 // event from the browser.
78 talk_base::SocketAddress local_address_
;
80 // Remote address for client TCP connections.
81 talk_base::SocketAddress remote_address_
;
83 // Current state of the object.
86 // Current error code. Valid when state_ == IS_ERROR.
89 DISALLOW_COPY_AND_ASSIGN(IpcPacketSocket
);
92 IpcPacketSocket::IpcPacketSocket()
93 : type_(P2P_SOCKET_UDP
),
94 message_loop_(MessageLoop::current()),
95 state_(IS_UNINITIALIZED
),
99 IpcPacketSocket::~IpcPacketSocket() {
100 if (state_
== IS_OPENING
|| state_
== IS_OPEN
||
101 state_
== IS_ERROR
) {
106 bool IpcPacketSocket::Init(P2PSocketType type
, P2PSocketClient
* client
,
107 const talk_base::SocketAddress
& local_address
,
108 const talk_base::SocketAddress
& remote_address
) {
109 DCHECK_EQ(MessageLoop::current(), message_loop_
);
110 DCHECK_EQ(state_
, IS_UNINITIALIZED
);
114 local_address_
= local_address
;
115 remote_address_
= remote_address
;
118 net::IPEndPoint local_endpoint
;
119 if (!jingle_glue::SocketAddressToIPEndPoint(local_address
, &local_endpoint
)) {
123 net::IPEndPoint remote_endpoint
;
124 if (!jingle_glue::SocketAddressToIPEndPoint(
125 remote_address
, &remote_endpoint
)) {
129 client_
->Init(type
, local_endpoint
, remote_endpoint
, this);
134 void IpcPacketSocket::InitAcceptedTcp(
135 P2PSocketClient
* client
,
136 const talk_base::SocketAddress
& local_address
,
137 const talk_base::SocketAddress
& remote_address
) {
138 DCHECK_EQ(MessageLoop::current(), message_loop_
);
139 DCHECK_EQ(state_
, IS_UNINITIALIZED
);
142 local_address_
= local_address
;
143 remote_address_
= remote_address
;
145 client_
->set_delegate(this);
148 // talk_base::AsyncPacketSocket interface.
149 talk_base::SocketAddress
IpcPacketSocket::GetLocalAddress() const {
150 DCHECK_EQ(MessageLoop::current(), message_loop_
);
151 return local_address_
;
154 talk_base::SocketAddress
IpcPacketSocket::GetRemoteAddress() const {
155 DCHECK_EQ(MessageLoop::current(), message_loop_
);
156 return remote_address_
;
159 int IpcPacketSocket::Send(const void *data
, size_t data_size
) {
160 DCHECK_EQ(MessageLoop::current(), message_loop_
);
161 return SendTo(data
, data_size
, remote_address_
);
164 int IpcPacketSocket::SendTo(const void *data
, size_t data_size
,
165 const talk_base::SocketAddress
& address
) {
166 DCHECK_EQ(MessageLoop::current(), message_loop_
);
169 case IS_UNINITIALIZED
:
179 // Continue sending the packet.
183 const char* data_char
= reinterpret_cast<const char*>(data
);
184 std::vector
<char> data_vector(data_char
, data_char
+ data_size
);
186 net::IPEndPoint address_chrome
;
187 if (!jingle_glue::SocketAddressToIPEndPoint(address
, &address_chrome
)) {
188 // Just drop the packet if we failed to convert the address.
192 client_
->Send(address_chrome
, data_vector
);
194 // Fake successful send. The caller ignores result anyway.
198 int IpcPacketSocket::Close() {
199 DCHECK_EQ(MessageLoop::current(), message_loop_
);
207 talk_base::AsyncPacketSocket::State
IpcPacketSocket::GetState() const {
208 DCHECK_EQ(MessageLoop::current(), message_loop_
);
211 case IS_UNINITIALIZED
:
216 return STATE_BINDING
;
219 if (type_
== P2P_SOCKET_TCP_CLIENT
) {
220 return STATE_CONNECTED
;
234 int IpcPacketSocket::GetOption(talk_base::Socket::Option opt
, int* value
) {
235 // We don't support socket options for IPC sockets.
239 int IpcPacketSocket::SetOption(talk_base::Socket::Option opt
, int value
) {
240 // We don't support socket options for IPC sockets.
242 // TODO(sergeyu): Make sure we set proper socket options on the
247 int IpcPacketSocket::GetError() const {
248 DCHECK_EQ(MessageLoop::current(), message_loop_
);
252 void IpcPacketSocket::SetError(int error
) {
253 DCHECK_EQ(MessageLoop::current(), message_loop_
);
257 void IpcPacketSocket::OnOpen(const net::IPEndPoint
& address
) {
258 DCHECK_EQ(MessageLoop::current(), message_loop_
);
260 if (!jingle_glue::IPEndPointToSocketAddress(address
, &local_address_
)) {
261 // Always expect correct IPv4 address to be allocated.
269 SignalAddressReady(this, local_address_
);
270 if (type_
== P2P_SOCKET_TCP_CLIENT
)
274 void IpcPacketSocket::OnIncomingTcpConnection(
275 const net::IPEndPoint
& address
,
276 P2PSocketClient
* client
) {
277 DCHECK_EQ(MessageLoop::current(), message_loop_
);
279 scoped_ptr
<IpcPacketSocket
> socket(new IpcPacketSocket());
281 talk_base::SocketAddress remote_address
;
282 if (!jingle_glue::IPEndPointToSocketAddress(address
, &remote_address
)) {
283 // Always expect correct IPv4 address to be allocated.
286 socket
->InitAcceptedTcp(client
, local_address_
, remote_address
);
287 SignalNewConnection(this, socket
.release());
290 void IpcPacketSocket::OnError() {
291 DCHECK_EQ(MessageLoop::current(), message_loop_
);
293 error_
= ECONNABORTED
;
296 void IpcPacketSocket::OnDataReceived(const net::IPEndPoint
& address
,
297 const std::vector
<char>& data
) {
298 DCHECK_EQ(MessageLoop::current(), message_loop_
);
300 talk_base::SocketAddress address_lj
;
301 if (!jingle_glue::IPEndPointToSocketAddress(address
, &address_lj
)) {
302 // We should always be able to convert address here because we
303 // don't expect IPv6 address on IPv4 connections.
308 SignalReadPacket(this, &data
[0], data
.size(), address_lj
);
313 IpcPacketSocketFactory::IpcPacketSocketFactory(
314 P2PSocketDispatcher
* socket_dispatcher
)
315 : socket_dispatcher_(socket_dispatcher
) {
318 IpcPacketSocketFactory::~IpcPacketSocketFactory() {
321 talk_base::AsyncPacketSocket
* IpcPacketSocketFactory::CreateUdpSocket(
322 const talk_base::SocketAddress
& local_address
, int min_port
, int max_port
) {
323 talk_base::SocketAddress crome_address
;
324 P2PSocketClient
* socket_client
= new P2PSocketClient(socket_dispatcher_
);
325 scoped_ptr
<IpcPacketSocket
> socket(new IpcPacketSocket());
326 // TODO(sergeyu): Respect local_address and port limits here (need
327 // to pass them over IPC channel to the browser).
328 if (!socket
->Init(P2P_SOCKET_UDP
, socket_client
,
329 local_address
, talk_base::SocketAddress())) {
332 return socket
.release();
335 talk_base::AsyncPacketSocket
* IpcPacketSocketFactory::CreateServerTcpSocket(
336 const talk_base::SocketAddress
& local_address
, int min_port
, int max_port
,
338 // TODO(sergeyu): Implement SSL support.
342 talk_base::SocketAddress crome_address
;
343 P2PSocketClient
* socket_client
= new P2PSocketClient(socket_dispatcher_
);
344 scoped_ptr
<IpcPacketSocket
> socket(new IpcPacketSocket());
345 if (!socket
->Init(P2P_SOCKET_TCP_SERVER
, socket_client
, local_address
,
346 talk_base::SocketAddress())) {
349 return socket
.release();
352 talk_base::AsyncPacketSocket
* IpcPacketSocketFactory::CreateClientTcpSocket(
353 const talk_base::SocketAddress
& local_address
,
354 const talk_base::SocketAddress
& remote_address
,
355 const talk_base::ProxyInfo
& proxy_info
,
356 const std::string
& user_agent
, bool ssl
) {
357 // TODO(sergeyu): Implement SSL support.
361 talk_base::SocketAddress crome_address
;
362 P2PSocketClient
* socket_client
= new P2PSocketClient(socket_dispatcher_
);
363 scoped_ptr
<IpcPacketSocket
> socket(new IpcPacketSocket());
364 if (!socket
->Init(P2P_SOCKET_TCP_CLIENT
, socket_client
, local_address
,
367 return socket
.release();
370 } // namespace content