summaryrefslogtreecommitdiff
path: root/src/xwayland/Server.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/xwayland/Server.cpp')
-rw-r--r--src/xwayland/Server.cpp175
1 files changed, 64 insertions, 111 deletions
diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp
index d5dce333..99bcdf62 100644
--- a/src/xwayland/Server.cpp
+++ b/src/xwayland/Server.cpp
@@ -24,70 +24,41 @@
#include "../defines.hpp"
#include "../Compositor.hpp"
#include "../managers/CursorManager.hpp"
+using namespace Hyprutils::OS;
// Constants
-constexpr int SOCKET_DIR_PERMISSIONS = 0755;
-constexpr int SOCKET_BACKLOG = 1;
-constexpr int MAX_SOCKET_RETRIES = 32;
-constexpr int LOCK_FILE_MODE = 0444;
-
-static bool setCloseOnExec(int fd, bool cloexec) {
- int flags = fcntl(fd, F_GETFD);
- if (flags == -1) {
- Debug::log(ERR, "fcntl failed");
- return false;
- }
-
- if (cloexec)
- flags = flags | FD_CLOEXEC;
- else
- flags = flags & ~FD_CLOEXEC;
-
- if (fcntl(fd, F_SETFD, flags) == -1) {
- Debug::log(ERR, "fcntl failed");
- return false;
- }
-
- return true;
-}
-
-static void cleanUpSocket(int fd, const char* path) {
- close(fd);
- if (path[0])
- unlink(path);
-}
-
-static inline void closeSocketSafely(int& fd) {
- if (fd >= 0)
- close(fd);
-}
-
-static int createSocket(struct sockaddr_un* addr, size_t path_size) {
- socklen_t size = offsetof(struct sockaddr_un, sun_path) + path_size + 1;
- int fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (fd < 0) {
+constexpr int SOCKET_DIR_PERMISSIONS = 0755;
+constexpr int SOCKET_BACKLOG = 1;
+constexpr int MAX_SOCKET_RETRIES = 32;
+constexpr int LOCK_FILE_MODE = 0444;
+
+static CFileDescriptor createSocket(struct sockaddr_un* addr, size_t path_size) {
+ socklen_t size = offsetof(struct sockaddr_un, sun_path) + path_size + 1;
+ CFileDescriptor fd{socket(AF_UNIX, SOCK_STREAM, 0)};
+ if (!fd.isValid()) {
Debug::log(ERR, "Failed to create socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1);
- return -1;
+ return {};
}
- if (!setCloseOnExec(fd, true)) {
- close(fd);
- return -1;
+ if (!fd.setFlags(fd.getFlags() | FD_CLOEXEC)) {
+ return {};
}
if (addr->sun_path[0])
unlink(addr->sun_path);
- if (bind(fd, (struct sockaddr*)addr, size) < 0) {
+ if (bind(fd.get(), (struct sockaddr*)addr, size) < 0) {
Debug::log(ERR, "Failed to bind socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1);
- cleanUpSocket(fd, addr->sun_path);
- return -1;
+ if (addr->sun_path[0])
+ unlink(addr->sun_path);
+ return {};
}
- if (listen(fd, SOCKET_BACKLOG) < 0) {
+ if (listen(fd.get(), SOCKET_BACKLOG) < 0) {
Debug::log(ERR, "Failed to listen to socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1);
- cleanUpSocket(fd, addr->sun_path);
- return -1;
+ if (addr->sun_path[0])
+ unlink(addr->sun_path);
+ return {};
}
return fd;
@@ -141,7 +112,7 @@ static std::string getSocketPath(int display, bool isLinux) {
return std::format("/tmp/.X11-unix/X{}_", display);
}
-static bool openSockets(std::array<int, 2>& sockets, int display) {
+static bool openSockets(std::array<CFileDescriptor, 2>& sockets, int display) {
if (!ensureSocketDirExists())
return false;
@@ -151,17 +122,16 @@ static bool openSockets(std::array<int, 2>& sockets, int display) {
path = getSocketPath(display, false);
strncpy(addr.sun_path, path.c_str(), path.length() + 1);
- sockets[0] = createSocket(&addr, path.length());
- if (sockets[0] < 0)
+ sockets[0] = CFileDescriptor{createSocket(&addr, path.length())};
+ if (!sockets[0].isValid())
return false;
path = getSocketPath(display, true);
strncpy(addr.sun_path, path.c_str(), path.length() + 1);
- sockets[1] = createSocket(&addr, path.length());
- if (sockets[1] < 0) {
- close(sockets[0]);
- sockets[0] = -1;
+ sockets[1] = CFileDescriptor{createSocket(&addr, path.length())};
+ if (!sockets[1].isValid()) {
+ sockets[0].reset();
return false;
}
@@ -174,7 +144,8 @@ static void startServer(void* data) {
}
static int xwaylandReady(int fd, uint32_t mask, void* data) {
- return g_pXWayland->pServer->ready(fd, mask);
+ CFileDescriptor xwlFd{fd};
+ return g_pXWayland->pServer->ready(std::move(xwlFd), mask);
}
static bool safeRemove(const std::string& path) {
@@ -186,38 +157,34 @@ static bool safeRemove(const std::string& path) {
bool CXWaylandServer::tryOpenSockets() {
for (size_t i = 0; i <= MAX_SOCKET_RETRIES; ++i) {
- std::string lockPath = std::format("/tmp/.X{}-lock", i);
+ std::string lockPath = std::format("/tmp/.X{}-lock", i);
- int fd = open(lockPath.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, LOCK_FILE_MODE);
- if (fd >= 0) {
+ CFileDescriptor fd{open(lockPath.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, LOCK_FILE_MODE)};
+ if (fd.isValid()) {
// we managed to open the lock
if (!openSockets(xFDs, i)) {
safeRemove(lockPath);
- close(fd);
continue;
}
const std::string pidStr = std::to_string(getpid());
- if (write(fd, pidStr.c_str(), pidStr.length()) != (long)pidStr.length()) {
+ if (write(fd.get(), pidStr.c_str(), pidStr.length()) != (long)pidStr.length()) {
safeRemove(lockPath);
- close(fd);
continue;
}
- close(fd);
display = i;
displayName = std::format(":{}", display);
break;
}
- fd = open(lockPath.c_str(), O_RDONLY | O_CLOEXEC);
+ fd = CFileDescriptor{open(lockPath.c_str(), O_RDONLY | O_CLOEXEC)};
- if (fd < 0)
+ if (!fd.isValid())
continue;
char pidstr[12] = {0};
- read(fd, pidstr, sizeof(pidstr) - 1);
- close(fd);
+ read(fd.get(), pidstr, sizeof(pidstr) - 1);
int32_t pid = 0;
try {
@@ -249,9 +216,6 @@ CXWaylandServer::~CXWaylandServer() {
if (display < 0)
return;
- closeSocketSafely(xFDs[0]);
- closeSocketSafely(xFDs[1]);
-
std::string lockPath = std::format("/tmp/.X{}-lock", display);
safeRemove(lockPath);
@@ -277,21 +241,11 @@ void CXWaylandServer::die() {
if (pipeSource)
wl_event_source_remove(pipeSource);
- if (pipeFd >= 0)
- close(pipeFd);
-
- closeSocketSafely(waylandFDs[0]);
- closeSocketSafely(waylandFDs[1]);
- closeSocketSafely(xwmFDs[0]);
- closeSocketSafely(xwmFDs[1]);
-
// possible crash. Better to leak a bit.
//if (xwaylandClient)
// wl_client_destroy(xwaylandClient);
xwaylandClient = nullptr;
- waylandFDs = {-1, -1};
- xwmFDs = {-1, -1};
}
bool CXWaylandServer::create() {
@@ -307,15 +261,17 @@ bool CXWaylandServer::create() {
return true;
}
-void CXWaylandServer::runXWayland(int notifyFD) {
- if (!setCloseOnExec(xFDs[0], false) || !setCloseOnExec(xFDs[1], false) || !setCloseOnExec(waylandFDs[1], false) || !setCloseOnExec(xwmFDs[1], false)) {
+void CXWaylandServer::runXWayland(CFileDescriptor& notifyFD) {
+ if (!xFDs[0].setFlags(xFDs[0].getFlags() & ~FD_CLOEXEC) || !xFDs[1].setFlags(xFDs[1].getFlags() & ~FD_CLOEXEC) ||
+ !waylandFDs[1].setFlags(waylandFDs[1].getFlags() & ~FD_CLOEXEC) || !xwmFDs[1].setFlags(xwmFDs[1].getFlags() & ~FD_CLOEXEC)) {
Debug::log(ERR, "Failed to unset cloexec on fds");
_exit(EXIT_FAILURE);
}
- auto cmd = std::format("Xwayland {} -rootless -core -listenfd {} -listenfd {} -displayfd {} -wm {}", displayName, xFDs[0], xFDs[1], notifyFD, xwmFDs[1]);
+ auto cmd =
+ std::format("Xwayland {} -rootless -core -listenfd {} -listenfd {} -displayfd {} -wm {}", displayName, xFDs[0].get(), xFDs[1].get(), notifyFD.get(), xwmFDs[1].get());
- auto waylandSocket = std::format("{}", waylandFDs[1]);
+ auto waylandSocket = std::format("{}", waylandFDs[1].get());
setenv("WAYLAND_SOCKET", waylandSocket.c_str(), true);
Debug::log(LOG, "Starting XWayland with \"{}\", bon voyage!", cmd);
@@ -327,40 +283,46 @@ void CXWaylandServer::runXWayland(int notifyFD) {
}
bool CXWaylandServer::start() {
- idleSource = nullptr;
-
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, waylandFDs.data()) != 0) {
+ idleSource = nullptr;
+ int wlPair[2] = {-1, -1};
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, wlPair) != 0) {
Debug::log(ERR, "socketpair failed (1)");
die();
return false;
}
+ waylandFDs[0] = CFileDescriptor{wlPair[0]};
+ waylandFDs[1] = CFileDescriptor{wlPair[1]};
- if (!setCloseOnExec(waylandFDs[0], true) || !setCloseOnExec(waylandFDs[1], true)) {
+ if (!waylandFDs[0].setFlags(waylandFDs[0].getFlags() | FD_CLOEXEC) || !waylandFDs[1].setFlags(waylandFDs[1].getFlags() | FD_CLOEXEC)) {
Debug::log(ERR, "set_cloexec failed (1)");
die();
return false;
}
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, xwmFDs.data()) != 0) {
+ int xwmPair[2] = {-1, -1};
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, xwmPair) != 0) {
Debug::log(ERR, "socketpair failed (2)");
die();
return false;
}
- if (!setCloseOnExec(xwmFDs[0], true) || !setCloseOnExec(xwmFDs[1], true)) {
+ xwmFDs[0] = CFileDescriptor{xwmPair[0]};
+ xwmFDs[1] = CFileDescriptor{xwmPair[1]};
+
+ if (!xwmFDs[0].setFlags(xwmFDs[0].getFlags() | FD_CLOEXEC) || !xwmFDs[1].setFlags(xwmFDs[1].getFlags() | FD_CLOEXEC)) {
Debug::log(ERR, "set_cloexec failed (2)");
die();
return false;
}
- xwaylandClient = wl_client_create(g_pCompositor->m_sWLDisplay, waylandFDs[0]);
+ xwaylandClient = wl_client_create(g_pCompositor->m_sWLDisplay, waylandFDs[0].get());
if (!xwaylandClient) {
Debug::log(ERR, "wl_client_create failed");
die();
return false;
}
- waylandFDs[0] = -1;
+ waylandFDs[0].take(); // does this leak?
int notify[2] = {-1, -1};
if (pipe(notify) < 0) {
@@ -369,22 +331,20 @@ bool CXWaylandServer::start() {
return false;
}
- if (!setCloseOnExec(notify[0], true)) {
+ CFileDescriptor notifyFds[2] = {CFileDescriptor{notify[0]}, CFileDescriptor{notify[1]}};
+
+ if (!notifyFds[0].setFlags(notifyFds[0].getFlags() | FD_CLOEXEC)) {
Debug::log(ERR, "set_cloexec failed (3)");
- close(notify[0]);
- close(notify[1]);
die();
return false;
}
- pipeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, notify[0], WL_EVENT_READABLE, ::xwaylandReady, nullptr);
- pipeFd = notify[0];
+ pipeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, notifyFds[0].get(), WL_EVENT_READABLE, ::xwaylandReady, nullptr);
+ pipeFd = std::move(notifyFds[0]);
serverPID = fork();
if (serverPID < 0) {
Debug::log(ERR, "fork failed");
- close(notify[0]);
- close(notify[1]);
die();
return false;
} else if (serverPID == 0) {
@@ -393,25 +353,19 @@ bool CXWaylandServer::start() {
Debug::log(ERR, "second fork failed");
_exit(1);
} else if (pid == 0)
- runXWayland(notify[1]);
+ runXWayland(notifyFds[1]);
_exit(0);
}
- close(notify[1]);
- close(waylandFDs[1]);
- closeSocketSafely(xwmFDs[1]);
- waylandFDs[1] = -1;
- xwmFDs[1] = -1;
-
return true;
}
-int CXWaylandServer::ready(int fd, uint32_t mask) {
+int CXWaylandServer::ready(CFileDescriptor fd, uint32_t mask) {
if (mask & WL_EVENT_READABLE) {
// xwayland writes twice
char buf[64];
- ssize_t n = read(fd, buf, sizeof(buf));
+ ssize_t n = read(fd.get(), buf, sizeof(buf));
if (n < 0 && errno != EINTR) {
Debug::log(ERR, "Xwayland: read from displayFd failed");
mask = 0;
@@ -436,7 +390,6 @@ int CXWaylandServer::ready(int fd, uint32_t mask) {
Debug::log(LOG, "XWayland is ready");
- close(fd);
wl_event_source_remove(pipeSource);
pipeSource = nullptr;