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
52namespace sandbox {
53
54// the possible channel states as described above
55enum 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.
69const DWORD kIPCWaitTimeOut1 = 1000;   // Milliseconds.
70const DWORD kIPCWaitTimeOut2 =   50;   // Milliseconds.
71
72// the channel control structure
73struct 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
87struct 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.
99class 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