diff options
| author | Vaxry <vaxry@vaxry.net> | 2026-02-28 15:06:10 +0000 |
|---|---|---|
| committer | Vaxry <vaxry@vaxry.net> | 2026-02-28 15:06:10 +0000 |
| commit | 362ea7b0f3bb858996198a8d760acbd3397dea22 (patch) | |
| tree | d55c8f2ab7d368c3379a95b042e1fb0a81f5c961 | |
| parent | f7114016c6dbf524763038642521892b473f4d36 (diff) | |
hyprctl: fix buffer overflowing writes to the socket
| -rw-r--r-- | hyprctl/src/main.cpp | 24 | ||||
| -rw-r--r-- | src/debug/HyprCtl.cpp | 36 |
2 files changed, 41 insertions, 19 deletions
diff --git a/hyprctl/src/main.cpp b/hyprctl/src/main.cpp index 7146c635..0a33f3ed 100644 --- a/hyprctl/src/main.cpp +++ b/hyprctl/src/main.cpp @@ -228,23 +228,23 @@ int request(std::string_view arg, int minArgs = 0, bool needRoll = false) { constexpr size_t BUFFER_SIZE = 8192; char buffer[BUFFER_SIZE] = {0}; - sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE); - - if (sizeWritten < 0) { - if (errno == EWOULDBLOCK) - log("Hyprland IPC didn't respond in time\n"); - log("Couldn't read (6)"); - return 6; - } - - reply += std::string(buffer, sizeWritten); - - while (sizeWritten == BUFFER_SIZE) { + // 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); + if (sizeWritten < 0) { + if (errno == EWOULDBLOCK) + log("Hyprland IPC didn't respond in time\n"); log("Couldn't read (6)"); return 6; } + + if (sizeWritten == 0) { + // server closed connection, we're done + break; + } + reply += std::string(buffer, sizeWritten); } diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index f3a9402d..1fcb3dd1 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -2210,16 +2210,38 @@ std::string CHyprCtl::makeDynamicCall(const std::string& input) { } static bool successWrite(int fd, const std::string& data, bool needLog = true) { - if (write(fd, data.c_str(), data.length()) > 0) - return true; + size_t totalWritten = 0; + size_t remaining = data.length(); + size_t waitsDone = 0; + constexpr const size_t MAX_WAITS = 20; // 2000µs = 2ms - if (errno == EAGAIN) - return true; + while (totalWritten < data.length()) { + ssize_t written = write(fd, data.c_str() + totalWritten, remaining); - if (needLog) - Log::logger->log(Log::ERR, "Couldn't write to socket. Error: " + std::string(strerror(errno))); + if (waitsDone > MAX_WAITS) { + Log::logger->log(Log::ERR, "Couldn't write to socket. Buffer was full and the client couldn't read in time."); + return false; + } + + if (written < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + // socket buffer full, wait a bit and retry + std::this_thread::sleep_for(std::chrono::microseconds(100)); + waitsDone++; + continue; + } + if (needLog) + Log::logger->log(Log::ERR, "Couldn't write to socket. Error: {}", strerror(errno)); + return false; + } + + waitsDone = 0; + + totalWritten += written; + remaining -= written; + } - return false; + return true; } static void runWritingDebugLogThread(const int conn) { |
