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