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", "ChannelReader::DispatchInputData", "name", name);
     87 #else
     88       TRACE_EVENT2("ipc", "ChannelReader::DispatchInputData",
     89                    "class", IPC_MESSAGE_ID_CLASS(m.type()),
     90                    "line", IPC_MESSAGE_ID_LINE(m.type()));
     91 #endif
     92       m.TraceMessageEnd();
     93       if (IsInternalMessage(m))
     94         HandleInternalMessage(m);
     95       else
     96         listener_->OnMessageReceived(m);
     97       p = message_tail;
     98     } else {
     99       // Last message is partial.
    100       break;
    101     }
    102   }
    103 
    104   // Save any partial data in the overflow buffer.
    105   input_overflow_buf_.assign(p, end - p);
    106 
    107   if (input_overflow_buf_.empty() && !DidEmptyInputBuffers())
    108     return false;
    109   return true;
    110 }
    111 
    112 
    113 }  // namespace internal
    114 }  // namespace IPC
    115