blob: bd3833736c417d796bede00f8cbef9a69b0d55f1 [file] [log] [blame]
[email protected]7419d4b2011-04-06 15:18:041// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]5a8db802010-10-06 17:34:432// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome_frame/cfproxy_private.h"
6
7#include "base/tuple.h"
8#include "ipc/ipc_sync_message.h"
[email protected]a8ba6362010-11-10 20:02:259#include "chrome/common/automation_messages.h"
[email protected]5a8db802010-10-06 17:34:4310
11CFProxy::CFProxy(CFProxyTraits* api) : ipc_thread_("ipc"),
12 sync_dispatcher_(&tab2delegate_),
13 ipc_sender_(NULL),
14 api_(api),
15 delegate_count_(0),
16 is_connected_(false) {
17}
18
19CFProxy::~CFProxy() {
20 ipc_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
21 &CFProxy::CleanupOnIoThread));
22 // ipc_thread destructor will do the Stop anyway. this is for debug :)
23 ipc_thread_.Stop();
24}
25
26
27void CFProxy::Init(const ProxyParams& params) {
28 ipc_thread_.StartWithOptions(base::Thread::Options(MessageLoop::TYPE_IO, 0));
29 ipc_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
30 &CFProxy::InitInIoThread, params));
31}
32
[email protected]314a06962010-10-20 21:32:3233int CFProxy::AddDelegate(ChromeProxyDelegate* delegate) {
[email protected]5a8db802010-10-06 17:34:4334 ipc_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
[email protected]314a06962010-10-20 21:32:3235 &CFProxy::AddDelegateOnIoThread, delegate));
[email protected]5a8db802010-10-06 17:34:4336 return ++delegate_count_;
37}
38
[email protected]314a06962010-10-20 21:32:3239int CFProxy::RemoveDelegate(ChromeProxyDelegate* delegate) {
[email protected]5a8db802010-10-06 17:34:4340 ipc_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
[email protected]314a06962010-10-20 21:32:3241 &CFProxy::RemoveDelegateOnIoThread, delegate));
[email protected]5a8db802010-10-06 17:34:4342 return --delegate_count_;
43}
44
[email protected]314a06962010-10-20 21:32:3245void CFProxy::AddDelegateOnIoThread(ChromeProxyDelegate* delegate) {
[email protected]5a8db802010-10-06 17:34:4346 DCHECK(CalledOnIpcThread());
[email protected]314a06962010-10-20 21:32:3247 DelegateHolder::AddDelegate(delegate);
[email protected]5a8db802010-10-06 17:34:4348 if (is_connected_) {
[email protected]314a06962010-10-20 21:32:3249 delegate->Connected(this);
[email protected]5a8db802010-10-06 17:34:4350 }
51}
52
[email protected]314a06962010-10-20 21:32:3253void CFProxy::RemoveDelegateOnIoThread(ChromeProxyDelegate* delegate) {
[email protected]5a8db802010-10-06 17:34:4354 DCHECK(CalledOnIpcThread());
[email protected]314a06962010-10-20 21:32:3255 // Cancel any calls in progress.
56 sync_dispatcher_.Cancel(delegate);
57 DelegateHolder::RemoveDelegate(delegate);
58 delegate->Disconnected();
[email protected]5a8db802010-10-06 17:34:4359}
60
61void CFProxy::InitInIoThread(const ProxyParams& params) {
62 DCHECK(CalledOnIpcThread());
63 std::string channel_id = GenerateChannelId();
64 ipc_sender_ = api_->CreateChannel(channel_id, this);
65 std::wstring cmd_line = BuildCmdLine(channel_id, params.profile_path,
66 params.extra_params);
67 if (api_->LaunchApp(cmd_line)) {
68 CancelableTask* launch_timeout = NewRunnableMethod(this,
69 &CFProxy::LaunchTimeOut);
70 ipc_thread_.message_loop()->PostDelayedTask(FROM_HERE, launch_timeout,
71 params.timeout.InMilliseconds());
72 } else {
73 OnPeerLost(ChromeProxyDelegate::CHROME_EXE_LAUNCH_FAILED);
74 }
75}
76
77void CFProxy::CleanupOnIoThread() {
78 DCHECK(CalledOnIpcThread());
79 if (ipc_sender_) {
80 api_->CloseChannel(ipc_sender_);
81 ipc_sender_ = NULL;
82 }
83 // TODO(stoyan): shall we notify delegates?
84 // The object is dying, so under normal circumstances there should be
85 // no delegates.
86 DCHECK_EQ(0, delegate_count_);
87 DCHECK_EQ(0u, delegate_list_.size());
88 DCHECK_EQ(0u, tab2delegate_.size());
89}
90
91void CFProxy::LaunchTimeOut() {
92 DCHECK(CalledOnIpcThread());
93 if (!is_connected_) {
94 OnPeerLost(ChromeProxyDelegate::CHROME_EXE_LAUNCH_TIMEOUT);
95 }
96}
97
98void CFProxy::OnPeerLost(ChromeProxyDelegate::DisconnectReason reason) {
99 // Kill the channel. Inform delegates
100 DCHECK(CalledOnIpcThread());
101 if (ipc_sender_) {
102 api_->CloseChannel(ipc_sender_);
103 ipc_sender_ = NULL;
104 }
105
106 for (DelegateList::iterator it = delegate_list_.begin();
107 it != delegate_list_.end(); ++it) {
108 (*it)->PeerLost(this, reason);
109 }
110}
111
112void CFProxy::SendIpcMessage(IPC::Message* m) {
113 ipc_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
114 &CFProxy::SendIpcMessageOnIoThread, m));
115}
116
117void CFProxy::SendIpcMessageOnIoThread(IPC::Message* m) {
118 DCHECK(CalledOnIpcThread());
119 if (ipc_sender_) {
120 ipc_sender_->Send(m);
121 } else {
122 delete m;
123 }
124}
125
126//////////////////////////////////////////////////////////////////////////
127// Sync messages.
[email protected]5a8db802010-10-06 17:34:43128void CFProxy::Tab_Find(int tab, const string16& search_string,
129 FindInPageDirection forward, FindInPageCase match_case,
130 bool find_next) {
131 AutomationMsg_Find_Params params;
132 params.unused = 0;
133 params.search_string = search_string;
134 params.find_next = find_next;
135 params.match_case = (match_case == CASE_SENSITIVE);
136 params.forward = (forward == FWD);
[email protected]f5494d42010-12-23 22:15:34137 IPC::SyncMessage* m = new AutomationMsg_Find(tab, params, NULL, NULL);
[email protected]5a8db802010-10-06 17:34:43138 // Not interested in result.
139 sync_dispatcher_.QueueSyncMessage(m, NULL, NULL);
140 SendIpcMessage(m);
141}
142
143void CFProxy::Tab_OverrideEncoding(int tab, const char* encoding) {
[email protected]f5494d42010-12-23 22:15:34144 IPC::SyncMessage* m = new AutomationMsg_OverrideEncoding(tab, encoding, NULL);
[email protected]5a8db802010-10-06 17:34:43145 // Not interested in result.
146 sync_dispatcher_.QueueSyncMessage(m, NULL, NULL);
147 SendIpcMessage(m);
148}
149
150void CFProxy::Tab_Navigate(int tab, const GURL& url, const GURL& referrer) {
[email protected]f5494d42010-12-23 22:15:34151 IPC::SyncMessage* m = new AutomationMsg_NavigateInExternalTab(
[email protected]5a8db802010-10-06 17:34:43152 tab, url, referrer, NULL);
153 // We probably are not interested in result since provider just checks
154 // whether tab handle is valid.
155 sync_dispatcher_.QueueSyncMessage(m, NULL, NULL);
156 SendIpcMessage(m);
157}
158
159void CFProxy::CreateTab(ChromeProxyDelegate* delegate,
[email protected]f5494d42010-12-23 22:15:34160 const ExternalTabSettings& p) {
161 IPC::SyncMessage* m = new AutomationMsg_CreateExternalTab(p, 0, 0, 0, 0);
[email protected]5a8db802010-10-06 17:34:43162 sync_dispatcher_.QueueSyncMessage(m, delegate, NULL);
163 SendIpcMessage(m);
164}
165
166void CFProxy::ConnectTab(ChromeProxyDelegate* delegate, HWND hwnd,
167 uint64 cookie) {
[email protected]f5494d42010-12-23 22:15:34168 IPC::SyncMessage* m = new AutomationMsg_ConnectExternalTab(cookie, true,
[email protected]751bf4b2010-11-05 22:06:31169 hwnd, NULL, NULL, NULL, 0);
[email protected]5a8db802010-10-06 17:34:43170 sync_dispatcher_.QueueSyncMessage(m, delegate, NULL);
171 SendIpcMessage(m);
172}
173
174void CFProxy::BlockTab(uint64 cookie) {
[email protected]f5494d42010-12-23 22:15:34175 IPC::SyncMessage* m = new AutomationMsg_ConnectExternalTab(cookie, false,
[email protected]751bf4b2010-11-05 22:06:31176 NULL, NULL, NULL, NULL, 0);
[email protected]5a8db802010-10-06 17:34:43177 sync_dispatcher_.QueueSyncMessage(m, NULL, NULL);
178 SendIpcMessage(m);
179}
180
181void CFProxy::Tab_RunUnloadHandlers(int tab) {
[email protected]f5494d42010-12-23 22:15:34182 IPC::SyncMessage* m = new AutomationMsg_RunUnloadHandlers(tab, 0);
[email protected]5a8db802010-10-06 17:34:43183 ChromeProxyDelegate* p = Tab2Delegate(tab);
184 sync_dispatcher_.QueueSyncMessage(m, p, NULL);
185 SendIpcMessage(m);
186}
187
188// IPC::Channel::Listener
[email protected]a95986a82010-12-24 06:19:28189bool CFProxy::OnMessageReceived(const IPC::Message& message) {
[email protected]5a8db802010-10-06 17:34:43190 // Handle sync message reply.
191 bool done = sync_dispatcher_.OnReplyReceived(&message);
192 if (done)
[email protected]a95986a82010-12-24 06:19:28193 return true;
[email protected]5a8db802010-10-06 17:34:43194
195 // Handle tab related message.
[email protected]f5494d42010-12-23 22:15:34196 ChromeProxyDelegate* d = Tab2Delegate(message.routing_id());
197 if (d)
198 return d->OnMessageReceived(message);
[email protected]5a8db802010-10-06 17:34:43199
200 DLOG(WARNING) << "Unknown message received!";
[email protected]a95986a82010-12-24 06:19:28201 return false;
[email protected]5a8db802010-10-06 17:34:43202}
203
204void CFProxy::OnChannelConnected(int32 peer_pid) {
205 is_connected_ = true;
206 // TODO(stoyan): May be we should wait for Hello message.
207 for (DelegateList::iterator it = delegate_list_.begin();
208 it != delegate_list_.end(); ++it) {
209 (*it)->Connected(this);
210 }
211}
212
213void CFProxy::OnChannelError() {
214 is_connected_ = false;
215
216 // Inform the sync message callbacks that there are not going to see
217 // any reply.
218 sync_dispatcher_.OnChannelClosed();
219 OnPeerLost(ChromeProxyDelegate::CHANNEL_ERROR);
220
221 // TODO(stoyan): Relaunch?
222}