feat(MP/daemon): create ipc server to handle socketpair
This commit is contained in:
161
src/06-mini-project/daemon/ipc/ipc_server.c
Normal file
161
src/06-mini-project/daemon/ipc/ipc_server.c
Normal file
@@ -0,0 +1,161 @@
|
||||
// ipc_socket.c
|
||||
#include "ipc_server.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
/* Global variables for the IPC module */
|
||||
static int server_fd = -1;
|
||||
static pthread_t ipc_thread;
|
||||
static struct ipc_callbacks_t current_cbs = {0};
|
||||
static int is_running = 0;
|
||||
|
||||
/**
|
||||
* process_message() - Route the received IPC message to the correct callback.
|
||||
*/
|
||||
static void process_message(ipc_msg_t *msg) {
|
||||
switch (msg->command) {
|
||||
case CMD_SET_MODE:
|
||||
if (current_cbs.on_set_mode) {
|
||||
current_cbs.on_set_mode(msg->value);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_SET_FREQ:
|
||||
if (current_cbs.on_set_frequency) {
|
||||
current_cbs.on_set_frequency(msg->value);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_INC_FREQ:
|
||||
if (current_cbs.on_inc_frequency) {
|
||||
current_cbs.on_inc_frequency();
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_DEC_FREQ:
|
||||
if (current_cbs.on_dec_frequency) {
|
||||
current_cbs.on_dec_frequency();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("[IPC] Received unknown command: %d\n", msg->command);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ipc_thread_func() - The main loop of the background IPC thread.
|
||||
*/
|
||||
static void *ipc_thread_func(void *arg) {
|
||||
ipc_msg_t msg;
|
||||
ssize_t bytes_read;
|
||||
|
||||
printf("[IPC] Thread started. Listening on %s\n", SOCKET_PATH);
|
||||
|
||||
while (is_running) {
|
||||
/* Block until a message arrives or the socket is closed */
|
||||
bytes_read = recvfrom(server_fd, &msg, sizeof(msg), 0, NULL, NULL);
|
||||
|
||||
if (bytes_read == sizeof(ipc_msg_t)) {
|
||||
process_message(&msg);
|
||||
}
|
||||
else if (bytes_read <= 0 && is_running == 0) {
|
||||
/* Normal exit condition when shutdown() is called */
|
||||
break;
|
||||
}
|
||||
else if (bytes_read > 0) {
|
||||
printf("[IPC] Received malformed message (size %zd)\n", bytes_read);
|
||||
}
|
||||
else {
|
||||
perror("[IPC] Error receiving message");
|
||||
}
|
||||
}
|
||||
|
||||
printf("[IPC] Thread stopped.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* --- Public functions --- */
|
||||
|
||||
int start_ipc_server(struct ipc_callbacks_t *cbs) {
|
||||
struct sockaddr_un server_addr;
|
||||
|
||||
if (is_running) {
|
||||
printf("[IPC] Server is already running.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Save the provided callbacks */
|
||||
if (cbs) {
|
||||
current_cbs = *cbs;
|
||||
}
|
||||
|
||||
/* Create local socket */
|
||||
server_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if (server_fd < 0) {
|
||||
perror("[IPC] Failed to create socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Bind socket to the file path */
|
||||
memset(&server_addr, 0, sizeof(server_addr));
|
||||
server_addr.sun_family = AF_UNIX;
|
||||
strncpy(server_addr.sun_path, SOCKET_PATH, sizeof(server_addr.sun_path) - 1);
|
||||
|
||||
unlink(SOCKET_PATH); /* Clean up existing orphaned socket file */
|
||||
|
||||
if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
|
||||
perror("[IPC] Failed to bind socket");
|
||||
close(server_fd);
|
||||
server_fd = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Start the background thread */
|
||||
is_running = 1;
|
||||
if (pthread_create(&ipc_thread, NULL, ipc_thread_func, NULL) != 0) {
|
||||
perror("[IPC] Failed to create IPC thread");
|
||||
is_running = 0;
|
||||
close(server_fd);
|
||||
unlink(SOCKET_PATH);
|
||||
server_fd = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stop_ipc_server(void) {
|
||||
if (!is_running) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("[IPC] Stopping server...\n");
|
||||
|
||||
/* Signal thread to stop */
|
||||
is_running = 0;
|
||||
|
||||
/* Unblock the recvfrom() by shutting down the socket */
|
||||
if (server_fd != -1) {
|
||||
shutdown(server_fd, SHUT_RDWR);
|
||||
close(server_fd);
|
||||
server_fd = -1;
|
||||
}
|
||||
|
||||
/* Wait for thread to exit */
|
||||
pthread_join(ipc_thread, NULL);
|
||||
|
||||
/* Remove the socket file */
|
||||
unlink(SOCKET_PATH);
|
||||
|
||||
/* Clear callbacks */
|
||||
memset(¤t_cbs, 0, sizeof(struct ipc_callbacks_t));
|
||||
|
||||
return 0;
|
||||
}
|
||||
32
src/06-mini-project/daemon/ipc/ipc_server.h
Normal file
32
src/06-mini-project/daemon/ipc/ipc_server.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef IPC_SERVER_H
|
||||
#define IPC_SERVER_H
|
||||
|
||||
#include "../../common/common_ipc.h"
|
||||
|
||||
/*
|
||||
* Structure holding the callbacks for IPC commands.
|
||||
* Each function pointer will be called when the corresponding command is received.
|
||||
*/
|
||||
struct ipc_callbacks_t {
|
||||
void (*on_set_mode)(int mode);
|
||||
void (*on_set_frequency)(int freq);
|
||||
void (*on_inc_frequency)(void);
|
||||
void (*on_dec_frequency)(void);
|
||||
} ;
|
||||
|
||||
/**
|
||||
* start_ipc_server() - Start the IPC background thread.
|
||||
* @cbs: Pointer to the structure containing the callback functions.
|
||||
*
|
||||
* Return: 0 on success, or a negative value on error.
|
||||
*/
|
||||
int start_ipc_server(struct ipc_callbacks_t *cbs);
|
||||
|
||||
/**
|
||||
* stop_ipc_server() - Stop the IPC thread and clean up the socket.
|
||||
*
|
||||
* Return: 0 on success.
|
||||
*/
|
||||
int stop_ipc_server(void);
|
||||
|
||||
#endif //IPC_SERVER_H
|
||||
Reference in New Issue
Block a user