Hot reloading + state saving
This commit is contained in:
		
							parent
							
								
									3b68f2dfda
								
							
						
					
					
						commit
						a4e73470e2
					
				
							
								
								
									
										4
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								Makefile
									
									
									
									
									
								
							|  | @ -4,12 +4,12 @@ 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_post_reload_f) (void*); | ||||||
| typedef void  (*plug_poll_f)        (char*, size_t); | typedef void  (*plug_poll_f)        (char*, size_t); | ||||||
| typedef void  (*plug_free_f)        (void); | 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
 | ||||||
|  | } | ||||||
							
								
								
									
										73
									
								
								src/plug.c
									
									
									
									
									
								
							
							
						
						
									
										73
									
								
								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) { | ||||||
|  | @ -83,17 +93,18 @@ plug_int_t* load_plugin(char* path) { | ||||||
|     #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_post_reload = (plug_post_reload_f) load_plug_sym(plug_f, "plug_post_reload"); | ||||||
|     plug->f_poll        = (plug_poll_f)        load_plug_sym(plug_f, "plug_poll"); |     plug->f_poll        = (plug_poll_f)        load_plug_sym(plug_f, "plug_poll"); | ||||||
|     plug->f_free        = (plug_free_f)        load_plug_sym(plug_f, "plug_free"); |     plug->f_free        = (plug_free_f)        load_plug_sym(plug_f, "plug_free"); | ||||||
|     plug->s_plug_info = (plug_t*)load_plug_sym(plug_f, "PLUG"); |  | ||||||
| 
 | 
 | ||||||
|     #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