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