Server config load and graceful client exit

This commit is contained in:
2026-01-26 01:25:16 +01:00
parent 904efbd9b9
commit fe703b6ddd
7 changed files with 252 additions and 26 deletions
+48 -6
View File
@@ -2,12 +2,21 @@
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <unistd.h>
#include "commands.h"
#include "signal.h"
// Wanted a graceful exit so need to keep this in global state
static int client_queue_id_global = -1;
static int server_queue_id_global = -1;
static char client_id_global[COMMAND_LENGTH];
static pid_t heartbeat_pid = -1;
static pid_t input_pid = -1;
// Make a macro for this cause I'm not typing sizeof twice every time
#define send(queue_id, msgbuf_ptr) msgsnd(queue_id, msgbuf_ptr, sizeof(*(msgbuf_ptr)) - sizeof(long), 0)
@@ -30,6 +39,27 @@ static void cleanup_queue(int qid) {
}
}
void cleanup_and_exit(int sig) {
printf("\nLogging out... ");
if (server_queue_id_global != -1) {
msgbuf_t logout = {.mtype = Logout, .sender = ""};
strncpy(logout.sender, client_id_global, COMMAND_LENGTH - 1);
msgsnd(server_queue_id_global, &logout, sizeof(logout) - sizeof(long), 0);
}
// Burn the orphanage
if (heartbeat_pid > 0)
kill(heartbeat_pid, SIGTERM);
if (input_pid > 0)
kill(input_pid, SIGTERM);
cleanup_queue(client_queue_id_global);
printf("Bye!\n");
exit(0);
}
static void input_loop(int server_queue_id, const char *client_id) {
while (1) {
// Minimum length plus extra space fore command name and seperators
@@ -88,9 +118,8 @@ static void input_loop(int server_queue_id, const char *client_id) {
}
} else if (strncmp(buffer, "/mute ", 6) == 0) {
// handle mute
} else if (strcmp(buffer, "/quit") == 0) {
// TODO: Would be nice to have a way to gracefully logout and not just
// depend on heartbeats, maybe
} else if (strcmp(buffer, "/quit") == 0 || strcmp(buffer, "/exit") == 0 || strcmp(buffer, "/q") == 0) {
return;
} else if (strncmp(buffer, "/inbox", 8) == 0) {
msgbuf_t msg = {.mtype = Inbox, .sender = ""};
strncpy(msg.sender, client_id, COMMAND_LENGTH - 1);
@@ -163,16 +192,29 @@ int main(int argc, char *argv[]) {
printf("Login accepted. Welcome, %s!\n", resp.command);
if (fork() == 0) {
strncpy(client_id_global, client_id, COMMAND_LENGTH - 1);
client_queue_id_global = client_queue_id;
server_queue_id_global = server_queue_id;
heartbeat_pid = fork();
if (heartbeat_pid == 0) {
heartbeat_loop(server_queue_id, client_id);
return 0;
}
if (fork() == 0) {
input_pid = fork();
if (input_pid == 0) {
input_loop(server_queue_id, client_id);
// The /quit command just returns from the input loop
kill(getppid(), SIGTERM);
return 0;
}
// Setup them below the forks to avoid multiple triggers
signal(SIGINT, cleanup_and_exit);
signal(SIGTERM, cleanup_and_exit);
while (1) {
msgbuf_t incoming;
ssize_t got = msgrcv(client_queue_id, &incoming, sizeof(incoming) - sizeof(long), 0, 0);
@@ -194,7 +236,7 @@ int main(int argc, char *argv[]) {
// Check the command field for the list type
if (strncmp(incoming.command, "active", COMMAND_LENGTH) == 0) {
printf("Active clients:\n%s\n", incoming.message);
} else if (strncmp(incoming.command, "group", COMMAND_LENGTH) == 0) {
} else if (strncmp(incoming.command, "groups", COMMAND_LENGTH) == 0) {
printf("All group members:\n%s\n", incoming.message);
} else {
printf("All clients:\n%s\n", incoming.message);