summaryrefslogtreecommitdiff
path: root/src/core/instance.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/instance.c')
-rw-r--r--src/core/instance.c272
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;
+}
git clone -b <branch> https://cgit.mode42.com/<repo>.git
git clone -b <branch> git://cgit.mode42.com/<repo>.git

info@mode42.com