Only grant permissions to new extensions from sync if they have the expected version
[chromium-blink-merge.git] / remoting / host / gnubby_socket.cc
blob21dad8152f25e479d8919b49775618adeb8c3226
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/callback_helpers.h"
8 #include "base/macros.h"
9 #include "base/timer/timer.h"
10 #include "net/base/io_buffer.h"
11 #include "net/base/net_errors.h"
12 #include "net/socket/stream_socket.h"
14 namespace remoting {
16 namespace {
18 const size_t kRequestSizeBytes = 4;
19 const size_t kMaxRequestLength = 16384;
20 const size_t kRequestReadBufferLength = kRequestSizeBytes + kMaxRequestLength;
22 // SSH Failure Code
23 const char kSshError[] = {0x05};
25 } // namespace
27 GnubbySocket::GnubbySocket(scoped_ptr<net::StreamSocket> socket,
28 const base::TimeDelta& timeout,
29 const base::Closure& timeout_callback)
30 : socket_(socket.Pass()),
31 read_completed_(false),
32 read_buffer_(new net::IOBufferWithSize(kRequestReadBufferLength)) {
33 timer_.reset(new base::Timer(false, false));
34 timer_->Start(FROM_HERE, timeout, timeout_callback);
37 GnubbySocket::~GnubbySocket() {}
39 bool GnubbySocket::GetAndClearRequestData(std::string* data_out) {
40 DCHECK(CalledOnValidThread());
41 DCHECK(read_completed_);
43 if (!read_completed_)
44 return false;
45 if (!IsRequestComplete() || IsRequestTooLarge())
46 return false;
47 // The request size is not part of the data; don't send it.
48 data_out->assign(request_data_.begin() + kRequestSizeBytes,
49 request_data_.end());
50 request_data_.clear();
51 return true;
54 void GnubbySocket::SendResponse(const std::string& response_data) {
55 DCHECK(CalledOnValidThread());
56 DCHECK(!write_buffer_);
58 std::string response_length_string = GetResponseLengthAsBytes(response_data);
59 int response_len = response_length_string.size() + response_data.size();
60 scoped_ptr<std::string> response(
61 new std::string(response_length_string + response_data));
62 write_buffer_ = new net::DrainableIOBuffer(
63 new net::StringIOBuffer(response.Pass()), response_len);
64 DoWrite();
67 void GnubbySocket::SendSshError() {
68 DCHECK(CalledOnValidThread());
70 SendResponse(std::string(kSshError, arraysize(kSshError)));
73 void GnubbySocket::StartReadingRequest(
74 const base::Closure& request_received_callback) {
75 DCHECK(CalledOnValidThread());
76 DCHECK(request_received_callback_.is_null());
78 request_received_callback_ = request_received_callback;
79 DoRead();
82 void GnubbySocket::OnDataWritten(int result) {
83 DCHECK(CalledOnValidThread());
84 DCHECK(write_buffer_);
86 if (result < 0) {
87 LOG(ERROR) << "Error sending response: " << result;
88 return;
90 ResetTimer();
91 write_buffer_->DidConsume(result);
92 DoWrite();
95 void GnubbySocket::DoWrite() {
96 DCHECK(CalledOnValidThread());
97 DCHECK(write_buffer_);
99 if (!write_buffer_->BytesRemaining()) {
100 write_buffer_ = nullptr;
101 return;
103 int result = socket_->Write(
104 write_buffer_.get(), write_buffer_->BytesRemaining(),
105 base::Bind(&GnubbySocket::OnDataWritten, base::Unretained(this)));
106 if (result != net::ERR_IO_PENDING)
107 OnDataWritten(result);
110 void GnubbySocket::OnDataRead(int result) {
111 DCHECK(CalledOnValidThread());
113 if (result <= 0) {
114 if (result < 0)
115 LOG(ERROR) << "Error reading request: " << result;
116 read_completed_ = true;
117 base::ResetAndReturn(&request_received_callback_).Run();
118 return;
121 ResetTimer();
122 request_data_.insert(request_data_.end(), read_buffer_->data(),
123 read_buffer_->data() + result);
124 if (IsRequestComplete()) {
125 read_completed_ = true;
126 base::ResetAndReturn(&request_received_callback_).Run();
127 return;
130 DoRead();
133 void GnubbySocket::DoRead() {
134 DCHECK(CalledOnValidThread());
136 int result = socket_->Read(
137 read_buffer_.get(), kRequestReadBufferLength,
138 base::Bind(&GnubbySocket::OnDataRead, base::Unretained(this)));
139 if (result != net::ERR_IO_PENDING)
140 OnDataRead(result);
143 bool GnubbySocket::IsRequestComplete() const {
144 DCHECK(CalledOnValidThread());
146 if (request_data_.size() < kRequestSizeBytes)
147 return false;
148 return GetRequestLength() <= request_data_.size();
151 bool GnubbySocket::IsRequestTooLarge() const {
152 DCHECK(CalledOnValidThread());
154 if (request_data_.size() < kRequestSizeBytes)
155 return false;
156 return GetRequestLength() > kMaxRequestLength;
159 size_t GnubbySocket::GetRequestLength() const {
160 DCHECK(request_data_.size() >= kRequestSizeBytes);
162 return ((request_data_[0] & 255) << 24) + ((request_data_[1] & 255) << 16) +
163 ((request_data_[2] & 255) << 8) + (request_data_[3] & 255) +
164 kRequestSizeBytes;
167 std::string GnubbySocket::GetResponseLengthAsBytes(
168 const std::string& response) const {
169 std::string response_len;
170 response_len.reserve(kRequestSizeBytes);
171 int len = response.size();
173 response_len.push_back((len >> 24) & 255);
174 response_len.push_back((len >> 16) & 255);
175 response_len.push_back((len >> 8) & 255);
176 response_len.push_back(len & 255);
178 return response_len;
181 void GnubbySocket::ResetTimer() {
182 if (timer_->IsRunning())
183 timer_->Reset();
186 } // namespace remoting