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
16namespace {
17
18uint64 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
27namespace content {
28
29P2PSocketClientImpl::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
40P2PSocketClientImpl::~P2PSocketClientImpl() {
41  CHECK(state_ == STATE_CLOSED || state_ == STATE_UNINITIALIZED);
42}
43
44void 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
62void 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
72void 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
93void 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
99void 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
115void 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
124void 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
137int P2PSocketClientImpl::GetSocketID() const {
138  return socket_id_;
139}
140
141void P2PSocketClientImpl::SetDelegate(P2PSocketClientDelegate* delegate) {
142  DCHECK(delegate_message_loop_->BelongsToCurrentThread());
143  delegate_ = delegate;
144}
145
146void 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
159void 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
167void 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
187void 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
199void P2PSocketClientImpl::OnSendComplete() {
200  DCHECK(ipc_message_loop_->BelongsToCurrentThread());
201
202  delegate_message_loop_->PostTask(
203      FROM_HERE, base::Bind(&P2PSocketClientImpl::DeliverOnSendComplete, this));
204}
205
206void P2PSocketClientImpl::DeliverOnSendComplete() {
207  DCHECK(delegate_message_loop_->BelongsToCurrentThread());
208  if (delegate_)
209    delegate_->OnSendComplete();
210}
211
212void 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
220void P2PSocketClientImpl::DeliverOnError() {
221  DCHECK(delegate_message_loop_->BelongsToCurrentThread());
222  if (delegate_)
223    delegate_->OnError();
224}
225
226void 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
240void 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
248void P2PSocketClientImpl::Detach() {
249  DCHECK(ipc_message_loop_->BelongsToCurrentThread());
250  dispatcher_ = NULL;
251  OnError();
252}
253
254}  // namespace content
255