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