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 "tools/ipc_fuzzer/replay/replay_process.h"
6
7#include <limits.h>
8#include <string>
9#include "base/bind.h"
10#include "base/command_line.h"
11#include "base/files/file_path.h"
12#include "base/logging.h"
13#include "base/posix/global_descriptors.h"
14#include "chrome/common/chrome_switches.h"
15#include "ipc/ipc_descriptors.h"
16#include "ipc/ipc_switches.h"
17
18namespace ipc_fuzzer {
19
20ReplayProcess::ReplayProcess()
21    : io_thread_("Chrome_ChildIOThread"),
22      shutdown_event_(true, false),
23      message_index_(0) {
24}
25
26ReplayProcess::~ReplayProcess() {
27  channel_.reset();
28}
29
30bool ReplayProcess::Initialize(int argc, const char** argv) {
31  CommandLine::Init(argc, argv);
32
33  if (!CommandLine::ForCurrentProcess()->HasSwitch(
34      switches::kIpcFuzzerTestcase)) {
35    LOG(ERROR) << "This binary shouldn't be executed directly, "
36               << "please use tools/ipc_fuzzer/play_testcase.py";
37    return false;
38  }
39
40  // Log to default destination.
41  logging::SetMinLogLevel(logging::LOG_ERROR);
42  logging::InitLogging(logging::LoggingSettings());
43
44  io_thread_.StartWithOptions(
45      base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
46
47  base::GlobalDescriptors* g_fds = base::GlobalDescriptors::GetInstance();
48  g_fds->Set(kPrimaryIPCChannel,
49             kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor);
50  return true;
51}
52
53void ReplayProcess::OpenChannel() {
54  std::string channel_name =
55      CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
56          switches::kProcessChannelID);
57
58  channel_ = IPC::ChannelProxy::Create(channel_name,
59                                       IPC::Channel::MODE_CLIENT,
60                                       this,
61                                       io_thread_.message_loop_proxy());
62}
63
64bool ReplayProcess::OpenTestcase() {
65  base::FilePath path = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
66      switches::kIpcFuzzerTestcase);
67  return MessageFile::Read(path, &messages_);
68}
69
70void ReplayProcess::SendNextMessage() {
71  if (message_index_ >= messages_.size()) {
72    base::MessageLoop::current()->Quit();
73    return;
74  }
75
76  // Take next message and release it from vector.
77  IPC::Message* message = messages_[message_index_];
78  messages_[message_index_++] = NULL;
79
80  if (!channel_->Send(message)) {
81    LOG(ERROR) << "ChannelProxy::Send() failed after "
82               << message_index_ << " messages";
83    base::MessageLoop::current()->Quit();
84  }
85}
86
87void ReplayProcess::Run() {
88  timer_.reset(new base::Timer(false, true));
89  timer_->Start(FROM_HERE,
90                base::TimeDelta::FromMilliseconds(1),
91                base::Bind(&ReplayProcess::SendNextMessage,
92                           base::Unretained(this)));
93  base::MessageLoop::current()->Run();
94}
95
96bool ReplayProcess::OnMessageReceived(const IPC::Message& msg) {
97  return true;
98}
99
100void ReplayProcess::OnChannelError() {
101  LOG(ERROR) << "Channel error, quitting after "
102             << message_index_ << " messages";
103  base::MessageLoop::current()->Quit();
104}
105
106}  // namespace ipc_fuzzer
107