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. 4 5#include "content/browser/renderer_host/p2p/socket_host_tcp_server.h" 6 7#include "base/bind.h" 8#include "base/bind_helpers.h" 9#include "base/stl_util.h" 10#include "content/browser/renderer_host/p2p/socket_host_tcp.h" 11#include "content/common/p2p_messages.h" 12#include "net/base/address_list.h" 13#include "net/base/net_errors.h" 14#include "net/base/net_util.h" 15#include "net/socket/stream_socket.h" 16 17namespace { 18const int kListenBacklog = 5; 19} // namespace 20 21namespace content { 22 23P2PSocketHostTcpServer::P2PSocketHostTcpServer(IPC::Sender* message_sender, 24 int socket_id, 25 P2PSocketType client_type) 26 : P2PSocketHost(message_sender, socket_id, P2PSocketHost::TCP), 27 client_type_(client_type), 28 socket_(new net::TCPServerSocket(NULL, net::NetLog::Source())), 29 accept_callback_(base::Bind(&P2PSocketHostTcpServer::OnAccepted, 30 base::Unretained(this))) { 31} 32 33P2PSocketHostTcpServer::~P2PSocketHostTcpServer() { 34 STLDeleteContainerPairSecondPointers(accepted_sockets_.begin(), 35 accepted_sockets_.end()); 36 37 if (state_ == STATE_OPEN) { 38 DCHECK(socket_.get()); 39 socket_.reset(); 40 } 41} 42 43bool P2PSocketHostTcpServer::Init(const net::IPEndPoint& local_address, 44 const P2PHostAndIPEndPoint& remote_address) { 45 DCHECK_EQ(state_, STATE_UNINITIALIZED); 46 47 int result = socket_->Listen(local_address, kListenBacklog); 48 if (result < 0) { 49 LOG(ERROR) << "Listen() failed: " << result; 50 OnError(); 51 return false; 52 } 53 54 result = socket_->GetLocalAddress(&local_address_); 55 if (result < 0) { 56 LOG(ERROR) << "P2PSocketHostTcpServer::Init(): can't to get local address: " 57 << result; 58 OnError(); 59 return false; 60 } 61 VLOG(1) << "Local address: " << local_address_.ToString(); 62 63 state_ = STATE_OPEN; 64 // NOTE: Remote address can be empty as socket is just listening 65 // in this state. 66 message_sender_->Send(new P2PMsg_OnSocketCreated( 67 id_, local_address_, remote_address.ip_address)); 68 DoAccept(); 69 return true; 70} 71 72void P2PSocketHostTcpServer::OnError() { 73 socket_.reset(); 74 75 if (state_ == STATE_UNINITIALIZED || state_ == STATE_OPEN) 76 message_sender_->Send(new P2PMsg_OnError(id_)); 77 78 state_ = STATE_ERROR; 79} 80 81void P2PSocketHostTcpServer::DoAccept() { 82 while (true) { 83 int result = socket_->Accept(&accept_socket_, accept_callback_); 84 if (result == net::ERR_IO_PENDING) { 85 break; 86 } else { 87 HandleAcceptResult(result); 88 } 89 } 90} 91 92void P2PSocketHostTcpServer::HandleAcceptResult(int result) { 93 if (result < 0) { 94 if (result != net::ERR_IO_PENDING) 95 OnError(); 96 return; 97 } 98 99 net::IPEndPoint address; 100 if (accept_socket_->GetPeerAddress(&address) != net::OK) { 101 LOG(ERROR) << "Failed to get address of an accepted socket."; 102 accept_socket_.reset(); 103 return; 104 } 105 AcceptedSocketsMap::iterator it = accepted_sockets_.find(address); 106 if (it != accepted_sockets_.end()) 107 delete it->second; 108 109 accepted_sockets_[address] = accept_socket_.release(); 110 message_sender_->Send( 111 new P2PMsg_OnIncomingTcpConnection(id_, address)); 112} 113 114void P2PSocketHostTcpServer::OnAccepted(int result) { 115 HandleAcceptResult(result); 116 if (result == net::OK) 117 DoAccept(); 118} 119 120void P2PSocketHostTcpServer::Send(const net::IPEndPoint& to, 121 const std::vector<char>& data, 122 const rtc::PacketOptions& options, 123 uint64 packet_id) { 124 NOTREACHED(); 125 OnError(); 126} 127 128P2PSocketHost* P2PSocketHostTcpServer::AcceptIncomingTcpConnection( 129 const net::IPEndPoint& remote_address, int id) { 130 AcceptedSocketsMap::iterator it = accepted_sockets_.find(remote_address); 131 if (it == accepted_sockets_.end()) 132 return NULL; 133 134 net::StreamSocket* socket = it->second; 135 accepted_sockets_.erase(it); 136 137 scoped_ptr<P2PSocketHostTcpBase> result; 138 if (client_type_ == P2P_SOCKET_TCP_CLIENT) { 139 result.reset(new P2PSocketHostTcp(message_sender_, id, client_type_, NULL)); 140 } else { 141 result.reset( 142 new P2PSocketHostStunTcp(message_sender_, id, client_type_, NULL)); 143 } 144 if (!result->InitAccepted(remote_address, socket)) 145 return NULL; 146 return result.release(); 147} 148 149bool P2PSocketHostTcpServer::SetOption(P2PSocketOption option, 150 int value) { 151 // Currently we don't have use case tcp server sockets are used for p2p. 152 return false; 153} 154 155} // namespace content 156