diff options
| author | info@mode42.com <info@mode42.com> | 2026-08-08 03:54:55 +0000 |
|---|---|---|
| committer | info@mode42.com <info@mode42.com> | 2026-08-08 03:54:55 +0000 |
| commit | 20cb29c2f8c5c87bc590896854a20b1473ceb358 (patch) | |
| tree | 2857f41513a56ad41af97b57362639298aa7f033 /src/core/instance.c | |
#2
Diffstat (limited to 'src/core/instance.c')
| -rw-r--r-- | src/core/instance.c | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/src/core/instance.c b/src/core/instance.c new file mode 100644 index 0000000..4640678 --- /dev/null +++ b/src/core/instance.c @@ -0,0 +1,272 @@ +#include "hybbx/instance.h" +#include "hybbx/log.h" +#include "hybbx/util.h" + +#include <string.h> + +static int g_instance_standalone; + +static int str_ieq(const char *a, const char *b) +{ + if (a == NULL || b == NULL) { + return 0; + } + + while (*a != '\0' && *b != '\0') { + char ca = (char)(*a >= 'A' && *a <= 'Z' ? *a + 32 : *a); + char cb = (char)(*b >= 'A' && *b <= 'Z' ? *b + 32 : *b); + + if (ca != cb) { + return 0; + } + a++; + b++; + } + + return *a == '\0' && *b == '\0'; +} + +#if defined(__GNUC__) || defined(__clang__) +__attribute__((weak)) +#endif +hybbx_instance_role_t hybbx_instance_role(void) +{ + /* Overridden by instance_role_{main,secondary,proxy}.c on each binary. */ + return HYBBX_INSTANCE_MAIN; +} + +const char *hybbx_instance_binary_name(void) +{ + switch (hybbx_instance_role()) { + case HYBBX_INSTANCE_SECONDARY: + return "hybbxsd"; + case HYBBX_INSTANCE_PROXY: + return "hybbxpd"; + case HYBBX_INSTANCE_MAIN: + default: + return "hybbxd"; + } +} + +const char *hybbx_instance_role_name(void) +{ + switch (hybbx_instance_role()) { + case HYBBX_INSTANCE_SECONDARY: + return "Secondary"; + case HYBBX_INSTANCE_PROXY: + return "Proxy"; + case HYBBX_INSTANCE_MAIN: + default: + return "Main"; + } +} + +int hybbx_instance_offers_user_bbx(void) +{ + return hybbx_instance_role() == HYBBX_INSTANCE_MAIN; +} + +void hybbx_instance_set_standalone(int enabled) +{ + g_instance_standalone = enabled != 0; +} + +int hybbx_instance_standalone(void) +{ + return g_instance_standalone; +} + +static int instance_main_standalone(void) +{ + return hybbx_instance_role() == HYBBX_INSTANCE_MAIN && + hybbx_instance_standalone(); +} + +int hybbx_instance_plugin_allowed(const char *plugin_name) +{ + hybbx_instance_role_t role; + + if (plugin_name == NULL || plugin_name[0] == '\0') { + return 0; + } + + role = hybbx_instance_role(); + + if (instance_main_standalone()) { + if (str_ieq(plugin_name, "circuit")) { + return 1; + } + if (str_ieq(plugin_name, "mains_proxy")) { + return 1; + } + return 1; + } + + /* Split layout: packet_radio stays in HyBBX only via MAX25 prep on Secondary/Proxy; + * hub Main uses circuit peers instead. */ + if (str_ieq(plugin_name, "packet_radio")) { + return role != HYBBX_INSTANCE_MAIN; + } + + switch (role) { + case HYBBX_INSTANCE_MAIN: + if (str_ieq(plugin_name, "baycom") || + str_ieq(plugin_name, "ardop") || + str_ieq(plugin_name, "crdop")) { + return 0; + } + if (str_ieq(plugin_name, "telnet") || str_ieq(plugin_name, "ssh")) { + return 0; + } + return 1; + + case HYBBX_INSTANCE_PROXY: + if (str_ieq(plugin_name, "websocket")) { + return 0; + } + return 1; + + case HYBBX_INSTANCE_SECONDARY: + if (str_ieq(plugin_name, "telnet") || + str_ieq(plugin_name, "ssh") || + str_ieq(plugin_name, "websocket")) { + return 0; + } + return 1; + + default: + return 0; + } +} + +hybbx_result_t hybbx_networks_enforce_instance(hybbx_networks_config_t *networks) +{ + hybbx_instance_role_t role; + + if (networks == NULL) { + return HYBBX_ERR_INVALID; + } + + role = hybbx_instance_role(); + + if (instance_main_standalone()) { + hybbx_log_info("[instance] standalone=yes — %s keeps INI transports " + "(local RF via MAX25 prep when configured)", + hybbx_instance_binary_name()); + hybbx_log_info("[instance] binary=%s role=%s standalone=yes user_bbx=%s " + "telnet=%s ssh=%s ax25=%s baycom=%s ardop=%s crdop=%s " + "websocket=%s circuit=%s mains_proxy=%s", + hybbx_instance_binary_name(), + hybbx_instance_role_name(), + hybbx_instance_offers_user_bbx() ? "yes" : "no", + hybbx_bool_to_string(networks->telnet), + hybbx_bool_to_string(networks->ssh), + hybbx_bool_to_string(networks->ax25), + hybbx_bool_to_string(networks->baycom), + hybbx_bool_to_string(networks->ardop), + hybbx_bool_to_string(networks->crdop), + hybbx_bool_to_string(networks->websocket), + hybbx_bool_to_string(networks->circuit), + hybbx_bool_to_string(networks->mains_proxy)); + return HYBBX_OK; + } + + if (networks->ax25 && role == HYBBX_INSTANCE_MAIN) { + hybbx_log_warn("[instance] %s: ax25/packet_radio on hub Main — forcing off " + "(use standalone=yes or Secondary RF host)", + hybbx_instance_binary_name()); + networks->ax25 = 0; + } + + switch (role) { + case HYBBX_INSTANCE_MAIN: + if (networks->baycom || networks->ardop || networks->crdop) { + hybbx_log_warn("[instance] hybbxd: RF adapters forbidden on Main " + "— forcing baycom/ardop/crdop off (use hybbxpd + MAX25)"); + networks->baycom = 0; + networks->ardop = 0; + networks->crdop = 0; + } + if (networks->ssh) { + hybbx_log_warn("[instance] hybbxd: SSH user path forbidden — " + "WebSocket/reverse-proxy only; forcing ssh=no"); + networks->ssh = 0; + } + if (networks->telnet) { + hybbx_log_warn("[instance] hybbxd: telnet user path forbidden — " + "WebSocket/reverse-proxy only; forcing telnet=no"); + networks->telnet = 0; + } + /* WebSocket is the sole remote user path. */ + if (!networks->websocket) { + hybbx_log_warn("[instance] hybbxd: enabling websocket " + "(required user path)"); + networks->websocket = 1; + } + /* Circuit hub for Proxy attach. */ + if (!networks->circuit) { + hybbx_log_warn("[instance] hybbxd: enabling circuit hub " + "(Proxy in/out)"); + networks->circuit = 1; + } + break; + + case HYBBX_INSTANCE_SECONDARY: + if (networks->telnet) { + hybbx_log_warn("[instance] hybbxsd: no user telnet — forcing off"); + networks->telnet = 0; + } + if (networks->websocket) { + hybbx_log_warn("[instance] hybbxsd: no user WebSocket — forcing off"); + networks->websocket = 0; + } + if (networks->ssh) { + hybbx_log_warn("[instance] hybbxsd: no user SSH — forcing off"); + networks->ssh = 0; + } + /* Peer other Mains — mains_proxy required. */ + if (!networks->mains_proxy) { + hybbx_log_warn("[instance] hybbxsd: enabling mains_proxy " + "(Secondary = other-Main peers)"); + networks->mains_proxy = 1; + } + break; + + case HYBBX_INSTANCE_PROXY: + if (networks->websocket) { + hybbx_log_warn("[instance] hybbxpd: WebSocket forbidden — forcing off"); + networks->websocket = 0; + } + if (networks->baycom) { + hybbx_log_warn("[instance] hybbxpd: baycom enabled — prefer MAX25 " + "relay/gateway/digipeater for hyBBX RF"); + } + if (!networks->circuit) { + hybbx_log_warn("[instance] hybbxpd: enabling circuit " + "(attach toward Main)"); + networks->circuit = 1; + } + break; + + default: + return HYBBX_ERR_INVALID; + } + + hybbx_log_info("[instance] binary=%s role=%s user_bbx=%s " + "telnet=%s ssh=%s ax25=%s baycom=%s ardop=%s crdop=%s " + "websocket=%s circuit=%s mains_proxy=%s", + hybbx_instance_binary_name(), + hybbx_instance_role_name(), + hybbx_instance_offers_user_bbx() ? "yes" : "no", + hybbx_bool_to_string(networks->telnet), + hybbx_bool_to_string(networks->ssh), + hybbx_bool_to_string(networks->ax25), + hybbx_bool_to_string(networks->baycom), + hybbx_bool_to_string(networks->ardop), + hybbx_bool_to_string(networks->crdop), + hybbx_bool_to_string(networks->websocket), + hybbx_bool_to_string(networks->circuit), + hybbx_bool_to_string(networks->mains_proxy)); + + return HYBBX_OK; +} |
