mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-26 16:00:53 +01:00
Merge pull request #1802 from Sonicadvance1/fexserver_wait
FEXServer: Adds -w option for waiting on current FEXServer
This commit is contained in:
6 files changed
+195
-107
No files matched your search
@@ -21,6 +21,71 @@
|
||||
#include <thread>
|
||||
|
||||
namespace FEXServerClient {
|
||||
int RequestPIDFDPacket(int ServerSocket, PacketType Type) {
|
||||
FEXServerRequestPacket Req {
|
||||
.Header {
|
||||
.Type = Type,
|
||||
},
|
||||
};
|
||||
|
||||
int Result = write(ServerSocket, &Req, sizeof(Req.BasicRequest));
|
||||
if (Result != -1) {
|
||||
// Wait for success response with SCM_RIGHTS
|
||||
|
||||
FEXServerResultPacket Res{};
|
||||
struct iovec iov {
|
||||
.iov_base = &Res,
|
||||
.iov_len = sizeof(Res),
|
||||
};
|
||||
|
||||
struct msghdr msg {
|
||||
.msg_name = nullptr,
|
||||
.msg_namelen = 0,
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
|
||||
// Setup the ancillary buffer. This is where we will be getting pipe FDs
|
||||
// We only need 4 bytes for the FD
|
||||
constexpr size_t CMSG_SIZE = CMSG_SPACE(sizeof(int));
|
||||
union AncillaryBuffer {
|
||||
struct cmsghdr Header;
|
||||
uint8_t Buffer[CMSG_SIZE];
|
||||
};
|
||||
AncillaryBuffer AncBuf{};
|
||||
|
||||
// Now link to our ancilllary buffer
|
||||
msg.msg_control = AncBuf.Buffer;
|
||||
msg.msg_controllen = CMSG_SIZE;
|
||||
|
||||
ssize_t DataResult = recvmsg(ServerSocket, &msg, 0);
|
||||
if (DataResult > 0) {
|
||||
// Now that we have the data, we can extract the FD from the ancillary buffer
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
|
||||
|
||||
// Do some error checking
|
||||
if (cmsg == nullptr ||
|
||||
cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
|
||||
cmsg->cmsg_level != SOL_SOCKET ||
|
||||
cmsg->cmsg_type != SCM_RIGHTS) {
|
||||
// Couldn't get a socket
|
||||
}
|
||||
else {
|
||||
// Check for Success.
|
||||
// If type error was returned then the FEXServer doesn't have a log to pipe in to
|
||||
if (Res.Header.Type == PacketType::TYPE_SUCCESS) {
|
||||
// Now that we know the cmsg is sane, read the FD
|
||||
int NewFD{};
|
||||
memcpy(&NewFD, CMSG_DATA(cmsg), sizeof(NewFD));
|
||||
return NewFD;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ServerFD {-1};
|
||||
|
||||
std::string GetServerLockFolder() {
|
||||
@@ -163,68 +228,7 @@ namespace FEXServerClient {
|
||||
}
|
||||
|
||||
int RequestLogFD(int ServerSocket) {
|
||||
FEXServerRequestPacket Req {
|
||||
.Header {
|
||||
.Type = PacketType::TYPE_GET_LOG_FD,
|
||||
},
|
||||
};
|
||||
|
||||
int Result = write(ServerSocket, &Req, sizeof(Req.BasicRequest));
|
||||
if (Result != -1) {
|
||||
// Wait for success response with SCM_RIGHTS
|
||||
|
||||
FEXServerResultPacket Res{};
|
||||
struct iovec iov {
|
||||
.iov_base = &Res,
|
||||
.iov_len = sizeof(Res),
|
||||
};
|
||||
|
||||
struct msghdr msg {
|
||||
.msg_name = nullptr,
|
||||
.msg_namelen = 0,
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
|
||||
// Setup the ancillary buffer. This is where we will be getting pipe FDs
|
||||
// We only need 4 bytes for the FD
|
||||
constexpr size_t CMSG_SIZE = CMSG_SPACE(sizeof(int));
|
||||
union AncillaryBuffer {
|
||||
struct cmsghdr Header;
|
||||
uint8_t Buffer[CMSG_SIZE];
|
||||
};
|
||||
AncillaryBuffer AncBuf{};
|
||||
|
||||
// Now link to our ancilllary buffer
|
||||
msg.msg_control = AncBuf.Buffer;
|
||||
msg.msg_controllen = CMSG_SIZE;
|
||||
|
||||
ssize_t DataResult = recvmsg(ServerSocket, &msg, 0);
|
||||
if (DataResult > 0) {
|
||||
// Now that we have the data, we can extract the FD from the ancillary buffer
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
|
||||
|
||||
// Do some error checking
|
||||
if (cmsg == nullptr ||
|
||||
cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
|
||||
cmsg->cmsg_level != SOL_SOCKET ||
|
||||
cmsg->cmsg_type != SCM_RIGHTS) {
|
||||
// Couldn't get a socket
|
||||
}
|
||||
else {
|
||||
// Check for Success.
|
||||
// If type error was returned then the FEXServer doesn't have a log to pipe in to
|
||||
if (Res.Header.Type == PacketType::TYPE_SUCCESS) {
|
||||
// Now that we know the cmsg is sane, read the FD
|
||||
int NewFD{};
|
||||
memcpy(&NewFD, CMSG_DATA(cmsg), sizeof(NewFD));
|
||||
return NewFD;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
return RequestPIDFDPacket(ServerSocket, PacketType::TYPE_GET_LOG_FD);
|
||||
}
|
||||
|
||||
std::string RequestRootFSPath(int ServerSocket) {
|
||||
@@ -252,6 +256,10 @@ namespace FEXServerClient {
|
||||
return {};
|
||||
}
|
||||
|
||||
int RequestPIDFD(int ServerSocket) {
|
||||
return RequestPIDFDPacket(ServerSocket, PacketType::TYPE_GET_PID_FD);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace FEXServerClient {
|
||||
TYPE_KILL,
|
||||
TYPE_GET_LOG_FD,
|
||||
TYPE_GET_ROOTFS_PATH,
|
||||
TYPE_GET_PID_FD,
|
||||
|
||||
// Result only
|
||||
TYPE_SUCCESS,
|
||||
@@ -88,6 +89,16 @@ namespace FEXServerClient {
|
||||
int RequestLogFD(int ServerSocket);
|
||||
|
||||
std::string RequestRootFSPath(int ServerSocket);
|
||||
|
||||
/**
|
||||
* @brief Request a FEXServer to give us a pidfd of the process
|
||||
*
|
||||
* @param ServerSocket - Socket to the server
|
||||
*
|
||||
* @return FD for pidfd
|
||||
*/
|
||||
int RequestPIDFD(int ServerSocket);
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,6 +31,11 @@ namespace FEXServer::Config {
|
||||
.metavar("n")
|
||||
.help("Make FEXServer persistent. Optional number of seconds");
|
||||
|
||||
Parser.add_option("-w", "--wait")
|
||||
.action("store_true")
|
||||
.set_default(false)
|
||||
.help("Wait for the FEXServer to shutdown");
|
||||
|
||||
Parser.add_option("-v")
|
||||
.action("version")
|
||||
.help("Version string");
|
||||
@@ -39,6 +44,10 @@ namespace FEXServer::Config {
|
||||
|
||||
FEXOptions.Kill = Options.get("kill");
|
||||
FEXOptions.Foreground = Options.get("foreground");
|
||||
FEXOptions.Wait = Options.get("wait");
|
||||
if (FEXOptions.Wait) {
|
||||
FEXOptions.Foreground = true;
|
||||
}
|
||||
FEXOptions.PersistentTimeout = Options.get("persistent");
|
||||
|
||||
return FEXOptions;
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace FEXServer::Config {
|
||||
struct FEXServerOptions {
|
||||
bool Kill;
|
||||
bool Foreground;
|
||||
bool Wait;
|
||||
uint32_t PersistentTimeout;
|
||||
};
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/wait.h>
|
||||
#include <thread>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -145,6 +146,29 @@ int main(int argc, char **argv, char **const envp) {
|
||||
// Reload the meta layer
|
||||
FEXCore::Config::ReloadMetaLayer();
|
||||
|
||||
if (Options.Wait) {
|
||||
int ServerPipe = FEXServerClient::ConnectToServer();
|
||||
if (ServerPipe != -1) {
|
||||
int FEXServerPID = FEXServerClient::RequestPIDFD(ServerPipe);
|
||||
close(ServerPipe);
|
||||
if (FEXServerPID != -1) {
|
||||
LogMan::Msg::IFmt("[FEXServer] Waiting for FEXServer to close");
|
||||
// We can't use waitid (P_PIDFD) here because the active FEXServer isn't a child of this process.
|
||||
// Use poll instead which will return once the pidfd closes.
|
||||
pollfd PollFD;
|
||||
PollFD.fd = FEXServerPID;
|
||||
PollFD.events = POLLIN | POLLOUT | POLLRDHUP | POLLERR | POLLHUP | POLLNVAL;
|
||||
|
||||
// Wait for a result on the pipe that isn't EINTR
|
||||
while (poll(&PollFD, 1, -1) == -1 && errno == EINTR);
|
||||
|
||||
LogMan::Msg::IFmt("[FEXServer] FEXServer shutdown");
|
||||
}
|
||||
PipeScanner::ClosePipes();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (Options.Kill) {
|
||||
int ServerPipe = FEXServerClient::ConnectToServer();
|
||||
|
||||
|
||||
@@ -215,6 +215,72 @@ namespace ProcessPipe {
|
||||
return true;
|
||||
}
|
||||
|
||||
void SendEmptyErrorPacket(int Socket) {
|
||||
FEXServerClient::FEXServerResultPacket Res {
|
||||
.Header {
|
||||
.Type = FEXServerClient::PacketType::TYPE_ERROR,
|
||||
},
|
||||
};
|
||||
|
||||
struct iovec iov {
|
||||
.iov_base = &Res,
|
||||
.iov_len = sizeof(Res),
|
||||
};
|
||||
|
||||
struct msghdr msg {
|
||||
.msg_name = nullptr,
|
||||
.msg_namelen = 0,
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
|
||||
sendmsg(Socket, &msg, 0);
|
||||
}
|
||||
|
||||
void SendFDSuccessPacket(int Socket, int FD) {
|
||||
FEXServerClient::FEXServerResultPacket Res {
|
||||
.Header {
|
||||
.Type = FEXServerClient::PacketType::TYPE_SUCCESS,
|
||||
},
|
||||
};
|
||||
|
||||
struct iovec iov {
|
||||
.iov_base = &Res,
|
||||
.iov_len = sizeof(Res),
|
||||
};
|
||||
|
||||
struct msghdr msg {
|
||||
.msg_name = nullptr,
|
||||
.msg_namelen = 0,
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
|
||||
// Setup the ancillary buffer. This is where we will be getting pipe FDs
|
||||
// We only need 4 bytes for the FD
|
||||
constexpr size_t CMSG_SIZE = CMSG_SPACE(sizeof(int));
|
||||
union AncillaryBuffer {
|
||||
struct cmsghdr Header;
|
||||
uint8_t Buffer[CMSG_SIZE];
|
||||
};
|
||||
AncillaryBuffer AncBuf{};
|
||||
|
||||
// Now link to our ancilllary buffer
|
||||
msg.msg_control = AncBuf.Buffer;
|
||||
msg.msg_controllen = CMSG_SIZE;
|
||||
|
||||
// Now we need to setup the ancillary buffer data. We are only sending an FD
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
|
||||
// We are giving the daemon the write side of the pipe
|
||||
memcpy(CMSG_DATA(cmsg), &FD, sizeof(int));
|
||||
|
||||
sendmsg(Socket, &msg, 0);
|
||||
}
|
||||
|
||||
void HandleSocketData(int Socket) {
|
||||
std::vector<uint8_t> Data(1500);
|
||||
size_t CurrentRead{};
|
||||
@@ -266,54 +332,14 @@ namespace ProcessPipe {
|
||||
CurrentOffset += sizeof(FEXServerClient::FEXServerRequestPacket::BasicRequest);
|
||||
break;
|
||||
case FEXServerClient::PacketType::TYPE_GET_LOG_FD: {
|
||||
FEXServerClient::FEXServerResultPacket Res {
|
||||
.Header {
|
||||
.Type = FEXServerClient::PacketType::TYPE_SUCCESS,
|
||||
},
|
||||
};
|
||||
|
||||
struct iovec iov {
|
||||
.iov_base = &Res,
|
||||
.iov_len = sizeof(Res),
|
||||
};
|
||||
|
||||
struct msghdr msg {
|
||||
.msg_name = nullptr,
|
||||
.msg_namelen = 0,
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
|
||||
if (Logger::LogThreadRunning()) {
|
||||
// Setup the ancillary buffer. This is where we will be getting pipe FDs
|
||||
// We only need 4 bytes for the FD
|
||||
constexpr size_t CMSG_SIZE = CMSG_SPACE(sizeof(int));
|
||||
union AncillaryBuffer {
|
||||
struct cmsghdr Header;
|
||||
uint8_t Buffer[CMSG_SIZE];
|
||||
};
|
||||
AncillaryBuffer AncBuf{};
|
||||
|
||||
// Now link to our ancilllary buffer
|
||||
msg.msg_control = AncBuf.Buffer;
|
||||
msg.msg_controllen = CMSG_SIZE;
|
||||
|
||||
// Now we need to setup the ancillary buffer data. We are only sending an FD
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
|
||||
int fds[2]{};
|
||||
pipe2(fds, 0);
|
||||
// 0 = Read
|
||||
// 1 = Write
|
||||
Logger::AppendLogFD(fds[0]);
|
||||
|
||||
// We are giving the daemon the write side of the pipe
|
||||
memcpy(CMSG_DATA(cmsg), &fds[1], sizeof(int));
|
||||
|
||||
sendmsg(Socket, &msg, 0);
|
||||
SendFDSuccessPacket(Socket, fds[1]);
|
||||
|
||||
// Close the write side now, doesn't matter to us
|
||||
close(fds[1]);
|
||||
@@ -324,14 +350,12 @@ namespace ProcessPipe {
|
||||
}
|
||||
else {
|
||||
// Log thread isn't running. Let FEXInterpreter know it can't have one.
|
||||
Res.Header.Type = FEXServerClient::PacketType::TYPE_ERROR;
|
||||
|
||||
sendmsg(Socket, &msg, 0);
|
||||
SendEmptyErrorPacket(Socket);
|
||||
}
|
||||
|
||||
CurrentOffset += sizeof(FEXServerClient::FEXServerRequestPacket::Header);
|
||||
break;
|
||||
}
|
||||
}
|
||||
case FEXServerClient::PacketType::TYPE_GET_ROOTFS_PATH: {
|
||||
std::string MountFolder = SquashFS::GetMountFolder();
|
||||
|
||||
@@ -372,6 +396,17 @@ namespace ProcessPipe {
|
||||
|
||||
CurrentOffset += sizeof(FEXServerClient::FEXServerRequestPacket::BasicRequest);
|
||||
break;
|
||||
}
|
||||
case FEXServerClient::PacketType::TYPE_GET_PID_FD: {
|
||||
int FD = ::syscall(SYS_pidfd_open, ::getpid(), 0);
|
||||
|
||||
SendFDSuccessPacket(Socket, FD);
|
||||
|
||||
// Close the FD now since we've sent it
|
||||
close(FD);
|
||||
|
||||
CurrentOffset += sizeof(FEXServerClient::FEXServerRequestPacket::Header);
|
||||
break;
|
||||
}
|
||||
// Invalid
|
||||
case FEXServerClient::PacketType::TYPE_ERROR:
|
||||
|
||||
Reference in new issue
Block a user