pseudotcp_channel_factory.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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/pseudotcp_channel_factory.h"
6
7#include "base/bind.h"
8#include "jingle/glue/pseudotcp_adapter.h"
9#include "net/base/net_errors.h"
10#include "net/socket/stream_socket.h"
11#include "remoting/base/constants.h"
12#include "remoting/protocol/datagram_channel_factory.h"
13
14namespace remoting {
15namespace protocol {
16
17namespace {
18
19// Value is chosen to balance the extra latency against the reduced
20// load due to ACK traffic.
21const int kTcpAckDelayMilliseconds = 10;
22
23// Values for the TCP send and receive buffer size. This should be tuned to
24// accommodate high latency network but not backlog the decoding pipeline.
25const int kTcpReceiveBufferSize = 256 * 1024;
26const int kTcpSendBufferSize = kTcpReceiveBufferSize + 30 * 1024;
27
28}  // namespace
29
30PseudoTcpChannelFactory::PseudoTcpChannelFactory(
31    DatagramChannelFactory* datagram_channel_factory)
32    : datagram_channel_factory_(datagram_channel_factory) {
33}
34
35PseudoTcpChannelFactory::~PseudoTcpChannelFactory() {
36  // CancelChannelCreation() is expected to be called before destruction.
37  DCHECK(pending_sockets_.empty());
38}
39
40void PseudoTcpChannelFactory::CreateChannel(
41    const std::string& name,
42    const ChannelCreatedCallback& callback) {
43  datagram_channel_factory_->CreateChannel(
44      name,
45      base::Bind(&PseudoTcpChannelFactory::OnDatagramChannelCreated,
46                 base::Unretained(this), name, callback));
47}
48
49void PseudoTcpChannelFactory::CancelChannelCreation(const std::string& name) {
50  PendingSocketsMap::iterator it = pending_sockets_.find(name);
51  if (it == pending_sockets_.end()) {
52    datagram_channel_factory_->CancelChannelCreation(name);
53  } else {
54    delete it->second;
55    pending_sockets_.erase(it);
56  }
57}
58
59void PseudoTcpChannelFactory::OnDatagramChannelCreated(
60    const std::string& name,
61    const ChannelCreatedCallback& callback,
62    scoped_ptr<net::Socket> datagram_socket) {
63  jingle_glue::PseudoTcpAdapter* adapter =
64      new jingle_glue::PseudoTcpAdapter(datagram_socket.release());
65  pending_sockets_[name] = adapter;
66
67  adapter->SetSendBufferSize(kTcpSendBufferSize);
68  adapter->SetReceiveBufferSize(kTcpReceiveBufferSize);
69  adapter->SetNoDelay(true);
70  adapter->SetAckDelay(kTcpAckDelayMilliseconds);
71
72  // TODO(sergeyu): This is a hack to improve latency of the video channel.
73  // Consider removing it once we have better flow control implemented.
74  if (name == kVideoChannelName)
75    adapter->SetWriteWaitsForSend(true);
76
77  int result = adapter->Connect(
78      base::Bind(&PseudoTcpChannelFactory::OnPseudoTcpConnected,
79                 base::Unretained(this), name, callback));
80  if (result != net::ERR_IO_PENDING)
81    OnPseudoTcpConnected(name, callback, result);
82}
83
84void PseudoTcpChannelFactory::OnPseudoTcpConnected(
85    const std::string& name,
86    const ChannelCreatedCallback& callback,
87    int result) {
88  PendingSocketsMap::iterator it = pending_sockets_.find(name);
89  DCHECK(it != pending_sockets_.end());
90  scoped_ptr<net::StreamSocket> socket(it->second);
91  pending_sockets_.erase(it);
92
93  if (result != net::OK)
94    socket.reset();
95
96  callback.Run(socket.Pass());
97}
98
99}  // namespace protocol
100}  // namespace remoting
101