diff options
-rw-r--r-- | lib/asn1/c_src/asn1_erl_nif.c | 432 | ||||
-rw-r--r-- | lib/asn1/doc/src/asn1_ug.xml | 4 | ||||
-rw-r--r-- | lib/asn1/doc/src/asn1ct.xml | 10 | ||||
-rw-r--r-- | lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl | 4 | ||||
-rw-r--r-- | lib/asn1/src/asn1ct_gen_ber_bin_v2.erl | 17 | ||||
-rw-r--r-- | lib/asn1/src/asn1rt_ber_bin_v2.erl | 78 | ||||
-rw-r--r-- | lib/asn1/src/asn1rt_nif.erl | 8 | ||||
-rw-r--r-- | lib/asn1/test/asn1_bin_v2_particular_SUITE.erl.src | 258 |
8 files changed, 590 insertions, 221 deletions
diff --git a/lib/asn1/c_src/asn1_erl_nif.c b/lib/asn1/c_src/asn1_erl_nif.c index 58314e23c2..9c9f83bc2a 100644 --- a/lib/asn1/c_src/asn1_erl_nif.c +++ b/lib/asn1/c_src/asn1_erl_nif.c @@ -46,10 +46,6 @@ #define ASN1_PRIMITIVE 0 #define ASN1_CONSTRUCTED 0x20 -#define ASN1_COMPLETE 1 -#define ASN1_BER_TLV_DECODE 2 -#define ASN1_BER_TLV_PARTIAL_DECODE 3 - #define ASN1_NOVALUE 0 #define ASN1_SKIPPED 0 @@ -61,38 +57,55 @@ #define INVMASK(X,M) (X & (M ^ 0xff)) #define MASK(X,M) (X & M) -int complete(ErlNifBinary *, unsigned char *, int ); +/* PER COMPLETE */ +int per_complete(ErlNifBinary *, unsigned char *, int); -int insert_octets(int, unsigned char **, unsigned char **, int *); +int per_insert_octets(int, unsigned char **, unsigned char **, int *); -int insert_octets_except_unused(int, unsigned char **, unsigned char **, int *, - int); +int per_insert_octets_except_unused(int, unsigned char **, unsigned char **, + int *, int); -int insert_octets_as_bits_exact_len(int, int, unsigned char **, +int per_insert_octets_as_bits_exact_len(int, int, unsigned char **, unsigned char **, int *); -int insert_octets_as_bits(int, unsigned char **, unsigned char **, int *); +int per_insert_octets_as_bits(int, unsigned char **, unsigned char **, int *); -int pad_bits(int, unsigned char **, int *); +int per_pad_bits(int, unsigned char **, int *); -int insert_least_sign_bits(int, unsigned char, unsigned char **, int *); +int per_insert_least_sign_bits(int, unsigned char, unsigned char **, int *); -int insert_most_sign_bits(int, unsigned char, unsigned char **, int *); +int per_insert_most_sign_bits(int, unsigned char, unsigned char **, int *); -int insert_bits_as_bits(int, int, unsigned char **, unsigned char **, int *); +int per_insert_bits_as_bits(int, int, unsigned char **, unsigned char **, int *); -int insert_octets_unaligned(int, unsigned char **, unsigned char **, int); +int per_insert_octets_unaligned(int, unsigned char **, unsigned char **, int); -int realloc_memory(ErlNifBinary *, int, unsigned char **); +int per_realloc_memory(ErlNifBinary *, int, unsigned char **); -int decode_begin(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int, +/* BER DECODE */ +int ber_decode_begin(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int, unsigned int *); -int decode(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int *, int); +int ber_decode(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int *, int); + +int ber_decode_tag(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int, int *); + +int ber_decode_value(ErlNifEnv*, ERL_NIF_TERM *, unsigned char *, int *, int, + int); + +/* BER ENCODE */ +typedef struct ber_encode_mem_chunk mem_chunk_t; + +int ber_encode(ErlNifEnv *, ERL_NIF_TERM , mem_chunk_t **, unsigned int *); -int decode_tag(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int, int *); +void ber_free_chunks(mem_chunk_t *chunk); +mem_chunk_t *ber_new_chunk(unsigned int length); +int ber_check_memory(mem_chunk_t **curr, unsigned int needed); -int decode_value(ErlNifEnv*, ERL_NIF_TERM *, unsigned char *, int *, int, int); +int ber_encode_tag(ErlNifEnv *, ERL_NIF_TERM , unsigned int , + mem_chunk_t **, unsigned int *); + +int ber_encode_length(size_t , mem_chunk_t **, unsigned int *); /* * @@ -101,7 +114,8 @@ int decode_value(ErlNifEnv*, ERL_NIF_TERM *, unsigned char *, int *, int, int); * */ -int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { +int per_complete(ErlNifBinary *out_binary, unsigned char *in_buf, + int in_buf_len) { int counter = in_buf_len; /* counter keeps track of number of bytes left in the input buffer */ @@ -175,7 +189,7 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { no_bits = (int) *(++in_ptr); val = *(++in_ptr); counter -= 2; - if ((ret = insert_least_sign_bits(no_bits, val, &ptr, &unused)) + if ((ret = per_insert_least_sign_bits(no_bits, val, &ptr, &unused)) == ASN1_ERROR ) return ASN1_ERROR; @@ -189,8 +203,8 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { no_bytes = (int) *(++in_ptr); counter -= (no_bytes + 1); if ((counter < 0) - || (ret = insert_octets(no_bytes, &in_ptr, &ptr, &unused)) - == ASN1_ERROR + || (ret = per_insert_octets(no_bytes, &in_ptr, &ptr, + &unused)) == ASN1_ERROR ) return ASN1_ERROR; buf_space -= ret; @@ -205,8 +219,8 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { no_bytes = no_bytes | (int) *(++in_ptr); counter -= (2 + no_bytes); if ((counter < 0) - || (ret = insert_octets(no_bytes, &in_ptr, &ptr, &unused)) - == ASN1_ERROR + || (ret = per_insert_octets(no_bytes, &in_ptr, &ptr, + &unused)) == ASN1_ERROR ) return ASN1_ERROR; buf_space -= ret; @@ -222,7 +236,7 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { counter -= (2 + no_bytes); ret = -4711; if ((counter < 0) - || (ret = insert_octets_except_unused(no_bytes, &in_ptr, + || (ret = per_insert_octets_except_unused(no_bytes, &in_ptr, &ptr, &unused, in_unused)) == ASN1_ERROR ) return ASN1_ERROR; @@ -241,7 +255,7 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { no_bytes = no_bytes | (int) *(++in_ptr); counter -= (3 + no_bytes); if ((counter < 0) - || (ret = insert_octets_except_unused(no_bytes, &in_ptr, + || (ret = per_insert_octets_except_unused(no_bytes, &in_ptr, &ptr, &unused, in_unused)) == ASN1_ERROR ) return ASN1_ERROR; @@ -273,15 +287,14 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { /* Have to allocate more memory */ buf_size += needed; buf_space += needed; - if (realloc_memory(out_binary, buf_size, &ptr) - == ASN1_ERROR - ) + if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR + ) return ASN1_ERROR; } counter -= (2 + no_bytes); if ((counter < 0) - || (ret = insert_octets_as_bits_exact_len(desired_len, + || (ret = per_insert_octets_as_bits_exact_len(desired_len, no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR ) return ASN1_ERROR; @@ -302,15 +315,14 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { /* Have to allocate more memory */ buf_size += needed; buf_space += needed; - if (realloc_memory(out_binary, buf_size, &ptr) - == ASN1_ERROR - ) + if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR + ) return ASN1_ERROR; } counter -= (3 + no_bytes); if ((counter < 0) - || (ret = insert_octets_as_bits_exact_len(desired_len, + || (ret = per_insert_octets_as_bits_exact_len(desired_len, no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR ) return ASN1_ERROR; @@ -331,15 +343,14 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { /* Have to allocate more memory */ buf_size += needed; buf_space += needed; - if (realloc_memory(out_binary, buf_size, &ptr) - == ASN1_ERROR - ) + if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR + ) return ASN1_ERROR; } counter -= (3 + no_bytes); if ((counter < 0) - || (ret = insert_octets_as_bits_exact_len(desired_len, + || (ret = per_insert_octets_as_bits_exact_len(desired_len, no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR ) return ASN1_ERROR; @@ -362,15 +373,14 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { /* Have to allocate more memory */ buf_size += needed; buf_space += needed; - if (realloc_memory(out_binary, buf_size, &ptr) - == ASN1_ERROR - ) + if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR + ) return ASN1_ERROR; } counter -= (4 + no_bytes); if ((counter < 0) - || (ret = insert_octets_as_bits_exact_len(desired_len, + || (ret = per_insert_octets_as_bits_exact_len(desired_len, no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR ) return ASN1_ERROR; @@ -392,16 +402,15 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { /* Have to allocate more memory */ buf_size += needed; buf_space += needed; - if (realloc_memory(out_binary, buf_size, &ptr) - == ASN1_ERROR - ) + if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR + ) return ASN1_ERROR; } counter -= (2 + no_bytes); if ((counter < 0) - || (ret = insert_bits_as_bits(desired_len, no_bytes, + || (ret = per_insert_bits_as_bits(desired_len, no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR ) return ASN1_ERROR; @@ -422,15 +431,14 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { /* Have to allocate more memory */ buf_size += needed; buf_space += needed; - if (realloc_memory(out_binary, buf_size, &ptr) - == ASN1_ERROR - ) + if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR + ) return ASN1_ERROR; } counter -= (3 + no_bytes); if ((counter < 0) - || (ret = insert_bits_as_bits(desired_len, no_bytes, + || (ret = per_insert_bits_as_bits(desired_len, no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR ) return ASN1_ERROR; @@ -453,15 +461,14 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { /* Have to allocate more memory */ buf_size += needed; buf_space += needed; - if (realloc_memory(out_binary, buf_size, &ptr) - == ASN1_ERROR - ) + if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR + ) return ASN1_ERROR; } counter -= (4 + no_bytes); if ((counter < 0) - || (ret = insert_bits_as_bits(desired_len, no_bytes, + || (ret = per_insert_bits_as_bits(desired_len, no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR ) return ASN1_ERROR; @@ -483,7 +490,7 @@ int complete(ErlNifBinary *out_binary, unsigned char *in_buf, int in_buf_len) { } } -int realloc_memory(ErlNifBinary *binary, int amount, unsigned char **ptr) { +int per_realloc_memory(ErlNifBinary *binary, int amount, unsigned char **ptr) { int i = *ptr - binary->data; @@ -496,7 +503,7 @@ int realloc_memory(ErlNifBinary *binary, int amount, unsigned char **ptr) { return ASN1_OK; } -int insert_most_sign_bits(int no_bits, unsigned char val, +int per_insert_most_sign_bits(int no_bits, unsigned char val, unsigned char **output_ptr, int *unused) { unsigned char *ptr = *output_ptr; @@ -517,7 +524,7 @@ int insert_most_sign_bits(int no_bits, unsigned char val, return ASN1_OK; } -int insert_least_sign_bits(int no_bits, unsigned char val, +int per_insert_least_sign_bits(int no_bits, unsigned char val, unsigned char **output_ptr, int *unused) { unsigned char *ptr = *output_ptr; int ret = 0; @@ -543,10 +550,10 @@ int insert_least_sign_bits(int no_bits, unsigned char val, return ret; } -/* pad_bits adds no_bits bits in the buffer that output_ptr +/* per_pad_bits adds no_bits bits in the buffer that output_ptr points at. */ -int pad_bits(int no_bits, unsigned char **output_ptr, int *unused) { +int per_pad_bits(int no_bits, unsigned char **output_ptr, int *unused) { unsigned char *ptr = *output_ptr; int ret = 0; @@ -569,37 +576,37 @@ int pad_bits(int no_bits, unsigned char **output_ptr, int *unused) { The unused parameter tells how many bits that are not set in the actual byte in the output buffer. If desired_no is more bits than the input buffer has in no_bytes bytes, then zero bits is padded.*/ -int insert_bits_as_bits(int desired_no, int no_bytes, unsigned char **input_ptr, - unsigned char **output_ptr, int *unused) { +int per_insert_bits_as_bits(int desired_no, int no_bytes, + unsigned char **input_ptr, unsigned char **output_ptr, int *unused) { unsigned char *in_ptr = *input_ptr; unsigned char val; int no_bits, ret, ret2; if (desired_no == (no_bytes * 8)) { - if (insert_octets_unaligned(no_bytes, &in_ptr, output_ptr, *unused) + if (per_insert_octets_unaligned(no_bytes, &in_ptr, output_ptr, *unused) == ASN1_ERROR ) return ASN1_ERROR; ret = no_bytes; } else if (desired_no < (no_bytes * 8)) { - /* printf("insert_bits_as_bits 1\n\r"); */ - if (insert_octets_unaligned(desired_no / 8, &in_ptr, output_ptr, + /* printf("per_insert_bits_as_bits 1\n\r"); */ + if (per_insert_octets_unaligned(desired_no / 8, &in_ptr, output_ptr, *unused) == ASN1_ERROR ) return ASN1_ERROR; - /* printf("insert_bits_as_bits 2\n\r"); */ + /* printf("per_insert_bits_as_bits 2\n\r"); */ val = *++in_ptr; /* printf("val = %d\n\r",(int)val); */ no_bits = desired_no % 8; /* printf("no_bits = %d\n\r",no_bits); */ - insert_most_sign_bits(no_bits, val, output_ptr, unused); + per_insert_most_sign_bits(no_bits, val, output_ptr, unused); ret = CEIL(desired_no,8); } else { - if (insert_octets_unaligned(no_bytes, &in_ptr, output_ptr, *unused) + if (per_insert_octets_unaligned(no_bytes, &in_ptr, output_ptr, *unused) == ASN1_ERROR ) return ASN1_ERROR; - ret2 = pad_bits(desired_no - (no_bytes * 8), output_ptr, unused); + ret2 = per_pad_bits(desired_no - (no_bytes * 8), output_ptr, unused); /* printf("ret2 = %d\n\r",ret2); */ ret = CEIL(desired_no,8); /* printf("ret = %d\n\r",ret); */ @@ -609,30 +616,30 @@ int insert_bits_as_bits(int desired_no, int no_bytes, unsigned char **input_ptr, return ret; } -/* insert_octets_as_bits_exact_len */ -int insert_octets_as_bits_exact_len(int desired_len, int in_buff_len, +/* per_insert_octets_as_bits_exact_len */ +int per_insert_octets_as_bits_exact_len(int desired_len, int in_buff_len, unsigned char **in_ptr, unsigned char **ptr, int *unused) { int ret = 0; int ret2 = 0; if (desired_len == in_buff_len) { - if ((ret = insert_octets_as_bits(in_buff_len, in_ptr, ptr, unused)) + if ((ret = per_insert_octets_as_bits(in_buff_len, in_ptr, ptr, unused)) == ASN1_ERROR ) return ASN1_ERROR; } else if (desired_len > in_buff_len) { - if ((ret = insert_octets_as_bits(in_buff_len, in_ptr, ptr, unused)) + if ((ret = per_insert_octets_as_bits(in_buff_len, in_ptr, ptr, unused)) == ASN1_ERROR ) return ASN1_ERROR; /* now pad with zero bits */ /* printf("~npad_bits: called with %d bits padding~n~n~r",desired_len - in_buff_len); */ - if ((ret2 = pad_bits(desired_len - in_buff_len, ptr, unused)) + if ((ret2 = per_pad_bits(desired_len - in_buff_len, ptr, unused)) == ASN1_ERROR ) return ASN1_ERROR; } else {/* desired_len < no_bits */ - if ((ret = insert_octets_as_bits(desired_len, in_ptr, ptr, unused)) + if ((ret = per_insert_octets_as_bits(desired_len, in_ptr, ptr, unused)) == ASN1_ERROR ) return ASN1_ERROR; @@ -648,7 +655,7 @@ int insert_octets_as_bits_exact_len(int desired_len, int in_buff_len, otherwise the function returns ASN1_ERROR. The output buffer is concatenated without alignment. */ -int insert_octets_as_bits(int no_bytes, unsigned char **input_ptr, +int per_insert_octets_as_bits(int no_bytes, unsigned char **input_ptr, unsigned char **output_ptr, int *unused) { unsigned char *in_ptr = *input_ptr; unsigned char *ptr = *output_ptr; @@ -688,7 +695,7 @@ int insert_octets_as_bits(int no_bytes, unsigned char **input_ptr, into the output buffer, *output_ptr. Before the first byte is inserted the input buffer is aligned. */ -int insert_octets(int no_bytes, unsigned char **input_ptr, +int per_insert_octets(int no_bytes, unsigned char **input_ptr, unsigned char **output_ptr, int *unused) { unsigned char *in_ptr = *input_ptr; unsigned char *ptr = *output_ptr; @@ -710,10 +717,10 @@ int insert_octets(int no_bytes, unsigned char **input_ptr, return (ret + no_bytes); } -/* insert_octets_unaligned inserts bytes from the input buffer, *input_ptr, +/* per_insert_octets_unaligned inserts bytes from the input buffer, *input_ptr, into the output buffer, *output_ptr.No alignment is done. */ -int insert_octets_unaligned(int no_bytes, unsigned char **input_ptr, +int per_insert_octets_unaligned(int no_bytes, unsigned char **input_ptr, unsigned char **output_ptr, int unused) { unsigned char *in_ptr = *input_ptr; unsigned char *ptr = *output_ptr; @@ -737,7 +744,7 @@ int insert_octets_unaligned(int no_bytes, unsigned char **input_ptr, return no_bytes; } -int insert_octets_except_unused(int no_bytes, unsigned char **input_ptr, +int per_insert_octets_except_unused(int no_bytes, unsigned char **input_ptr, unsigned char **output_ptr, int *unused, int in_unused) { unsigned char *in_ptr = *input_ptr; unsigned char *ptr = *output_ptr; @@ -745,12 +752,12 @@ int insert_octets_except_unused(int no_bytes, unsigned char **input_ptr, int ret = 0; if (in_unused == 0) { - if ((ret = insert_octets_unaligned(no_bytes, &in_ptr, &ptr, *unused)) + if ((ret = per_insert_octets_unaligned(no_bytes, &in_ptr, &ptr, *unused)) == ASN1_ERROR ) return ASN1_ERROR; } else { - if ((ret = insert_octets_unaligned(no_bytes - 1, &in_ptr, &ptr, *unused)) + if ((ret = per_insert_octets_unaligned(no_bytes - 1, &in_ptr, &ptr, *unused)) != ASN1_ERROR) { val = (int) *(++in_ptr); no_bits = 8 - in_unused; @@ -789,7 +796,7 @@ int insert_octets_except_unused(int no_bytes, unsigned char **input_ptr, /* * int decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, - int in_buf_len, unsigned int *err_pos) + int in_buf_len, unsigned int *err_pos) * term is a pointer to the term which is to be returned to erlang * in_buf is a pointer into the buffer of incoming bytes. * in_buf_len is the length of the incoming buffer. @@ -830,16 +837,16 @@ int insert_octets_except_unused(int no_bytes, unsigned char **input_ptr, * is the empty binary. * If some error occured during the decoding of the in_buf an error is returned. */ -int decode_begin(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, +int ber_decode_begin(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, int in_buf_len, unsigned int *err_pos) { int maybe_ret; int ib_index = 0; unsigned char *rest_data; ERL_NIF_TERM decoded_term, rest; - if ((maybe_ret = decode(env, &decoded_term, in_buf, &ib_index, in_buf_len)) - <= ASN1_ERROR) - { + if ((maybe_ret = ber_decode(env, &decoded_term, in_buf, &ib_index, + in_buf_len)) <= ASN1_ERROR) + { *err_pos = ib_index; return maybe_ret; }; @@ -855,7 +862,7 @@ int decode_begin(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, return ASN1_OK; } -int decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, +int ber_decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, int *ib_index, int in_buf_len) { int maybe_ret; int form; @@ -865,7 +872,7 @@ int decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, if ((*ib_index + 2) > in_buf_len) return ASN1_VALUE_ERROR; /* "{{TagNo," */ - if ((form = decode_tag(env, &tag, in_buf, in_buf_len, ib_index)) + if ((form = ber_decode_tag(env, &tag, in_buf, in_buf_len, ib_index)) <= ASN1_ERROR ) return form; /* 5 bytes */ @@ -875,7 +882,7 @@ int decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, /* buffer must hold at least one byte (0 as length and nothing as value) */ /* "{{TagNo,Value}," */ - if ((maybe_ret = decode_value(env, &value, in_buf, ib_index, form, + if ((maybe_ret = ber_decode_value(env, &value, in_buf, ib_index, form, in_buf_len)) <= ASN1_ERROR ) return maybe_ret; /* at least 5 bytes */ @@ -887,7 +894,7 @@ int decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf, * decode_tag decodes the BER encoded tag in in_buf and creates an * nif term tag */ -int decode_tag(ErlNifEnv* env, ERL_NIF_TERM *tag, unsigned char *in_buf, +int ber_decode_tag(ErlNifEnv* env, ERL_NIF_TERM *tag, unsigned char *in_buf, int in_buf_len, int *ib_index) { int tag_no, tmp_tag, form; @@ -930,11 +937,11 @@ int decode_tag(ErlNifEnv* env, ERL_NIF_TERM *tag, unsigned char *in_buf, } /* - * decode_value decodes the BER encoded length and value fields in the + * ber_decode_value decodes the BER encoded length and value fields in the * in_buf and puts the value part in the decode_buf as an Erlang * nif term into value */ -int decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *in_buf, +int ber_decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *in_buf, int *ib_index, int form, int in_buf_len) { int maybe_ret; unsigned int len = 0; @@ -970,7 +977,7 @@ int decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *in_buf, if (*ib_index >= in_buf_len) return ASN1_INDEF_LEN_ERROR; - if ((maybe_ret = decode(env, &term, in_buf, ib_index, in_buf_len)) + if ((maybe_ret = ber_decode(env, &term, in_buf, ib_index, in_buf_len)) <= ASN1_ERROR ) return maybe_ret; @@ -986,9 +993,9 @@ int decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *in_buf, curr_head = enif_make_list(env, 0); while (*ib_index < end_index) { - if ((maybe_ret = decode(env, &term, in_buf, ib_index, in_buf_len)) - <= ASN1_ERROR - ) + if ((maybe_ret = ber_decode(env, &term, in_buf, ib_index, + in_buf_len)) <= ASN1_ERROR + ) return maybe_ret; curr_head = enif_make_list_cell(env, term, curr_head); } @@ -1003,6 +1010,187 @@ int decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *in_buf, return ASN1_OK; } +struct ber_encode_mem_chunk { + mem_chunk_t *next; + int length; + char *top; + char *curr; +}; + +int ber_encode(ErlNifEnv *env, ERL_NIF_TERM term, mem_chunk_t **curr, unsigned int *count) { + + const ERL_NIF_TERM *tv; + unsigned int form; + int arity; + + if (!enif_get_tuple(env, term, &arity, &tv)) + return ASN1_ERROR; + + form = enif_is_list(env, tv[1]) ? ASN1_CONSTRUCTED : ASN1_PRIMITIVE; + + switch (form) { + case ASN1_PRIMITIVE: { + ErlNifBinary value; + if (!enif_inspect_binary(env, tv[1], &value)) + return ASN1_ERROR; + + if (ber_check_memory(curr, value.size)) + return ASN1_ERROR; + memcpy((*curr)->curr - value.size + 1, value.data, value.size); + (*curr)->curr -= value.size; + *count += value.size; + + if (ber_encode_length(value.size, curr, count)) + return ASN1_ERROR; + + break; + } + case ASN1_CONSTRUCTED: { + ERL_NIF_TERM head, tail; + unsigned int tmp_cnt; + + if(!enif_make_reverse_list(env, tv[1], &head)) + return ASN1_ERROR; + + if (!enif_get_list_cell(env, head, &head, &tail)) { + if (enif_is_empty_list(env, tv[1])) { + *((*curr)->curr) = 0; + (*curr)->curr -= 1; + (*count)++; + break; + } else + return ASN1_ERROR; + } + + do { + tmp_cnt = 0; + if (ber_encode(env, head, curr, &tmp_cnt)) { + return ASN1_ERROR; + } + *count += tmp_cnt; + } while (enif_get_list_cell(env, tail, &head, &tail)); + + if (ber_check_memory(curr, *count)) { + return ASN1_ERROR; + } + + if (ber_encode_length(*count, curr, count)) { + return ASN1_ERROR; + } + + break; + } + } + + // We need atleast 5 bytes to encode the next tlv + if (ber_check_memory(curr, 3)) + return ASN1_ERROR; + + if (ber_encode_tag(env, tv[0], form, curr, count)) + return ASN1_ERROR; + + return ASN1_OK; +} + +int ber_encode_tag(ErlNifEnv *env, ERL_NIF_TERM tag, unsigned int form, + mem_chunk_t **curr, unsigned int *count) { + unsigned int class_tag_no, head_tag; + if (!enif_get_uint(env, tag, &class_tag_no)) + return ASN1_ERROR; + + head_tag = form | ((class_tag_no & 0x30000) >> 10); + class_tag_no = class_tag_no & 0xFFFF; + + if (class_tag_no <= 30) { + *(*curr)->curr = head_tag | class_tag_no; + (*curr)->curr -= 1; + (*count)++; + return ASN1_OK; + } else { + *(*curr)->curr = class_tag_no & 127; + class_tag_no = class_tag_no >> 7; + (*curr)->curr -= 1; + (*count)++; + + while (class_tag_no > 0) { + *(*curr)->curr = (class_tag_no & 127) | 0x80; + class_tag_no >>= 7; + (*curr)->curr -= 1; + (*count)++; + } + + *(*curr)->curr = head_tag | 0x1F; + (*curr)->curr -= 1; + (*count)++; + + return ASN1_OK; + } +} + +int ber_encode_length(size_t size, mem_chunk_t **curr, unsigned int *count) { + if (size < 128) { + if (ber_check_memory(curr, 1u)) + return ASN1_ERROR; + *(*curr)->curr = size; + (*curr)->curr -= 1; + (*count)++; + } else { + int chunks = size / 256 + 1; + if (ber_check_memory(curr, chunks + 1)) + return ASN1_ERROR; + + while (size > 0) + { + *(*curr)->curr = size & 0xFF; + size >>= 8; + (*curr)->curr -= 1; + (*count)++; + } + + *(*curr)->curr = chunks | 0x80; + (*curr)->curr -= 1; + (*count)++; + } + return ASN1_OK; +} + +mem_chunk_t *ber_new_chunk(unsigned int length) { + mem_chunk_t *new = enif_alloc(sizeof(mem_chunk_t)); + if (new == NULL) + return NULL; + new->next = NULL; + new->top = enif_alloc(sizeof(char) * length); + if (new->top == NULL) { + free(new); + return NULL; + } + new->curr = new->top + length - 1; + new->length = length; + return new; +} + +void ber_free_chunks(mem_chunk_t *chunk) { + mem_chunk_t *curr, *next = chunk; + while (next != NULL) { + curr = next; + next = curr->next; + enif_free(curr->top); + enif_free(curr); + } +} + +int ber_check_memory(mem_chunk_t **curr, unsigned int needed) { + mem_chunk_t *new; + if ((*curr)->curr-needed >= (*curr)->top) + return ASN1_OK; + + if ((new = ber_new_chunk((*curr)->length > needed ? (*curr)->length * 2 : (*curr)->length + needed)) == NULL) + return ASN1_ERROR; + new->next = *curr; + *curr = new; + return ASN1_OK; +} + static ERL_NIF_TERM encode_per_complete(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ERL_NIF_TERM err_code; @@ -1018,11 +1206,11 @@ static ERL_NIF_TERM encode_per_complete(ErlNifEnv* env, int argc, if (in_binary.size == 0) return enif_make_binary(env, &out_binary); - if ((complete_len = complete(&out_binary, in_binary.data, in_binary.size)) - <= ASN1_ERROR) { + if ((complete_len = per_complete(&out_binary, in_binary.data, + in_binary.size)) <= ASN1_ERROR) { enif_release_binary(&out_binary); if (complete_len == ASN1_ERROR - ) + ) err_code = enif_make_uint(env, '1'); else err_code = enif_make_uint(env, 0); @@ -1043,7 +1231,7 @@ static ERL_NIF_TERM decode_ber_tlv(ErlNifEnv* env, int argc, if (!enif_inspect_iolist_as_binary(env, argv[0], &in_binary)) return enif_make_badarg(env); - if ((return_code = decode_begin(env, &return_term, in_binary.data, + if ((return_code = ber_decode_begin(env, &return_term, in_binary.data, in_binary.size, &err_pos)) != ASN1_OK ) return enif_make_tuple2(env, enif_make_atom(env,"error"), enif_make_tuple2(env, @@ -1051,6 +1239,43 @@ static ERL_NIF_TERM decode_ber_tlv(ErlNifEnv* env, int argc, return return_term; } +static ERL_NIF_TERM encode_ber_tlv(ErlNifEnv* env, int argc, + const ERL_NIF_TERM argv[]) { + ErlNifBinary out_binary; + unsigned int length = 0, pos = 0; + int encode_err; + mem_chunk_t *curr, *top; + ERL_NIF_TERM err_code; + + curr = ber_new_chunk(40); + + if ((encode_err = ber_encode(env, argv[0], &curr, &length)) + <= ASN1_ERROR) { + ber_free_chunks(curr); + err_code = enif_make_int(env, encode_err); + return enif_make_tuple2(env, enif_make_atom(env, "error"), err_code); + } + + if (!enif_alloc_binary(length, &out_binary)) { + ber_free_chunks(curr); + return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env,"oom")); + } + + top = curr; + + while (curr != NULL) { + length = curr->length - (curr->curr-curr->top) -1; + if (length > 0) + memcpy(out_binary.data + pos, curr->curr+1, length); + pos += length; + curr = curr->next; + } + + ber_free_chunks(top); + + return enif_make_binary(env, &out_binary); +} + static int is_ok_load_info(ErlNifEnv* env, ERL_NIF_TERM load_info) { int i; return enif_get_int(env, load_info, &i) && i == 1; @@ -1074,6 +1299,7 @@ static void unload(ErlNifEnv* env, void* priv_data) { } static ErlNifFunc nif_funcs[] = { { "encode_per_complete", 1, - encode_per_complete }, { "decode_ber_tlv", 1, decode_ber_tlv } }; + encode_per_complete }, { "decode_ber_tlv", 1, decode_ber_tlv }, { + "encode_ber_tlv", 1, encode_ber_tlv } }; ERL_NIF_INIT(asn1rt_nif, nif_funcs, load, NULL, upgrade, unload) diff --git a/lib/asn1/doc/src/asn1_ug.xml b/lib/asn1/doc/src/asn1_ug.xml index 61e4f6062f..1b399fb641 100644 --- a/lib/asn1/doc/src/asn1_ug.xml +++ b/lib/asn1/doc/src/asn1_ug.xml @@ -369,7 +369,7 @@ erlc -o ../asnfiles -I ../asnfiles -I /usr/local/standards/asn1 Person.asn <item> <p>Together with the flags <c>ber_bin</c> and <c>optimize</c> you choose to use a nif for considerable - faster decode. </p> + faster encode and decode. </p> </item> <tag><c>+asn1config</c></tag> <item> @@ -631,7 +631,7 @@ asn1ct:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre> </table> <p> - The sole compile options <c>ber</c>, <c>ber_bin</c>, <c>per</c> and + The compile options <c>ber</c>, <c>per</c> and <c>driver</c> are kept for backwards compatibility and should not be used in new code. The nif implementation which replaces the linked-in driver has been shown to be about 5-15% faster. diff --git a/lib/asn1/doc/src/asn1ct.xml b/lib/asn1/doc/src/asn1ct.xml index d7c2572dc8..13e6977419 100644 --- a/lib/asn1/doc/src/asn1ct.xml +++ b/lib/asn1/doc/src/asn1ct.xml @@ -225,8 +225,8 @@ Binary = binary() <item> <p>Option valid together with <c>ber_bin</c> and <c>optimize</c> options. It enables the use of several nifs that gives faster - decode. Nifs are only enabled by the explicit use of the option - <c>nif</c></p> + encode and decode. Nifs are only enabled by the explicit use of + the option <c>nif</c></p> </item> <tag><c>asn1config</c></tag> <item> @@ -269,7 +269,11 @@ Binary = binary() <c>.set.asn</c> are exported, unless a <c>{export,[atom()]}</c> or <c>{export_all,true}</c> option are provided. The list of atoms are names of chosen asn1 - specs from the <c>.set.asn</c> file.</p> + specs from the <c>.set.asn</c> file. </p> + <p>When used together with <c>nif</c> for <c>ber_bin</c>, the + asn1 nifs will be used if the <c>asn1rt_nif</c> module is + available. If it is not available, a slower erlang fallback + will be used.</p> </item> <tag><c>inline</c></tag> <item> diff --git a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl index e16873c717..243ff234a7 100644 --- a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl +++ b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl @@ -877,13 +877,13 @@ gen_dec_choice(Erules,TopType, _ChTag, CompList, Ext) -> emit([indent(9),"exit({error,{asn1,{invalid_choice_tag,", {curr,else},"}}})",nl]); _ -> - emit([indent(9),"{asn1_ExtAlt, ?RT_BER:encode(",{curr,else},")}",nl]) + emit([indent(9),"{asn1_ExtAlt, ?RT_BER:encode(",{curr,else}, + asn1ct_gen:nif_parameter(),")}",nl]) end, emit([indent(3),"end",nl]), asn1ct_name:new(tag), asn1ct_name:new(else). - gen_dec_choice_cases(_Erules,_TopType, []) -> ok; gen_dec_choice_cases(Erules,TopType, [H|T]) -> diff --git a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl index e8a4ad0cf1..781271bae7 100644 --- a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl +++ b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl @@ -728,13 +728,13 @@ gen_dec_prim(Erules,Att,BytesVar,DoTag,TagIn,Form,OptOrMand) -> {_,#'ObjectClassFieldType'{}} -> case asn1ct_gen:get_inner(Att#type.def) of 'ASN1_OPEN_TYPE' -> - emit([{asis,DoTag},")"]); + emit([{asis,DoTag},asn1ct_gen:nif_parameter(),")"]); _ -> ok end; {{string,TagStr},'ASN1_OPEN_TYPE'} -> - emit([TagStr,")"]); + emit([TagStr,asn1ct_gen:nif_parameter(),")"]); {_,'ASN1_OPEN_TYPE'} -> - emit([{asis,DoTag},")"]); + emit([{asis,DoTag},asn1ct_gen:nif_parameter(),")"]); {{string,TagStr},_} -> emit([TagStr,")"]); _ when is_list(DoTag) -> @@ -1502,13 +1502,14 @@ gen_objset_dec(Erules,ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName, _ClFields,_NthObj) -> emit(["'getdec_",ObjSetName,"'(_, _) ->",nl]), emit([indent(2),"fun(_,Bytes, _RestPrimFieldName) ->",nl]), + case Erules of ber_bin_v2 -> emit([indent(4),"case Bytes of",nl, indent(6),"Bin when is_binary(Bin) -> ",nl, indent(8),"Bin;",nl, indent(6),"_ ->",nl, - indent(8),"?RT_BER:encode(Bytes)",nl, + indent(8),"?RT_BER:encode(Bytes",driver_parameter(),")",nl, indent(4),"end",nl]); _ -> emit([indent(6),"Len = case Bytes of",nl,indent(9), @@ -1521,6 +1522,14 @@ gen_objset_dec(Erules,ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName, gen_objset_dec(_,_,_,[],_,_,_) -> ok. +driver_parameter() -> + Options = get(encoding_options), + case {lists:member(driver,Options),lists:member(nif,Options)} of + {true,_} -> ",nif"; + {_,true} -> ",nif"; + _ -> ",erlang" + end. + emit_default_getdec(ObjSetName,UniqueName) -> emit(["'getdec_",ObjSetName,"'(",{asis,UniqueName},", ErrV) ->",nl]), emit([indent(2), "fun(C,V,_) -> exit({{component,C},{value,V},{unique_name_and_value,",{asis,UniqueName},", ErrV}}) end"]). diff --git a/lib/asn1/src/asn1rt_ber_bin_v2.erl b/lib/asn1/src/asn1rt_ber_bin_v2.erl index 2df289e2b8..bef2216091 100644 --- a/lib/asn1/src/asn1rt_ber_bin_v2.erl +++ b/lib/asn1/src/asn1rt_ber_bin_v2.erl @@ -21,7 +21,7 @@ %% encoding / decoding of BER --export([decode/1, decode/2, match_tags/2, encode/1]). +-export([decode/1, decode/2, match_tags/2, encode/1, encode/2]). -export([fixoptionals/2, cindex/3, list_to_record/2, encode_tag_val/1, @@ -50,10 +50,13 @@ -export([encode_open_type/1,encode_open_type/2, decode_open_type/2,decode_open_type/3, - decode_open_type_as_binary/2]). + decode_open_type_as_binary/2, + decode_open_type_as_binary/3]). -export([decode_primitive_incomplete/2,decode_selective/2]). - + +-export([is_nif_loadable/0]). + -include("asn1_records.hrl"). % the encoding of class of tag bits 8 and 7 @@ -126,15 +129,28 @@ % encode(Tlv) -> % encode_constructed(Tlv). -encode([Tlv]) -> - encode(Tlv); -encode({TlvTag,TlvVal}) when is_list(TlvVal) -> +encode(Tlv) -> + encode(Tlv,erlang). + +encode(Tlv,_) when is_binary(Tlv) -> + Tlv; +encode([Tlv],Method) -> + encode(Tlv,Method); +encode(Tlv, nif) -> + case is_nif_loadable() of + true -> + asn1rt_nif:encode_ber_tlv(Tlv); + false -> + encode_erl(Tlv) + end; +encode(Tlv, _) -> + encode_erl(Tlv). + +encode_erl({TlvTag,TlvVal}) when is_list(TlvVal) -> %% constructed form of value encode_tlv(TlvTag,TlvVal,?CONSTRUCTED); -encode({TlvTag,TlvVal}) -> - encode_tlv(TlvTag,TlvVal,?PRIMITIVE); -encode(Bin) when is_binary(Bin) -> - Bin. +encode_erl({TlvTag,TlvVal}) -> + encode_tlv(TlvTag,TlvVal,?PRIMITIVE). encode_tlv(TlvTag,TlvVal,Form) -> Tag = encode_tlv_tag(TlvTag,Form), @@ -153,7 +169,7 @@ encode_tlv_val(Bin) -> {Bin,size(Bin)}. encode_tlv_list([Tlv|Tlvs],Acc) -> - EncTlv = encode(Tlv), + EncTlv = encode_erl(Tlv), encode_tlv_list(Tlvs,[EncTlv|Acc]); encode_tlv_list([],Acc) -> Bin=list_to_binary(lists:reverse(Acc)), @@ -164,28 +180,36 @@ decode(B) -> %% asn1-1.7 decode(B, nif) -> - case application:get_env(asn1, nif_loadable) of - {ok, true} -> + case is_nif_loadable() of + true -> case asn1rt_nif:decode_ber_tlv(B) of {error, Reason} -> handle_error(Reason, B); Else -> Else end; - {ok, false} -> - decode(B); - undefined -> - case catch code:load_file(asn1rt_nif) of - {module, asn1rt_nif} -> - application:set_env(asn1, nif_loadable, true); - _Else -> - application:set_env(asn1, nif_loadable, false) - end, - decode(B, nif) + false -> + decode(B) end; decode(B,erlang) when is_binary(B) -> decode_primitive(B); decode(Tlv,erlang) -> {Tlv,<<>>}. +%% Have to check this since asn1 is not guaranteed to be available +is_nif_loadable() -> + case application:get_env(asn1, nif_loadable) of + {ok,R} -> + R; + undefined -> + case catch code:load_file(asn1rt_nif) of + {module, asn1rt_nif} -> + application:set_env(asn1, nif_loadable, true), + true; + _Else -> + application:set_env(asn1, nif_loadable, false), + false + end + end. + handle_error([],_)-> exit({error,{asn1,{"memory allocation problem"}}}); handle_error({$1,_},L) -> % error in nif @@ -780,12 +804,14 @@ decode_open_type(Tlv, TagIn, Method) -> end. -decode_open_type_as_binary(Tlv,TagIn)-> +decode_open_type_as_binary(Tlv, TagIn) -> + decode_open_type_as_binary(Tlv, TagIn, erlang). +decode_open_type_as_binary(Tlv,TagIn, Method)-> case match_tags(Tlv,TagIn) of V when is_binary(V) -> V; - [Tlv2] -> encode(Tlv2); - Tlv2 -> encode(Tlv2) + [Tlv2] -> encode(Tlv2, Method); + Tlv2 -> encode(Tlv2, Method) end. %%=============================================================================== diff --git a/lib/asn1/src/asn1rt_nif.erl b/lib/asn1/src/asn1rt_nif.erl index 8580c70e6b..de1fb94816 100644 --- a/lib/asn1/src/asn1rt_nif.erl +++ b/lib/asn1/src/asn1rt_nif.erl @@ -22,7 +22,8 @@ %% Nif interface for asn1 -export([encode_per_complete/1, - decode_ber_tlv/1]). + decode_ber_tlv/1, + encode_ber_tlv/1]). -on_load(load_nif/0). @@ -76,8 +77,11 @@ load_nif() -> Status end. -encode_per_complete(_Binary) -> +encode_per_complete(_TagValueList) -> erlang:nif_error({nif_not_loaded,module,?MODULE,line,?LINE}). decode_ber_tlv(_Binary) -> erlang:nif_error({nif_not_loaded,module,?MODULE,line,?LINE}). + +encode_ber_tlv(_TagValueList) -> + erlang:nif_error({nif_not_loaded,module,?MODULE,line,?LINE}). diff --git a/lib/asn1/test/asn1_bin_v2_particular_SUITE.erl.src b/lib/asn1/test/asn1_bin_v2_particular_SUITE.erl.src index 6e15aa9fdc..4c3c8c7808 100644 --- a/lib/asn1/test/asn1_bin_v2_particular_SUITE.erl.src +++ b/lib/asn1/test/asn1_bin_v2_particular_SUITE.erl.src @@ -1,5 +1,5 @@ -particular() -> [smp, per_performance, ber_performance, ticket7904]. +particular() -> [smp, ticket7904]. smp(suite) -> []; @@ -34,104 +34,186 @@ smp(Config) -> end. per_performance(Config) -> + PrivDir = proplists:get_value(priv_dir, Config), + NifDir = filename:join(PrivDir,"nif"), + ErlDir = filename:join(PrivDir,"erl"), + file:make_dir(NifDir),file:make_dir(ErlDir), ?line Msg = {initiatingMessage, testNBAPsystem:cell_setup_req_msg()}, - ?line ok = testNBAPsystem:compile(Config,per_bin,[optimize]), - NumOfProcs = erlang:system_info(schedulers)*10, - N = 10000, - SmpN = lists:seq(1,round(N/NumOfProcs)), - - asn1_wrapper:encode('NBAP-PDU-Discriptions','NBAP-PDU', Msg), - - PerFun = fun() -> - [asn1_wrapper:encode('NBAP-PDU-Discriptions', - 'NBAP-PDU', - Msg) || _I <- lists:seq(1,N)], - ok + ?line ok = testNBAPsystem:compile([{priv_dir,NifDir}|Config],per_bin, + [optimize]), + ?line ok = testNBAPsystem:compile([{priv_dir,ErlDir}|Config],per_bin, + []), + + Modules = ['NBAP-CommonDataTypes', + 'NBAP-Constants', + 'NBAP-Containers', + 'NBAP-IEs', + 'NBAP-PDU-Contents', + 'NBAP-PDU-Discriptions'], + + + PreNif = fun() -> + code:add_patha(NifDir), + lists:foreach(fun(M) -> + code:purge(M), + code:load_file(M) + end,Modules) + end, + + PreErl = fun() -> + code:add_patha(ErlDir), + lists:foreach(fun(M) -> + code:purge(M), + code:load_file(M) + end,Modules) end, - PerSMPFun = - fun() -> - pforeach(fun(_) -> - [asn1_wrapper:encode('NBAP-PDU-Discriptions', - 'NBAP-PDU', - Msg) || _I <- SmpN] - end,lists:seq(1,NumOfProcs)) - end, - - ?line {TimeN,ok} = timer:tc(PerFun), - ?line {TimeNS,ok} = timer:tc(PerSMPFun), - - ?line ok = testNBAPsystem:compile(Config,per_bin,[]), - - ?line {TimeE,ok} = timer:tc(PerFun), - ?line {TimeES,ok} = timer:tc(PerSMPFun), - - ct:log("Seq:<br/>" - "Nif : ~p (~.2f%)<br/>" - "Erlang: ~p (~.2f%)<br/>" - "Parallel:<br/>" - "Nif : ~p (~.2f%)<br/>" - "Erlang: ~p (~.2f%)<br/>", - [TimeN,TimeN/TimeN*100, - TimeE,TimeE/TimeN*100, - TimeNS,TimeNS/TimeNS*100, - TimeES,TimeES/TimeNS*100]), - - {comment, lists:flatten(io_lib:format("Nifs are ~.2f% faster than erlang!", - [faster(TimeN+TimeNS, - TimeE+TimeES)]))}. + Func = fun() -> + element(1,timer:tc( + asn1_wrapper,encode,['NBAP-PDU-Discriptions', + 'NBAP-PDU', + Msg])) + end, + + nif_vs_erlang_performance({{{PreNif,Func},{PreErl,Func}},100000,32}). ber_performance(Config) -> ?line Msg = {initiatingMessage, testNBAPsystem:cell_setup_req_msg()}, ?line ok = testNBAPsystem:compile(Config,ber_bin,[optimize,nif]), - NumOfProcs = erlang:system_info(schedulers)*10, - N = 10000, - SmpN = lists:seq(1,round(N/NumOfProcs)), - {ok,B} = asn1_wrapper:encode('NBAP-PDU-Discriptions','NBAP-PDU', Msg), BerFun = fun() -> - [asn1_wrapper:decode( + {ok,B} = asn1_wrapper:encode('NBAP-PDU-Discriptions', + 'NBAP-PDU', Msg), + asn1_wrapper:decode( 'NBAP-PDU-Discriptions', 'NBAP-PDU', - B) || _I <- lists:seq(1,N)], - ok + B) end, - BerSMPFun = - fun() -> - pforeach(fun(_) -> - [asn1_wrapper:decode( - 'NBAP-PDU-Discriptions', - 'NBAP-PDU', - B) || _I <- SmpN] - end,lists:seq(1,NumOfProcs)) - end, - - ?line {TimeN,ok} = timer:tc(BerFun), - ?line {TimeNS,ok} = timer:tc(BerSMPFun), + nif_vs_erlang_performance({BerFun,100000,32}). - ?line ok = testNBAPsystem:compile(Config,ber_bin,[optimize]), +cert_pem_performance(Config) when is_list(Config) -> + cert_pem_performance({100000, 32}); +cert_pem_performance({N,S}) -> + nif_vs_erlang_performance({fun cert_pem/0,N,S}). - ?line {TimeE,ok} = timer:tc(BerFun), - ?line {TimeES,ok} = timer:tc(BerSMPFun), +dsa_pem_performance(Config) when is_list(Config) -> + cert_pem_performance({100000, 32}); +dsa_pem_performance({N,S}) -> + nif_vs_erlang_performance({fun dsa_pem/0,N,S}). + + +nif_vs_erlang_performance({{TC1,TC2},N,Sched}) -> + random:seed({123,456,789}), + io:format("Running a ~p sample with ~p max procs...~n~n",[N,Sched]), + + {True,False} = exec(TC1,TC2,Sched,N+1), + + io:format("~ndone!~n"), + + io:format("~n"),TStats = print_stats(strip(True,N div 20)), + io:format("~n"),FStats = print_stats(strip(False,N div 20)), + Str = io_lib:format("~nNifs are ~.3f% faster than erlang!~n", + [(element(2,FStats) - element(2,TStats)) / + element(2,FStats) * 100]), + io:format(Str), + {comment, lists:flatten(Str)}; +nif_vs_erlang_performance({T,N,Sched}) -> + PTC1 = fun() -> + application:set_env(asn1, nif_loadable, true) + end, + PTC2 = fun() -> + application:set_env(asn1, nif_loadable, false) + end, + TC = fun() -> + element(1,timer:tc(T)) + end, + nif_vs_erlang_performance({{{PTC1,TC},{PTC2,TC}},N,Sched}). + - ct:log("Seq:<br/>" - "Nif : ~p (~.2f%)<br/>" - "Erlang: ~p (~.2f%)<br/>" - "Parallel:<br/>" - "Nif : ~p (~.2f%)<br/>" - "Erlang: ~p (~.2f%)<br/>", - [TimeN,TimeN/TimeN*100, - TimeE,TimeE/TimeN*100, - TimeNS,TimeNS/TimeNS*100, - TimeES,TimeES/TimeNS*100]), +print_stats(Data) -> + Length = length(Data), + Mean = lists:sum(Data) / Length, + Variance = lists:foldl(fun(N,Acc) -> math:pow(N - Mean, 2)+Acc end, 0, Data), + StdDev = math:sqrt(Variance / Length), + Median = lists:nth(round(Length/2),Data), + Min = lists:min(Data), + Max = lists:max(Data), + if Length < 20 -> + io:format("Data: ~w~n",[Data]); + true -> + ok + end, + io:format("Length: ~p~nMean: ~p~nStdDev: ~p~nMedian: ~p~nMin: ~p~nMax: ~p~n", + [Length,Mean,StdDev,Median,Min,Max]), + {Length,Mean,StdDev,Median,Min,Max}. + +collect(Acc) -> + receive + {Tag,Val} -> + Prev = proplists:get_value(Tag,Acc,[]), + collect(lists:keystore(Tag,1,Acc,{Tag,[Val|Prev]})) + after 100 -> + Acc + end. - {comment, lists:flatten(io_lib:format("Nifs are ~.2f% faster than erlang!", - [faster(TimeN+TimeNS, - TimeE+TimeES)]))}. +exec(One,Two,Max,N) -> + exec(One,Two,Max,N,{[],[]}). +exec(_,_,_,1,{D1,D2}) -> + {lists:flatten(D1),lists:flatten(D2)}; +exec({PreOne,One} = O,{PreTwo,Two} = T,MaxProcs, N, {D1,D2}) -> + Num = random:uniform(round(N/2)), + if Num rem 3 == 0 -> + timer:sleep(Num rem 1000); + true -> + ok + end, + Procs = random:uniform(MaxProcs), + io:format("\tBatch: ~p items in ~p processes, ~p left~n",[Num,Procs,N-Num]), + if Num rem 2 == 1 -> + erlang:garbage_collect(), + PreOne(), + MoreOne = pexec(One, Num, Procs, []), + erlang:garbage_collect(), + PreTwo(), + MoreTwo = pexec(Two, Num, Procs, []); + true -> + erlang:garbage_collect(), + PreTwo(), + MoreTwo = pexec(Two, Num, Procs, []), + erlang:garbage_collect(), + PreOne(), + MoreOne = pexec(One, Num, Procs, []) + end, + exec(O,T,MaxProcs,N-Num,{[MoreOne|D1], + [MoreTwo|D2]}). + +pexec(_Fun, _, 0, []) -> + []; +pexec(Fun, _, 0, [{Ref,Pid}|Rest]) -> + receive + {data,D} -> + [D|pexec(Fun,0,0,[{Ref,Pid}|Rest])]; + {'DOWN', Ref, process, Pid, normal} -> + pexec(Fun, 0,0,Rest) + end; +pexec(Fun, 0, 1, AccProcs) -> + pexec(Fun, 0, 0, AccProcs); +pexec(Fun, N, 1, AccProcs) -> + [Fun()|pexec(Fun, N - 1, 1, AccProcs)]; +pexec(Fun, N, Procs, AccProcs) -> + S = self(), + Pid = spawn(fun() -> + S ! {data,pexec(Fun,N,1,[])} + end), + Ref = erlang:monitor(process, Pid), + pexec(Fun, N, Procs - 1, [{Ref,Pid}|AccProcs]). +strip(Data,Num) -> + {_,R} = lists:split(Num,lists:sort(Data)), + element(2,lists:split(Num,lists:reverse(R))). faster(A,B) -> (B - A)/B * 100. @@ -189,3 +271,21 @@ ticket7904(Config) -> ?line {ok,_} = 'RANAPextract1':encode('InitiatingMessage', Val1), asn1rt:unload_driver(), ?line {ok,_} = 'RANAPextract1':encode('InitiatingMessage', Val1). + +cert_pem() -> + 'OTP-PUB-KEY':decode('Certificate',<<48,130,3,184,48,130,3,33,160,3,2,1,2,2,1,1,48,13,6,9,42,134,72,134,247,13,1,1,5,5,0,48,129,131,49,14,48,12,6,3,85,4,3,19,5,111,116,112,67,65,49,19,48,17,6,3,85,4,11,19,10,69,114,108,97,110,103,32,79,84,80,49,20,48,18,6,3,85,4,10,19,11,69,114,105,99,115,115,111,110,32,65,66,49,11,48,9,6,3,85,4,6,19,2,83,69,49,18,48,16,6,3,85,4,7,19,9,83,116,111,99,107,104,111,108,109,49,37,48,35,6,9,42,134,72,134,247,13,1,9,1,22,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,48,30,23,13,48,56,48,49,48,57,48,56,50,57,51,48,90,23,13,49,55,49,49,49,55,48,56,50,57,51,48,90,48,129,132,49,15,48,13,6,3,85,4,3,19,6,99,108,105,101,110,116,49,19,48,17,6,3,85,4,11,19,10,69,114,108,97,110,103,32,79,84,80,49,20,48,18,6,3,85,4,10,19,11,69,114,105,99,115,115,111,110,32,65,66,49,11,48,9,6,3,85,4,6,19,2,83,69,49,18,48,16,6,3,85,4,7,19,9,83,116,111,99,107,104,111,108,109,49,37,48,35,6,9,42,134,72,134,247,13,1,9,1,22,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,48,129,159,48,13,6,9,42,134,72,134,247,13,1,1,1,5,0,3,129,141,0,48,129,137,2,129,129,0,245,56,68,254,220,239,193,190,63,221,182,60,67,77,121,163,214,136,137,183,139,8,166,30,100,27,45,17,126,58,15,173,151,218,75,224,148,14,22,164,10,100,186,183,104,175,197,97,96,182,146,150,106,129,140,100,194,106,90,62,133,233,155,46,155,33,101,220,83,193,182,232,240,99,253,249,114,8,159,172,143,77,179,132,229,205,29,110,185,233,224,52,25,149,249,100,80,229,199,125,23,106,146,233,159,26,13,8,161,206,221,43,240,149,42,45,194,190,85,6,235,152,220,219,160,32,144,67,2,3,1,0,1,163,130,1,55,48,130,1,51,48,9,6,3,85,29,19,4,2,48,0,48,11,6,3,85,29,15,4,4,3,2,5,224,48,29,6,3,85,29,14,4,22,4,20,26,59,44,5,72,211,158,214,23,34,30,241,125,27,123,115,93,163,231,120,48,129,179,6,3,85,29,35,4,129,171,48,129,168,128,20,6,171,128,52,58,164,184,118,178,189,157,46,40,229,109,145,222,125,1,155,161,129,140,164,129,137,48,129,134,49,17,48,15,6,3,85,4,3,19,8,101,114,108,97,110,103,67,65,49,19,48,17,6,3,85,4,11,19,10,69,114,108,97,110,103,32,79,84,80,49,20,48,18,6,3,85,4,10,19,11,69,114,105,99,115,115,111,110,32,65,66,49,18,48,16,6,3,85,4,7,19,9,83,116,111,99,107,104,111,108,109,49,11,48,9,6,3,85,4,6,19,2,83,69,49,37,48,35,6,9,42,134,72,134,247,13,1,9,1,22,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,130,1,1,48,33,6,3,85,29,17,4,26,48,24,129,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,48,33,6,3,85,29,18,4,26,48,24,129,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,48,13,6,9,42,134,72,134,247,13,1,1,5,5,0,3,129,129,0,93,11,112,227,121,15,121,179,247,135,110,216,17,197,84,18,149,166,147,142,190,178,0,209,190,0,142,233,144,100,194,205,220,182,73,204,108,42,95,23,48,63,4,120,239,42,194,25,184,35,117,107,96,229,18,45,76,122,125,40,171,210,132,50,146,178,160,55,17,35,255,208,114,30,47,55,185,154,155,165,204,180,14,143,20,234,6,234,201,225,72,235,5,87,61,255,250,23,217,1,144,246,98,221,223,102,49,168,177,13,70,241,26,27,254,251,217,14,244,18,242,197,151,50,186,214,15,42>>). + +dsa_pem() -> + 'OTP-PUB-KEY':decode('DSAPrivateKey',<<48,130,1,187,2,1,0,2,129,129,0,183,179,230,217,37,99,144,157,21,228,204,162,207,61,246,144,58,139,139,184,184,43,108,206,0,115,173,208,100,233,201,121,21,90,179,119,53,140,25,52,34,202,121,211,164,107,43,56,68,162,159,51,244,232,138,126,164,109,121,89,237,142,57,28,32,188,44,67,253,111,121,104,40,141,211,255,140,118,37,234,150,201,155,160,16,17,51,59,26,249,41,129,16,211,119,128,95,254,182,235,132,0,92,206,93,77,106,217,201,132,203,4,75,201,246,204,216,162,1,84,79,211,10,21,152,195,103,145,2,21,0,213,30,184,86,247,16,247,69,192,241,35,138,84,57,140,3,71,65,206,233,2,129,129,0,148,179,24,63,74,91,128,25,96,29,5,78,223,246,175,0,121,86,54,178,42,231,98,241,147,180,157,60,149,160,50,243,227,76,175,89,234,203,252,242,76,108,9,204,157,182,59,206,227,127,99,215,42,156,194,78,116,25,7,62,243,169,45,5,101,179,247,127,199,144,135,103,23,42,154,125,231,248,154,101,175,155,101,42,232,41,80,41,47,128,208,11,31,106,63,12,202,207,135,80,200,136,250,171,31,118,52,91,200,138,112,111,179,23,214,123,21,118,194,179,0,185,217,52,197,182,236,13,2,129,128,124,66,0,111,121,139,142,209,95,136,95,237,177,150,248,252,49,135,117,100,155,232,138,244,132,89,40,5,70,125,202,96,78,239,76,37,125,149,82,64,107,54,227,73,25,180,227,41,0,234,73,47,80,242,242,129,250,61,68,62,39,38,156,193,146,40,241,247,106,215,223,202,194,110,130,62,186,90,18,28,196,174,99,47,193,61,130,100,150,25,248,115,164,231,153,99,46,69,66,139,33,187,51,49,35,219,234,29,44,172,166,247,42,16,177,187,9,162,81,243,33,26,100,46,78,57,203,135,2,20,89,128,159,14,187,249,182,172,15,88,162,110,211,71,179,209,29,125,217,38>>), + 'OTP-PUB-KEY':decode('SubjectPublicKeyInfo',<<48,130,1,183,48,130,1,44,6,7,42,134,72,206,56,4,1,48,130,1,31,2,129,129,0,183,179,230,217,37,99,144,157,21,228,204,162,207,61,246,144,58,139,139,184,184,43,108,206,0,115,173,208,100,233,201,121,21,90,179,119,53,140,25,52,34,202,121,211,164,107,43,56,68,162,159,51,244,232,138,126,164,109,121,89,237,142,57,28,32,188,44,67,253,111,121,104,40,141,211,255,140,118,37,234,150,201,155,160,16,17,51,59,26,249,41,129,16,211,119,128,95,254,182,235,132,0,92,206,93,77,106,217,201,132,203,4,75,201,246,204,216,162,1,84,79,211,10,21,152,195,103,145,2,21,0,213,30,184,86,247,16,247,69,192,241,35,138,84,57,140,3,71,65,206,233,2,129,129,0,148,179,24,63,74,91,128,25,96,29,5,78,223,246,175,0,121,86,54,178,42,231,98,241,147,180,157,60,149,160,50,243,227,76,175,89,234,203,252,242,76,108,9,204,157,182,59,206,227,127,99,215,42,156,194,78,116,25,7,62,243,169,45,5,101,179,247,127,199,144,135,103,23,42,154,125,231,248,154,101,175,155,101,42,232,41,80,41,47,128,208,11,31,106,63,12,202,207,135,80,200,136,250,171,31,118,52,91,200,138,112,111,179,23,214,123,21,118,194,179,0,185,217,52,197,182,236,13,3,129,132,0,2,129,128,124,66,0,111,121,139,142,209,95,136,95,237,177,150,248,252,49,135,117,100,155,232,138,244,132,89,40,5,70,125,202,96,78,239,76,37,125,149,82,64,107,54,227,73,25,180,227,41,0,234,73,47,80,242,242,129,250,61,68,62,39,38,156,193,146,40,241,247,106,215,223,202,194,110,130,62,186,90,18,28,196,174,99,47,193,61,130,100,150,25,248,115,164,231,153,99,46,69,66,139,33,187,51,49,35,219,234,29,44,172,166,247,42,16,177,187,9,162,81,243,33,26,100,46,78,57,203,135>>), + 'OTP-PUB-KEY':decode('DSAParams',<<48,130,1,31,2,129,129,0,183,179,230,217,37,99,144,157,21,228,204,162,207,61,246,144,58,139,139,184,184,43,108,206,0,115,173,208,100,233,201,121,21,90,179,119,53,140,25,52,34,202,121,211,164,107,43,56,68,162,159,51,244,232,138,126,164,109,121,89,237,142,57,28,32,188,44,67,253,111,121,104,40,141,211,255,140,118,37,234,150,201,155,160,16,17,51,59,26,249,41,129,16,211,119,128,95,254,182,235,132,0,92,206,93,77,106,217,201,132,203,4,75,201,246,204,216,162,1,84,79,211,10,21,152,195,103,145,2,21,0,213,30,184,86,247,16,247,69,192,241,35,138,84,57,140,3,71,65,206,233,2,129,129,0,148,179,24,63,74,91,128,25,96,29,5,78,223,246,175,0,121,86,54,178,42,231,98,241,147,180,157,60,149,160,50,243,227,76,175,89,234,203,252,242,76,108,9,204,157,182,59,206,227,127,99,215,42,156,194,78,116,25,7,62,243,169,45,5,101,179,247,127,199,144,135,103,23,42,154,125,231,248,154,101,175,155,101,42,232,41,80,41,47,128,208,11,31,106,63,12,202,207,135,80,200,136,250,171,31,118,52,91,200,138,112,111,179,23,214,123,21,118,194,179,0,185,217,52,197,182,236,13>>), + 'OTP-PUB-KEY':decode('DSAPublicKey',<<2,129,128,124,66,0,111,121,139,142,209,95,136,95,237,177,150,248,252,49,135,117,100,155,232,138,244,132,89,40,5,70,125,202,96,78,239,76,37,125,149,82,64,107,54,227,73,25,180,227,41,0,234,73,47,80,242,242,129,250,61,68,62,39,38,156,193,146,40,241,247,106,215,223,202,194,110,130,62,186,90,18,28,196,174,99,47,193,61,130,100,150,25,248,115,164,231,153,99,46,69,66,139,33,187,51,49,35,219,234,29,44,172,166,247,42,16,177,187,9,162,81,243,33,26,100,46,78,57,203,135>>), + 'OTP-PUB-KEY':encode('DSAParams',{params,{'Dss-Parms',129000451850199666185842362389296595317127259539517666765336291347244303954511451744518587442120964433734460998523119938005801396466878889993179871123036311260456172022864663021425348874648247531097042575063545128239655736096045972718934778583429973433661785691086624069991876932064334822608460064613803976593,1216700114794736143432235288305776850295620488937,104420402274523493329542694749036577763086597934731674202966304958550599470165597750883637440049774107540742087494301536297571301945349213110548764383811017178451900599240379681904765817950545426764751538502808499880604633364255316249231153053427235538288687666086821781456733226598288985591031656134573747213}}), + 'OTP-PUB-KEY':encode( + 'SubjectPublicKeyInfo', + {'SubjectPublicKeyInfo', + {'AlgorithmIdentifier', + {1,2,840,10040,4,1}, + <<48,130,1,31,2,129,129,0,183,179,230,217,37,99,144,157,21,228,204,162,207,61,246,144,58,139,139,184,184,43,108,206,0,115,173,208,100,233,201,121,21,90,179,119,53,140,25,52,34,202,121,211,164,107,43,56,68,162,159,51,244,232,138,126,164,109,121,89,237,142,57,28,32,188,44,67,253,111,121,104,40,141,211,255,140,118,37,234,150,201,155,160,16,17,51,59,26,249,41,129,16,211,119,128,95,254,182,235,132,0,92,206,93,77,106,217,201,132,203,4,75,201,246,204,216,162,1,84,79,211,10,21,152,195,103,145,2,21,0,213,30,184,86,247,16,247,69,192,241,35,138,84,57,140,3,71,65,206,233,2,129,129,0,148,179,24,63,74,91,128,25,96,29,5,78,223,246,175,0,121,86,54,178,42,231,98,241,147,180,157,60,149,160,50,243,227,76,175,89,234,203,252,242,76,108,9,204,157,182,59,206,227,127,99,215,42,156,194,78,116,25,7,62,243,169,45,5,101,179,247,127,199,144,135,103,23,42,154,125,231,248,154,101,175,155,101,42,232,41,80,41,47,128,208,11,31,106,63,12,202,207,135,80,200,136,250,171,31,118,52,91,200,138,112,111,179,23,214,123,21,118,194,179,0,185,217,52,197,182,236,13>>}, + {0, + <<2,129,128,124,66,0,111,121,139,142,209,95,136,95,237,177,150,248,252,49,135,117,100,155,232,138,244,132,89,40,5,70,125,202,96,78,239,76,37,125,149,82,64,107,54,227,73,25,180,227,41,0,234,73,47,80,242,242,129,250,61,68,62,39,38,156,193,146,40,241,247,106,215,223,202,194,110,130,62,186,90,18,28,196,174,99,47,193,61,130,100,150,25,248,115,164,231,153,99,46,69,66,139,33,187,51,49,35,219,234,29,44,172,166,247,42,16,177,187,9,162,81,243,33,26,100,46,78,57,203,135>>}}). |