24#include <sys/socket.h>
32class ProcessImpl :
public Process
35 std::tuple<mp::ProcessId, mp::SocketId> spawn(
const std::string& new_exe_name,
const fs::path& argv0_path)
override
38 fs::path path = argv0_path;
39 path.remove_filename();
41 return std::vector<std::string>{
fs::PathToString(path),
"-ipcfd", std::move(connect_info)};
45 bool checkSpawned(
int argc,
char* argv[],
mp::SocketId& socket)
override
50 if (argc != 3 || strcmp(argv[1],
"-ipcfd") != 0) {
61 }
catch (
const std::exception& e) {
62 throw std::runtime_error(
strprintf(
"Invalid -ipcfd number '%s' (%s)", argv[2], e.what()));
67 const std::string& dest_exe_name,
68 std::string& address)
override;
69 mp::SocketId bind(
const fs::path& data_dir,
const std::string& exe_name, std::string& address)
override;
72static bool ParseAddress(std::string& address,
73 const fs::path& data_dir,
74 const std::string& dest_exe_name,
75 struct sockaddr_un& addr,
78 if (address ==
"unix" || address.starts_with(
"unix:")) {
80 if (address.size() <= 5) {
87 if (path_str.size() >=
sizeof(addr.sun_path)) {
88 error =
strprintf(
"Unix address path %s exceeded maximum socket path length", fs::quoted(fs::PathToString(path)));
91 memset(&addr, 0,
sizeof(addr));
92 addr.sun_family = AF_UNIX;
93 strncpy(addr.sun_path, path_str.c_str(),
sizeof(addr.sun_path)-1);
97 error =
strprintf(
"Unrecognized address '%s'", address);
101mp::SocketId ProcessImpl::connect(
const fs::path& data_dir,
102 const std::string& dest_exe_name,
103 std::string& address)
105 struct sockaddr_un addr;
107 if (!ParseAddress(address, data_dir, dest_exe_name, addr, error)) {
108 throw std::invalid_argument(error);
112 if ((fd = ::socket(addr.sun_family, SOCK_STREAM, 0)) ==
mp::SocketError) {
113 throw std::system_error(errno, std::system_category());
115 if (::connect(fd, (
struct sockaddr*)&addr,
sizeof(addr)) == 0) {
118 int connect_error = errno;
119 if (::close(fd) != 0) {
122 throw std::system_error(connect_error, std::system_category());
125mp::SocketId ProcessImpl::bind(
const fs::path& data_dir,
const std::string& exe_name, std::string& address)
127 struct sockaddr_un addr;
129 if (!ParseAddress(address, data_dir, exe_name, addr, error)) {
130 throw std::invalid_argument(error);
133 if (addr.sun_family == AF_UNIX) {
134 fs::path path = addr.sun_path;
135 if (path.has_parent_path()) fs::create_directories(path.parent_path());
136 if (fs::symlink_status(path).type() == fs::file_type::socket) {
142 if ((fd = ::socket(addr.sun_family, SOCK_STREAM, 0)) ==
mp::SocketError) {
143 throw std::system_error(errno, std::system_category());
146 if (::bind(fd, (
struct sockaddr*)&addr,
sizeof(addr)) == 0) {
149 int bind_error = errno;
150 if (::close(fd) != 0) {
153 throw std::system_error(bind_error, std::system_category());
157std::unique_ptr<Process>
MakeProcess() {
return std::make_unique<ProcessImpl>(); }
static std::string PathToString(const path &path)
Convert path object to a byte string.
static path PathFromString(const std::string &string)
Convert byte string to path object.
std::unique_ptr< Process > MakeProcess()
Constructor for Process interface.
int WaitProcess(int pid)
Wait for a process to exit and return its exit code.
int SpawnProcess(int &pid, FdToArgsFn &&fd_to_args)
Spawn a new process that communicates with the current process over a socket pair.
SocketId StartSpawned(const std::string &connect_info)
constexpr SocketId SocketError
std::string_view RemovePrefixView(std::string_view str, std::string_view prefix)
std::string SysErrorString(int err)
Return system error string from errno value.