Home | History | Annotate | Download | only in proxy
      1 // Copyright 2014 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 "ppapi/proxy/file_mapping_resource.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/numerics/safe_conversions.h"
      9 #include "base/task_runner_util.h"
     10 #include "ppapi/c/pp_errors.h"
     11 #include "ppapi/shared_impl/tracked_callback.h"
     12 #include "ppapi/shared_impl/var.h"
     13 #include "ppapi/thunk/enter.h"
     14 #include "ppapi/thunk/ppb_file_io_api.h"
     15 
     16 namespace ppapi {
     17 namespace proxy {
     18 
     19 FileMappingResource::FileMappingResource(Connection connection,
     20                                          PP_Instance instance)
     21     : PluginResource(connection, instance) {
     22 }
     23 
     24 FileMappingResource::~FileMappingResource() {
     25 }
     26 
     27 thunk::PPB_FileMapping_API* FileMappingResource::AsPPB_FileMapping_API() {
     28   return this;
     29 }
     30 
     31 int32_t FileMappingResource::Map(PP_Instance /* instance */,
     32                                  PP_Resource file_io,
     33                                  int64_t length,
     34                                  uint32_t protection,
     35                                  uint32_t flags,
     36                                  int64_t offset,
     37                                  void** address,
     38                                  scoped_refptr<TrackedCallback> callback) {
     39   thunk::EnterResourceNoLock<thunk::PPB_FileIO_API> enter(file_io, true);
     40   if (enter.failed())
     41     return PP_ERROR_BADARGUMENT;
     42   FileIOResource* file_io_resource =
     43       static_cast<FileIOResource*>(enter.object());
     44   scoped_refptr<FileIOResource::FileHolder> file_holder =
     45       file_io_resource->file_holder();
     46   if (!FileIOResource::FileHolder::IsValid(file_holder))
     47     return PP_ERROR_FAILED;
     48   if (length < 0 || offset < 0 ||
     49       !base::IsValueInRangeForNumericType<off_t>(offset)) {
     50     return PP_ERROR_BADARGUMENT;
     51   }
     52   if (!base::IsValueInRangeForNumericType<size_t>(length)) {
     53     return PP_ERROR_NOMEMORY;
     54   }
     55 
     56   // Ensure any bits we don't recognize are zero.
     57   if (protection &
     58       ~(PP_FILEMAPPROTECTION_READ | PP_FILEMAPPROTECTION_WRITE)) {
     59     return PP_ERROR_BADARGUMENT;
     60   }
     61   if (flags &
     62       ~(PP_FILEMAPFLAG_SHARED | PP_FILEMAPFLAG_PRIVATE |
     63         PP_FILEMAPFLAG_FIXED)) {
     64     return PP_ERROR_BADARGUMENT;
     65   }
     66   // Ensure at least one of SHARED and PRIVATE is set.
     67   if (!(flags & (PP_FILEMAPFLAG_SHARED | PP_FILEMAPFLAG_PRIVATE)))
     68     return PP_ERROR_BADARGUMENT;
     69   // Ensure at most one of SHARED and PRIVATE is set.
     70   if ((flags & PP_FILEMAPFLAG_SHARED) &&
     71       (flags & PP_FILEMAPFLAG_PRIVATE)) {
     72     return PP_ERROR_BADARGUMENT;
     73   }
     74   if (!address)
     75     return PP_ERROR_BADARGUMENT;
     76 
     77   base::Callback<MapResult()> map_cb(
     78       base::Bind(&FileMappingResource::DoMapBlocking, file_holder, *address,
     79                  length, protection, flags, offset));
     80   if (callback->is_blocking()) {
     81     // The plugin could release its reference to this instance when we release
     82     // the proxy lock below.
     83     scoped_refptr<FileMappingResource> protect(this);
     84     MapResult map_result;
     85     {
     86       // Release the proxy lock while making a potentially slow file call.
     87       ProxyAutoUnlock unlock;
     88       map_result = map_cb.Run();
     89     }
     90     OnMapCompleted(address, length, callback, map_result);
     91     return map_result.result;
     92   } else {
     93     base::PostTaskAndReplyWithResult(
     94       PpapiGlobals::Get()->GetFileTaskRunner(),
     95       FROM_HERE,
     96       map_cb,
     97       RunWhileLocked(Bind(&FileMappingResource::OnMapCompleted,
     98                           this,
     99                           base::Unretained(address),
    100                           length,
    101                           callback)));
    102     return PP_OK_COMPLETIONPENDING;
    103   }
    104 }
    105 
    106 int32_t FileMappingResource::Unmap(PP_Instance /* instance */,
    107                                    const void* address,
    108                                    int64_t length,
    109                                    scoped_refptr<TrackedCallback> callback) {
    110   if (!address)
    111     return PP_ERROR_BADARGUMENT;
    112   if (!base::IsValueInRangeForNumericType<size_t>(length))
    113     return PP_ERROR_BADARGUMENT;
    114 
    115   base::Callback<int32_t()> unmap_cb(
    116       base::Bind(&FileMappingResource::DoUnmapBlocking, address, length));
    117   if (callback->is_blocking()) {
    118     // Release the proxy lock while making a potentially slow file call.
    119     ProxyAutoUnlock unlock;
    120     return unmap_cb.Run();
    121   } else {
    122     base::PostTaskAndReplyWithResult(
    123       PpapiGlobals::Get()->GetFileTaskRunner(),
    124       FROM_HERE,
    125       unmap_cb,
    126       RunWhileLocked(Bind(&TrackedCallback::Run, callback)));
    127     return PP_OK_COMPLETIONPENDING;
    128   }
    129 }
    130 
    131 int64_t FileMappingResource::GetMapPageSize(PP_Instance /* instance */) {
    132   return DoGetMapPageSize();
    133 }
    134 
    135 void FileMappingResource::OnMapCompleted(
    136     void** mapped_address_out_param,
    137     int64_t length,
    138     scoped_refptr<TrackedCallback> callback,
    139     const MapResult& map_result) {
    140   if (callback->aborted()) {
    141     if (map_result.result == PP_OK) {
    142       // If the Map operation was successful, we need to Unmap to avoid leaks.
    143       // The plugin won't get the address, so doesn't have a chance to do the
    144       // Unmap.
    145       PpapiGlobals::Get()->GetFileTaskRunner()->PostTask(
    146           FROM_HERE,
    147           base::Bind(base::IgnoreResult(&FileMappingResource::DoUnmapBlocking),
    148                      map_result.address,
    149                      length));
    150     }
    151     return;
    152   }
    153   if (map_result.result == PP_OK)
    154     *mapped_address_out_param = map_result.address;
    155   if (!callback->is_blocking())
    156     callback->Run(map_result.result);
    157 }
    158 
    159 }  // namespace proxy
    160 }  // namespace ppapi
    161