1
0
Fork 0
mirror of https://gitlab.com/niansa/quickipc.git synced 2025-03-06 20:49:18 +01:00
quickipc/include/ipc.hpp

153 lines
3.3 KiB
C++

class QIPC;
class QBiIPC;
#ifndef _QIPC_IPC_HPP
#define _QIPC_IPC_HPP
#include <string>
#include <string_view>
#include <stdexcept>
#include <cstring>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
class QIPC {
public:
struct Error : public std::runtime_error {
using std::runtime_error::runtime_error;
};
private:
template<typename T>
static T syscchk(T code) {
// Check if system call result code is -1, if so throw exception
if (code < 0) {
throw Error(strerror(errno));
}
return code;
}
int raw_fds[2] = {-1, -1};
public:
static constexpr size_t default_max_buflen = 4000;
size_t max_buflen;
auto get_in() const {
return raw_fds[0];
}
auto get_out() const {
return raw_fds[1];
}
QIPC(int in, int out, size_t max_buflen = default_max_buflen)
: max_buflen(max_buflen) {
raw_fds[0] = in;
raw_fds[1] = out;
}
QIPC(size_t max_buflen = default_max_buflen) : max_buflen(max_buflen) {}
QIPC(const QIPC&) = delete;
QIPC(const QIPC&& o) {
QIPC(o.get_in(), o.get_out(), o.max_buflen);
}
auto operator =(const QIPC& o) {
QIPC(o.get_in(), o.get_out());
}
void create() {
syscchk(pipe(raw_fds));
}
void close() {
if (raw_fds[0] != -1) {
::close(raw_fds[0]);
}
if (raw_fds[1] != -1) {
::close(raw_fds[1]);
}
}
void send(std::string_view str) {
size_t len = str.size();
syscchk(write(get_out(), &len, sizeof(len))); // Write length
syscchk(write(get_out(), str.data(), len)); // Write data
}
auto recv() {
// Read len
size_t len;
syscchk(read(get_in(), &len, sizeof(len)));
// Check len
if (len > 2000) {
throw Error("Data length limit exceeded");
}
// Read data
auto data = new char[len];
syscchk(read(get_in(), data, len));
// Construct string
auto fres = std::string(data, data+len);
// Clean up
delete []data;
// Return final result
return fres;
}
template<typename T>
void send_raw(const T& data) {
syscchk(write(get_out(), &data, sizeof(data)));
}
template<typename T>
T recv_raw() {
// Disclaimer: Bad practice, but what if T does not have a default constructor?
// This allows us to not construct the object at all!
// Skipping the constructor might even improve performance and prevent UB!
char fres[sizeof(T)];
syscchk(read(get_in(), &fres, sizeof(fres)));
return *reinterpret_cast<T*>(&fres);
}
};
struct QBiIPC {
QIPC in, out;
void create() {
in.create();
out.create();
}
void swap() {
std::swap(in, out);
}
auto get_in() const {
return in.get_in();
}
auto get_out() const {
return out.get_out();
}
void send(std::string_view str) {
out.send(str);
}
auto recv() {
return in.recv();
}
template<typename T>
void send_raw(const T& data) {
out.send_raw<T>(data);
}
template<typename T>
auto recv_raw() {
return in.recv_raw<T>();
}
};
#endif