// Copyright (c) 2011 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 "jingle/glue/fake_socket_factory.h"
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "jingle/glue/utils.h"
#include "third_party/libjingle/source/talk/base/asyncpacketsocket.h"
#include "third_party/libjingle/source/talk/base/asyncsocket.h"
namespace jingle_glue {
FakeUDPPacketSocket::FakeUDPPacketSocket(FakeSocketManager* fake_socket_manager,
const net::IPEndPoint& address)
: fake_socket_manager_(fake_socket_manager),
endpoint_(address), state_(IS_OPEN), error_(0) {
CHECK(IPEndPointToSocketAddress(endpoint_, &local_address_));
fake_socket_manager_->AddSocket(this);
}
FakeUDPPacketSocket::~FakeUDPPacketSocket() {
fake_socket_manager_->RemoveSocket(this);
}
talk_base::SocketAddress FakeUDPPacketSocket::GetLocalAddress() const {
DCHECK(CalledOnValidThread());
return local_address_;
}
talk_base::SocketAddress FakeUDPPacketSocket::GetRemoteAddress() const {
DCHECK(CalledOnValidThread());
return remote_address_;
}
int FakeUDPPacketSocket::Send(const void *data, size_t data_size,
talk_base::DiffServCodePoint dscp) {
DCHECK(CalledOnValidThread());
return SendTo(data, data_size, remote_address_, dscp);
}
int FakeUDPPacketSocket::SendTo(const void *data, size_t data_size,
const talk_base::SocketAddress& address,
talk_base::DiffServCodePoint dscp) {
DCHECK(CalledOnValidThread());
if (state_ == IS_CLOSED) {
return ENOTCONN;
}
net::IPEndPoint destination;
if (!SocketAddressToIPEndPoint(address, &destination)) {
return EINVAL;
}
const char* data_char = reinterpret_cast<const char*>(data);
std::vector<char> data_vector(data_char, data_char + data_size);
fake_socket_manager_->SendPacket(endpoint_, destination, data_vector);
return data_size;
}
int FakeUDPPacketSocket::Close() {
DCHECK(CalledOnValidThread());
state_ = IS_CLOSED;
return 0;
}
talk_base::AsyncPacketSocket::State FakeUDPPacketSocket::GetState() const {
DCHECK(CalledOnValidThread());
switch (state_) {
case IS_OPEN:
return STATE_BOUND;
case IS_CLOSED:
return STATE_CLOSED;
}
NOTREACHED();
return STATE_CLOSED;
}
int FakeUDPPacketSocket::GetOption(talk_base::Socket::Option opt, int* value) {
DCHECK(CalledOnValidThread());
return -1;
}
int FakeUDPPacketSocket::SetOption(talk_base::Socket::Option opt, int value) {
DCHECK(CalledOnValidThread());
return -1;
}
int FakeUDPPacketSocket::GetError() const {
DCHECK(CalledOnValidThread());
return error_;
}
void FakeUDPPacketSocket::SetError(int error) {
DCHECK(CalledOnValidThread());
error_ = error;
}
void FakeUDPPacketSocket::DeliverPacket(const net::IPEndPoint& from,
const std::vector<char>& data) {
DCHECK(CalledOnValidThread());
talk_base::SocketAddress address;
if (!jingle_glue::IPEndPointToSocketAddress(from, &address)) {
// We should always be able to convert address here because we
// don't expect IPv6 address on IPv4 connections.
NOTREACHED();
return;
}
SignalReadPacket(this, &data[0], data.size(), address,
talk_base::CreatePacketTime(0));
}
FakeSocketManager::FakeSocketManager()
: message_loop_(base::MessageLoop::current()) {}
FakeSocketManager::~FakeSocketManager() { }
void FakeSocketManager::SendPacket(const net::IPEndPoint& from,
const net::IPEndPoint& to,
const std::vector<char>& data) {
DCHECK_EQ(base::MessageLoop::current(), message_loop_);
message_loop_->PostTask(
FROM_HERE,
base::Bind(&FakeSocketManager::DeliverPacket, this, from, to, data));
}
void FakeSocketManager::DeliverPacket(const net::IPEndPoint& from,
const net::IPEndPoint& to,
const std::vector<char>& data) {
DCHECK_EQ(base::MessageLoop::current(), message_loop_);
std::map<net::IPEndPoint, FakeUDPPacketSocket*>::iterator it =
endpoints_.find(to);
if (it == endpoints_.end()) {
LOG(WARNING) << "Dropping packet with unknown destination: "
<< to.ToString();
return;
}
it->second->DeliverPacket(from, data);
}
void FakeSocketManager::AddSocket(FakeUDPPacketSocket* socket_factory) {
DCHECK_EQ(base::MessageLoop::current(), message_loop_);
endpoints_[socket_factory->endpoint()] = socket_factory;
}
void FakeSocketManager::RemoveSocket(FakeUDPPacketSocket* socket_factory) {
DCHECK_EQ(base::MessageLoop::current(), message_loop_);
endpoints_.erase(socket_factory->endpoint());
}
FakeSocketFactory::FakeSocketFactory(FakeSocketManager* socket_manager,
const net::IPAddressNumber& address)
: socket_manager_(socket_manager),
address_(address),
last_allocated_port_(0) {
}
FakeSocketFactory::~FakeSocketFactory() {
}
talk_base::AsyncPacketSocket* FakeSocketFactory::CreateUdpSocket(
const talk_base::SocketAddress& local_address, int min_port, int max_port) {
CHECK_EQ(min_port, 0);
CHECK_EQ(max_port, 0);
return new FakeUDPPacketSocket(
socket_manager_.get(), net::IPEndPoint(address_, ++last_allocated_port_));
}
talk_base::AsyncPacketSocket* FakeSocketFactory::CreateServerTcpSocket(
const talk_base::SocketAddress& local_address, int min_port, int max_port,
int opts) {
// TODO(sergeyu): Implement fake TCP sockets.
NOTIMPLEMENTED();
return NULL;
}
talk_base::AsyncPacketSocket* FakeSocketFactory::CreateClientTcpSocket(
const talk_base::SocketAddress& local_address,
const talk_base::SocketAddress& remote_address,
const talk_base::ProxyInfo& proxy_info, const std::string& user_agent,
int opts) {
// TODO(sergeyu): Implement fake TCP sockets.
NOTIMPLEMENTED();
return NULL;
}
} // namespace jingle_glue