1 // Copyright 2013 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/native_messaging/native_messaging_writer.h"
6
7 #include <string>
8
9 #include "base/basictypes.h"
10 #include "base/json/json_writer.h"
11
12 namespace {
13
14 // 4-byte type used for the message header.
15 typedef uint32 MessageLengthType;
16
17 // Defined as an int, for passing to APIs that take an int, to avoid
18 // signed/unsigned warnings about implicit cast.
19 const int kMessageHeaderSize = sizeof(MessageLengthType);
20
21 // Limit the size of sent messages, since Chrome will not accept messages
22 // larger than 1MB, and this helps deal with the problem of integer overflow
23 // when passing sizes to net::FileStream APIs that take |int| parameters.
24 // This is defined as size_t (unsigned type) so it can be compared with the
25 // result of std::string::length() without compiler warnings.
26 const size_t kMaximumMessageSize = 1024 * 1024;
27
28 // Performs the same task as FileStream::WriteSync(), but ensures that exactly
29 // |buffer_length| bytes are written. Unlike WriteSync(), a partial write may
30 // only occur as a result of end-of-file or fatal error. Returns the number of
31 // bytes written (buffer_length) or an error-code <= 0.
32 //
33 // TODO(lambroslambrou): Add this method to net::FileStream, with unit-tests.
34 // See http://crbug.com/232202.
WriteUntilComplete(net::FileStream * out,const char * buffer,int buffer_length)35 int WriteUntilComplete(net::FileStream* out,
36 const char* buffer, int buffer_length) {
37 int written = 0;
38 while (written < buffer_length) {
39 int result = out->WriteSync(buffer + written, buffer_length - written);
40 if (result <= 0) {
41 return result;
42 }
43 DCHECK_LE(result, buffer_length - written);
44 written += result;
45 }
46 return written;
47 }
48
49 } // namespace
50
51 namespace remoting {
52
NativeMessagingWriter(base::PlatformFile handle)53 NativeMessagingWriter::NativeMessagingWriter(base::PlatformFile handle)
54 : write_stream_(handle, base::PLATFORM_FILE_WRITE, NULL),
55 fail_(false) {
56 }
57
~NativeMessagingWriter()58 NativeMessagingWriter::~NativeMessagingWriter() {
59 }
60
WriteMessage(const base::Value & message)61 bool NativeMessagingWriter::WriteMessage(const base::Value& message) {
62 if (fail_) {
63 LOG(ERROR) << "Stream marked as corrupt.";
64 return false;
65 }
66
67 std::string message_json;
68 base::JSONWriter::Write(&message, &message_json);
69
70 CHECK_LE(message_json.length(), kMaximumMessageSize);
71
72 // Cast from size_t to the proper header type. The check above ensures this
73 // won't overflow.
74 MessageLengthType message_length =
75 static_cast<MessageLengthType>(message_json.length());
76
77 int result = WriteUntilComplete(
78 &write_stream_, reinterpret_cast<char*>(&message_length),
79 kMessageHeaderSize);
80 if (result != kMessageHeaderSize) {
81 LOG(ERROR) << "Failed to send message header, write returned " << result;
82 fail_ = true;
83 return false;
84 }
85
86 // The length check above ensures that the cast won't overflow a signed
87 // 32-bit int.
88 int message_length_as_int = message_length;
89
90 // CHECK needed since data() is undefined on an empty std::string.
91 CHECK(!message_json.empty());
92 result = WriteUntilComplete(&write_stream_, message_json.data(),
93 message_length_as_int);
94 if (result != message_length_as_int) {
95 LOG(ERROR) << "Failed to send message body, write returned " << result;
96 fail_ = true;
97 return false;
98 }
99
100 return true;
101 }
102
103 } // namespace remoting
104