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/host/gnubby_socket.h" 6 7#include "base/macros.h" 8#include "base/timer/timer.h" 9#include "net/socket/stream_listen_socket.h" 10 11namespace remoting { 12 13namespace { 14 15const size_t kRequestSizeBytes = 4; 16const size_t kMaxRequestLength = 16384; 17const unsigned int kRequestTimeoutSeconds = 60; 18 19// SSH Failure Code 20const char kSshError[] = {0x05}; 21 22} // namespace 23 24GnubbySocket::GnubbySocket(scoped_ptr<net::StreamListenSocket> socket, 25 const base::Closure& timeout_callback) 26 : socket_(socket.Pass()) { 27 timer_.reset(new base::Timer(false, false)); 28 timer_->Start(FROM_HERE, 29 base::TimeDelta::FromSeconds(kRequestTimeoutSeconds), 30 timeout_callback); 31} 32 33GnubbySocket::~GnubbySocket() {} 34 35void GnubbySocket::AddRequestData(const char* data, int data_len) { 36 DCHECK(CalledOnValidThread()); 37 38 request_data_.insert(request_data_.end(), data, data + data_len); 39 ResetTimer(); 40} 41 42void GnubbySocket::GetAndClearRequestData(std::string* data_out) { 43 DCHECK(CalledOnValidThread()); 44 DCHECK(IsRequestComplete() && !IsRequestTooLarge()); 45 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} 51 52bool GnubbySocket::IsRequestComplete() const { 53 DCHECK(CalledOnValidThread()); 54 55 if (request_data_.size() < kRequestSizeBytes) 56 return false; 57 return GetRequestLength() <= request_data_.size(); 58} 59 60bool GnubbySocket::IsRequestTooLarge() const { 61 DCHECK(CalledOnValidThread()); 62 63 if (request_data_.size() < kRequestSizeBytes) 64 return false; 65 return GetRequestLength() > kMaxRequestLength; 66} 67 68void GnubbySocket::SendResponse(const std::string& response_data) { 69 DCHECK(CalledOnValidThread()); 70 71 socket_->Send(GetResponseLengthAsBytes(response_data)); 72 socket_->Send(response_data); 73 ResetTimer(); 74} 75 76void GnubbySocket::SendSshError() { 77 DCHECK(CalledOnValidThread()); 78 79 SendResponse(std::string(kSshError, arraysize(kSshError))); 80} 81 82bool GnubbySocket::IsSocket(net::StreamListenSocket* socket) const { 83 return socket == socket_.get(); 84} 85 86void GnubbySocket::SetTimerForTesting(scoped_ptr<base::Timer> timer) { 87 timer->Start(FROM_HERE, timer_->GetCurrentDelay(), timer_->user_task()); 88 timer_ = timer.Pass(); 89} 90 91size_t GnubbySocket::GetRequestLength() const { 92 DCHECK(request_data_.size() >= kRequestSizeBytes); 93 94 return ((request_data_[0] & 255) << 24) + ((request_data_[1] & 255) << 16) + 95 ((request_data_[2] & 255) << 8) + (request_data_[3] & 255) + 96 kRequestSizeBytes; 97} 98 99std::string GnubbySocket::GetResponseLengthAsBytes( 100 const std::string& response) const { 101 std::string response_len; 102 int len = response.size(); 103 104 response_len.push_back((len >> 24) & 255); 105 response_len.push_back((len >> 16) & 255); 106 response_len.push_back((len >> 8) & 255); 107 response_len.push_back(len & 255); 108 109 return response_len; 110} 111 112void GnubbySocket::ResetTimer() { 113 if (timer_->IsRunning()) 114 timer_->Reset(); 115} 116 117} // namespace remoting 118