72 lines
1.9 KiB
C++
72 lines
1.9 KiB
C++
#include <utility>
|
|
#include <variant>
|
|
#include <cstdlib>
|
|
#include <string>
|
|
#include <unistd.h>
|
|
|
|
#include "lib.h"
|
|
|
|
// Load Pipes
|
|
static std::variant<int, Trampoline::Error> get_pipe(const char *env) {
|
|
const char *value = getenv(env);
|
|
if (value == nullptr) {
|
|
return Trampoline::Error::MISSING_PIPE;
|
|
}
|
|
try {
|
|
const int val = std::stoi(value);
|
|
if (val >= 0) {
|
|
return val;
|
|
}
|
|
} catch (...) {
|
|
}
|
|
return Trampoline::Error::INVALID_PIPE;
|
|
}
|
|
#define set(var, env) \
|
|
val = get_pipe(env); \
|
|
if (std::holds_alternative<Error>(val)) { \
|
|
status = std::get<Error>(val); \
|
|
return; \
|
|
} \
|
|
var = std::get<int>(val)
|
|
PipeTrampoline::PipeTrampoline() {
|
|
std::variant<int, Error> val;
|
|
set(arguments_pipe, _MCPI_TRAMPOLINE_ARGUMENTS_ENV);
|
|
set(return_value_pipe, _MCPI_TRAMPOLINE_RETURN_VALUE_ENV);
|
|
// Success
|
|
status = Error::NONE;
|
|
}
|
|
#undef set
|
|
|
|
// Call
|
|
Trampoline::Error PipeTrampoline::call(const uint32_t id, uint32_t *ret_ptr, const uint32_t length, const unsigned char *args) {
|
|
// Check
|
|
if (status != Error::NONE) {
|
|
return status;
|
|
}
|
|
// Write Command
|
|
const trampoline_pipe_arguments cmd = {
|
|
.id = id,
|
|
.allow_early_return = ret_ptr == nullptr,
|
|
.length = length
|
|
};
|
|
if (write(arguments_pipe, &cmd, sizeof(trampoline_pipe_arguments)) != sizeof(trampoline_pipe_arguments)) {
|
|
return Error::PIPE_WRITE;
|
|
}
|
|
// Write Arguments
|
|
size_t position = 0;
|
|
while (position < length) {
|
|
const ssize_t ret = write(arguments_pipe, args + position, length - position);
|
|
if (ret == -1) {
|
|
return Error::PIPE_WRITE;
|
|
} else {
|
|
position += ret;
|
|
}
|
|
}
|
|
// Return Value
|
|
if (ret_ptr != nullptr && read(return_value_pipe, ret_ptr, sizeof(uint32_t)) != sizeof(uint32_t)) {
|
|
return Error::PIPE_READ;
|
|
}
|
|
// Success
|
|
return Error::NONE;
|
|
}
|