From 5fd91c67bebb770ecc32dec0d5e539009f7a5378 Mon Sep 17 00:00:00 2001 From: abelino Date: Fri, 30 Aug 2024 23:49:14 -0700 Subject: [PATCH] Register c-node globally and remove no-longer needed services --- lib/bacnet.ex | 17 ++++++++++ lib/bacnet/application.ex | 3 +- lib/bacnet/heartbeat.ex | 26 --------------- lib/bacnet/logger.ex | 40 ------------------------ src/ei_client.c | 29 ++++++++++++++++- src/ei_client.h | 4 +-- src/ei_heartbeat.c | 66 --------------------------------------- src/ei_heartbeat.h | 6 ---- src/ei_log.c | 29 ++++++++++------- src/ei_log.h | 12 ++++--- src/main.c | 46 ++++++++++++++++++++++----- 11 files changed, 111 insertions(+), 167 deletions(-) delete mode 100644 lib/bacnet/heartbeat.ex delete mode 100644 lib/bacnet/logger.ex delete mode 100644 src/ei_heartbeat.c delete mode 100644 src/ei_heartbeat.h diff --git a/lib/bacnet.ex b/lib/bacnet.ex index 7acb96a..229c3c6 100644 --- a/lib/bacnet.ex +++ b/lib/bacnet.ex @@ -2,4 +2,21 @@ defmodule Bacnet do @moduledoc """ BACNet client. """ + + use GenServer + + require Logger + + @spec start_link(any) :: GenServer.on_start() + def start_link(_opts) do + GenServer.start_link(__MODULE__, nil, name: __MODULE__) + end + + @impl GenServer + def init(_) do + {:ok, nil} + end + + @doc false + defdelegate ei_log(level, term), to: Logger, as: :log end diff --git a/lib/bacnet/application.ex b/lib/bacnet/application.ex index 315bd72..6f17af0 100644 --- a/lib/bacnet/application.ex +++ b/lib/bacnet/application.ex @@ -13,8 +13,7 @@ defmodule Bacnet.Application do defp children() do [ - {Bacnet.Logger, nil}, - {Bacnet.Heartbeat, nil}, + {Bacnet, nil}, {MuonTrap.Daemon, [bacnetd_exec(), bacnetd_args(), []]} ] end diff --git a/lib/bacnet/heartbeat.ex b/lib/bacnet/heartbeat.ex deleted file mode 100644 index a98d42e..0000000 --- a/lib/bacnet/heartbeat.ex +++ /dev/null @@ -1,26 +0,0 @@ -defmodule Bacnet.Heartbeat do - @moduledoc """ - Heartbeat server accepting periodic messages, keeping the cnode alive. - """ - - use GenServer - - require Logger - - @spec start_link(any) :: GenServer.on_start() - def start_link(_opts) do - GenServer.start_link(__MODULE__, nil, name: __MODULE__) - end - - @impl GenServer - def init(_) do - {:ok, nil} - end - - @impl GenServer - def handle_info(:heartbeat, state) do - Logger.debug("Heartbeat received from bacnetd") - - {:noreply, state} - end -end diff --git a/lib/bacnet/logger.ex b/lib/bacnet/logger.ex deleted file mode 100644 index 123de36..0000000 --- a/lib/bacnet/logger.ex +++ /dev/null @@ -1,40 +0,0 @@ -defmodule Bacnet.Logger do - @moduledoc """ - Log server for the cnode. - """ - - use GenServer - - require Logger - - @levels [ - :emergency, - :alert, - :critical, - :error, - :warning, - :notice, - :info, - :debug, - ] - - @spec start_link(any) :: GenServer.on_start() - def start_link(_opts) do - GenServer.start_link(__MODULE__, nil, name: __MODULE__) - end - - @impl GenServer - def init(_) do - {:ok, nil} - end - - @impl GenServer - def handle_info({level, term}, state) when level in @levels do - Logger.log(level, maybe_inspect(term)) - - {:noreply, state} - end - - defp maybe_inspect(term) when is_binary(term), do: term - defp maybe_inspect(term), do: inspect(term) -end diff --git a/src/ei_client.c b/src/ei_client.c index 03a6d58..77f01f3 100644 --- a/src/ei_client.c +++ b/src/ei_client.c @@ -5,7 +5,7 @@ #include "ei_client.h" -#define OTP_COMPAT_VER 25 +#define OTP_COMPAT_VER 24 #define HEARTBEAT_PROCESS "Elixir.Bacnet.Heartbeat" #define CNODE_NAME "bacnetd" @@ -53,6 +53,11 @@ bool ei_client_config(const char *nodename, const char *cookie) return false; } + erlang_pid *pid = ei_self(&client.cnode); + if (ei_global_register(client.fd, CNODE_NAME, pid) == -1) { + return false; + } + client.ready = true; return true; @@ -72,6 +77,28 @@ bool ei_client_send(char *process_name, ei_x_buff *msg) return ret == 0 ? true : false; } +bool ei_client_call(char *module, char *func, ei_x_buff *args, ei_x_buff *out) +{ + pthread_mutex_lock(&client.lock); + int ret = ei_rpc(&client.cnode, client.fd, module, func, args->buff, + args->index, out); + pthread_mutex_unlock(&client.lock); + + return ret == -1 ? false : true; +} + +bool ei_client_recv(erlang_msg *meta, ei_x_buff *msg) +{ + pthread_mutex_lock(&client.lock); + int ret = ei_xreceive_msg(client.fd, meta, msg); + pthread_mutex_unlock(&client.lock); + if (ret == ERL_ERROR) { + return false; + } + + return true; +} + static void ei_free() { if (client.fd != NULL) { diff --git a/src/ei_client.h b/src/ei_client.h index 11baa64..5cc7694 100644 --- a/src/ei_client.h +++ b/src/ei_client.h @@ -3,9 +3,9 @@ #include -typedef void(msg_handler_cb_t)(erlang_msg *msg, ei_x_buff *data); - bool ei_client_config(const char *nodename, const char *cookie); bool ei_client_send(char *process_name, ei_x_buff *msg); +bool ei_client_call(char *module, char *func, ei_x_buff *msg, ei_x_buff *out); +bool ei_client_recv(erlang_msg *meta, ei_x_buff *msg); #endif /* EI_CLIENT_H */ diff --git a/src/ei_heartbeat.c b/src/ei_heartbeat.c deleted file mode 100644 index ebcfa80..0000000 --- a/src/ei_heartbeat.c +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include -#include - -#include "ei_client.h" -#include "ei_log.h" - -#define HEARTBEAT_PROCESS "Elixir.Bacnet.Heartbeat" - -static bool initialized; -static timer_t timer; -static void heartbeat_cb(int sig, siginfo_t *si, void *uc); - -bool ei_heartbeat_start() -{ - if (initialized) { - LOG_DBG("Heartbeat already initialized"); - return true; - } - - struct sigaction sa = { - .sa_flags = SA_SIGINFO, - .sa_sigaction = heartbeat_cb, - }; - - sigemptyset(&sa.sa_mask); - - if (sigaction(SIGRTMIN, &sa, NULL) < 0) { - return false; - } - - struct sigevent event = { - .sigev_notify = SIGEV_SIGNAL, - .sigev_signo = SIGRTMIN, - }; - - if (timer_create(CLOCK_REALTIME, &event, &timer)) { - return false; - } - - struct itimerspec spec = { - .it_interval = {.tv_sec = 4}, - .it_value = {.tv_sec = 4}, - }; - - if (timer_settime(timer, 0, &spec, NULL)) { - return false; - } - - initialized = true; - - return true; -} - -static void heartbeat_cb(int sig, siginfo_t *si, void *uc) -{ - ei_x_buff msg; - ei_x_new_with_version(&msg); - ei_x_encode_atom(&msg, "heartbeat"); - - if (!ei_client_send(HEARTBEAT_PROCESS, &msg)) { - LOG_ERR("Failed to send heartbeat"); - } - - ei_x_free(&msg); -} diff --git a/src/ei_heartbeat.h b/src/ei_heartbeat.h deleted file mode 100644 index c77c00a..0000000 --- a/src/ei_heartbeat.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef EI_HEARTBEAT_H -#define EI_HEARTBEAT_H - -bool ei_heartbeat_start(); - -#endif /* EI_HEARTBEAT_H */ diff --git a/src/ei_log.c b/src/ei_log.c index 45fb5e3..8ca29cc 100644 --- a/src/ei_log.c +++ b/src/ei_log.c @@ -10,26 +10,31 @@ static const char *level_to_str(log_level_t level); void ei_log(log_level_t level, const char *format, ...) { - va_list args; - va_start(args, format); + va_list vargs; + va_start(vargs, format); char log_buffer[MAX_LOG_LEN]; - int log_len = snprintf(log_buffer, sizeof(log_buffer), format, args); + int log_len = vsnprintf(log_buffer, sizeof(log_buffer), format, vargs); - ei_x_buff msg; - ei_x_new_with_version(&msg); - ei_x_encode_tuple_header(&msg, 2); - ei_x_encode_atom(&msg, level_to_str(level)); - ei_x_encode_binary(&msg, log_buffer, log_len); + ei_x_buff out; + ei_x_new(&out); - if (!ei_client_send("Elixir.Bacnet.Logger", &msg)) { + ei_x_buff args; + ei_x_new(&args); + ei_x_encode_list_header(&args, 2); + ei_x_encode_atom(&args, level_to_str(level)); + ei_x_encode_binary(&args, log_buffer, log_len); + ei_x_encode_empty_list(&args); + + if (!ei_client_call("Elixir.Bacnet", "ei_log", &args, &out)) { char new_format[MAX_LOG_LEN]; snprintf(new_format, sizeof(new_format), "%s\n", format); - vprintf(new_format, args); + vprintf(new_format, vargs); } - ei_x_free(&msg); - va_end(args); + ei_x_free(&out); + ei_x_free(&args); + va_end(vargs); } static const char *level_to_str(log_level_t level) diff --git a/src/ei_log.h b/src/ei_log.h index 5c93aed..d766a5c 100644 --- a/src/ei_log.h +++ b/src/ei_log.h @@ -1,10 +1,14 @@ #ifndef EI_LOG_H #define EI_LOG_H -#define LOG_ERR(format, ...) ei_log(ERROR, format __VA_ARGS__) -#define LOG_WRN(format, ...) ei_log(WARNING, format __VA_ARGS__) -#define LOG_INF(format, ...) ei_log(INFO, format __VA_ARGS__) -#define LOG_DBG(format, ...) ei_log(DEBUG, format __VA_ARGS__) +#define LOG_EME(format, ...) ei_log(EMERGENCY, format, ##__VA_ARGS__) +#define LOG_ALE(format, ...) ei_log(ALERT, format, ##__VA_ARGS__) +#define LOG_CRT(format, ...) ei_log(CRITICAL, format, ##__VA_ARGS__) +#define LOG_ERR(format, ...) ei_log(ERROR, format, ##__VA_ARGS__) +#define LOG_WRN(format, ...) ei_log(WARNING, format, ##__VA_ARGS__) +#define LOG_NTC(format, ...) ei_log(NOTICE, format, ##__VA_ARGS__) +#define LOG_INF(format, ...) ei_log(INFO, format, ##__VA_ARGS__) +#define LOG_DBG(format, ...) ei_log(DEBUG, format, ##__VA_ARGS__) typedef enum { EMERGENCY, diff --git a/src/main.c b/src/main.c index 096ebad..874a799 100644 --- a/src/main.c +++ b/src/main.c @@ -3,30 +3,60 @@ #include "arg.h" #include "bacnet/datalink/dlenv.h" #include "ei_client.h" -#include "ei_heartbeat.h" #include "ei_log.h" static arg_t args; +static void unimplemented(const char *msg_type); int main(int argc, char **argv) { dlenv_init(); - args_parse(&args, argc, argv); if (!ei_client_config(args.nodename, args.cookie)) { - LOG_ERR("Failed to start ei client"); + LOG_ERR("bacnetd: unable to establish connection"); return -1; } - if (!ei_heartbeat_start()) { - LOG_ERR("Heartbeat failed to start"); - return -1; - } + LOG_DBG("bacnetd: process started"); while (1) { - pause(); + erlang_msg meta; + ei_x_buff msg; + ei_x_new(&msg); + + if (!ei_client_recv(&meta, &msg)) { + goto cleanup; + } + + int index = 0; + int version = 0; + int arity = 0; + char msg_type[MAXATOMLEN] = { 0 }; + + char *buf = msg.buff; + bool bad_msg = (false + || ei_decode_version(buf, &index, &version) + || ei_decode_tuple_header(buf, &index, &arity) + || (arity < 2) + || ei_decode_atom(buf, &index, msg_type)); + + if (bad_msg) { + goto cleanup; + } + + if (strcmp(msg_type, "$gen_call") == 0) { + unimplemented("$gen_call"); + } + + cleanup: + ei_x_free(&msg); } return 0; } + +static void unimplemented(const char *msg_type) +{ + LOG_WRN("bacnetd: %s unimplemented", msg_type); +}