pipe_messaging_channel.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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 "remoting/host/native_messaging/pipe_messaging_channel.h"
6
7#include "base/basictypes.h"
8#include "base/bind.h"
9#include "base/callback.h"
10#include "base/callback_helpers.h"
11#include "base/location.h"
12#include "base/values.h"
13
14#if defined(OS_POSIX)
15#include <unistd.h>
16#endif
17
18namespace {
19
20base::File DuplicatePlatformFile(base::File file) {
21  base::PlatformFile result;
22#if defined(OS_WIN)
23  if (!DuplicateHandle(GetCurrentProcess(),
24                       file.TakePlatformFile(),
25                       GetCurrentProcess(),
26                       &result,
27                       0,
28                       FALSE,
29                       DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
30    PLOG(ERROR) << "Failed to duplicate handle " << file.GetPlatformFile();
31    return base::File();
32  }
33  return base::File(result);
34#elif defined(OS_POSIX)
35  result = dup(file.GetPlatformFile());
36  return base::File(result);
37#else
38#error Not implemented.
39#endif
40}
41
42}  // namespace
43
44namespace remoting {
45
46PipeMessagingChannel::PipeMessagingChannel(
47    base::File input,
48    base::File output)
49    : native_messaging_reader_(DuplicatePlatformFile(input.Pass())),
50      native_messaging_writer_(new NativeMessagingWriter(
51          DuplicatePlatformFile(output.Pass()))),
52      event_handler_(NULL),
53      weak_factory_(this) {
54  weak_ptr_ = weak_factory_.GetWeakPtr();
55}
56
57PipeMessagingChannel::~PipeMessagingChannel() {
58}
59
60void PipeMessagingChannel::Start(EventHandler* event_handler) {
61  DCHECK(CalledOnValidThread());
62  DCHECK(!event_handler_);
63
64  event_handler_ = event_handler;
65  DCHECK(event_handler_);
66
67  native_messaging_reader_.Start(
68      base::Bind(&PipeMessagingChannel::ProcessMessage, weak_ptr_),
69      base::Bind(&PipeMessagingChannel::Shutdown, weak_ptr_));
70}
71
72void PipeMessagingChannel::ProcessMessage(scoped_ptr<base::Value> message) {
73  DCHECK(CalledOnValidThread());
74
75  if (message->GetType() != base::Value::TYPE_DICTIONARY) {
76    LOG(ERROR) << "Expected DictionaryValue";
77    Shutdown();
78    return;
79  }
80
81  if (event_handler_)
82    event_handler_->OnMessage(message.Pass());
83}
84
85void PipeMessagingChannel::SendMessage(
86    scoped_ptr<base::Value> message) {
87  DCHECK(CalledOnValidThread());
88
89  bool success = message && native_messaging_writer_;
90  if (success)
91    success = native_messaging_writer_->WriteMessage(*message);
92
93  if (!success) {
94    // Close the write pipe so no more responses will be sent.
95    native_messaging_writer_.reset();
96    Shutdown();
97  }
98}
99
100void PipeMessagingChannel::Shutdown() {
101  DCHECK(CalledOnValidThread());
102
103  if (event_handler_) {
104    // Set event_handler_ to NULL to indicate the object is in a shutdown cycle.
105    // Since event_handler->OnDisconnect() will destroy the current object,
106    // |event_handler_| will become a dangling pointer after OnDisconnect()
107    // returns. Therefore, we set |event_handler_| to NULL beforehand.
108    EventHandler* handler = event_handler_;
109    event_handler_ = NULL;
110    handler->OnDisconnect();
111  }
112}
113
114}  // namespace remoting
115