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>
|
|
|
|
|
|
|
|
static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'};
|
|
|
|
static const size_t ipc_header_size = sizeof(ipc_magic)+8;
|
|
|
|
|
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-13 19:23:43 +00:00
|
|
|
struct ipc_response response;
|
|
|
|
char data[ipc_header_size];
|
2018-08-16 12:29:41 +00:00
|
|
|
auto data32 = reinterpret_cast<uint32_t *>(data + sizeof(ipc_magic));
|
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) {
|
|
|
|
ssize_t received = recv(socketfd, data + total, ipc_header_size - total, 0);
|
|
|
|
if (received <= 0) {
|
|
|
|
throw std::runtime_error("Unable to receive IPC response");
|
|
|
|
}
|
|
|
|
total += received;
|
|
|
|
}
|
2018-08-08 21:54:58 +00:00
|
|
|
|
2018-08-13 19:23:43 +00:00
|
|
|
total = 0;
|
|
|
|
response.size = data32[0];
|
|
|
|
response.type = data32[1];
|
2018-08-08 21:54:58 +00:00
|
|
|
char payload[response.size + 1];
|
|
|
|
|
2018-08-13 19:23:43 +00:00
|
|
|
while (total < response.size) {
|
|
|
|
ssize_t received = recv(socketfd, payload + total, response.size - total, 0);
|
|
|
|
if (received < 0) {
|
|
|
|
throw std::runtime_error("Unable to receive IPC response");
|
|
|
|
}
|
|
|
|
total += received;
|
|
|
|
}
|
|
|
|
payload[response.size] = '\0';
|
|
|
|
response.payload = std::string(payload);
|
|
|
|
return response;
|
2018-08-08 21:54:58 +00:00
|
|
|
}
|
|
|
|
|
2018-08-16 12:29:41 +00:00
|
|
|
std::string ipcSingleCommand(int socketfd, uint32_t type, const char *payload, uint32_t *len) {
|
2018-08-13 19:23:43 +00:00
|
|
|
char data[ipc_header_size];
|
2018-08-16 12:29:41 +00:00
|
|
|
auto data32 = reinterpret_cast<uint32_t *>(data + sizeof(ipc_magic));
|
2018-08-13 19:23:43 +00:00
|
|
|
memcpy(data, ipc_magic, sizeof(ipc_magic));
|
|
|
|
data32[0] = *len;
|
|
|
|
data32[1] = type;
|
2018-08-08 21:54:58 +00:00
|
|
|
|
2018-08-16 12:29:41 +00:00
|
|
|
if (send(socketfd, 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
|
|
|
}
|
|
|
|
if (send(socketfd, payload, *len, 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
|
|
|
}
|
|
|
|
struct ipc_response resp = ipcRecvResponse(socketfd);
|
2018-08-13 19:23:43 +00:00
|
|
|
*len = resp.size;
|
|
|
|
return resp.payload;
|
2018-08-08 21:54:58 +00:00
|
|
|
}
|