|
1 // Copyright (c) 2006-2008 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 SANDBOX_SRC_SHAREDMEM_IPC_CLIENT_H__ |
|
6 #define SANDBOX_SRC_SHAREDMEM_IPC_CLIENT_H__ |
|
7 |
|
8 #include "sandbox/win/src/crosscall_params.h" |
|
9 #include "sandbox/win/src/sandbox.h" |
|
10 |
|
11 // IPC transport implementation that uses shared memory. |
|
12 // This is the client side |
|
13 // |
|
14 // The shared memory is divided on blocks called channels, and potentially |
|
15 // it can perform as many concurrent IPC calls as channels. The IPC over |
|
16 // each channel is strictly synchronous for the client. |
|
17 // |
|
18 // Each channel as a channel control section associated with. Each control |
|
19 // section has two kernel events (known as ping and pong) and a integer |
|
20 // variable that maintains a state |
|
21 // |
|
22 // this is the state diagram of a channel: |
|
23 // |
|
24 // locked in service |
|
25 // kFreeChannel---------->BusyChannel-------------->kAckChannel |
|
26 // ^ | |
|
27 // |_________________________________________________| |
|
28 // answer ready |
|
29 // |
|
30 // The protocol is as follows: |
|
31 // 1) client finds a free channel: state = kFreeChannel |
|
32 // 2) does an atomic compare-and-swap, now state = BusyChannel |
|
33 // 3) client writes the data into the channel buffer |
|
34 // 4) client signals the ping event and waits (blocks) on the pong event |
|
35 // 5) eventually the server signals the pong event |
|
36 // 6) the client awakes and reads the answer from the same channel |
|
37 // 7) the client updates its InOut parameters with the new data from the |
|
38 // shared memory section. |
|
39 // 8) the client atomically sets the state = kFreeChannel |
|
40 // |
|
41 // In the shared memory the layout is as follows: |
|
42 // |
|
43 // [ channel count ] |
|
44 // [ channel control 0] |
|
45 // [ channel control 1] |
|
46 // [ channel control N] |
|
47 // [ channel buffer 0 ] 1024 bytes |
|
48 // [ channel buffer 1 ] 1024 bytes |
|
49 // [ channel buffer N ] 1024 bytes |
|
50 // |
|
51 // By default each channel buffer is 1024 bytes |
|
52 namespace sandbox { |
|
53 |
|
54 // the possible channel states as described above |
|
55 enum ChannelState { |
|
56 // channel is free |
|
57 kFreeChannel = 1, |
|
58 // IPC in progress client side |
|
59 kBusyChannel, |
|
60 // IPC in progress server side |
|
61 kAckChannel, |
|
62 // not used right now |
|
63 kReadyChannel, |
|
64 // IPC abandoned by client side |
|
65 kAbandonnedChannel |
|
66 }; |
|
67 |
|
68 // The next two constants control the time outs for the IPC. |
|
69 const DWORD kIPCWaitTimeOut1 = 1000; // Milliseconds. |
|
70 const DWORD kIPCWaitTimeOut2 = 50; // Milliseconds. |
|
71 |
|
72 // the channel control structure |
|
73 struct ChannelControl { |
|
74 // points to be beginning of the channel buffer, where data goes |
|
75 size_t channel_base; |
|
76 // maintains the state from the ChannelState enumeration |
|
77 volatile LONG state; |
|
78 // the ping event is signaled by the client when the IPC data is ready on |
|
79 // the buffer |
|
80 HANDLE ping_event; |
|
81 // the client waits on the pong event for the IPC answer back |
|
82 HANDLE pong_event; |
|
83 // the IPC unique identifier |
|
84 uint32 ipc_tag; |
|
85 }; |
|
86 |
|
87 struct IPCControl { |
|
88 // total number of channels available, some might be busy at a given time |
|
89 size_t channels_count; |
|
90 // handle to a shared mutex to detect when the server is dead |
|
91 HANDLE server_alive; |
|
92 // array of channel control structures |
|
93 ChannelControl channels[1]; |
|
94 }; |
|
95 |
|
96 // the actual shared memory IPC implementation class. This object is designed |
|
97 // to be lightweight so it can be constructed on-site (at the calling place) |
|
98 // wherever an IPC call is needed. |
|
99 class SharedMemIPCClient { |
|
100 public: |
|
101 // Creates the IPC client. |
|
102 // as parameter it takes the base address of the shared memory |
|
103 explicit SharedMemIPCClient(void* shared_mem); |
|
104 |
|
105 // locks a free channel and returns the channel buffer memory base. This call |
|
106 // blocks until there is a free channel |
|
107 void* GetBuffer(); |
|
108 |
|
109 // releases the lock on the channel, for other to use. call this if you have |
|
110 // called GetBuffer and you want to abort but have not called yet DoCall() |
|
111 void FreeBuffer(void* buffer); |
|
112 |
|
113 // Performs the actual IPC call. |
|
114 // params: The blob of packed input parameters. |
|
115 // answer: upon IPC completion, it contains the server answer to the IPC. |
|
116 // If the return value is not SBOX_ERROR_CHANNEL_ERROR, the caller has to free |
|
117 // the channel. |
|
118 // returns ALL_OK if the IPC mechanism successfully delivered. You still need |
|
119 // to check on the answer structure to see the actual IPC result. |
|
120 ResultCode DoCall(CrossCallParams* params, CrossCallReturn* answer); |
|
121 |
|
122 private: |
|
123 // Returns the index of the first free channel. It sets 'severe_failure' |
|
124 // to true if there is an unrecoverable error that does not allow to |
|
125 // find a channel. |
|
126 size_t LockFreeChannel(bool* severe_failure); |
|
127 // Return the channel index given the address of the buffer. |
|
128 size_t ChannelIndexFromBuffer(const void* buffer); |
|
129 IPCControl* control_; |
|
130 // point to the first channel base |
|
131 char* first_base_; |
|
132 }; |
|
133 |
|
134 } // namespace sandbox |
|
135 |
|
136 #endif // SANDBOX_SRC_SHAREDMEM_IPC_CLIENT_H__ |