sharedmem_ipc_client.h 5.0 KB

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