Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(211)

Side by Side Diff: base/sync_socket_win.cc

Issue 8965053: Implement support for a cancelable SyncSocket. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Using a single event for file operations on Windows. Some comment improvements. Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/sync_socket.h" 5 #include "base/sync_socket.h"
6 #include <limits.h> 6
7 #include <stdio.h>
8 #include <windows.h>
9 #include <sys/types.h>
10 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/win/scoped_handle.h"
9
10 using base::win::ScopedHandle;
11 11
12 12
13 namespace base { 13 namespace base {
14 14
15 namespace { 15 namespace {
16 // This prefix used to be appended to pipe names for pipes 16 // This prefix used to be appended to pipe names for pipes
17 // created in CreatePair. 17 // created in CreatePair.
18 const wchar_t kPipePrefix[] = L"\\\\.\\pipe\\chrome.sync."; 18 const wchar_t kPipePrefix[] = L"\\\\.\\pipe\\chrome.sync.";
19 const size_t kPipePrefixSize = arraysize(kPipePrefix); 19 const size_t kPipePrefixSize = arraysize(kPipePrefix);
20 const size_t kPathMax = 28; // print length of process id + pair count. 20 const size_t kPathMax = 28; // print length of process id + pair count.
21 const size_t kPipePathMax = kPipePrefixSize + kPathMax + 1; 21 const size_t kPipePathMax = kPipePrefixSize + kPathMax + 1;
22 22
23 // To avoid users sending negative message lengths to Send/Receive 23 // To avoid users sending negative message lengths to Send/Receive
24 // we clamp message lengths, which are size_t, to no more than INT_MAX. 24 // we clamp message lengths, which are size_t, to no more than INT_MAX.
25 const size_t kMaxMessageLength = static_cast<size_t>(INT_MAX); 25 const size_t kMaxMessageLength = static_cast<size_t>(INT_MAX);
26 26
27 const int kOutBufferSize = 4096; 27 const int kOutBufferSize = 4096;
28 const int kInBufferSize = 4096; 28 const int kInBufferSize = 4096;
29 const int kDefaultTimeoutMilliSeconds = 1000; 29 const int kDefaultTimeoutMilliSeconds = 1000;
30 30
31 static const SyncSocket::Handle kInvalidHandle = INVALID_HANDLE_VALUE; 31 static const SyncSocket::Handle kInvalidHandle = INVALID_HANDLE_VALUE;
32 32
33 } // namespace 33 bool CreatePairImpl(HANDLE* socket_a, HANDLE* socket_b, bool overlapped) {
34 DCHECK(socket_a != socket_b);
35 DCHECK(*socket_a == kInvalidHandle);
36 DCHECK(*socket_b == kInvalidHandle);
34 37
35 bool SyncSocket::CreatePair(SyncSocket* pair[2]) { 38 wchar_t name[kPipePathMax];
36 Handle handles[2]; 39 ScopedHandle handle_a;
37 SyncSocket* tmp_sockets[2]; 40 DWORD flags = PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE;
41 if (overlapped)
42 flags |= FILE_FLAG_OVERLAPPED;
38 43
39 // Create the two SyncSocket objects first to avoid ugly cleanup issues. 44 do {
40 tmp_sockets[0] = new SyncSocket(kInvalidHandle); 45 unsigned int rnd_name;
41 if (tmp_sockets[0] == NULL) { 46 if (rand_s(&rnd_name) != 0) {
42 return false; 47 NOTREACHED();
43 } 48 return false;
44 tmp_sockets[1] = new SyncSocket(kInvalidHandle); 49 }
45 if (tmp_sockets[1] == NULL) { 50
46 delete tmp_sockets[0]; 51 swprintf(name, kPipePathMax, L"%s%u.%lu",
52 kPipePrefix, GetCurrentProcessId(),
53 rnd_name);
54
55 handle_a.Set(CreateNamedPipeW(name,
56 flags, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, kOutBufferSize,
57 kInBufferSize, kDefaultTimeoutMilliSeconds, NULL));
58
59 if (!handle_a.IsValid()) {
60 DWORD error = GetLastError();
61 if (error != ERROR_ACCESS_DENIED && error != ERROR_PIPE_BUSY)
62 return false;
63 }
64 } while (!handle_a.IsValid());
65
66 flags = SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS;
67 if (overlapped)
68 flags |= FILE_FLAG_OVERLAPPED;
69
70 ScopedHandle handle_b(CreateFileW(name,
71 GENERIC_READ | GENERIC_WRITE,
72 0, // no sharing.
73 NULL, // default security attributes.
74 OPEN_EXISTING, // opens existing pipe.
75 flags, // no impersonation.
76 NULL)); // no template file.
77 if (!handle_b.IsValid()) {
78 DPLOG(ERROR) << "CreateFileW failed";
47 return false; 79 return false;
48 } 80 }
49 81
50 wchar_t name[kPipePathMax]; 82 if (!ConnectNamedPipe(handle_a, NULL)) {
51 do {
52 unsigned int rnd_name;
53 if (rand_s(&rnd_name) != 0)
54 return false;
55 swprintf(name, kPipePathMax, L"%s%u.%lu",
56 kPipePrefix, GetCurrentProcessId(),
57 rnd_name);
58 handles[0] = CreateNamedPipeW(
59 name,
60 PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE,
61 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
62 1,
63 kOutBufferSize,
64 kInBufferSize,
65 kDefaultTimeoutMilliSeconds,
66 NULL);
67 if (handles[0] == INVALID_HANDLE_VALUE &&
68 GetLastError() != ERROR_ACCESS_DENIED &&
69 GetLastError() != ERROR_PIPE_BUSY) {
70 return false;
71 }
72 } while (handles[0] == INVALID_HANDLE_VALUE);
73 handles[1] = CreateFileW(name,
74 GENERIC_READ | GENERIC_WRITE,
75 0, // no sharing.
76 NULL, // default security attributes.
77 OPEN_EXISTING, // opens existing pipe.
78 SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS,
79 // no impersonation.
80 NULL); // no template file.
81 if (handles[1] == INVALID_HANDLE_VALUE) {
82 CloseHandle(handles[0]);
83 return false;
84 }
85 if (ConnectNamedPipe(handles[0], NULL) == FALSE) {
86 DWORD error = GetLastError(); 83 DWORD error = GetLastError();
87 if (error != ERROR_PIPE_CONNECTED) { 84 if (error != ERROR_PIPE_CONNECTED) {
88 CloseHandle(handles[0]); 85 DPLOG(ERROR) << "ConnectNamedPipe failed";
89 CloseHandle(handles[1]);
90 return false; 86 return false;
91 } 87 }
92 } 88 }
93 // Copy the handles out for successful return. 89
94 tmp_sockets[0]->handle_ = handles[0]; 90 *socket_a = handle_a.Take();
95 pair[0] = tmp_sockets[0]; 91 *socket_b = handle_b.Take();
96 tmp_sockets[1]->handle_ = handles[1]; 92
97 pair[1] = tmp_sockets[1];
98 return true; 93 return true;
99 } 94 }
100 95
96 // Template function that supports calling ReadFile or WriteFile in an
97 // overlapped fashion and waits for IO completion. The function also waits
98 // on an event that can be used to cancel the operation. If the operation
99 // is cancelled, the function returns and closes the relevant socket object.
100 template <typename BufferType, typename Function>
101 size_t CancelableFileOperation(Function operation, HANDLE file,
102 BufferType* buffer, size_t length,
103 base::WaitableEvent* io_event,
104 base::WaitableEvent* cancel_event,
105 CancelableSyncSocket* socket) {
106 // The buffer must be byte size or the length check won't make much sense.
107 COMPILE_ASSERT(sizeof(buffer[0]) == sizeof(char), incorrect_buffer_type);
108 DCHECK_LE(length, kMaxMessageLength);
109
110 OVERLAPPED ol = {0};
111 ol.hEvent = io_event->handle();
112 size_t count = 0;
113 while (count < length) {
114 DWORD len;
115 // The following statement is for 64 bit portability.
116 DWORD chunk = static_cast<DWORD>(
117 ((length - count) <= UINT_MAX) ? (length - count) : UINT_MAX);
118 // This is either the ReadFile or WriteFile call depending on whether
119 // we're receiving or sending data.
120 BOOL ok = operation(file, static_cast<BufferType*>(buffer) + count, chunk,
121 &len, &ol);
122 if (!ok) {
123 if (::GetLastError() == ERROR_IO_PENDING) {
124 base::WaitableEvent* events[] = { io_event, cancel_event };
125 size_t signaled = WaitableEvent::WaitMany(events, arraysize(events));
126 if (signaled == 1) {
127 VLOG(1) << "Shutdown was signaled. Closing socket.";
128 socket->Close();
129 break;
130 } else {
131 GetOverlappedResult(file, &ol, &len, TRUE);
132 }
133 } else {
134 return (0 < count) ? count : 0;
135 }
136 }
137 count += len;
138 }
139 return count;
140 }
141
142 } // namespace
143
144 SyncSocket::SyncSocket() : handle_(kInvalidHandle) {}
145
146 SyncSocket::~SyncSocket() {
147 Close();
148 }
149
150 // static
151 bool SyncSocket::CreatePair(SyncSocket* socket_a, SyncSocket* socket_b) {
152 return CreatePairImpl(&socket_a->handle_, &socket_b->handle_, false);
153 }
154
101 bool SyncSocket::Close() { 155 bool SyncSocket::Close() {
102 if (handle_ == kInvalidHandle) { 156 if (handle_ == kInvalidHandle)
103 return false; 157 return false;
104 } 158
105 BOOL retval = CloseHandle(handle_); 159 BOOL retval = CloseHandle(handle_);
106 handle_ = kInvalidHandle; 160 handle_ = kInvalidHandle;
107 return retval ? true : false; 161 return retval ? true : false;
108 } 162 }
109 163
110 size_t SyncSocket::Send(const void* buffer, size_t length) { 164 size_t SyncSocket::Send(const void* buffer, size_t length) {
111 DCHECK_LE(length, kMaxMessageLength); 165 DCHECK_LE(length, kMaxMessageLength);
112 size_t count = 0; 166 size_t count = 0;
113 while (count < length) { 167 while (count < length) {
114 DWORD len; 168 DWORD len;
115 // The following statement is for 64 bit portability. 169 // The following statement is for 64 bit portability.
116 DWORD chunk = static_cast<DWORD>( 170 DWORD chunk = static_cast<DWORD>(
117 ((length - count) <= UINT_MAX) ? (length - count) : UINT_MAX); 171 ((length - count) <= UINT_MAX) ? (length - count) : UINT_MAX);
118 if (WriteFile(handle_, static_cast<const char*>(buffer) + count, 172 if (WriteFile(handle_, static_cast<const char*>(buffer) + count,
119 chunk, &len, NULL) == FALSE) { 173 chunk, &len, NULL) == FALSE) {
120 return (0 < count) ? count : 0; 174 return (0 < count) ? count : 0;
121 } 175 }
122 count += len; 176 count += len;
123 } 177 }
124 return count; 178 return count;
125 } 179 }
126 180
127 size_t SyncSocket::Receive(void* buffer, size_t length) { 181 size_t SyncSocket::Receive(void* buffer, size_t length) {
128 DCHECK_LE(length, kMaxMessageLength); 182 DCHECK_LE(length, kMaxMessageLength);
129 size_t count = 0; 183 size_t count = 0;
130 while (count < length) { 184 while (count < length) {
131 DWORD len; 185 DWORD len;
132 DWORD chunk = static_cast<DWORD>( 186 DWORD chunk = static_cast<DWORD>(
133 ((length - count) <= UINT_MAX) ? (length - count) : UINT_MAX); 187 ((length - count) <= UINT_MAX) ? (length - count) : UINT_MAX);
134 if (ReadFile(handle_, static_cast<char*>(buffer) + count, 188 if (ReadFile(handle_, static_cast<char*>(buffer) + count,
135 chunk, &len, NULL) == FALSE) { 189 chunk, &len, NULL) == FALSE) {
136 return (0 < count) ? count : 0; 190 return (0 < count) ? count : 0;
137 } 191 }
138 count += len; 192 count += len;
139 } 193 }
140 return count; 194 return count;
141 } 195 }
142 196
143 size_t SyncSocket::Peek() { 197 size_t SyncSocket::Peek() {
144 DWORD available = 0; 198 DWORD available = 0;
145 PeekNamedPipe(handle_, NULL, 0, NULL, &available, NULL); 199 PeekNamedPipe(handle_, NULL, 0, NULL, &available, NULL);
146 return available; 200 return available;
147 } 201 }
148 202
203 CancelableSyncSocket::CancelableSyncSocket()
204 : shutdown_event_(true, false), file_operation_(true, false) {
205 }
206
207 CancelableSyncSocket::CancelableSyncSocket(Handle handle)
208 : SyncSocket(handle), shutdown_event_(true, false),
209 file_operation_(true, false) {
210 }
211
212 bool CancelableSyncSocket::Shutdown() {
213 // This doesn't shut down the pipe immediately, but subsequent Receive or Send
214 // methods will fail straight away.
215 shutdown_event_.Signal();
216 return true;
217 }
218
219 bool CancelableSyncSocket::Close() {
220 bool ret = SyncSocket::Close();
221 shutdown_event_.Reset();
222 return ret;
223 }
224
225 size_t CancelableSyncSocket::Send(const void* buffer, size_t length) {
226 return CancelableFileOperation(&WriteFile, handle_,
227 reinterpret_cast<const char*>(buffer), length, &file_operation_,
228 &shutdown_event_, this);
229 }
230
231 size_t CancelableSyncSocket::Receive(void* buffer, size_t length) {
232 return CancelableFileOperation(&ReadFile, handle_,
233 reinterpret_cast<char*>(buffer), length, &file_operation_,
234 &shutdown_event_, this);
235 }
236
237 // static
238 bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a,
239 CancelableSyncSocket* socket_b) {
240 return CreatePairImpl(&socket_a->handle_, &socket_b->handle_, true);
241 }
242
243
149 } // namespace base 244 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698