mirror of
https://dev.lirent.ru/Vatrog/vm-automation-signaling.git
synced 2026-06-25 20:36:36 +03:00
9bde398b6c
- core: runtime attach/detach of a per-endpoint adapter trio (runtime-safe add_adapter + vmsig_core_detach_endpoint, deferred reap) - roster: VMSIG_EV_ROSTER + CAP_ROSTER, retained per-endpoint and replayed to late subscribers - discovery: inotify trigger dir, vmid/endpoint slot allocator, host probe; vmsigd daemon with config + per-uid admission - input driver and vgpu perception built in-tree; vgpu perception as a separate library - memctx: own the supplied ro_fd (closed at detach) - deb packaging: install rules, systemd unit, tmpfiles, default config
114 lines
2.6 KiB
C
114 lines
2.6 KiB
C
/* qmp.c — AF_UNIX QMP client: connect + capability handshake, line-based recv
|
|
* with a poll timeout, and synchronous command execution. */
|
|
|
|
#include "qmp.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#include <poll.h>
|
|
|
|
#define QMP_TIMEOUT_MS 5000
|
|
#define QMP_BUF_SIZE 4096
|
|
|
|
struct qmp_conn {
|
|
int fd;
|
|
};
|
|
|
|
static int recv_line(int fd, char* buf, size_t cap) {
|
|
size_t n = 0;
|
|
while (n + 1 < cap) {
|
|
struct pollfd pfd = { .fd = fd, .events = POLLIN };
|
|
if (poll(&pfd, 1, QMP_TIMEOUT_MS) <= 0) return -1;
|
|
char c;
|
|
if (read(fd, &c, 1) != 1) return -1;
|
|
buf[n++] = c;
|
|
if (c == '\n') break;
|
|
}
|
|
buf[n] = '\0';
|
|
return (int)n;
|
|
}
|
|
|
|
static int send_all(int fd, const char* s, size_t len) {
|
|
while (len > 0) {
|
|
ssize_t w = write(fd, s, len);
|
|
if (w <= 0) return -1;
|
|
s += w;
|
|
len -= (size_t)w;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
qmp_conn* qmp_connect(const char* sock_path) {
|
|
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
if (fd < 0) return NULL;
|
|
|
|
struct sockaddr_un addr;
|
|
memset(&addr, 0, sizeof addr);
|
|
addr.sun_family = AF_UNIX;
|
|
strncpy(addr.sun_path, sock_path, sizeof addr.sun_path - 1);
|
|
|
|
if (connect(fd, (struct sockaddr*)&addr, sizeof addr) < 0) {
|
|
close(fd);
|
|
return NULL;
|
|
}
|
|
|
|
char buf[QMP_BUF_SIZE];
|
|
if (recv_line(fd, buf, sizeof buf) < 0) {
|
|
close(fd);
|
|
return NULL;
|
|
}
|
|
|
|
const char* cap_cmd = "{\"execute\":\"qmp_capabilities\"}\r\n";
|
|
if (send_all(fd, cap_cmd, strlen(cap_cmd)) < 0) {
|
|
close(fd);
|
|
return NULL;
|
|
}
|
|
|
|
if (recv_line(fd, buf, sizeof buf) < 0) {
|
|
close(fd);
|
|
return NULL;
|
|
}
|
|
|
|
qmp_conn* c = malloc(sizeof *c);
|
|
if (!c) {
|
|
close(fd);
|
|
return NULL;
|
|
}
|
|
c->fd = fd;
|
|
return c;
|
|
}
|
|
|
|
void qmp_disconnect(qmp_conn* c) {
|
|
if (!c) return;
|
|
close(c->fd);
|
|
free(c);
|
|
}
|
|
|
|
int qmp_exec(qmp_conn* c, const char* cmd, char* resp, size_t cap) {
|
|
size_t cmdlen = strlen(cmd);
|
|
if (send_all(c->fd, cmd, cmdlen) < 0) return -1;
|
|
if (send_all(c->fd, "\r\n", 2) < 0) return -1;
|
|
|
|
char line[QMP_BUF_SIZE];
|
|
for (;;) {
|
|
if (recv_line(c->fd, line, sizeof line) < 0) return -1;
|
|
if (strstr(line, "\"return\"")) {
|
|
if (resp && cap > 0) {
|
|
strncpy(resp, line, cap - 1);
|
|
resp[cap - 1] = '\0';
|
|
}
|
|
return 0;
|
|
}
|
|
if (strstr(line, "\"error\"")) {
|
|
if (resp && cap > 0) {
|
|
strncpy(resp, line, cap - 1);
|
|
resp[cap - 1] = '\0';
|
|
}
|
|
return -1;
|
|
}
|
|
}
|
|
}
|