hyprctl: fix buffer overflowing writes to the socket
This commit is contained in:
parent
f7114016c6
commit
362ea7b0f3
2 changed files with 41 additions and 19 deletions
|
|
@ -228,23 +228,23 @@ int request(std::string_view arg, int minArgs = 0, bool needRoll = false) {
|
||||||
constexpr size_t BUFFER_SIZE = 8192;
|
constexpr size_t BUFFER_SIZE = 8192;
|
||||||
char buffer[BUFFER_SIZE] = {0};
|
char buffer[BUFFER_SIZE] = {0};
|
||||||
|
|
||||||
sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE);
|
// read all data until server closes the connection
|
||||||
|
// this handles partial writes on the server side under high load
|
||||||
if (sizeWritten < 0) {
|
while (true) {
|
||||||
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) {
|
|
||||||
sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE);
|
sizeWritten = read(SERVERSOCKET, buffer, BUFFER_SIZE);
|
||||||
|
|
||||||
if (sizeWritten < 0) {
|
if (sizeWritten < 0) {
|
||||||
|
if (errno == EWOULDBLOCK)
|
||||||
|
log("Hyprland IPC didn't respond in time\n");
|
||||||
log("Couldn't read (6)");
|
log("Couldn't read (6)");
|
||||||
return 6;
|
return 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sizeWritten == 0) {
|
||||||
|
// server closed connection, we're done
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
reply += std::string(buffer, sizeWritten);
|
reply += std::string(buffer, sizeWritten);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2210,16 +2210,38 @@ std::string CHyprCtl::makeDynamicCall(const std::string& input) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool successWrite(int fd, const std::string& data, bool needLog = true) {
|
static bool successWrite(int fd, const std::string& data, bool needLog = true) {
|
||||||
if (write(fd, data.c_str(), data.length()) > 0)
|
size_t totalWritten = 0;
|
||||||
return true;
|
size_t remaining = data.length();
|
||||||
|
size_t waitsDone = 0;
|
||||||
|
constexpr const size_t MAX_WAITS = 20; // 2000µs = 2ms
|
||||||
|
|
||||||
if (errno == EAGAIN)
|
while (totalWritten < data.length()) {
|
||||||
return true;
|
ssize_t written = write(fd, data.c_str() + totalWritten, remaining);
|
||||||
|
|
||||||
if (needLog)
|
if (waitsDone > MAX_WAITS) {
|
||||||
Log::logger->log(Log::ERR, "Couldn't write to socket. Error: " + std::string(strerror(errno)));
|
Log::logger->log(Log::ERR, "Couldn't write to socket. Buffer was full and the client couldn't read in time.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
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 true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void runWritingDebugLogThread(const int conn) {
|
static void runWritingDebugLogThread(const int conn) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue