mirror of
https://github.com/FEX-Emu/FEX.git
synced 2025-02-17 05:18:49 +00:00
Merge pull request #4159 from asahilina/fexserver-two-sockets
FEXServer: Listen on both abstract & named sockets
This commit is contained in:
commit
d5c96555f1
@ -96,14 +96,21 @@ fextl::string GetServerRootFSLockFile() {
|
||||
}
|
||||
|
||||
fextl::string GetTempFolder() {
|
||||
auto XDGRuntimeEnv = getenv("XDG_RUNTIME_DIR");
|
||||
if (XDGRuntimeEnv) {
|
||||
// If the XDG runtime directory works then use that.
|
||||
return XDGRuntimeEnv;
|
||||
const std::array<const char*, 5> Vars = {
|
||||
"XDG_RUNTIME_DIR", "TMPDIR", "TMP", "TEMP", "TEMPDIR",
|
||||
};
|
||||
|
||||
for (auto& Var : Vars) {
|
||||
auto Path = getenv(Var);
|
||||
if (Path) {
|
||||
// If one of the env variable-driven paths works then use that.
|
||||
return Path;
|
||||
}
|
||||
}
|
||||
// Fallback to `/tmp/` if XDG_RUNTIME_DIR doesn't exist.
|
||||
|
||||
// Fallback to `/tmp/` if no env vars are set.
|
||||
// Might not be ideal but we don't have much of a choice.
|
||||
return fextl::string {std::filesystem::temp_directory_path().string()};
|
||||
return fextl::string {"/tmp"};
|
||||
}
|
||||
|
||||
fextl::string GetServerMountFolder() {
|
||||
@ -143,6 +150,24 @@ fextl::string GetServerSocketName() {
|
||||
return ServerSocketPath;
|
||||
}
|
||||
|
||||
fextl::string GetServerSocketPath() {
|
||||
FEX_CONFIG_OPT(ServerSocketPath, SERVERSOCKETPATH);
|
||||
|
||||
auto name = ServerSocketPath();
|
||||
|
||||
if (name.starts_with("/")) {
|
||||
return name;
|
||||
}
|
||||
|
||||
auto Folder = GetTempFolder();
|
||||
|
||||
if (name.empty()) {
|
||||
return fextl::fmt::format("{}/{}.FEXServer.Socket", Folder, ::geteuid());
|
||||
} else {
|
||||
return fextl::fmt::format("{}/{}", Folder, name);
|
||||
}
|
||||
}
|
||||
|
||||
int GetServerFD() {
|
||||
return ServerFD;
|
||||
}
|
||||
@ -153,7 +178,7 @@ int ConnectToServer(ConnectionOption ConnectionOption) {
|
||||
// Create the initial unix socket
|
||||
int SocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (SocketFD == -1) {
|
||||
LogMan::Msg::EFmt("Couldn't open AF_UNIX socket {} {}", errno, strerror(errno));
|
||||
LogMan::Msg::EFmt("Couldn't open AF_UNIX socket {}", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -170,13 +195,29 @@ int ConnectToServer(ConnectionOption ConnectionOption) {
|
||||
|
||||
if (connect(SocketFD, reinterpret_cast<struct sockaddr*>(&addr), SizeOfAddr) == -1) {
|
||||
if (ConnectionOption == ConnectionOption::Default || errno != ECONNREFUSED) {
|
||||
LogMan::Msg::EFmt("Couldn't connect to FEXServer socket {} {} {}", ServerSocketName, errno, strerror(errno));
|
||||
LogMan::Msg::EFmt("Couldn't connect to FEXServer socket {} {}", ServerSocketName, errno);
|
||||
}
|
||||
close(SocketFD);
|
||||
return -1;
|
||||
} else {
|
||||
return SocketFD;
|
||||
}
|
||||
|
||||
return SocketFD;
|
||||
// Try again with a path-based socket, since abstract sockets will fail if we have been
|
||||
// placed in a new netns as part of a sandbox.
|
||||
auto ServerSocketPath = GetServerSocketPath();
|
||||
|
||||
SizeOfSocketString = std::min(ServerSocketPath.size(), sizeof(addr.sun_path) - 1);
|
||||
strncpy(addr.sun_path, ServerSocketPath.data(), SizeOfSocketString);
|
||||
SizeOfAddr = sizeof(addr.sun_family) + SizeOfSocketString;
|
||||
if (connect(SocketFD, reinterpret_cast<struct sockaddr*>(&addr), SizeOfAddr) == -1) {
|
||||
if (ConnectionOption == ConnectionOption::Default || (errno != ECONNREFUSED && errno != ENOENT)) {
|
||||
LogMan::Msg::EFmt("Couldn't connect to FEXServer socket {} {}", ServerSocketPath, errno);
|
||||
}
|
||||
} else {
|
||||
return SocketFD;
|
||||
}
|
||||
|
||||
close(SocketFD);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool SetupClient(char* InterpreterPath) {
|
||||
|
@ -53,6 +53,7 @@ fextl::string GetServerRootFSLockFile();
|
||||
fextl::string GetTempFolder();
|
||||
fextl::string GetServerMountFolder();
|
||||
fextl::string GetServerSocketName();
|
||||
fextl::string GetServerSocketPath();
|
||||
int GetServerFD();
|
||||
|
||||
bool SetupClient(char* InterpreterPath);
|
||||
|
@ -163,7 +163,13 @@ int main(int argc, char** argv, char** const envp) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ProcessPipe::InitializeServerSocket()) {
|
||||
if (!ProcessPipe::InitializeServerSocket(true)) {
|
||||
// Couldn't create server socket for some reason
|
||||
PipeScanner::ClosePipes();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ProcessPipe::InitializeServerSocket(false)) {
|
||||
// Couldn't create server socket for some reason
|
||||
PipeScanner::ClosePipes();
|
||||
return -1;
|
||||
|
@ -19,6 +19,7 @@ namespace ProcessPipe {
|
||||
constexpr int USER_PERMS = S_IRWXU | S_IRWXG | S_IRWXO;
|
||||
int ServerLockFD {-1};
|
||||
int ServerSocketFD {-1};
|
||||
int ServerFSSocketFD {-1};
|
||||
std::atomic<bool> ShouldShutdown {false};
|
||||
time_t RequestTimeout {10};
|
||||
bool Foreground {false};
|
||||
@ -175,40 +176,58 @@ bool InitializeServerPipe() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InitializeServerSocket() {
|
||||
auto ServerSocketName = FEXServerClient::GetServerSocketName();
|
||||
bool InitializeServerSocket(bool abstract) {
|
||||
|
||||
// Create the initial unix socket
|
||||
ServerSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (ServerSocketFD == -1) {
|
||||
int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (fd == -1) {
|
||||
LogMan::Msg::EFmt("Couldn't create AF_UNIX socket: {} {}\n", errno, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sockaddr_un addr {};
|
||||
addr.sun_family = AF_UNIX;
|
||||
size_t SizeOfSocketString = std::min(ServerSocketName.size() + 1, sizeof(addr.sun_path) - 1);
|
||||
addr.sun_path[0] = 0; // Abstract AF_UNIX sockets start with \0
|
||||
strncpy(addr.sun_path + 1, ServerSocketName.data(), SizeOfSocketString);
|
||||
|
||||
size_t SizeOfSocketString;
|
||||
if (abstract) {
|
||||
auto ServerSocketName = FEXServerClient::GetServerSocketName();
|
||||
SizeOfSocketString = std::min(ServerSocketName.size() + 1, sizeof(addr.sun_path) - 1);
|
||||
addr.sun_path[0] = 0; // Abstract AF_UNIX sockets start with \0
|
||||
strncpy(addr.sun_path + 1, ServerSocketName.data(), SizeOfSocketString);
|
||||
} else {
|
||||
auto ServerSocketPath = FEXServerClient::GetServerSocketPath();
|
||||
// Unlink the socket file if it exists
|
||||
// We are being asked to create a daemon, not error check
|
||||
// We don't care if this failed or not
|
||||
unlink(ServerSocketPath.c_str());
|
||||
|
||||
SizeOfSocketString = std::min(ServerSocketPath.size(), sizeof(addr.sun_path) - 1);
|
||||
strncpy(addr.sun_path, ServerSocketPath.data(), SizeOfSocketString);
|
||||
}
|
||||
// Include final null character.
|
||||
size_t SizeOfAddr = sizeof(addr.sun_family) + SizeOfSocketString;
|
||||
|
||||
// Bind the socket to the path
|
||||
int Result = bind(ServerSocketFD, reinterpret_cast<struct sockaddr*>(&addr), SizeOfAddr);
|
||||
int Result = bind(fd, reinterpret_cast<struct sockaddr*>(&addr), SizeOfAddr);
|
||||
if (Result == -1) {
|
||||
LogMan::Msg::EFmt("Couldn't bind AF_UNIX socket '{}': {} {}\n", addr.sun_path, errno, strerror(errno));
|
||||
close(ServerSocketFD);
|
||||
ServerSocketFD = -1;
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
listen(ServerSocketFD, 16);
|
||||
listen(fd, 16);
|
||||
PollFDs.emplace_back(pollfd {
|
||||
.fd = ServerSocketFD,
|
||||
.fd = fd,
|
||||
.events = POLLIN,
|
||||
.revents = 0,
|
||||
});
|
||||
|
||||
if (abstract) {
|
||||
ServerSocketFD = fd;
|
||||
} else {
|
||||
ServerFSSocketFD = fd;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -422,6 +441,7 @@ void CloseConnections() {
|
||||
|
||||
// Close the server socket so no more connections can be started
|
||||
close(ServerSocketFD);
|
||||
close(ServerFSSocketFD);
|
||||
}
|
||||
|
||||
void WaitForRequests() {
|
||||
@ -441,12 +461,12 @@ void WaitForRequests() {
|
||||
bool Erase {};
|
||||
|
||||
if (Event.revents != 0) {
|
||||
if (Event.fd == ServerSocketFD) {
|
||||
if (Event.fd == ServerSocketFD || Event.fd == ServerFSSocketFD) {
|
||||
if (Event.revents & POLLIN) {
|
||||
// If it is the listen socket then we have a new connection
|
||||
struct sockaddr_storage Addr {};
|
||||
socklen_t AddrSize {};
|
||||
int NewFD = accept(ServerSocketFD, reinterpret_cast<struct sockaddr*>(&Addr), &AddrSize);
|
||||
int NewFD = accept(Event.fd, reinterpret_cast<struct sockaddr*>(&Addr), &AddrSize);
|
||||
|
||||
// Add the new client to the temporary array
|
||||
NewPollFDs.emplace_back(pollfd {
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
namespace ProcessPipe {
|
||||
bool InitializeServerPipe();
|
||||
bool InitializeServerSocket();
|
||||
bool InitializeServerSocket(bool abstract);
|
||||
void WaitForRequests();
|
||||
void SetConfiguration(bool Foreground, uint32_t PersistentTimeout);
|
||||
void Shutdown();
|
||||
|
@ -79,6 +79,9 @@ Use `FHU::Filesystem::GetFilename` instead.
|
||||
#### std::filesystem::copy_file
|
||||
Use `FHU::Filesystem::CopyFile` instead.
|
||||
|
||||
#### std::filesystem::temp_directory_path
|
||||
See `GetTempFolder()` in `FEXServerClient.cpp` (split/move to `FHU::Filesystem` if needed by other users).
|
||||
|
||||
### `std::fstream`
|
||||
This API always allocates memory and should be avoided.
|
||||
Use a combination of open and fextl::string APIs instead of fstream.
|
||||
|
Loading…
x
Reference in New Issue
Block a user