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 "pnacl_translation_resource_host.h"
6
7#ifndef DISABLE_NACL
8#include "components/nacl/common/nacl_host_messages.h"
9#include "ppapi/c/pp_errors.h"
10#include "ppapi/shared_impl/ppapi_globals.h"
11
12using ppapi::TrackedCallback;
13using ppapi::PpapiGlobals;
14
15PnaclTranslationResourceHost::CacheRequestInfo::CacheRequestInfo(
16    PP_Bool* hit,
17    PP_FileHandle* handle,
18    scoped_refptr<TrackedCallback> cb)
19    : is_hit(hit), file_handle(handle), callback(cb) {}
20
21PnaclTranslationResourceHost::CacheRequestInfo::~CacheRequestInfo() {}
22
23PnaclTranslationResourceHost::PnaclTranslationResourceHost(
24    const scoped_refptr<base::MessageLoopProxy>& io_message_loop)
25    : io_message_loop_(io_message_loop), channel_(NULL) {}
26
27PnaclTranslationResourceHost::~PnaclTranslationResourceHost() {
28  DCHECK(io_message_loop_->BelongsToCurrentThread());
29  CleanupCacheRequests();
30}
31
32void PnaclTranslationResourceHost::OnFilterAdded(IPC::Channel* channel) {
33  DCHECK(io_message_loop_->BelongsToCurrentThread());
34  channel_ = channel;
35}
36
37void PnaclTranslationResourceHost::OnFilterRemoved() {
38  DCHECK(io_message_loop_->BelongsToCurrentThread());
39  channel_ = NULL;
40}
41
42void PnaclTranslationResourceHost::OnChannelClosing() {
43  DCHECK(io_message_loop_->BelongsToCurrentThread());
44  channel_ = NULL;
45}
46
47bool PnaclTranslationResourceHost::OnMessageReceived(
48    const IPC::Message& message) {
49  DCHECK(io_message_loop_->BelongsToCurrentThread());
50  bool handled = true;
51  IPC_BEGIN_MESSAGE_MAP(PnaclTranslationResourceHost, message)
52    IPC_MESSAGE_HANDLER(NaClViewMsg_NexeTempFileReply, OnNexeTempFileReply)
53    IPC_MESSAGE_UNHANDLED(handled = false)
54  IPC_END_MESSAGE_MAP()
55  return handled;
56}
57
58void PnaclTranslationResourceHost::RequestNexeFd(
59    int render_view_id,
60    PP_Instance instance,
61    const nacl::PnaclCacheInfo& cache_info,
62    PP_Bool* is_hit,
63    PP_FileHandle* file_handle,
64    scoped_refptr<TrackedCallback> callback) {
65  DCHECK(PpapiGlobals::Get()->
66         GetMainThreadMessageLoop()->BelongsToCurrentThread());
67  io_message_loop_->PostTask(
68      FROM_HERE,
69      base::Bind(&PnaclTranslationResourceHost::SendRequestNexeFd,
70                 this,
71                 render_view_id,
72                 instance,
73                 cache_info,
74                 is_hit,
75                 file_handle,
76                 callback));
77  return;
78}
79
80void PnaclTranslationResourceHost::SendRequestNexeFd(
81    int render_view_id,
82    PP_Instance instance,
83    const nacl::PnaclCacheInfo& cache_info,
84    PP_Bool* is_hit,
85    PP_FileHandle* file_handle,
86    scoped_refptr<TrackedCallback> callback) {
87  DCHECK(io_message_loop_->BelongsToCurrentThread());
88  if (!channel_ || !channel_->Send(new NaClHostMsg_NexeTempFileRequest(
89                       render_view_id, instance, cache_info))) {
90    PpapiGlobals::Get()->GetMainThreadMessageLoop()
91        ->PostTask(FROM_HERE,
92                   base::Bind(&TrackedCallback::Run,
93                              callback,
94                              static_cast<int32_t>(PP_ERROR_FAILED)));
95    return;
96  }
97  pending_cache_requests_.insert(std::make_pair(
98      instance, CacheRequestInfo(is_hit, file_handle, callback)));
99}
100
101void PnaclTranslationResourceHost::ReportTranslationFinished(
102    PP_Instance instance,
103    PP_Bool success) {
104  DCHECK(PpapiGlobals::Get()->
105         GetMainThreadMessageLoop()->BelongsToCurrentThread());
106  io_message_loop_->PostTask(
107      FROM_HERE,
108      base::Bind(&PnaclTranslationResourceHost::SendReportTranslationFinished,
109                 this,
110                 instance,
111                 success));
112  return;
113}
114
115void PnaclTranslationResourceHost::SendReportTranslationFinished(
116    PP_Instance instance,
117    PP_Bool success) {
118  DCHECK(io_message_loop_->BelongsToCurrentThread());
119  // If the channel is closed or we have been detached, we are probably shutting
120  // down, so just don't send anything.
121  if (!channel_)
122    return;
123  DCHECK(pending_cache_requests_.count(instance) == 0);
124  channel_->Send(new NaClHostMsg_ReportTranslationFinished(instance,
125                                                           PP_ToBool(success)));
126}
127
128void PnaclTranslationResourceHost::OnNexeTempFileReply(
129    PP_Instance instance,
130    bool is_hit,
131    IPC::PlatformFileForTransit file) {
132  DCHECK(io_message_loop_->BelongsToCurrentThread());
133  CacheRequestInfoMap::iterator it = pending_cache_requests_.find(instance);
134  int32_t status = PP_ERROR_FAILED;
135  // Handle the expected successful case first.
136  if (it != pending_cache_requests_.end() &&
137      !(file == IPC::InvalidPlatformFileForTransit()) &&
138      TrackedCallback::IsPending(it->second.callback)) {
139    *it->second.is_hit = PP_FromBool(is_hit);
140    *it->second.file_handle = IPC::PlatformFileForTransitToPlatformFile(file);
141    status = PP_OK;
142  }
143  if (it == pending_cache_requests_.end()) {
144    DLOG(ERROR) << "Could not find pending request for reply";
145  } else {
146    PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
147        FROM_HERE,
148        base::Bind(&TrackedCallback::Run, it->second.callback, status));
149    pending_cache_requests_.erase(it);
150  }
151  if (file == IPC::InvalidPlatformFileForTransit()) {
152    DLOG(ERROR) << "Got invalid platformfilefortransit";
153  } else if (status != PP_OK) {
154    base::ClosePlatformFile(IPC::PlatformFileForTransitToPlatformFile(file));
155  }
156}
157
158void PnaclTranslationResourceHost::CleanupCacheRequests() {
159  DCHECK(io_message_loop_->BelongsToCurrentThread());
160  for (CacheRequestInfoMap::iterator it = pending_cache_requests_.begin();
161       it != pending_cache_requests_.end();
162       ++it) {
163    it->second.callback->PostAbort();
164  }
165  pending_cache_requests_.clear();
166}
167
168#endif  // DISABLE_NACL
169