| Index: remoting/host/gnubby_socket.cc
|
| diff --git a/remoting/host/gnubby_socket.cc b/remoting/host/gnubby_socket.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..09d5d301825f9a9b24699de230fd349e2f4be525
|
| --- /dev/null
|
| +++ b/remoting/host/gnubby_socket.cc
|
| @@ -0,0 +1,116 @@
|
| +// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "remoting/host/gnubby_socket.h"
|
| +
|
| +#include "base/timer/timer.h"
|
| +#include "net/socket/stream_listen_socket.h"
|
| +
|
| +namespace remoting {
|
| +
|
| +namespace {
|
| +
|
| +const size_t kRequestSizeBytes = 4;
|
| +const size_t kMaxRequestLength = 16384;
|
| +const unsigned int kRequestTimeoutSeconds = 60;
|
| +
|
| +// SSH Failure Code
|
| +const char kSshError[] = {0x05};
|
| +
|
| +} // namespace
|
| +
|
| +GnubbySocket::GnubbySocket(scoped_ptr<net::StreamListenSocket> socket,
|
| + const base::Closure& timeout_callback)
|
| + : socket_(socket.Pass()) {
|
| + timer_.reset(new base::Timer(false, false));
|
| + timer_->Start(FROM_HERE,
|
| + base::TimeDelta::FromSeconds(kRequestTimeoutSeconds),
|
| + timeout_callback);
|
| +}
|
| +
|
| +GnubbySocket::~GnubbySocket() {}
|
| +
|
| +void GnubbySocket::AddRequestData(const char* data, int data_len) {
|
| + DCHECK(CalledOnValidThread());
|
| +
|
| + request_data_.insert(request_data_.end(), data, data + data_len);
|
| + ResetTimer();
|
| +}
|
| +
|
| +void GnubbySocket::GetAndClearRequestData(std::string* data_out) {
|
| + DCHECK(CalledOnValidThread());
|
| + DCHECK(IsRequestComplete() && !IsRequestTooLarge());
|
| +
|
| + // The request size is not part of the data; don't send it.
|
| + data_out->assign(request_data_.begin() + kRequestSizeBytes,
|
| + request_data_.end());
|
| + request_data_.clear();
|
| +}
|
| +
|
| +bool GnubbySocket::IsRequestComplete() const {
|
| + DCHECK(CalledOnValidThread());
|
| +
|
| + if (request_data_.size() < kRequestSizeBytes)
|
| + return false;
|
| + return GetRequestLength() <= request_data_.size();
|
| +}
|
| +
|
| +bool GnubbySocket::IsRequestTooLarge() const {
|
| + DCHECK(CalledOnValidThread());
|
| +
|
| + if (request_data_.size() < kRequestSizeBytes)
|
| + return false;
|
| + return GetRequestLength() > kMaxRequestLength;
|
| +}
|
| +
|
| +void GnubbySocket::SendResponse(const std::string& response_data) {
|
| + DCHECK(CalledOnValidThread());
|
| +
|
| + socket_->Send(GetResponseLengthAsBytes(response_data));
|
| + socket_->Send(response_data);
|
| + ResetTimer();
|
| +}
|
| +
|
| +void GnubbySocket::SendSshError() {
|
| + DCHECK(CalledOnValidThread());
|
| +
|
| + SendResponse(kSshError);
|
| +}
|
| +
|
| +bool GnubbySocket::IsSocket(net::StreamListenSocket* socket) const {
|
| + return socket == socket_.get();
|
| +}
|
| +
|
| +void GnubbySocket::SetTimerForTesting(scoped_ptr<base::Timer> timer) {
|
| + timer->Start(FROM_HERE, timer_->GetCurrentDelay(), timer_->user_task());
|
| + timer_ = timer.Pass();
|
| +}
|
| +
|
| +size_t GnubbySocket::GetRequestLength() const {
|
| + DCHECK(request_data_.size() >= kRequestSizeBytes);
|
| +
|
| + return ((request_data_[0] & 255) << 24) + ((request_data_[1] & 255) << 16) +
|
| + ((request_data_[2] & 255) << 8) + (request_data_[3] & 255) +
|
| + kRequestSizeBytes;
|
| +}
|
| +
|
| +std::string GnubbySocket::GetResponseLengthAsBytes(
|
| + const std::string& response) const {
|
| + std::string response_len;
|
| + int len = response.size();
|
| +
|
| + response_len.push_back((len >> 24) & 255);
|
| + response_len.push_back((len >> 16) & 255);
|
| + response_len.push_back((len >> 8) & 255);
|
| + response_len.push_back(len & 255);
|
| +
|
| + return response_len;
|
| +}
|
| +
|
| +void GnubbySocket::ResetTimer() {
|
| + if (timer_->IsRunning())
|
| + timer_->Reset();
|
| +}
|
| +
|
| +} // namespace remoting
|
|
|