sync_socket_win.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. // Copyright (c) 2012 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. #include "base/sync_socket.h"
  5. #include <limits.h>
  6. #include <stddef.h>
  7. #include "base/logging.h"
  8. #include "base/rand_util.h"
  9. #include "base/threading/scoped_blocking_call.h"
  10. #include "base/win/scoped_handle.h"
  11. namespace base {
  12. using win::ScopedHandle;
  13. namespace {
  14. // IMPORTANT: do not change how this name is generated because it will break
  15. // in sandboxed scenarios as we might have by-name policies that allow pipe
  16. // creation. Also keep the secure random number generation.
  17. const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\chrome.sync.%u.%u.%lu";
  18. const size_t kPipePathMax = std::size(kPipeNameFormat) + (3 * 10) + 1;
  19. // To avoid users sending negative message lengths to Send/Receive
  20. // we clamp message lengths, which are size_t, to no more than INT_MAX.
  21. const size_t kMaxMessageLength = static_cast<size_t>(INT_MAX);
  22. const int kOutBufferSize = 4096;
  23. const int kInBufferSize = 4096;
  24. const int kDefaultTimeoutMilliSeconds = 1000;
  25. bool CreatePairImpl(ScopedHandle* socket_a,
  26. ScopedHandle* socket_b,
  27. bool overlapped) {
  28. DCHECK_NE(socket_a, socket_b);
  29. DCHECK(!socket_a->is_valid());
  30. DCHECK(!socket_b->is_valid());
  31. wchar_t name[kPipePathMax];
  32. ScopedHandle handle_a;
  33. DWORD flags = PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE;
  34. if (overlapped)
  35. flags |= FILE_FLAG_OVERLAPPED;
  36. do {
  37. unsigned long rnd_name;
  38. RandBytes(&rnd_name, sizeof(rnd_name));
  39. swprintf(name, kPipePathMax,
  40. kPipeNameFormat,
  41. GetCurrentProcessId(),
  42. GetCurrentThreadId(),
  43. rnd_name);
  44. handle_a.Set(CreateNamedPipeW(
  45. name,
  46. flags,
  47. PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
  48. 1,
  49. kOutBufferSize,
  50. kInBufferSize,
  51. kDefaultTimeoutMilliSeconds,
  52. NULL));
  53. } while (!handle_a.is_valid() && (GetLastError() == ERROR_PIPE_BUSY));
  54. if (!handle_a.is_valid()) {
  55. NOTREACHED();
  56. return false;
  57. }
  58. // The SECURITY_ANONYMOUS flag means that the server side (handle_a) cannot
  59. // impersonate the client (handle_b). This allows us not to care which side
  60. // ends up in which side of a privilege boundary.
  61. flags = SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS;
  62. if (overlapped)
  63. flags |= FILE_FLAG_OVERLAPPED;
  64. ScopedHandle handle_b(CreateFileW(name,
  65. GENERIC_READ | GENERIC_WRITE,
  66. 0, // no sharing.
  67. NULL, // default security attributes.
  68. OPEN_EXISTING, // opens existing pipe.
  69. flags,
  70. NULL)); // no template file.
  71. if (!handle_b.is_valid()) {
  72. DPLOG(ERROR) << "CreateFileW failed";
  73. return false;
  74. }
  75. if (!ConnectNamedPipe(handle_a.get(), NULL)) {
  76. DWORD error = GetLastError();
  77. if (error != ERROR_PIPE_CONNECTED) {
  78. DPLOG(ERROR) << "ConnectNamedPipe failed";
  79. return false;
  80. }
  81. }
  82. *socket_a = std::move(handle_a);
  83. *socket_b = std::move(handle_b);
  84. return true;
  85. }
  86. // Inline helper to avoid having the cast everywhere.
  87. DWORD GetNextChunkSize(size_t current_pos, size_t max_size) {
  88. // The following statement is for 64 bit portability.
  89. return static_cast<DWORD>(((max_size - current_pos) <= UINT_MAX) ?
  90. (max_size - current_pos) : UINT_MAX);
  91. }
  92. // Template function that supports calling ReadFile or WriteFile in an
  93. // overlapped fashion and waits for IO completion. The function also waits
  94. // on an event that can be used to cancel the operation. If the operation
  95. // is cancelled, the function returns and closes the relevant socket object.
  96. template <typename BufferType, typename Function>
  97. size_t CancelableFileOperation(Function operation,
  98. HANDLE file,
  99. BufferType* buffer,
  100. size_t length,
  101. WaitableEvent* io_event,
  102. WaitableEvent* cancel_event,
  103. CancelableSyncSocket* socket,
  104. DWORD timeout_in_ms) {
  105. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  106. // The buffer must be byte size or the length check won't make much sense.
  107. static_assert(sizeof(buffer[0]) == sizeof(char), "incorrect buffer type");
  108. DCHECK_GT(length, 0u);
  109. DCHECK_LE(length, kMaxMessageLength);
  110. DCHECK_NE(file, SyncSocket::kInvalidHandle);
  111. // Track the finish time so we can calculate the timeout as data is read.
  112. TimeTicks current_time, finish_time;
  113. if (timeout_in_ms != INFINITE) {
  114. current_time = TimeTicks::Now();
  115. finish_time = current_time + base::Milliseconds(timeout_in_ms);
  116. }
  117. size_t count = 0;
  118. do {
  119. // The OVERLAPPED structure will be modified by ReadFile or WriteFile.
  120. OVERLAPPED ol = { 0 };
  121. ol.hEvent = io_event->handle();
  122. const DWORD chunk = GetNextChunkSize(count, length);
  123. // This is either the ReadFile or WriteFile call depending on whether
  124. // we're receiving or sending data.
  125. DWORD len = 0;
  126. const BOOL operation_ok = operation(
  127. file, static_cast<BufferType*>(buffer) + count, chunk, &len, &ol);
  128. if (!operation_ok) {
  129. if (::GetLastError() == ERROR_IO_PENDING) {
  130. HANDLE events[] = { io_event->handle(), cancel_event->handle() };
  131. const DWORD wait_result = WaitForMultipleObjects(
  132. std::size(events), events, FALSE,
  133. timeout_in_ms == INFINITE
  134. ? timeout_in_ms
  135. : static_cast<DWORD>(
  136. (finish_time - current_time).InMilliseconds()));
  137. if (wait_result != WAIT_OBJECT_0 + 0) {
  138. // CancelIo() doesn't synchronously cancel outstanding IO, only marks
  139. // outstanding IO for cancellation. We must call GetOverlappedResult()
  140. // below to ensure in flight writes complete before returning.
  141. CancelIo(file);
  142. }
  143. // We set the |bWait| parameter to TRUE for GetOverlappedResult() to
  144. // ensure writes are complete before returning.
  145. if (!GetOverlappedResult(file, &ol, &len, TRUE))
  146. len = 0;
  147. if (wait_result == WAIT_OBJECT_0 + 1) {
  148. DVLOG(1) << "Shutdown was signaled. Closing socket.";
  149. socket->Close();
  150. return count;
  151. }
  152. // Timeouts will be handled by the while() condition below since
  153. // GetOverlappedResult() may complete successfully after CancelIo().
  154. DCHECK(wait_result == WAIT_OBJECT_0 + 0 || wait_result == WAIT_TIMEOUT);
  155. } else {
  156. break;
  157. }
  158. }
  159. count += len;
  160. // Quit the operation if we can't write/read anymore.
  161. if (len != chunk)
  162. break;
  163. // Since TimeTicks::Now() is expensive, only bother updating the time if we
  164. // have more work to do.
  165. if (timeout_in_ms != INFINITE && count < length)
  166. current_time = base::TimeTicks::Now();
  167. } while (count < length &&
  168. (timeout_in_ms == INFINITE || current_time < finish_time));
  169. return count;
  170. }
  171. } // namespace
  172. // static
  173. bool SyncSocket::CreatePair(SyncSocket* socket_a, SyncSocket* socket_b) {
  174. return CreatePairImpl(&socket_a->handle_, &socket_b->handle_, false);
  175. }
  176. void SyncSocket::Close() {
  177. handle_.Close();
  178. }
  179. size_t SyncSocket::Send(const void* buffer, size_t length) {
  180. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  181. DCHECK_GT(length, 0u);
  182. DCHECK_LE(length, kMaxMessageLength);
  183. DCHECK(IsValid());
  184. size_t count = 0;
  185. while (count < length) {
  186. DWORD len;
  187. DWORD chunk = GetNextChunkSize(count, length);
  188. if (::WriteFile(handle(), static_cast<const char*>(buffer) + count, chunk,
  189. &len, NULL) == FALSE) {
  190. return count;
  191. }
  192. count += len;
  193. }
  194. return count;
  195. }
  196. size_t SyncSocket::ReceiveWithTimeout(void* buffer,
  197. size_t length,
  198. TimeDelta timeout) {
  199. NOTIMPLEMENTED();
  200. return 0;
  201. }
  202. size_t SyncSocket::Receive(void* buffer, size_t length) {
  203. ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
  204. DCHECK_GT(length, 0u);
  205. DCHECK_LE(length, kMaxMessageLength);
  206. DCHECK(IsValid());
  207. size_t count = 0;
  208. while (count < length) {
  209. DWORD len;
  210. DWORD chunk = GetNextChunkSize(count, length);
  211. if (::ReadFile(handle(), static_cast<char*>(buffer) + count, chunk, &len,
  212. NULL) == FALSE) {
  213. return count;
  214. }
  215. count += len;
  216. }
  217. return count;
  218. }
  219. size_t SyncSocket::Peek() {
  220. DWORD available = 0;
  221. PeekNamedPipe(handle(), NULL, 0, NULL, &available, NULL);
  222. return available;
  223. }
  224. bool SyncSocket::IsValid() const {
  225. return handle_.is_valid();
  226. }
  227. SyncSocket::Handle SyncSocket::handle() const {
  228. return handle_.get();
  229. }
  230. SyncSocket::Handle SyncSocket::Release() {
  231. return handle_.release();
  232. }
  233. bool CancelableSyncSocket::Shutdown() {
  234. // This doesn't shut down the pipe immediately, but subsequent Receive or Send
  235. // methods will fail straight away.
  236. shutdown_event_.Signal();
  237. return true;
  238. }
  239. void CancelableSyncSocket::Close() {
  240. SyncSocket::Close();
  241. shutdown_event_.Reset();
  242. }
  243. size_t CancelableSyncSocket::Send(const void* buffer, size_t length) {
  244. static const DWORD kWaitTimeOutInMs = 500;
  245. return CancelableFileOperation(
  246. &::WriteFile, handle(), reinterpret_cast<const char*>(buffer), length,
  247. &file_operation_, &shutdown_event_, this, kWaitTimeOutInMs);
  248. }
  249. size_t CancelableSyncSocket::Receive(void* buffer, size_t length) {
  250. return CancelableFileOperation(
  251. &::ReadFile, handle(), reinterpret_cast<char*>(buffer), length,
  252. &file_operation_, &shutdown_event_, this, INFINITE);
  253. }
  254. size_t CancelableSyncSocket::ReceiveWithTimeout(void* buffer,
  255. size_t length,
  256. TimeDelta timeout) {
  257. return CancelableFileOperation(&::ReadFile, handle(),
  258. reinterpret_cast<char*>(buffer), length,
  259. &file_operation_, &shutdown_event_, this,
  260. static_cast<DWORD>(timeout.InMilliseconds()));
  261. }
  262. // static
  263. bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a,
  264. CancelableSyncSocket* socket_b) {
  265. return CreatePairImpl(&socket_a->handle_, &socket_b->handle_, true);
  266. }
  267. } // namespace base