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

Reply via email to