Merge pull request #4159 from asahilina/fexserver-two-sockets

FEXServer: Listen on both abstract & named sockets
This commit is contained in:
Ryan Houdek 2024-11-19 09:28:48 -08:00 committed by GitHub
commit d5c96555f1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 98 additions and 27 deletions

View File

@ -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) {

View File

@ -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);

View File

@ -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;

View File

@ -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 {

View File

@ -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();

View File

@ -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.