• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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