#ifndef IPC_H
|
#define IPC_H
|
|
#include <string>
|
#include <stdlib.h>
|
|
#ifdef _WIN32
|
#include <winsock2.h>
|
#include <windows.h>
|
#else
|
#include <unistd.h>
|
#include <sys/socket.h>
|
#include <sys/un.h>
|
#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
|