1// Copyright 2014 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 "remoting/protocol/fake_datagram_socket.h"
6
7#include "base/bind.h"
8#include "base/single_thread_task_runner.h"
9#include "base/thread_task_runner_handle.h"
10#include "net/base/address_list.h"
11#include "net/base/io_buffer.h"
12#include "net/base/net_errors.h"
13#include "net/base/net_util.h"
14#include "testing/gtest/include/gtest/gtest.h"
15
16namespace remoting {
17namespace protocol {
18
19FakeDatagramSocket::FakeDatagramSocket()
20    : input_pos_(0),
21      task_runner_(base::ThreadTaskRunnerHandle::Get()),
22      weak_factory_(this) {
23}
24
25FakeDatagramSocket::~FakeDatagramSocket() {
26  EXPECT_TRUE(task_runner_->BelongsToCurrentThread());
27}
28
29void FakeDatagramSocket::AppendInputPacket(const std::string& data) {
30  EXPECT_TRUE(task_runner_->BelongsToCurrentThread());
31  input_packets_.push_back(data);
32
33  // Complete pending read if any.
34  if (!read_callback_.is_null()) {
35    DCHECK_EQ(input_pos_, static_cast<int>(input_packets_.size()) - 1);
36    int result = CopyReadData(read_buffer_.get(), read_buffer_size_);
37    read_buffer_ = NULL;
38
39    net::CompletionCallback callback = read_callback_;
40    read_callback_.Reset();
41    callback.Run(result);
42  }
43}
44
45void FakeDatagramSocket::PairWith(FakeDatagramSocket* peer_socket) {
46  EXPECT_TRUE(task_runner_->BelongsToCurrentThread());
47  peer_socket_ = peer_socket->GetWeakPtr();
48  peer_socket->peer_socket_ = GetWeakPtr();
49}
50
51base::WeakPtr<FakeDatagramSocket> FakeDatagramSocket::GetWeakPtr() {
52  return weak_factory_.GetWeakPtr();
53}
54
55int FakeDatagramSocket::Read(net::IOBuffer* buf, int buf_len,
56                             const net::CompletionCallback& callback) {
57  EXPECT_TRUE(task_runner_->BelongsToCurrentThread());
58  if (input_pos_ < static_cast<int>(input_packets_.size())) {
59    return CopyReadData(buf, buf_len);
60  } else {
61    read_buffer_ = buf;
62    read_buffer_size_ = buf_len;
63    read_callback_ = callback;
64    return net::ERR_IO_PENDING;
65  }
66}
67
68int FakeDatagramSocket::Write(net::IOBuffer* buf, int buf_len,
69                         const net::CompletionCallback& callback) {
70  EXPECT_TRUE(task_runner_->BelongsToCurrentThread());
71  written_packets_.push_back(std::string());
72  written_packets_.back().assign(buf->data(), buf->data() + buf_len);
73
74  if (peer_socket_.get()) {
75    task_runner_->PostTask(
76        FROM_HERE,
77        base::Bind(&FakeDatagramSocket::AppendInputPacket,
78                   peer_socket_,
79                   std::string(buf->data(), buf->data() + buf_len)));
80  }
81
82  return buf_len;
83}
84
85int FakeDatagramSocket::SetReceiveBufferSize(int32 size) {
86  NOTIMPLEMENTED();
87  return net::ERR_NOT_IMPLEMENTED;
88}
89
90int FakeDatagramSocket::SetSendBufferSize(int32 size) {
91  NOTIMPLEMENTED();
92  return net::ERR_NOT_IMPLEMENTED;
93}
94
95int FakeDatagramSocket::CopyReadData(net::IOBuffer* buf, int buf_len) {
96  int size = std::min(
97      buf_len, static_cast<int>(input_packets_[input_pos_].size()));
98  memcpy(buf->data(), &(*input_packets_[input_pos_].begin()), size);
99  ++input_pos_;
100  return size;
101}
102
103FakeDatagramChannelFactory::FakeDatagramChannelFactory()
104    : task_runner_(base::ThreadTaskRunnerHandle::Get()),
105      asynchronous_create_(false),
106      fail_create_(false),
107      weak_factory_(this) {
108}
109
110FakeDatagramChannelFactory::~FakeDatagramChannelFactory() {
111  for (ChannelsMap::iterator it = channels_.begin(); it != channels_.end();
112       ++it) {
113    EXPECT_TRUE(it->second == NULL);
114  }
115}
116
117void FakeDatagramChannelFactory::PairWith(
118    FakeDatagramChannelFactory* peer_factory) {
119  peer_factory_ = peer_factory->weak_factory_.GetWeakPtr();
120  peer_factory_->peer_factory_ = weak_factory_.GetWeakPtr();
121}
122
123FakeDatagramSocket* FakeDatagramChannelFactory::GetFakeChannel(
124    const std::string& name) {
125  return channels_[name].get();
126}
127
128void FakeDatagramChannelFactory::CreateChannel(
129    const std::string& name,
130    const ChannelCreatedCallback& callback) {
131  EXPECT_TRUE(channels_[name] == NULL);
132
133  scoped_ptr<FakeDatagramSocket> channel(new FakeDatagramSocket());
134  channels_[name] = channel->GetWeakPtr();
135
136  if (peer_factory_) {
137    FakeDatagramSocket* peer_socket = peer_factory_->GetFakeChannel(name);
138    if (peer_socket)
139      channel->PairWith(peer_socket);
140  }
141
142  if (fail_create_)
143    channel.reset();
144
145  if (asynchronous_create_) {
146    task_runner_->PostTask(
147        FROM_HERE,
148        base::Bind(&FakeDatagramChannelFactory::NotifyChannelCreated,
149                   weak_factory_.GetWeakPtr(), base::Passed(&channel),
150                   name, callback));
151  } else {
152    NotifyChannelCreated(channel.Pass(), name, callback);
153  }
154}
155
156void FakeDatagramChannelFactory::NotifyChannelCreated(
157    scoped_ptr<FakeDatagramSocket> owned_socket,
158    const std::string& name,
159    const ChannelCreatedCallback& callback) {
160  if (channels_.find(name) != channels_.end())
161    callback.Run(owned_socket.PassAs<net::Socket>());
162}
163
164void FakeDatagramChannelFactory::CancelChannelCreation(
165    const std::string& name) {
166  channels_.erase(name);
167}
168
169}  // namespace protocol
170}  // namespace remoting
171