Skip to content

Commit

Permalink
Add support for handling responses to gen_server calls
Browse files Browse the repository at this point in the history
  • Loading branch information
abelino committed Sep 1, 2024
1 parent 5fd91c6 commit 7d2b8c9
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 8 deletions.
7 changes: 6 additions & 1 deletion lib/bacnet.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ defmodule Bacnet do
GenServer.start_link(__MODULE__, nil, name: __MODULE__)
end

@impl GenServer
@spec add_device(device :: term) :: :ok | {:error, term}
def add_device(device) do
GenServer.call({:global, :bacnetd}, {:add_device, device})
end

end @impl GenServer
def init(_) do
{:ok, nil}
end
Expand Down
13 changes: 13 additions & 0 deletions src/ei_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,19 @@ bool ei_client_send(char *process_name, ei_x_buff *msg)
return ret == 0 ? true : false;
}

bool ei_client_send_to(erlang_pid *pid, ei_x_buff *msg)
{
if (!client.ready) {
return false;
}

pthread_mutex_lock(&client.lock);
int ret = ei_send(client.fd, pid, msg->buff, msg->index);
pthread_mutex_unlock(&client.lock);

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);
Expand Down
1 change: 1 addition & 0 deletions src/ei_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

bool ei_client_config(const char *nodename, const char *cookie);
bool ei_client_send(char *process_name, ei_x_buff *msg);
bool ei_client_send_to(erlang_pid *pid, 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);

Expand Down
83 changes: 76 additions & 7 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
#include "ei_client.h"
#include "ei_log.h"

#define STRINGIFY(x) #x
#define TOSTR(x) STRINGIFY(x)
#define ERL_TUPLE TOSTR(ERL_SMALL_TUPLE_EXT) TOSTR(ERL_SMALL_TUPLE_EXT)

static arg_t args;
static void unimplemented(const char *msg_type);
static void handle_call(char *buf, int *index, ei_x_buff *reply);

int main(int argc, char **argv)
{
Expand All @@ -31,22 +35,59 @@ int main(int argc, char **argv)

int index = 0;
int version = 0;
int arity = 0;
ei_term t = { 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_tuple_header(buf, &index, &t.size)
|| (t.size < 2)
|| ei_decode_atom(buf, &index, msg_type));

if (bad_msg) {
goto cleanup;
}

if (strcmp(msg_type, "$gen_call") == 0) {
unimplemented("$gen_call");
erlang_pid from_pid;
erlang_ref from_ref;

// request {:"$gen_call", {PID, [:alias | REF]}, TUPLE}}
bool bad_msg = (false
|| ei_decode_tuple_header(buf, &index, &t.size)
|| (t.size != 2)
|| ei_decode_pid(buf, &index, &from_pid)
|| ei_decode_list_header(buf, &index, &t.size)
|| (t.size != 1)
|| ei_decode_atom(buf, &index, t.value.atom_name)
|| strcmp(t.value.atom_name, "alias")
|| ei_decode_ref(buf, &index, &from_ref)
|| ei_get_type(buf, &index, (int *)&t.ei_type, &t.size)
|| memchr(ERL_TUPLE, t.ei_type, sizeof(ERL_TUPLE)) == NULL);

if (bad_msg) {
LOG_ERR("Failed decoding message");
goto cleanup;
}

// reply {[:alias | REF], REPLY}
ei_x_buff reply;
ei_x_new_with_version(&reply);
ei_x_encode_tuple_header(&reply, 2);
ei_x_encode_list_header(&reply, 1);
ei_x_encode_atom(&reply, "alias");
ei_x_encode_ref(&reply, &from_ref);

handle_call(buf, &index, &reply);

if (!ei_client_send_to(&from_pid, &reply)) {
LOG_ERR("Unable to send reply");
}

ei_x_free(&reply);
} else {
LOG_WRN("bacnetd: unknown message type %s", msg_type);
}

cleanup:
Expand All @@ -56,7 +97,35 @@ int main(int argc, char **argv)
return 0;
}

static void unimplemented(const char *msg_type)
static void add_device(char *buf, int *index, ei_x_buff *reply)
{
ei_x_encode_tuple_header(reply, 2);
ei_x_encode_atom(reply, "error");
ei_x_encode_atom(reply, "unimplemented");
}

static void handle_call(char *buf, int *index, ei_x_buff *reply)
{
LOG_WRN("bacnetd: %s unimplemented", msg_type);
int size = 0;
char call_type[MAXATOMLEN] = { 0 };

bool bad_msg = (false
|| ei_decode_tuple_header(buf, index, &size)
|| ei_decode_atom(buf, index, call_type));

if (bad_msg) {
ei_x_encode_tuple_header(reply, 2);
ei_x_encode_atom(reply, "error");
ei_x_encode_atom(reply, "bad_request");
return;
}

if (strcmp(call_type, "add_device") == 0) {
add_device(buf, index, reply);
}
else {
ei_x_encode_tuple_header(reply, 2);
ei_x_encode_atom(reply, "error");
ei_x_encode_atom(reply, "unimplemented");
}
}

0 comments on commit 7d2b8c9

Please sign in to comment.