#ifndef IPC_H #define IPC_H #include #include #ifdef _WIN32 #include #include #else #include #include #include #endif class IPC { public: IPC(std::string path) { mStopped = false; #ifdef _WIN32 while (true) { mPipe = CreateFile( path.data(), // pipe name GENERIC_READ | GENERIC_WRITE, // read and write access 0, // no sharing NULL, // default security attributes OPEN_EXISTING, // opens existing pipe FILE_FLAG_OVERLAPPED, // attributes NULL // no template file ); if (mPipe != INVALID_HANDLE_VALUE) { break; } if (GetLastError() != ERROR_PIPE_BUSY) { throw std::runtime_error("Could not open pipe"); } // Wait for pipe to become available if it is busy if (!WaitNamedPipe(path.data(), 30000)) { throw std::runtime_error("Error waiting for pipe"); } } mReader = CreateEvent(NULL, true, false, NULL); mWriter = CreateEvent(NULL, true, false, NULL); #else struct sockaddr_un addr; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path) - 1); mSock = socket(AF_UNIX, SOCK_STREAM, 0); if (connect(mSock, (struct sockaddr *) &addr, sizeof(struct sockaddr_un))) { throw std::runtime_error("Error connecting to socket"); } #endif } ~IPC() { mStopped = true; #ifdef _WIN32 CancelIo(mPipe); CloseHandle(mPipe); CloseHandle(mReader); CloseHandle(mWriter); #else shutdown(mSock, SHUT_RDWR); #endif } void write(std::string buf) { #ifdef _WIN32 OVERLAPPED overlapped; overlapped.hEvent = mWriter; bool success = WriteFile( mPipe, // pipe handle buf.data(), // message buf.size(), // message length NULL, // bytes written &overlapped // overlapped ); if (mStopped) { return; } if (!success) { if (GetLastError() != ERROR_IO_PENDING) { throw std::runtime_error("Write error"); } } DWORD written; success = GetOverlappedResult(mPipe, &overlapped, &written, true); if (!success) { throw std::runtime_error("GetOverlappedResult failed"); } if (written != buf.size()) { throw std::runtime_error("Wrong number of bytes written"); } #else int r = 0; for (unsigned int i = 0; i != buf.size(); i += r) { r = ::write(mSock, &buf[i], buf.size() - i); if (r == -1) { if (errno == EAGAIN) { r = 0; } else if (mStopped) { return; } else { throw std::runtime_error("Write error"); } } } #endif } int read(char *buf, size_t len) { #ifdef _WIN32 OVERLAPPED overlapped; overlapped.hEvent = mReader; bool success = ReadFile( mPipe, // pipe handle buf, // buffer to receive reply len, // size of buffer NULL, // number of bytes read &overlapped // overlapped ); if (!success && !mStopped) { if (GetLastError() != ERROR_IO_PENDING) { throw std::runtime_error("Read error"); } } DWORD read = 0; success = GetOverlappedResult(mPipe, &overlapped, &read, true); if (!success && !mStopped) { throw std::runtime_error("GetOverlappedResult failed"); } return read; #else int r = ::read(mSock, buf, len); if (r == 0 && !mStopped) { throw std::runtime_error("Socket ended unexpectedly"); } if (r < 0) { if (mStopped) { return 0; } throw std::runtime_error(strerror(errno)); } return r; #endif } private: bool mStopped; #ifdef _WIN32 HANDLE mPipe; HANDLE mReader; HANDLE mWriter; #else int mSock; #endif }; #endif