Hot reloading + state saving
This commit is contained in:
parent
3b68f2dfda
commit
a4e73470e2
6
Makefile
6
Makefile
|
@ -3,13 +3,13 @@ CC=gcc
|
||||||
CCARGS=-Isrc/include -Wall -pedantic
|
CCARGS=-Isrc/include -Wall -pedantic
|
||||||
|
|
||||||
MODULES= \
|
MODULES= \
|
||||||
modules/clock.dim \
|
modules/clock.dim \
|
||||||
modules/battery.dim\
|
modules/battery.dim
|
||||||
|
|
||||||
|
|
||||||
all: $(BIN) $(MODULES) compile_commands.json
|
all: $(BIN) $(MODULES) compile_commands.json
|
||||||
|
|
||||||
$(BIN): src/main.c src/plug.c
|
$(BIN): src/main.c src/plug.c src/socket.c src/util.c
|
||||||
$(CC) -o $@ $^ $(CCARGS) -lX11 -ldl
|
$(CC) -o $@ $^ $(CCARGS) -lX11 -ldl
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,28 +5,31 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
typedef void (*plug_init_f) (void);
|
typedef void* (*plug_init_f) (void);
|
||||||
typedef void (*plug_reload_f) (void);
|
typedef void* (*plug_pre_reload_f) (void);
|
||||||
typedef void (*plug_poll_f) (char*, size_t);
|
typedef void (*plug_post_reload_f) (void*);
|
||||||
typedef void (*plug_free_f) (void);
|
typedef void (*plug_poll_f) (char*, size_t);
|
||||||
|
typedef void (*plug_free_f) (void);
|
||||||
|
|
||||||
typedef struct plug_t {
|
typedef struct plug_t {
|
||||||
char* name;
|
char* name;
|
||||||
char* version;
|
char* version;
|
||||||
bool is_ready;
|
|
||||||
} plug_t;
|
} plug_t;
|
||||||
|
|
||||||
typedef struct plug_int_t {
|
typedef struct plug_int_t {
|
||||||
|
char* path;
|
||||||
plug_init_f f_init;
|
plug_init_f f_init;
|
||||||
plug_reload_f f_reload;
|
plug_pre_reload_f f_pre_reload;
|
||||||
|
plug_post_reload_f f_post_reload;
|
||||||
plug_poll_f f_poll;
|
plug_poll_f f_poll;
|
||||||
plug_free_f f_free;
|
plug_free_f f_free;
|
||||||
plug_t* s_plug_info;
|
plug_t* state;
|
||||||
} plug_int_t;
|
} plug_int_t;
|
||||||
|
|
||||||
void setup_plugins(char* plugin_path);
|
void setup_plugins(char* plugin_path);
|
||||||
char* poll_plugins(char* sep);
|
char* poll_plugins(char* sep);
|
||||||
void free_plugins(void);
|
void free_plugins(void);
|
||||||
|
void reload_plugins(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
19
src/include/socket.h
Normal file
19
src/include/socket.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
#ifndef _H_SOCKET
|
||||||
|
#define _H_SOCKET
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
|
||||||
|
typedef enum sock_msg_t{
|
||||||
|
SM_NONE = 0,
|
||||||
|
SM_RELOAD = 1,
|
||||||
|
} sock_msg_t;
|
||||||
|
|
||||||
|
int socket_init(void);
|
||||||
|
sock_msg_t socket_poll(void);
|
||||||
|
void socket_close(void);
|
||||||
|
void socket_send(char*);
|
||||||
|
|
||||||
|
#endif
|
9
src/include/util.h
Normal file
9
src/include/util.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
#ifndef _H_UTIL
|
||||||
|
#define _H_UTIL
|
||||||
|
|
||||||
|
void to_lowercase(char* str);
|
||||||
|
void to_uppercase(char* str);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
57
src/main.c
57
src/main.c
|
@ -2,9 +2,39 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "plug.h"
|
#include <signal.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "plug.h"
|
||||||
|
#include "socket.h"
|
||||||
|
|
||||||
|
void interrupt_handler(int);
|
||||||
|
void print_help(void);
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
signal(SIGINT, interrupt_handler);
|
||||||
|
|
||||||
|
if (argc > 1) {
|
||||||
|
if (strcmp(argv[1], "send") == 0) {
|
||||||
|
if (argc == 3) {
|
||||||
|
socket_send(argv[2]);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
print_help();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print_help();
|
||||||
|
printf("ERROR: Unknown subcommand\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (socket_init() != 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int main(void) {
|
|
||||||
setup_plugins("./modules");
|
setup_plugins("./modules");
|
||||||
char* buffer;
|
char* buffer;
|
||||||
|
|
||||||
|
@ -12,6 +42,15 @@ int main(void) {
|
||||||
Window window = DefaultRootWindow(display);
|
Window window = DefaultRootWindow(display);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
sock_msg_t msg = socket_poll();
|
||||||
|
|
||||||
|
switch (msg) {
|
||||||
|
case SM_RELOAD: {
|
||||||
|
reload_plugins();
|
||||||
|
} break;
|
||||||
|
case SM_NONE: break;
|
||||||
|
}
|
||||||
|
|
||||||
buffer = poll_plugins("|");
|
buffer = poll_plugins("|");
|
||||||
XStoreName(display, window, buffer);
|
XStoreName(display, window, buffer);
|
||||||
XFlush(display);
|
XFlush(display);
|
||||||
|
@ -24,3 +63,17 @@ int main(void) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void interrupt_handler(int sig) {
|
||||||
|
(void) sig;
|
||||||
|
printf("\nCaught SIGINT, exiting\n");
|
||||||
|
free_plugins();
|
||||||
|
socket_close();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_help(void) {
|
||||||
|
printf("Usage: dim [command]\n");
|
||||||
|
printf("Commands:\n");
|
||||||
|
printf(" send [MESSAGE] - Sends a message, available messages: [reload]\n");
|
||||||
|
}
|
||||||
|
|
|
@ -1,44 +1,61 @@
|
||||||
#include "plug.h"
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
plug_t PLUG = {0};
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
typedef struct plug_t {
|
||||||
|
char* name;
|
||||||
|
char* version;
|
||||||
|
FILE* fp;
|
||||||
|
} plug_t;
|
||||||
|
|
||||||
|
|
||||||
|
static plug_t* p = {0};
|
||||||
|
|
||||||
static FILE* fp = NULL;
|
|
||||||
|
|
||||||
char* batt_files[] = {
|
char* batt_files[] = {
|
||||||
"/sys/class/power_supply/BAT0/capacity",
|
"/sys/class/power_supply/BAT0/capacity",
|
||||||
"/sys/class/power_supply/BAT1/capacity"
|
"/sys/class/power_supply/BAT1/capacity"
|
||||||
};
|
};
|
||||||
|
|
||||||
void plug_init(void) {
|
void* plug_init(void) {
|
||||||
PLUG.name = "Battery";
|
p = malloc(sizeof(plug_t));
|
||||||
PLUG.version = "0.0.1";
|
assert(p);
|
||||||
|
p->name = "Battery";
|
||||||
|
p->version = "0.0.1";
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof(batt_files)/sizeof(batt_files[0]); i++) {
|
for (size_t i = 0; i < sizeof(batt_files)/sizeof(batt_files[0]); i++) {
|
||||||
if (access(batt_files[i], F_OK) == 0) {
|
if (access(batt_files[i], F_OK) == 0) {
|
||||||
fp = fopen(batt_files[i], "r");
|
p->fp = fopen(batt_files[i], "r");
|
||||||
if (fp) {
|
if (p->fp) {
|
||||||
printf("Opened %s\n", batt_files[i]);
|
printf("Opened %s\n", batt_files[i]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fp) {
|
if (!p->fp) {
|
||||||
printf("MODULE: ERROR: Unable to find battery\n");
|
printf("MODULE: ERROR: Unable to find battery\n");
|
||||||
return;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
PLUG.is_ready = true;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void plug_reload(void) { /* Unused */ }
|
void* plug_pre_reload(void) {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void plug_post_reload(void* pp) {
|
||||||
|
p = pp;
|
||||||
|
}
|
||||||
|
|
||||||
void plug_poll(char* buf, size_t len) {
|
void plug_poll(char* buf, size_t len) {
|
||||||
if (!fp) return;
|
if (!p->fp) return;
|
||||||
int perc = 0;
|
int perc = 0;
|
||||||
fseek(fp, 0, SEEK_SET);
|
fseek(p->fp, 0, SEEK_SET);
|
||||||
fscanf(fp, "%d", &perc);
|
fscanf(p->fp, "%d", &perc);
|
||||||
snprintf(buf, len, "Batt: %d%%", perc);
|
snprintf(buf, len, "Batt: %d%%", perc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,33 @@
|
||||||
#include "plug.h"
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
plug_t PLUG = {0};
|
typedef struct plug_t {
|
||||||
|
char* name;
|
||||||
|
char* version;
|
||||||
|
int i;
|
||||||
|
} plug_t;
|
||||||
|
|
||||||
void plug_init(void) {
|
|
||||||
PLUG.name = "time";
|
plug_t* p = {0};
|
||||||
PLUG.version = "0.0.1";
|
|
||||||
PLUG.is_ready = true;
|
void* plug_init(void) {
|
||||||
|
p = malloc(sizeof(plug_t));
|
||||||
|
p->name = "time";
|
||||||
|
p->version = "0.0.1";
|
||||||
|
p->i = 0;
|
||||||
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void plug_reload(void) { /* Unused */ }
|
void* plug_pre_reload(void) {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void plug_post_reload(void* pp) {
|
||||||
|
p = pp;
|
||||||
|
p->i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
void plug_poll(char* buf, size_t len) {
|
void plug_poll(char* buf, size_t len) {
|
||||||
time_t rawtime;
|
time_t rawtime;
|
||||||
|
|
35
src/modules/example.c
Normal file
35
src/modules/example.c
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
typedef struct plug_t {
|
||||||
|
char* name; // Always keep these on top
|
||||||
|
char* version;
|
||||||
|
} plug_t;
|
||||||
|
|
||||||
|
|
||||||
|
static plug_t* p = {0};
|
||||||
|
|
||||||
|
|
||||||
|
void* plug_init(void) {
|
||||||
|
p = malloc(sizeof(plug_t));
|
||||||
|
assert(p);
|
||||||
|
p->name = "example";
|
||||||
|
p->version = "0.0.1";
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* plug_pre_reload(void) {
|
||||||
|
return p; // send state to dim
|
||||||
|
}
|
||||||
|
|
||||||
|
void plug_post_reload(void* pp) {
|
||||||
|
p = pp; // get back state
|
||||||
|
}
|
||||||
|
|
||||||
|
void plug_poll(char* buf, size_t len) {
|
||||||
|
// print text to `buf` with max len `len`
|
||||||
|
}
|
||||||
|
|
||||||
|
void plug_free(void) {
|
||||||
|
free(p); // free state
|
||||||
|
}
|
79
src/plug.c
79
src/plug.c
|
@ -21,7 +21,7 @@ typedef struct PlugMan {
|
||||||
static plugman_t PLUGMAN = {0};
|
static plugman_t PLUGMAN = {0};
|
||||||
|
|
||||||
void* load_plug_sym(void* plug_f, char* fn_name);
|
void* load_plug_sym(void* plug_f, char* fn_name);
|
||||||
plug_int_t* load_plugin(char* path);
|
plug_int_t* load_plugin(char* path, bool);
|
||||||
|
|
||||||
void load_plugins(const char* mod_dir_p) {
|
void load_plugins(const char* mod_dir_p) {
|
||||||
DIR* dir = {0};
|
DIR* dir = {0};
|
||||||
|
@ -56,12 +56,11 @@ void load_plugins(const char* mod_dir_p) {
|
||||||
|
|
||||||
printf("INFO: Found plugin: %s/%s\n", mod_dir_p, dir_entry->d_name);
|
printf("INFO: Found plugin: %s/%s\n", mod_dir_p, dir_entry->d_name);
|
||||||
|
|
||||||
char full_path[PLUG_MAX_COUNT] = {0};
|
char* full_path = (char*)malloc(sizeof(char)*1028);
|
||||||
snprintf(full_path, PLUG_MAX_COUNT, "%s/%s", mod_dir_p, dir_entry->d_name);
|
snprintf(full_path, PLUG_MAX_COUNT, "%s/%s", mod_dir_p, dir_entry->d_name);
|
||||||
plug_int_t* plug = load_plugin(full_path);
|
plug_int_t* plug = load_plugin(full_path, true);
|
||||||
|
|
||||||
if (!plug) {
|
if (!plug) {
|
||||||
printf("ERROR: Failed to load plugin %s, skipping\n", full_path);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
PLUGMAN.plugs[PLUGMAN.plug_count++] = plug;
|
PLUGMAN.plugs[PLUGMAN.plug_count++] = plug;
|
||||||
|
@ -69,8 +68,19 @@ void load_plugins(const char* mod_dir_p) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
plug_int_t* load_plugin(char* path) {
|
plug_int_t* load_plugin(char* path, bool check_duplicates) {
|
||||||
|
if (check_duplicates) {
|
||||||
|
for (size_t i = 0; i < PLUGMAN.plug_count; i++) {
|
||||||
|
plug_int_t* plug = PLUGMAN.plugs[i];
|
||||||
|
if (strcmp(plug->path, path) == 0) {
|
||||||
|
return NULL; // plugin exists
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
plug_int_t* plug = malloc(sizeof(plug_int_t));
|
plug_int_t* plug = malloc(sizeof(plug_int_t));
|
||||||
|
plug->path = path;
|
||||||
|
|
||||||
void* plug_f = dlopen(path, RTLD_NOW);
|
void* plug_f = dlopen(path, RTLD_NOW);
|
||||||
|
|
||||||
if (!plug_f) {
|
if (!plug_f) {
|
||||||
|
@ -82,18 +92,19 @@ plug_int_t* load_plugin(char* path) {
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||||
|
|
||||||
plug->f_init = (plug_init_f)load_plug_sym(plug_f, "plug_init");
|
plug->f_init = (plug_init_f) load_plug_sym(plug_f, "plug_init");
|
||||||
plug->f_reload = (plug_reload_f)load_plug_sym(plug_f, "plug_reload");
|
plug->f_pre_reload = (plug_pre_reload_f) load_plug_sym(plug_f, "plug_pre_reload");
|
||||||
plug->f_poll = (plug_poll_f)load_plug_sym(plug_f, "plug_poll");
|
plug->f_post_reload = (plug_post_reload_f) load_plug_sym(plug_f, "plug_post_reload");
|
||||||
plug->f_free = (plug_free_f)load_plug_sym(plug_f, "plug_free");
|
plug->f_poll = (plug_poll_f) load_plug_sym(plug_f, "plug_poll");
|
||||||
plug->s_plug_info = (plug_t*)load_plug_sym(plug_f, "PLUG");
|
plug->f_free = (plug_free_f) load_plug_sym(plug_f, "plug_free");
|
||||||
|
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
if (!plug->f_init || !plug->f_reload ||
|
if (!plug->f_init || !plug->f_pre_reload ||
|
||||||
!plug->f_poll || !plug->f_free ||
|
!plug->f_poll || !plug->f_free ||
|
||||||
!plug->s_plug_info) {
|
!plug->f_post_reload) {
|
||||||
dlclose(plug_f);
|
dlclose(plug_f);
|
||||||
|
printf("ERROR: Failed to find all functions in plugin");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,8 +130,14 @@ void setup_plugins(char* plugin_path) {
|
||||||
for (size_t i = 0; i < PLUGMAN.plug_count; i++) {
|
for (size_t i = 0; i < PLUGMAN.plug_count; i++) {
|
||||||
plug_int_t* plug = PLUGMAN.plugs[i];
|
plug_int_t* plug = PLUGMAN.plugs[i];
|
||||||
|
|
||||||
(plug->f_init)();
|
plug->state = (plug->f_init)();
|
||||||
printf(" - %s (%s)\n", plug->s_plug_info->name, plug->s_plug_info->version);
|
|
||||||
|
if (!plug->state) {
|
||||||
|
printf("Plugin '%s' did not initialise, skipping\n", plug->path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(" - %s (%s)\n", plug->state->name, plug->state->version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,10 +164,10 @@ char* poll_plugins(char* sep) {
|
||||||
|
|
||||||
for (size_t i = 0; i < PLUGMAN.plug_count; i++) {
|
for (size_t i = 0; i < PLUGMAN.plug_count; i++) {
|
||||||
plug_int_t* plug = PLUGMAN.plugs[i];
|
plug_int_t* plug = PLUGMAN.plugs[i];
|
||||||
if (!plug->s_plug_info->is_ready) continue;
|
if (!plug->state) continue;
|
||||||
|
|
||||||
|
|
||||||
printf("Polling plug id %zu\n", i);
|
// printf("Polling plug id %zu\n", i);
|
||||||
size_t len = strlen(buf);
|
size_t len = strlen(buf);
|
||||||
(plug->f_poll)(buf + len, PLUG_POLL_BUF_SZ - len);
|
(plug->f_poll)(buf + len, PLUG_POLL_BUF_SZ - len);
|
||||||
|
|
||||||
|
@ -160,10 +177,38 @@ char* poll_plugins(char* sep) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Setting title: '%s'\n", buf);
|
// printf("Setting title: '%s'\n", buf);
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void reload_plugins(void) {
|
||||||
|
void* plug_states[PLUG_MAX_COUNT];
|
||||||
|
size_t plug_count = 0;
|
||||||
|
|
||||||
|
printf("INFO: Reloading plugins\n");
|
||||||
|
// save states
|
||||||
|
for (size_t i = 0; i < PLUGMAN.plug_count; i++) {
|
||||||
|
plug_int_t* plug = PLUGMAN.plugs[i];
|
||||||
|
void* state = (plug->f_pre_reload)();
|
||||||
|
plug_states[plug_count++] = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
// unload plugins
|
||||||
|
for (size_t i = 0; i < PLUGMAN.plug_obj_count; i++) {
|
||||||
|
dlclose(PLUGMAN.plug_objs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
PLUGMAN.plug_obj_count = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < PLUGMAN.plug_count; i++) {
|
||||||
|
plug_int_t* plug = PLUGMAN.plugs[i];
|
||||||
|
plug = load_plugin(plug->path, false);
|
||||||
|
(plug->f_post_reload)(plug_states[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
load_plugins("./modules");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
189
src/socket.c
Normal file
189
src/socket.c
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "socket.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#define SOCKET_PATH "/tmp/dim.sock"
|
||||||
|
#define BUFFER_SIZE 255
|
||||||
|
|
||||||
|
typedef struct sock_server_t {
|
||||||
|
int s_fd;
|
||||||
|
int c_fd;
|
||||||
|
struct sockaddr_un s_addr;
|
||||||
|
char buf[BUFFER_SIZE];
|
||||||
|
int max_fd;
|
||||||
|
fd_set read_fds;
|
||||||
|
} sock_server_t;
|
||||||
|
|
||||||
|
sock_server_t SOCK_SERVER = {0};
|
||||||
|
|
||||||
|
|
||||||
|
int socket_init(void) {
|
||||||
|
|
||||||
|
// Check if socket exists
|
||||||
|
if (access(SOCKET_PATH, F_OK) == 0) {
|
||||||
|
remove(SOCKET_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Create the socket
|
||||||
|
SOCK_SERVER.s_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (SOCK_SERVER.s_fd == -1) {
|
||||||
|
perror("ERROR: Failed to create socket");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int flags = fcntl(SOCK_SERVER.s_fd, F_GETFL, 0);
|
||||||
|
if (fcntl(SOCK_SERVER.s_fd, F_SETFL, flags | O_NONBLOCK) == -1) {
|
||||||
|
perror("ERROR: Failed to set socket to non blocking");
|
||||||
|
close(SOCK_SERVER.s_fd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up the server address structure
|
||||||
|
memset(&SOCK_SERVER.s_addr, 0, sizeof(struct sockaddr_un));
|
||||||
|
SOCK_SERVER.s_addr.sun_family = AF_UNIX;
|
||||||
|
strncpy(SOCK_SERVER.s_addr.sun_path, SOCKET_PATH, sizeof(SOCK_SERVER.s_addr.sun_path) - 1);
|
||||||
|
|
||||||
|
// Bind the socket to the address
|
||||||
|
int berr = bind(
|
||||||
|
SOCK_SERVER.s_fd,
|
||||||
|
(struct sockaddr *)&SOCK_SERVER.s_addr,
|
||||||
|
sizeof(struct sockaddr_un));
|
||||||
|
|
||||||
|
if (berr == -1) {
|
||||||
|
perror("ERROR: Failed to bind to socket");
|
||||||
|
close(SOCK_SERVER.s_fd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listen for incoming connections
|
||||||
|
if (listen(SOCK_SERVER.s_fd, 5) == -1) {
|
||||||
|
perror("ERRROR: Failed to start listening for messages in the socket");
|
||||||
|
close(SOCK_SERVER.s_fd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("INFO: Server is listening on %s\n", SOCKET_PATH);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct timeval timeout = {0};
|
||||||
|
|
||||||
|
sock_msg_t socket_poll(void) {
|
||||||
|
FD_ZERO(&SOCK_SERVER.read_fds);
|
||||||
|
FD_SET(SOCK_SERVER.s_fd, &SOCK_SERVER.read_fds);
|
||||||
|
SOCK_SERVER.max_fd = SOCK_SERVER.s_fd;
|
||||||
|
|
||||||
|
// Add client sockets to the set
|
||||||
|
if (SOCK_SERVER.c_fd > 0) {
|
||||||
|
FD_SET(SOCK_SERVER.c_fd, &SOCK_SERVER.read_fds);
|
||||||
|
if (SOCK_SERVER.c_fd > SOCK_SERVER.max_fd) {
|
||||||
|
SOCK_SERVER.max_fd = SOCK_SERVER.c_fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Wait for an activity on one of the sockets
|
||||||
|
int activity = select(SOCK_SERVER.max_fd + 1, &SOCK_SERVER.read_fds, NULL, NULL, &timeout);
|
||||||
|
|
||||||
|
if (activity < 0 && errno != EINTR) {
|
||||||
|
perror("select error");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If something happened on the server socket, it's an incoming connection
|
||||||
|
if (FD_ISSET(SOCK_SERVER.s_fd, &SOCK_SERVER.read_fds)) {
|
||||||
|
if ((SOCK_SERVER.c_fd = accept(SOCK_SERVER.s_fd, NULL, NULL)) == -1) {
|
||||||
|
if (errno != EWOULDBLOCK && errno != EAGAIN) {
|
||||||
|
perror("accept error");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//printf("Accepted new connection\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If something happened on the client socket, it's incoming data
|
||||||
|
if (SOCK_SERVER.c_fd > 0 && FD_ISSET(SOCK_SERVER.c_fd, &SOCK_SERVER.read_fds)) {
|
||||||
|
int num_bytes = read(SOCK_SERVER.c_fd, SOCK_SERVER.buf, BUFFER_SIZE - 1);
|
||||||
|
if (num_bytes > 0) {
|
||||||
|
SOCK_SERVER.buf[num_bytes] = '\0'; // Null-terminate the buffer
|
||||||
|
return (sock_msg_t)atoi(SOCK_SERVER.buf);
|
||||||
|
//printf("Received message: %s\n", SOCK_SERVER.buf);
|
||||||
|
} else if (num_bytes == 0) {
|
||||||
|
// Client disconnected
|
||||||
|
//printf("Client disconnected\n");
|
||||||
|
close(SOCK_SERVER.c_fd);
|
||||||
|
SOCK_SERVER.c_fd = -1;
|
||||||
|
} else {
|
||||||
|
if (errno != EWOULDBLOCK && errno != EAGAIN) {
|
||||||
|
perror("read error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SM_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void socket_close(void) {
|
||||||
|
close(SOCK_SERVER.s_fd);
|
||||||
|
unlink(SOCKET_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void socket_send(char* msg_str) {
|
||||||
|
to_lowercase(msg_str);
|
||||||
|
|
||||||
|
sock_msg_t msg_t = SM_NONE;
|
||||||
|
|
||||||
|
if (strcmp(msg_str, "reload") == 0) {
|
||||||
|
msg_t = SM_RELOAD;
|
||||||
|
} else {
|
||||||
|
printf("ERROR: Unknown message type '%s'\n", msg_str);
|
||||||
|
printf("NOTE: Available messages:\n");
|
||||||
|
printf(" - reload\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int client_fd;
|
||||||
|
struct sockaddr_un server_addr;
|
||||||
|
|
||||||
|
// Create the socket
|
||||||
|
if ((client_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
|
||||||
|
perror("ERROR: Failed to create error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up the server address structure
|
||||||
|
memset(&server_addr, 0, sizeof(struct sockaddr_un));
|
||||||
|
server_addr.sun_family = AF_UNIX;
|
||||||
|
strncpy(server_addr.sun_path, SOCKET_PATH, sizeof(server_addr.sun_path) - 1);
|
||||||
|
|
||||||
|
// Connect to the server
|
||||||
|
if (connect(client_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_un)) == -1) {
|
||||||
|
perror("ERROR: Failed to connect to server");
|
||||||
|
close(client_fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char msg[255];
|
||||||
|
|
||||||
|
snprintf(msg, 255, "%d", msg_t);
|
||||||
|
|
||||||
|
// Send a message to the server
|
||||||
|
if (write(client_fd, msg, strlen(msg)) == -1) {
|
||||||
|
perror("ERROR: Failed to write message to server");
|
||||||
|
close(client_fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
close(client_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
14
src/util.c
Normal file
14
src/util.c
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
void to_lowercase(char* str) {
|
||||||
|
for(int i = 0; str[i]; i++){
|
||||||
|
str[i] = tolower(str[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void to_uppercase(char* str) {
|
||||||
|
for(int i = 0; str[i]; i++){
|
||||||
|
str[i] = tolower(str[i]);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user