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