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__ 137