Home | History | Annotate | Download | only in message_lib
      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 <limits.h>
      6 #include <set>
      7 
      8 #include "base/files/file.h"
      9 #include "base/logging.h"
     10 #include "tools/ipc_fuzzer/message_lib/message_file.h"
     11 #include "tools/ipc_fuzzer/message_lib/message_file_format.h"
     12 #include "tools/ipc_fuzzer/message_lib/message_names.h"
     13 
     14 namespace ipc_fuzzer {
     15 
     16 namespace {
     17 
     18 // Helper class to write a MessageVector + message names to a file.
     19 class Writer {
     20  public:
     21   Writer(const base::FilePath& path);
     22   ~Writer() {}
     23   bool Write(const MessageVector& messages);
     24 
     25  private:
     26   bool OpenFile();
     27 
     28   // Helper to append data to file_.
     29   bool WriteBlob(const void *buffer, size_t size);
     30 
     31   // Collects a set of MessageVector message types. Corresponding message
     32   // names need to be included in the file.
     33   bool CollectMessageTypes();
     34 
     35   bool WriteHeader();
     36   bool WriteMessages();
     37 
     38   // Each name table entry is a message type + string table offset.
     39   bool WriteNameTable();
     40 
     41   // String table contains the actual message names.
     42   bool WriteStringTable();
     43 
     44   typedef std::set<uint32> TypesSet;
     45   base::FilePath path_;
     46   base::File file_;
     47   const MessageVector* messages_;
     48   TypesSet types_;
     49 
     50   DISALLOW_COPY_AND_ASSIGN(Writer);
     51 };
     52 
     53 Writer::Writer(const base::FilePath& path) : path_(path), messages_(NULL) {
     54 }
     55 
     56 bool Writer::OpenFile() {
     57   file_.Initialize(path_,
     58                    base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
     59   if (!file_.IsValid()) {
     60     LOG(ERROR) << "Failed to create IPC message file: " << path_.value();
     61     return false;
     62   }
     63   return true;
     64 }
     65 
     66 bool Writer::WriteBlob(const void *buffer, size_t size) {
     67   if (size > INT_MAX)
     68     return false;
     69   const char* char_buffer = static_cast<const char*>(buffer);
     70   int ret = file_.WriteAtCurrentPos(char_buffer, size);
     71   if (ret != static_cast<int>(size)) {
     72     LOG(ERROR) << "Failed to write " << size << " bytes.";
     73     return false;
     74   }
     75   return true;
     76 }
     77 
     78 bool Writer::CollectMessageTypes() {
     79   for (size_t i = 0; i < messages_->size(); ++i) {
     80     uint32_t type = (*messages_)[i]->type();
     81     if (!MessageNames::GetInstance()->TypeExists(type)) {
     82       LOG(ERROR) << "Unknown message type: " << type;
     83       return false;
     84     }
     85     types_.insert(type);
     86   }
     87   return true;
     88 }
     89 
     90 bool Writer::WriteHeader() {
     91   FileHeader header;
     92   if (messages_->size() > UINT_MAX)
     93     return false;
     94   header.magic = FileHeader::kMagicValue;
     95   header.version = FileHeader::kCurrentVersion;
     96   header.message_count = messages_->size();
     97   header.name_count = types_.size();
     98   if (!WriteBlob(&header, sizeof(FileHeader)))
     99     return false;
    100   return true;
    101 }
    102 
    103 bool Writer::WriteMessages() {
    104   for (size_t i = 0; i < messages_->size(); ++i) {
    105     IPC::Message* message = (*messages_)[i];
    106     if (!WriteBlob(message->data(), message->size()))
    107       return false;
    108   }
    109   return true;
    110 }
    111 
    112 bool Writer::WriteNameTable() {
    113   size_t string_table_offset = 0;
    114   NameTableEntry entry;
    115 
    116   for (TypesSet::iterator it = types_.begin(); it != types_.end(); ++it) {
    117     if (string_table_offset > UINT_MAX)
    118       return false;
    119     entry.type = *it;
    120     entry.string_table_offset = string_table_offset;
    121     if (!WriteBlob(&entry, sizeof(NameTableEntry)))
    122       return false;
    123     const std::string& name = MessageNames::GetInstance()->TypeToName(*it);
    124     string_table_offset += name.length() + 1;
    125   }
    126   return true;
    127 }
    128 
    129 bool Writer::WriteStringTable() {
    130   for (TypesSet::iterator it = types_.begin(); it != types_.end(); ++it) {
    131     const std::string& name = MessageNames::GetInstance()->TypeToName(*it);
    132     if (!WriteBlob(name.c_str(), name.length() + 1))
    133       return false;
    134   }
    135   return true;
    136 }
    137 
    138 bool Writer::Write(const MessageVector& messages) {
    139   messages_ = &messages;
    140 
    141   if (!OpenFile())
    142     return false;
    143   if (!CollectMessageTypes())
    144     return false;
    145   if (!WriteHeader())
    146     return false;
    147   if (!WriteMessages())
    148     return false;
    149   if (!WriteNameTable())
    150     return false;
    151   if (!WriteStringTable())
    152     return false;
    153 
    154   return true;
    155 }
    156 
    157 }  // namespace
    158 
    159 bool MessageFile::Write(const base::FilePath& path,
    160                         const MessageVector& messages) {
    161   Writer writer(path);
    162   return writer.Write(messages);
    163 }
    164 
    165 }  // namespace ipc_fuzzer
    166