Home | History | Annotate | Download | only in loader
      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 #ifndef CHROME_NACL_NACL_IPC_ADAPTER_H_
      6 #define CHROME_NACL_NACL_IPC_ADAPTER_H_
      7 
      8 #include <map>
      9 #include <queue>
     10 #include <string>
     11 #include <vector>
     12 
     13 #include "base/basictypes.h"
     14 #include "base/callback.h"
     15 #include "base/memory/ref_counted.h"
     16 #include "base/memory/scoped_ptr.h"
     17 #include "base/memory/scoped_vector.h"
     18 #include "base/memory/shared_memory.h"
     19 #include "base/pickle.h"
     20 #include "base/synchronization/condition_variable.h"
     21 #include "base/synchronization/lock.h"
     22 #include "base/task_runner.h"
     23 #include "ipc/ipc_listener.h"
     24 #include "ipc/ipc_platform_file.h"
     25 #include "ppapi/c/pp_stdint.h"
     26 #include "ppapi/proxy/nacl_message_scanner.h"
     27 
     28 struct NaClDesc;
     29 struct NaClImcTypedMsgHdr;
     30 struct PP_Size;
     31 
     32 namespace IPC {
     33 class Channel;
     34 struct ChannelHandle;
     35 }
     36 
     37 namespace ppapi {
     38 class HostResource;
     39 }
     40 
     41 // Adapts a Chrome IPC channel to an IPC channel that we expose to Native
     42 // Client. This provides a mapping in both directions, so when IPC messages
     43 // come in from another process, we rewrite them and allow them to be received
     44 // via a recvmsg-like interface in the NaCl code. When NaCl code calls sendmsg,
     45 // we implement that as sending IPC messages on the channel.
     46 //
     47 // This object also provides the necessary logic for rewriting IPC messages.
     48 // NaCl code is platform-independent and runs in a Posix-like enviroment, but
     49 // some formatting in the message and the way handles are transferred varies
     50 // by platform. This class bridges that gap to provide what looks like a
     51 // normal platform-specific IPC implementation to Chrome, and a Posix-like
     52 // version on every platform to NaCl.
     53 //
     54 // This object must be threadsafe since the nacl environment determines which
     55 // thread every function is called on.
     56 class NaClIPCAdapter : public base::RefCountedThreadSafe<NaClIPCAdapter>,
     57                        public IPC::Listener {
     58  public:
     59   // Chrome's IPC message format varies by platform, NaCl's does not. In
     60   // particular, the header has some extra fields on Posix platforms. Since
     61   // NaCl is a Posix environment, it gets that version of the header. This
     62   // header is duplicated here so we have a cross-platform definition of the
     63   // header we're exposing to NaCl.
     64 #pragma pack(push, 4)
     65   struct NaClMessageHeader : public Pickle::Header {
     66     int32 routing;
     67     uint32 type;
     68     uint32 flags;
     69     uint16 num_fds;
     70     uint16 pad;
     71   };
     72 #pragma pack(pop)
     73 
     74   // Creates an adapter, using the thread associated with the given task
     75   // runner for posting messages. In normal use, the task runner will post to
     76   // the I/O thread of the process.
     77   //
     78   // If you use this constructor, you MUST call ConnectChannel after the
     79   // NaClIPCAdapter is constructed, or the NaClIPCAdapter's channel will not be
     80   // connected.
     81   NaClIPCAdapter(const IPC::ChannelHandle& handle, base::TaskRunner* runner);
     82 
     83   // Initializes with a given channel that's already created for testing
     84   // purposes. This function will take ownership of the given channel.
     85   NaClIPCAdapter(scoped_ptr<IPC::Channel> channel, base::TaskRunner* runner);
     86 
     87   // Connect the channel. This must be called after the constructor that accepts
     88   // an IPC::ChannelHandle, and causes the Channel to be connected on the IO
     89   // thread.
     90   void ConnectChannel();
     91 
     92   // Implementation of sendmsg. Returns the number of bytes written or -1 on
     93   // failure.
     94   int Send(const NaClImcTypedMsgHdr* msg);
     95 
     96   // Implementation of recvmsg. Returns the number of bytes read or -1 on
     97   // failure. This will block until there's an error or there is data to
     98   // read.
     99   int BlockingReceive(NaClImcTypedMsgHdr* msg);
    100 
    101   // Closes the IPC channel.
    102   void CloseChannel();
    103 
    104   // Make a NaClDesc that refers to this NaClIPCAdapter. Note that the returned
    105   // NaClDesc is reference-counted, and a reference is returned.
    106   NaClDesc* MakeNaClDesc();
    107 
    108 #if defined(OS_POSIX)
    109   int TakeClientFileDescriptor();
    110 #endif
    111 
    112   // Listener implementation.
    113   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
    114   virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
    115   virtual void OnChannelError() OVERRIDE;
    116 
    117   typedef base::Callback<void(IPC::PlatformFileForTransit, base::FilePath)>
    118       ResolveFileTokenReplyCallback;
    119 
    120   typedef base::Callback<void(uint64_t,  // file_token_lo
    121                               uint64_t,  // file_token_hi
    122                               ResolveFileTokenReplyCallback)>
    123       ResolveFileTokenCallback;
    124 
    125   // Sets a callback to be invoked for resolving file tokens received from the
    126   // renderer. When the file token is resolved, the
    127   // ResolveFileTokenReplyCallback passed inside the ResolveFileTokenCallback
    128   // will be invoked.
    129   void set_resolve_file_token_callback(ResolveFileTokenCallback cb) {
    130     resolve_file_token_cb_ = cb;
    131   }
    132 
    133  private:
    134   friend class base::RefCountedThreadSafe<NaClIPCAdapter>;
    135 
    136   class RewrittenMessage;
    137 
    138   // This is the data that must only be accessed inside the lock. This struct
    139   // just separates it so it's easier to see.
    140   struct LockedData {
    141     LockedData();
    142     ~LockedData();
    143 
    144     // Messages that we have read off of the Chrome IPC channel that are waiting
    145     // to be received by the plugin.
    146     std::queue< scoped_refptr<RewrittenMessage> > to_be_received_;
    147 
    148     ppapi::proxy::NaClMessageScanner nacl_msg_scanner_;
    149 
    150     // Data that we've queued from the plugin to send, but doesn't consist of a
    151     // full message yet. The calling code can break apart the message into
    152     // smaller pieces, and we need to send the message to the other process in
    153     // one chunk.
    154     //
    155     // The IPC channel always starts a new send() at the beginning of each
    156     // message, so we don't need to worry about arbitrary message boundaries.
    157     std::string to_be_sent_;
    158 
    159     bool channel_closed_;
    160   };
    161 
    162   // This is the data that must only be accessed on the I/O thread (as defined
    163   // by TaskRunner). This struct just separates it so it's easier to see.
    164   struct IOThreadData {
    165     IOThreadData();
    166     ~IOThreadData();
    167 
    168     scoped_ptr<IPC::Channel> channel_;
    169 
    170     // When we send a synchronous message (from untrusted to trusted), we store
    171     // its type here, so that later we can associate the reply with its type
    172     // for scanning.
    173     typedef std::map<int, uint32> PendingSyncMsgMap;
    174     PendingSyncMsgMap pending_sync_msgs_;
    175   };
    176 
    177   virtual ~NaClIPCAdapter();
    178 
    179   void OnFileTokenResolved(const IPC::Message& orig_msg,
    180                            IPC::PlatformFileForTransit ipc_fd,
    181                            base::FilePath file_path);
    182 
    183   bool RewriteMessage(const IPC::Message& msg, uint32_t type);
    184 
    185   // Returns 0 if nothing is waiting.
    186   int LockedReceive(NaClImcTypedMsgHdr* msg);
    187 
    188   // Sends a message that we know has been completed to the Chrome process.
    189   bool SendCompleteMessage(const char* buffer, size_t buffer_len);
    190 
    191   // Clears the LockedData.to_be_sent_ structure in a way to make sure that
    192   // the memory is deleted. std::string can sometimes hold onto the buffer
    193   // for future use which we don't want.
    194   void ClearToBeSent();
    195 
    196   void ConnectChannelOnIOThread();
    197   void CloseChannelOnIOThread();
    198   void SendMessageOnIOThread(scoped_ptr<IPC::Message> message);
    199 
    200   // Saves the message to forward to NaCl. This method assumes that the caller
    201   // holds the lock for locked_data_.
    202   void SaveMessage(const IPC::Message& message,
    203                    RewrittenMessage* rewritten_message);
    204 
    205   base::Lock lock_;
    206   base::ConditionVariable cond_var_;
    207 
    208   scoped_refptr<base::TaskRunner> task_runner_;
    209 
    210   ResolveFileTokenCallback resolve_file_token_cb_;
    211 
    212   // To be accessed inside of lock_ only.
    213   LockedData locked_data_;
    214 
    215   // To be accessed on the I/O thread (via task runner) only.
    216   IOThreadData io_thread_data_;
    217 
    218   DISALLOW_COPY_AND_ASSIGN(NaClIPCAdapter);
    219 };
    220 
    221 // Export TranslatePepperFileReadWriteOpenFlags for testing.
    222 int TranslatePepperFileReadWriteOpenFlagsForTesting(int32_t pp_open_flags);
    223 
    224 #endif  // CHROME_NACL_NACL_IPC_ADAPTER_H_
    225