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 |