mirror of
https://gitlab.com/niansa/quickipc.git
synced 2025-03-06 20:49:18 +01:00
Initial commit
This commit is contained in:
commit
1dfce00163
3 changed files with 121 additions and 0 deletions
2
Makefile
Normal file
2
Makefile
Normal file
|
@ -0,0 +1,2 @@
|
|||
install:
|
||||
cp -r include /usr/include/QIPC
|
23
examples/main.cpp
Normal file
23
examples/main.cpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include "QIPC/ipc.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
|
||||
void child(QIPC& ipc) {
|
||||
ipc.send("Hello world!");
|
||||
ipc.send_raw(size_t(1234567890));
|
||||
}
|
||||
|
||||
int main() {
|
||||
QIPC ipc;
|
||||
ipc.create();
|
||||
|
||||
if (fork() == 0) {
|
||||
child(ipc);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
std::cout << ipc.recv() << std::endl;
|
||||
std::cout << ipc.recv_raw<size_t>() << std::endl;
|
||||
}
|
96
include/ipc.hpp
Normal file
96
include/ipc.hpp
Normal file
|
@ -0,0 +1,96 @@
|
|||
#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) {
|
||||
if (code < 0) {
|
||||
throw std::runtime_error(strerror(errno));
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
class Fds {
|
||||
int raw[2] = {-1, -1};
|
||||
|
||||
public:
|
||||
void create_pipe() {
|
||||
syscchk(pipe(raw));
|
||||
}
|
||||
|
||||
auto get_in() {
|
||||
return raw[0];
|
||||
}
|
||||
auto get_out() {
|
||||
return raw[1];
|
||||
}
|
||||
} fds;
|
||||
|
||||
public:
|
||||
QIPC(const Fds fds) {
|
||||
this->fds = fds;
|
||||
}
|
||||
QIPC() {}
|
||||
|
||||
const Fds& get_fds() {
|
||||
return fds;
|
||||
}
|
||||
|
||||
void create() {
|
||||
fds.create_pipe();
|
||||
}
|
||||
|
||||
void send(std::string_view str) {
|
||||
size_t len = str.size();
|
||||
syscchk(write(fds.get_out(), &len, sizeof(len))); // Write length
|
||||
syscchk(write(fds.get_out(), str.data(), len)); // Write data
|
||||
}
|
||||
|
||||
auto recv() {
|
||||
// Read len
|
||||
size_t len;
|
||||
syscchk(read(fds.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(fds.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(fds.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.
|
||||
char fres[sizeof(T)];
|
||||
syscchk(read(fds.get_in(), &fres, sizeof(fres)));
|
||||
return *reinterpret_cast<T*>(&fres);
|
||||
}
|
||||
};
|
Loading…
Add table
Reference in a new issue