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 11 namespace remoting { 12 13 namespace { 14 15 const size_t kRequestSizeBytes = 4; 16 const size_t kMaxRequestLength = 16384; 17 const unsigned int kRequestTimeoutSeconds = 60; 18 19 // SSH Failure Code 20 const char kSshError[] = {0x05}; 21 22 } // namespace 23 24 GnubbySocket::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 33 GnubbySocket::~GnubbySocket() {} 34 35 void 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 42 void 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 52 bool GnubbySocket::IsRequestComplete() const { 53 DCHECK(CalledOnValidThread()); 54 55 if (request_data_.size() < kRequestSizeBytes) 56 return false; 57 return GetRequestLength() <= request_data_.size(); 58 } 59 60 bool GnubbySocket::IsRequestTooLarge() const { 61 DCHECK(CalledOnValidThread()); 62 63 if (request_data_.size() < kRequestSizeBytes) 64 return false; 65 return GetRequestLength() > kMaxRequestLength; 66 } 67 68 void 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 76 void GnubbySocket::SendSshError() { 77 DCHECK(CalledOnValidThread()); 78 79 SendResponse(std::string(kSshError, arraysize(kSshError))); 80 } 81 82 bool GnubbySocket::IsSocket(net::StreamListenSocket* socket) const { 83 return socket == socket_.get(); 84 } 85 86 void GnubbySocket::SetTimerForTesting(scoped_ptr<base::Timer> timer) { 87 timer->Start(FROM_HERE, timer_->GetCurrentDelay(), timer_->user_task()); 88 timer_ = timer.Pass(); 89 } 90 91 size_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 99 std::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 112 void GnubbySocket::ResetTimer() { 113 if (timer_->IsRunning()) 114 timer_->Reset(); 115 } 116 117 } // namespace remoting 118