• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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