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"}]}.