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