1// Copyright (c) 2011 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 "jingle/glue/fake_socket_factory.h"
6
7#include "base/bind.h"
8#include "base/message_loop/message_loop.h"
9#include "jingle/glue/utils.h"
10#include "third_party/libjingle/source/talk/base/asyncpacketsocket.h"
11#include "third_party/libjingle/source/talk/base/asyncsocket.h"
12
13namespace jingle_glue {
14
15FakeUDPPacketSocket::FakeUDPPacketSocket(FakeSocketManager* fake_socket_manager,
16                                         const net::IPEndPoint& address)
17    : fake_socket_manager_(fake_socket_manager),
18      endpoint_(address), state_(IS_OPEN), error_(0) {
19  CHECK(IPEndPointToSocketAddress(endpoint_, &local_address_));
20  fake_socket_manager_->AddSocket(this);
21}
22
23FakeUDPPacketSocket::~FakeUDPPacketSocket() {
24  fake_socket_manager_->RemoveSocket(this);
25}
26
27talk_base::SocketAddress FakeUDPPacketSocket::GetLocalAddress() const {
28  DCHECK(CalledOnValidThread());
29  return local_address_;
30}
31
32talk_base::SocketAddress FakeUDPPacketSocket::GetRemoteAddress() const {
33  DCHECK(CalledOnValidThread());
34  return remote_address_;
35}
36
37int FakeUDPPacketSocket::Send(const void *data, size_t data_size,
38                              talk_base::DiffServCodePoint dscp) {
39  DCHECK(CalledOnValidThread());
40  return SendTo(data, data_size, remote_address_, dscp);
41}
42
43int FakeUDPPacketSocket::SendTo(const void *data, size_t data_size,
44                                const talk_base::SocketAddress& address,
45                                talk_base::DiffServCodePoint dscp) {
46  DCHECK(CalledOnValidThread());
47
48  if (state_ == IS_CLOSED) {
49    return ENOTCONN;
50  }
51
52  net::IPEndPoint destination;
53  if (!SocketAddressToIPEndPoint(address, &destination)) {
54    return EINVAL;
55  }
56
57  const char* data_char = reinterpret_cast<const char*>(data);
58  std::vector<char> data_vector(data_char, data_char + data_size);
59
60  fake_socket_manager_->SendPacket(endpoint_, destination, data_vector);
61
62  return data_size;
63}
64
65int FakeUDPPacketSocket::Close() {
66  DCHECK(CalledOnValidThread());
67  state_ = IS_CLOSED;
68  return 0;
69}
70
71talk_base::AsyncPacketSocket::State FakeUDPPacketSocket::GetState() const {
72  DCHECK(CalledOnValidThread());
73
74  switch (state_) {
75    case IS_OPEN:
76      return STATE_BOUND;
77    case IS_CLOSED:
78      return STATE_CLOSED;
79  }
80
81  NOTREACHED();
82  return STATE_CLOSED;
83}
84
85int FakeUDPPacketSocket::GetOption(talk_base::Socket::Option opt, int* value) {
86  DCHECK(CalledOnValidThread());
87  return -1;
88}
89
90int FakeUDPPacketSocket::SetOption(talk_base::Socket::Option opt, int value) {
91  DCHECK(CalledOnValidThread());
92  return -1;
93}
94
95int FakeUDPPacketSocket::GetError() const {
96  DCHECK(CalledOnValidThread());
97  return error_;
98}
99
100void FakeUDPPacketSocket::SetError(int error) {
101  DCHECK(CalledOnValidThread());
102  error_ = error;
103}
104
105void FakeUDPPacketSocket::DeliverPacket(const net::IPEndPoint& from,
106                                        const std::vector<char>& data) {
107  DCHECK(CalledOnValidThread());
108
109  talk_base::SocketAddress address;
110  if (!jingle_glue::IPEndPointToSocketAddress(from, &address)) {
111    // We should always be able to convert address here because we
112    // don't expect IPv6 address on IPv4 connections.
113    NOTREACHED();
114    return;
115  }
116
117  SignalReadPacket(this, &data[0], data.size(), address,
118                   talk_base::CreatePacketTime(0));
119}
120
121FakeSocketManager::FakeSocketManager()
122    : message_loop_(base::MessageLoop::current()) {}
123
124FakeSocketManager::~FakeSocketManager() { }
125
126void FakeSocketManager::SendPacket(const net::IPEndPoint& from,
127                                   const net::IPEndPoint& to,
128                                   const std::vector<char>& data) {
129  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
130
131  message_loop_->PostTask(
132      FROM_HERE,
133      base::Bind(&FakeSocketManager::DeliverPacket, this, from, to, data));
134}
135
136void FakeSocketManager::DeliverPacket(const net::IPEndPoint& from,
137                                      const net::IPEndPoint& to,
138                                      const std::vector<char>& data) {
139  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
140
141  std::map<net::IPEndPoint, FakeUDPPacketSocket*>::iterator it =
142      endpoints_.find(to);
143  if (it == endpoints_.end()) {
144    LOG(WARNING) << "Dropping packet with unknown destination: "
145                 << to.ToString();
146    return;
147  }
148  it->second->DeliverPacket(from, data);
149}
150
151void FakeSocketManager::AddSocket(FakeUDPPacketSocket* socket_factory) {
152  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
153
154  endpoints_[socket_factory->endpoint()] = socket_factory;
155}
156
157void FakeSocketManager::RemoveSocket(FakeUDPPacketSocket* socket_factory) {
158  DCHECK_EQ(base::MessageLoop::current(), message_loop_);
159
160  endpoints_.erase(socket_factory->endpoint());
161}
162
163FakeSocketFactory::FakeSocketFactory(FakeSocketManager* socket_manager,
164                                     const net::IPAddressNumber& address)
165    : socket_manager_(socket_manager),
166      address_(address),
167      last_allocated_port_(0) {
168}
169
170FakeSocketFactory::~FakeSocketFactory() {
171}
172
173talk_base::AsyncPacketSocket* FakeSocketFactory::CreateUdpSocket(
174    const talk_base::SocketAddress& local_address, int min_port, int max_port) {
175  CHECK_EQ(min_port, 0);
176  CHECK_EQ(max_port, 0);
177  return new FakeUDPPacketSocket(
178      socket_manager_.get(), net::IPEndPoint(address_, ++last_allocated_port_));
179}
180
181talk_base::AsyncPacketSocket* FakeSocketFactory::CreateServerTcpSocket(
182    const talk_base::SocketAddress& local_address, int min_port, int max_port,
183    int opts) {
184  // TODO(sergeyu): Implement fake TCP sockets.
185  NOTIMPLEMENTED();
186  return NULL;
187}
188
189talk_base::AsyncPacketSocket* FakeSocketFactory::CreateClientTcpSocket(
190    const talk_base::SocketAddress& local_address,
191    const talk_base::SocketAddress& remote_address,
192    const talk_base::ProxyInfo& proxy_info, const std::string& user_agent,
193    int opts) {
194  // TODO(sergeyu): Implement fake TCP sockets.
195  NOTIMPLEMENTED();
196  return NULL;
197}
198
199}  // namespace jingle_glue
200