Files
fm95/io/ipc.c
T
2026-05-03 17:12:22 +02:00

96 lines
2.5 KiB
C

#include "ipc.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
static int make_server_socket(const char *path)
{
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0) { perror("ipc: socket"); return -1; }
unlink(path);
struct sockaddr_un addr = { .sun_family = AF_UNIX };
strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("ipc: bind"); close(fd); return -1;
}
if (listen(fd, IPC_BACKLOG) < 0) {
perror("ipc: listen"); close(fd); return -1;
}
return fd;
}
static void *listener_thread(void *arg) {
ipc_ctx_t *ctx = (ipc_ctx_t *)arg;
while (ctx->running) {
struct sockaddr_un peer;
socklen_t peer_len = sizeof(peer);
int client_fd = accept(ctx->server_fd,
(struct sockaddr *)&peer, &peer_len);
if (client_fd < 0) {
if (errno == EINVAL || errno == EBADF) break; /* shutting down */
if (errno == EINTR) continue;
perror("ipc: accept");
continue;
}
printf("[ipc] new client fd=%d\n", client_fd);
int *fd_ptr = malloc(sizeof(int));
if (!fd_ptr) { close(client_fd); continue; }
*fd_ptr = client_fd;
pthread_t tid;
if (pthread_create(&tid, NULL, ctx->handler, fd_ptr) != 0) {
perror("ipc: pthread_create");
free(fd_ptr);
close(client_fd);
continue;
}
pthread_detach(tid);
}
printf("[ipc] listener exiting\n");
return NULL;
}
int create_ipc(ipc_ctx_t *ctx, ipc_client_fn handler, const char* socket_path) {
ctx->handler = handler;
ctx->running = 1;
ctx->server_fd = make_server_socket(socket_path);
ctx->socket_path = strdup(socket_path);
if (ctx->server_fd < 0) return -1;
pthread_t tid;
if (pthread_create(&tid, NULL, listener_thread, ctx) != 0) {
perror("ipc: pthread_create");
close(ctx->server_fd);
unlink(socket_path);
return -1;
}
/* store tid so destroy_ipc can join it */
ctx->_tid = tid;
printf("[ipc] listening on %s\n", socket_path);
return 0;
}
void destroy_ipc(ipc_ctx_t *ctx) {
ctx->running = 0;
shutdown(ctx->server_fd, SHUT_RDWR); /* unblock accept() */
close(ctx->server_fd);
unlink(ctx->socket_path);
pthread_join(ctx->_tid, NULL);
printf("[ipc] shut down\n");
}