mirror of
https://dev.lirent.ru/Vatrog/vm-automation-signaling.git
synced 2026-06-26 04:36:37 +03:00
vmsig: management daemon, runtime endpoint lifecycle, roster, discovery, in-tree drivers, packaging
- 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
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user