aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSverker Eriksson <[email protected]>2019-04-17 19:09:57 +0200
committerSverker Eriksson <[email protected]>2019-04-17 19:09:57 +0200
commit236cb4b5eb3b89c837324a5ae7a11117d671d717 (patch)
tree41a090786155ab22d5c7a883c275c59d059a4ea0
parentdbe9bbfb801bcd92cc54c73ce96203b3a04c5517 (diff)
parent6a0deeae54ee18aa2028e994c33d633bb41021ed (diff)
downloadotp-236cb4b5eb3b89c837324a5ae7a11117d671d717.tar.gz
otp-236cb4b5eb3b89c837324a5ae7a11117d671d717.tar.bz2
otp-236cb4b5eb3b89c837324a5ae7a11117d671d717.zip
Merge branch 'sverker/bit-binary-ext/OTP-15712'
* sverker/bit-binary-ext/OTP-15712: jinterface: Add dist flag for export funs erl_interface: Add bitstring and export fun support erl_interface: Remove old r9 pid and port compatibility erl_interface: Refactor ei_decode_SUITE erl_interface: Fix maps arity from ei_get_type() erl_interface: Remove ei_get_type_internal() erl_interface: Deprecate ei_encode_term and ei_decode_term
-rw-r--r--lib/erl_interface/doc/src/ei.xml61
-rw-r--r--lib/erl_interface/include/ei.h40
-rw-r--r--lib/erl_interface/src/connect/ei_connect.c18
-rw-r--r--lib/erl_interface/src/connect/ei_connect_int.h2
-rw-r--r--lib/erl_interface/src/decode/decode_binary.c36
-rw-r--r--lib/erl_interface/src/decode/decode_fun.c98
-rw-r--r--lib/erl_interface/src/decode/decode_skip.c16
-rw-r--r--lib/erl_interface/src/encode/encode_binary.c24
-rw-r--r--lib/erl_interface/src/encode/encode_fun.c114
-rw-r--r--lib/erl_interface/src/legacy/erl_eterm.c14
-rw-r--r--lib/erl_interface/src/misc/ei_compat.c17
-rw-r--r--lib/erl_interface/src/misc/ei_decode_term.c8
-rw-r--r--lib/erl_interface/src/misc/ei_internal.h2
-rw-r--r--lib/erl_interface/src/misc/ei_printterm.c32
-rw-r--r--lib/erl_interface/src/misc/ei_x_encode.c10
-rw-r--r--lib/erl_interface/src/misc/get_type.c11
-rw-r--r--lib/erl_interface/src/misc/show_msg.c15
-rw-r--r--lib/erl_interface/src/prog/ei_fake_prog.c1
-rw-r--r--lib/erl_interface/src/registry/reg_dump.c2
-rw-r--r--lib/erl_interface/test/all_SUITE_data/ei_runner.h1
-rw-r--r--lib/erl_interface/test/ei_accept_SUITE.erl21
-rw-r--r--lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c22
-rw-r--r--lib/erl_interface/test/ei_connect_SUITE.erl5
-rw-r--r--lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c13
-rw-r--r--lib/erl_interface/test/ei_decode_SUITE.erl3
-rw-r--r--lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c193
-rw-r--r--lib/erl_interface/test/ei_decode_encode_SUITE.erl2
-rw-r--r--lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c31
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractNode.java3
-rw-r--r--lib/jinterface/test/nc_SUITE.erl3
30 files changed, 595 insertions, 223 deletions
diff --git a/lib/erl_interface/doc/src/ei.xml b/lib/erl_interface/doc/src/ei.xml
index f081ca926a..254ae27cc8 100644
--- a/lib/erl_interface/doc/src/ei.xml
+++ b/lib/erl_interface/doc/src/ei.xml
@@ -183,6 +183,35 @@ typedef enum {
</func>
<func>
+ <name since="OTP @OTP-15712@"><ret>int</ret><nametext>ei_decode_bitstring(const char *buf, int *index, void *p, size_t plen, size_t *bitsp)</nametext></name>
+ <fsummary>Decode a bitstring.</fsummary>
+ <desc>
+ <p>Decodes a bitstring from the binary format.</p>
+ <taglist>
+ <tag><c>p</c></tag>
+ <item><p>Either <c>NULL</c> or points to a buffer where the bytes of the
+ bitstring will be written.</p>
+ </item>
+ <tag><c>plen</c></tag>
+ <item><p>The max size of the bitstring in <em>bytes</em>, that is the
+ size of the buffer if <c>p != NULL</c>.</p>
+ </item>
+ <tag><c>*bitsp</c></tag>
+ <item><p>If <c>bitsp</c> is not <c>NULL</c>, set to the actual
+ number of <em>bits</em> of the bitstring.</p>
+ </item>
+ </taglist>
+ <p>Returns <c>0</c> if it was a bitstring no longer than <c>plen</c>
+ bytes. The actual length of the bitstring will be
+ <c>(*bitsp+7)/8</c> bytes. If <c>(*bitsp % 8) > 0</c> only the high
+ <c>(*bitsp % 8)</c> bits of the last byte are significant.</p>
+ <p>Number of bits may be divisible by 8, which means a binary
+ decodable by <c>ei_decode_binary</c> is also decodable by
+ <c>ei_decode_bitstring</c>.</p>
+ </desc>
+ </func>
+
+ <func>
<name since=""><ret>int</ret><nametext>ei_decode_boolean(const char *buf, int *index, int *p)</nametext></name>
<fsummary>Decode a boolean.</fsummary>
<desc>
@@ -349,8 +378,10 @@ typedef enum {
<c>t</c> is actually an <c>ETERM**</c> (see
<seealso marker="erl_eterm"><c>erl_eterm</c></seealso>).
The term is later to be deallocated.</p>
- <p>Notice that this function is located in the <c>Erl_Interface</c>
- library.</p>
+ <note><p>This function is deprecated as of OTP 22 and will be removed in
+ OTP 23 together with the old legacy <c>erl_interface</c> library (functions
+ with prefix <c>erl_</c>).</p>
+ </note>
</desc>
</func>
@@ -459,6 +490,18 @@ typedef enum {
</func>
<func>
+ <name since="OTP @OTP-15712@"><ret>int</ret><nametext>ei_encode_bitstring(char *buf, int *index, const void *p, size_t bits)</nametext></name>
+ <name since="OTP @OTP-15712@"><ret>int</ret><nametext>ei_x_encode_bitstring(ei_x_buff* x, const void *p, size_t bits)</nametext></name>
+ <fsummary>Encode a bitstring.</fsummary>
+ <desc>
+ <p>Encodes a bitstring in the binary format. The data is at
+ <c>p</c>. The size of the data is <c>bits</c> bits or
+ <c>(bits+7)/8</c> bytes. If <c>(bits%8) > 0</c> only the high
+ <c>(bits%8)</c> bits of the last byte are significant.</p>
+ </desc>
+ </func>
+
+ <func>
<name since=""><ret>int</ret><nametext>ei_encode_boolean(char *buf, int *index, int p)</nametext></name>
<name since=""><ret>int</ret><nametext>ei_x_encode_boolean(ei_x_buff* x, int p)</nametext></name>
<fsummary>Encode a boolean.</fsummary>
@@ -656,6 +699,10 @@ ei_x_encode_string(&amp;x, "Banana");</pre>
<c>erl_interface</c>. Parameter <c>t</c> is
actually an <c>ETERM</c> pointer. This function
does not free the <c>ETERM</c>.</p>
+ <note><p>These functions are deprecated as of OTP 22 and will be removed in
+ OTP 23 together with the old legacy <c>erl_interface</c> library
+ (functions with prefix <c>erl_</c>).</p>
+ </note>
</desc>
</func>
<func>
@@ -725,12 +772,12 @@ ei_encode_tuple_header(buf, &amp;i, 0);</pre>
<name since=""><ret>int</ret><nametext>ei_get_type(const char *buf, const int *index, int *type, int *size)</nametext></name>
<fsummary>Fetch the type and size of an encoded term.</fsummary>
<desc>
- <p>Returns the type in <c>type</c> and size in
- <c>size</c> of the encoded term. For strings and atoms,
+ <p>Returns the type in <c>*type</c> and size in
+ <c>*size</c> of the encoded term. For strings and atoms,
size is the number of characters <em>not</em> including the
- terminating <c>NULL</c>. For binaries, <c>size</c> is the number of
- bytes. For lists and tuples, <c>size</c> is the arity of
- the object. For other types, <c>size</c> is 0. In all
+ terminating <c>NULL</c>. For binaries and bitstrings, <c>*size</c> is
+ the number of bytes. For lists, tuples and maps, <c>*size</c> is the
+ arity of the object. For other types, <c>*size</c> is 0. In all
cases, <c>index</c> is left unchanged.</p>
</desc>
</func>
diff --git a/lib/erl_interface/include/ei.h b/lib/erl_interface/include/ei.h
index aa2a49098f..591367dc95 100644
--- a/lib/erl_interface/include/ei.h
+++ b/lib/erl_interface/include/ei.h
@@ -154,11 +154,14 @@ typedef LONG_PTR ssize_t; /* Sigh... */
#define ERL_STRING_EXT 'k'
#define ERL_LIST_EXT 'l'
#define ERL_BINARY_EXT 'm'
+#define ERL_BIT_BINARY_EXT 'M'
#define ERL_SMALL_BIG_EXT 'n'
#define ERL_LARGE_BIG_EXT 'o'
#define ERL_NEW_FUN_EXT 'p'
#define ERL_MAP_EXT 't'
#define ERL_FUN_EXT 'u'
+#define ERL_EXPORT_EXT 'q'
+
#define ERL_NEW_CACHE 'N' /* c nodes don't know these two */
#define ERL_CACHED_ATOM 'C'
@@ -269,15 +272,23 @@ typedef struct {
typedef struct {
long arity;
char module[MAXATOMLEN_UTF8];
- erlang_char_encoding module_org_enc;
- char md5[16];
- long index;
- long old_index;
- long uniq;
- long n_free_vars;
- erlang_pid pid;
- long free_var_len;
- char* free_vars;
+ enum { EI_FUN_CLOSURE, EI_FUN_EXPORT } type;
+ union {
+ struct {
+ char md5[16];
+ long index;
+ long old_index;
+ long uniq;
+ long n_free_vars;
+ erlang_pid pid;
+ long free_var_len;
+ char* free_vars;
+ } closure;
+ struct {
+ char* func;
+ int func_allocated;
+ } export;
+ } u;
} erlang_fun;
/* a big */
@@ -515,7 +526,9 @@ int ei_x_encode_atom_len(ei_x_buff* x, const char* s, int len);
int ei_x_encode_atom_len_as(ei_x_buff* x, const char* s, int len,
erlang_char_encoding from, erlang_char_encoding to);
int ei_encode_binary(char *buf, int *index, const void *p, long len);
+int ei_encode_bitstring(char *buf, int *index, const void *p, size_t bits);
int ei_x_encode_binary(ei_x_buff* x, const void* s, int len);
+int ei_x_encode_bitstring(ei_x_buff* x, const void* p, size_t bits);
int ei_encode_pid(char *buf, int *index, const erlang_pid *p);
int ei_x_encode_pid(ei_x_buff* x, const erlang_pid* pid);
int ei_encode_fun(char* buf, int* index, const erlang_fun* p);
@@ -524,8 +537,8 @@ int ei_encode_port(char *buf, int *index, const erlang_port *p);
int ei_x_encode_port(ei_x_buff* x, const erlang_port *p);
int ei_encode_ref(char *buf, int *index, const erlang_ref *p);
int ei_x_encode_ref(ei_x_buff* x, const erlang_ref *p);
-int ei_encode_term(char *buf, int *index, void *t); /* ETERM* actually */
-int ei_x_encode_term(ei_x_buff* x, void* t);
+int ei_encode_term(char *buf, int *index, void *t) EI_DEPRECATED_ATTR;
+int ei_x_encode_term(ei_x_buff* x, void* t) EI_DEPRECATED_ATTR;
int ei_encode_trace(char *buf, int *index, const erlang_trace *p);
int ei_x_encode_trace(ei_x_buff* x, const erlang_trace *p);
int ei_encode_tuple_header(char *buf, int *index, int arity);
@@ -547,8 +560,6 @@ int ei_x_encode_map_header(ei_x_buff* x, long n);
*/
int ei_get_type(const char *buf, const int *index, int *type, int *size);
-int ei_get_type_internal(const char *buf, const int *index, int *type,
- int *size);
/* Step through buffer, decoding the given type into the buffer
* provided. On success, 0 is returned and index is updated to point
@@ -567,12 +578,13 @@ int ei_decode_string(const char *buf, int *index, char *p);
int ei_decode_atom(const char *buf, int *index, char *p);
int ei_decode_atom_as(const char *buf, int *index, char *p, int destlen, erlang_char_encoding want, erlang_char_encoding* was, erlang_char_encoding* result);
int ei_decode_binary(const char *buf, int *index, void *p, long *len);
+int ei_decode_bitstring(const char *buf, int *index, void *p, size_t plen, size_t *bitsp);
int ei_decode_fun(const char* buf, int* index, erlang_fun* p);
void free_fun(erlang_fun* f);
int ei_decode_pid(const char *buf, int *index, erlang_pid *p);
int ei_decode_port(const char *buf, int *index, erlang_port *p);
int ei_decode_ref(const char *buf, int *index, erlang_ref *p);
-int ei_decode_term(const char *buf, int *index, void *t); /* ETERM** actually */
+int ei_decode_term(const char *buf, int *index, void *t) EI_DEPRECATED_ATTR;
int ei_decode_trace(const char *buf, int *index, erlang_trace *p);
int ei_decode_tuple_header(const char *buf, int *index, int *arity);
int ei_decode_list_header(const char *buf, int *index, int *arity);
diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c
index 7a304e6d4f..0cbad235cc 100644
--- a/lib/erl_interface/src/connect/ei_connect.c
+++ b/lib/erl_interface/src/connect/ei_connect.c
@@ -1846,6 +1846,7 @@ static int send_name_or_challenge(ei_socket_callbacks *cbs,
const char* function[] = {"SEND_NAME", "SEND_CHALLENGE"};
int err;
ssize_t len;
+ unsigned int flags;
if (f_chall)
siz += 4;
@@ -1867,7 +1868,7 @@ static int send_name_or_challenge(ei_socket_callbacks *cbs,
}
put8(s, 'n');
put16be(s, version);
- put32be(s, (DFLAG_EXTENDED_REFERENCES
+ flags = (DFLAG_EXTENDED_REFERENCES
| DFLAG_DIST_MONITOR
| DFLAG_EXTENDED_PIDS_PORTS
| DFLAG_FUN_TAGS
@@ -1876,7 +1877,14 @@ static int send_name_or_challenge(ei_socket_callbacks *cbs,
| DFLAG_SMALL_ATOM_TAGS
| DFLAG_UTF8_ATOMS
| DFLAG_MAP_TAG
- | DFLAG_BIG_CREATION));
+ | DFLAG_BIG_CREATION
+ | DFLAG_EXPORT_PTR_TAG
+ | DFLAG_BIT_BINARIES);
+ if (ei_internal_use_21_bitstr_expfun()) {
+ flags &= ~(DFLAG_EXPORT_PTR_TAG
+ | DFLAG_BIT_BINARIES);
+ }
+ put32be(s, flags);
if (f_chall)
put32be(s, challenge);
memcpy(s, nodename, strlen(nodename));
@@ -1941,8 +1949,7 @@ static int recv_challenge(ei_socket_callbacks *cbs, void *ctx,
goto error;
}
- if (!(*flags & DFLAG_EXTENDED_PIDS_PORTS)
- && !ei_internal_use_r9_pids_ports()) {
+ if (!(*flags & DFLAG_EXTENDED_PIDS_PORTS)) {
EI_TRACE_ERR0("recv_challenge","<- RECV_CHALLENGE peer cannot "
"handle extended pids and ports");
erl_errno = EIO;
@@ -2236,8 +2243,7 @@ static int recv_name(ei_socket_callbacks *cbs, void *ctx,
goto error;
}
- if (!(*flags & DFLAG_EXTENDED_PIDS_PORTS)
- && !ei_internal_use_r9_pids_ports()) {
+ if (!(*flags & DFLAG_EXTENDED_PIDS_PORTS)) {
EI_TRACE_ERR0("recv_name","<- RECV_NAME peer cannot "
"handle extended pids and ports");
erl_errno = EIO;
diff --git a/lib/erl_interface/src/connect/ei_connect_int.h b/lib/erl_interface/src/connect/ei_connect_int.h
index 0bcccaa84b..b41a5f2b23 100644
--- a/lib/erl_interface/src/connect/ei_connect_int.h
+++ b/lib/erl_interface/src/connect/ei_connect_int.h
@@ -102,6 +102,8 @@ extern int h_errno;
#define DFLAG_FUN_TAGS 16
#define DFLAG_NEW_FUN_TAGS 0x80
#define DFLAG_EXTENDED_PIDS_PORTS 0x100
+#define DFLAG_EXPORT_PTR_TAG 0x200
+#define DFLAG_BIT_BINARIES 0x400
#define DFLAG_NEW_FLOATS 0x800
#define DFLAG_SMALL_ATOM_TAGS 0x4000
#define DFLAG_UTF8_ATOMS 0x10000
diff --git a/lib/erl_interface/src/decode/decode_binary.c b/lib/erl_interface/src/decode/decode_binary.c
index 5b8d234984..2799438bef 100644
--- a/lib/erl_interface/src/decode/decode_binary.c
+++ b/lib/erl_interface/src/decode/decode_binary.c
@@ -40,4 +40,40 @@ int ei_decode_binary(const char *buf, int *index, void *p, long *lenp)
return 0;
}
+int ei_decode_bitstring(const char *buf, int *index, void *p, size_t plen,
+ size_t *bitsp)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+ unsigned long len;
+ unsigned char last_bits;
+ const unsigned char tag = get8(s);
+
+ if (tag == ERL_BINARY_EXT) {
+ long bytes;
+ int ret = ei_decode_binary(buf, index, p, &bytes);
+ if (bitsp)
+ *bitsp = (size_t)bytes * 8;
+ return ret;
+ }
+
+ if (tag != ERL_BIT_BINARY_EXT)
+ return -1;
+
+ len = get32be(s);
+ last_bits = get8(s);
+
+ if (len > plen || ((last_bits==0) != (len==0)) || last_bits > 8)
+ return -1;
+
+ if (p)
+ memcpy(p, s, len);
+ s += len;
+
+ if (bitsp)
+ *bitsp = (len == 0) ? 0 : ((len-1) * 8) + last_bits;
+
+ *index += s-s0;
+ return 0;
+}
diff --git a/lib/erl_interface/src/decode/decode_fun.c b/lib/erl_interface/src/decode/decode_fun.c
index f944c028af..32a950433e 100644
--- a/lib/erl_interface/src/decode/decode_fun.c
+++ b/lib/erl_interface/src/decode/decode_fun.c
@@ -33,22 +33,20 @@ int ei_decode_fun(const char *buf, int *index, erlang_fun *p)
int i, ix, ix0, n;
erlang_pid* p_pid;
char* p_module;
- erlang_char_encoding* p_module_org_enc;
long* p_index;
long* p_uniq;
long* p_old_index;
if (p != NULL) {
- p_pid = &p->pid;
+ p_pid = &p->u.closure.pid;
p_module = &p->module[0];
- p_module_org_enc = &p->module_org_enc;
- p_index = &p->index;
- p_uniq = &p->uniq;
- p_old_index = &p->old_index;
+ p_index = &p->u.closure.index;
+ p_uniq = &p->u.closure.uniq;
+ p_old_index = &p->u.closure.old_index;
}
else {
- p_pid = NULL; p_module = NULL; p_module_org_enc = NULL;
p_index = NULL; p_uniq = NULL; p_old_index = NULL;
+ p_pid = NULL; p_module = NULL;
}
switch (get8(s)) {
@@ -63,7 +61,7 @@ int ei_decode_fun(const char *buf, int *index, erlang_fun *p)
return -1;
/* then the module (atom) */
if (ei_decode_atom_as(s, &ix, p_module, MAXATOMLEN_UTF8, ERLANG_UTF8,
- p_module_org_enc, NULL) < 0)
+ NULL, NULL) < 0)
return -1;
/* then the index */
if (ei_decode_long(s, &ix, p_index) < 0)
@@ -78,11 +76,11 @@ int ei_decode_fun(const char *buf, int *index, erlang_fun *p)
return -1;
}
if (p != NULL) {
- p->n_free_vars = n;
- p->free_var_len = ix - ix0;
- p->free_vars = ei_malloc(ix - ix0);
- if (!(p->free_vars)) return -1;
- memcpy(p->free_vars, s + ix0, ix - ix0);
+ p->u.closure.n_free_vars = n;
+ p->u.closure.free_var_len = ix - ix0;
+ p->u.closure.free_vars = ei_malloc(ix - ix0);
+ if (!(p->u.closure.free_vars)) return -1;
+ memcpy(p->u.closure.free_vars, s + ix0, ix - ix0);
}
s += ix;
*index += s-s0;
@@ -93,20 +91,23 @@ int ei_decode_fun(const char *buf, int *index, erlang_fun *p)
n = get32be(s);
/* then the arity */
i = get8(s);
- if (p != NULL) p->arity = i;
- /* then md5 */
- if (p != NULL) memcpy(p->md5, s, 16);
+ if (p != NULL) {
+ p->type = EI_FUN_CLOSURE;
+ p->arity = i;
+ /* then md5 */
+ memcpy(p->u.closure.md5, s, 16);
+ }
s += 16;
/* then index */
i = get32be(s);
- if (p != NULL) p->index = i;
+ if (p != NULL) p->u.closure.index = i;
/* then the number of free vars (environment) */
i = get32be(s);
- if (p != NULL) p->n_free_vars = i;
+ if (p != NULL) p->u.closure.n_free_vars = i;
/* then the module (atom) */
ix = 0;
if (ei_decode_atom_as(s, &ix, p_module, MAXATOMLEN_UTF8, ERLANG_UTF8,
- p_module_org_enc, NULL) < 0)
+ NULL, NULL) < 0)
return -1;
/* then the old_index */
if (ei_decode_long(s, &ix, p_old_index) < 0)
@@ -122,17 +123,56 @@ int ei_decode_fun(const char *buf, int *index, erlang_fun *p)
n = n - (s - s0) + 1;
if (n < 0) return -1;
if (p != NULL) {
- p->free_var_len = n;
+ p->u.closure.free_var_len = n;
if (n > 0) {
- p->free_vars = malloc(n);
- if (!(p->free_vars)) return -1;
- memcpy(p->free_vars, s, n);
+ p->u.closure.free_vars = malloc(n);
+ if (!(p->u.closure.free_vars)) return -1;
+ memcpy(p->u.closure.free_vars, s, n);
}
}
s += n;
*index += s-s0;
return 0;
break;
+ case ERL_EXPORT_EXT: {
+ char* p_func;
+ long* p_arity;
+ int used;
+
+ if (p) {
+ p->type = EI_FUN_EXPORT;
+ p_arity = &p->arity;
+ }
+ else {
+ p_arity = NULL;
+ }
+ if (ei_decode_atom_as(s, &ix, p_module, MAXATOMLEN_UTF8, ERLANG_UTF8,
+ NULL, NULL) < 0)
+ return -1;
+ if (p) {
+ /* try use module buffer for function name */
+ used = strlen(p->module) + 1;
+ p_func = p->module + used;
+ p->u.export.func = p_func;
+ p->u.export.func_allocated = 0;
+ }
+ else {
+ used = 0;
+ p_func = NULL;
+ }
+ while (ei_decode_atom_as(s, &ix, p_func, MAXATOMLEN_UTF8-used,
+ ERLANG_UTF8, NULL, NULL) < 0) {
+ if (!used)
+ return -1;
+ p_func = malloc(MAXATOMLEN_UTF8);
+ p->u.export.func = p_func;
+ p->u.export.func_allocated = 1;
+ used = 0;
+ }
+ if (ei_decode_long(s, &ix, p_arity) < 0)
+ return -1;
+ return 0;
+ }
default:
return -1;
}
@@ -140,6 +180,14 @@ int ei_decode_fun(const char *buf, int *index, erlang_fun *p)
void free_fun(erlang_fun* f)
{
- if (f->free_var_len > 0)
- ei_free(f->free_vars);
+ switch (f->type) {
+ case EI_FUN_CLOSURE:
+ if (f->u.closure.free_var_len > 0)
+ ei_free(f->u.closure.free_vars);
+ break;
+ case EI_FUN_EXPORT:
+ if (f->u.export.func_allocated)
+ ei_free(f->u.export.func);
+ break;
+ }
}
diff --git a/lib/erl_interface/src/decode/decode_skip.c b/lib/erl_interface/src/decode/decode_skip.c
index 0db315f09b..11d3bc1786 100644
--- a/lib/erl_interface/src/decode/decode_skip.c
+++ b/lib/erl_interface/src/decode/decode_skip.c
@@ -21,13 +21,21 @@
#include "eiext.h"
#include "decode_skip.h"
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+#ifndef SIZE_MAX
+# define SIZE_MAX (~((size_t)0))
+#endif
+
int ei_skip_term(const char* buf, int* index)
{
int i, n, ty;
/* ASSERT(ep != NULL); */
- ei_get_type_internal(buf, index, &ty, &n);
+ ei_get_type(buf, index, &ty, &n);
switch (ty) {
case ERL_ATOM_EXT:
/* FIXME: what if some weird locale is in use? */
@@ -54,7 +62,7 @@ int ei_skip_term(const char* buf, int* index)
if (ei_decode_list_header(buf, index, &n) < 0) return -1;
for (i = 0; i < n; ++i)
ei_skip_term(buf, index);
- if (ei_get_type_internal(buf, index, &ty, &n) < 0) return -1;
+ if (ei_get_type(buf, index, &ty, &n) < 0) return -1;
if (ty != ERL_NIL_EXT)
ei_skip_term(buf, index);
else
@@ -79,6 +87,10 @@ int ei_skip_term(const char* buf, int* index)
if (ei_decode_binary(buf, index, NULL, NULL) < 0)
return -1;
break;
+ case ERL_BIT_BINARY_EXT:
+ if (ei_decode_bitstring(buf, index, NULL, SIZE_MAX, NULL) < 0)
+ return -1;
+ break;
case ERL_SMALL_INTEGER_EXT:
case ERL_INTEGER_EXT:
if (ei_decode_long(buf, index, NULL) < 0) return -1;
diff --git a/lib/erl_interface/src/encode/encode_binary.c b/lib/erl_interface/src/encode/encode_binary.c
index 4471c51769..4aa9f6bc16 100644
--- a/lib/erl_interface/src/encode/encode_binary.c
+++ b/lib/erl_interface/src/encode/encode_binary.c
@@ -40,3 +40,27 @@ int ei_encode_binary(char *buf, int *index, const void *p, long len)
return 0;
}
+int ei_encode_bitstring(char *buf, int *index, const void *p, size_t bits)
+{
+ char *s = buf + *index;
+ char *s0 = s;
+ size_t bytes = (bits + 7) / 8;
+ char last_bits = bits % 8;
+
+ if (bytes == 0 || last_bits == 0)
+ return ei_encode_binary(buf, index, p, bytes);
+
+ if (!buf) s += 6;
+ else {
+ put8(s, ERL_BIT_BINARY_EXT);
+ put32be(s, bytes);
+ put8(s, last_bits);
+ memcpy(s, p, bytes);
+ s[bytes-1] &= (0xff << (8-last_bits));
+ }
+ s += bytes;
+
+ *index += s-s0;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/encode/encode_fun.c b/lib/erl_interface/src/encode/encode_fun.c
index 3bfc7530d1..38ba7c5b30 100644
--- a/lib/erl_interface/src/encode/encode_fun.c
+++ b/lib/erl_interface/src/encode/encode_fun.c
@@ -26,56 +26,72 @@ int ei_encode_fun(char *buf, int *index, const erlang_fun *p)
{
int ix = *index;
- if (p->arity == -1) {
- /* ERL_FUN_EXT */
- if (buf != NULL) {
- char* s = buf + ix;
- put8(s, ERL_FUN_EXT);
- put32be(s, p->n_free_vars);
- }
- ix += sizeof(char) + 4;
- if (ei_encode_pid(buf, &ix, &p->pid) < 0)
- return -1;
- if (ei_encode_atom_as(buf, &ix, p->module, ERLANG_UTF8, p->module_org_enc) < 0)
- return -1;
- if (ei_encode_long(buf, &ix, p->index) < 0)
- return -1;
- if (ei_encode_long(buf, &ix, p->uniq) < 0)
- return -1;
- if (buf != NULL)
- memcpy(buf + ix, p->free_vars, p->free_var_len);
- ix += p->free_var_len;
- } else {
- char *size_p;
- /* ERL_NEW_FUN_EXT */
- if (buf != NULL) {
- char* s = buf + ix;
- put8(s, ERL_NEW_FUN_EXT);
- size_p = s;
- s += 4;
- put8(s, p->arity);
- memcpy(s, p->md5, sizeof(p->md5));
- s += sizeof(p->md5);
- put32be(s, p->index);
- put32be(s, p->n_free_vars);
- } else
- size_p = NULL;
- ix += 1 + 4 + 1 + sizeof(p->md5) + 4 + 4;
- if (ei_encode_atom_as(buf, &ix, p->module, ERLANG_UTF8, p->module_org_enc) < 0)
- return -1;
- if (ei_encode_long(buf, &ix, p->old_index) < 0)
- return -1;
- if (ei_encode_long(buf, &ix, p->uniq) < 0)
- return -1;
- if (ei_encode_pid(buf, &ix, &p->pid) < 0)
- return -1;
- if (buf != NULL)
- memcpy(buf + ix, p->free_vars, p->free_var_len);
- ix += p->free_var_len;
- if (size_p != NULL) {
- int sz = buf + ix - size_p;
- put32be(size_p, sz);
+ switch (p->type) {
+ case EI_FUN_CLOSURE:
+ if (p->arity == -1) {
+ /* ERL_FUN_EXT */
+ if (buf != NULL) {
+ char* s = buf + ix;
+ put8(s, ERL_FUN_EXT);
+ put32be(s, p->u.closure.n_free_vars);
+ }
+ ix += sizeof(char) + 4;
+ if (ei_encode_pid(buf, &ix, &p->u.closure.pid) < 0)
+ return -1;
+ if (ei_encode_atom_as(buf, &ix, p->module, ERLANG_UTF8, ERLANG_UTF8) < 0)
+ return -1;
+ if (ei_encode_long(buf, &ix, p->u.closure.index) < 0)
+ return -1;
+ if (ei_encode_long(buf, &ix, p->u.closure.uniq) < 0)
+ return -1;
+ if (buf != NULL)
+ memcpy(buf + ix, p->u.closure.free_vars, p->u.closure.free_var_len);
+ ix += p->u.closure.free_var_len;
+ } else {
+ char *size_p;
+ if (buf != NULL) {
+ char* s = buf + ix;
+ put8(s, ERL_NEW_FUN_EXT);
+ size_p = s;
+ s += 4;
+ put8(s, p->arity);
+ memcpy(s, p->u.closure.md5, sizeof(p->u.closure.md5));
+ s += sizeof(p->u.closure.md5);
+ put32be(s, p->u.closure.index);
+ put32be(s, p->u.closure.n_free_vars);
+ } else
+ size_p = NULL;
+ ix += 1 + 4 + 1 + sizeof(p->u.closure.md5) + 4 + 4;
+ if (ei_encode_atom_as(buf, &ix, p->module, ERLANG_UTF8, ERLANG_UTF8) < 0)
+ return -1;
+ if (ei_encode_long(buf, &ix, p->u.closure.old_index) < 0)
+ return -1;
+ if (ei_encode_long(buf, &ix, p->u.closure.uniq) < 0)
+ return -1;
+ if (ei_encode_pid(buf, &ix, &p->u.closure.pid) < 0)
+ return -1;
+ if (buf != NULL)
+ memcpy(buf + ix, p->u.closure.free_vars, p->u.closure.free_var_len);
+ ix += p->u.closure.free_var_len;
+ if (size_p != NULL) {
+ int sz = buf + ix - size_p;
+ put32be(size_p, sz);
+ }
}
+ break;
+ case EI_FUN_EXPORT:
+ if (buf != NULL) {
+ char* s = buf + ix;
+ put8(s, ERL_EXPORT_EXT);
+ }
+ ix++;
+ if (ei_encode_atom_as(buf, &ix, p->module, ERLANG_UTF8, ERLANG_UTF8) < 0)
+ return -1;
+ if (ei_encode_atom_as(buf, &ix, p->u.export.func, ERLANG_UTF8, ERLANG_UTF8) < 0)
+ return -1;
+ if (ei_encode_long(buf, &ix, p->arity) < 0)
+ return -1;
+ break;
}
*index = ix;
return 0;
diff --git a/lib/erl_interface/src/legacy/erl_eterm.c b/lib/erl_interface/src/legacy/erl_eterm.c
index 7ed2bdbc93..7ecea83b1a 100644
--- a/lib/erl_interface/src/legacy/erl_eterm.c
+++ b/lib/erl_interface/src/legacy/erl_eterm.c
@@ -299,12 +299,7 @@ void erl_mk_pid_helper(ETERM *ep, unsigned int number,
unsigned int serial, unsigned int creation)
{
ERL_PID_NUMBER(ep) = number & 0x7fff; /* 15 bits */
- if (ei_internal_use_r9_pids_ports()) {
- ERL_PID_SERIAL(ep) = serial & 0x07; /* 3 bits */
- }
- else {
- ERL_PID_SERIAL(ep) = serial & 0x1fff; /* 13 bits */
- }
+ ERL_PID_SERIAL(ep) = serial & 0x1fff; /* 13 bits */
ERL_PID_CREATION(ep) = creation; /* 32 bits */
}
@@ -334,12 +329,7 @@ ETERM *erl_mk_port(const char *node,
void erl_mk_port_helper(ETERM* ep, unsigned number, unsigned int creation)
{
- if (ei_internal_use_r9_pids_ports()) {
- ERL_PORT_NUMBER(ep) = number & 0x3ffff; /* 18 bits */
- }
- else {
- ERL_PORT_NUMBER(ep) = number & 0x0fffffff; /* 18 bits */
- }
+ ERL_PORT_NUMBER(ep) = number & 0x0fffffff; /* 18 bits */
ERL_PORT_CREATION(ep) = creation; /* 32 bits */
}
diff --git a/lib/erl_interface/src/misc/ei_compat.c b/lib/erl_interface/src/misc/ei_compat.c
index 93d7dbfb83..787895992e 100644
--- a/lib/erl_interface/src/misc/ei_compat.c
+++ b/lib/erl_interface/src/misc/ei_compat.c
@@ -22,19 +22,22 @@
#include "ei.h"
#include "ei_internal.h"
-#define EI_COMPAT_NO_REL (~((unsigned) 0))
+#include <limits.h>
-static unsigned compat_rel = EI_COMPAT_NO_REL;
+#ifndef EI_COMPAT
+# define EI_COMPAT UINT_MAX
+#endif
+
+static unsigned compat_rel = EI_COMPAT;
void
ei_set_compat_rel(unsigned rel)
{
- if (compat_rel == EI_COMPAT_NO_REL)
- compat_rel = rel;
+ compat_rel = rel;
}
-int
-ei_internal_use_r9_pids_ports(void)
+int ei_internal_use_21_bitstr_expfun(void)
{
- return compat_rel < 10;
+ return compat_rel < 22;
}
+
diff --git a/lib/erl_interface/src/misc/ei_decode_term.c b/lib/erl_interface/src/misc/ei_decode_term.c
index 63a7034508..8a4f7cc30d 100644
--- a/lib/erl_interface/src/misc/ei_decode_term.c
+++ b/lib/erl_interface/src/misc/ei_decode_term.c
@@ -87,6 +87,14 @@ int ei_decode_ei_term(const char* buf, int* index, ei_term* term)
case ERL_BINARY_EXT:
term->size = get32be(s);
return 0;
+ case ERL_BIT_BINARY_EXT: {
+ int bytes = get32be(s);
+ int last_bits = get8(s);
+ if (((last_bits==0) != (bytes==0)) || last_bits > 8)
+ return -1;
+ term->size = bytes;
+ return 0;
+ }
case ERL_SMALL_BIG_EXT:
if ((term->arity = get8(s)) != 4) return -1;
sign = get8(s);
diff --git a/lib/erl_interface/src/misc/ei_internal.h b/lib/erl_interface/src/misc/ei_internal.h
index f28dd6d668..ab12597c86 100644
--- a/lib/erl_interface/src/misc/ei_internal.h
+++ b/lib/erl_interface/src/misc/ei_internal.h
@@ -157,7 +157,7 @@ int ei_init_connect(void);
void ei_trace_printf(const char *name, int level, const char *format, ...);
-int ei_internal_use_r9_pids_ports(void);
+int ei_internal_use_21_bitstr_expfun(void);
int ei_get_cbs_ctx__(ei_socket_callbacks **cbs, void **ctx, int fd);
diff --git a/lib/erl_interface/src/misc/ei_printterm.c b/lib/erl_interface/src/misc/ei_printterm.c
index 058de00de5..a89b990ac1 100644
--- a/lib/erl_interface/src/misc/ei_printterm.c
+++ b/lib/erl_interface/src/misc/ei_printterm.c
@@ -131,7 +131,7 @@ static int print_term(FILE* fp, ei_x_buff* x,
if (fp == NULL && x == NULL) return -1;
doquote = 0;
- ei_get_type_internal(buf, index, &ty, &n);
+ ei_get_type(buf, index, &ty, &n);
switch (ty) {
case ERL_ATOM_EXT:
case ERL_ATOM_UTF8_EXT:
@@ -189,7 +189,7 @@ static int print_term(FILE* fp, ei_x_buff* x,
xputs(", ", fp, x); ch_written += 2;
}
}
- if (ei_get_type_internal(buf, &tindex, &ty, &n) < 0) goto err;
+ if (ei_get_type(buf, &tindex, &ty, &n) < 0) goto err;
if (ty != ERL_NIL_EXT) {
xputs(" | ", fp, x); ch_written += 3;
r = print_term(fp, x, buf, &tindex);
@@ -249,6 +249,34 @@ static int print_term(FILE* fp, ei_x_buff* x,
xputc('>', fp, x); ++ch_written;
ei_free(p);
break;
+ case ERL_BIT_BINARY_EXT: {
+ size_t bits;
+ int trunc = 0;
+ p = ei_malloc(n);
+ if (p == NULL) goto err;
+ if (ei_decode_bitstring(buf, index, p, n, &bits) < 0) {
+ ei_free(p);
+ goto err;
+ }
+ ch_written += xprintf(fp, x, "#Bits<");
+ m = (bits+7) / 8;
+ if (m > BINPRINTSIZE) {
+ m = BINPRINTSIZE;
+ trunc = 1;
+ }
+ --m;
+ for (i = 0; i < m; ++i) {
+ ch_written += xprintf(fp, x, "%d,", p[i]);
+ }
+ ch_written += xprintf(fp, x, "%d", p[i]);
+ if (trunc)
+ ch_written += xprintf(fp, x, ",...");
+ else if (bits % 8 != 0)
+ ch_written += xprintf(fp, x, ":%u", (unsigned)(bits % 8));
+ xputc('>', fp, x); ++ch_written;
+ ei_free(p);
+ break;
+ }
case ERL_SMALL_INTEGER_EXT:
case ERL_INTEGER_EXT:
if (ei_decode_long(buf, index, &l) < 0) goto err;
diff --git a/lib/erl_interface/src/misc/ei_x_encode.c b/lib/erl_interface/src/misc/ei_x_encode.c
index 4ff5974663..2da271795f 100644
--- a/lib/erl_interface/src/misc/ei_x_encode.c
+++ b/lib/erl_interface/src/misc/ei_x_encode.c
@@ -117,6 +117,16 @@ int ei_x_encode_binary(ei_x_buff* x, const void* p, int len)
return ei_encode_binary(x->buff, &x->index, p, len);
}
+int ei_x_encode_bitstring(ei_x_buff* x, const void* p, size_t bits)
+{
+ int i = x->index;
+ if (ei_encode_bitstring(NULL, &i, p, bits) == -1)
+ return -1;
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_bitstring(x->buff, &x->index, p, bits);
+}
+
int ei_x_encode_long(ei_x_buff* x, long n)
{
int i = x->index;
diff --git a/lib/erl_interface/src/misc/get_type.c b/lib/erl_interface/src/misc/get_type.c
index aa69cd4d60..eef58a9363 100644
--- a/lib/erl_interface/src/misc/get_type.c
+++ b/lib/erl_interface/src/misc/get_type.c
@@ -27,17 +27,8 @@
/* for types with meaningful length attributes, return the length too.
In other cases, return length 0 */
-/* FIXME working on this one.... */
-
int ei_get_type(const char *buf, const int *index, int *type, int *len)
{
- return ei_get_type_internal(buf, index, type, len);
-}
-
-
-int ei_get_type_internal(const char *buf, const int *index,
- int *type, int *len)
-{
const char *s = buf + *index;
*type = get8(s);
@@ -64,7 +55,9 @@ int ei_get_type_internal(const char *buf, const int *index,
case ERL_LARGE_TUPLE_EXT:
case ERL_LIST_EXT:
+ case ERL_MAP_EXT:
case ERL_BINARY_EXT:
+ case ERL_BIT_BINARY_EXT:
*len = get32be(s);
break;
diff --git a/lib/erl_interface/src/misc/show_msg.c b/lib/erl_interface/src/misc/show_msg.c
index 5868cccba6..2d49eb6449 100644
--- a/lib/erl_interface/src/misc/show_msg.c
+++ b/lib/erl_interface/src/misc/show_msg.c
@@ -24,6 +24,13 @@
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+#ifndef SIZE_MAX
+# define SIZE_MAX (~((size_t)0))
+#endif
#include <sys/types.h>
@@ -342,7 +349,7 @@ static void show_term(const char *termbuf, int *index, FILE *stream)
int i, len;
char *s;
- ei_get_type_internal(termbuf,index,&type,&len);
+ ei_get_type(termbuf,index,&type,&len);
switch (type) {
case ERL_VERSION_MAGIC:
@@ -455,6 +462,12 @@ static void show_term(const char *termbuf, int *index, FILE *stream)
fprintf(stream,"#Bin<%ld>",num);
break;
+ case ERL_BIT_BINARY_EXT: {
+ size_t bits;
+ ei_decode_bitstring(termbuf, index, NULL, SIZE_MAX, &bits);
+ fprintf(stream, "#Bits<%lu>", (unsigned long)bits);
+ break;
+ }
case ERL_LARGE_BIG_EXT:
/* doesn't actually decode - just skip over it */
/* FIXME if GMP, what to do here?? */
diff --git a/lib/erl_interface/src/prog/ei_fake_prog.c b/lib/erl_interface/src/prog/ei_fake_prog.c
index 158464b385..6f58c9833d 100644
--- a/lib/erl_interface/src/prog/ei_fake_prog.c
+++ b/lib/erl_interface/src/prog/ei_fake_prog.c
@@ -186,7 +186,6 @@ int main(void)
ei_x_encode_empty_list(&eix);
ei_get_type(charp, intp, intp, intp);
- ei_get_type_internal(charp, intp, intp, intp);
ei_decode_version(charp, intp, intp);
ei_decode_long(charp, intp, longp);
diff --git a/lib/erl_interface/src/registry/reg_dump.c b/lib/erl_interface/src/registry/reg_dump.c
index 43c9824433..da0413e6e6 100644
--- a/lib/erl_interface/src/registry/reg_dump.c
+++ b/lib/erl_interface/src/registry/reg_dump.c
@@ -90,7 +90,7 @@ static int mn_start_dump(int fd, const erlang_pid *self,
|| (arity != 2)
|| ei_decode_atom(buf,&index,tmpbuf)
|| strcmp(tmpbuf,"rex")
- || ei_get_type_internal(buf,&index,&type,&arity)
+ || ei_get_type(buf,&index,&type,&arity)
|| (type != ERL_PID_EXT))
return -1; /* bad response from other side */
diff --git a/lib/erl_interface/test/all_SUITE_data/ei_runner.h b/lib/erl_interface/test/all_SUITE_data/ei_runner.h
index 2608661303..7c874ac82e 100644
--- a/lib/erl_interface/test/all_SUITE_data/ei_runner.h
+++ b/lib/erl_interface/test/all_SUITE_data/ei_runner.h
@@ -53,6 +53,7 @@ void free_packet(char*);
#define fail(reason) do_fail(__FILE__, __LINE__, reason)
#define fail1(reason, a1) do_fail(__FILE__, __LINE__, reason, a1)
+#define fail2(reason, a1, a2) do_fail(__FILE__, __LINE__, reason, a1, a2)
#define report(ok) do_report(__FILE__, __LINE__, ok)
void do_report(char* file, int line, int ok);
diff --git a/lib/erl_interface/test/ei_accept_SUITE.erl b/lib/erl_interface/test/ei_accept_SUITE.erl
index 9c9c3f86b6..f40c67375b 100644
--- a/lib/erl_interface/test/ei_accept_SUITE.erl
+++ b/lib/erl_interface/test/ei_accept_SUITE.erl
@@ -43,8 +43,12 @@ init_per_testcase(Case, Config) ->
runner:init_per_testcase(?MODULE, Case, Config).
ei_accept(Config) when is_list(Config) ->
+ ei_accept_do(Config, 0), % default
+ ei_accept_do(Config, 21). % ei_set_compat_rel
+
+ei_accept_do(Config, CompatRel) ->
P = runner:start(Config, ?interpret),
- 0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
+ 0 = ei_connect_init(P, 42, erlang:get_cookie(), 0, CompatRel),
Myname = hd(tl(string:tokens(atom_to_list(node()), "@"))),
io:format("Myname ~p ~n", [Myname]),
@@ -52,15 +56,18 @@ ei_accept(Config) when is_list(Config) ->
io:format("EINode ~p ~n", [EINode]),
%% We take this opportunity to also test export-funs and bit-strings
- %% with (ugly) tuple fallbacks.
+ %% with (ugly) tuple fallbacks in OTP 21 and older.
%% Test both toward pending connection and established connection.
RealTerms = [<<1:1>>, fun lists:map/2],
- Fallbacks = [{<<128>>,1}, {lists,map}],
+ EncTerms = case CompatRel of
+ 0 -> RealTerms;
+ 21 -> [{<<128>>,1}, {lists,map}]
+ end,
Self = self(),
Funny = fun() -> hello end,
TermToSend = {call, Self, "Test", Funny, RealTerms},
- TermToGet = {call, Self, "Test", Funny, Fallbacks},
+ TermToGet = {call, Self, "Test", Funny, EncTerms},
Port = 6543,
{ok, ListenFd} = ei_publish(P, Port),
{any, EINode} ! TermToSend,
@@ -94,7 +101,7 @@ ei_threaded_accept(Config) when is_list(Config) ->
%% Test erlang:monitor toward erl_interface "processes"
monitor_ei_process(Config) when is_list(Config) ->
P = runner:start(Config, ?interpret),
- 0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
+ 0 = ei_connect_init(P, 42, erlang:get_cookie(), 0, 0),
Myname = hd(tl(string:tokens(atom_to_list(node()), "@"))),
io:format("Myname ~p ~n", [Myname]),
@@ -167,8 +174,8 @@ start_einode(Einode, N, Host) ->
%%% Interface functions for ei (erl_interface) functions.
-ei_connect_init(P, Num, Cookie, Creation) ->
- send_command(P, ei_connect_init, [Num,Cookie,Creation]),
+ei_connect_init(P, Num, Cookie, Creation, Compat) ->
+ send_command(P, ei_connect_init, [Num,Cookie,Creation,Compat]),
case get_term(P) of
{term,Int} when is_integer(Int) -> Int
end.
diff --git a/lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c b/lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c
index c209f506b1..09b0b5440b 100644
--- a/lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c
+++ b/lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c
@@ -58,7 +58,7 @@ static struct {
int num_args; /* Number of arguments. */
void (*func)(char* buf, int len);
} commands[] = {
- "ei_connect_init", 3, cmd_ei_connect_init,
+ "ei_connect_init", 4, cmd_ei_connect_init,
"ei_publish", 1, cmd_ei_publish,
"ei_accept", 1, cmd_ei_accept,
"ei_receive", 1, cmd_ei_receive,
@@ -106,21 +106,25 @@ TESTCASE(interpret)
static void cmd_ei_connect_init(char* buf, int len)
{
int index = 0, r = 0;
- int type, size;
- long l;
- char b[100];
+ long num, creation;
+ unsigned long compat;
+ char node_name[100];
char cookie[MAXATOMLEN], * cp = cookie;
ei_x_buff res;
- if (ei_decode_long(buf, &index, &l) < 0)
+ if (ei_decode_long(buf, &index, &num) < 0)
fail("expected int");
- sprintf(b, "c%d", l);
- /* FIXME don't use internal and maybe use skip?! */
- ei_get_type_internal(buf, &index, &type, &size);
+ sprintf(node_name, "c%d", num);
if (ei_decode_atom(buf, &index, cookie) < 0)
fail("expected atom (cookie)");
if (cookie[0] == '\0')
cp = NULL;
- r = ei_connect_init(&ec, b, cp, 0);
+ if (ei_decode_long(buf, &index, &creation) < 0)
+ fail("expected int");
+ if (ei_decode_long(buf, &index, &compat) < 0)
+ fail("expected uint");
+ if (compat)
+ ei_set_compat_rel(compat);
+ r = ei_connect_init(&ec, node_name, cp, creation);
ei_x_new_with_version(&res);
ei_x_encode_long(&res, r);
send_bin_term(&res);
diff --git a/lib/erl_interface/test/ei_connect_SUITE.erl b/lib/erl_interface/test/ei_connect_SUITE.erl
index 75b6bf18da..6184ce801b 100644
--- a/lib/erl_interface/test/ei_connect_SUITE.erl
+++ b/lib/erl_interface/test/ei_connect_SUITE.erl
@@ -79,9 +79,10 @@ ei_send_funs(Config) when is_list(Config) ->
{ok,Fd} = ei_connect(P, node()),
Fun1 = fun ei_send/1,
- Fun2 = fun(X) -> P, X, Fd, Fun1 end,
+ Fun2 = fun(X) -> {P, X, Fd, Fun1} end,
+ Bits = <<1,2,3:5>>,
- AMsg={Fun1,Fun2},
+ AMsg={Fun1,Fun2,Bits},
%%AMsg={wait_with_funs, new_dist_format},
ok = ei_send_funs(P, Fd, self(), AMsg),
EIMsg = receive M -> M end,
diff --git a/lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c b/lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c
index 58c0c7f8d8..7c9e79f837 100644
--- a/lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c
+++ b/lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c
@@ -107,7 +107,6 @@ TESTCASE(interpret)
static void cmd_ei_connect_init(char* buf, int len)
{
int index = 0, r = 0;
- int type, size;
long l;
char b[100];
char cookie[MAXATOMLEN], * cp = cookie;
@@ -115,8 +114,6 @@ static void cmd_ei_connect_init(char* buf, int len)
if (ei_decode_long(buf, &index, &l) < 0)
fail("expected int");
sprintf(b, "c%ld", l);
- /* FIXME don't use internal and maybe use skip?! */
- ei_get_type_internal(buf, &index, &type, &size);
if (ei_decode_atom(buf, &index, cookie) < 0)
fail("expected atom (cookie)");
if (cookie[0] == '\0')
@@ -212,6 +209,8 @@ static void cmd_ei_send_funs(char* buf, int len)
erlang_pid pid;
ei_x_buff x;
erlang_fun fun1, fun2;
+ unsigned char bitstring[10];
+ size_t bits;
if (ei_decode_long(buf, &index, &fd) < 0)
fail("expected long");
@@ -219,20 +218,24 @@ static void cmd_ei_send_funs(char* buf, int len)
fail("expected pid (node)");
if (ei_decode_tuple_header(buf, &index, &n) < 0)
fail("expected tuple");
- if (n != 2)
+ if (n != 3)
fail("expected tuple");
if (ei_decode_fun(buf, &index, &fun1) < 0)
fail("expected Fun1");
if (ei_decode_fun(buf, &index, &fun2) < 0)
fail("expected Fun2");
+ if (ei_decode_bitstring(buf, &index, bitstring, sizeof(bitstring), &bits) < 0)
+ fail("expected bitstring");
if (ei_x_new_with_version(&x) < 0)
fail("ei_x_new_with_version");
- if (ei_x_encode_tuple_header(&x, 2) < 0)
+ if (ei_x_encode_tuple_header(&x, 3) < 0)
fail("encode tuple header");
if (ei_x_encode_fun(&x, &fun1) < 0)
fail("encode fun1");
if (ei_x_encode_fun(&x, &fun2) < 0)
fail("encode fun2");
+ if (ei_x_encode_bitstring(&x, bitstring, bits) < 0)
+ fail("encode bitstring");
free_fun(&fun1);
free_fun(&fun2);
send_errno_result(ei_send(fd, &pid, x.buff, x.index));
diff --git a/lib/erl_interface/test/ei_decode_SUITE.erl b/lib/erl_interface/test/ei_decode_SUITE.erl
index 75560ea7c9..e005ec89c7 100644
--- a/lib/erl_interface/test/ei_decode_SUITE.erl
+++ b/lib/erl_interface/test/ei_decode_SUITE.erl
@@ -194,6 +194,9 @@ test_ei_decode_misc(Config) when is_list(Config) ->
send_term_as_binary(P,<<>>),
send_term_as_binary(P,<<"ÅÄÖåäö">>),
+ send_term_as_binary(P,<<1, 2, 3:5>>),
+ send_term_as_binary(P,<<1:1>>),
+
% send_term_as_binary(P,{}),
% send_term_as_binary(P,[]),
diff --git a/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c b/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c
index e516f310b6..d39970a857 100644
--- a/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c
+++ b/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c
@@ -256,66 +256,129 @@ int ei_decode_my_string(const char *buf, int *index, char *to,
//#define EI_DECODE_UTF8_STRING(FUNC,SIZE,VAL)
-#define EI_DECODE_BIN(FUNC,SIZE,VAL,LEN) \
- { \
- char p[1024]; \
- char *buf; \
- long len; \
- int size1 = 0; \
- int size2 = 0; \
- int err; \
- message("ei_" #FUNC " should be " #VAL); \
- buf = read_packet(NULL); \
- err = ei_ ## FUNC(buf+1, &size1, NULL, &len); \
+static void decode_bin(int exp_size, const char* val, int exp_len)
+{
+ char p[1024];
+ char *buf;
+ long len;
+ int size1 = 0;
+ int size2 = 0;
+ int err;
+ message("ei_decode_binary should be %s", val);
+ buf = read_packet(NULL);
+ err = ei_decode_binary(buf+1, &size1, NULL, &len);
message("err = %d, size = %d, len = %d, expected size = %d, expected len = %d\n",\
- err,size1,len,SIZE,LEN); \
- if (err != 0) { \
- if (err != -1) { \
- fail("returned non zero but not -1 if NULL pointer"); \
- } else { \
- fail("returned non zero"); \
- } \
- return; \
- } \
-\
- if (len != LEN) { \
- fail("size is not correct"); \
- return; \
- } \
-\
- err = ei_ ## FUNC(buf+1, &size2, p, &len); \
+ err,size1,len, exp_size, exp_len);
+ if (err != 0) {
+ if (err != -1) {
+ fail("returned non zero but not -1 if NULL pointer");
+ } else {
+ fail("returned non zero");
+ }
+ return;
+ }
+
+ if (len != exp_len) {
+ fail("size is not correct");
+ return;
+ }
+
+ err = ei_decode_binary(buf+1, &size2, p, &len);
message("err = %d, size = %d, len = %d, expected size = %d, expected len = %d\n",\
- err,size2,len,SIZE,LEN); \
- if (err != 0) { \
- if (err != -1) { \
- fail("returned non zero but not -1 if NULL pointer"); \
- } else { \
- fail("returned non zero"); \
- } \
- return; \
- } \
-\
- if (len != LEN) { \
- fail("size is not correct"); \
- return; \
- } \
-\
- if (strncmp(p,VAL,LEN) != 0) { \
- fail("value is not correct"); \
- return; \
- } \
-\
- if (size1 != size2) { \
- fail("size with and without pointer differs"); \
- return; \
- } \
-\
- if (size1 != SIZE) { \
- fail("size of encoded data is incorrect"); \
- return; \
- } \
- free_packet(buf); \
- } \
+ err,size2,len, exp_size, exp_len);
+ if (err != 0) {
+ if (err != -1) {
+ fail("returned non zero but not -1 if NULL pointer");
+ } else {
+ fail("returned non zero");
+ }
+ return;
+ }
+
+ if (len != exp_len) {
+ fail("size is not correct");
+ return;
+ }
+
+ if (strncmp(p,val,exp_len) != 0) {
+ fail("value is not correct");
+ return;
+ }
+
+ if (size1 != size2) {
+ fail("size with and without pointer differs");
+ return;
+ }
+
+ if (size1 != exp_size) {
+ fail("size of encoded data is incorrect");
+ return;
+ }
+ free_packet(buf);
+}
+
+static void decode_bits(int exp_size, const char* val, size_t exp_bits)
+{
+ char p[1024];
+ char *buf;
+ size_t bits;
+ int size1 = 0;
+ int size2 = 0;
+ int err;
+ message("ei_decode_bitstring should be %d bits", (int)exp_bits);
+ buf = read_packet(NULL);
+ err = ei_decode_bitstring(buf+1, &size1, NULL, sizeof(p), &bits);
+ message("err = %d, size = %d, len = %d, expected size = %d, expected bits = %d\n",\
+ err,size1, (int)bits, exp_size, (int)exp_bits);
+
+ if (err != 0) {
+ if (err != -1) {
+ fail("returned non zero but not -1 if NULL pointer");
+ } else {
+ fail("returned non zero");
+ }
+ return;
+ }
+
+ if (bits != exp_bits) {
+ fail("number of bits is not correct");
+ return;
+ }
+
+ err = ei_decode_bitstring(buf+1, &size2, p, sizeof(p), &bits);
+ message("err = %d, size = %d, len = %d, expected size = %d, expected len = %d\n",\
+ err,size2, (int)bits, exp_size, (int)exp_bits);
+ if (err != 0) {
+ if (err != -1) {
+ fail("returned non zero but not -1 if NULL pointer");
+ } else {
+ fail("returned non zero");
+ }
+ return;
+ }
+
+ if (bits != exp_bits) {
+ fail("bits is not correct");
+ return;
+ }
+
+ if (memcmp(p, val, (exp_bits+7)/8) != 0) {
+ fail("value is not correct");
+ return;
+ }
+
+ if (size1 != size2) {
+ fail("size with and without pointer differs");
+ return;
+ }
+
+ if (size1 != exp_size) {
+ fail2("size of encoded data is incorrect %d != %d", size1, exp_size);
+ return;
+ }
+ free_packet(buf);
+}
+
/* ******************************************************************** */
@@ -644,9 +707,17 @@ TESTCASE(test_ei_decode_misc)
EI_DECODE_STRING(decode_my_string, 1, "");
EI_DECODE_STRING(decode_my_string, 9, "������");
- EI_DECODE_BIN(decode_binary, 8, "foo", 3);
- EI_DECODE_BIN(decode_binary, 5, "", 0);
- EI_DECODE_BIN(decode_binary, 11, "������", 6);
+ decode_bin(8, "foo", 3);
+ decode_bin(5, "", 0);
+ decode_bin(11, "������", 6);
+
+#define LAST_BYTE(V, BITS) ((V) << (8-(BITS)))
+ {
+ unsigned char bits1[] = {1, 2, LAST_BYTE(3,5) };
+ unsigned char bits2[] = {LAST_BYTE(1,1) };
+ decode_bits(9, bits1, 21);
+ decode_bits(7, bits2, 1);
+ }
/* FIXME check \0 in strings and atoms? */
/*
diff --git a/lib/erl_interface/test/ei_decode_encode_SUITE.erl b/lib/erl_interface/test/ei_decode_encode_SUITE.erl
index 0f23cdfbb9..d8b0bce3ae 100644
--- a/lib/erl_interface/test/ei_decode_encode_SUITE.erl
+++ b/lib/erl_interface/test/ei_decode_encode_SUITE.erl
@@ -120,6 +120,8 @@ test_ei_decode_encode(Config) when is_list(Config) ->
send_rec(P, #{key => value}),
send_rec(P, maps:put(Port, Ref, #{key => value, key2 => Pid})),
+ [send_rec(P, <<16#dec0deb175:B/little>>) || B <- lists:seq(0,48)],
+
runner:recv_eot(P),
ok.
diff --git a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
index 55d9ed1b1a..f9c05b2739 100644
--- a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
+++ b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
@@ -40,6 +40,12 @@ typedef struct
erlang_char_encoding enc;
}my_atom;
+typedef struct
+{
+ char bytes[MAXATOMLEN_UTF8];
+ size_t nbits;
+}my_bitstring;
+
struct my_obj {
union {
erlang_fun fun;
@@ -49,6 +55,7 @@ struct my_obj {
erlang_trace trace;
erlang_big big;
my_atom atom;
+ my_bitstring bits;
int arity;
}u;
@@ -119,6 +126,26 @@ struct Type my_atom_type = {
(encodeFT*)ei_encode_my_atom, (x_encodeFT*)ei_x_encode_my_atom
};
+int ei_decode_my_bits(const char *buf, int *index, my_bitstring* a)
+{
+ return ei_decode_bitstring(buf, index, (a ? a->bytes : NULL),
+ sizeof(a->bytes),
+ (a ? &a->nbits : NULL));
+}
+int ei_encode_my_bits(char *buf, int *index, my_bitstring* a)
+{
+ return ei_encode_bitstring(buf, index, a->bytes, a->nbits);
+}
+int ei_x_encode_my_bits(ei_x_buff* x, my_bitstring* a)
+{
+ return ei_x_encode_bitstring(x, a->bytes, a->nbits);
+}
+
+struct Type my_bitstring_type = {
+ "bits", "my_bitstring", (decodeFT*)ei_decode_my_bits,
+ (encodeFT*)ei_encode_my_bits, (x_encodeFT*)ei_x_encode_my_bits
+};
+
int my_decode_tuple_header(const char *buf, int *index, struct my_obj* obj)
{
@@ -537,6 +564,10 @@ TESTCASE(test_ei_decode_encode)
decode_encode(map, 7);
}
+ for (i=0; i <= 48; i++) {
+ decode_encode_one(&my_bitstring_type);
+ }
+
report(1);
}
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractNode.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractNode.java
index 222330654a..c3f71a84f0 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractNode.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/AbstractNode.java
@@ -89,7 +89,7 @@ public class AbstractNode implements OtpTransportFactory {
static final int dFlagHiddenAtomCache = 0x40; // NOT SUPPORTED
static final int dflagNewFunTags = 0x80;
static final int dFlagExtendedPidsPorts = 0x100;
- static final int dFlagExportPtrTag = 0x200; // NOT SUPPORTED
+ static final int dFlagExportPtrTag = 0x200;
static final int dFlagBitBinaries = 0x400;
static final int dFlagNewFloats = 0x800;
static final int dFlagUnicodeIo = 0x1000;
@@ -105,6 +105,7 @@ public class AbstractNode implements OtpTransportFactory {
int flags = dFlagExtendedReferences | dFlagExtendedPidsPorts
| dFlagBitBinaries | dFlagNewFloats | dFlagFunTags
| dflagNewFunTags | dFlagUtf8Atoms | dFlagMapTag
+ | dFlagExportPtrTag
| dFlagBigCreation;
/* initialize hostname and default cookie */
diff --git a/lib/jinterface/test/nc_SUITE.erl b/lib/jinterface/test/nc_SUITE.erl
index 4f225a396e..7833d070b7 100644
--- a/lib/jinterface/test/nc_SUITE.erl
+++ b/lib/jinterface/test/nc_SUITE.erl
@@ -142,7 +142,8 @@ fun_roundtrip(Config) when is_list(Config)->
do_echo([fun(A, B) -> A + B end,
fun(A) -> lists:reverse(A) end,
fun() -> ok end,
- fun fun_roundtrip/1],
+ fun fun_roundtrip/1,
+ fun ?MODULE:fun_roundtrip/1],
Config).
port_roundtrip(doc) -> [];