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