1 | #ifndef IPC_H
|
---|
2 | #define IPC_H
|
---|
3 |
|
---|
4 | #include <string>
|
---|
5 | #include <stdlib.h>
|
---|
6 |
|
---|
7 | #ifdef _WIN32
|
---|
8 | #include <winsock2.h>
|
---|
9 | #include <windows.h>
|
---|
10 | #else
|
---|
11 | #include <unistd.h>
|
---|
12 | #include <sys/socket.h>
|
---|
13 | #include <sys/un.h>
|
---|
14 | #endif
|
---|
15 |
|
---|
16 | class IPC {
|
---|
17 | public:
|
---|
18 | IPC(std::string path) {
|
---|
19 | mStopped = false;
|
---|
20 | #ifdef _WIN32
|
---|
21 | while (true) {
|
---|
22 | mPipe = CreateFile(
|
---|
23 | path.data(), // pipe name
|
---|
24 | GENERIC_READ | GENERIC_WRITE, // read and write access
|
---|
25 | 0, // no sharing
|
---|
26 | NULL, // default security attributes
|
---|
27 | OPEN_EXISTING, // opens existing pipe
|
---|
28 | FILE_FLAG_OVERLAPPED, // attributes
|
---|
29 | NULL // no template file
|
---|
30 | );
|
---|
31 |
|
---|
32 | if (mPipe != INVALID_HANDLE_VALUE) {
|
---|
33 | break;
|
---|
34 | }
|
---|
35 |
|
---|
36 | if (GetLastError() != ERROR_PIPE_BUSY) {
|
---|
37 | throw std::runtime_error("Could not open pipe");
|
---|
38 | }
|
---|
39 |
|
---|
40 | // Wait for pipe to become available if it is busy
|
---|
41 | if (!WaitNamedPipe(path.data(), 30000)) {
|
---|
42 | throw std::runtime_error("Error waiting for pipe");
|
---|
43 | }
|
---|
44 | }
|
---|
45 |
|
---|
46 | mReader = CreateEvent(NULL, true, false, NULL);
|
---|
47 | mWriter = CreateEvent(NULL, true, false, NULL);
|
---|
48 | #else
|
---|
49 | struct sockaddr_un addr;
|
---|
50 | memset(&addr, 0, sizeof(addr));
|
---|
51 | addr.sun_family = AF_UNIX;
|
---|
52 | strncpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path) - 1);
|
---|
53 |
|
---|
54 | mSock = socket(AF_UNIX, SOCK_STREAM, 0);
|
---|
55 | if (connect(mSock, (struct sockaddr *) &addr, sizeof(struct sockaddr_un))) {
|
---|
56 | throw std::runtime_error("Error connecting to socket");
|
---|
57 | }
|
---|
58 | #endif
|
---|
59 | }
|
---|
60 |
|
---|
61 | ~IPC() {
|
---|
62 | mStopped = true;
|
---|
63 | #ifdef _WIN32
|
---|
64 | CancelIo(mPipe);
|
---|
65 | CloseHandle(mPipe);
|
---|
66 | CloseHandle(mReader);
|
---|
67 | CloseHandle(mWriter);
|
---|
68 | #else
|
---|
69 | shutdown(mSock, SHUT_RDWR);
|
---|
70 | #endif
|
---|
71 | }
|
---|
72 |
|
---|
73 | void write(std::string buf) {
|
---|
74 | #ifdef _WIN32
|
---|
75 | OVERLAPPED overlapped;
|
---|
76 | overlapped.hEvent = mWriter;
|
---|
77 | bool success = WriteFile(
|
---|
78 | mPipe, // pipe handle
|
---|
79 | buf.data(), // message
|
---|
80 | buf.size(), // message length
|
---|
81 | NULL, // bytes written
|
---|
82 | &overlapped // overlapped
|
---|
83 | );
|
---|
84 |
|
---|
85 | if (mStopped) {
|
---|
86 | return;
|
---|
87 | }
|
---|
88 |
|
---|
89 | if (!success) {
|
---|
90 | if (GetLastError() != ERROR_IO_PENDING) {
|
---|
91 | throw std::runtime_error("Write error");
|
---|
92 | }
|
---|
93 | }
|
---|
94 |
|
---|
95 | DWORD written;
|
---|
96 | success = GetOverlappedResult(mPipe, &overlapped, &written, true);
|
---|
97 | if (!success) {
|
---|
98 | throw std::runtime_error("GetOverlappedResult failed");
|
---|
99 | }
|
---|
100 |
|
---|
101 | if (written != buf.size()) {
|
---|
102 | throw std::runtime_error("Wrong number of bytes written");
|
---|
103 | }
|
---|
104 | #else
|
---|
105 | int r = 0;
|
---|
106 | for (unsigned int i = 0; i != buf.size(); i += r) {
|
---|
107 | r = ::write(mSock, &buf[i], buf.size() - i);
|
---|
108 | if (r == -1) {
|
---|
109 | if (errno == EAGAIN) {
|
---|
110 | r = 0;
|
---|
111 | } else if (mStopped) {
|
---|
112 | return;
|
---|
113 | } else {
|
---|
114 | throw std::runtime_error("Write error");
|
---|
115 | }
|
---|
116 | }
|
---|
117 | }
|
---|
118 | #endif
|
---|
119 | }
|
---|
120 |
|
---|
121 | int read(char *buf, size_t len) {
|
---|
122 | #ifdef _WIN32
|
---|
123 | OVERLAPPED overlapped;
|
---|
124 | overlapped.hEvent = mReader;
|
---|
125 | bool success = ReadFile(
|
---|
126 | mPipe, // pipe handle
|
---|
127 | buf, // buffer to receive reply
|
---|
128 | len, // size of buffer
|
---|
129 | NULL, // number of bytes read
|
---|
130 | &overlapped // overlapped
|
---|
131 | );
|
---|
132 |
|
---|
133 | if (!success && !mStopped) {
|
---|
134 | if (GetLastError() != ERROR_IO_PENDING) {
|
---|
135 | throw std::runtime_error("Read error");
|
---|
136 | }
|
---|
137 | }
|
---|
138 |
|
---|
139 | DWORD read = 0;
|
---|
140 | success = GetOverlappedResult(mPipe, &overlapped, &read, true);
|
---|
141 | if (!success && !mStopped) {
|
---|
142 | throw std::runtime_error("GetOverlappedResult failed");
|
---|
143 | }
|
---|
144 |
|
---|
145 | return read;
|
---|
146 | #else
|
---|
147 | int r = ::read(mSock, buf, len);
|
---|
148 | if (r == 0 && !mStopped) {
|
---|
149 | throw std::runtime_error("Socket ended unexpectedly");
|
---|
150 | }
|
---|
151 |
|
---|
152 | if (r < 0) {
|
---|
153 | if (mStopped) {
|
---|
154 | return 0;
|
---|
155 | }
|
---|
156 |
|
---|
157 | throw std::runtime_error(strerror(errno));
|
---|
158 | }
|
---|
159 |
|
---|
160 | return r;
|
---|
161 | #endif
|
---|
162 | }
|
---|
163 |
|
---|
164 | private:
|
---|
165 | bool mStopped;
|
---|
166 | #ifdef _WIN32
|
---|
167 | HANDLE mPipe;
|
---|
168 | HANDLE mReader;
|
---|
169 | HANDLE mWriter;
|
---|
170 | #else
|
---|
171 | int mSock;
|
---|
172 | #endif
|
---|
173 | };
|
---|
174 |
|
---|
175 | #endif
|
---|