1 // Copyright 2013 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 "content/renderer/p2p/socket_client_impl.h"
6
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop_proxy.h"
9 #include "base/time/time.h"
10 #include "content/common/p2p_messages.h"
11 #include "content/renderer/p2p/socket_client_delegate.h"
12 #include "content/renderer/p2p/socket_dispatcher.h"
13 #include "content/renderer/render_thread_impl.h"
14 #include "crypto/random.h"
15
16 namespace {
17
GetUniqueId(uint32 random_socket_id,uint32 packet_id)18 uint64 GetUniqueId(uint32 random_socket_id, uint32 packet_id) {
19 uint64 uid = random_socket_id;
20 uid <<= 32;
21 uid |= packet_id;
22 return uid;
23 }
24
25 } // namespace
26
27 namespace content {
28
P2PSocketClientImpl(P2PSocketDispatcher * dispatcher)29 P2PSocketClientImpl::P2PSocketClientImpl(P2PSocketDispatcher* dispatcher)
30 : dispatcher_(dispatcher),
31 ipc_message_loop_(dispatcher->message_loop()),
32 delegate_message_loop_(base::MessageLoopProxy::current()),
33 socket_id_(0), delegate_(NULL),
34 state_(STATE_UNINITIALIZED),
35 random_socket_id_(0),
36 next_packet_id_(0) {
37 crypto::RandBytes(&random_socket_id_, sizeof(random_socket_id_));
38 }
39
~P2PSocketClientImpl()40 P2PSocketClientImpl::~P2PSocketClientImpl() {
41 CHECK(state_ == STATE_CLOSED || state_ == STATE_UNINITIALIZED);
42 }
43
Init(P2PSocketType type,const net::IPEndPoint & local_address,const P2PHostAndIPEndPoint & remote_address,P2PSocketClientDelegate * delegate)44 void P2PSocketClientImpl::Init(
45 P2PSocketType type,
46 const net::IPEndPoint& local_address,
47 const P2PHostAndIPEndPoint& remote_address,
48 P2PSocketClientDelegate* delegate) {
49 DCHECK(delegate_message_loop_->BelongsToCurrentThread());
50 DCHECK(delegate);
51 // |delegate_| is only accessesed on |delegate_message_loop_|.
52 delegate_ = delegate;
53
54 ipc_message_loop_->PostTask(
55 FROM_HERE, base::Bind(&P2PSocketClientImpl::DoInit,
56 this,
57 type,
58 local_address,
59 remote_address));
60 }
61
DoInit(P2PSocketType type,const net::IPEndPoint & local_address,const P2PHostAndIPEndPoint & remote_address)62 void P2PSocketClientImpl::DoInit(P2PSocketType type,
63 const net::IPEndPoint& local_address,
64 const P2PHostAndIPEndPoint& remote_address) {
65 DCHECK_EQ(state_, STATE_UNINITIALIZED);
66 state_ = STATE_OPENING;
67 socket_id_ = dispatcher_->RegisterClient(this);
68 dispatcher_->SendP2PMessage(new P2PHostMsg_CreateSocket(
69 type, socket_id_, local_address, remote_address));
70 }
71
SendWithDscp(const net::IPEndPoint & address,const std::vector<char> & data,const rtc::PacketOptions & options)72 void P2PSocketClientImpl::SendWithDscp(
73 const net::IPEndPoint& address,
74 const std::vector<char>& data,
75 const rtc::PacketOptions& options) {
76 if (!ipc_message_loop_->BelongsToCurrentThread()) {
77 ipc_message_loop_->PostTask(
78 FROM_HERE, base::Bind(
79 &P2PSocketClientImpl::SendWithDscp, this, address, data, options));
80 return;
81 }
82
83 // Can send data only when the socket is open.
84 DCHECK(state_ == STATE_OPEN || state_ == STATE_ERROR);
85 if (state_ == STATE_OPEN) {
86 uint64 unique_id = GetUniqueId(random_socket_id_, ++next_packet_id_);
87 TRACE_EVENT_ASYNC_BEGIN0("p2p", "Send", unique_id);
88 dispatcher_->SendP2PMessage(new P2PHostMsg_Send(socket_id_, address, data,
89 options, unique_id));
90 }
91 }
92
Send(const net::IPEndPoint & address,const std::vector<char> & data)93 void P2PSocketClientImpl::Send(const net::IPEndPoint& address,
94 const std::vector<char>& data) {
95 rtc::PacketOptions options(rtc::DSCP_DEFAULT);
96 SendWithDscp(address, data, options);
97 }
98
SetOption(P2PSocketOption option,int value)99 void P2PSocketClientImpl::SetOption(P2PSocketOption option,
100 int value) {
101 if (!ipc_message_loop_->BelongsToCurrentThread()) {
102 ipc_message_loop_->PostTask(
103 FROM_HERE, base::Bind(
104 &P2PSocketClientImpl::SetOption, this, option, value));
105 return;
106 }
107
108 DCHECK(state_ == STATE_OPEN || state_ == STATE_ERROR);
109 if (state_ == STATE_OPEN) {
110 dispatcher_->SendP2PMessage(new P2PHostMsg_SetOption(socket_id_,
111 option, value));
112 }
113 }
114
Close()115 void P2PSocketClientImpl::Close() {
116 DCHECK(delegate_message_loop_->BelongsToCurrentThread());
117
118 delegate_ = NULL;
119
120 ipc_message_loop_->PostTask(
121 FROM_HERE, base::Bind(&P2PSocketClientImpl::DoClose, this));
122 }
123
DoClose()124 void P2PSocketClientImpl::DoClose() {
125 DCHECK(ipc_message_loop_->BelongsToCurrentThread());
126 if (dispatcher_) {
127 if (state_ == STATE_OPEN || state_ == STATE_OPENING ||
128 state_ == STATE_ERROR) {
129 dispatcher_->SendP2PMessage(new P2PHostMsg_DestroySocket(socket_id_));
130 }
131 dispatcher_->UnregisterClient(socket_id_);
132 }
133
134 state_ = STATE_CLOSED;
135 }
136
GetSocketID() const137 int P2PSocketClientImpl::GetSocketID() const {
138 return socket_id_;
139 }
140
SetDelegate(P2PSocketClientDelegate * delegate)141 void P2PSocketClientImpl::SetDelegate(P2PSocketClientDelegate* delegate) {
142 DCHECK(delegate_message_loop_->BelongsToCurrentThread());
143 delegate_ = delegate;
144 }
145
OnSocketCreated(const net::IPEndPoint & local_address,const net::IPEndPoint & remote_address)146 void P2PSocketClientImpl::OnSocketCreated(
147 const net::IPEndPoint& local_address,
148 const net::IPEndPoint& remote_address) {
149 DCHECK(ipc_message_loop_->BelongsToCurrentThread());
150 DCHECK_EQ(state_, STATE_OPENING);
151 state_ = STATE_OPEN;
152
153 delegate_message_loop_->PostTask(
154 FROM_HERE,
155 base::Bind(&P2PSocketClientImpl::DeliverOnSocketCreated, this,
156 local_address, remote_address));
157 }
158
DeliverOnSocketCreated(const net::IPEndPoint & local_address,const net::IPEndPoint & remote_address)159 void P2PSocketClientImpl::DeliverOnSocketCreated(
160 const net::IPEndPoint& local_address,
161 const net::IPEndPoint& remote_address) {
162 DCHECK(delegate_message_loop_->BelongsToCurrentThread());
163 if (delegate_)
164 delegate_->OnOpen(local_address, remote_address);
165 }
166
OnIncomingTcpConnection(const net::IPEndPoint & address)167 void P2PSocketClientImpl::OnIncomingTcpConnection(
168 const net::IPEndPoint& address) {
169 DCHECK(ipc_message_loop_->BelongsToCurrentThread());
170 DCHECK_EQ(state_, STATE_OPEN);
171
172 scoped_refptr<P2PSocketClientImpl> new_client =
173 new P2PSocketClientImpl(dispatcher_);
174 new_client->socket_id_ = dispatcher_->RegisterClient(new_client.get());
175 new_client->state_ = STATE_OPEN;
176 new_client->delegate_message_loop_ = delegate_message_loop_;
177
178 dispatcher_->SendP2PMessage(new P2PHostMsg_AcceptIncomingTcpConnection(
179 socket_id_, address, new_client->socket_id_));
180
181 delegate_message_loop_->PostTask(
182 FROM_HERE, base::Bind(
183 &P2PSocketClientImpl::DeliverOnIncomingTcpConnection,
184 this, address, new_client));
185 }
186
DeliverOnIncomingTcpConnection(const net::IPEndPoint & address,scoped_refptr<P2PSocketClient> new_client)187 void P2PSocketClientImpl::DeliverOnIncomingTcpConnection(
188 const net::IPEndPoint& address,
189 scoped_refptr<P2PSocketClient> new_client) {
190 DCHECK(delegate_message_loop_->BelongsToCurrentThread());
191 if (delegate_) {
192 delegate_->OnIncomingTcpConnection(address, new_client.get());
193 } else {
194 // Just close the socket if there is no delegate to accept it.
195 new_client->Close();
196 }
197 }
198
OnSendComplete()199 void P2PSocketClientImpl::OnSendComplete() {
200 DCHECK(ipc_message_loop_->BelongsToCurrentThread());
201
202 delegate_message_loop_->PostTask(
203 FROM_HERE, base::Bind(&P2PSocketClientImpl::DeliverOnSendComplete, this));
204 }
205
DeliverOnSendComplete()206 void P2PSocketClientImpl::DeliverOnSendComplete() {
207 DCHECK(delegate_message_loop_->BelongsToCurrentThread());
208 if (delegate_)
209 delegate_->OnSendComplete();
210 }
211
OnError()212 void P2PSocketClientImpl::OnError() {
213 DCHECK(ipc_message_loop_->BelongsToCurrentThread());
214 state_ = STATE_ERROR;
215
216 delegate_message_loop_->PostTask(
217 FROM_HERE, base::Bind(&P2PSocketClientImpl::DeliverOnError, this));
218 }
219
DeliverOnError()220 void P2PSocketClientImpl::DeliverOnError() {
221 DCHECK(delegate_message_loop_->BelongsToCurrentThread());
222 if (delegate_)
223 delegate_->OnError();
224 }
225
OnDataReceived(const net::IPEndPoint & address,const std::vector<char> & data,const base::TimeTicks & timestamp)226 void P2PSocketClientImpl::OnDataReceived(const net::IPEndPoint& address,
227 const std::vector<char>& data,
228 const base::TimeTicks& timestamp) {
229 DCHECK(ipc_message_loop_->BelongsToCurrentThread());
230 DCHECK_EQ(STATE_OPEN, state_);
231 delegate_message_loop_->PostTask(
232 FROM_HERE,
233 base::Bind(&P2PSocketClientImpl::DeliverOnDataReceived,
234 this,
235 address,
236 data,
237 timestamp));
238 }
239
DeliverOnDataReceived(const net::IPEndPoint & address,const std::vector<char> & data,const base::TimeTicks & timestamp)240 void P2PSocketClientImpl::DeliverOnDataReceived(
241 const net::IPEndPoint& address, const std::vector<char>& data,
242 const base::TimeTicks& timestamp) {
243 DCHECK(delegate_message_loop_->BelongsToCurrentThread());
244 if (delegate_)
245 delegate_->OnDataReceived(address, data, timestamp);
246 }
247
Detach()248 void P2PSocketClientImpl::Detach() {
249 DCHECK(ipc_message_loop_->BelongsToCurrentThread());
250 dispatcher_ = NULL;
251 OnError();
252 }
253
254 } // namespace content
255