Home | History | Annotate | Download | only in ipc
      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 
     11 namespace IPC {
     12 namespace internal {
     13 
     14 ChannelReader::ChannelReader(Listener* listener) : listener_(listener) {
     15   memset(input_buf_, 0, sizeof(input_buf_));
     16 }
     17 
     18 ChannelReader::~ChannelReader() {
     19 }
     20 
     21 bool 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 
     37 bool ChannelReader::AsyncReadComplete(int bytes_read) {
     38   return DispatchInputData(input_buf_, bytes_read);
     39 }
     40 
     41 bool ChannelReader::IsInternalMessage(const Message& m) const {
     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 
     47 bool ChannelReader::IsHelloMessage(const Message& m) const {
     48   return m.routing_id() == MSG_ROUTING_NONE &&
     49       m.type() == Channel::HELLO_MESSAGE_TYPE;
     50 }
     51 
     52 bool 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