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"
18 const size_t kRequestSizeBytes
= 4;
19 const size_t kMaxRequestLength
= 16384;
20 const size_t kRequestReadBufferLength
= kRequestSizeBytes
+ kMaxRequestLength
;
23 const char kSshError
[] = {0x05};
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_
);
45 if (!IsRequestComplete() || IsRequestTooLarge())
47 // The request size is not part of the data; don't send it.
48 data_out
->assign(request_data_
.begin() + kRequestSizeBytes
,
50 request_data_
.clear();
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
);
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
;
82 void GnubbySocket::OnDataWritten(int result
) {
83 DCHECK(CalledOnValidThread());
84 DCHECK(write_buffer_
);
87 LOG(ERROR
) << "Error sending response: " << result
;
91 write_buffer_
->DidConsume(result
);
95 void GnubbySocket::DoWrite() {
96 DCHECK(CalledOnValidThread());
97 DCHECK(write_buffer_
);
99 if (!write_buffer_
->BytesRemaining()) {
100 write_buffer_
= nullptr;
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());
115 LOG(ERROR
) << "Error reading request: " << result
;
116 read_completed_
= true;
117 base::ResetAndReturn(&request_received_callback_
).Run();
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();
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
)
143 bool GnubbySocket::IsRequestComplete() const {
144 DCHECK(CalledOnValidThread());
146 if (request_data_
.size() < kRequestSizeBytes
)
148 return GetRequestLength() <= request_data_
.size();
151 bool GnubbySocket::IsRequestTooLarge() const {
152 DCHECK(CalledOnValidThread());
154 if (request_data_
.size() < kRequestSizeBytes
)
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) +
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);
181 void GnubbySocket::ResetTimer() {
182 if (timer_
->IsRunning())
186 } // namespace remoting