1
0
Fork 0
mirror of https://github.com/fastogt/fastocloud.git synced 2025-03-09 23:18:50 +00:00
fastocloud/src/server/process_slave_wrapper_posix.cpp
2024-12-26 09:06:54 +03:00

185 lines
6.2 KiB
C++

/* Copyright (C) 2014-2022 FastoGT. All right reserved.
This file is part of fastocloud.
fastocloud is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
fastocloud is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with fastocloud. If not, see <http://www.gnu.org/licenses/>.
*/
#include "server/process_slave_wrapper.h"
#if defined(OS_LINUX)
#include <sys/prctl.h>
#endif
#include <common/file_system/file_system.h>
#include <common/file_system/string_path_utils.h>
#include <common/libev/tcp/tcp_server.h>
#include <dlfcn.h>
#include <sys/wait.h>
#include <unistd.h>
#include "base/stream_info.h"
#include "server/child_stream.h"
#include "server/utils/utils.h"
#define PIPE
#if defined(PIPE)
#include "pipe/client.h"
#else
#include "tcp/client.h"
#endif
namespace fastocloud {
namespace server {
common::ErrnoError ProcessSlaveWrapper::CreateChildStreamImpl(const serialized_stream_t& config_args,
const StreamInfo& sha) {
const auto sid = GetSid(config_args);
if (!sid) {
return common::make_errno_error_inval();
}
#if defined(PIPE)
common::net::socket_descr_t read_command_client;
common::net::socket_descr_t write_requests_client;
common::ErrnoError err = CreatePipe(&read_command_client, &write_requests_client);
if (err) {
return err;
}
common::net::socket_descr_t read_responce_client;
common::net::socket_descr_t write_responce_client;
err = CreatePipe(&read_responce_client, &write_responce_client);
if (err) {
common::ErrnoError errn = common::file_system::close_descriptor(read_command_client);
if (errn) {
DEBUG_MSG_ERROR(errn, common::logging::LOG_LEVEL_WARNING);
}
errn = common::file_system::close_descriptor(write_requests_client);
if (errn) {
DEBUG_MSG_ERROR(errn, common::logging::LOG_LEVEL_WARNING);
}
return err;
}
#else
common::net::socket_descr_t parent_sock;
common::net::socket_descr_t child_sock;
common::ErrnoError err = CreateSocketPair(&parent_sock, &child_sock);
if (err) {
return err;
}
#endif
#if !defined(TEST)
pid_t pid = fork();
#else
pid_t pid = 0;
#endif
if (pid == 0) { // child
typedef int (*stream_exec_t)(const char* process_name, const void* args, void* command_client);
const std::string absolute_source_dir = common::file_system::absolute_path_from_relative(RELATIVE_SOURCE_DIR);
const std::string lib_full_path = common::file_system::make_path(absolute_source_dir, CORE_LIBRARY);
void* handle = dlopen(lib_full_path.c_str(), RTLD_LAZY);
if (!handle) {
ERROR_LOG() << "Failed to load " CORE_LIBRARY " path: " << lib_full_path << ", error: " << dlerror();
_exit(EXIT_FAILURE);
}
stream_exec_t stream_exec_func = reinterpret_cast<stream_exec_t>(dlsym(handle, "stream_exec"));
char* error = dlerror();
if (error) {
ERROR_LOG() << "Failed to load start stream function error: " << error;
dlclose(handle);
_exit(EXIT_FAILURE);
}
const std::string new_process_name = common::MemSPrintf(STREAMER_NAME "_%s", *sid);
const char* new_name = new_process_name.c_str();
#if defined(OS_LINUX)
for (int i = 0; i < process_argc_; ++i) {
memset(process_argv_[i], 0, strlen(process_argv_[i]));
}
char* app_name = process_argv_[0];
strncpy(app_name, new_name, new_process_name.length());
app_name[new_process_name.length()] = 0;
prctl(PR_SET_NAME, new_name);
#elif defined(OS_FREEBSD)
setproctitle(new_name);
#else
#pragma message "Please implement"
#endif
#if defined(PIPE)
#if !defined(TEST)
// close not needed pipes
common::ErrnoError errn = common::file_system::close_descriptor(read_responce_client);
if (errn) {
DEBUG_MSG_ERROR(errn, common::logging::LOG_LEVEL_WARNING);
}
errn = common::file_system::close_descriptor(write_requests_client);
if (errn) {
DEBUG_MSG_ERROR(errn, common::logging::LOG_LEVEL_WARNING);
}
#endif
pipe::Client* client = new pipe::Client(nullptr, read_command_client, write_responce_client);
#else
// close not needed sock
common::ErrnoError errn = common::file_system::close_descriptor(parent_sock);
if (errn) {
DEBUG_MSG_ERROR(errn, common::logging::LOG_LEVEL_WARNING);
}
tcp::Client* client = new tcp::Client(nullptr, common::net::socket_info(child_sock));
#endif
client->SetName(*sid);
int res = stream_exec_func(new_name, config_args.get(), client);
ignore_result(client->Close());
delete client;
dlclose(handle);
_exit(res);
} else if (pid < 0) {
ERROR_LOG() << "Failed to start children!";
} else {
#if defined(PIPE)
// close not needed pipes
common::ErrnoError errn = common::file_system::close_descriptor(read_command_client);
if (errn) {
DEBUG_MSG_ERROR(errn, common::logging::LOG_LEVEL_WARNING);
}
errn = common::file_system::close_descriptor(write_responce_client);
if (err) {
DEBUG_MSG_ERROR(errn, common::logging::LOG_LEVEL_WARNING);
}
pipe::Client* client = new pipe::Client(loop_, read_responce_client, write_requests_client);
#else
// close not needed sock
common::ErrnoError errn = common::file_system::close_descriptor(child_sock);
if (errn) {
DEBUG_MSG_ERROR(errn, common::logging::LOG_LEVEL_WARNING);
}
tcp::Client* client = new tcp::Client(loop_, common::net::socket_info(parent_sock));
#endif
client->SetName(*sid);
bool registered = loop_->RegisterClient(client);
if (!registered) {
return common::make_errno_error("Can't register communication pipe", EAGAIN);
}
ChildStream* new_channel = new ChildStream(loop_, sha);
new_channel->SetClient(client);
loop_->RegisterChild(new_channel, pid);
}
return common::ErrnoError();
}
} // namespace server
} // namespace fastocloud