1 // Copyright 2010-2018, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 // skip all unless OS_WIN
31 #ifdef OS_WIN
32
33 #include "ipc/ipc.h"
34
35 #include <Windows.h>
36 #include <Sddl.h>
37
38 #include <algorithm>
39 #include <string>
40
41 #include "base/const.h"
42 #include "base/cpu_stats.h"
43 #include "base/logging.h"
44 #include "base/scoped_handle.h"
45 #include "base/singleton.h"
46 #include "base/system_util.h"
47 #include "base/thread.h"
48 #include "base/util.h"
49 #include "base/win_sandbox.h"
50 #include "base/win_util.h"
51 #include "ipc/ipc_path_manager.h"
52
53 namespace mozc {
54 namespace {
55
56 const bool kReadTypeACK = true;
57 const bool kReadTypeData = false;
58 const bool kSendTypeData = false;
59 const int kMaxSuccessiveConnectionFailureCount = 5;
60
GetNumberOfProcessors()61 size_t GetNumberOfProcessors() {
62 // thread-safety is not required.
63 static size_t num = CPUStats().GetNumberOfProcessors();
64 return std::max(num, static_cast<size_t>(1));
65 }
66
67 // Least significant bit of OVERLAPPED::hEvent can be used for special
68 // purpose against GetQueuedCompletionStatus API.
69 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa364986.aspx
70 // This function provides a safe way to retrieve the actual event handle
71 // even in this situation.
GetEventHandleFromOverlapped(const OVERLAPPED * overlapped)72 HANDLE GetEventHandleFromOverlapped(const OVERLAPPED *overlapped) {
73 return reinterpret_cast<HANDLE>(
74 reinterpret_cast<DWORD_PTR>(overlapped->hEvent) & ~1);
75 }
76
77 // Returns true if the given |overlapped| is initialized in successful.
InitOverlapped(OVERLAPPED * overlapped,HANDLE wait_handle)78 bool InitOverlapped(OVERLAPPED *overlapped, HANDLE wait_handle) {
79 if (wait_handle == 0 || wait_handle == INVALID_HANDLE_VALUE) {
80 LOG(ERROR) << "wait_handle is invalid.";
81 return false;
82 }
83 ::ZeroMemory(overlapped, sizeof(OVERLAPPED));
84 if (::ResetEvent(wait_handle) == FALSE) {
85 const DWORD last_error = ::GetLastError();
86 LOG(ERROR) << "::ResetEvent failed. error: " << last_error;
87 return false;
88 }
89 overlapped->hEvent = wait_handle;
90 return true;
91 }
92
93 class IPCClientMutexBase {
94 public:
IPCClientMutexBase(const string & ipc_channel_name)95 explicit IPCClientMutexBase(const string &ipc_channel_name) {
96 // Make a kernel mutex object so that multiple ipc connections are
97 // serialized here. In Windows, there is no useful way to serialize
98 // the multiple connections to the single-thread named pipe server.
99 // WaitForNamedPipe doesn't work for this propose as it just lets
100 // clients know that the connection becomes "available" right now.
101 // It doesn't mean that connection is available for the current
102 // thread. The "available" notification is sent to all waiting ipc
103 // clients at the same time and only one client gets the connection.
104 // This causes redundant and wasteful CreateFile calles.
105 string mutex_name = kMutexPathPrefix;
106 mutex_name += SystemUtil::GetUserSidAsString();
107 mutex_name += ".";
108 mutex_name += ipc_channel_name;
109 mutex_name += ".ipc";
110 std::wstring wmutex_name;
111 Util::UTF8ToWide(mutex_name, &wmutex_name);
112
113 LPSECURITY_ATTRIBUTES security_attributes_ptr = nullptr;
114 SECURITY_ATTRIBUTES security_attributes;
115 if (!WinSandbox::MakeSecurityAttributes(WinSandbox::kSharableMutex,
116 &security_attributes)) {
117 LOG(ERROR) << "Cannot make SecurityAttributes";
118 } else {
119 security_attributes_ptr = &security_attributes;
120 }
121
122 // http://msdn.microsoft.com/en-us/library/ms682411(VS.85).aspx:
123 // Two or more processes can call CreateMutex to create the same named
124 // mutex. The first process actually creates the mutex, and subsequent
125 // processes with sufficient access rights simply open a handle to
126 // the existing mutex. This enables multiple processes to get handles
127 // of the same mutex, while relieving the user of the responsibility
128 // of ensuring that the creating process is started first.
129 // When using this technique, you should set the
130 // bInitialOwner flag to FALSE; otherwise, it can be difficult to be
131 // certain which process has initial ownership.
132 ipc_mutex_.reset(::CreateMutex(security_attributes_ptr,
133 FALSE, wmutex_name.c_str()));
134 if (security_attributes_ptr != nullptr) {
135 ::LocalFree(security_attributes_ptr->lpSecurityDescriptor);
136 }
137
138 const DWORD create_mutex_error = ::GetLastError();
139 if (ipc_mutex_.get() == nullptr) {
140 LOG(ERROR) << "CreateMutex failed: " << create_mutex_error;
141 return;
142 }
143 }
144
~IPCClientMutexBase()145 virtual ~IPCClientMutexBase() {}
146
get() const147 HANDLE get() const {
148 return ipc_mutex_.get();
149 }
150
151 private:
152 ScopedHandle ipc_mutex_;
153 };
154
155 class ConverterClientMutex : public IPCClientMutexBase {
156 public:
ConverterClientMutex()157 ConverterClientMutex()
158 : IPCClientMutexBase("converter") {}
159
160 private:
161 DISALLOW_COPY_AND_ASSIGN(ConverterClientMutex);
162 };
163
164 class RendererClientMutex : public IPCClientMutexBase {
165 public:
RendererClientMutex()166 RendererClientMutex()
167 : IPCClientMutexBase("renderer") {}
168
169 private:
170 DISALLOW_COPY_AND_ASSIGN(RendererClientMutex);
171 };
172
173 class FallbackClientMutex : public IPCClientMutexBase {
174 public:
FallbackClientMutex()175 FallbackClientMutex()
176 : IPCClientMutexBase("fallback") {}
177
178 private:
179 DISALLOW_COPY_AND_ASSIGN(FallbackClientMutex);
180 };
181
182 // In Mozc client, we should support different IPC channels (client-converter
183 // and client-renderer) so we need to have different global mutexes to
184 // serialize each client. Currently |ipc_name| starts with "session" and
185 // "renderer" are expected.
GetClientMutex(const string & ipc_name)186 HANDLE GetClientMutex(const string &ipc_name) {
187 if (Util::StartsWith(ipc_name, "session")) {
188 return Singleton<ConverterClientMutex>::get()->get();
189 }
190 if (Util::StartsWith(ipc_name, "renderer")) {
191 return Singleton<RendererClientMutex>::get()->get();
192 }
193 LOG(WARNING) << "unexpected IPC name: " << ipc_name;
194 return Singleton<FallbackClientMutex>::get()->get();
195 }
196
197 // RAII class for calling ReleaseMutex in destructor.
198 class ScopedReleaseMutex {
199 public:
ScopedReleaseMutex(HANDLE handle)200 explicit ScopedReleaseMutex(HANDLE handle)
201 : pipe_handle_(handle) {}
202
~ScopedReleaseMutex()203 virtual ~ScopedReleaseMutex() {
204 if (nullptr != pipe_handle_) {
205 ::ReleaseMutex(pipe_handle_);
206 }
207 pipe_handle_ = nullptr;
208 }
209
get() const210 HANDLE get() const {
211 return pipe_handle_;
212 }
213
214 private:
215 HANDLE pipe_handle_;
216
217 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedReleaseMutex);
218 };
219
GetServerProcessIdImpl(HANDLE handle)220 uint32 GetServerProcessIdImpl(HANDLE handle) {
221 ULONG pid = 0;
222 if (::GetNamedPipeServerProcessId(handle, &pid) == 0) {
223 const DWORD get_named_pipe_server_process_id_error = ::GetLastError();
224 LOG(ERROR) << "GetNamedPipeServerProcessId failed: "
225 << get_named_pipe_server_process_id_error;
226 return static_cast<uint32>(-1); // always deny the connection
227 }
228
229 VLOG(1) << "Got server ProcessID: " << pid;
230
231 return static_cast<uint32>(pid);
232 }
233
SafeCancelIO(HANDLE device_handle,OVERLAPPED * overlapped)234 void SafeCancelIO(HANDLE device_handle, OVERLAPPED *overlapped) {
235 if (::CancelIo(device_handle) == FALSE) {
236 const DWORD cancel_error = ::GetLastError();
237 LOG(ERROR) << "Failed to CancelIo: " << cancel_error;
238 }
239
240 // Wait for the completion of the on-going request forever. This is not
241 // _safe_ and should be fixed anyway.
242 // TODO(yukawa): Avoid INFINITE if possible.
243 ::WaitForSingleObject(GetEventHandleFromOverlapped(overlapped), INFINITE);
244 }
245
WaitForQuitOrIOImpl(HANDLE device_handle,HANDLE quit_event,DWORD timeout,OVERLAPPED * overlapped,IPCErrorType * last_ipc_error)246 bool WaitForQuitOrIOImpl(
247 HANDLE device_handle, HANDLE quit_event, DWORD timeout,
248 OVERLAPPED *overlapped, IPCErrorType *last_ipc_error) {
249 const HANDLE events[] = {
250 quit_event, GetEventHandleFromOverlapped(overlapped)
251 };
252 const DWORD wait_result = ::WaitForMultipleObjects(
253 ARRAYSIZE(events), events, FALSE, timeout);
254 const DWORD wait_error = ::GetLastError();
255 // Clear the I/O operation if still exists.
256 if (!HasOverlappedIoCompleted(overlapped)) {
257 // This is not safe because this operation may be blocked forever.
258 // TODO(yukawa): Implement safer cancelation mechanism.
259 SafeCancelIO(device_handle, overlapped);
260 }
261 if (wait_result == WAIT_TIMEOUT) {
262 LOG(WARNING) << "Timeout: " << timeout;
263 *last_ipc_error = IPC_TIMEOUT_ERROR;
264 return false;
265 }
266 if (wait_result == WAIT_OBJECT_0) {
267 // Should be quit immediately
268 *last_ipc_error = IPC_QUIT_EVENT_SIGNALED;
269 return false;
270 }
271 if (wait_result != (WAIT_OBJECT_0 + 1)) {
272 LOG(WARNING) << "Unknown result: " << wait_result
273 << ", Error: " << wait_error;
274 *last_ipc_error = IPC_UNKNOWN_ERROR;
275 return false;
276 }
277 return true;
278 }
279
WaitForIOImpl(HANDLE device_handle,DWORD timeout,OVERLAPPED * overlapped,IPCErrorType * last_ipc_error)280 bool WaitForIOImpl(HANDLE device_handle, DWORD timeout,
281 OVERLAPPED *overlapped, IPCErrorType *last_ipc_error) {
282 const DWORD wait_result = ::WaitForSingleObject(
283 GetEventHandleFromOverlapped(overlapped), timeout);
284 // Clear the I/O operation if still exists.
285 if (!HasOverlappedIoCompleted(overlapped)) {
286 // This is not safe because this operation may be blocked forever.
287 // TODO(yukawa): Implement safer cancelation mechanism.
288 SafeCancelIO(device_handle, overlapped);
289 }
290 if (wait_result == WAIT_TIMEOUT) {
291 LOG(WARNING) << "Timeout: " << timeout;
292 *last_ipc_error = IPC_TIMEOUT_ERROR;
293 return false;
294 }
295 if (wait_result != WAIT_OBJECT_0) {
296 LOG(WARNING) << "Unknown result: " << wait_result;
297 *last_ipc_error = IPC_UNKNOWN_ERROR;
298 return false;
299 }
300 return true;
301 }
302
WaitForQuitOrIO(HANDLE device_handle,HANDLE quit_event,DWORD timeout,OVERLAPPED * overlapped,IPCErrorType * last_ipc_error)303 bool WaitForQuitOrIO(
304 HANDLE device_handle, HANDLE quit_event, DWORD timeout,
305 OVERLAPPED *overlapped, IPCErrorType *last_ipc_error) {
306 if (quit_event != nullptr) {
307 return WaitForQuitOrIOImpl(device_handle, quit_event, timeout,
308 overlapped, last_ipc_error);
309 }
310 return WaitForIOImpl(device_handle, timeout, overlapped, last_ipc_error);
311 }
312
313 // To work around a bug of GetOverlappedResult in Vista
314 // http://msdn.microsoft.com/en-us/library/dd371711.aspx
SafeWaitOverlappedResult(HANDLE device_handle,HANDLE quit_event,DWORD timeout,OVERLAPPED * overlapped,DWORD * num_bytes_updated,IPCErrorType * last_ipc_error,bool wait_ack)315 bool SafeWaitOverlappedResult(
316 HANDLE device_handle, HANDLE quit_event, DWORD timeout,
317 OVERLAPPED *overlapped, DWORD *num_bytes_updated,
318 IPCErrorType *last_ipc_error, bool wait_ack) {
319 DCHECK(overlapped);
320 DCHECK(num_bytes_updated);
321 DCHECK(last_ipc_error);
322 if (!WaitForQuitOrIO(device_handle, quit_event, timeout,
323 overlapped, last_ipc_error)) {
324 return false;
325 }
326
327 *num_bytes_updated = 0;
328 const BOOL get_overlapped_result = ::GetOverlappedResult(
329 device_handle, overlapped, num_bytes_updated, FALSE);
330 if (get_overlapped_result == FALSE) {
331 const DWORD get_overlapped_error = ::GetLastError();
332 if (get_overlapped_error == ERROR_BROKEN_PIPE) {
333 if (wait_ack) {
334 // This is an expected behavior.
335 return true;
336 }
337 LOG(ERROR) << "GetOverlappedResult() failed: ERROR_BROKEN_PIPE";
338 } else {
339 LOG(ERROR) << "GetOverlappedResult() failed: " << get_overlapped_error;
340 }
341 *last_ipc_error = IPC_UNKNOWN_ERROR;
342 return false;
343 }
344 return true;
345 }
346
SendIPCMessage(HANDLE device_handle,HANDLE write_wait_handle,const char * buf,size_t buf_length,int timeout,IPCErrorType * last_ipc_error)347 bool SendIPCMessage(HANDLE device_handle, HANDLE write_wait_handle,
348 const char *buf, size_t buf_length, int timeout,
349 IPCErrorType *last_ipc_error) {
350 if (buf_length == 0) {
351 LOG(WARNING) << "buf length is 0";
352 *last_ipc_error = IPC_UNKNOWN_ERROR;
353 return false;
354 }
355
356 DWORD num_bytes_written = 0;
357 OVERLAPPED overlapped;
358 if (!InitOverlapped(&overlapped, write_wait_handle)) {
359 *last_ipc_error = IPC_WRITE_ERROR;
360 return false;
361 }
362
363 const bool write_file_result = (::WriteFile(
364 device_handle, buf, static_cast<DWORD>(buf_length),
365 &num_bytes_written, &overlapped) != FALSE);
366 const DWORD write_file_error = ::GetLastError();
367 if (write_file_result) {
368 // ::WriteFile is done as sync operation.
369 } else {
370 if (write_file_error != ERROR_IO_PENDING) {
371 LOG(ERROR) << "WriteFile() failed: " << write_file_error;
372 *last_ipc_error = IPC_WRITE_ERROR;
373 return false;
374 }
375 if (!SafeWaitOverlappedResult(
376 device_handle, nullptr, timeout, &overlapped,
377 &num_bytes_written, last_ipc_error, kSendTypeData)) {
378 return false;
379 }
380 }
381
382 // As we use message-type namedpipe, all the data should be written in one
383 // shot. Otherwise, single message will be split into multiple packets.
384 if (num_bytes_written != buf_length) {
385 LOG(ERROR) << "Data truncated. buf_length: " << buf_length
386 << ", num_bytes_written: " << num_bytes_written;
387 *last_ipc_error = IPC_UNKNOWN_ERROR;
388 return false;
389 }
390 return true;
391 }
392
RecvIPCMessage(HANDLE device_handle,HANDLE read_wait_handle,char * buf,size_t * buf_length,int timeout,bool read_type_ack,IPCErrorType * last_ipc_error)393 bool RecvIPCMessage(HANDLE device_handle, HANDLE read_wait_handle, char *buf,
394 size_t *buf_length, int timeout, bool read_type_ack,
395 IPCErrorType *last_ipc_error) {
396 if (*buf_length == 0) {
397 LOG(WARNING) << "buf length is 0";
398 *last_ipc_error = IPC_UNKNOWN_ERROR;
399 return false;
400 }
401
402 OVERLAPPED overlapped;
403 if (!InitOverlapped(&overlapped, read_wait_handle)) {
404 *last_ipc_error = IPC_READ_ERROR;
405 return false;
406 }
407
408 DWORD num_bytes_read = 0;
409 const bool read_file_result = (::ReadFile(
410 device_handle, buf, static_cast<DWORD>(*buf_length), &num_bytes_read,
411 &overlapped) != FALSE);
412 const DWORD read_file_error = ::GetLastError();
413 if (read_file_result) {
414 // ::ReadFile is done as sync operation.
415 } else {
416 if (read_type_ack && (read_file_error == ERROR_BROKEN_PIPE)) {
417 // The client has already disconnected this pipe. This is an expected
418 // behavior and do not treat as an error.
419 return true;
420 }
421 if (read_file_error != ERROR_IO_PENDING) {
422 LOG(ERROR) << "ReadFile() failed: " << read_file_error;
423 *last_ipc_error = IPC_READ_ERROR;
424 return false;
425 }
426 // Actually this is an async operation. Let's wait for its completion.
427 if (!SafeWaitOverlappedResult(
428 device_handle, nullptr, timeout, &overlapped,
429 &num_bytes_read, last_ipc_error, read_type_ack)) {
430 return false;
431 }
432 }
433
434 if (!read_type_ack && (num_bytes_read == 0)) {
435 LOG(WARNING) << "Received 0 result.";
436 }
437
438 *buf_length = num_bytes_read;
439
440 return true;
441 }
442
CreateManualResetEvent()443 HANDLE CreateManualResetEvent() {
444 return ::CreateEvent(nullptr, TRUE, FALSE, nullptr);
445 }
446
447 // We do not care about the signaled state of the device handle itself.
448 // This slightly improves the performance.
449 // See http://msdn.microsoft.com/en-us/library/windows/desktop/aa365538.aspx
MaybeDisableFileCompletionNotification(HANDLE device_handle)450 void MaybeDisableFileCompletionNotification(HANDLE device_handle) {
451 // This is not a mandatory task. Just ignore the actual error (if any).
452 ::SetFileCompletionNotificationModes(device_handle,
453 FILE_SKIP_SET_EVENT_ON_HANDLE);
454 }
455
456 } // namespace
457
IPCServer(const string & name,int32 num_connections,int32 timeout)458 IPCServer::IPCServer(const string &name,
459 int32 num_connections,
460 int32 timeout)
461 : connected_(false),
462 pipe_event_(CreateManualResetEvent()),
463 quit_event_(CreateManualResetEvent()),
464 timeout_(timeout) {
465 IPCPathManager *manager = IPCPathManager::GetIPCPathManager(name);
466 string server_address;
467
468 if (!manager->CreateNewPathName() && !manager->LoadPathName()) {
469 LOG(ERROR) << "Cannot prepare IPC path name";
470 return;
471 }
472
473 if (!manager->GetPathName(&server_address)) {
474 LOG(ERROR) << "Cannot make IPC path name";
475 return;
476 }
477 DCHECK(!server_address.empty());
478
479 SECURITY_ATTRIBUTES security_attributes;
480 if (!WinSandbox::MakeSecurityAttributes(WinSandbox::kSharablePipe,
481 &security_attributes)) {
482 LOG(ERROR) << "Cannot make SecurityAttributes";
483 return;
484 }
485
486 // Create a named pipe.
487 std::wstring wserver_address;
488 Util::UTF8ToWide(server_address, &wserver_address);
489 HANDLE handle = ::CreateNamedPipe(wserver_address.c_str(),
490 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
491 FILE_FLAG_FIRST_PIPE_INSTANCE,
492 PIPE_TYPE_MESSAGE |
493 PIPE_READMODE_MESSAGE |
494 PIPE_WAIT,
495 (num_connections <= 0
496 ? PIPE_UNLIMITED_INSTANCES
497 : num_connections),
498 sizeof(request_),
499 sizeof(response_),
500 0,
501 &security_attributes);
502 const DWORD create_named_pipe_error = ::GetLastError();
503 ::LocalFree(security_attributes.lpSecurityDescriptor);
504
505 if (INVALID_HANDLE_VALUE == handle) {
506 LOG(FATAL) << "CreateNamedPipe failed" << create_named_pipe_error;
507 return;
508 }
509
510 pipe_handle_.reset(handle);
511
512 MaybeDisableFileCompletionNotification(pipe_handle_.get());
513
514 if (!manager->SavePathName()) {
515 LOG(ERROR) << "Cannot save IPC path name";
516 return;
517 }
518
519 connected_ = true;
520 }
521
~IPCServer()522 IPCServer::~IPCServer() {
523 Terminate();
524 }
525
Connected() const526 bool IPCServer::Connected() const {
527 return connected_;
528 }
529
Terminate()530 void IPCServer::Terminate() {
531 if (server_thread_.get() == nullptr) {
532 return;
533 }
534
535 if (!server_thread_->IsRunning()) {
536 return;
537 }
538
539 if (!::SetEvent(quit_event_.get())) {
540 LOG(ERROR) << "SetEvent failed";
541 }
542
543 // Close the named pipe.
544 // This is a workaround for killing child thread
545 if (server_thread_.get() != nullptr) {
546 server_thread_->Join();
547 server_thread_->Terminate();
548 }
549
550 connected_ = false;
551 }
552
Loop()553 void IPCServer::Loop() {
554 IPCErrorType last_ipc_error = IPC_NO_ERROR;
555
556 int successive_connection_failure_count = 0;
557 while (connected_) {
558 OVERLAPPED overlapped;
559 if (!InitOverlapped(&overlapped, pipe_event_.get())) {
560 connected_ = false;
561 return;
562 }
563
564 const BOOL result = ::ConnectNamedPipe(pipe_handle_.get(), &overlapped);
565 const DWORD connect_named_pipe_error = ::GetLastError();
566 if (result == FALSE) {
567 if (connect_named_pipe_error == ERROR_PIPE_CONNECTED) {
568 // Already connected. Nothing to do.
569 } else if (connect_named_pipe_error == ERROR_NO_DATA) {
570 // client already closes the connection
571 ::DisconnectNamedPipe(pipe_handle_.get());
572 continue;
573 } else if (connect_named_pipe_error == ERROR_IO_PENDING) {
574 // Actually this is async operation.
575 DWORD ignored = 0;
576 IPCErrorType ipc_error = IPC_NO_ERROR;
577 if (!SafeWaitOverlappedResult(pipe_handle_.get(), quit_event_.get(),
578 INFINITE, &overlapped, &ignored,
579 &ipc_error, kReadTypeData)) {
580 if (ipc_error == IPC_QUIT_EVENT_SIGNALED) {
581 VLOG(1) << "Recived Conrol event from other thread";
582 connected_ = false;
583 return;
584 }
585 ++successive_connection_failure_count;
586 if (successive_connection_failure_count >=
587 kMaxSuccessiveConnectionFailureCount) {
588 LOG(ERROR) << "Give up to connect named pipe.";
589 connected_ = false;
590 return;
591 }
592 ::DisconnectNamedPipe(pipe_handle_.get());
593 continue;
594 }
595 } else {
596 LOG(FATAL) << "Unexpected error: " << connect_named_pipe_error;
597 }
598 }
599
600 successive_connection_failure_count = 0;
601 // Retrieve an incoming message.
602 size_t request_size = sizeof(request_);
603 if (RecvIPCMessage(pipe_handle_.get(), pipe_event_.get(),
604 &request_[0], &request_size, timeout_,
605 kReadTypeData, &last_ipc_error)) {
606 size_t response_size = sizeof(response_);
607 if (!Process(&request_[0], request_size,
608 &response_[0], &response_size)) {
609 connected_ = false;
610 }
611
612 // When Process() returns 0 result, force to call DisconnectNamedPipe()
613 // instead of checking ACK message
614 if (response_size == 0) {
615 LOG(WARNING) << "Process() return 0 result";
616 ::DisconnectNamedPipe(pipe_handle_.get());
617 continue;
618 }
619
620 // Send a response
621 SendIPCMessage(pipe_handle_.get(), pipe_event_.get(),
622 &response_[0], response_size, timeout_, &last_ipc_error);
623 }
624
625 // Special treatment for Windows per discussion with thatanaka:
626 // It's hard to know that client has processed the server's response.
627 // We will be able to call ::FlushFileHandles() here, but
628 // FlushFileHandles() is blocked if client doesn't call ReadFile(). That
629 // means that a malicious user can easily block the server not by calling
630 // ReadFile. In order to know the transaction completes successfully,
631 // client needs to send an ACK message to the server.
632
633 // Wait ACK-like signal from client for 0.1 second. If we detect the pipe
634 // disconnect event, so far so good. If we receive more data, we assume it
635 // is an ACK signal (the IPC client of Mozc 1.5.x or earlier does this).
636 char ack_request[1] = {0};
637 size_t ack_request_size = 1;
638 static const int kAckTimeout = 100;
639 if (!RecvIPCMessage(pipe_handle_.get(), pipe_event_.get(),
640 ack_request, &ack_request_size, kAckTimeout,
641 kReadTypeACK, &last_ipc_error)) {
642 // This case happens when the client did not recive the server's response
643 // within timeout. Anyway we will close the connection so that the server
644 // will not be blocked.
645 LOG(WARNING) << "Client didn't respond within "
646 << kAckTimeout << " msec.";
647 }
648 ::DisconnectNamedPipe(pipe_handle_.get());
649 }
650
651 connected_ = false;
652 }
653
654 // old interface
IPCClient(const string & name)655 IPCClient::IPCClient(const string &name)
656 : pipe_event_(CreateManualResetEvent()),
657 connected_(false),
658 ipc_path_manager_(nullptr),
659 last_ipc_error_(IPC_NO_ERROR) {
660 Init(name, "");
661 }
662
IPCClient(const string & name,const string & server_path)663 IPCClient::IPCClient(const string &name, const string &server_path)
664 : pipe_event_(CreateManualResetEvent()),
665 connected_(false),
666 ipc_path_manager_(nullptr),
667 last_ipc_error_(IPC_NO_ERROR) {
668 Init(name, server_path);
669 }
670
Init(const string & name,const string & server_path)671 void IPCClient::Init(const string &name, const string &server_path) {
672 last_ipc_error_ = IPC_NO_CONNECTION;
673
674 // We should change the mutex based on which IPC server we will talk with.
675 ScopedReleaseMutex ipc_mutex(GetClientMutex(name));
676
677 if (ipc_mutex.get() == nullptr) {
678 LOG(ERROR) << "IPC mutex is not available";
679 } else {
680 const int kMutexTimeout = 10 * 1000; // wait at most 10sec.
681 switch (::WaitForSingleObject(ipc_mutex.get(), kMutexTimeout)) {
682 case WAIT_TIMEOUT:
683 // TODO(taku): with suspend/resume, WaitForSingleObject may
684 // return WAIT_TIMEOUT. We have to consider the case
685 // in the future.
686 LOG(ERROR) << "IPC client was not available even after "
687 << kMutexTimeout << " msec.";
688 break;
689 case WAIT_ABANDONED:
690 DLOG(INFO) << "mutex object was removed";
691 break;
692 case WAIT_OBJECT_0:
693 break;
694 default:
695 break;
696 }
697 }
698
699 IPCPathManager *manager = IPCPathManager::GetIPCPathManager(name);
700 if (manager == nullptr) {
701 LOG(ERROR) << "IPCPathManager::GetIPCPathManager failed";
702 return;
703 }
704
705 ipc_path_manager_ = manager;
706
707 // TODO(taku): enable them on Mac/Linux
708 #ifdef DEBUG
709 const size_t kMaxTrial = 256;
710 #else
711 const size_t kMaxTrial = 2;
712 #endif
713
714 for (size_t trial = 0; trial < kMaxTrial; ++trial) {
715 string server_address;
716 if (!manager->LoadPathName() || !manager->GetPathName(&server_address)) {
717 continue;
718 }
719 std::wstring wserver_address;
720 Util::UTF8ToWide(server_address, &wserver_address);
721
722 if (GetNumberOfProcessors() == 1) {
723 // When the code is running in single processor environment, sometimes
724 // IPC server has not finished the clean-up tasks for the previous IPC
725 // session here. So we intentionally call WaitNamedPipe API so that IPC
726 // server has a chance to complete clean-up tasks if necessary.
727 // NOTE: We cannot set 0 for the wait time because 0 has a special meaning
728 // as |NMPWAIT_USE_DEFAULT_WAIT|.
729 const DWORD kMinWaitTimeForWaitNamedPipe = 1;
730 ::WaitNamedPipe(wserver_address.c_str(), kMinWaitTimeForWaitNamedPipe);
731 }
732
733 ScopedHandle new_handle(::CreateFile(wserver_address.c_str(),
734 GENERIC_READ | GENERIC_WRITE,
735 0, nullptr, OPEN_EXISTING,
736 FILE_FLAG_OVERLAPPED |
737 SECURITY_SQOS_PRESENT |
738 SECURITY_IDENTIFICATION |
739 SECURITY_EFFECTIVE_ONLY,
740 nullptr));
741 const DWORD create_file_error = ::GetLastError();
742 // ScopedHandle returns nullptr even when it received INVALID_HANDLE_VALUE.
743 if (new_handle.get() != nullptr) {
744 pipe_handle_.reset(new_handle.take());
745 MaybeDisableFileCompletionNotification(pipe_handle_.get());
746 if (!manager->IsValidServer(GetServerProcessIdImpl(pipe_handle_.get()),
747 server_path)) {
748 LOG(ERROR) << "Connecting to invalid server";
749 last_ipc_error_ = IPC_INVALID_SERVER;
750 return;
751 }
752
753 last_ipc_error_ = IPC_NO_ERROR;
754 connected_ = true;
755 return;
756 }
757
758 if (ERROR_PIPE_BUSY != create_file_error) {
759 LOG(ERROR) << "Server is not running: " << create_file_error;
760 manager->Clear();
761 continue;
762 }
763
764 // wait for 10 second until server is ready
765 // TODO(taku): control the timeout via flag.
766 #ifdef DEBUG
767 const int kNamedPipeTimeout = 100000; // 100 sec
768 #else
769 const int kNamedPipeTimeout = 10000; // 10 sec
770 #endif
771 DLOG(ERROR) << "Server is busy. waiting for "
772 << kNamedPipeTimeout << " msec";
773 if (!::WaitNamedPipe(wserver_address.c_str(),
774 kNamedPipeTimeout)) {
775 const DWORD wait_named_pipe_error = ::GetLastError();
776 LOG(ERROR) << "WaitNamedPipe failed: " << wait_named_pipe_error;
777 if ((trial + 1) == kMaxTrial) {
778 last_ipc_error_ = IPC_TIMEOUT_ERROR;
779 return;
780 }
781 continue; // go 2nd trial
782 }
783 }
784 }
785
~IPCClient()786 IPCClient::~IPCClient() {}
787
Connected() const788 bool IPCClient::Connected() const {
789 return connected_;
790 }
791
Call(const char * request,size_t request_size,char * response,size_t * response_size,int32 timeout)792 bool IPCClient::Call(const char *request, size_t request_size,
793 char *response, size_t *response_size,
794 int32 timeout) {
795 last_ipc_error_ = IPC_NO_ERROR;
796 if (!connected_) {
797 LOG(ERROR) << "IPCClient is not connected";
798 last_ipc_error_ = IPC_NO_CONNECTION;
799 return false;
800 }
801
802 if (!SendIPCMessage(pipe_handle_.get(), pipe_event_.get(), request,
803 request_size, timeout, &last_ipc_error_)) {
804 LOG(ERROR) << "SendIPCMessage() failed";
805 return false;
806 }
807
808 if (!RecvIPCMessage(pipe_handle_.get(), pipe_event_.get(), response,
809 response_size, timeout, kReadTypeData,
810 &last_ipc_error_)) {
811 LOG(ERROR) << "RecvIPCMessage() failed";
812 return false;
813 }
814
815 // Instead of sending ACK message to Server, we simply disconnect the named
816 // pile to notify that client can read the message successfully.
817 connected_ = false;
818 pipe_handle_.reset(INVALID_HANDLE_VALUE);
819
820 return true;
821 }
822
823 } // namespace mozc
824
825 #endif // OS_WIN
826