Waybar/src/modules/sway/ipc/client.cpp

98 lines
2.8 KiB
C++
Raw Normal View History

2018-08-08 21:54:58 +00:00
#define _POSIX_C_SOURCE 200809L
2018-08-16 12:29:41 +00:00
#include "modules/sway/ipc/client.hpp"
#include <cstdio>
2018-08-08 21:54:58 +00:00
#include <string>
#include <sys/socket.h>
#include <sys/un.h>
2018-08-18 14:01:56 +00:00
static const std::string ipc_magic("i3-ipc");
static const size_t ipc_header_size = ipc_magic.size() + 8;
2018-08-08 21:54:58 +00:00
2018-08-16 12:29:41 +00:00
std::string getSocketPath() {
2018-08-08 21:54:58 +00:00
const char *env = getenv("SWAYSOCK");
2018-08-16 12:29:41 +00:00
if (env != nullptr) {
return std::string(env);
}
2018-08-13 19:23:43 +00:00
std::string str;
2018-08-08 21:54:58 +00:00
{
2018-08-13 19:23:43 +00:00
std::string str_buf;
FILE* in;
char buf[512] = { 0 };
2018-08-16 12:29:41 +00:00
if ((in = popen("sway --get-socketpath 2>/dev/null", "r")) == nullptr) {
2018-08-13 19:23:43 +00:00
throw std::runtime_error("Failed to get socket path");
}
while (fgets(buf, sizeof(buf), in) != nullptr) {
str_buf.append(buf, sizeof(buf));
}
pclose(in);
str = str_buf;
}
if (str.back() == '\n') {
str.pop_back();
}
return str;
2018-08-08 21:54:58 +00:00
}
2018-08-16 12:29:41 +00:00
int ipcOpenSocket(const std::string &socketPath) {
2018-08-17 12:24:00 +00:00
struct sockaddr_un addr = {0};
2018-08-13 19:23:43 +00:00
int socketfd;
if ((socketfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
throw std::runtime_error("Unable to open Unix socket");
}
addr.sun_family = AF_UNIX;
2018-08-16 12:29:41 +00:00
strncpy(addr.sun_path, socketPath.c_str(), sizeof(addr.sun_path) - 1);
2018-08-13 19:23:43 +00:00
addr.sun_path[sizeof(addr.sun_path) - 1] = 0;
int l = sizeof(struct sockaddr_un);
2018-08-16 12:29:41 +00:00
if (connect(socketfd, reinterpret_cast<struct sockaddr *>(&addr), l) == -1) {
throw std::runtime_error("Unable to connect to " + socketPath);
2018-08-13 19:23:43 +00:00
}
return socketfd;
2018-08-08 21:54:58 +00:00
}
2018-08-16 12:29:41 +00:00
struct ipc_response ipcRecvResponse(int socketfd) {
2018-08-18 14:01:56 +00:00
std::string header;
header.reserve(ipc_header_size);
auto data32 = reinterpret_cast<uint32_t *>(header.data() + ipc_magic.size());
2018-08-13 19:23:43 +00:00
size_t total = 0;
2018-08-08 21:54:58 +00:00
2018-08-13 19:23:43 +00:00
while (total < ipc_header_size) {
2018-08-18 14:01:56 +00:00
ssize_t res =
::recv(socketfd, header.data() + total, ipc_header_size - total, 0);
if (res <= 0) {
2018-08-13 19:23:43 +00:00
throw std::runtime_error("Unable to receive IPC response");
}
2018-08-18 14:01:56 +00:00
total += res;
2018-08-13 19:23:43 +00:00
}
2018-08-08 21:54:58 +00:00
2018-08-13 19:23:43 +00:00
total = 0;
2018-08-18 14:01:56 +00:00
std::string payload;
payload.reserve(data32[0]);
while (total < data32[0]) {
ssize_t res =
::recv(socketfd, payload.data() + total, data32[0] - total, 0);
if (res < 0) {
2018-08-13 19:23:43 +00:00
throw std::runtime_error("Unable to receive IPC response");
}
2018-08-18 14:01:56 +00:00
total += res;
2018-08-13 19:23:43 +00:00
}
2018-08-18 14:01:56 +00:00
return { data32[0], data32[1], &payload.front() };
2018-08-08 21:54:58 +00:00
}
2018-08-18 14:01:56 +00:00
struct ipc_response ipcSingleCommand(int socketfd, uint32_t type,
const std::string& payload) {
std::string header;
header.reserve(ipc_header_size);
auto data32 = reinterpret_cast<uint32_t *>(header.data() + ipc_magic.size());
memcpy(header.data(), ipc_magic.c_str(), ipc_magic.size());
data32[0] = payload.size();
2018-08-13 19:23:43 +00:00
data32[1] = type;
2018-08-08 21:54:58 +00:00
2018-08-18 14:01:56 +00:00
if (send(socketfd, header.data(), ipc_header_size, 0) == -1) {
2018-08-13 19:23:43 +00:00
throw std::runtime_error("Unable to send IPC header");
2018-08-16 12:29:41 +00:00
}
2018-08-18 14:01:56 +00:00
if (send(socketfd, payload.c_str(), payload.size(), 0) == -1) {
2018-08-13 19:23:43 +00:00
throw std::runtime_error("Unable to send IPC payload");
2018-08-16 12:29:41 +00:00
}
2018-08-18 14:01:56 +00:00
return ipcRecvResponse(socketfd);
2018-08-08 21:54:58 +00:00
}