1// Copyright (c) 2012 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 "ipc/ipc_channel_reader.h"
6
7#include "ipc/ipc_listener.h"
8#include "ipc/ipc_logging.h"
9#include "ipc/ipc_message_macros.h"
10
11namespace IPC {
12namespace internal {
13
14ChannelReader::ChannelReader(Listener* listener) : listener_(listener) {
15  memset(input_buf_, 0, sizeof(input_buf_));
16}
17
18ChannelReader::~ChannelReader() {
19}
20
21bool ChannelReader::ProcessIncomingMessages() {
22  while (true) {
23    int bytes_read = 0;
24    ReadState read_state = ReadData(input_buf_, Channel::kReadBufferSize,
25                                    &bytes_read);
26    if (read_state == READ_FAILED)
27      return false;
28    if (read_state == READ_PENDING)
29      return true;
30
31    DCHECK(bytes_read > 0);
32    if (!DispatchInputData(input_buf_, bytes_read))
33      return false;
34  }
35}
36
37bool ChannelReader::AsyncReadComplete(int bytes_read) {
38  return DispatchInputData(input_buf_, bytes_read);
39}
40
41bool ChannelReader::IsInternalMessage(const Message& m) {
42  return m.routing_id() == MSG_ROUTING_NONE &&
43      m.type() >= Channel::CLOSE_FD_MESSAGE_TYPE &&
44      m.type() <= Channel::HELLO_MESSAGE_TYPE;
45}
46
47bool ChannelReader::IsHelloMessage(const Message& m) {
48  return m.routing_id() == MSG_ROUTING_NONE &&
49      m.type() == Channel::HELLO_MESSAGE_TYPE;
50}
51
52bool ChannelReader::DispatchInputData(const char* input_data,
53                                      int input_data_len) {
54  const char* p;
55  const char* end;
56
57  // Possibly combine with the overflow buffer to make a larger buffer.
58  if (input_overflow_buf_.empty()) {
59    p = input_data;
60    end = input_data + input_data_len;
61  } else {
62    if (input_overflow_buf_.size() + input_data_len >
63        Channel::kMaximumMessageSize) {
64      input_overflow_buf_.clear();
65      LOG(ERROR) << "IPC message is too big";
66      return false;
67    }
68    input_overflow_buf_.append(input_data, input_data_len);
69    p = input_overflow_buf_.data();
70    end = p + input_overflow_buf_.size();
71  }
72
73  // Dispatch all complete messages in the data buffer.
74  while (p < end) {
75    const char* message_tail = Message::FindNext(p, end);
76    if (message_tail) {
77      int len = static_cast<int>(message_tail - p);
78      Message m(p, len);
79      if (!WillDispatchInputMessage(&m))
80        return false;
81
82#ifdef IPC_MESSAGE_LOG_ENABLED
83      Logging* logger = Logging::GetInstance();
84      std::string name;
85      logger->GetMessageText(m.type(), &name, &m, NULL);
86      TRACE_EVENT1("ipc,toplevel", "ChannelReader::DispatchInputData",
87                   "name", name);
88#else
89      TRACE_EVENT2("ipc,toplevel", "ChannelReader::DispatchInputData",
90                   "class", IPC_MESSAGE_ID_CLASS(m.type()),
91                   "line", IPC_MESSAGE_ID_LINE(m.type()));
92#endif
93      m.TraceMessageEnd();
94      if (IsInternalMessage(m))
95        HandleInternalMessage(m);
96      else
97        listener_->OnMessageReceived(m);
98      if (m.dispatch_error())
99        listener_->OnBadMessageReceived(m);
100      p = message_tail;
101    } else {
102      // Last message is partial.
103      break;
104    }
105  }
106
107  // Save any partial data in the overflow buffer.
108  input_overflow_buf_.assign(p, end - p);
109
110  if (input_overflow_buf_.empty() && !DidEmptyInputBuffers())
111    return false;
112  return true;
113}
114
115
116}  // namespace internal
117}  // namespace IPC
118