From f2eafdf1057ffbd513e1238ddcb5262237825aff Mon Sep 17 00:00:00 2001 From: NotPppp1116 <264624490+NotPppp1116@users.noreply.github.com> Date: Tue, 14 Jul 2026 16:32:05 +0100 Subject: [PATCH] hyprctl: handle partial IPC transfers (#15408) Co-authored-by: Pppp1116 --- hyprctl/src/main.cpp | 46 ++++++++++++++++++++--------- hyprpm/src/core/HyprlandSocket.cpp | 47 ++++++++++++++++++++---------- 2 files changed, 64 insertions(+), 29 deletions(-) diff --git a/hyprctl/src/main.cpp b/hyprctl/src/main.cpp index d32af74f2..ae2dfe6c0 100644 --- a/hyprctl/src/main.cpp +++ b/hyprctl/src/main.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -53,6 +54,24 @@ void log(const std::string_view str) { std::println("{}", str); } +static bool writeAll(const int fd, std::string_view data) { + size_t totalWritten = 0; + while (totalWritten < data.size()) { + const auto written = write(fd, data.data() + totalWritten, data.size() - totalWritten); + if (written > 0) { + totalWritten += sc(written); + continue; + } + + if (written < 0 && errno == EINTR) + continue; + + return false; + } + + return true; +} + static int getUID() { const auto UID = getuid(); const auto PWUID = getpwuid(UID); @@ -217,9 +236,7 @@ int request(std::string_view arg, int minArgs = 0, bool needRoll = false) { return 4; } - auto sizeWritten = write(SERVERSOCKET, arg.data(), arg.size()); - - if (sizeWritten < 0) { + if (!writeAll(SERVERSOCKET, arg)) { log("Couldn't write (5)"); return 5; } @@ -234,21 +251,23 @@ int request(std::string_view arg, int minArgs = 0, bool needRoll = false) { // read all data until server closes the connection // this handles partial writes on the server side under high load while (true) { - sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE); + const auto sizeRead = read(SERVERSOCKET, buffer, BUFFER_SIZE); - if (sizeWritten < 0) { + if (sizeRead < 0) { + if (errno == EINTR) + continue; if (errno == EWOULDBLOCK) log("Hyprland IPC didn't respond in time\n"); log("Couldn't read (6)"); return 6; } - if (sizeWritten == 0) { + if (sizeRead == 0) { // server closed connection, we're done break; } - reply += std::string(buffer, sizeWritten); + reply.append(buffer, sc(sizeRead)); } close(SERVERSOCKET); @@ -289,25 +308,26 @@ int requestIPC(std::string_view filename, std::string_view arg) { arg = arg.substr(arg.find_first_of('/') + 1); // strip flags arg = arg.substr(arg.find_first_of(' ') + 1); // strip "hyprpaper" - auto sizeWritten = write(SERVERSOCKET, arg.data(), arg.size()); - - if (sizeWritten < 0) { + if (!writeAll(SERVERSOCKET, arg)) { log("Couldn't write (4)"); return 4; } constexpr size_t BUFFER_SIZE = 8192; char buffer[BUFFER_SIZE] = {0}; - sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE); + ssize_t sizeRead = 0; + do { + sizeRead = read(SERVERSOCKET, buffer, BUFFER_SIZE); + } while (sizeRead < 0 && errno == EINTR); - if (sizeWritten < 0) { + if (sizeRead < 0) { log("Couldn't read (5)"); return 5; } close(SERVERSOCKET); - log(std::string(buffer)); + log(std::string(buffer, sc(sizeRead))); return 0; } diff --git a/hyprpm/src/core/HyprlandSocket.cpp b/hyprpm/src/core/HyprlandSocket.cpp index 47142e549..2609dae29 100644 --- a/hyprpm/src/core/HyprlandSocket.cpp +++ b/hyprpm/src/core/HyprlandSocket.cpp @@ -1,4 +1,5 @@ #include "HyprlandSocket.hpp" +#include #include #include #include "../helpers/StringUtils.hpp" @@ -10,6 +11,24 @@ using namespace Hyprutils::Memory; +static bool writeAll(const int fd, std::string_view data) { + size_t totalWritten = 0; + while (totalWritten < data.size()) { + const auto written = write(fd, data.data() + totalWritten, data.size() - totalWritten); + if (written > 0) { + totalWritten += sc(written); + continue; + } + + if (written < 0 && errno == EINTR) + continue; + + return false; + } + + return true; +} + static int getUID() { const auto UID = getuid(); const auto PWUID = getpwuid(UID); @@ -54,9 +73,7 @@ std::string NHyprlandSocket::send(const std::string& cmd) { return ""; } - auto sizeWritten = write(SERVERSOCKET, cmd.c_str(), cmd.length()); - - if (sizeWritten < 0) { + if (!writeAll(SERVERSOCKET, cmd)) { std::println("{}", failureString("Couldn't write (5)")); return ""; } @@ -65,22 +82,20 @@ std::string NHyprlandSocket::send(const std::string& cmd) { constexpr size_t BUFFER_SIZE = 8192; char buffer[BUFFER_SIZE] = {0}; - sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE); + while (true) { + const auto sizeRead = read(SERVERSOCKET, buffer, BUFFER_SIZE); + if (sizeRead < 0) { + if (errno == EINTR) + continue; - if (sizeWritten < 0) { - std::println("{}", failureString("Couldn't read (6)")); - return ""; - } - - reply += std::string(buffer, sizeWritten); - - while (sizeWritten == BUFFER_SIZE) { - sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE); - if (sizeWritten < 0) { - std::println("{}", failureString("Couldn't read (7)")); + std::println("{}", failureString("Couldn't read (6)")); return ""; } - reply += std::string(buffer, sizeWritten); + + if (sizeRead == 0) + break; + + reply.append(buffer, sc(sizeRead)); } close(SERVERSOCKET);