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/setup/native_messaging_writer.h"
6
7#include <string>
8
9#include "base/basictypes.h"
10#include "base/json/json_writer.h"
11
12namespace {
13
14// 4-byte type used for the message header.
15typedef 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.
19const 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.
26const 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.
35int 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
51namespace remoting {
52
53NativeMessagingWriter::NativeMessagingWriter(base::PlatformFile handle)
54    : write_stream_(handle, base::PLATFORM_FILE_WRITE, NULL),
55      fail_(false) {
56}
57
58NativeMessagingWriter::~NativeMessagingWriter() {
59}
60
61bool 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