- add sources.
[platform/framework/web/crosswalk.git] / src / remoting / host / native_messaging / native_messaging_channel.cc
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/native_messaging_channel.h"
6
7 #include "base/basictypes.h"
8 #include "base/bind.h"
9 #include "base/callback.h"
10 #include "base/location.h"
11 #include "base/values.h"
12
13 #if defined(OS_POSIX)
14 #include <unistd.h>
15 #endif
16
17 namespace {
18
19 base::PlatformFile DuplicatePlatformFile(base::PlatformFile handle) {
20   base::PlatformFile result;
21 #if defined(OS_WIN)
22   if (!DuplicateHandle(GetCurrentProcess(),
23                        handle,
24                        GetCurrentProcess(),
25                        &result,
26                        0,
27                        FALSE,
28                        DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
29     PLOG(ERROR) << "Failed to duplicate handle " << handle;
30     return base::kInvalidPlatformFileValue;
31   }
32   return result;
33 #elif defined(OS_POSIX)
34   result = dup(handle);
35   base::ClosePlatformFile(handle);
36   return result;
37 #else
38 #error Not implemented.
39 #endif
40 }
41
42 }  // namespace
43
44 namespace remoting {
45
46 NativeMessagingChannel::NativeMessagingChannel(
47     scoped_ptr<Delegate> delegate,
48     base::PlatformFile input,
49     base::PlatformFile output)
50     : native_messaging_reader_(DuplicatePlatformFile(input)),
51       native_messaging_writer_(new NativeMessagingWriter(
52           DuplicatePlatformFile(output))),
53       delegate_(delegate.Pass()),
54       pending_requests_(0),
55       shutdown_(false),
56       weak_factory_(this) {
57   weak_ptr_ = weak_factory_.GetWeakPtr();
58 }
59
60 NativeMessagingChannel::~NativeMessagingChannel() {
61 }
62
63 void NativeMessagingChannel::Start(const base::Closure& quit_closure) {
64   DCHECK(CalledOnValidThread());
65   DCHECK(quit_closure_.is_null());
66   DCHECK(!quit_closure.is_null());
67
68   quit_closure_ = quit_closure;
69   native_messaging_reader_.Start(
70       base::Bind(&NativeMessagingChannel::ProcessMessage, weak_ptr_),
71       base::Bind(&NativeMessagingChannel::Shutdown, weak_ptr_));
72 }
73
74 void NativeMessagingChannel::ProcessMessage(scoped_ptr<base::Value> message) {
75   DCHECK(CalledOnValidThread());
76
77   // Don't process any more messages if Shutdown() has been called.
78   if (shutdown_)
79     return;
80
81   if (message->GetType() != base::Value::TYPE_DICTIONARY) {
82     LOG(ERROR) << "Expected DictionaryValue";
83     Shutdown();
84     return;
85   }
86
87   DCHECK_GE(pending_requests_, 0);
88   pending_requests_++;
89
90   scoped_ptr<base::DictionaryValue> message_dict(
91       static_cast<base::DictionaryValue*>(message.release()));
92   delegate_->ProcessMessage(
93       message_dict.Pass(),
94       base::Bind(&NativeMessagingChannel::SendResponse, weak_ptr_));
95 }
96
97 void NativeMessagingChannel::SendResponse(
98     scoped_ptr<base::DictionaryValue> response) {
99   DCHECK(CalledOnValidThread());
100
101   bool success = response && native_messaging_writer_;
102   if (success)
103     success = native_messaging_writer_->WriteMessage(*response);
104
105   if (!success) {
106     // Close the write pipe so no more responses will be sent.
107     native_messaging_writer_.reset();
108     Shutdown();
109   }
110
111   pending_requests_--;
112   DCHECK_GE(pending_requests_, 0);
113
114   if (shutdown_ && !pending_requests_)
115     quit_closure_.Run();
116 }
117
118 void NativeMessagingChannel::Shutdown() {
119   DCHECK(CalledOnValidThread());
120
121   if (shutdown_)
122     return;
123
124   shutdown_ = true;
125   if (!pending_requests_)
126     quit_closure_.Run();
127 }
128
129 }  // namespace remoting