tags 961652 + patch
thanks
Hi Philipp!
I'd like to offer a patch (a rewrite of epam.c) which switches to
libei and seems to work for Erlang 21, 22, 23. It'd be better to check
it upstream though.
Cheers!
--
Sergei Golovan
diff --git a/c_src/epam.c b/c_src/epam.c
index 95e97fb..b7ad488 100644
--- a/c_src/epam.c
+++ b/c_src/epam.c
@@ -19,7 +19,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <erl_interface.h>
#include <ei.h>
#include <unistd.h>
@@ -99,11 +98,11 @@ static int acct_mgmt(char *service, char *user)
return retval;
}
-static int read_buf(int fd, byte *buf, int len)
+static int read_buf(int fd, const char *buf, int len)
{
int i, got = 0;
do {
- if ((i = read(fd, buf+got, len-got)) <= 0) {
+ if ((i = read(fd, (char *)buf+got, len-got)) <= 0) {
if (i == 0) return got;
if (errno != EINTR)
return got;
@@ -114,7 +113,7 @@ static int read_buf(int fd, byte *buf, int len)
return (len);
}
-static int read_cmd(byte *buf)
+static int read_cmd(const char *buf)
{
int len;
if (read_buf(0, buf, 2) != 2)
@@ -150,113 +149,128 @@ static int write_cmd(char *buf, int len)
return 1;
}
-static int process_reply(ETERM *pid, int cmd, int res)
+static int process_reply(erlang_pid pid, erlang_ref ref, int cmd, int res)
{
- ETERM *result;
- ETERM *errbin;
- int len, retval;
+ ei_x_buff result;
+ int retval = 0;
const char *errtxt;
- byte *buf;
- if (res == PAM_SUCCESS)
- result = erl_format("{~i, ~w, true}", cmd, pid);
- else
- {
- errtxt = pam_strerror(NULL, res);
- errbin = erl_mk_binary(errtxt, strlen(errtxt));
- result = erl_format("{~i, ~w, {false, ~w}}", cmd, pid, errbin);
- erl_free_term(errbin);
- }
- len = erl_term_len(result);
- buf = erl_malloc(len);
- erl_encode(result, buf);
- retval = write_cmd((char *)buf, len);
- erl_free_term(result);
- erl_free(buf);
+
+ if (ei_x_new_with_version(&result) != 0) return 0;
+ if (ei_x_encode_tuple_header(&result, 3) != 0) goto cleanup;
+ if (ei_x_encode_char(&result, cmd) != 0) goto cleanup;
+ if (ei_x_encode_tuple_header(&result, 2) != 0) goto cleanup;
+ if (ei_x_encode_pid(&result, &pid) != 0) goto cleanup;
+ if (ei_x_encode_ref(&result, &ref) != 0) goto cleanup;
+
+ if (res == PAM_SUCCESS) {
+ if (ei_x_encode_atom(&result, "true") != 0) goto cleanup;
+ } else {
+ errtxt = pam_strerror(NULL, res);
+ if (ei_x_encode_tuple_header(&result, 2) != 0) goto cleanup;
+ if (ei_x_encode_atom(&result, "false") != 0) goto cleanup;
+ if (ei_x_encode_binary(&result, errtxt, strlen(errtxt)) != 0) goto cleanup;
+ }
+ retval = write_cmd(result.buff, result.index);
+ cleanup:
+ ei_x_free(&result);
return retval;
}
-static int process_acct(ETERM *pid, ETERM *data)
+static int decode_binary(const char *buf, int *index, char **output)
+{
+ int type, size;
+ long len;
+
+ if (ei_get_type(buf, index, &type, &size) != 0) return -1;
+ if (type != ERL_BINARY_EXT) return -1;
+
+ *output = malloc(size+1);
+ if (*output == NULL) return -1;
+ if (ei_decode_binary(buf, index, *output, &len) != 0) {
+ free(*output);
+ return -1;
+ }
+ *(*output+len) = 0;
+ return 0;
+}
+
+static int process_acct(erlang_pid pid, erlang_ref ref, const char *buf, int index)
{
int retval = 0;
- ETERM *pattern, *srv, *user;
+ int arity;
char *service, *username;
- pattern = erl_format("{Srv, User}");
- if (erl_match(pattern, data))
- {
- srv = erl_var_content(pattern, "Srv");
- service = erl_iolist_to_string(srv);
- user = erl_var_content(pattern, "User");
- username = erl_iolist_to_string(user);
- retval = process_reply(pid, CMD_ACCT, acct_mgmt(service, username));
- erl_free_term(srv);
- erl_free_term(user);
- erl_free(service);
- erl_free(username);
- }
- erl_free_term(pattern);
+
+ if (ei_decode_tuple_header(buf, &index, &arity) != 0) return 0;
+ if (arity != 2) return 0;
+ if (decode_binary(buf, &index, &service) != 0) return 0;
+ if (decode_binary(buf, &index, &username) != 0) return 0;
+
+ retval = process_reply(pid, ref, CMD_ACCT, acct_mgmt(service, username));
+
+ free(service);
+ free(username);
+
return retval;
}
-static int process_auth(ETERM *pid, ETERM *data)
+static int process_auth(erlang_pid pid, erlang_ref ref, const char *buf, int index)
{
int retval = 0;
- ETERM *pattern, *srv, *user, *pass, *rhost;
+ int arity;
char *service, *username, *password, *remote_host;
- pattern = erl_format("{Srv, User, Pass, Rhost}");
- if (erl_match(pattern, data))
- {
- srv = erl_var_content(pattern, "Srv");
- service = erl_iolist_to_string(srv);
- user = erl_var_content(pattern, "User");
- username = erl_iolist_to_string(user);
- pass = erl_var_content(pattern, "Pass");
- password = erl_iolist_to_string(pass);
- rhost = erl_var_content(pattern, "Rhost");
- remote_host = erl_iolist_to_string(rhost);
- retval = process_reply(pid, CMD_AUTH, auth(service, username, password, remote_host));
- erl_free_term(srv);
- erl_free_term(user);
- erl_free_term(pass);
- erl_free(service);
- erl_free(username);
- erl_free(password);
- };
- erl_free_term(pattern);
+
+ if (ei_decode_tuple_header(buf, &index, &arity) != 0) return 0;
+ if (arity != 4) return 0;
+ if (decode_binary(buf, &index, &service) != 0) return 0;
+ if (decode_binary(buf, &index, &username) != 0) return 0;
+ if (decode_binary(buf, &index, &password) != 0) return 0;
+ if (decode_binary(buf, &index, &remote_host) != 0) return 0;
+
+ retval = process_reply(pid, ref, CMD_AUTH, auth(service, username, password, remote_host));
+
+ free(service);
+ free(username);
+ free(password);
+ free(remote_host);
+
return retval;
}
-static int process_command(byte *buf)
+static int process_command(const char *buf)
{
int retval = 0;
- ETERM *pattern, *tuple, *cmd, *port, *data;
- pattern = erl_format("{Cmd, Port, Data}");
- tuple = erl_decode(buf);
- if (erl_match(pattern, tuple))
+ int index = 0;
+ int version;
+ int arity;
+ char cmd;
+ erlang_pid pid;
+ erlang_ref ref;
+
+ if (ei_decode_version(buf, &index, &version) != 0) return 0;
+ if (ei_decode_tuple_header(buf, &index, &arity) != 0) return 0;
+ if (arity != 3) return 0;
+ if (ei_decode_char(buf, &index, &cmd) != 0) return 0;
+ if (ei_decode_tuple_header(buf, &index, &arity) != 0) return 0;
+ if (arity != 2) return 0;
+ if (ei_decode_pid(buf, &index, &pid) != 0) return 0;
+ if (ei_decode_ref(buf, &index, &ref) != 0) return 0;
+
+ switch (cmd)
{
- cmd = erl_var_content(pattern, "Cmd");
- port = erl_var_content(pattern, "Port");
- data = erl_var_content(pattern, "Data");
- switch (ERL_INT_VALUE(cmd))
- {
- case CMD_AUTH:
- retval = process_auth(port, data);
- break;
- case CMD_ACCT:
- retval = process_acct(port, data);
- break;
- };
- erl_free_term(cmd);
- erl_free_term(port);
- erl_free_term(data);
- }
- erl_free_term(pattern);
- erl_free_term(tuple);
+ case CMD_AUTH:
+ retval = process_auth(pid, ref, buf, index);
+ break;
+ case CMD_ACCT:
+ retval = process_acct(pid, ref, buf, index);
+ break;
+ };
+
return retval;
}
static void loop(void)
{
- byte buf[BUFSIZE];
+ const char buf[BUFSIZE];
int retval = 0;
do {
if (read_cmd(buf) > 0)
@@ -268,7 +282,6 @@ static void loop(void)
int main(int argc, char *argv[])
{
- erl_init(NULL, 0);
loop();
return 0;
}
diff --git a/rebar.config b/rebar.config
index 617c299..e1a0a3c 100644
--- a/rebar.config
+++ b/rebar.config
@@ -23,6 +23,7 @@
{erl_opts, [debug_info, {src_dirs, ["src"]}]}.
{port_env, [{"CFLAGS", "$CFLAGS"},
+ {"ERL_LDFLAGS", " -L$ERL_EI_LIBDIR -lei"},
{"LDFLAGS", "$LDFLAGS"}]}.
% {port_env, [{"EXE_LDFLAGS", "$ERL_LDFLAGS -lpthread -lpam"}]}.