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