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/macros.h"
8 #include "base/timer/timer.h"
9 #include "net/base/io_buffer.h"
10 #include "net/base/net_errors.h"
11 #include "net/socket/stream_socket.h"
17 const size_t kRequestSizeBytes
= 4;
18 const size_t kMaxRequestLength
= 16384;
19 const size_t kRequestReadBufferLength
= kRequestSizeBytes
+ kMaxRequestLength
;
22 const char kSshError
[] = {0x05};
26 GnubbySocket::GnubbySocket(scoped_ptr
<net::StreamSocket
> socket
,
27 const base::TimeDelta
& timeout
,
28 const base::Closure
& timeout_callback
)
29 : socket_(socket
.Pass()),
30 read_completed_(false),
31 read_buffer_(new net::IOBufferWithSize(kRequestReadBufferLength
)) {
32 timer_
.reset(new base::Timer(false, false));
33 timer_
->Start(FROM_HERE
, timeout
, timeout_callback
);
36 GnubbySocket::~GnubbySocket() {}
38 bool GnubbySocket::GetAndClearRequestData(std::string
* data_out
) {
39 DCHECK(CalledOnValidThread());
40 DCHECK(read_completed_
);
44 if (!IsRequestComplete() || IsRequestTooLarge())
46 // The request size is not part of the data; don't send it.
47 data_out
->assign(request_data_
.begin() + kRequestSizeBytes
,
49 request_data_
.clear();
53 void GnubbySocket::SendResponse(const std::string
& response_data
) {
54 DCHECK(CalledOnValidThread());
55 DCHECK(!write_buffer_
);
57 std::string response_length_string
= GetResponseLengthAsBytes(response_data
);
58 int response_len
= response_length_string
.size() + response_data
.size();
59 scoped_ptr
<std::string
> response(
60 new std::string(response_length_string
+ response_data
));
61 write_buffer_
= new net::DrainableIOBuffer(
62 new net::StringIOBuffer(response
.Pass()), response_len
);
66 void GnubbySocket::SendSshError() {
67 DCHECK(CalledOnValidThread());
69 SendResponse(std::string(kSshError
, arraysize(kSshError
)));
72 void GnubbySocket::StartReadingRequest(
73 const base::Closure
& request_received_callback
) {
74 DCHECK(CalledOnValidThread());
76 request_received_callback_
= request_received_callback
;
80 void GnubbySocket::OnDataWritten(int result
) {
81 DCHECK(CalledOnValidThread());
82 DCHECK(write_buffer_
);
85 LOG(ERROR
) << "Error in sending response.";
89 write_buffer_
->DidConsume(result
);
93 void GnubbySocket::DoWrite() {
94 DCHECK(CalledOnValidThread());
95 DCHECK(write_buffer_
);
97 if (!write_buffer_
->BytesRemaining()) {
98 write_buffer_
= nullptr;
101 int result
= socket_
->Write(
102 write_buffer_
.get(), write_buffer_
->BytesRemaining(),
103 base::Bind(&GnubbySocket::OnDataWritten
, base::Unretained(this)));
104 if (result
!= net::ERR_IO_PENDING
)
105 OnDataWritten(result
);
108 void GnubbySocket::OnDataRead(int bytes_read
) {
109 DCHECK(CalledOnValidThread());
111 if (bytes_read
< 0) {
112 LOG(ERROR
) << "Error in reading request.";
113 read_completed_
= true;
114 request_received_callback_
.Run();
118 request_data_
.insert(request_data_
.end(), read_buffer_
->data(),
119 read_buffer_
->data() + bytes_read
);
120 if (IsRequestComplete()) {
121 read_completed_
= true;
122 request_received_callback_
.Run();
128 void GnubbySocket::DoRead() {
129 DCHECK(CalledOnValidThread());
131 int result
= socket_
->Read(
132 read_buffer_
.get(), kRequestReadBufferLength
,
133 base::Bind(&GnubbySocket::OnDataRead
, base::Unretained(this)));
134 if (result
!= net::ERR_IO_PENDING
)
138 bool GnubbySocket::IsRequestComplete() const {
139 DCHECK(CalledOnValidThread());
141 if (request_data_
.size() < kRequestSizeBytes
)
143 return GetRequestLength() <= request_data_
.size();
146 bool GnubbySocket::IsRequestTooLarge() const {
147 DCHECK(CalledOnValidThread());
149 if (request_data_
.size() < kRequestSizeBytes
)
151 return GetRequestLength() > kMaxRequestLength
;
154 size_t GnubbySocket::GetRequestLength() const {
155 DCHECK(request_data_
.size() >= kRequestSizeBytes
);
157 return ((request_data_
[0] & 255) << 24) + ((request_data_
[1] & 255) << 16) +
158 ((request_data_
[2] & 255) << 8) + (request_data_
[3] & 255) +
162 std::string
GnubbySocket::GetResponseLengthAsBytes(
163 const std::string
& response
) const {
164 std::string response_len
;
165 response_len
.reserve(kRequestSizeBytes
);
166 int len
= response
.size();
168 response_len
.push_back((len
>> 24) & 255);
169 response_len
.push_back((len
>> 16) & 255);
170 response_len
.push_back((len
>> 8) & 255);
171 response_len
.push_back(len
& 255);
176 void GnubbySocket::ResetTimer() {
177 if (timer_
->IsRunning())
181 } // namespace remoting