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