Use single and correct URL to flot library homepage
[chromium-blink-merge.git] / remoting / host / gnubby_socket.cc
blob7df45148a96a0ebc799f1de1cb68ee0b099f9c42
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.
5 #include "remoting/host/gnubby_socket.h"
7 #include "base/macros.h"
8 #include "base/timer/timer.h"
9 #include "net/base/io_buffer.h"
10 #include "net/base/net_errors.h"
11 #include "net/socket/stream_socket.h"
13 namespace remoting {
15 namespace {
17 const size_t kRequestSizeBytes = 4;
18 const size_t kMaxRequestLength = 16384;
19 const size_t kRequestReadBufferLength = kRequestSizeBytes + kMaxRequestLength;
21 // SSH Failure Code
22 const char kSshError[] = {0x05};
24 } // namespace
26 GnubbySocket::GnubbySocket(scoped_ptr<net::StreamSocket> socket,
27 const base::TimeDelta& timeout,
28 const base::Closure& timeout_callback)
29 : socket_(socket.Pass()),
30 read_completed_(false),
31 read_buffer_(new net::IOBufferWithSize(kRequestReadBufferLength)) {
32 timer_.reset(new base::Timer(false, false));
33 timer_->Start(FROM_HERE, timeout, timeout_callback);
36 GnubbySocket::~GnubbySocket() {}
38 bool GnubbySocket::GetAndClearRequestData(std::string* data_out) {
39 DCHECK(CalledOnValidThread());
40 DCHECK(read_completed_);
42 if (!read_completed_)
43 return false;
44 if (!IsRequestComplete() || IsRequestTooLarge())
45 return false;
46 // The request size is not part of the data; don't send it.
47 data_out->assign(request_data_.begin() + kRequestSizeBytes,
48 request_data_.end());
49 request_data_.clear();
50 return true;
53 void GnubbySocket::SendResponse(const std::string& response_data) {
54 DCHECK(CalledOnValidThread());
55 DCHECK(!write_buffer_);
57 std::string response_length_string = GetResponseLengthAsBytes(response_data);
58 int response_len = response_length_string.size() + response_data.size();
59 scoped_ptr<std::string> response(
60 new std::string(response_length_string + response_data));
61 write_buffer_ = new net::DrainableIOBuffer(
62 new net::StringIOBuffer(response.Pass()), response_len);
63 DoWrite();
66 void GnubbySocket::SendSshError() {
67 DCHECK(CalledOnValidThread());
69 SendResponse(std::string(kSshError, arraysize(kSshError)));
72 void GnubbySocket::StartReadingRequest(
73 const base::Closure& request_received_callback) {
74 DCHECK(CalledOnValidThread());
76 request_received_callback_ = request_received_callback;
77 DoRead();
80 void GnubbySocket::OnDataWritten(int result) {
81 DCHECK(CalledOnValidThread());
82 DCHECK(write_buffer_);
84 if (result < 0) {
85 LOG(ERROR) << "Error in sending response.";
86 return;
88 ResetTimer();
89 write_buffer_->DidConsume(result);
90 DoWrite();
93 void GnubbySocket::DoWrite() {
94 DCHECK(CalledOnValidThread());
95 DCHECK(write_buffer_);
97 if (!write_buffer_->BytesRemaining()) {
98 write_buffer_ = nullptr;
99 return;
101 int result = socket_->Write(
102 write_buffer_.get(), write_buffer_->BytesRemaining(),
103 base::Bind(&GnubbySocket::OnDataWritten, base::Unretained(this)));
104 if (result != net::ERR_IO_PENDING)
105 OnDataWritten(result);
108 void GnubbySocket::OnDataRead(int bytes_read) {
109 DCHECK(CalledOnValidThread());
111 if (bytes_read < 0) {
112 LOG(ERROR) << "Error in reading request.";
113 read_completed_ = true;
114 request_received_callback_.Run();
115 return;
117 ResetTimer();
118 request_data_.insert(request_data_.end(), read_buffer_->data(),
119 read_buffer_->data() + bytes_read);
120 if (IsRequestComplete()) {
121 read_completed_ = true;
122 request_received_callback_.Run();
123 return;
125 DoRead();
128 void GnubbySocket::DoRead() {
129 DCHECK(CalledOnValidThread());
131 int result = socket_->Read(
132 read_buffer_.get(), kRequestReadBufferLength,
133 base::Bind(&GnubbySocket::OnDataRead, base::Unretained(this)));
134 if (result != net::ERR_IO_PENDING)
135 OnDataRead(result);
138 bool GnubbySocket::IsRequestComplete() const {
139 DCHECK(CalledOnValidThread());
141 if (request_data_.size() < kRequestSizeBytes)
142 return false;
143 return GetRequestLength() <= request_data_.size();
146 bool GnubbySocket::IsRequestTooLarge() const {
147 DCHECK(CalledOnValidThread());
149 if (request_data_.size() < kRequestSizeBytes)
150 return false;
151 return GetRequestLength() > kMaxRequestLength;
154 size_t GnubbySocket::GetRequestLength() const {
155 DCHECK(request_data_.size() >= kRequestSizeBytes);
157 return ((request_data_[0] & 255) << 24) + ((request_data_[1] & 255) << 16) +
158 ((request_data_[2] & 255) << 8) + (request_data_[3] & 255) +
159 kRequestSizeBytes;
162 std::string GnubbySocket::GetResponseLengthAsBytes(
163 const std::string& response) const {
164 std::string response_len;
165 response_len.reserve(kRequestSizeBytes);
166 int len = response.size();
168 response_len.push_back((len >> 24) & 255);
169 response_len.push_back((len >> 16) & 255);
170 response_len.push_back((len >> 8) & 255);
171 response_len.push_back(len & 255);
173 return response_len;
176 void GnubbySocket::ResetTimer() {
177 if (timer_->IsRunning())
178 timer_->Reset();
181 } // namespace remoting