| // Copyright (c) 2006-2008 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 SANDBOX_SRC_SHAREDMEM_IPC_CLIENT_H__ |
| #define SANDBOX_SRC_SHAREDMEM_IPC_CLIENT_H__ |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include "sandbox/win/src/crosscall_params.h" |
| #include "sandbox/win/src/sandbox.h" |
| |
| // IPC transport implementation that uses shared memory. |
| // This is the client side |
| // |
| // The shared memory is divided on blocks called channels, and potentially |
| // it can perform as many concurrent IPC calls as channels. The IPC over |
| // each channel is strictly synchronous for the client. |
| // |
| // Each channel as a channel control section associated with. Each control |
| // section has two kernel events (known as ping and pong) and a integer |
| // variable that maintains a state |
| // |
| // this is the state diagram of a channel: |
| // |
| // locked in service |
| // kFreeChannel---------->BusyChannel-------------->kAckChannel |
| // ^ | |
| // |_________________________________________________| |
| // answer ready |
| // |
| // The protocol is as follows: |
| // 1) client finds a free channel: state = kFreeChannel |
| // 2) does an atomic compare-and-swap, now state = BusyChannel |
| // 3) client writes the data into the channel buffer |
| // 4) client signals the ping event and waits (blocks) on the pong event |
| // 5) eventually the server signals the pong event |
| // 6) the client awakes and reads the answer from the same channel |
| // 7) the client updates its InOut parameters with the new data from the |
| // shared memory section. |
| // 8) the client atomically sets the state = kFreeChannel |
| // |
| // In the shared memory the layout is as follows: |
| // |
| // [ channel count ] |
| // [ channel control 0] |
| // [ channel control 1] |
| // [ channel control N] |
| // [ channel buffer 0 ] 1024 bytes |
| // [ channel buffer 1 ] 1024 bytes |
| // [ channel buffer N ] 1024 bytes |
| // |
| // By default each channel buffer is 1024 bytes |
| namespace sandbox { |
| |
| // the possible channel states as described above |
| enum ChannelState { |
| // channel is free |
| kFreeChannel = 1, |
| // IPC in progress client side |
| kBusyChannel, |
| // IPC in progress server side |
| kAckChannel, |
| // not used right now |
| kReadyChannel, |
| // IPC abandoned by client side |
| kAbandonedChannel |
| }; |
| |
| // The next two constants control the time outs for the IPC. |
| const DWORD kIPCWaitTimeOut1 = 1000; // Milliseconds. |
| const DWORD kIPCWaitTimeOut2 = 50; // Milliseconds. |
| |
| // the channel control structure |
| struct ChannelControl { |
| // points to be beginning of the channel buffer, where data goes |
| size_t channel_base; |
| // maintains the state from the ChannelState enumeration |
| volatile LONG state; |
| // the ping event is signaled by the client when the IPC data is ready on |
| // the buffer |
| HANDLE ping_event; |
| // the client waits on the pong event for the IPC answer back |
| HANDLE pong_event; |
| // the IPC unique identifier |
| uint32_t ipc_tag; |
| }; |
| |
| struct IPCControl { |
| // total number of channels available, some might be busy at a given time |
| size_t channels_count; |
| // handle to a shared mutex to detect when the server is dead |
| HANDLE server_alive; |
| // array of channel control structures |
| ChannelControl channels[1]; |
| }; |
| |
| // the actual shared memory IPC implementation class. This object is designed |
| // to be lightweight so it can be constructed on-site (at the calling place) |
| // wherever an IPC call is needed. |
| class SharedMemIPCClient { |
| public: |
| // Creates the IPC client. |
| // as parameter it takes the base address of the shared memory |
| explicit SharedMemIPCClient(void* shared_mem); |
| |
| // locks a free channel and returns the channel buffer memory base. This call |
| // blocks until there is a free channel |
| void* GetBuffer(); |
| |
| // releases the lock on the channel, for other to use. call this if you have |
| // called GetBuffer and you want to abort but have not called yet DoCall() |
| void FreeBuffer(void* buffer); |
| |
| // Performs the actual IPC call. |
| // params: The blob of packed input parameters. |
| // answer: upon IPC completion, it contains the server answer to the IPC. |
| // If the return value is not SBOX_ERROR_CHANNEL_ERROR, the caller has to free |
| // the channel. |
| // returns ALL_OK if the IPC mechanism successfully delivered. You still need |
| // to check on the answer structure to see the actual IPC result. |
| ResultCode DoCall(CrossCallParams* params, CrossCallReturn* answer); |
| |
| private: |
| // Returns the index of the first free channel. It sets 'severe_failure' |
| // to true if there is an unrecoverable error that does not allow to |
| // find a channel. |
| size_t LockFreeChannel(bool* severe_failure); |
| // Return the channel index given the address of the buffer. |
| size_t ChannelIndexFromBuffer(const void* buffer); |
| IPCControl* control_; |
| // point to the first channel base |
| char* first_base_; |
| }; |
| |
| } // namespace sandbox |
| |
| #endif // SANDBOX_SRC_SHAREDMEM_IPC_CLIENT_H__ |