| // 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.h" |
| #include "jingle/glue/utils.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) { |
| DCHECK(CalledOnValidThread()); |
| return SendTo(data, data_size, remote_address_); |
| } |
| |
| int FakeUDPPacketSocket::SendTo(const void *data, size_t data_size, |
| const talk_base::SocketAddress& address) { |
| 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); |
| } |
| |
| FakeSocketManager::FakeSocketManager() |
| : message_loop_(MessageLoop::current()) { |
| } |
| |
| FakeSocketManager::~FakeSocketManager() { } |
| |
| void FakeSocketManager::SendPacket(const net::IPEndPoint& from, |
| const net::IPEndPoint& to, |
| const std::vector<char>& data) { |
| DCHECK_EQ(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(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(MessageLoop::current(), message_loop_); |
| |
| endpoints_[socket_factory->endpoint()] = socket_factory; |
| } |
| |
| void FakeSocketManager::RemoveSocket(FakeUDPPacketSocket* socket_factory) { |
| DCHECK_EQ(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_, net::IPEndPoint(address_, ++last_allocated_port_)); |
| } |
| |
| talk_base::AsyncPacketSocket* FakeSocketFactory::CreateServerTcpSocket( |
| const talk_base::SocketAddress& local_address, int min_port, int max_port, |
| bool ssl) { |
| // 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, |
| bool ssl) { |
| // TODO(sergeyu): Implement fake TCP sockets. |
| NOTIMPLEMENTED(); |
| return NULL; |
| } |
| |
| } // namespace jingle_glue |