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