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 #ifndef MOZC_IPC_IPC_H_
31 #define MOZC_IPC_IPC_H_
32 
33 #ifdef OS_MACOSX
34 #include <mach/mach.h>  // for mach_port_t
35 #endif  // OS_OS_MACOSX
36 
37 #include <memory>
38 #include <string>
39 
40 #include "base/scoped_handle.h"
41 #include "base/port.h"
42 
43 namespace mozc {
44 
45 class IPCPathManager;
46 class Thread;
47 
48 enum {
49   IPC_REQUESTSIZE = 16 * 8192,
50   IPC_RESPONSESIZE = 16 * 8192,
51 };
52 
53 // increment this value if protocol has changed.
54 enum {
55   IPC_PROTOCOL_VERSION = 3,
56 };
57 
58 enum IPCErrorType {
59   IPC_NO_ERROR,
60   IPC_NO_CONNECTION,
61   IPC_TIMEOUT_ERROR,
62   IPC_READ_ERROR,
63   IPC_WRITE_ERROR,
64   IPC_INVALID_SERVER,
65   IPC_UNKNOWN_ERROR,
66   IPC_QUIT_EVENT_SIGNALED,
67   IPC_ERROR_TYPE_SIZE
68 };
69 
70 class IPCClientInterface {
71  public:
72   virtual ~IPCClientInterface();
73 
74   virtual bool Connected() const = 0;
75   virtual bool Call(const char *request,
76                     size_t request_size,
77                     char *response,
78                     size_t *response_size,
79                     int32 timeout) = 0;
80 
81   virtual uint32 GetServerProtocolVersion() const = 0;
82   virtual const string &GetServerProductVersion() const = 0;
83   virtual uint32 GetServerProcessId() const = 0;
84 
85   // return last error
86   virtual IPCErrorType GetLastIPCError() const = 0;
87 };
88 
89 #ifdef OS_MACOSX
90 class MachPortManagerInterface {
91  public:
~MachPortManagerInterface()92   virtual ~MachPortManagerInterface() {}
93 
94   // If the mach port can be obtained successfully, set the specified
95   // "port" and returns true.  Otherwise port doesn't change and
96   // returns false.
97   virtual bool GetMachPort(const string &name, mach_port_t *port) = 0;
98 
99   // Returns true if the connecting server is running, checked via
100   // OS-depended way.  This method can be defined differently for testing.
101   virtual bool IsServerRunning(const string &name) const = 0;
102 };
103 #endif  // OS_MACOSX
104 
105 // Synchronous, Single-thread IPC Client
106 // Usage:
107 //  IPCClient con("name", "/foo/bar/server");
108 //  string request = "foo";
109 //  char result[32];
110 //  uint32 size = sizeof(result);
111 //  CHECK(con.Connected());
112 //  CHECK(con.Call(request.data(),
113 //                 request.size(),
114 //                 result, &size 1000);
115 //                 // wait for 1000msec
116 class IPCClient : public IPCClientInterface {
117  public:
118   // connect to an IPC server named "name".
119   // You can pass an absolute server_path to make sure
120   // the client is connecting a valid server.
121   // If server_path is empty, no validation is executed.
122   // Note: "server_path" will be ignored on Mac (MachIPC).
123   IPCClient(const string &name, const string &server_path);
124 
125   // old interface
126   // same as IPCClient(name, "");
127   explicit IPCClient(const string &name);
128 
129   virtual ~IPCClient();
130 
131   // Return true if the connection is available
132   bool Connected() const;
133 
134   // Return server protocol version
135   uint32 GetServerProtocolVersion() const;
136 
137   const string &GetServerProductVersion() const;
138 
139   uint32 GetServerProcessId() const;
140 
141 
142   // Synchronous IPC call:
143   // Client request is encoded in 'request' whose size is request_size.
144   // Server response is stored in 'response'.
145   // Need to pass the maximum size of response before calling IPC.
146   // Return true when IPC finishes successfully.
147   // When Server doesn't send response within timeout, 'Call' returns false.
148   // When timeout (in msec) is set -1, 'Call' waits forever.
149   // Note that on Linux and Windows, Call() closes the socket_. This means you
150   // cannot call the Call() function more than once.
151   bool Call(const char *request,
152             size_t request_size,
153             char *response,
154             size_t *response_size,
155             int32 timeout);  // msec
156 
GetLastIPCError()157   IPCErrorType GetLastIPCError() const {
158     return last_ipc_error_;
159   }
160 
161   // terminate the server process named |name|
162   // Do not use it unless version mismatch happens
163   static bool TerminateServer(const string &name);
164 
165 #ifdef OS_MACOSX
SetMachPortManager(MachPortManagerInterface * manager)166   void SetMachPortManager(MachPortManagerInterface *manager) {
167     mach_port_manager_ = manager;
168   }
169 #endif
170 
171  private:
172   void Init(const string &name, const string &server_path);
173 
174 #ifdef OS_WIN
175   // Windows
176   ScopedHandle pipe_handle_;
177   ScopedHandle pipe_event_;
178 #elif defined(OS_MACOSX)
179   string name_;
180   MachPortManagerInterface *mach_port_manager_;
181 #else
182   int socket_;
183 #endif
184   bool connected_;
185   IPCPathManager *ipc_path_manager_;
186   IPCErrorType last_ipc_error_;
187 };
188 
189 class IPCClientFactoryInterface {
190  public:
191   virtual ~IPCClientFactoryInterface();
192   virtual IPCClientInterface *NewClient(const string &name,
193                                         const string &path_name) = 0;
194 
195   // old interface for backward compatiblity.
196   // same as NewClient(name, "");
197   virtual IPCClientInterface *NewClient(const string &name) = 0;
198 };
199 
200 // Creates IPCClient object.
201 class IPCClientFactory : public IPCClientFactoryInterface {
202  public:
203   virtual ~IPCClientFactory();
204 
205   // new inteface
206   virtual IPCClientInterface *NewClient(const string &name,
207                                         const string &path_name);
208 
209   // old interface for backward compatiblity.
210   // same as NewClient(name, "");
211   virtual IPCClientInterface *NewClient(const string &name);
212 
213   // Return a singleton instance.
214   static IPCClientFactory *GetIPCClientFactory();
215 };
216 
217 // Synchronous, Single-thread IPC Server
218 // Usage:
219 // class MyEchoServer: public IPCServer {
220 //  public:
221 //   virtual bool Process(const char *input, uint32 isize,
222 //                        char *output, uint32 *osize) {
223 //      implement a logic in Process
224 //      return true;
225 //   }
226 //  };
227 //  // listen 10 connections, and timeout is 1000msec
228 //  MyEchoServer server("/tmp/.soket", 10, 1000);
229 //  CHECK(server.Connected());
230 //  server.Loop();
231 class IPCServer {
232  public:
233   // Make IPCServer instance:
234   // name: name of this server
235   // num_connections: maximum number of connections per server.
236   // timeout: After a client makes a connection, the client needs to
237   //          send a request within 'timeout'. If timeout is -1,
238   //          IPCServer waits forever. Default setting is -1.
239   // TODO(taku): timeout is not implemented properly
240   IPCServer(const string &name,
241             int32 num_connections,
242             int32 timeout);
243   virtual ~IPCServer();
244 
245   // Return true if the connectoin is available
246   bool Connected() const;
247 
248   // Implement a server algorithm in subclass.
249   // If 'Process' return false, server finishes select loop
250   virtual bool Process(const char *request,
251                        size_t request_size,
252                        char *response,
253                        size_t *response_size) = 0;
254 
255   // Start select loop. It goes into infinite loop.
256   void Loop();
257 
258   // Start select loop and return immediately.
259   // It invokes a thread internally.
260   void LoopAndReturn();
261 
262   // Wait until the thread ends
263   void Wait();
264 
265   // Terminate select loop from other thread
266   // On Win32, we make a control event to terminate
267   // main loop gracefully. On Mac/Linux, we simply
268   // call TerminateThread()
269   void Terminate();
270 
271 #ifdef OS_MACOSX
SetMachPortManager(MachPortManagerInterface * manager)272   void SetMachPortManager(MachPortManagerInterface *manager) {
273     mach_port_manager_ = manager;
274   }
275 #endif
276 
277  private:
278   char request_[IPC_REQUESTSIZE];
279   char response_[IPC_RESPONSESIZE];
280   bool connected_;
281   std::unique_ptr<Thread> server_thread_;
282 
283 #ifdef OS_WIN
284   ScopedHandle pipe_handle_;
285   ScopedHandle pipe_event_;
286   ScopedHandle quit_event_;
287 #elif defined(OS_MACOSX)
288   string name_;
289   MachPortManagerInterface *mach_port_manager_;
290 #else
291   int socket_;
292   string server_address_;
293 #endif
294 
295   int timeout_;
296 };
297 
298 }   // namespace mozc
299 #endif  // MOZC_IPC_IPC_H_
300