aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--bootstrap/lib/compiler/ebin/beam_a.beambin2236 -> 2288 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/compile.beambin37788 -> 37728 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/os.beambin5276 -> 5280 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/beam_lib.beambin18112 -> 18104 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_eval.beambin23220 -> 22692 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/otp_internal.beambin7860 -> 10004 bytes
-rw-r--r--erts/configure.in1
-rw-r--r--erts/doc/src/erl.xml24
-rw-r--r--erts/emulator/Makefile.in7
-rw-r--r--erts/emulator/beam/atom.names1
-rw-r--r--erts/emulator/beam/erl_afit_alloc.c6
-rw-r--r--erts/emulator/beam/erl_afit_alloc.h2
-rw-r--r--erts/emulator/beam/erl_alloc.c23
-rw-r--r--erts/emulator/beam/erl_alloc.types2
-rw-r--r--erts/emulator/beam/erl_alloc_util.c62
-rw-r--r--erts/emulator/beam/erl_alloc_util.h2
-rw-r--r--erts/emulator/beam/erl_ao_firstfit_alloc.c22
-rw-r--r--erts/emulator/beam/erl_ao_firstfit_alloc.h2
-rw-r--r--erts/emulator/beam/erl_bestfit_alloc.c24
-rw-r--r--erts/emulator/beam/erl_bestfit_alloc.h2
-rwxr-xr-xerts/emulator/beam/erl_bif_info.c19
-rw-r--r--erts/emulator/beam/erl_gc.c173
-rw-r--r--erts/emulator/beam/erl_goodfit_alloc.c14
-rw-r--r--erts/emulator/beam/erl_goodfit_alloc.h2
-rw-r--r--erts/emulator/beam/erl_init.c61
-rw-r--r--erts/emulator/beam/erl_process.c7
-rw-r--r--erts/emulator/beam/erl_process.h9
-rw-r--r--erts/emulator/beam/erl_ptab.c342
-rw-r--r--erts/emulator/beam/erl_ptab.h13
-rwxr-xr-xerts/emulator/beam/global.h8
-rw-r--r--erts/emulator/beam/io.c6
-rw-r--r--erts/emulator/sys/common/erl_mseg.c27
-rw-r--r--erts/emulator/sys/common/erl_mseg.h5
-rw-r--r--erts/emulator/sys/win32/sys_float.c4
-rw-r--r--erts/emulator/test/driver_SUITE_data/thr_alloc_drv.c4
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c75
-rw-r--r--erts/emulator/test/port_SUITE.erl13
-rw-r--r--erts/emulator/test/process_SUITE.erl12
-rw-r--r--erts/etc/unix/cerl.src33
-rw-r--r--erts/preloaded/ebin/erlang.beambin92912 -> 93520 bytes
-rw-r--r--erts/preloaded/ebin/prim_eval.beambin0 -> 1352 bytes
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin70072 -> 70216 bytes
-rw-r--r--erts/preloaded/src/.gitignore1
-rw-r--r--erts/preloaded/src/Makefile26
-rw-r--r--erts/preloaded/src/add_abstract_code34
-rw-r--r--erts/preloaded/src/erlang.erl20
-rw-r--r--erts/preloaded/src/prim_eval.S70
-rw-r--r--erts/preloaded/src/prim_eval.erl28
-rw-r--r--erts/preloaded/src/prim_inet.erl23
-rw-r--r--lib/asn1/src/Makefile10
-rw-r--r--lib/asn1/src/asn1_db.erl67
-rw-r--r--lib/asn1/src/asn1_records.hrl2
-rw-r--r--lib/asn1/src/asn1ct.erl573
-rw-r--r--lib/asn1/src/asn1ct_check.erl970
-rw-r--r--lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl83
-rw-r--r--lib/asn1/src/asn1ct_constructed_per.erl573
-rw-r--r--lib/asn1/src/asn1ct_func.erl21
-rw-r--r--lib/asn1/src/asn1ct_gen.erl179
-rw-r--r--lib/asn1/src/asn1ct_gen_ber_bin_v2.erl532
-rw-r--r--lib/asn1/src/asn1ct_gen_per.erl553
-rw-r--r--lib/asn1/src/asn1ct_gen_per_rt2ct.erl946
-rw-r--r--lib/asn1/src/asn1ct_imm.erl85
-rw-r--r--lib/asn1/src/asn1ct_name.erl152
-rw-r--r--lib/asn1/src/asn1ct_parser2.erl7
-rw-r--r--lib/asn1/src/asn1ct_value.erl4
-rw-r--r--lib/asn1/src/asn1rtt_ber.erl136
-rw-r--r--lib/asn1/src/asn1rtt_per.erl187
-rw-r--r--lib/asn1/src/asn1rtt_uper.erl178
-rw-r--r--lib/asn1/test/Makefile3
-rw-r--r--lib/asn1/test/asn1_SUITE.erl40
-rw-r--r--lib/asn1/test/asn1_SUITE_data/BadEnumValue1.asn8
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Certificate.asn0
-rw-r--r--lib/asn1/test/asn1_SUITE_data/ChoExtension.asn16
-rw-r--r--lib/asn1/test/asn1_SUITE_data/ConstraintEquivalence.asn120
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Constraints.py7
-rw-r--r--lib/asn1/test/asn1_SUITE_data/EUTRA-InterNodeDefinitions.asn123
-rw-r--r--lib/asn1/test/asn1_SUITE_data/EUTRA-UE-Variables.asn49
-rw-r--r--lib/asn1/test/asn1_SUITE_data/EnumExt.asn163
-rw-r--r--lib/asn1/test/asn1_SUITE_data/InfObj.asn92
-rw-r--r--lib/asn1/test/asn1_SUITE_data/InfObj2.asn156
-rw-r--r--lib/asn1/test/asn1_SUITE_data/MAP-insertSubscriberData-def.py102
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Mod.set.asn5
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Mod1.asn18
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Mod2.asn43
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Mod3.asn33
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Mod4.asn33
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Mod5.asn37
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Mvrasn.set.asn7
-rw-r--r--lib/asn1/test/asn1_SUITE_data/P-Record.asn1dbbin3128 -> 0 bytes
-rw-r--r--lib/asn1/test/asn1_SUITE_data/P-Record.erl244
-rw-r--r--lib/asn1/test/asn1_SUITE_data/P-Record.hrl17
-rw-r--r--lib/asn1/test/asn1_SUITE_data/PDUs.py325
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Pattern.asn8
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Prim.asn112
-rw-r--r--lib/asn1/test/asn1_SUITE_data/PrimStrings.asn179
-rw-r--r--lib/asn1/test/asn1_SUITE_data/ROSE.asn1449
-rw-r--r--lib/asn1/test/asn1_SUITE_data/SeqDefault.asn111
-rw-r--r--lib/asn1/test/asn1_SUITE_data/SeqOf.asn19
-rw-r--r--lib/asn1/test/asn1_SUITE_data/SetDefault.asn111
-rw-r--r--lib/asn1/test/asn1_SUITE_data/TConstr.asn16
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Tst.py153
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Two.py34
-rw-r--r--lib/asn1/test/asn1_SUITE_data/UPERDefault.asn18
-rw-r--r--lib/asn1/test/asn1_SUITE_data/UndefType.py14
-rw-r--r--lib/asn1/test/asn1_SUITE_data/extensionAdditionGroup.erl82
-rw-r--r--lib/asn1/test/asn1_test_lib.erl9
-rw-r--r--lib/asn1/test/error_SUITE.erl104
-rw-r--r--lib/asn1/test/testChoExtension.erl5
-rw-r--r--lib/asn1/test/testCompactBitString.erl2
-rw-r--r--lib/asn1/test/testConstraints.erl61
-rw-r--r--lib/asn1/test/testDeepTConstr.erl59
-rw-r--r--lib/asn1/test/testEnumExt.erl12
-rw-r--r--lib/asn1/test/testInfObj.erl47
-rw-r--r--lib/asn1/test/testPrim.erl569
-rw-r--r--lib/asn1/test/testPrimStrings.erl521
-rw-r--r--lib/asn1/test/testSeqOf.erl281
-rw-r--r--lib/common_test/src/ct_config.erl10
-rw-r--r--lib/common_test/src/ct_util.erl2
-rw-r--r--lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl70
-rw-r--r--lib/common_test/test/ct_telnet_SUITE.erl15
-rw-r--r--lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_timetrap_SUITE.erl76
-rw-r--r--lib/compiler/src/beam_a.erl4
-rw-r--r--lib/compiler/src/beam_utils.erl4
-rw-r--r--lib/compiler/src/compile.erl20
-rw-r--r--lib/compiler/test/compile_SUITE.erl10
-rw-r--r--lib/compiler/test/compile_SUITE_data/key_compatibility.beambin0 -> 844 bytes
-rw-r--r--lib/compiler/test/compile_SUITE_data/key_compatibility.erl8
-rw-r--r--lib/compiler/test/receive_SUITE.erl21
-rw-r--r--lib/crypto/c_src/crypto.c2
-rw-r--r--lib/crypto/doc/src/crypto.xml108
-rw-r--r--lib/crypto/src/crypto.erl116
-rw-r--r--lib/crypto/test/Makefile3
-rw-r--r--lib/crypto/test/crypto_SUITE.erl3347
-rw-r--r--lib/crypto/test/old_crypto_SUITE.erl2342
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/tuple_set_crash.erl8
-rw-r--r--lib/diameter/doc/src/diameter_app.xml14
-rw-r--r--lib/diameter/doc/src/diameter_transport.xml7
-rw-r--r--lib/diameter/include/diameter_gen.hrl200
-rw-r--r--lib/diameter/src/base/diameter_capx.erl19
-rw-r--r--lib/diameter/src/base/diameter_codec.erl175
-rw-r--r--lib/diameter/src/base/diameter_peer_fsm.erl50
-rw-r--r--lib/diameter/src/base/diameter_traffic.erl165
-rw-r--r--lib/diameter/src/base/diameter_watchdog.erl4
-rw-r--r--lib/diameter/src/compiler/diameter_codegen.erl6
-rw-r--r--lib/diameter/test/diameter_3xxx_SUITE.erl82
-rw-r--r--lib/diameter/test/diameter_app_SUITE.erl2
-rw-r--r--lib/diameter/test/diameter_codec_SUITE_data/diameter_test_unknown.erl4
-rw-r--r--lib/diameter/test/diameter_codec_test.erl10
-rw-r--r--lib/diameter/test/diameter_distribution_SUITE.erl10
-rw-r--r--lib/diameter/test/diameter_examples_SUITE.erl27
-rw-r--r--lib/diameter/test/diameter_gen_tcp_SUITE.erl106
-rw-r--r--lib/diameter/test/diameter_tls_SUITE.erl18
-rw-r--r--lib/diameter/test/diameter_traffic_SUITE.erl150
-rw-r--r--lib/diameter/test/modules.mk1
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl55
-rw-r--r--lib/inets/src/http_lib/http_chunk.erl53
-rw-r--r--lib/inets/test/erl_make_certs.erl107
-rw-r--r--lib/inets/test/httpc_SUITE.erl9
-rw-r--r--lib/kernel/src/os.erl23
-rw-r--r--lib/kernel/test/gen_tcp_misc_SUITE.erl2
-rw-r--r--lib/kernel/test/os_SUITE.erl45
-rw-r--r--lib/observer/src/crashdump_viewer.erl269
-rw-r--r--lib/observer/src/crashdump_viewer.hrl5
-rw-r--r--lib/observer/src/crashdump_viewer_html.erl84
-rw-r--r--lib/observer/src/observer_lib.erl7
-rw-r--r--lib/observer/src/observer_procinfo.erl56
-rw-r--r--lib/observer/src/observer_sys_wx.erl94
-rw-r--r--lib/odbc/configure.in3
-rw-r--r--lib/public_key/src/pubkey_pbe.erl64
-rw-r--r--lib/public_key/src/pubkey_ssh.erl41
-rw-r--r--lib/public_key/src/public_key.erl16
-rw-r--r--lib/public_key/test/erl_make_certs.erl66
-rw-r--r--lib/public_key/test/pbe_SUITE.erl14
-rw-r--r--lib/public_key/test/pkits_SUITE.erl4
-rw-r--r--lib/reltool/doc/src/reltool_examples.xml3
-rw-r--r--lib/runtime_tools/src/observer_backend.erl24
-rw-r--r--lib/sasl/src/systools_make.erl4
-rw-r--r--lib/snmp/.gitignore5
-rw-r--r--lib/snmp/doc/src/files.mk2
-rw-r--r--lib/snmp/doc/src/notes.xml211
-rw-r--r--lib/snmp/doc/src/ref_man.xml2
-rw-r--r--lib/snmp/doc/src/snmp_app.xml186
-rw-r--r--lib/snmp/doc/src/snmp_config.xml170
-rw-r--r--lib/snmp/doc/src/snmpa_mib_data.xml392
-rw-r--r--lib/snmp/doc/src/snmpa_mib_storage.xml292
-rw-r--r--lib/snmp/src/agent/depend.mk20
-rw-r--r--lib/snmp/src/agent/modules.mk16
-rw-r--r--lib/snmp/src/agent/snmp_user_based_sm_mib.erl35
-rw-r--r--lib/snmp/src/agent/snmpa.erl33
-rw-r--r--lib/snmp/src/agent/snmpa_agent.erl185
-rw-r--r--lib/snmp/src/agent/snmpa_agent_sup.erl10
-rw-r--r--lib/snmp/src/agent/snmpa_mib.erl207
-rw-r--r--lib/snmp/src/agent/snmpa_mib_data.erl1374
-rw-r--r--lib/snmp/src/agent/snmpa_mib_data_ttln.erl1402
-rw-r--r--lib/snmp/src/agent/snmpa_mib_data_tttn.erl1443
-rw-r--r--lib/snmp/src/agent/snmpa_mib_storage.erl181
-rw-r--r--lib/snmp/src/agent/snmpa_mib_storage_dets.erl309
-rw-r--r--lib/snmp/src/agent/snmpa_mib_storage_ets.erl341
-rw-r--r--lib/snmp/src/agent/snmpa_mib_storage_mnesia.erl302
-rw-r--r--lib/snmp/src/agent/snmpa_supervisor.erl107
-rw-r--r--lib/snmp/src/agent/snmpa_symbolic_store.erl283
-rw-r--r--lib/snmp/src/app/snmp.app.src8
-rw-r--r--lib/snmp/src/app/snmp.appup.src12
-rw-r--r--lib/snmp/src/app/snmp.erl18
-rw-r--r--lib/snmp/src/app/snmp_app.erl14
-rw-r--r--lib/snmp/src/manager/snmpm_config.erl41
-rw-r--r--lib/snmp/src/misc/snmp_config.erl22
-rw-r--r--lib/snmp/src/misc/snmp_misc.erl17
-rw-r--r--lib/snmp/src/misc/snmp_usm.erl51
-rw-r--r--lib/snmp/test/snmp_agent_mibs_test.erl263
-rw-r--r--lib/snmp/test/snmp_agent_test.erl2235
-rw-r--r--lib/snmp/test/snmp_agent_test_lib.erl319
-rw-r--r--lib/snmp/test/snmp_test_lib.erl9
-rw-r--r--lib/snmp/vsn.mk2
-rw-r--r--lib/ssh/src/ssh_bits.erl27
-rw-r--r--lib/ssh/src/ssh_math.erl96
-rw-r--r--lib/ssh/src/ssh_transport.erl41
-rw-r--r--lib/ssl/src/Makefile2
-rw-r--r--lib/ssl/src/ssl.erl1
-rw-r--r--lib/ssl/src/ssl_cipher.erl32
-rw-r--r--lib/ssl/src/ssl_connection.erl3
-rw-r--r--lib/ssl/src/ssl_handshake.erl9
-rw-r--r--lib/ssl/src/ssl_record.erl3
-rw-r--r--lib/ssl/src/ssl_srp_primes.hrl1
-rw-r--r--lib/ssl/src/ssl_tls1.erl62
-rw-r--r--lib/ssl/test/erl_make_certs.erl50
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl4
-rw-r--r--lib/ssl/test/ssl_test_lib.erl38
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl6
-rw-r--r--lib/stdlib/doc/src/c.xml4
-rw-r--r--lib/stdlib/doc/src/erl_eval.xml5
-rw-r--r--lib/stdlib/src/beam_lib.erl18
-rw-r--r--lib/stdlib/src/c.erl6
-rw-r--r--lib/stdlib/src/erl_eval.erl64
-rw-r--r--lib/stdlib/src/otp_internal.erl76
-rw-r--r--lib/stdlib/test/c_SUITE.erl11
-rw-r--r--lib/test_server/src/ts_install_cth.erl4
238 files changed, 16663 insertions, 13141 deletions
diff --git a/.gitignore b/.gitignore
index a3e03dc46f..7ccedd3ff3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -287,13 +287,13 @@ JAVADOC-GENERATED
# otp_mibs
-/lib/otp_mibs/include/[A-Z]*.hrl
+/lib/otp_mibs/include/OTP*.hrl
/lib/otp_mibs/mibs/v1/OTP*.mib.v1
/lib/otp_mibs/priv/mibs/OTP*.bin
# os_mon
-/lib/os_mon/include/[A-Z]*.hrl
+/lib/os_mon/include/OTP*.hrl
/lib/os_mon/mibs/v1/OTP*.mib.v1
/lib/os_mon/priv/mibs/OTP*.bin
diff --git a/bootstrap/lib/compiler/ebin/beam_a.beam b/bootstrap/lib/compiler/ebin/beam_a.beam
index fd53a2e0f9..a4965abd48 100644
--- a/bootstrap/lib/compiler/ebin/beam_a.beam
+++ b/bootstrap/lib/compiler/ebin/beam_a.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam
index e87e6a8555..ba17952caf 100644
--- a/bootstrap/lib/compiler/ebin/compile.beam
+++ b/bootstrap/lib/compiler/ebin/compile.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/os.beam b/bootstrap/lib/kernel/ebin/os.beam
index 3972fe7b91..bb981bbf89 100644
--- a/bootstrap/lib/kernel/ebin/os.beam
+++ b/bootstrap/lib/kernel/ebin/os.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/beam_lib.beam b/bootstrap/lib/stdlib/ebin/beam_lib.beam
index 37ed5b2bf8..611f271cb9 100644
--- a/bootstrap/lib/stdlib/ebin/beam_lib.beam
+++ b/bootstrap/lib/stdlib/ebin/beam_lib.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_eval.beam b/bootstrap/lib/stdlib/ebin/erl_eval.beam
index 07f663b2c6..6f4180ee07 100644
--- a/bootstrap/lib/stdlib/ebin/erl_eval.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_eval.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/otp_internal.beam b/bootstrap/lib/stdlib/ebin/otp_internal.beam
index c853cf37bd..c19ca1763a 100644
--- a/bootstrap/lib/stdlib/ebin/otp_internal.beam
+++ b/bootstrap/lib/stdlib/ebin/otp_internal.beam
Binary files differ
diff --git a/erts/configure.in b/erts/configure.in
index b9c9a76ef6..c47c211c4e 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -624,6 +624,7 @@ case $chk_arch_ in
armv5teb) ARCH=arm;;
armv5tel) ARCH=arm;;
armv5tejl) ARCH=arm;;
+ armv6l) ARCH=arm;;
armv7l) ARCH=arm;;
tile) ARCH=tile;;
*) ARCH=noarch;;
diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml
index a68e62d051..8dca7402e8 100644
--- a/erts/doc/src/erl.xml
+++ b/erts/doc/src/erl.xml
@@ -657,10 +657,11 @@
<p>Se also <seealso marker="stdlib:io#printable_range/0">
io:printable_range/0</seealso>.</p>
</item>
- <tag><marker id="+P"/><marker id="max_processes"><c><![CDATA[+P Number]]></c></marker></tag>
+ <tag><marker id="+P"/><marker id="max_processes"><c><![CDATA[+P Number|legacy]]></c></marker></tag>
<item>
<p>Sets the maximum number of simultaneously existing processes for this
- system. Valid range for <c>Number</c> is <c>[1024-134217727]</c></p>
+ system if a <c>Number</c> is passed as value. Valid range for
+ <c>Number</c> is <c>[1024-134217727]</c></p>
<p><em>NOTE</em>: The actual maximum chosen may be much larger than
the <c>Number</c> passed. Currently the runtime system often,
but not always, chooses a value that is a power of 2. This might,
@@ -668,11 +669,19 @@
checked by calling
<seealso marker="erlang#system_info_process_limit">erlang:system_info(process_limit)</seealso>.</p>
<p>The default value is <c>262144</c></p>
+ <p>If <c>legacy</c> is passed as value, the legacy algorithm for
+ allocation of process identifiers will be used. Using the legacy
+ algorithm, identifiers will be allocated in a strictly increasing
+ fashion until largest possible identifier has been reached. Note that
+ this algorithm suffers from performance issues and can under certain
+ circumstances be extremely expensive. The legacy algoritm is deprecated,
+ and the <c>legacy</c> option is scheduled for removal in OTP-R18.</p>
</item>
- <tag><marker id="+Q"/><marker id="max_ports"><c><![CDATA[+Q Number]]></c></marker></tag>
+ <tag><marker id="+Q"/><marker id="max_ports"><c><![CDATA[+Q Number|legacy]]></c></marker></tag>
<item>
<p>Sets the maximum number of simultaneously existing ports for this
- system. Valid range for <c>Number</c> is <c>[1024-134217727]</c></p>
+ system if a Number is passed as value. Valid range for <c>Number</c>
+ is <c>[1024-134217727]</c></p>
<p><em>NOTE</em>: The actual maximum chosen may be much larger than
the actual <c>Number</c> passed. Currently the runtime system often,
but not always, chooses a value that is a power of 2. This might,
@@ -691,6 +700,13 @@
for setting the maximum number of simultaneously existing ports. This
environment variable is deprecated, and scheduled for removal in
OTP-R17, but can still be used.</p>
+ <p>If <c>legacy</c> is passed as value, the legacy algorithm for
+ allocation of port identifiers will be used. Using the legacy
+ algorithm, identifiers will be allocated in a strictly increasing
+ fashion until largest possible identifier has been reached. Note that
+ this algorithm suffers from performance issues and can under certain
+ circumstances be extremely expensive. The legacy algoritm is deprecated,
+ and the <c>legacy</c> option is scheduled for removal in OTP-R18.</p>
</item>
<tag><marker id="compat_rel"><c><![CDATA[+R ReleaseNumber]]></c></marker></tag>
<item>
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index 2031ec3a4c..58e83540e1 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -559,13 +559,14 @@ GENERATE += $(TTF_DIR)/driver_tab.c
# Preloaded code.
#
# This list must be consistent with PRE_LOADED_MODULES in
-# lib/kernel/src/Makefile.
+# erts/preloaded/src/Makefile.
ifeq ($(TARGET),win32)
# On windows the preloaded objects are in a resource object.
PRELOAD_OBJ = $(OBJDIR)/beams.$(RES_EXT)
PRELOAD_SRC = $(TARGET)/beams.rc
$(PRELOAD_SRC): $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \
$(ERL_TOP)/erts/preloaded/ebin/init.beam \
+ $(ERL_TOP)/erts/preloaded/ebin/prim_eval.beam \
$(ERL_TOP)/erts/preloaded/ebin/prim_inet.beam \
$(ERL_TOP)/erts/preloaded/ebin/prim_file.beam \
$(ERL_TOP)/erts/preloaded/ebin/zlib.beam \
@@ -579,6 +580,7 @@ PRELOAD_OBJ = $(OBJDIR)/preload.o
PRELOAD_SRC = $(TARGET)/preload.c
$(PRELOAD_SRC): $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \
$(ERL_TOP)/erts/preloaded/ebin/init.beam \
+ $(ERL_TOP)/erts/preloaded/ebin/prim_eval.beam \
$(ERL_TOP)/erts/preloaded/ebin/prim_inet.beam \
$(ERL_TOP)/erts/preloaded/ebin/prim_file.beam \
$(ERL_TOP)/erts/preloaded/ebin/zlib.beam \
@@ -1021,7 +1023,8 @@ endif
$(TARGET)/gen_git_version.mk:
# We touch beam/erl_bif.info.c if we regenerated the git version to force a
# rebuild.
- if $(gen_verbose)utils/gen_git_version $@; then touch beam/erl_bif_info.c; fi
+ $(gen_verbose)
+ $(V_at)if utils/gen_git_version $@; then touch beam/erl_bif_info.c; fi
.PHONY: depend
ifdef VOID_EMULATOR
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names
index ce60bb9bbc..9e12080732 100644
--- a/erts/emulator/beam/atom.names
+++ b/erts/emulator/beam/atom.names
@@ -248,6 +248,7 @@ atom get_data
atom get_seq_token
atom get_tcw
atom getenv
+atom gather_gc_info_result
atom gather_sched_wall_time_result
atom getting_linked
atom getting_unlinked
diff --git a/erts/emulator/beam/erl_afit_alloc.c b/erts/emulator/beam/erl_afit_alloc.c
index 5850f80843..b45201af42 100644
--- a/erts/emulator/beam/erl_afit_alloc.c
+++ b/erts/emulator/beam/erl_afit_alloc.c
@@ -259,10 +259,10 @@ info_options(Allctr_t *allctr,
* to erts_afalc_test() *
\* */
-unsigned long
-erts_afalc_test(unsigned long op, unsigned long a1, unsigned long a2)
+UWord
+erts_afalc_test(UWord op, UWord a1, UWord a2)
{
switch (op) {
- default: ASSERT(0); return ~((unsigned long) 0);
+ default: ASSERT(0); return ~((UWord) 0);
}
}
diff --git a/erts/emulator/beam/erl_afit_alloc.h b/erts/emulator/beam/erl_afit_alloc.h
index cf7b99c463..b90ac8f7c5 100644
--- a/erts/emulator/beam/erl_afit_alloc.h
+++ b/erts/emulator/beam/erl_afit_alloc.h
@@ -56,7 +56,7 @@ struct AFAllctr_t_ {
AFFreeBlock_t * free_list;
};
-unsigned long erts_afalc_test(unsigned long, unsigned long, unsigned long);
+UWord erts_afalc_test(UWord, UWord, UWord);
#endif /* #if defined(GET_ERL_AF_ALLOC_IMPL)
&& !defined(ERL_AF_ALLOC_IMPL__) */
diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c
index c19a2647e4..403776aade 100644
--- a/erts/emulator/beam/erl_alloc.c
+++ b/erts/emulator/beam/erl_alloc.c
@@ -2176,7 +2176,6 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg)
if (want_tot_or_sys || want.processes || want.processes_used) {
- int max_processes = erts_ptab_max(&erts_proc);
UWord tmp;
if (ERTS_MEM_NEED_ALL_ALCU)
@@ -2186,7 +2185,7 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg)
fi, ERTS_ALC_NO_FIXED_SIZES);
tmp = alcu_size(ERTS_ALC_A_EHEAP, NULL, 0);
}
- tmp += max_processes*sizeof(erts_smp_atomic_t);
+ tmp += erts_ptab_mem_size(&erts_proc);
tmp += erts_bif_timer_memory_size();
tmp += erts_tot_link_lh_size();
@@ -2312,13 +2311,11 @@ struct aa_values {
Eterm
erts_allocated_areas(int *print_to_p, void *print_to_arg, void *proc)
{
-#define MAX_AA_VALUES (23)
+#define MAX_AA_VALUES (24)
struct aa_values values[MAX_AA_VALUES];
Eterm res = THE_NON_VALUE;
int i, length;
Uint reserved_atom_space, atom_space;
- int max_processes = erts_ptab_max(&erts_proc);
- int max_ports = erts_ptab_max(&erts_port);
if (proc) {
ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN
@@ -2349,8 +2346,8 @@ erts_allocated_areas(int *print_to_p, void *print_to_arg, void *proc)
values[i].arity = 2;
values[i].name = "static";
- values[i].ui[0] =
- max_ports*sizeof(erts_smp_atomic_t) /* Port table */
+ values[i].ui[0] =
+ sizeof(ErtsPTab)*2 /* proc & port tables */
+ erts_timer_wheel_memory_size(); /* Timer wheel */
i++;
@@ -2429,7 +2426,12 @@ erts_allocated_areas(int *print_to_p, void *print_to_arg, void *proc)
values[i].arity = 2;
values[i].name = "process_table";
- values[i].ui[0] = max_processes*sizeof(Process*);
+ values[i].ui[0] = erts_ptab_mem_size(&erts_proc);
+ i++;
+
+ values[i].arity = 2;
+ values[i].name = "port_table";
+ values[i].ui[0] = erts_ptab_mem_size(&erts_port);
i++;
values[i].arity = 2;
@@ -3219,10 +3221,7 @@ void *safe_realloc(void *ptr, Uint sz)
\* */
#define ERTS_ALC_TEST_ABORT erl_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error\n")
-UWord erts_alc_test(UWord op,
- UWord a1,
- UWord a2,
- UWord a3)
+UWord erts_alc_test(UWord op, UWord a1, UWord a2, UWord a3)
{
switch (op >> 8) {
case 0x0: return erts_alcu_test(op, a1, a2);
diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types
index 5a92ab7f24..f913525726 100644
--- a/erts/emulator/beam/erl_alloc.types
+++ b/erts/emulator/beam/erl_alloc.types
@@ -366,6 +366,7 @@ type MONITOR_SH STANDARD_LOW PROCESSES monitor_sh
type NLINK_SH STANDARD_LOW PROCESSES nlink_sh
type AINFO_REQ STANDARD_LOW SYSTEM alloc_info_request
type SCHED_WTIME_REQ STANDARD_LOW SYSTEM sched_wall_time_request
+type GC_INFO_REQ STANDARD_LOW SYSTEM gc_info_request
+else # "fullword"
@@ -383,6 +384,7 @@ type MONITOR_SH FIXED_SIZE PROCESSES monitor_sh
type NLINK_SH FIXED_SIZE PROCESSES nlink_sh
type AINFO_REQ SHORT_LIVED SYSTEM alloc_info_request
type SCHED_WTIME_REQ SHORT_LIVED SYSTEM sched_wall_time_request
+type GC_INFO_REQ SHORT_LIVED SYSTEM gc_info_request
+endif
diff --git a/erts/emulator/beam/erl_alloc_util.c b/erts/emulator/beam/erl_alloc_util.c
index cbeb2c1e3a..53062979a6 100644
--- a/erts/emulator/beam/erl_alloc_util.c
+++ b/erts/emulator/beam/erl_alloc_util.c
@@ -4405,42 +4405,42 @@ erts_alcu_init(AlcUInit_t *init)
* to erts_alcu_test() *
\* */
-unsigned long
-erts_alcu_test(unsigned long op, unsigned long a1, unsigned long a2)
+UWord
+erts_alcu_test(UWord op, UWord a1, UWord a2)
{
switch (op) {
- case 0x000: return (unsigned long) BLK_SZ((Block_t *) a1);
- case 0x001: return (unsigned long) BLK_UMEM_SZ((Block_t *) a1);
- case 0x002: return (unsigned long) IS_PREV_BLK_FREE((Block_t *) a1);
- case 0x003: return (unsigned long) IS_FREE_BLK((Block_t *) a1);
- case 0x004: return (unsigned long) IS_LAST_BLK((Block_t *) a1);
- case 0x005: return (unsigned long) UMEM2BLK((void *) a1);
- case 0x006: return (unsigned long) BLK2UMEM((Block_t *) a1);
- case 0x007: return (unsigned long) IS_SB_CARRIER((Carrier_t *) a1);
- case 0x008: return (unsigned long) IS_SBC_BLK((Block_t *) a1);
- case 0x009: return (unsigned long) IS_MB_CARRIER((Carrier_t *) a1);
- case 0x00a: return (unsigned long) IS_MSEG_CARRIER((Carrier_t *) a1);
- case 0x00b: return (unsigned long) CARRIER_SZ((Carrier_t *) a1);
- case 0x00c: return (unsigned long) SBC2BLK((Allctr_t *) a1,
+ case 0x000: return (UWord) BLK_SZ((Block_t *) a1);
+ case 0x001: return (UWord) BLK_UMEM_SZ((Block_t *) a1);
+ case 0x002: return (UWord) IS_PREV_BLK_FREE((Block_t *) a1);
+ case 0x003: return (UWord) IS_FREE_BLK((Block_t *) a1);
+ case 0x004: return (UWord) IS_LAST_BLK((Block_t *) a1);
+ case 0x005: return (UWord) UMEM2BLK((void *) a1);
+ case 0x006: return (UWord) BLK2UMEM((Block_t *) a1);
+ case 0x007: return (UWord) IS_SB_CARRIER((Carrier_t *) a1);
+ case 0x008: return (UWord) IS_SBC_BLK((Block_t *) a1);
+ case 0x009: return (UWord) IS_MB_CARRIER((Carrier_t *) a1);
+ case 0x00a: return (UWord) IS_MSEG_CARRIER((Carrier_t *) a1);
+ case 0x00b: return (UWord) CARRIER_SZ((Carrier_t *) a1);
+ case 0x00c: return (UWord) SBC2BLK((Allctr_t *) a1,
(Carrier_t *) a2);
- case 0x00d: return (unsigned long) BLK_TO_SBC((Block_t *) a2);
- case 0x00e: return (unsigned long) MBC_TO_FIRST_BLK((Allctr_t *) a1,
+ case 0x00d: return (UWord) BLK_TO_SBC((Block_t *) a2);
+ case 0x00e: return (UWord) MBC_TO_FIRST_BLK((Allctr_t *) a1,
(Carrier_t *) a2);
- case 0x00f: return (unsigned long) FIRST_BLK_TO_MBC((Allctr_t *) a1,
+ case 0x00f: return (UWord) FIRST_BLK_TO_MBC((Allctr_t *) a1,
(Block_t *) a2);
- case 0x010: return (unsigned long) ((Allctr_t *) a1)->mbc_list.first;
- case 0x011: return (unsigned long) ((Allctr_t *) a1)->mbc_list.last;
- case 0x012: return (unsigned long) ((Allctr_t *) a1)->sbc_list.first;
- case 0x013: return (unsigned long) ((Allctr_t *) a1)->sbc_list.last;
- case 0x014: return (unsigned long) ((Carrier_t *) a1)->next;
- case 0x015: return (unsigned long) ((Carrier_t *) a1)->prev;
- case 0x016: return (unsigned long) ABLK_HDR_SZ;
- case 0x017: return (unsigned long) ((Allctr_t *) a1)->min_block_size;
- case 0x018: return (unsigned long) NXT_BLK((Block_t *) a1);
- case 0x019: return (unsigned long) PREV_BLK((Block_t *) a1);
- case 0x01a: return (unsigned long) IS_MBC_FIRST_BLK((Allctr_t*)a1, (Block_t *) a2);
- case 0x01b: return (unsigned long) sizeof(Unit_t);
- default: ASSERT(0); return ~((unsigned long) 0);
+ case 0x010: return (UWord) ((Allctr_t *) a1)->mbc_list.first;
+ case 0x011: return (UWord) ((Allctr_t *) a1)->mbc_list.last;
+ case 0x012: return (UWord) ((Allctr_t *) a1)->sbc_list.first;
+ case 0x013: return (UWord) ((Allctr_t *) a1)->sbc_list.last;
+ case 0x014: return (UWord) ((Carrier_t *) a1)->next;
+ case 0x015: return (UWord) ((Carrier_t *) a1)->prev;
+ case 0x016: return (UWord) ABLK_HDR_SZ;
+ case 0x017: return (UWord) ((Allctr_t *) a1)->min_block_size;
+ case 0x018: return (UWord) NXT_BLK((Block_t *) a1);
+ case 0x019: return (UWord) PREV_BLK((Block_t *) a1);
+ case 0x01a: return (UWord) IS_MBC_FIRST_BLK((Allctr_t*)a1, (Block_t *) a2);
+ case 0x01b: return (UWord) sizeof(Unit_t);
+ default: ASSERT(0); return ~((UWord) 0);
}
}
diff --git a/erts/emulator/beam/erl_alloc_util.h b/erts/emulator/beam/erl_alloc_util.h
index e0754e7f69..4773598561 100644
--- a/erts/emulator/beam/erl_alloc_util.h
+++ b/erts/emulator/beam/erl_alloc_util.h
@@ -501,7 +501,7 @@ void erts_alcu_stop(Allctr_t *);
void erts_alcu_verify_unused(Allctr_t *);
void erts_alcu_verify_unused_ts(Allctr_t *allctr);
-unsigned long erts_alcu_test(unsigned long, unsigned long, unsigned long);
+UWord erts_alcu_test(UWord, UWord, UWord);
#ifdef DEBUG
int is_sbc_blk(Block_t*);
diff --git a/erts/emulator/beam/erl_ao_firstfit_alloc.c b/erts/emulator/beam/erl_ao_firstfit_alloc.c
index 6ce209085c..b916cb6198 100644
--- a/erts/emulator/beam/erl_ao_firstfit_alloc.c
+++ b/erts/emulator/beam/erl_ao_firstfit_alloc.c
@@ -780,19 +780,19 @@ info_options(Allctr_t *allctr,
* to erts_aoffalc_test() *
\* */
-unsigned long
-erts_aoffalc_test(unsigned long op, unsigned long a1, unsigned long a2)
+UWord
+erts_aoffalc_test(UWord op, UWord a1, UWord a2)
{
switch (op) {
- case 0x500: return (unsigned long) 0; /* IS_AOBF */
- case 0x501: return (unsigned long) ((AOFFAllctr_t *) a1)->mbc_root;
- case 0x502: return (unsigned long) ((AOFF_RBTree_t *) a1)->parent;
- case 0x503: return (unsigned long) ((AOFF_RBTree_t *) a1)->left;
- case 0x504: return (unsigned long) ((AOFF_RBTree_t *) a1)->right;
- case 0x506: return (unsigned long) IS_BLACK((AOFF_RBTree_t *) a1);
- case 0x508: return (unsigned long) 1; /* IS_AOFF */
- case 0x509: return (unsigned long) ((AOFF_RBTree_t *) a1)->max_sz;
- default: ASSERT(0); return ~((unsigned long) 0);
+ case 0x500: return (UWord) 0; /* IS_AOBF */
+ case 0x501: return (UWord) ((AOFFAllctr_t *) a1)->mbc_root;
+ case 0x502: return (UWord) ((AOFF_RBTree_t *) a1)->parent;
+ case 0x503: return (UWord) ((AOFF_RBTree_t *) a1)->left;
+ case 0x504: return (UWord) ((AOFF_RBTree_t *) a1)->right;
+ case 0x506: return (UWord) IS_BLACK((AOFF_RBTree_t *) a1);
+ case 0x508: return (UWord) 1; /* IS_AOFF */
+ case 0x509: return (UWord) ((AOFF_RBTree_t *) a1)->max_sz;
+ default: ASSERT(0); return ~((UWord) 0);
}
}
diff --git a/erts/emulator/beam/erl_ao_firstfit_alloc.h b/erts/emulator/beam/erl_ao_firstfit_alloc.h
index 6fa626f723..21c36c6654 100644
--- a/erts/emulator/beam/erl_ao_firstfit_alloc.h
+++ b/erts/emulator/beam/erl_ao_firstfit_alloc.h
@@ -54,7 +54,7 @@ struct AOFFAllctr_t_ {
struct AOFF_RBTree_t_* sbmbc_root;
};
-unsigned long erts_aoffalc_test(unsigned long, unsigned long, unsigned long);
+UWord erts_aoffalc_test(UWord, UWord, UWord);
#endif /* #if defined(GET_ERL_AOFF_ALLOC_IMPL)
&& !defined(ERL_AOFF_ALLOC_IMPL__) */
diff --git a/erts/emulator/beam/erl_bestfit_alloc.c b/erts/emulator/beam/erl_bestfit_alloc.c
index 5625622e3f..ed843a51fb 100644
--- a/erts/emulator/beam/erl_bestfit_alloc.c
+++ b/erts/emulator/beam/erl_bestfit_alloc.c
@@ -972,20 +972,20 @@ info_options(Allctr_t *allctr,
* to erts_bfalc_test() *
\* */
-unsigned long
-erts_bfalc_test(unsigned long op, unsigned long a1, unsigned long a2)
+UWord
+erts_bfalc_test(UWord op, UWord a1, UWord a2)
{
switch (op) {
- case 0x200: return (unsigned long) ((BFAllctr_t *) a1)->address_order;
- case 0x201: return (unsigned long) ((BFAllctr_t *) a1)->mbc_root;
- case 0x202: return (unsigned long) ((RBTree_t *) a1)->parent;
- case 0x203: return (unsigned long) ((RBTree_t *) a1)->left;
- case 0x204: return (unsigned long) ((RBTree_t *) a1)->right;
- case 0x205: return (unsigned long) ((RBTreeList_t *) a1)->next;
- case 0x206: return (unsigned long) IS_BLACK((RBTree_t *) a1);
- case 0x207: return (unsigned long) IS_TREE_NODE((RBTree_t *) a1);
- case 0x208: return (unsigned long) 0; /* IS_AOFF */
- default: ASSERT(0); return ~((unsigned long) 0);
+ case 0x200: return (UWord) ((BFAllctr_t *) a1)->address_order;
+ case 0x201: return (UWord) ((BFAllctr_t *) a1)->mbc_root;
+ case 0x202: return (UWord) ((RBTree_t *) a1)->parent;
+ case 0x203: return (UWord) ((RBTree_t *) a1)->left;
+ case 0x204: return (UWord) ((RBTree_t *) a1)->right;
+ case 0x205: return (UWord) ((RBTreeList_t *) a1)->next;
+ case 0x206: return (UWord) IS_BLACK((RBTree_t *) a1);
+ case 0x207: return (UWord) IS_TREE_NODE((RBTree_t *) a1);
+ case 0x208: return (UWord) 0; /* IS_AOFF */
+ default: ASSERT(0); return ~((UWord) 0);
}
}
diff --git a/erts/emulator/beam/erl_bestfit_alloc.h b/erts/emulator/beam/erl_bestfit_alloc.h
index 0c29662852..f2d2f07d7a 100644
--- a/erts/emulator/beam/erl_bestfit_alloc.h
+++ b/erts/emulator/beam/erl_bestfit_alloc.h
@@ -59,7 +59,7 @@ struct BFAllctr_t_ {
int address_order;
};
-unsigned long erts_bfalc_test(unsigned long, unsigned long, unsigned long);
+UWord erts_bfalc_test(UWord, UWord, UWord);
#endif /* #if defined(GET_ERL_BF_ALLOC_IMPL)
&& !defined(ERL_BF_ALLOC_IMPL__) */
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index 54eefe8d12..1744afbae1 100755
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -59,6 +59,7 @@ static Export* alloc_info_trap = NULL;
static Export* alloc_sizes_trap = NULL;
static Export *gather_sched_wall_time_res_trap;
+static Export *gather_gc_info_res_trap;
#define DECL_AM(S) Eterm AM_ ## S = am_atom_put(#S, sizeof(#S) - 1)
@@ -3103,18 +3104,10 @@ BIF_RETTYPE statistics_1(BIF_ALIST_1)
res = TUPLE2(hp, cs, SMALL_ZERO);
BIF_RET(res);
} else if (BIF_ARG_1 == am_garbage_collection) {
- Uint hsz = 4;
- ErtsGCInfo gc_info;
- Eterm gcs;
- Eterm recl;
- erts_gc_info(&gc_info);
- (void) erts_bld_uint(NULL, &hsz, gc_info.garbage_collections);
- (void) erts_bld_uint(NULL, &hsz, gc_info.reclaimed);
- hp = HAlloc(BIF_P, hsz);
- gcs = erts_bld_uint(&hp, NULL, gc_info.garbage_collections);
- recl = erts_bld_uint(&hp, NULL, gc_info.reclaimed);
- res = TUPLE3(hp, gcs, recl, SMALL_ZERO);
- BIF_RET(res);
+ res = erts_gc_info_request(BIF_P);
+ if (is_non_value(res))
+ BIF_RET(am_undefined);
+ BIF_TRAP1(gather_gc_info_res_trap, BIF_P, res);
} else if (BIF_ARG_1 == am_reductions) {
Uint reds;
Uint diff;
@@ -4082,6 +4075,8 @@ erts_bif_info_init(void)
alloc_sizes_trap = erts_export_put(am_erlang, am_alloc_sizes, 1);
gather_sched_wall_time_res_trap
= erts_export_put(am_erlang, am_gather_sched_wall_time_result, 1);
+ gather_gc_info_res_trap
+ = erts_export_put(am_erlang, am_gather_gc_info_result, 1);
process_info_init();
os_info_init();
}
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index 298909c921..0d12e658d9 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -47,10 +47,6 @@
*/
#define ALENGTH(a) (sizeof(a)/sizeof(a[0]))
-static erts_smp_spinlock_t info_lck;
-static Uint garbage_cols; /* no of garbage collections */
-static Uint reclaimed; /* no of words reclaimed in GCs */
-
# define STACK_SZ_ON_HEAP(p) ((p)->hend - (p)->stop)
# define OverRunCheck(P) \
if ((P)->stop < (P)->htop) { \
@@ -120,6 +116,8 @@ static void offset_rootset(Process *p, Sint offs, char* area, Uint area_size,
static void offset_off_heap(Process* p, Sint offs, char* area, Uint area_size);
static void offset_mqueue(Process *p, Sint offs, char* area, Uint area_size);
+static void init_gc_info(ErtsGCInfo *gcip);
+
#ifdef HARDDEBUG
static void disallow_heap_frag_ref_in_heap(Process* p);
static void disallow_heap_frag_ref_in_old_heap(Process* p);
@@ -137,13 +135,41 @@ static int num_heap_sizes; /* Number of heap sizes. */
Uint erts_test_long_gc_sleep; /* Only used for testing... */
+typedef struct {
+ Process *proc;
+ Eterm ref;
+ Eterm ref_heap[REF_THING_SIZE];
+ Uint req_sched;
+ erts_smp_atomic32_t refc;
+} ErtsGCInfoReq;
+
+#if !HALFWORD_HEAP
+ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(gcireq,
+ ErtsGCInfoReq,
+ 5,
+ ERTS_ALC_T_GC_INFO_REQ)
+#else
+static ERTS_INLINE ErtsGCInfoReq *
+gcireq_alloc(void)
+{
+ return erts_alloc(ERTS_ALC_T_GC_INFO_REQ,
+ sizeof(ErtsGCInfoReq));
+}
+
+static ERTS_INLINE void
+gcireq_free(ErtsGCInfoReq *ptr)
+{
+ erts_free(ERTS_ALC_T_GC_INFO_REQ, ptr);
+}
+#endif
+
/*
* Initialize GC global data.
*/
void
erts_init_gc(void)
{
- int i = 0;
+ int i = 0, ix;
Sint max_heap_size = 0;
ASSERT(offsetof(ProcBin,thing_word) == offsetof(struct erl_off_heap_header,thing_word));
@@ -156,9 +182,6 @@ erts_init_gc(void)
ASSERT(offsetof(ProcBin,next) == offsetof(ErlFunThing,next));
ASSERT(offsetof(ProcBin,next) == offsetof(ExternalThing,next));
- erts_smp_spinlock_init(&info_lck, "gc_info");
- garbage_cols = 0;
- reclaimed = 0;
erts_test_long_gc_sleep = 0;
/*
@@ -199,6 +222,16 @@ erts_init_gc(void)
}
}
num_heap_sizes = i;
+
+ for (ix = 0; ix < erts_no_schedulers; ix++) {
+ ErtsSchedulerData *esdp = ERTS_SCHEDULER_IX(ix);
+ init_gc_info(&esdp->gc_info);
+ }
+
+#if !HALFWORD_HEAP
+ init_gcireq_alloc();
+#endif
+
}
/*
@@ -287,17 +320,6 @@ erts_heap_sizes(Process* p)
return res;
}
-void
-erts_gc_info(ErtsGCInfo *gcip)
-{
- if (gcip) {
- erts_smp_spin_lock(&info_lck);
- gcip->garbage_collections = garbage_cols;
- gcip->reclaimed = reclaimed;
- erts_smp_spin_unlock(&info_lck);
- }
-}
-
void
erts_offset_heap(Eterm* hp, Uint sz, Sint offs, Eterm* low, Eterm* high)
{
@@ -378,6 +400,7 @@ erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj)
Uint reclaimed_now = 0;
int done = 0;
Uint ms1, s1, us1;
+ ErtsSchedulerData *esdp = erts_get_scheduler_data();
#ifdef USE_VM_PROBES
DTRACE_CHARBUF(pidbuf, DTRACE_TERM_BUF_SIZE);
#endif
@@ -455,11 +478,9 @@ erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj)
monitor_large_heap(p);
}
- erts_smp_spin_lock(&info_lck);
- garbage_cols++;
- reclaimed += reclaimed_now;
- erts_smp_spin_unlock(&info_lck);
-
+ esdp->gc_info.garbage_cols++;
+ esdp->gc_info.reclaimed += reclaimed_now;
+
FLAGS(p) &= ~F_FORCE_GC;
#ifdef CHECK_FOR_HOLES
@@ -2543,6 +2564,110 @@ offset_rootset(Process *p, Sint offs, char* area, Uint area_size,
offset_one_rootset(p, offs, area, area_size, objv, nobj);
}
+static void
+init_gc_info(ErtsGCInfo *gcip)
+{
+ gcip->reclaimed = 0;
+ gcip->garbage_cols = 0;
+}
+
+static void
+reply_gc_info(void *vgcirp)
+{
+ Uint64 reclaimed = 0, garbage_cols = 0;
+ ErtsSchedulerData *esdp = erts_get_scheduler_data();
+ ErtsGCInfoReq *gcirp = (ErtsGCInfoReq *) vgcirp;
+ ErtsProcLocks rp_locks = (gcirp->req_sched == esdp->no
+ ? ERTS_PROC_LOCK_MAIN
+ : 0);
+ Process *rp = gcirp->proc;
+ Eterm ref_copy = NIL, msg;
+ Eterm *hp = NULL;
+ Eterm **hpp;
+ Uint sz, *szp;
+ ErlOffHeap *ohp = NULL;
+ ErlHeapFragment *bp = NULL;
+
+ ASSERT(esdp);
+
+ reclaimed = esdp->gc_info.reclaimed;
+ garbage_cols = esdp->gc_info.garbage_cols;
+
+ sz = 0;
+ hpp = NULL;
+ szp = &sz;
+
+ while (1) {
+ if (hpp)
+ ref_copy = STORE_NC(hpp, ohp, gcirp->ref);
+ else
+ *szp += REF_THING_SIZE;
+
+ msg = erts_bld_tuple(hpp, szp, 3,
+ make_small(esdp->no),
+ erts_bld_uint64(hpp, szp, garbage_cols),
+ erts_bld_uint64(hpp, szp, reclaimed));
+
+ msg = erts_bld_tuple(hpp, szp, 2, ref_copy, msg);
+ if (hpp)
+ break;
+
+ hp = erts_alloc_message_heap(sz, &bp, &ohp, rp, &rp_locks);
+ szp = NULL;
+ hpp = &hp;
+ }
+
+ erts_queue_message(rp, &rp_locks, bp, msg, NIL
+#ifdef USE_VM_PROBES
+ , NIL
+#endif
+ );
+
+ if (gcirp->req_sched == esdp->no)
+ rp_locks &= ~ERTS_PROC_LOCK_MAIN;
+
+ if (rp_locks)
+ erts_smp_proc_unlock(rp, rp_locks);
+
+ erts_smp_proc_dec_refc(rp);
+
+ if (erts_smp_atomic32_dec_read_nob(&gcirp->refc) == 0)
+ gcireq_free(vgcirp);
+}
+
+Eterm
+erts_gc_info_request(Process *c_p)
+{
+ ErtsSchedulerData *esdp = ERTS_PROC_GET_SCHDATA(c_p);
+ Eterm ref;
+ ErtsGCInfoReq *gcirp;
+ Eterm *hp;
+
+ gcirp = gcireq_alloc();
+ ref = erts_make_ref(c_p);
+ hp = &gcirp->ref_heap[0];
+
+ gcirp->proc = c_p;
+ gcirp->ref = STORE_NC(&hp, NULL, ref);
+ gcirp->req_sched = esdp->no;
+ erts_smp_atomic32_init_nob(&gcirp->refc,
+ (erts_aint32_t) erts_no_schedulers);
+
+ erts_smp_proc_add_refc(c_p, (Sint32) erts_no_schedulers);
+
+#ifdef ERTS_SMP
+ if (erts_no_schedulers > 1)
+ erts_schedule_multi_misc_aux_work(1,
+ erts_no_schedulers,
+ reply_gc_info,
+ (void *) gcirp);
+#endif
+
+ reply_gc_info((void *) gcirp);
+
+ return ref;
+}
+
#if defined(DEBUG) || defined(ERTS_OFFHEAP_DEBUG)
static int
diff --git a/erts/emulator/beam/erl_goodfit_alloc.c b/erts/emulator/beam/erl_goodfit_alloc.c
index c2088929e9..79d8b40f8c 100644
--- a/erts/emulator/beam/erl_goodfit_alloc.c
+++ b/erts/emulator/beam/erl_goodfit_alloc.c
@@ -589,16 +589,16 @@ info_options(Allctr_t *allctr,
* to erts_gfalc_test() *
\* */
-unsigned long
-erts_gfalc_test(unsigned long op, unsigned long a1, unsigned long a2)
+UWord
+erts_gfalc_test(UWord op, UWord a1, UWord a2)
{
switch (op) {
- case 0x100: return (unsigned long) BKT_IX((GFAllctr_t *) a1, (Uint) a2);
- case 0x101: return (unsigned long) BKT_MIN_SZ((GFAllctr_t *) a1, (int) a2);
- case 0x102: return (unsigned long) NO_OF_BKTS;
- case 0x103: return (unsigned long)
+ case 0x100: return (UWord) BKT_IX((GFAllctr_t *) a1, (Uint) a2);
+ case 0x101: return (UWord) BKT_MIN_SZ((GFAllctr_t *) a1, (int) a2);
+ case 0x102: return (UWord) NO_OF_BKTS;
+ case 0x103: return (UWord)
find_bucket(&((GFAllctr_t *) a1)->bucket_mask, (int) a2);
- default: ASSERT(0); return ~((unsigned long) 0);
+ default: ASSERT(0); return ~((UWord) 0);
}
}
diff --git a/erts/emulator/beam/erl_goodfit_alloc.h b/erts/emulator/beam/erl_goodfit_alloc.h
index a554a6f466..11bef77e7f 100644
--- a/erts/emulator/beam/erl_goodfit_alloc.h
+++ b/erts/emulator/beam/erl_goodfit_alloc.h
@@ -82,7 +82,7 @@ struct GFAllctr_t_ {
};
-unsigned long erts_gfalc_test(unsigned long, unsigned long, unsigned long);
+UWord erts_gfalc_test(UWord, UWord, UWord);
#endif /* #if defined(GET_ERL_GF_ALLOC_IMPL)
&& !defined(ERL_GF_ALLOC_IMPL__) */
diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c
index e6a96d427f..b3a3c3d403 100644
--- a/erts/emulator/beam/erl_init.c
+++ b/erts/emulator/beam/erl_init.c
@@ -131,8 +131,10 @@ extern void ConWaitForExit(void);
static void erl_init(int ncpu,
int proc_tab_sz,
+ int legacy_proc_tab,
int port_tab_sz,
- int port_tab_sz_ignore_files);
+ int port_tab_sz_ignore_files,
+ int legacy_port_tab);
static erts_atomic_t exiting;
@@ -280,7 +282,9 @@ erts_short_init(void)
int ncpu = early_init(NULL, NULL);
erl_init(ncpu,
ERTS_DEFAULT_MAX_PROCESSES,
+ 0,
ERTS_DEFAULT_MAX_PORTS,
+ 0,
0);
erts_initialized = 1;
}
@@ -288,19 +292,21 @@ erts_short_init(void)
static void
erl_init(int ncpu,
int proc_tab_sz,
+ int legacy_proc_tab,
int port_tab_sz,
- int port_tab_sz_ignore_files)
+ int port_tab_sz_ignore_files,
+ int legacy_port_tab)
{
init_benchmarking();
erts_init_monitors();
- erts_init_gc();
erts_init_time();
erts_init_sys_common_misc();
- erts_init_process(ncpu, proc_tab_sz);
+ erts_init_process(ncpu, proc_tab_sz, legacy_proc_tab);
erts_init_scheduling(no_schedulers,
no_schedulers_online);
erts_init_cpu_topology(); /* Must be after init_scheduling */
+ erts_init_gc(); /* Must be after init_scheduling */
erts_alloc_late_init();
H_MIN_SIZE = erts_next_heap_size(H_MIN_SIZE, 0);
@@ -327,7 +333,7 @@ erl_init(int ncpu,
init_dist();
erl_drv_thr_init();
erts_init_async();
- erts_init_io(port_tab_sz, port_tab_sz_ignore_files);
+ erts_init_io(port_tab_sz, port_tab_sz_ignore_files, legacy_port_tab);
init_load();
erts_init_bif();
erts_init_bif_chksum();
@@ -923,6 +929,9 @@ erl_start(int argc, char **argv)
int proc_tab_sz = ERTS_DEFAULT_MAX_PROCESSES;
int port_tab_sz = ERTS_DEFAULT_MAX_PORTS;
int port_tab_sz_ignore_files = 0;
+ int legacy_proc_tab = 0;
+ int legacy_port_tab = 0;
+
envbufsz = sizeof(envbuf);
if (erts_sys_getenv_raw(ERL_MAX_ETS_TABLES_ENV, envbuf, &envbufsz) == 0)
@@ -1268,27 +1277,35 @@ erl_start(int argc, char **argv)
case 'P': /* set maximum number of processes */
arg = get_arg(argv[i]+2, argv[i+1], &i);
- errno = 0;
- proc_tab_sz = strtol(arg, NULL, 10);
- if (errno != 0
- || proc_tab_sz < ERTS_MIN_PROCESSES
- || ERTS_MAX_PROCESSES < proc_tab_sz) {
- erts_fprintf(stderr, "bad number of processes %s\n", arg);
- erts_usage();
+ if (strcmp(arg, "legacy") == 0)
+ legacy_proc_tab = 1;
+ else {
+ errno = 0;
+ proc_tab_sz = strtol(arg, NULL, 10);
+ if (errno != 0
+ || proc_tab_sz < ERTS_MIN_PROCESSES
+ || ERTS_MAX_PROCESSES < proc_tab_sz) {
+ erts_fprintf(stderr, "bad number of processes %s\n", arg);
+ erts_usage();
+ }
}
break;
case 'Q': /* set maximum number of ports */
arg = get_arg(argv[i]+2, argv[i+1], &i);
- errno = 0;
- port_tab_sz = strtol(arg, NULL, 10);
- if (errno != 0
- || port_tab_sz < ERTS_MIN_PROCESSES
- || ERTS_MAX_PROCESSES < port_tab_sz) {
- erts_fprintf(stderr, "bad number of ports %s\n", arg);
- erts_usage();
+ if (strcmp(arg, "legacy") == 0)
+ legacy_port_tab = 1;
+ else {
+ errno = 0;
+ port_tab_sz = strtol(arg, NULL, 10);
+ if (errno != 0
+ || port_tab_sz < ERTS_MIN_PROCESSES
+ || ERTS_MAX_PROCESSES < port_tab_sz) {
+ erts_fprintf(stderr, "bad number of ports %s\n", arg);
+ erts_usage();
+ }
+ port_tab_sz_ignore_files = 1;
}
- port_tab_sz_ignore_files = 1;
break;
case 'S' : /* Was handled in early_init() just read past it */
@@ -1642,8 +1659,10 @@ erl_start(int argc, char **argv)
erl_init(ncpu,
proc_tab_sz,
+ legacy_proc_tab,
port_tab_sz,
- port_tab_sz_ignore_files);
+ port_tab_sz_ignore_files,
+ legacy_port_tab);
load_preloaded();
erts_end_staging_code_ix();
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 7415a5721f..81799ddbb1 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -485,7 +485,7 @@ release_process(void *vproc)
/* initialize the scheduler */
void
-erts_init_process(int ncpu, int proc_tab_size)
+erts_init_process(int ncpu, int proc_tab_size, int legacy_proc_tab)
{
#ifdef ERTS_SMP
@@ -505,7 +505,8 @@ erts_init_process(int ncpu, int proc_tab_size)
(ErtsPTabElementCommon *) &erts_invalid_process.common,
proc_tab_size,
sizeof(Process),
- "process_table");
+ "process_table",
+ legacy_proc_tab);
last_reductions = 0;
last_exact_reductions = 0;
@@ -4670,8 +4671,8 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online)
esdp->reductions = 0;
init_sched_wall_time(&esdp->sched_wall_time);
-
erts_port_task_handle_init(&esdp->nosuspend_port_task_handle);
+
}
init_misc_aux_work();
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 5a1f6bbe8d..7dd8116857 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -420,6 +420,11 @@ typedef struct {
} ErtsSchedWallTime;
typedef struct {
+ Uint64 reclaimed;
+ Uint64 garbage_cols;
+} ErtsGCInfo;
+
+typedef struct {
int sched;
erts_aint32_t aux_work;
} ErtsDelayedAuxWorkWakeupJob;
@@ -507,6 +512,7 @@ struct ErtsSchedulerData_ {
Uint64 reductions;
ErtsSchedWallTime sched_wall_time;
+ ErtsGCInfo gc_info;
ErtsPortTaskHandle nosuspend_port_task_handle;
#ifdef ERTS_DO_VERIFY_UNUSED_TEMP_ALLOC
@@ -1126,6 +1132,7 @@ void erts_early_init_scheduling(int);
void erts_init_scheduling(int, int);
Eterm erts_sched_wall_time_request(Process *c_p, int set, int enable);
+Eterm erts_gc_info_request(Process *c_p);
Uint64 erts_get_proc_interval(void);
Uint64 erts_ensure_later_proc_interval(Uint64);
Uint64 erts_step_proc_interval(void);
@@ -1352,7 +1359,7 @@ void erts_schedule_multi_misc_aux_work(int ignore_self,
erts_aint32_t erts_set_aux_work_timeout(int, erts_aint32_t, int);
void erts_sched_notify_check_cpu_bind(void);
Uint erts_active_schedulers(void);
-void erts_init_process(int, int);
+void erts_init_process(int, int, int);
Eterm erts_process_status(Process *, ErtsProcLocks, Process *, Eterm);
Uint erts_run_queues_len(Uint *);
void erts_add_to_runq(Process *);
diff --git a/erts/emulator/beam/erl_ptab.c b/erts/emulator/beam/erl_ptab.c
index 5bbc71c659..8da135b2c8 100644
--- a/erts/emulator/beam/erl_ptab.c
+++ b/erts/emulator/beam/erl_ptab.c
@@ -34,6 +34,8 @@
typedef struct ErtsPTabListBifData_ ErtsPTabListBifData;
+#define ERTS_PTAB_NEW_MAX_RESERVE_FAIL 1000
+
#define ERTS_PTAB_LIST_BIF_TAB_INSPECT_INDICES_PER_RED 25
#define ERTS_PTAB_LIST_BIF_TAB_CHUNK_SIZE 1000
#define ERTS_PTAB_LIST_BIF_MIN_START_REDS \
@@ -415,6 +417,27 @@ last_data_cmp(Uint64 ld1, Uint64 ld2)
#define ERTS_PTAB_LastData2EtermData(LD) \
((Eterm) ((LD) & ~(~((Uint64) 0) << ERTS_PTAB_ID_DATA_SIZE)))
+static ERTS_INLINE Uint32
+ix_to_free_id_data_ix(ErtsPTab *ptab, Uint32 ix)
+{
+ Uint32 dix;
+
+ dix = ((ix & ptab->r.o.dix_cl_mask) << ptab->r.o.dix_cl_shift);
+ dix += ((ix >> ptab->r.o.dix_cli_shift) & ptab->r.o.dix_cli_mask);
+ ASSERT(0 <= dix && dix < ptab->r.o.max);
+ return dix;
+}
+
+UWord
+erts_ptab_mem_size(ErtsPTab *ptab)
+{
+ UWord size = ptab->r.o.max*sizeof(erts_smp_atomic_t);
+ if (ptab->r.o.free_id_data)
+ size += ptab->r.o.max*sizeof(Uint32);
+ return size;
+}
+
+
void
erts_ptab_init_table(ErtsPTab *ptab,
ErtsAlcType_t atype,
@@ -422,10 +445,11 @@ erts_ptab_init_table(ErtsPTab *ptab,
ErtsPTabElementCommon *invalid_element,
int size,
UWord element_size,
- char *name)
+ char *name,
+ int legacy)
{
- size_t tab_sz;
- int bits;
+ size_t tab_sz, alloc_sz;
+ Uint32 bits, cl, cli, ix, ix_per_cache_line, tab_cache_lines;
char *tab_end;
erts_smp_atomic_t *tab_entry;
erts_smp_rwmtx_opt_t rwmtx_opts = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER;
@@ -448,7 +472,10 @@ erts_ptab_init_table(ErtsPTab *ptab,
ptab->r.o.max = size;
tab_sz = ERTS_ALC_CACHE_LINE_ALIGN_SIZE(size*sizeof(erts_smp_atomic_t));
- ptab->r.o.tab = erts_alloc_permanent_cache_aligned(atype, tab_sz);
+ alloc_sz = tab_sz;
+ if (!legacy)
+ alloc_sz += ERTS_ALC_CACHE_LINE_ALIGN_SIZE(size*sizeof(Uint32));
+ ptab->r.o.tab = erts_alloc_permanent_cache_aligned(atype, alloc_sz);
tab_end = ((char *) ptab->r.o.tab) + tab_sz;
tab_entry = ptab->r.o.tab;
while (tab_end > ((char *) tab_entry)) {
@@ -456,28 +483,57 @@ erts_ptab_init_table(ErtsPTab *ptab,
tab_entry++;
}
- ptab->r.o.tab_cache_lines = tab_sz/ERTS_CACHE_LINE_SIZE;
- ptab->r.o.pix_per_cache_line = (ERTS_CACHE_LINE_SIZE
- / sizeof(erts_smp_atomic_t));
+ tab_cache_lines = tab_sz/ERTS_CACHE_LINE_SIZE;
+ ix_per_cache_line = (ERTS_CACHE_LINE_SIZE/sizeof(erts_smp_atomic_t));
ASSERT((ptab->r.o.max & (ptab->r.o.max - 1)) == 0); /* power of 2 */
- ASSERT((ptab->r.o.pix_per_cache_line
- & (ptab->r.o.pix_per_cache_line - 1)) == 0); /* power of 2 */
- ASSERT((ptab->r.o.tab_cache_lines
- & (ptab->r.o.tab_cache_lines - 1)) == 0); /* power of 2 */
-
- ptab->r.o.pix_mask
- = (1 << bits) - 1;
- ptab->r.o.pix_cl_mask
- = ptab->r.o.tab_cache_lines-1;
- ptab->r.o.pix_cl_shift
- = erts_fit_in_bits_int32(ptab->r.o.pix_per_cache_line-1);
- ptab->r.o.pix_cli_shift
- = erts_fit_in_bits_int32(ptab->r.o.pix_cl_mask);
- ptab->r.o.pix_cli_mask
- = (1 << (bits - ptab->r.o.pix_cli_shift)) - 1;
+ ASSERT((ix_per_cache_line & (ix_per_cache_line - 1)) == 0); /* power of 2 */
+ ASSERT((tab_cache_lines & (tab_cache_lines - 1)) == 0); /* power of 2 */
+
+ ptab->r.o.pix_mask = (1 << bits) - 1;
+ ptab->r.o.pix_cl_mask = tab_cache_lines-1;
+ ptab->r.o.pix_cl_shift = erts_fit_in_bits_int32(ix_per_cache_line-1);
+ ptab->r.o.pix_cli_shift = erts_fit_in_bits_int32(ptab->r.o.pix_cl_mask);
+ ptab->r.o.pix_cli_mask = (1 << (bits - ptab->r.o.pix_cli_shift)) - 1;
ASSERT(ptab->r.o.pix_cl_shift + ptab->r.o.pix_cli_shift == bits);
+ if (legacy) {
+ ptab->r.o.free_id_data = NULL;
+ ptab->r.o.dix_cl_mask = 0;
+ ptab->r.o.dix_cl_shift = 0;
+ ptab->r.o.dix_cli_shift = 0;
+ ptab->r.o.dix_cli_mask = 0;
+ }
+ else {
+
+ tab_sz = ERTS_ALC_CACHE_LINE_ALIGN_SIZE(size*sizeof(Uint32));
+ ptab->r.o.free_id_data = (Uint32 *) tab_end;
+
+ tab_cache_lines = tab_sz/ERTS_CACHE_LINE_SIZE;
+ ix_per_cache_line = (ERTS_CACHE_LINE_SIZE/sizeof(Uint32));
+
+ ptab->r.o.dix_cl_mask = tab_cache_lines-1;
+ ptab->r.o.dix_cl_shift = erts_fit_in_bits_int32(ix_per_cache_line-1);
+ ptab->r.o.dix_cli_shift = erts_fit_in_bits_int32(ptab->r.o.dix_cl_mask);
+ ptab->r.o.dix_cli_mask = (1 << (bits - ptab->r.o.dix_cli_shift)) - 1;
+
+ ASSERT((ix_per_cache_line & (ix_per_cache_line - 1)) == 0); /* power of 2 */
+ ASSERT((tab_cache_lines & (tab_cache_lines - 1)) == 0); /* power of 2 */
+
+ ASSERT(ptab->r.o.dix_cl_shift + ptab->r.o.dix_cli_shift == bits);
+
+ ix = 0;
+ for (cl = 0; cl < tab_cache_lines; cl++) {
+ for (cli = 0; cli < ix_per_cache_line; cli++) {
+ ptab->r.o.free_id_data[ix] = cli*tab_cache_lines+cl;
+ ix++;
+ }
+ }
+
+ erts_smp_atomic32_init_nob(&ptab->vola.tile.aid_ix, -1);
+ erts_smp_atomic32_init_nob(&ptab->vola.tile.fid_ix, -1);
+
+ }
ptab->r.o.invalid_element = invalid_element;
ptab->r.o.invalid_data = erts_ptab_id2data(ptab, invalid_element->id);
ptab->r.o.release_element = release_element;
@@ -522,9 +578,7 @@ erts_ptab_new_element(ErtsPTab *ptab,
void *init_arg,
void (*init_ptab_el)(void *, Eterm))
{
- int pix;
- Uint64 ld, exp_ld;
- Eterm data;
+ Uint32 pix, ix, data;
erts_aint32_t count;
erts_aint_t invalid = (erts_aint_t) ptab->r.o.invalid_element;
@@ -551,62 +605,108 @@ erts_ptab_new_element(ErtsPTab *ptab,
ptab_el->u.alive.started_interval
= erts_smp_current_interval_nob(erts_ptab_interval(ptab));
- ld = last_data_read_acqb(ptab);
+ if (ptab->r.o.free_id_data) {
- /* Reserve slot */
- while (1) {
- ld++;
- pix = erts_ptab_data2pix(ptab, ERTS_PTAB_LastData2EtermData(ld));
- if (erts_smp_atomic_read_nob(&ptab->r.o.tab[pix]) == ERTS_AINT_NULL) {
- erts_aint_t val;
- val = erts_smp_atomic_cmpxchg_relb(&ptab->r.o.tab[pix],
- invalid,
- ERTS_AINT_NULL);
+ ix = (Uint32) erts_smp_atomic32_inc_read_acqb(&ptab->vola.tile.aid_ix);
+ ix = ix_to_free_id_data_ix(ptab, ix);
+
+ data = ptab->r.o.free_id_data[ix];
+
+ init_ptab_el(init_arg, (Eterm) data);
+
+#ifdef ERTS_SMP
+ erts_smp_atomic32_init_nob(&ptab_el->refc, 1);
+#endif
+
+ pix = erts_ptab_data2pix(ptab, (Eterm) data);
+
+#ifdef DEBUG
+ ASSERT(ERTS_AINT_NULL == erts_smp_atomic_xchg_relb(&ptab->r.o.tab[pix],
+ (erts_aint_t) ptab_el));
+#else
+ erts_smp_atomic_set_relb(&ptab->r.o.tab[pix], (erts_aint_t) ptab_el);
+#endif
+
+ erts_ptab_runlock(ptab);
- if (ERTS_AINT_NULL == val)
- break;
- }
}
+ else {
+ int rlocked = ERTS_PTAB_NEW_MAX_RESERVE_FAIL;
+ Uint64 ld, exp_ld;
+ /* Deprecated legacy algorithm... */
+
+ restart:
+
+ ptab_el->u.alive.started_interval
+ = erts_smp_current_interval_nob(erts_ptab_interval(ptab));
- data = ERTS_PTAB_LastData2EtermData(ld);
+ ld = last_data_read_acqb(ptab);
+
+ /* Reserve slot */
+ while (1) {
+ ld++;
+ pix = erts_ptab_data2pix(ptab, ERTS_PTAB_LastData2EtermData(ld));
+ if (erts_smp_atomic_read_nob(&ptab->r.o.tab[pix])
+ == ERTS_AINT_NULL) {
+ erts_aint_t val;
+ val = erts_smp_atomic_cmpxchg_relb(&ptab->r.o.tab[pix],
+ invalid,
+ ERTS_AINT_NULL);
+
+ if (ERTS_AINT_NULL == val)
+ break;
+ }
+ if (rlocked && --rlocked == 0) {
+ erts_ptab_runlock(ptab);
+ erts_ptab_rwlock(ptab);
+ goto restart;
+ }
+ }
- if (data == ptab->r.o.invalid_data) {
- /* Do not use invalid data; fix it... */
- ld += ptab->r.o.max;
- ASSERT(pix == erts_ptab_data2pix(ptab,
- ERTS_PTAB_LastData2EtermData(ld)));
data = ERTS_PTAB_LastData2EtermData(ld);
- ASSERT(data != ptab->r.o.invalid_data);
- }
- exp_ld = last_data_read_nob(ptab);
+ if (data == ptab->r.o.invalid_data) {
+ /* Do not use invalid data; fix it... */
+ ld += ptab->r.o.max;
+ ASSERT(pix == erts_ptab_data2pix(ptab,
+ ERTS_PTAB_LastData2EtermData(ld)));
+ data = ERTS_PTAB_LastData2EtermData(ld);
+ ASSERT(data != ptab->r.o.invalid_data);
+ }
- /* Move last data forward */
- while (1) {
- Uint64 act_ld;
- if (last_data_cmp(ld, exp_ld) < 0)
- break;
- act_ld = last_data_cmpxchg_relb(ptab, ld, exp_ld);
- if (act_ld == exp_ld)
- break;
- exp_ld = act_ld;
- }
+ exp_ld = last_data_read_nob(ptab);
+
+ /* Move last data forward */
+ while (1) {
+ Uint64 act_ld;
+ if (last_data_cmp(ld, exp_ld) < 0)
+ break;
+ act_ld = last_data_cmpxchg_relb(ptab, ld, exp_ld);
+ if (act_ld == exp_ld)
+ break;
+ exp_ld = act_ld;
+ }
- init_ptab_el(init_arg, data);
+ init_ptab_el(init_arg, data);
#ifdef ERTS_SMP
- erts_smp_atomic32_init_nob(&ptab_el->refc, 1);
+ erts_smp_atomic32_init_nob(&ptab_el->refc, 1);
#endif
- /* Move into slot reserved */
+ /* Move into slot reserved */
#ifdef DEBUG
- ASSERT(invalid == erts_smp_atomic_xchg_relb(&ptab->r.o.tab[pix],
+ ASSERT(invalid == erts_smp_atomic_xchg_relb(&ptab->r.o.tab[pix],
(erts_aint_t) ptab_el));
#else
- erts_smp_atomic_set_relb(&ptab->r.o.tab[pix], (erts_aint_t) ptab_el);
+ erts_smp_atomic_set_relb(&ptab->r.o.tab[pix], (erts_aint_t) ptab_el);
#endif
- erts_ptab_runlock(ptab);
+ if (rlocked)
+ erts_ptab_runlock(ptab);
+ else
+ erts_ptab_rwunlock(ptab);
+
+ }
return 1;
}
@@ -647,7 +747,9 @@ erts_ptab_delete_element(ErtsPTab *ptab,
ErtsPTabElementCommon *ptab_el)
{
int maybe_save;
- int pix = erts_ptab_id2pix(ptab, ptab_el->id);
+ Uint32 pix, ix, data;
+
+ pix = erts_ptab_id2pix(ptab, ptab_el->id);
ASSERT(erts_get_scheduler_id()); /* *Need* to be a scheduler */
@@ -660,6 +762,26 @@ erts_ptab_delete_element(ErtsPTab *ptab,
erts_smp_atomic_set_relb(&ptab->r.o.tab[pix], ERTS_AINT_NULL);
+ if (ptab->r.o.free_id_data) {
+
+ /* Next data for this slot... */
+ data = (Uint32) erts_ptab_id2data(ptab, ptab_el->id);
+ data += ptab->r.o.max;
+ data &= ~(~((Uint32) 0) << ERTS_PTAB_ID_DATA_SIZE);
+ if (data == ptab->r.o.invalid_data) { /* make sure not invalid */
+ data += ptab->r.o.max;
+ data &= ~(~((Uint32) 0) << ERTS_PTAB_ID_DATA_SIZE);
+ }
+
+ ASSERT(data != ptab->r.o.invalid_data);
+ ASSERT(pix == erts_ptab_data2pix(ptab, data));
+
+ ix = (Uint32) erts_smp_atomic32_inc_read_relb(&ptab->vola.tile.fid_ix);
+ ix = ix_to_free_id_data_ix(ptab, ix);
+
+ ptab->r.o.free_id_data[ix] = data;
+ }
+
ASSERT(erts_smp_atomic32_read_nob(&ptab->vola.tile.count) > 0);
erts_smp_atomic32_dec_relb(&ptab->vola.tile.count);
@@ -1280,42 +1402,86 @@ erts_ptab_test_next_id(ErtsPTab *ptab, int set, Uint next)
erts_ptab_rwlock(ptab);
- if (!set)
- ld = last_data_read_nob(ptab);
- else {
+ if (ptab->r.o.free_id_data) {
+ Uint32 aid_ix, dix;
- ld = (Uint64) next;
- data = ERTS_PTAB_LastData2EtermData(ld);
- if (ptab->r.o.invalid_data == data) {
- ld += ptab->r.o.max;
- ASSERT(erts_ptab_data2pix(ptab, data)
- == erts_ptab_data2pix(ptab,
- ERTS_PTAB_LastData2EtermData(ld)));
+ if (set) {
+ Uint32 max_ix, ser, num, start;
+ max_ix = ptab->r.o.max - 1;
+ ser = next & ~max_ix;
+ start = num = next & max_ix;
+
+ aid_ix = (Uint32) erts_smp_atomic32_read_nob(&ptab->vola.tile.aid_ix) + 1;
+
+ do {
+ Uint32 pix = erts_ptab_data2pix(ptab, num);
+ if (ERTS_AINT_NULL == erts_ptab_pix2intptr_nob(ptab, pix)) {
+ dix = ix_to_free_id_data_ix(ptab, aid_ix);
+ ptab->r.o.free_id_data[dix] = ser + num;
+ ASSERT(pix == erts_ptab_data2pix(ptab, ser+num));
+ if (aid_ix == max_ix)
+ aid_ix = 0;
+ else
+ aid_ix++;
+ }
+ if (num == max_ix)
+ num = 0;
+ else
+ num++;
+ } while (num != start);
+
+#ifdef DEBUG
+ if (aid_ix == 0)
+ aid_ix = max_ix;
+ else
+ aid_ix--;
+ ASSERT((aid_ix & max_ix) == (((Uint32) erts_atomic32_read_nob(&ptab->vola.tile.fid_ix)) & max_ix));
+#endif
}
- last_data_set_relb(ptab, ld);
+
+ aid_ix = (Uint32) erts_smp_atomic32_read_nob(&ptab->vola.tile.aid_ix) + 1;
+ dix = ix_to_free_id_data_ix(ptab, aid_ix);
+ res = (Sint) ptab->r.o.free_id_data[dix];
}
+ else {
+ /* Deprecated legacy algorithm... */
+ if (!set)
+ ld = last_data_read_nob(ptab);
+ else {
- while (1) {
- int pix;
- ld++;
- pix = (int) (ld % ptab->r.o.max);
- if (first_pix < 0)
- first_pix = pix;
- else if (pix == first_pix) {
- res = -1;
- break;
- }
- if (ERTS_AINT_NULL == erts_ptab_pix2intptr_nob(ptab, pix)) {
+ ld = (Uint64) next;
data = ERTS_PTAB_LastData2EtermData(ld);
if (ptab->r.o.invalid_data == data) {
ld += ptab->r.o.max;
ASSERT(erts_ptab_data2pix(ptab, data)
== erts_ptab_data2pix(ptab,
ERTS_PTAB_LastData2EtermData(ld)));
+ }
+ last_data_set_relb(ptab, ld);
+ }
+
+ while (1) {
+ int pix;
+ ld++;
+ pix = (int) (ld % ptab->r.o.max);
+ if (first_pix < 0)
+ first_pix = pix;
+ else if (pix == first_pix) {
+ res = -1;
+ break;
+ }
+ if (ERTS_AINT_NULL == erts_ptab_pix2intptr_nob(ptab, pix)) {
data = ERTS_PTAB_LastData2EtermData(ld);
+ if (ptab->r.o.invalid_data == data) {
+ ld += ptab->r.o.max;
+ ASSERT(erts_ptab_data2pix(ptab, data)
+ == erts_ptab_data2pix(ptab,
+ ERTS_PTAB_LastData2EtermData(ld)));
+ data = ERTS_PTAB_LastData2EtermData(ld);
+ }
+ res = data;
+ break;
}
- res = data;
- break;
}
}
diff --git a/erts/emulator/beam/erl_ptab.h b/erts/emulator/beam/erl_ptab.h
index 7fa1251900..84ff7d0de4 100644
--- a/erts/emulator/beam/erl_ptab.h
+++ b/erts/emulator/beam/erl_ptab.h
@@ -94,18 +94,23 @@ typedef struct {
erts_smp_atomic_t last_data;
#endif
erts_smp_atomic32_t count;
+ erts_smp_atomic32_t aid_ix;
+ erts_smp_atomic32_t fid_ix;
} ErtsPTabVolatileData;
typedef struct {
erts_smp_atomic_t *tab;
+ Uint32 *free_id_data;
Uint32 max;
- Uint32 tab_cache_lines;
- Uint32 pix_per_cache_line;
Uint32 pix_mask;
Uint32 pix_cl_mask;
Uint32 pix_cl_shift;
Uint32 pix_cli_mask;
Uint32 pix_cli_shift;
+ Uint32 dix_cl_mask;
+ Uint32 dix_cl_shift;
+ Uint32 dix_cli_mask;
+ Uint32 dix_cli_shift;
ErtsPTabElementCommon *invalid_element;
Eterm invalid_data;
void (*release_element)(void *);
@@ -179,7 +184,8 @@ void erts_ptab_init_table(ErtsPTab *ptab,
ErtsPTabElementCommon *invalid_element,
int size,
UWord element_size,
- char *name);
+ char *name,
+ int legacy);
int erts_ptab_new_element(ErtsPTab *ptab,
ErtsPTabElementCommon *ptab_el,
void *init_arg,
@@ -187,6 +193,7 @@ int erts_ptab_new_element(ErtsPTab *ptab,
void erts_ptab_delete_element(ErtsPTab *ptab,
ErtsPTabElementCommon *ptab_el);
int erts_ptab_initialized(ErtsPTab *ptab);
+UWord erts_ptab_mem_size(ErtsPTab *ptab);
ERTS_GLB_INLINE erts_interval_t *erts_ptab_interval(ErtsPTab *ptab);
ERTS_GLB_INLINE int erts_ptab_max(ErtsPTab *ptab);
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index 012c1c7e6a..26ed5f82c1 100755
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -688,12 +688,6 @@ void MD5Final(unsigned char [16], MD5_CTX *);
/* ggc.c */
-
-typedef struct {
- Uint garbage_collections;
- Uint reclaimed;
-} ErtsGCInfo;
-
void erts_gc_info(ErtsGCInfo *gcip);
void erts_init_gc(void);
int erts_garbage_collect(Process*, int, Eterm*, int);
@@ -724,7 +718,7 @@ int erts_add_driver_entry(ErlDrvEntry *drv, DE_Handle *handle, int driver_list_l
void erts_destroy_driver(erts_driver_t *drv);
int erts_save_suspend_process_on_port(Port*, Process*);
Port *erts_open_driver(erts_driver_t*, Eterm, char*, SysDriverOpts*, int *, int *);
-void erts_init_io(int, int);
+void erts_init_io(int, int, int);
void erts_raw_port_command(Port*, byte*, Uint);
void driver_report_exit(ErlDrvPort, int);
LineBuf* allocate_linebuf(int);
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index b6b7b47bd6..13cff24b95 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -2707,7 +2707,8 @@ erts_port_link(Process *c_p, Port *prt, Eterm to, Eterm *refp)
}
void erts_init_io(int port_tab_size,
- int port_tab_size_ignore_files)
+ int port_tab_size_ignore_files,
+ int legacy_port_tab)
{
ErlDrvEntry** dp;
UWord common_element_size;
@@ -2750,7 +2751,8 @@ void erts_init_io(int port_tab_size,
(ErtsPTabElementCommon *) &erts_invalid_port.common,
port_tab_size,
common_element_size, /* Doesn't need to be excact */
- "port_table");
+ "port_table",
+ legacy_port_tab);
erts_smp_atomic_init_nob(&erts_bytes_out, 0);
erts_smp_atomic_init_nob(&erts_bytes_in, 0);
diff --git a/erts/emulator/sys/common/erl_mseg.c b/erts/emulator/sys/common/erl_mseg.c
index b6e2c9382b..2748edba02 100644
--- a/erts/emulator/sys/common/erl_mseg.c
+++ b/erts/emulator/sys/common/erl_mseg.c
@@ -1749,45 +1749,42 @@ erts_mseg_late_init(void)
#endif /* #if HAVE_ERTS_MSEG */
-unsigned long
-erts_mseg_test(unsigned long op,
- unsigned long a1,
- unsigned long a2,
- unsigned long a3)
+UWord
+erts_mseg_test(UWord op, UWord a1, UWord a2, UWord a3)
{
switch (op) {
#if HAVE_ERTS_MSEG
case 0x400: /* Have erts_mseg */
- return (unsigned long) 1;
+ return (UWord) 1;
case 0x401:
- return (unsigned long) erts_mseg_alloc(ERTS_ALC_A_INVALID, (Uint *) a1, (Uint) 0);
+ return (UWord) erts_mseg_alloc(ERTS_ALC_A_INVALID, (Uint *) a1, (Uint) 0);
case 0x402:
erts_mseg_dealloc(ERTS_ALC_A_INVALID, (void *) a1, (Uint) a2, (Uint) 0);
- return (unsigned long) 0;
+ return (UWord) 0;
case 0x403:
- return (unsigned long) erts_mseg_realloc(ERTS_ALC_A_INVALID,
+ return (UWord) erts_mseg_realloc(ERTS_ALC_A_INVALID,
(void *) a1,
(Uint) a2,
(Uint *) a3,
(Uint) 0);
case 0x404:
erts_mseg_clear_cache();
- return (unsigned long) 0;
+ return (UWord) 0;
case 0x405:
- return (unsigned long) erts_mseg_no(&erts_mseg_default_opt);
+ return (UWord) erts_mseg_no(&erts_mseg_default_opt);
case 0x406: {
ErtsMsegAllctr_t *ma = ERTS_MSEG_ALLCTR_IX(0);
- unsigned long res;
+ UWord res;
ERTS_MSEG_LOCK(ma);
- res = (unsigned long) tot_cache_size(ma);
+ res = (UWord) tot_cache_size(ma);
ERTS_MSEG_UNLOCK(ma);
return res;
}
#else /* #if HAVE_ERTS_MSEG */
case 0x400: /* Have erts_mseg */
- return (unsigned long) 0;
+ return (UWord) 0;
#endif /* #if HAVE_ERTS_MSEG */
- default: ASSERT(0); return ~((unsigned long) 0);
+ default: ASSERT(0); return ~((UWord) 0);
}
}
diff --git a/erts/emulator/sys/common/erl_mseg.h b/erts/emulator/sys/common/erl_mseg.h
index 3cab9e18da..a4f250ceab 100644
--- a/erts/emulator/sys/common/erl_mseg.h
+++ b/erts/emulator/sys/common/erl_mseg.h
@@ -109,9 +109,6 @@ Eterm erts_mseg_info(int, int *, void*, int, Uint **, Uint *);
#endif /* #if HAVE_ERTS_MSEG */
-unsigned long erts_mseg_test(unsigned long,
- unsigned long,
- unsigned long,
- unsigned long);
+UWord erts_mseg_test(UWord, UWord, UWord, UWord);
#endif /* #ifndef ERL_MSEG_H_ */
diff --git a/erts/emulator/sys/win32/sys_float.c b/erts/emulator/sys/win32/sys_float.c
index e2a777d182..0e19746cf5 100644
--- a/erts/emulator/sys/win32/sys_float.c
+++ b/erts/emulator/sys/win32/sys_float.c
@@ -52,7 +52,7 @@ void erts_thread_disable_fpe(void)
int
sys_chars_to_double(char *buf, double *fp)
{
- char *s = buf, *t, *dp;
+ unsigned char *s = buf, *t, *dp;
/* Robert says that something like this is what he really wanted:
* (The [.,] radix test is NOT what Robert wanted - it was added later)
@@ -120,7 +120,7 @@ sys_chars_to_double(char *buf, double *fp)
int
sys_double_to_chars_ext(double fp, char *buffer, size_t buffer_size, size_t decimals)
{
- char *s = buffer;
+ unsigned char *s = buffer;
if (erts_snprintf(buffer, buffer_size, "%.*e", decimals, fp) >= buffer_size)
return -1;
diff --git a/erts/emulator/test/driver_SUITE_data/thr_alloc_drv.c b/erts/emulator/test/driver_SUITE_data/thr_alloc_drv.c
index 95a6ae9bdf..500725a7cd 100644
--- a/erts/emulator/test/driver_SUITE_data/thr_alloc_drv.c
+++ b/erts/emulator/test/driver_SUITE_data/thr_alloc_drv.c
@@ -58,7 +58,7 @@ void *
test_thread(void *vsize)
{
int i;
- int size = (int) (long) vsize;
+ int size = (int) (ErlDrvSInt) vsize;
void *mem;
mem = driver_alloc(size);
if (mem)
@@ -88,7 +88,7 @@ ErlDrvSSizeT control(ErlDrvData drv_data, unsigned int command, char *buf,
res = erl_drv_thread_create("test_thread",
&tid,
test_thread,
- (void *) (long) size,
+ (void *) (ErlDrvSInt) size,
NULL);
if (res == 0) {
res = erl_drv_thread_join(tid, NULL);
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
index c8f286f629..0c4a9f7e5c 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -40,7 +40,7 @@ typedef struct
int ref_cnt;
CallInfo* call_history;
NifModPrivData* nif_mod;
- union { ErlNifResourceType* t; long l; } rt_arr[2];
+ union { ErlNifResourceType* t; void* vp; } rt_arr[2];
} PrivData;
/*
@@ -93,6 +93,23 @@ struct binary_resource {
unsigned size;
};
+static int get_pointer(ErlNifEnv* env, ERL_NIF_TERM term, void** pp)
+{
+ ErlNifUInt64 i64;
+ int r = enif_get_uint64(env, term, &i64);
+ if (r) {
+ *pp = (void*)i64;
+ }
+ return r;
+}
+
+static ERL_NIF_TERM make_pointer(ErlNifEnv* env, void* p)
+{
+ ErlNifUInt64 i64 = (ErlNifUInt64) p;
+ return enif_make_uint64(env, i64);
+}
+
+
static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
{
PrivData* data = enif_alloc(sizeof(PrivData));
@@ -224,15 +241,15 @@ static ERL_NIF_TERM call_history(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
static ERL_NIF_TERM hold_nif_mod_priv_data(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
PrivData* data = (PrivData*) enif_priv_data(env);
- unsigned long ptr_as_ulong;
+ void* ptr;
- if (!enif_get_ulong(env,argv[0],&ptr_as_ulong)) {
+ if (!get_pointer(env,argv[0],&ptr)) {
return enif_make_badarg(env);
}
if (data->nif_mod != NULL) {
NifModPrivData_release(data->nif_mod);
}
- data->nif_mod = (NifModPrivData*) ptr_as_ulong;
+ data->nif_mod = (NifModPrivData*) ptr;
return enif_make_int(env,++(data->nif_mod->ref_cnt));
}
@@ -696,7 +713,7 @@ static ERL_NIF_TERM last_resource_dtor_call(ErlNifEnv* env, int argc, const ERL_
memcpy(enif_make_new_binary(env, resource_dtor_last_sz, &bin),
resource_dtor_last_data, resource_dtor_last_sz);
ret = enif_make_tuple3(env,
- enif_make_long(env, (long)resource_dtor_last),
+ make_pointer(env, resource_dtor_last),
bin,
enif_make_int(env, resource_dtor_cnt));
}
@@ -717,40 +734,40 @@ static ERL_NIF_TERM get_resource_type(ErlNifEnv* env, int argc, const ERL_NIF_TE
if (!enif_get_int(env, argv[0], &ix) || ix >= 2) {
return enif_make_badarg(env);
}
- return enif_make_long(env, data->rt_arr[ix].l);
+ return make_pointer(env, data->rt_arr[ix].vp);
}
static ERL_NIF_TERM alloc_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary data_bin;
- union { ErlNifResourceType* t; long l; } type;
- union { void* p; long l;} data;
- if (!enif_get_long(env, argv[0], &type.l)
+ union { ErlNifResourceType* t; void* vp; } type;
+ void* data;
+ if (!get_pointer(env, argv[0], &type.vp)
|| !enif_inspect_binary(env, argv[1], &data_bin)
- || (data.p = enif_alloc_resource(type.t, data_bin.size))==NULL) {
+ || (data = enif_alloc_resource(type.t, data_bin.size))==NULL) {
return enif_make_badarg(env);
}
- memcpy(data.p, data_bin.data, data_bin.size);
- return enif_make_long(env, data.l);
+ memcpy(data, data_bin.data, data_bin.size);
+ return make_pointer(env, data);
}
static ERL_NIF_TERM make_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- union { void* p; long l; } data;
- if (!enif_get_long(env, argv[0], &data.l)) {
+ void* data;
+ if (!get_pointer(env, argv[0], &data)) {
return enif_make_badarg(env);
}
- return enif_make_resource(env, data.p);
+ return enif_make_resource(env, data);
}
static ERL_NIF_TERM make_new_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary data_bin;
- union { ErlNifResourceType* t; long l; } type;
+ union { ErlNifResourceType* t; void* vp; } type;
void* data;
ERL_NIF_TERM ret;
- if (!enif_get_long(env, argv[0], &type.l)
+ if (!get_pointer(env, argv[0], &type.vp)
|| !enif_inspect_binary(env, argv[1], &data_bin)
|| (data = enif_alloc_resource(type.t, data_bin.size))==NULL) {
@@ -765,7 +782,7 @@ static ERL_NIF_TERM make_new_resource(ErlNifEnv* env, int argc, const ERL_NIF_TE
static ERL_NIF_TERM make_new_resource_binary(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary data_bin;
- union { struct binary_resource* p; void* vp; long l; } br;
+ union { struct binary_resource* p; void* vp; } br;
void* buf;
ERL_NIF_TERM ret;
if (!enif_inspect_binary(env, argv[0], &data_bin)
@@ -781,7 +798,7 @@ static ERL_NIF_TERM make_new_resource_binary(ErlNifEnv* env, int argc, const ERL
memcpy(br.p->data, data_bin.data, data_bin.size);
ret = enif_make_resource_binary(env, br.vp, br.p->data, br.p->size);
enif_release_resource(br.p);
- return enif_make_tuple2(env, enif_make_long(env,br.l), ret);
+ return enif_make_tuple2(env, make_pointer(env,br.vp), ret);
}
static void binary_resource_dtor(ErlNifEnv* env, void* obj)
@@ -796,33 +813,33 @@ static void binary_resource_dtor(ErlNifEnv* env, void* obj)
static ERL_NIF_TERM get_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary data_bin;
- union { ErlNifResourceType* t; long l; } type;
- union { void* p; long l; } data;
+ union { ErlNifResourceType* t; void* vp; } type;
+ void* data;
type.t = NULL;
if (enif_is_identical(argv[0], atom_binary_resource_type)) {
type.t = binary_resource_type;
}
else {
- enif_get_long(env, argv[0], &type.l);
+ get_pointer(env, argv[0], &type.vp);
}
if (type.t == NULL
- || !enif_get_resource(env, argv[1], type.t, &data.p)) {
+ || !enif_get_resource(env, argv[1], type.t, &data)) {
return enif_make_badarg(env);
}
- enif_alloc_binary(enif_sizeof_resource(data.p), &data_bin);
- memcpy(data_bin.data, data.p, data_bin.size);
- return enif_make_tuple2(env, enif_make_long(env,data.l),
+ enif_alloc_binary(enif_sizeof_resource(data), &data_bin);
+ memcpy(data_bin.data, data, data_bin.size);
+ return enif_make_tuple2(env, make_pointer(env,data),
enif_make_binary(env, &data_bin));
}
static ERL_NIF_TERM release_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
- union { void* p; long l; } data;
- if (!enif_get_long(env, argv[0], &data.l)) {
+ void* data;
+ if (!get_pointer(env, argv[0], &data)) {
return enif_make_badarg(env);
}
- enif_release_resource(data.p);
+ enif_release_resource(data);
return enif_make_atom(env,"ok");
}
diff --git a/erts/emulator/test/port_SUITE.erl b/erts/emulator/test/port_SUITE.erl
index 13aa0f4c00..e467e844b3 100644
--- a/erts/emulator/test/port_SUITE.erl
+++ b/erts/emulator/test/port_SUITE.erl
@@ -92,7 +92,7 @@
spawn_driver/1, spawn_executable/1, close_deaf_port/1,
unregister_name/1, parallelism_option/1]).
--export([]).
+-export([do_iter_max_ports/2]).
%% Internal exports.
-export([tps/3]).
@@ -635,9 +635,16 @@ iter_max_ports_test(Config) ->
{win32,_} -> 4;
_ -> 10
end,
- L = do_iter_max_ports(Iters, Command),
+ %% Run on a different node in order to limit the effect if this test fails.
+ Dir = filename:dirname(code:which(?MODULE)),
+ {ok,Node} = test_server:start_node(test_iter_max_socks,slave,
+ [{args,"+Q 2048 -pa " ++ Dir}]),
+ L = rpc:call(Node,?MODULE,do_iter_max_ports,[Iters, Command]),
+ test_server:stop_node(Node),
+
io:format("Result: ~p",[L]),
all_equal(L),
+ all_equal(L),
test_server:timetrap_cancel(Dog),
{comment, "Max ports: " ++ integer_to_list(hd(L))}.
@@ -670,7 +677,7 @@ close_ports([]) ->
ok.
open_ports(Name, Settings) ->
- test_server:sleep(50),
+ test_server:sleep(5),
case catch open_port(Name, Settings) of
P when is_port(P) ->
[P| open_ports(Name, Settings)];
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index 863cd2d654..72f3e8fe85 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -1494,6 +1494,7 @@ processes_bif_cleaner() ->
spawn_initial_hangarounds(Cleaner) ->
TabSz = erlang:system_info(process_limit),
+ erts_debug:set_internal_state(next_pid,TabSz),
spawn_initial_hangarounds(Cleaner,
TabSz,
TabSz*2,
@@ -1538,14 +1539,21 @@ hangaround(Cleaner, Type) ->
spawn_initial_hangarounds(_Cleaner, NP, Max, Len, HAs) when NP > Max ->
{Len, HAs};
spawn_initial_hangarounds(Cleaner, NP, Max, Len, HAs) ->
- erts_debug:set_internal_state(next_pid,NP),
+ Skip = 30,
HA1 = spawn_opt(?MODULE, hangaround, [Cleaner, initial_hangaround],
[{priority, low}]),
HA2 = spawn_opt(?MODULE, hangaround, [Cleaner, initial_hangaround],
[{priority, normal}]),
HA3 = spawn_opt(?MODULE, hangaround, [Cleaner, initial_hangaround],
[{priority, high}]),
- spawn_initial_hangarounds(Cleaner, NP+30, Max, Len+3, [HA1,HA2,HA3|HAs]).
+ spawn_drop(Skip),
+ spawn_initial_hangarounds(Cleaner, NP+Skip, Max, Len+3, [HA1,HA2,HA3|HAs]).
+
+spawn_drop(N) when N =< 0 ->
+ ok;
+spawn_drop(N) ->
+ spawn(fun () -> ok end),
+ spawn_drop(N-1).
do_processes(WantReds) ->
erts_debug:set_internal_state(reds_left, WantReds),
diff --git a/erts/etc/unix/cerl.src b/erts/etc/unix/cerl.src
index f99059cb72..691b32e143 100644
--- a/erts/etc/unix/cerl.src
+++ b/erts/etc/unix/cerl.src
@@ -31,6 +31,8 @@
# -debug Run debug compiled emulator
# -gdb Run the debug compiled emulator in emacs and gdb.
# You have to start beam in gdb using "run".
+# -rgdb Run the debug compiled emulator in gdb.
+# You have to start beam in gdb using "run".
# -break F Run the debug compiled emulator in emacs and gdb and set break.
# The session is started, i.e. "run" is already don for you.
# -xxgdb FIXME currently disabled
@@ -178,6 +180,10 @@ while [ $# -gt 0 ]; do
;;
"-gdb")
shift
+ GDB=egdb
+ ;;
+ "-rgdb")
+ shift
GDB=gdb
;;
"-break")
@@ -188,6 +194,12 @@ while [ $# -gt 0 ]; do
;;
"-core")
shift
+ GDB=egdb
+ core="$1"
+ shift
+ ;;
+ "-rcore")
+ shift
GDB=gdb
core="$1"
shift
@@ -285,6 +297,27 @@ if [ "x$GDB" = "x" ]; then
else
exec $EXEC $eeargs $xargs ${1+"$@"}
fi
+elif [ "x$GDB" = "xgdb" ]; then
+ case "x$core" in
+ x)
+ # Get emu args to use from erlexec...
+ beam_args=`$EXEC -emu_args_exit ${1+"$@"}`
+ gdbcmd="--args $EMU_NAME $beam_args"
+ ;;
+ x/*)
+ gdbcmd="$EMU_NAME ${core}"
+ GDBBP=
+ ;;
+ *)
+ dir=`pwd`
+ gdbcmd="$EMU_NAME ${dir}/${core}"
+ GDBBP=
+ ;;
+ esac
+ cmdfile="/tmp/.cerlgdb.$$"
+ echo "source $ROOTDIR/erts/etc/unix/etp-commands" > $cmdfile
+ # Fire up gdb in emacs...
+ exec gdb $GDBBP -x $cmdfile $gdbcmd
else
if [ "x$EMACS" = "x" ]; then
EMACS=emacs
diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index 308cb99be5..315f9ebd47 100644
--- a/erts/preloaded/ebin/erlang.beam
+++ b/erts/preloaded/ebin/erlang.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_eval.beam b/erts/preloaded/ebin/prim_eval.beam
new file mode 100644
index 0000000000..6c7b7e5262
--- /dev/null
+++ b/erts/preloaded/ebin/prim_eval.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index 43cbc17dbf..a0a4314128 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/src/.gitignore b/erts/preloaded/src/.gitignore
new file mode 100644
index 0000000000..e4658fe142
--- /dev/null
+++ b/erts/preloaded/src/.gitignore
@@ -0,0 +1 @@
+prim_eval.abstr
diff --git a/erts/preloaded/src/Makefile b/erts/preloaded/src/Makefile
index a224b6a5d4..f53809e765 100644
--- a/erts/preloaded/src/Makefile
+++ b/erts/preloaded/src/Makefile
@@ -32,7 +32,7 @@ STATIC_EBIN=../ebin
include $(ERL_TOP)/erts/vsn.mk
include $(ERL_TOP)/lib/kernel/vsn.mk
-PRE_LOADED_MODULES = \
+PRE_LOADED_ERL_MODULES = \
erl_prim_loader \
init \
prim_file \
@@ -43,10 +43,17 @@ PRE_LOADED_MODULES = \
erlang \
erts_internal
+PRE_LOADED_BEAM_MODULES = \
+ prim_eval
+
+PRE_LOADED_MODULES = $(PRE_LOADED_ERL_MODULES) $(PRE_LOADED_BEAM_MODULES)
+
RELSYSDIR = $(RELEASE_PATH)/lib/erts-$(VSN)
# not $(RELEASE_PATH)/erts-$(VSN)/preloaded
-ERL_FILES= $(PRE_LOADED_MODULES:%=%.erl)
+ERL_FILES= $(PRE_LOADED_ERL_MODULES:%=%.erl)
+BEAM_FILES= $(PRE_LOADED_BEAM_MODULES:%=%.S)
+STUBS_FILES= $(PRE_LOADED_BEAM_MODULES:%=%.erl)
TARGET_FILES = $(PRE_LOADED_MODULES:%=$(EBIN)/%.$(EMULATOR))
STATIC_TARGET_FILES = $(PRE_LOADED_MODULES:%=$(STATIC_EBIN)/%.$(EMULATOR))
@@ -70,7 +77,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec:
$(INSTALL_DIR) "$(RELSYSDIR)/src"
- $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)/src"
+ $(INSTALL_DATA) $(ERL_FILES) $(BEAM_FILES) $(STUBS_FILES) "$(RELSYSDIR)/src"
$(INSTALL_DIR) "$(RELSYSDIR)/ebin"
$(INSTALL_DATA) $(STATIC_TARGET_FILES) "$(RELSYSDIR)/ebin"
@@ -80,6 +87,19 @@ release_docs_spec:
list_preloaded:
@echo $(PRE_LOADED_MODULES)
+#
+# Combine a BEAM assembly script file a stub Erlang file into a BEAM file.
+# See add_abstract_chunk script.
+#
+
+prim_eval.abstr: prim_eval.erl
+ $(V_ERLC) $(ERL_COMPILE_FLAGS) -o$(dir $@) +dabstr $<
+
+prim_eval.beam: prim_eval.S prim_eval.abstr
+ $(gen_verbose)
+ $(V_at)$(ERLC) $(ERL_COMPILE_FLAGS) $<
+ $(V_at)escript add_abstract_code $@ prim_eval.abstr || (rm $@; exit 1)
+
# Include dependencies -- list below added by PaN
$(EBIN)/erl_prim_loader.beam: $(KERNEL_SRC)/inet_boot.hrl $(KERNEL_INCLUDE)/file.hrl
$(EBIN)/prim_file.beam: $(KERNEL_INCLUDE)/file.hrl
diff --git a/erts/preloaded/src/add_abstract_code b/erts/preloaded/src/add_abstract_code
new file mode 100644
index 0000000000..e670156d21
--- /dev/null
+++ b/erts/preloaded/src/add_abstract_code
@@ -0,0 +1,34 @@
+#!/usr/bin/env escript
+%% -*- erlang -*-
+
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-mode(compile).
+
+-export([main/1]).
+
+main([BeamFile,AbstrFile]) ->
+ {ok,_,Chunks0} = beam_lib:all_chunks(BeamFile),
+ {ok,Abstr} = file:consult(AbstrFile),
+ Chunks = lists:keyreplace("Abst", 1, Chunks0,
+ {"Abst",term_to_binary({raw_abstract_v1,Abstr})}),
+ {ok,Module} = beam_lib:build_module(Chunks),
+ ok = file:write_file(BeamFile, Module),
+ init:stop().
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index 7106c0a4fb..6929ca3fa5 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -45,7 +45,8 @@
-export([alloc_info/1, alloc_sizes/1]).
-export([gather_sched_wall_time_result/1,
- await_sched_wall_time_modifications/2]).
+ await_sched_wall_time_modifications/2,
+ gather_gc_info_result/1]).
-deprecated([hash/2]).
@@ -3536,3 +3537,20 @@ sched_wall_time(Ref, N, Acc) ->
{Ref, undefined} -> sched_wall_time(Ref, N-1, undefined);
{Ref, SWT} -> sched_wall_time(Ref, N-1, [SWT|Acc])
end.
+
+-spec erlang:gather_gc_info_result(Ref) -> [{pos_integer(),
+ pos_integer(),
+ 0}] when
+ Ref :: reference().
+
+gather_gc_info_result(Ref) when erlang:is_reference(Ref) ->
+ gc_info(Ref, erlang:system_info(schedulers), {0,0}).
+
+gc_info(_Ref, 0, {Colls,Recl}) ->
+ {Colls,Recl,0};
+gc_info(Ref, N, {OrigColls,OrigRecl}) ->
+ receive
+ {Ref, {_,Colls, Recl}} ->
+ gc_info(Ref, N-1, {Colls+OrigColls,Recl+OrigRecl})
+ end.
+
diff --git a/erts/preloaded/src/prim_eval.S b/erts/preloaded/src/prim_eval.S
new file mode 100644
index 0000000000..958a79a1da
--- /dev/null
+++ b/erts/preloaded/src/prim_eval.S
@@ -0,0 +1,70 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+{module, prim_eval}.
+
+%% This module uses low-level BEAM instructions for the message queue facility
+%% to allow erl_eval to evaluate receive expressions correctly.
+
+{exports, [{'receive',2},{module_info,0},{module_info,1}]}.
+
+{attributes, []}.
+
+{labels, 10}.
+
+
+{function, 'receive', 2, 2}.
+ {label,1}.
+ {func_info,{atom,prim_eval},{atom,'receive'},2}.
+ {label,2}.
+ {allocate,2,2}.
+ {move,{x,1},{y,0}}.
+ {move,{x,0},{y,1}}.
+ {label,3}.
+ {loop_rec,{f,5},{x,0}}.
+ {move,{y,1},{x,1}}.
+ {call_fun,1}.
+ {test,is_ne_exact,{f,4},[{x,0},{atom,nomatch}]}.
+ remove_message.
+ {deallocate,2}.
+ return.
+ {label,4}.
+ {loop_rec_end,{f,3}}.
+ {label,5}.
+ {wait_timeout,{f,3},{y,0}}.
+ timeout.
+ {move,{atom,timeout},{x,0}}.
+ {deallocate,2}.
+ return.
+
+
+{function, module_info, 0, 8}.
+ {label,6}.
+ {func_info,{atom,prim_eval},{atom,module_info},0}.
+ {label,7}.
+ {move,{atom,prim_eval},{x,0}}.
+ {call_ext_only,1,{extfunc,erlang,get_module_info,1}}.
+
+
+{function, module_info, 1, 10}.
+ {label,8}.
+ {func_info,{atom,prim_eval},{atom,module_info},1}.
+ {label,9}.
+ {move,{x,0},{x,1}}.
+ {move,{atom,prim_eval},{x,0}}.
+ {call_ext_only,2,{extfunc,erlang,get_module_info,2}}.
diff --git a/erts/preloaded/src/prim_eval.erl b/erts/preloaded/src/prim_eval.erl
new file mode 100644
index 0000000000..ec5af8c138
--- /dev/null
+++ b/erts/preloaded/src/prim_eval.erl
@@ -0,0 +1,28 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(prim_eval).
+
+%% This module is simply a stub which abstract code gets included in the result
+%% of compilation of prim_eval.S, to keep Dialyzer happy.
+
+-export(['receive'/2]).
+
+-spec 'receive'(fun((term()) -> nomatch | T), timeout()) -> T.
+'receive'(_, _) ->
+ erlang:nif_error(stub).
diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl
index d0e70aa95c..36a650cb5c 100644
--- a/erts/preloaded/src/prim_inet.erl
+++ b/erts/preloaded/src/prim_inet.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -151,30 +151,35 @@ shutdown_pend_loop(S, N0) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
close(S) when is_port(S) ->
- unlink(S), %% avoid getting {'EXIT', S, Reason}
case subscribe(S, [subs_empty_out_q]) of
{ok, [{subs_empty_out_q,N}]} when N > 0 ->
close_pend_loop(S, N); %% wait for pending output to be sent
_ ->
- catch erlang:port_close(S),
- ok
+ close_port(S)
end.
close_pend_loop(S, N) ->
receive
{empty_out_q,S} ->
- catch erlang:port_close(S), ok
+ close_port(S)
after ?INET_CLOSE_TIMEOUT ->
case getstat(S, [send_pend]) of
{ok, [{send_pend,N1}]} ->
- if N1 =:= N -> catch erlang:port_close(S), ok;
- true -> close_pend_loop(S, N1)
+ if
+ N1 =:= N ->
+ close_port(S);
+ true ->
+ close_pend_loop(S, N1)
end;
_ ->
- catch erlang:port_close(S), ok
+ close_port(S)
end
end.
-
+
+close_port(S) ->
+ catch erlang:port_close(S),
+ receive {'EXIT',S,_} -> ok after 0 -> ok end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% BIND(insock(), IP, Port) -> {ok, integer()} | {error, Reason}
diff --git a/lib/asn1/src/Makefile b/lib/asn1/src/Makefile
index 9607799401..33cd3cc4c3 100644
--- a/lib/asn1/src/Makefile
+++ b/lib/asn1/src/Makefile
@@ -134,10 +134,10 @@ $(EBIN)/asn1ct.$(EMULATOR):asn1ct.erl
$(V_ERLC) -b$(EMULATOR) -o$(EBIN) $(ERL_COMPILE_FLAGS) -Dvsn=\"$(VSN)\" $<
$(EBIN)/asn1ct_func.$(EMULATOR): asn1ct_func.erl
- $(ERLC) -o$(EBIN) $(ERL_COMPILE_FLAGS) -I../rt_templates $<
+ $(V_ERLC) -o$(EBIN) $(ERL_COMPILE_FLAGS) -I../rt_templates $<
asn1ct_eval_%.erl: asn1ct_eval_%.funcs
- erl -pa $(EBIN) -noshell -noinput \
+ $(gen_verbose)erl -pa $(EBIN) -noshell -noinput \
-run prepare_templates gen_asn1ct_eval $< >$@
$(APP_TARGET): $(APP_SRC) ../vsn.mk
@@ -182,14 +182,14 @@ RT_TEMPLATES_ERL = $(RT_TEMPLATES:%=%.erl)
RT_TEMPLATES_TARGET = $(RT_TEMPLATES:%=%.$(EMULATOR))
asn1ct_rtt.erl: prepare_templates.$(EMULATOR) $(RT_TEMPLATES_TARGET)
- erl -noshell -noinput -run prepare_templates gen_asn1ct_rtt \
+ $(gen_verbose)erl -noshell -noinput -run prepare_templates gen_asn1ct_rtt \
$(RT_TEMPLATES_TARGET) >asn1ct_rtt.erl
prepare_templates.$(EMULATOR): prepare_templates.erl
- erlc prepare_templates.erl
+ $(V_ERLC) prepare_templates.erl
asn1rtt_%.$(EMULATOR): asn1rtt_%.erl
- erlc +debug_info $<
+ $(V_ERLC) +debug_info $<
$(EVAL_CT_MODULES:%=%.erl): prepare_templates.$(EMULATOR) \
$(EBIN)/asn1ct_rtt.$(EMULATOR)
diff --git a/lib/asn1/src/asn1_db.erl b/lib/asn1/src/asn1_db.erl
index 843fc66c9c..e96ca9ae25 100644
--- a/lib/asn1/src/asn1_db.erl
+++ b/lib/asn1/src/asn1_db.erl
@@ -19,31 +19,22 @@
%%
-module(asn1_db).
--export([dbstart/1,dbnew/1,dbsave/2,dbload/1,dbput/3,dbget/2,dbget_all/1]).
--export([dbget_all_mod/1,dbclear/0,dberase_module/1,dbstop/0]).
+-export([dbstart/1,dbnew/1,dbsave/2,dbput/3,dbget/2]).
+-export([dbstop/0]).
-record(state, {parent, monitor, includes, table}).
%% Interface
dbstart(Includes) ->
Parent = self(),
- case get(?MODULE) of
- undefined ->
- put(?MODULE, spawn_link(fun() -> init(Parent, Includes) end)),
- true;
- _Pid ->
- req({new_includes, Includes})
- end.
+ undefined = get(?MODULE), %Assertion.
+ put(?MODULE, spawn_link(fun() -> init(Parent, Includes) end)),
+ ok.
dbnew(Module) -> req({new, Module}).
-dbsave(OutFile, Module) -> req({save, OutFile, Module}).
-dbload(Module) -> req({load, Module}).
-dbput(Module, K, V) -> req({set, Module, K, V}).
+dbsave(OutFile, Module) -> cast({save, OutFile, Module}).
+dbput(Module, K, V) -> cast({set, Module, K, V}).
dbget(Module, K) -> req({get, Module, K}).
-dbget_all(K) -> req({get_all, K}).
-dbget_all_mod(Mod) -> req({all_mod, Mod}).
-dbclear() -> req(clear).
-dberase_module({module,M}) -> req({delete_mod, M}).
dbstop() -> Resp = req(stop), erase(?MODULE), Resp.
%% Internal functions
@@ -59,8 +50,13 @@ req(Request) ->
exit({db_error,Info})
end.
+cast(Request) ->
+ get(?MODULE) ! Request,
+ ok.
+
reply({Ref,From}, Response) ->
- From ! {{Ref,?MODULE}, Response}.
+ From ! {{Ref,?MODULE}, Response},
+ ok.
init(Parent, Includes) ->
MRef = erlang:monitor(process, Parent),
@@ -70,10 +66,9 @@ init(Parent, Includes) ->
loop(#state{parent = Parent, monitor = MRef, table = Table,
includes = Includes} = State) ->
receive
- {From, {set, Mod, K2, V}} ->
+ {set, Mod, K2, V} ->
[{_, Modtab}] = ets:lookup(Table, Mod),
ets:insert(Modtab, {K2, V}),
- reply(From, ok),
loop(State);
{From, {get, Mod, K2}} ->
Result = case ets:lookup(Table, Mod) of
@@ -85,44 +80,16 @@ loop(#state{parent = Parent, monitor = MRef, table = Table,
_Error -> reply(From, undefined)
end,
loop(State);
- {From, {all_mod, Mod}} ->
- [{_, Modtab}] = ets:lookup(Table, Mod),
- reply(From, ets:tab2list(Modtab)),
- loop(State);
- {From, {delete_mod, Mod}} ->
- [{_, Modtab}] = ets:lookup(Table, Mod),
- ets:delete(Modtab),
- ets:delete(Table, Mod),
- reply(From, ok),
- loop(State);
- {From, {save, OutFile, Mod}} ->
+ {save, OutFile, Mod} ->
[{_,Mtab}] = ets:lookup(Table, Mod),
- reply(From, ets:tab2file(Mtab, OutFile)),
- loop(State);
- {From, {load, Mod}} ->
- Result = case ets:lookup(Table, Mod) of
- [] -> opentab(Table, Mod, Includes);
- [{_, Modtab}] -> {ok, Modtab}
- end,
- reply(From, Result),
+ ok = ets:tab2file(Mtab, OutFile),
loop(State);
{From, {new, Mod}} ->
- case ets:lookup(Table, Mod) of
- [{_, Modtab}] -> ets:delete(Modtab);
- _ -> true
- end,
+ [] = ets:lookup(Table, Mod), %Assertion.
ModTableId = ets:new(list_to_atom(lists:concat(["asn1_",Mod])), []),
ets:insert(Table, {Mod, ModTableId}),
reply(From, ok),
loop(State);
- {From, clear} ->
- [ets:delete(Mt) || {_, Mt} <- ets:tab2list(Table)],
- ets:delete(Table),
- reply(From, cleared),
- loop(State#state{table = ets:new(asn1, [set])});
- {From, {new_includes, NewIncludes}} ->
- reply(From, true),
- loop(State#state{includes = NewIncludes});
{From, stop} ->
reply(From, stopped); %% Nothing to store
{'DOWN', MRef, process, Parent, Reason} ->
diff --git a/lib/asn1/src/asn1_records.hrl b/lib/asn1/src/asn1_records.hrl
index 16d14c2e7b..396ba0fcfa 100644
--- a/lib/asn1/src/asn1_records.hrl
+++ b/lib/asn1/src/asn1_records.hrl
@@ -45,9 +45,7 @@
-record(pobjectdef,{checked=false,pos,name,args,class,def}).
-record(pobjectsetdef,{checked=false,pos,name,args,class,def}).
--record(typereference,{pos,val}).
-record(identifier,{pos,val}).
--record(constraint,{c,e}).
-record('Constraint',{'SingleValue'=no,'SizeConstraint'=no,'ValueRange'=no,'PermittedAlphabet'=no,
'ContainedSubtype'=no, 'TypeConstraint'=no,'InnerSubtyping'=no,e=no,'Other'=no}).
-record(simpletableattributes,{objectsetname,c_name,c_index,usedclassfield,
diff --git a/lib/asn1/src/asn1ct.erl b/lib/asn1/src/asn1ct.erl
index 770b92cbc3..8e71a5697c 100644
--- a/lib/asn1/src/asn1ct.erl
+++ b/lib/asn1/src/asn1ct.erl
@@ -25,21 +25,20 @@
%%-compile(export_all).
%% Public exports
-export([compile/1, compile/2]).
--export([start/0, start/1]).
-export([encode/2, encode/3, decode/3]).
-export([test/1, test/2, test/3, value/2, value/3]).
%% Application internal exports
-export([compile_asn/3,compile_asn1/3,compile_py/3,compile/3,
vsn/0,
get_name_of_def/1,get_pos_of_def/1]).
--export([read_config_data/1,get_gen_state_field/1,get_gen_state/0,
- partial_inc_dec_toptype/1,save_gen_state/1,update_gen_state/2,
+-export([read_config_data/1,get_gen_state_field/1,
+ partial_inc_dec_toptype/1,update_gen_state/2,
get_tobe_refed_func/1,reset_gen_state/0,is_function_generated/1,
- generated_refed_func/1,next_refed_func/0,pop_namelist/0,
- next_namelist_el/0,update_namelist/1,step_in_constructed/0,
+ generated_refed_func/1,next_refed_func/0,
+ update_namelist/1,step_in_constructed/0,
add_tobe_refed_func/1,add_generated_refed_func/1,
- maybe_rename_function/3,latest_sindex/0,current_sindex/0,
- set_current_sindex/1,next_sindex/0,maybe_saved_sindex/2,
+ maybe_rename_function/3,current_sindex/0,
+ set_current_sindex/1,maybe_saved_sindex/2,
parse_and_save/2,verbose/3,warning/3,warning/4,error/3]).
-export([get_bit_string_format/0]).
@@ -82,7 +81,6 @@
%%
%%
-
compile(File) ->
compile(File,[]).
@@ -96,14 +94,30 @@ compile(File, Options0) when is_list(Options0) ->
Error
end.
+-record(st,
+ {file=[],
+ files=[],
+ inputmodules=[],
+ code,
+ opts=[],
+ outfile,
+ dbfile,
+ includes=[],
+ erule,
+ error=none,
+ run
+ }).
+
compile_proc(File, Includes, Options) ->
+ Erule = get_rule(Options),
+ St = #st{opts=Options,includes=Includes,erule=Erule},
case input_file_type(File, Includes) of
{single_file, SuffixedFile} -> %% "e.g. "/tmp/File.asn"
- compile1(SuffixedFile, Options);
+ compile1(SuffixedFile, St);
{multiple_files_file, SetBase, FileName} ->
case get_file_list(FileName, Includes) of
FileList when is_list(FileList) ->
- compile_set(SetBase, FileList, Options);
+ compile_set(SetBase, FileList, St);
Err ->
Err
end;
@@ -111,22 +125,222 @@ compile_proc(File, Includes, Options) ->
{error, Err}
end.
-compile1(File,Options) when is_list(Options) ->
- verbose("Erlang ASN.1 version ~p compiling ~p ~n",[?vsn,File],Options),
- verbose("Compiler Options: ~p~n",[Options],Options),
- Ext = filename:extension(File),
- Base = filename:basename(File,Ext),
- OutFile = outfile(Base,"",Options),
- DbFile = outfile(Base,"asn1db",Options),
- Includes = [I || {i,I} <- Options],
- EncodingRule = get_rule(Options),
- Continue1 = scan(File,Options),
- Continue2 = parse(Continue1,File,Options),
- Continue3 = check(Continue2,File,OutFile,Includes,EncodingRule,
- DbFile,Options,[]),
- Continue4 = generate(Continue3,OutFile,EncodingRule,Options),
- compile_erl(Continue4, OutFile, Options).
+set_passes() ->
+ [{pass,scan_parse,fun set_scan_parse_pass/1},
+ {pass,merge,fun merge_pass/1}|common_passes()].
+
+single_passes() ->
+ [{pass,scan,fun scan_pass/1},
+ {pass,parse,fun parse_pass/1}|common_passes()].
+
+parse_and_save_passes() ->
+ [{pass,scan,fun scan_pass/1},
+ {pass,parse,fun parse_pass/1},
+ {pass,save,fun save_pass/1}].
+
+common_passes() ->
+ [{pass,check,fun check_pass/1},
+ {iff,abs,{pass,abs_listing,fun abs_listing/1}},
+ {pass,generate,fun generate_pass/1},
+ {unless,noobj,{pass,compile,fun compile_pass/1}}].
+
+scan_pass(#st{file=File}=St) ->
+ case asn1ct_tok:file(File) of
+ {error,Reason} ->
+ {error,St#st{error=Reason}};
+ Tokens when is_list(Tokens) ->
+ {ok,St#st{code=Tokens}}
+ end.
+
+set_scan_parse_pass(#st{files=Files}=St) ->
+ try
+ L = set_scan_parse_pass_1(Files, St),
+ {ok,St#st{code=L}}
+ catch
+ throw:Error ->
+ {error,St#st{error=Error}}
+ end.
+
+set_scan_parse_pass_1([F|Fs], St) ->
+ case asn1ct_tok:file(F) of
+ {error,Error} ->
+ throw(Error);
+ Tokens when is_list(Tokens) ->
+ case catch asn1ct_parser2:parse(Tokens) of
+ {ok,M} ->
+ [M|set_scan_parse_pass_1(Fs, St)];
+ {error,ErrorTerm} ->
+ throw(handle_parse_error(ErrorTerm, St))
+ end
+ end;
+set_scan_parse_pass_1([], _) -> [].
+
+parse_pass(#st{code=Tokens}=St) ->
+ case catch asn1ct_parser2:parse(Tokens) of
+ {ok,M} ->
+ {ok,St#st{code=M}};
+ {error,ErrorTerm} ->
+ {error,St#st{error=handle_parse_error(ErrorTerm, St)}}
+ end.
+
+handle_parse_error(ErrorTerm, #st{file=File,opts=Opts}) ->
+ case ErrorTerm of
+ {{Line,_Mod,Message},_TokTup} ->
+ if
+ is_integer(Line) ->
+ BaseName = filename:basename(File),
+ error("syntax error at line ~p in module ~s:~n",
+ [Line,BaseName], Opts);
+ true ->
+ error("syntax error in module ~p:~n",
+ [File], Opts)
+ end,
+ print_error_message(Message),
+ Message;
+ {Line,_Mod,[Message,Token]} ->
+ error("syntax error: ~p ~p at line ~p~n",
+ [Message,Token,Line], Opts),
+ {Line,[Message,Token]}
+ end.
+
+merge_pass(#st{file=Base,code=Code}=St) ->
+ M = merge_modules(Code, Base),
+ {ok,St#st{code=M}}.
+
+check_pass(#st{code=M,file=File,includes=Includes,
+ erule=Erule,dbfile=DbFile,opts=Opts,
+ inputmodules=InputModules}=St) ->
+ start(Includes),
+ case asn1ct_check:storeindb(#state{erule=Erule}, M) of
+ ok ->
+ Module = asn1_db:dbget(M#module.name, 'MODULE'),
+ State = #state{mname=Module#module.name,
+ module=Module#module{typeorval=[]},
+ erule=Erule,
+ inputmodules=InputModules,
+ options=Opts,
+ sourcedir=filename:dirname(File)},
+ case asn1ct_check:check(State, Module#module.typeorval) of
+ {error,Reason} ->
+ {error,St#st{error=Reason}};
+ {ok,NewTypeOrVal,GenTypeOrVal} ->
+ NewM = Module#module{typeorval=NewTypeOrVal},
+ asn1_db:dbput(NewM#module.name, 'MODULE', NewM),
+ asn1_db:dbsave(DbFile, M#module.name),
+ verbose("--~p--~n", [{generated,DbFile}], Opts),
+ {ok,St#st{code={M,GenTypeOrVal}}}
+ end;
+ {error,Reason} ->
+ {error,St#st{error=Reason}}
+ end.
+
+save_pass(#st{code=M,erule=Erule,dbfile=DbFile}=St) ->
+ ok = asn1ct_check:storeindb(#state{erule=Erule}, M),
+ asn1_db:dbsave(DbFile,M#module.name),
+ {ok,St}.
+
+abs_listing(#st{code={M,_},outfile=OutFile}) ->
+ pretty2(M#module.name, OutFile++".abs"),
+ done.
+generate_pass(#st{code=Code,outfile=OutFile,erule=Erule,opts=Opts}=St0) ->
+ St = St0#st{code=undefined}, %Reclaim heap space
+ case generate(Code, OutFile, Erule, Opts) of
+ {error,Reason} ->
+ {error,St#st{error=Reason}};
+ ok ->
+ {ok,St}
+ end.
+
+compile_pass(#st{outfile=OutFile,opts=Opts0}=St) ->
+ asn1_db:dbstop(), %Reclaim memory.
+ asn1ct_table:delete([renamed_defs,original_imports,automatic_tags]),
+ Opts = remove_asn_flags(Opts0),
+ case c:c(OutFile, Opts) of
+ {ok,_Module} ->
+ {ok,St};
+ _ ->
+ {error,St}
+ end.
+
+run_passes(Passes, #st{opts=Opts}=St) ->
+ Run = case lists:member(time, Opts) of
+ false ->
+ fun(_, Pass, S) -> Pass(S) end;
+ true ->
+ fun run_tc/3
+ end,
+ run_passes_1(Passes, St#st{run=Run}).
+
+run_tc(Name, Fun, St) ->
+ Before0 = statistics(runtime),
+ Val = (catch Fun(St)),
+ After0 = statistics(runtime),
+ {Before_c, _} = Before0,
+ {After_c, _} = After0,
+ io:format("~-31s: ~10.2f s\n",
+ [Name,(After_c-Before_c) / 1000]),
+ Val.
+
+run_passes_1([{unless,Opt,Pass}|Passes], #st{opts=Opts}=St) ->
+ case proplists:get_bool(Opt, Opts) of
+ false ->
+ run_passes_1([Pass|Passes], St);
+ true ->
+ run_passes_1(Passes, St)
+ end;
+run_passes_1([{iff,Opt,Pass}|Passes], #st{opts=Opts}=St) ->
+ case proplists:get_bool(Opt, Opts) of
+ true ->
+ run_passes_1([Pass|Passes], St);
+ false ->
+ run_passes_1(Passes, St)
+ end;
+run_passes_1([{pass,Name,Pass}|Passes], #st{run=Run}=St0)
+ when is_function(Pass, 1) ->
+ try Run(Name, Pass, St0) of
+ {ok,St} ->
+ run_passes_1(Passes, St);
+ {error,#st{error=Errors}} ->
+ {Structured,AllErrors} = clean_errors(Errors),
+ print_structured_errors(Structured),
+ {error,AllErrors};
+ done ->
+ ok
+ catch
+ Class:Error ->
+ Stk = erlang:get_stacktrace(),
+ io:format("Internal error: ~p:~p\n~p\n",
+ [Class,Error,Stk]),
+ {error,{internal_error,{Class,Error}}}
+ end;
+run_passes_1([], _St) ->
+ ok.
+
+clean_errors(Errors) when is_list(Errors) ->
+ F = fun({structured_error,_,_,_}) -> true;
+ (_) -> false
+ end,
+ {Structured0,AdHoc} = lists:partition(F, Errors),
+ Structured = lists:sort(Structured0),
+ {Structured,Structured ++ AdHoc};
+clean_errors(AdHoc) -> {[],AdHoc}.
+
+print_structured_errors([_|_]=Errors) ->
+ _ = [io:format("~ts:~w: ~ts\n", [F,L,M:format_error(E)]) ||
+ {structured_error,{F,L},M,E} <- Errors],
+ ok;
+print_structured_errors(_) -> ok.
+
+compile1(File, #st{opts=Opts}=St0) ->
+ verbose("Erlang ASN.1 version ~p, compiling ~p~n", [?vsn,File], Opts),
+ verbose("Compiler Options: ~p~n", [Opts], Opts),
+ Passes = single_passes(),
+ Base = filename:rootname(filename:basename(File)),
+ OutFile = outfile(Base, "", Opts),
+ DbFile = outfile(Base, "asn1db", Opts),
+ St1 = St0#st{file=File,outfile=OutFile,dbfile=DbFile},
+ run_passes(Passes, St1).
%%****************************************************************************%%
%% functions dealing with compiling of several input files to one output file %%
@@ -134,53 +348,20 @@ compile1(File,Options) when is_list(Options) ->
%% compile_set/3 merges and compiles a number of asn1 modules
%% specified in a .set.asn file to one .erl file.
-compile_set(SetBase,Files,Options)
- when is_list(hd(Files)),is_list(Options) ->
- %% case when there are several input files in a list
- verbose("Erlang ASN.1 version ~p compiling ~p ~n",[?vsn,Files],Options),
- verbose("Compiler Options: ~p~n",[Options],Options),
- OutFile = outfile(SetBase,"",Options),
- DbFile = outfile(SetBase,"asn1db",Options),
- Includes = [I || {i,I} <- Options],
- EncodingRule = get_rule(Options),
- ScanRes = scan_set(Files,Options),
- ParseRes = parse_set(ScanRes,Options),
- Result =
- case [X||X <- ParseRes,element(1,X)==true] of
- [] -> %% all were false, time to quit
- lists:map(fun(X)->element(2,X) end,ParseRes);
- ParseRes -> %% all were true, continue with check
- InputModules =
- lists:map(
- fun(F)->
- E = filename:extension(F),
- B = filename:basename(F,E),
- if
- is_list(B) -> list_to_atom(B);
- true -> B
- end
- end,
- Files),
- check_set(ParseRes,SetBase,OutFile,Includes,
- EncodingRule,DbFile,Options,InputModules);
- Other ->
- {error,{'unexpected error in scan/parse phase',
- lists:map(fun(X)->element(3,X) end,Other)}}
- end,
- Result.
-
-check_set(ParseRes,SetBase,OutFile,Includes,EncRule,DbFile,
- Options,InputModules) ->
-
- MergedModule = merge_modules(ParseRes,SetBase),
- SetM = MergedModule#module{name=SetBase},
- Continue1 = check({true,SetM},SetBase,OutFile,Includes,EncRule,DbFile,
- Options,InputModules),
- Continue2 = generate(Continue1,OutFile,EncRule,Options),
-
- asn1ct_table:delete([renamed_defs, original_imports, automatic_tags]),
-
- compile_erl(Continue2, OutFile, Options).
+compile_set(SetBase, Files, #st{opts=Opts}=St0) ->
+ verbose("Erlang ASN.1 version ~p compiling ~p ~n", [?vsn,Files], Opts),
+ verbose("Compiler Options: ~p~n",[Opts], Opts),
+ OutFile = outfile(SetBase, "", Opts),
+ DbFile = outfile(SetBase, "asn1db", Opts),
+ InputModules = [begin
+ F1 = filename:basename(F0),
+ F = filename:rootname(F1),
+ list_to_atom(F)
+ end || F0 <- Files],
+ St = St0#st{file=SetBase,files=Files,outfile=OutFile,
+ dbfile=DbFile,inputmodules=InputModules},
+ Passes = set_passes(),
+ run_passes(Passes, St).
%% merge_modules/2 -> returns a module record where the typeorval lists are merged,
%% the exports lists are merged, the imports lists are merged when the
@@ -188,8 +369,7 @@ check_set(ParseRes,SetBase,OutFile,Includes,EncRule,DbFile,
%% field gets the shared value if all modules have same tagging scheme,
%% otherwise a tagging_error exception is thrown,
%% the extensiondefault ...(not handled yet).
-merge_modules(ParseRes,CommonName) ->
- ModuleList = lists:map(fun(X)->element(2,X) end,ParseRes),
+merge_modules(ModuleList, CommonName) ->
NewModuleList = remove_name_collisions(ModuleList),
case asn1ct_table:size(renamed_defs) of
0 -> asn1ct_table:delete(renamed_defs);
@@ -379,6 +559,8 @@ get_pos_of_def(#pobjectdef{pos=Pos}) ->
Pos;
get_pos_of_def(#pobjectsetdef{pos=Pos}) ->
Pos;
+get_pos_of_def(#'Externalvaluereference'{pos=Pos}) ->
+ Pos;
get_pos_of_def(_) ->
undefined.
@@ -651,123 +833,9 @@ delete_double_of_symbol1([],Acc) ->
Acc.
-scan_set(Files,Options) ->
- %% The files in Files already have their relative path and extension
- lists:map(
- fun(F)->
- case scan(F,Options) of
- {false,{error,Reason}} ->
- throw({error,{'scan error in file:',F,Reason}});
- {TrueOrFalse,Res} ->
- {TrueOrFalse,Res,F}
- end
- end,
- Files).
-
-parse_set(ScanRes,Options) ->
- lists:map(
- fun({TorF,Toks,F})->
- case parse({TorF,Toks},F,Options) of
- {false,{error,Reason}} ->
- throw({error,{'parse error in file:',F,Reason}});
- {TrueOrFalse,Res} ->
- {TrueOrFalse,Res,F}
- end
- end,
- ScanRes).
-
-
%%***********************************
-
-scan(File,Options) ->
- case asn1ct_tok:file(File) of
- {error,Reason} ->
- error("~p~n",[Reason],Options),
- {false,{error,Reason}};
- Tokens ->
- case lists:member(ss,Options) of
- true -> % we terminate after scan
- {false,Tokens};
- false -> % continue with next pass
- {true,Tokens}
- end
- end.
-
-
-parse({true,Tokens},File,Options) ->
- %Presult = asn1ct_parser2:parse(Tokens),
- %%case lists:member(p1,Options) of
- %% true ->
- %% asn1ct_parser:parse(Tokens);
- %% _ ->
- %% asn1ct_parser2:parse(Tokens)
- %% end,
- case catch asn1ct_parser2:parse(Tokens) of
- {error,{{Line,_Mod,Message},_TokTup}} ->
- if
- is_integer(Line) ->
- BaseName = filename:basename(File),
- error("syntax error at line ~p in module ~s:~n",
- [Line,BaseName],Options);
- true ->
- error("syntax error in module ~p:~n",
- [File],Options)
- end,
- print_error_message(Message),
- {false,{error,Message}};
- {error,{Line,_Mod,[Message,Token]}} ->
- error("syntax error: ~p ~p at line ~p~n",
- [Message,Token,Line],Options),
- {false,{error,{Line,[Message,Token]}}};
- {ok,M} ->
- case lists:member(sp,Options) of
- true -> % terminate after parse
- {false,M};
- false -> % continue with next pass
- {true,M}
- end;
- OtherError ->
- error("~p~n",[OtherError],Options)
- end;
-parse({false,Tokens},_,_) ->
- {false,Tokens}.
-
-check({true,M},File,OutFile,Includes,EncodingRule,DbFile,Options,InputMods) ->
-
- start(Includes),
- case asn1ct_check:storeindb(#state{erule=EncodingRule},M) of
- ok ->
- Module = asn1_db:dbget(M#module.name,'MODULE'),
- State = #state{mname=Module#module.name,
- module=Module#module{typeorval=[]},
- erule=EncodingRule,
- inputmodules=InputMods,
- options=Options,
- sourcedir=filename:dirname(File)},
- Check = asn1ct_check:check(State,Module#module.typeorval),
- case {Check,lists:member(abs,Options)} of
- {{error,Reason},_} ->
- {false,{error,Reason}};
- {{ok,NewTypeOrVal,_},true} ->
- NewM = Module#module{typeorval=NewTypeOrVal},
- asn1_db:dbput(NewM#module.name,'MODULE',NewM),
- pretty2(M#module.name,lists:concat([OutFile,".abs"])),
- {false,ok};
- {{ok,NewTypeOrVal,GenTypeOrVal},_} ->
- NewM = Module#module{typeorval=NewTypeOrVal},
- asn1_db:dbput(NewM#module.name,'MODULE',NewM),
- asn1_db:dbsave(DbFile,M#module.name),
- verbose("--~p--~n",[{generated,DbFile}],Options),
- {true,{M,NewM,GenTypeOrVal}}
- end;
- ErrorList = {error,_} ->
- {false,ErrorList}
- end;
-check({false,M},_,_,_,_,_,_,_) ->
- {false,M}.
-
-generate({true,{M,_Module,GenTOrV}}, OutFile, EncodingRule, Options) ->
+generate({M,GenTOrV}, OutFile, EncodingRule, Options) ->
debug_on(Options),
setup_bit_string_format(Options),
put(encoding_options,Options),
@@ -796,19 +864,7 @@ generate({true,{M,_Module,GenTOrV}}, OutFile, EncodingRule, Options) ->
erase(tlv_format), % used in ber
erase(class_default_type),% used in ber
asn1ct_table:delete(check_functions),
- case Result of
- {error,_} ->
- {false,Result};
- ok ->
- case lists:member(sg,Options) of
- true -> % terminate here , with .erl file generated
- {false,true};
- false ->
- {true,true}
- end
- end;
-generate({false,M},_,_,_) ->
- {false,M}.
+ Result.
setup_bit_string_format(Opts) ->
Format = case {lists:member(compact_bit_string, Opts),
@@ -836,14 +892,13 @@ get_bit_string_format() ->
parse_and_save(Module,S) ->
Options = S#state.options,
SourceDir = S#state.sourcedir,
- Includes = [I || {i,I} <-Options],
-
- case get_input_file(Module,[SourceDir|Includes]) of
+ Includes = [I || {i,I} <- Options],
+ case get_input_file(Module, [SourceDir|Includes]) of
%% search for asn1 source
{file,SuffixedASN1source} ->
case dbfile_uptodate(SuffixedASN1source,Options) of
false ->
- parse_and_save1(S,SuffixedASN1source,Options,Includes);
+ parse_and_save1(S, SuffixedASN1source, Options);
_ -> ok
end;
Err ->
@@ -851,24 +906,14 @@ parse_and_save(Module,S) ->
[lists:concat([Module,".asn1db"])],Options),
{error,{asn1,input_file_error,Err}}
end.
-parse_and_save1(S,File,Options,Includes) ->
+
+parse_and_save1(#state{erule=Erule}, File, Options) ->
Ext = filename:extension(File),
- Base = filename:basename(File,Ext),
- DbFile = outfile(Base,"asn1db",Options),
- Continue1 = scan(File,Options),
- M =
- case parse(Continue1,File,Options) of
- {true,Mod} -> Mod;
- _ ->
-%% io:format("~p~nnow I die!!!!!!!!!!!~n",[File]),
- exit({error,{asn1,File,"no such file"}})
- end,
-% start(["."|Includes]),
- start(Includes),
- case asn1ct_check:storeindb(S,M) of
- ok ->
- asn1_db:dbsave(DbFile,M#module.name)
- end.
+ Base = filename:basename(File, Ext),
+ DbFile = outfile(Base, "asn1db", Options),
+ St = #st{file=File,dbfile=DbFile,erule=Erule},
+ Passes = parse_and_save_passes(),
+ run_passes(Passes, St).
get_input_file(Module,[]) ->
Module;
@@ -926,13 +971,6 @@ dbfile_uptodate(File,Options) ->
end.
-compile_erl({true,_},OutFile,Options) ->
- erl_compile(OutFile,Options);
-compile_erl({false,true},_,_) ->
- ok;
-compile_erl({false,Result},_,_) ->
- Result.
-
input_file_type(Name,I) ->
case input_file_type(Name) of
{error,_} -> input_file_type2(filename:basename(Name),I);
@@ -1064,22 +1102,6 @@ translate_options([H|T]) ->
[H|translate_options(T)];
translate_options([]) -> [].
-erl_compile(OutFile,Options) ->
-% io:format("Options:~n~p~n",[Options]),
- case lists:member(noobj,Options) of
- true ->
- ok;
- _ ->
- ErlOptions = remove_asn_flags(Options),
- %% io:format("~n~nc:c(~p,~p)~n~n",[OutFile,ErlOptions]),
- case c:c(OutFile,ErlOptions) of
- {ok,_Module} ->
- ok;
- _ ->
- {error,'no_compilation'}
- end
- end.
-
remove_asn_flags(Options) ->
[X || X <- Options,
X /= get_rule(Options),
@@ -1216,7 +1238,6 @@ make_erl_options(Opts) ->
lists:map(fun(Dir) -> {i, Dir} end, Includes)]++Specific.
pretty2(Module,AbsFile) ->
- start(),
{ok,F} = file:open(AbsFile,[write]),
M = asn1_db:dbget(Module,'MODULE'),
io:format(F,"%%%%%%%%%%%%%%%%%%% ~p %%%%%%%%%%%%%%%%%%%~n",[Module]),
@@ -1251,10 +1272,6 @@ pretty2(Module,AbsFile) ->
lists:foreach(fun(T)-> io:format(F,"~s.\n",
[asn1ct_pretty_format:term(asn1_db:dbget(Module,T))])
end,ObjectSets).
-start() ->
- Includes = ["."],
- start(Includes).
-
start(Includes) when is_list(Includes) ->
asn1_db:dbstart(Includes).
@@ -2097,52 +2114,6 @@ update_namelist(Name) ->
Other -> Other
end.
-pop_namelist() ->
- DeepTail = %% removes next element in order
- fun([[{_,A}]|T],_Fun) when is_atom(A) -> T;
- ([{_N,L}|T],_Fun) when is_list(L) -> [L|T];
- ([[]|T],Fun) -> Fun(T,Fun);
- ([L1|L2],Fun) when is_list(L1) ->
- case lists:flatten(L1) of
- [] -> Fun([L2],Fun);
- _ -> [Fun(L1,Fun)|L2]
- end;
- ([_H|T],_Fun) -> T
- end,
- {Pop,NewNL} =
- case get_gen_state_field(namelist) of
- [] -> {[],[]};
- L ->
- {next_namelist_el(L),
- DeepTail(L,DeepTail)}
- end,
- update_gen_state(namelist,NewNL),
- Pop.
-
-%% next_namelist_el fetches the next type/component name in turn in
-%% the namelist, without changing the namelist.
-next_namelist_el() ->
- case get_gen_state_field(namelist) of
- undefined -> undefined;
- L when is_list(L) -> next_namelist_el(L)
- end.
-
-next_namelist_el([]) ->
- [];
-next_namelist_el([L]) when is_list(L) ->
- next_namelist_el(L);
-next_namelist_el([H|_]) when is_atom(H) ->
- H;
-next_namelist_el([L|T]) when is_list(L) ->
- case next_namelist_el(L) of
- [] ->
- next_namelist_el([T]);
- R ->
- R
- end;
-next_namelist_el([H={_,A}|_]) when is_atom(A) ->
- H.
-
%% removes a bracket from the namelist
step_in_constructed() ->
case get_gen_state_field(namelist) of
@@ -2382,14 +2353,6 @@ maybe_saved_sindex(Name,Pattern) ->
end
end.
-next_sindex() ->
- SI = get_gen_state_field(suffix_index),
- update_gen_state(suffix_index,SI+1),
- SI+1.
-
-latest_sindex() ->
- get_gen_state_field(suffix_index).
-
current_sindex() ->
get_gen_state_field(current_suffix_index).
diff --git a/lib/asn1/src/asn1ct_check.erl b/lib/asn1/src/asn1ct_check.erl
index 0622998445..f94550b0a4 100644
--- a/lib/asn1/src/asn1ct_check.erl
+++ b/lib/asn1/src/asn1ct_check.erl
@@ -25,7 +25,7 @@
%-compile(export_all).
%% Avoid warning for local function error/1 clashing with autoimported BIF.
-compile({no_auto_import,[error/1]}).
--export([check/2,storeindb/2]).
+-export([check/2,storeindb/2,format_error/1]).
%-define(debug,1).
-include("asn1_records.hrl").
%%% The tag-number for universal types
@@ -73,7 +73,6 @@
end).
-record(newt,{type=unchanged,tag=unchanged,constraint=unchanged,inlined=no}). % used in check_type to update type and tag
--record(newv,{type=unchanged,value=unchanged}). % used in check_value to update type and value
check(S,{Types,Values,ParameterizedTypes,Classes,Objects,ObjectSets}) ->
%%Predicates used to filter errors
@@ -92,14 +91,14 @@ check(S,{Types,Values,ParameterizedTypes,Classes,Objects,ObjectSets}) ->
save_asn1db_uptodate(S,S#state.erule,S#state.mname),
put(top_module,S#state.mname),
- _Perror = checkp(S,ParameterizedTypes,[]), % must do this before the templates are used
+ _ = checkp(S, ParameterizedTypes), %must do this before the templates are used
%% table to save instances of parameterized objects,object sets
asn1ct_table:new(parameterized_objects),
asn1ct_table:new(inlined_objects),
- Terror = checkt(S,Types,[]),
+ Terror = checkt(S, Types),
?dbg("checkt finished with errors:~n~p~n~n",[Terror]),
%% get parameterized object sets sent to checkt/3
@@ -107,7 +106,7 @@ check(S,{Types,Values,ParameterizedTypes,Classes,Objects,ObjectSets}) ->
{PObjSetNames1,Terror2} = filter_errors(IsPObjSet,Terror),
- Verror = checkv(S,Values ++ ObjectSets,[]), %value sets may be parsed as object sets
+ Verror = checkv(S, Values ++ ObjectSets), %value sets may be parsed as object sets
?dbg("checkv finished with errors:~n~p~n~n",[Verror]),
%% get information object classes wrongly sent to checkt/3
%% and update Terror2
@@ -116,7 +115,7 @@ check(S,{Types,Values,ParameterizedTypes,Classes,Objects,ObjectSets}) ->
NewClasses = Classes++AddClasses,
- Cerror = checkc(S,NewClasses,[]),
+ Cerror = checkc(S, NewClasses),
?dbg("checkc finished with errors:~n~p~n~n",[Cerror]),
%% get object sets incorrectly sent to checkv/3
%% and update Verror
@@ -175,8 +174,9 @@ check(S,{Types,Values,ParameterizedTypes,Classes,Objects,ObjectSets}) ->
{NewTypes,NewValues,ParameterizedTypes,NewClasses,
lists:subtract(NewObjects,ExclO)++InlinedObjects,
lists:subtract(NewObjectSets,ExclOS)++ParObjectSetNames}};
- _ ->{error,{asn1,lists:flatten([Terror3,Verror5,Cerror,
- Oerror,Exporterror,ImportError])}}
+ _ ->
+ {error,lists:flatten([Terror3,Verror5,Cerror,
+ Oerror,Exporterror,ImportError])}
end.
context_switch_in_spec() ->
@@ -338,51 +338,40 @@ chained_import(S,ImpMod,DefMod,Name) ->
chained_import(S,OtherMod,DefMod,Name)
end
end.
-
-checkt(S,[Name|T],Acc) ->
- ?dbg("Checking type ~p~n",[Name]),
- Result =
- case asn1_db:dbget(S#state.mname,Name) of
- undefined ->
- error({type,{internal_error,'???'},S});
- Type when is_record(Type,typedef) ->
- NewS = S#state{type=Type,tname=Name},
- case catch(check_type(NewS,Type,Type#typedef.typespec)) of
- {error,Reason} ->
- error({type,Reason,NewS});
- {'EXIT',Reason} ->
- error({type,{internal_error,Reason},NewS});
- {asn1_class,_ClassDef} ->
- {asn1_class,Name};
- pobjectsetdef ->
- {pobjectsetdef,Name};
- pvalueset ->
- {pvalueset,Name};
- Ts ->
- case Type#typedef.checked of
- true -> % already checked and updated
- ok;
- _ ->
- NewTypeDef = Type#typedef{checked=true,typespec = Ts},
-
- asn1_db:dbput(NewS#state.mname,Name,NewTypeDef), % update the type
- ok
- end
- end
- end,
- case Result of
- ok ->
- checkt(S,T,Acc);
- _ ->
- checkt(S,T,[Result|Acc])
- end;
-checkt(S,[],Acc) ->
- case check_contextswitchingtypes(S,[]) of
- [] ->
- lists:reverse(Acc);
- L ->
- checkt(S,L,Acc)
+checkt(S0, Names) ->
+ Check = fun do_checkt/3,
+
+ %% NOTE: check_type/3 will store information in the process
+ %% dictionary if context switching types are encountered;
+ %% therefore we must force the evaluation order.
+ Types = check_fold(S0, Names, Check),
+ CtxtSwitch = check_contextswitchingtypes(S0, []),
+ check_fold(S0, lists:reverse(CtxtSwitch), Check) ++ Types.
+
+do_checkt(S, Name, #typedef{typespec=TypeSpec}=Type0) ->
+ NewS = S#state{type=Type0,tname=Name},
+ try check_type(NewS, Type0, TypeSpec) of
+ #type{}=Ts ->
+ case Type0#typedef.checked of
+ true -> %already checked and updated
+ ok;
+ _ ->
+ Type = Type0#typedef{checked=true,
+ typespec=Ts},
+ asn1_db:dbput(NewS#state.mname,
+ Name, Type),
+ ok
+ end
+ catch
+ {error,Reason} ->
+ error({type,Reason,NewS});
+ {asn1_class,_ClassDef} ->
+ {asn1_class,Name};
+ pobjectsetdef ->
+ {pobjectsetdef,Name};
+ pvalueset ->
+ {pvalueset,Name}
end.
check_contextswitchingtypes(S,Acc) ->
@@ -402,131 +391,86 @@ check_contextswitchingtypes(S,[{T,TName}|Ts],Acc) ->
check_contextswitchingtypes(_,[],Acc) ->
Acc.
-checkv(S,[Name|T],Acc) ->
- ?dbg("Checking valuedef ~p~n",[Name]),
- Result = case asn1_db:dbget(S#state.mname,Name) of
- undefined -> error({value,{internal_error,'???'},S});
- Value when is_record(Value,valuedef);
- is_record(Value,typedef); %Value set may be parsed as object set.
- is_record(Value,pvaluedef);
- is_record(Value,pvaluesetdef) ->
- NewS = S#state{value=Value},
- case catch(check_value(NewS,Value)) of
- {error,Reason} ->
- error({value,Reason,NewS});
- {'EXIT',Reason} ->
- error({value,{internal_error,Reason},NewS});
- {pobjectsetdef} ->
- {pobjectsetdef,Name};
- {objectsetdef} ->
- {objectsetdef,Name};
- {objectdef} ->
- %% this is an object, save as typedef
- #valuedef{checked=C,pos=Pos,name=N,type=Type,
- value=Def}=Value,
- ClassName = Type#type.def,
- NewSpec = #'Object'{classname=ClassName,
- def=Def},
- NewDef = #typedef{checked=C,pos=Pos,name=N,
- typespec=NewSpec},
- asn1_db:dbput(NewS#state.mname,Name,NewDef),
- {objectdef,Name};
- {valueset,VSet} ->
- Pos = asn1ct:get_pos_of_def(Value),
- CheckedVSDef = #typedef{checked=true,pos=Pos,
- name=Name,typespec=VSet},
- asn1_db:dbput(NewS#state.mname,Name,CheckedVSDef),
- {valueset,Name};
- V ->
- %% update the valuedef
- asn1_db:dbput(NewS#state.mname,Name,V),
- ok
- end
- end,
- case Result of
- ok ->
- checkv(S,T,Acc);
- _ ->
- checkv(S,T,[Result|Acc])
- end;
-checkv(_S,[],Acc) ->
- lists:reverse(Acc).
-
-
-checkp(S,[Name|T],Acc) ->
- %io:format("check_ptypedef:~p~n",[Name]),
- Result = case asn1_db:dbget(S#state.mname,Name) of
- undefined ->
- error({type,{internal_error,'???'},S});
- Type when is_record(Type,ptypedef) ->
- NewS = S#state{type=Type,tname=Name},
- case catch(check_ptype(NewS,Type,Type#ptypedef.typespec)) of
- {error,Reason} ->
- error({type,Reason,NewS});
- {'EXIT',Reason} ->
- error({type,{internal_error,Reason},NewS});
- {asn1_class,_ClassDef} ->
- {asn1_class,Name};
- {asn1_param_class,_} -> ok;
- Ts ->
- NewType = Type#ptypedef{checked=true,typespec = Ts},
- asn1_db:dbput(NewS#state.mname,Name,NewType), % update the type
- ok
- end
- end,
- case Result of
- ok ->
- checkp(S,T,Acc);
- _ ->
- checkp(S,T,[Result|Acc])
- end;
-checkp(_S,[],Acc) ->
- lists:reverse(Acc).
-
+checkv(S, Names) ->
+ check_fold(S, Names, fun do_checkv/3).
+
+do_checkv(S, Name, Value)
+ when is_record(Value, valuedef);
+ is_record(Value, typedef); %Value set may be parsed as object set.
+ is_record(Value, pvaluedef);
+ is_record(Value, pvaluesetdef) ->
+ NewS = S#state{value=Value},
+ try check_value(NewS, Value) of
+ {valueset,VSet} ->
+ Pos = asn1ct:get_pos_of_def(Value),
+ CheckedVSDef = #typedef{checked=true,pos=Pos,
+ name=Name,typespec=VSet},
+ asn1_db:dbput(NewS#state.mname, Name, CheckedVSDef),
+ {valueset,Name};
+ V ->
+ %% update the valuedef
+ asn1_db:dbput(NewS#state.mname, Name, V),
+ ok
+ catch
+ {error,Reason} ->
+ error({value,Reason,NewS});
+ {pobjectsetdef} ->
+ {pobjectsetdef,Name};
+ {objectsetdef} ->
+ {objectsetdef,Name};
+ {objectdef} ->
+ %% this is an object, save as typedef
+ #valuedef{checked=C,pos=Pos,name=N,type=Type,
+ value=Def} = Value,
+ ClassName = Type#type.def,
+ NewSpec = #'Object'{classname=ClassName,def=Def},
+ NewDef = #typedef{checked=C,pos=Pos,name=N,typespec=NewSpec},
+ asn1_db:dbput(NewS#state.mname, Name, NewDef),
+ {objectdef,Name}
+ end.
+%% Check parameterized types.
+checkp(S, Names) ->
+ check_fold(S, Names, fun do_checkp/3).
+do_checkp(S0, Name, #ptypedef{typespec=TypeSpec}=Type0) ->
+ S = S0#state{type=Type0,tname=Name},
+ try check_ptype(S, Type0, TypeSpec) of
+ #type{}=Ts ->
+ Type = Type0#ptypedef{checked=true,typespec=Ts},
+ asn1_db:dbput(S#state.mname, Name, Type),
+ ok
+ catch
+ {error,Reason} ->
+ error({type,Reason,S});
+ {asn1_class,_ClassDef} ->
+ {asn1_class,Name};
+ {asn1_param_class,_} ->
+ ok
+ end.
-checkc(S,[Name|Cs],Acc) ->
- Result =
- case asn1_db:dbget(S#state.mname,Name) of
- undefined ->
- error({class,{internal_error,'???'},S});
- Class ->
- ClassSpec = if
- is_record(Class,classdef) ->
-% Class#classdef.typespec;
- Class;
- is_record(Class,typedef) ->
- Class#typedef.typespec
- end,
- NewS = S#state{type=Class,tname=Name},
- case catch(check_class(NewS,ClassSpec)) of
- {error,Reason} ->
- error({class,Reason,NewS});
- {'EXIT',Reason} ->
- error({class,{internal_error,Reason},NewS});
- C ->
- %% update the classdef
- NewClass =
- if
- is_record(Class,classdef) ->
- Class#classdef{checked=true,typespec=C};
- is_record(Class,typedef) ->
- #classdef{checked=true,name=Name,typespec=C}
- end,
- asn1_db:dbput(NewS#state.mname,Name,NewClass),
- ok
- end
+%% Check class definitions.
+checkc(S, Names) ->
+ check_fold(S, Names, fun do_checkc/3).
+
+do_checkc(S0, Name, Class0) ->
+ {Class1,ClassSpec} =
+ case Class0 of
+ #classdef{} ->
+ {Class0,Class0};
+ #typedef{} ->
+ {#classdef{name=Name},Class0#typedef.typespec}
end,
- case Result of
- ok ->
- checkc(S,Cs,Acc);
- _ ->
- checkc(S,Cs,[Result|Acc])
- end;
-checkc(_S,[],Acc) ->
-%% include_default_class(S#state.mname),
- lists:reverse(Acc).
+ S = S0#state{type=Class0,tname=Name},
+ try check_class(S, ClassSpec) of
+ C ->
+ Class = Class1#classdef{checked=true,typespec=C},
+ asn1_db:dbput(S#state.mname, Name, Class),
+ ok
+ catch
+ {error,Reason} ->
+ error({class,Reason,S})
+ end.
checko(S,[Name|Os],Acc,ExclO,ExclOS) ->
?dbg("Checking object ~p~n",[Name]),
@@ -695,8 +639,7 @@ check_class_fields(S,[F|Fields],Acc) ->
Type2 = maybe_unchecked_OCFT(S,Type),
Cat =
case asn1ct_gen:type(asn1ct_gen:get_inner(Type2#type.def)) of
- Def when is_record(Def,typereference);
- is_record(Def,'Externaltypereference') ->
+ Def when is_record(Def,'Externaltypereference') ->
{_,D} = get_referenced_type(S,Def),
D;
{undefined,user} ->
@@ -876,14 +819,6 @@ check_object(S,
?dbg("check_object set: ~p~n",[ObjSet#'ObjectSet'.set]),
{_,ClassDef} = get_referenced_type(S,ClassRef),
NewClassRef = check_externaltypereference(S,ClassRef),
- %% XXXXXXXXXX
- case ObjSet of
- #'ObjectSet'{set={'Externaltypereference',undefined,'MSAccessProtocol',
- 'AllOperations'}} ->
- ok;
- _ ->
- ok
- end,
{UniqueFieldName,UniqueInfo} =
case (catch get_unique_fieldname(S,ClassDef)) of
{error,'__undefined_',_} ->
@@ -1233,8 +1168,7 @@ check_object_list(S,ClassRef,[ObjOrSet|Objs],Acc) ->
ObjSet when is_record(ObjSet,type) ->
ObjSetDef =
case ObjSet#type.def of
- Ref when is_record(Ref,typereference);
- is_record(Ref,'Externaltypereference') ->
+ Ref when is_record(Ref,'Externaltypereference') ->
{_,D} = get_referenced_type(S,ObjSet#type.def),
D;
Other ->
@@ -1826,10 +1760,6 @@ convert_to_defaultfield(S,ObjFieldName,[OFS|RestOFS],CField)->
T = check_type(S,#typedef{typespec=ObjFieldSetting},
ObjFieldSetting),
{#typedef{checked=true,name=Bif,typespec=T},RestSettings};
- _OCFT = #'ObjectClassFieldType'{} ->
- T=check_type(S,#typedef{typespec=ObjFieldSetting},ObjFieldSetting),
- %%io:format("OCFT=~p~n,T=~p~n",[OCFT,T]),
- {#typedef{checked=true,typespec=T},RestSettings};
_ ->
%this case should not happen any more
{Mod,T} =
@@ -2140,172 +2070,72 @@ check_value(S,#valuedef{pos=Pos,name=Name,type=Type,
NewType = Type#type{constraint=[Constr]},
{valueset,
check_type(S,#typedef{pos=Pos,name=Name,typespec=NewType},NewType)};
-check_value(OldS=#state{recordtopname=TopName},V) when is_record(V,valuedef) ->
- #valuedef{name=Name,checked=Checked,type=Vtype,
- value=Value,module=ModName} = V,
- ?dbg("check_value, V: ~p~n",[V]),
- case Checked of
- true ->
- V;
- {error,_} ->
+check_value(S, #valuedef{}=V) ->
+ ?dbg("check_value, V: ~p~n",[V0]),
+ case V of
+ #valuedef{checked=true} ->
V;
- false ->
- Def = Vtype#type.def,
- Constr = Vtype#type.constraint,
- S = OldS#state{type=Vtype,tname=Def,value=V,vname=Name},
- SVal = update_state(S,ModName),
- NewDef =
- case Def of
- Ext when is_record(Ext,'Externaltypereference') ->
- RecName = Ext#'Externaltypereference'.type,
- {RefM,Type} = get_referenced_type(S,Ext),
- %% If V isn't a value but an object Type is a #classdef{}
- %%NewS = S#state{mname=RefM},
- NewS = update_state(S,RefM),
- case Type of
- #classdef{} ->
- throw({objectdef});
- #typedef{} ->
- case is_contextswitchtype(Type) of
- true ->
- #valuedef{value=CheckedVal}=
- check_value(NewS,V#valuedef{type=Type#typedef.typespec}),
- #newv{value=CheckedVal};
- _ ->
- #valuedef{value=CheckedVal}=
- check_value(NewS#state{recordtopname=[RecName|TopName]},
- V#valuedef{type=Type#typedef.typespec}),
- #newv{value=CheckedVal}
- end;
- #type{} ->
- %% A parameter that couldn't be categorized.
- #valuedef{value=CheckedVal}=
- check_value(NewS#state{recordtopname=[RecName|TopName]},
- V#valuedef{type=Type}),
- #newv{value=CheckedVal}
- end;
- 'ANY' ->
- case Value of
- {opentypefieldvalue,ANYType,ANYValue} ->
- CheckedV=
- check_value(SVal,#valuedef{name=Name,
- type=ANYType,
- value=ANYValue,
- module=ModName}),
- #newv{value=CheckedV#valuedef.value};
- _ ->
- throw({error,{asn1,{'cant check value of type',Def}}})
- end;
- 'INTEGER' ->
- ok=validate_integer(SVal,Value,[],Constr),
- #newv{value=normalize_value(SVal,Vtype,Value,[])};
- {'INTEGER',NamedNumberList} ->
- ok=validate_integer(SVal,Value,NamedNumberList,Constr),
- #newv{value=normalize_value(SVal,Vtype,Value,[])};
- {'BIT STRING',NamedNumberList} ->
- ok=validate_bitstring(SVal,Value,NamedNumberList,Constr),
- #newv{value=normalize_value(SVal,Vtype,Value,[])};
- 'NULL' ->
- ok=validate_null(SVal,Value,Constr),
- #newv{};
- 'OBJECT IDENTIFIER' ->
- {ok,_}=validate_objectidentifier(SVal,Value,Constr),
- #newv{value = normalize_value(SVal,Vtype,Value,[])};
- 'RELATIVE-OID' ->
- {ok,_}=validate_relative_oid(SVal,Value,Constr),
- #newv{value = Value};
- 'ObjectDescriptor' ->
- ok=validate_objectdescriptor(SVal,Value,Constr),
- #newv{value=normalize_value(SVal,Vtype,Value,[])};
- 'REAL' ->
- ok = validate_real(SVal,Value,Constr),
- #newv{value=normalize_value(SVal,Vtype,Value,[])};
- {'ENUMERATED',NamedNumberList} ->
- ok=validate_enumerated(SVal,Value,NamedNumberList,Constr),
- #newv{value=normalize_value(SVal,Vtype,Value,[])};
- 'BOOLEAN'->
- ok=validate_boolean(SVal,Value,Constr),
- #newv{value=normalize_value(SVal,Vtype,Value,[])};
- 'OCTET STRING' ->
- ok=validate_octetstring(SVal,Value,Constr),
- #newv{value=normalize_value(SVal,Vtype,Value,[])};
- 'NumericString' ->
- ok=validate_restrictedstring(SVal,Value,Def,Constr),
- #newv{value=normalize_value(SVal,Vtype,Value,[])};
- TString when TString =:= 'TeletexString';
- TString =:= 'T61String' ->
- ok=validate_restrictedstring(SVal,Value,Def,Constr),
- #newv{value=normalize_value(SVal,Vtype,Value,[])};
- 'VideotexString' ->
- ok=validate_restrictedstring(SVal,Value,Def,Constr),
- #newv{value=normalize_value(SVal,Vtype,Value,[])};
- 'UTCTime' ->
- #newv{value=normalize_value(SVal,Vtype,Value,[])};
-% exit({'cant check value of type' ,Def});
- 'GeneralizedTime' ->
- #newv{value=normalize_value(SVal,Vtype,Value,[])};
-% exit({'cant check value of type' ,Def});
- 'GraphicString' ->
- ok=validate_restrictedstring(SVal,Value,Def,Constr),
- #newv{value=normalize_value(SVal,Vtype,Value,[])};
- 'VisibleString' ->
- ok=validate_restrictedstring(SVal,Value,Def,Constr),
- #newv{value=normalize_value(SVal,Vtype,Value,[])};
- 'GeneralString' ->
- ok=validate_restrictedstring(SVal,Value,Def,Constr),
- #newv{value=normalize_value(SVal,Vtype,Value,[])};
- 'PrintableString' ->
- ok=validate_restrictedstring(SVal,Value,Def,Constr),
- #newv{value=normalize_value(SVal,Vtype,Value,[])};
- 'IA5String' ->
- ok=validate_restrictedstring(SVal,Value,Def,Constr),
- #newv{value=normalize_value(SVal,Vtype,Value,[])};
- 'BMPString' ->
- ok=validate_restrictedstring(SVal,Value,Def,Constr),
- #newv{value=normalize_value(SVal,Vtype,Value,[])};
- 'UTF8String' ->
- ok = validate_restrictedstring(SVal,Vtype,Value,Constr),
- %%io:format("Vtype: ~p~nValue: ~p~n",[Vtype,Value]);
- #newv{value=normalize_value(SVal,Vtype,Value,[])};
- 'UniversalString' -> %added 6/12 -00
- ok = validate_restrictedstring(SVal,Value,Def,Constr),
- #newv{value=normalize_value(SVal,Vtype,Value,[])};
- Seq when is_record(Seq,'SEQUENCE') ->
- {ok,SeqVal} = validate_sequence(SVal,Value,
- Seq#'SEQUENCE'.components,
- Constr),
- #newv{value=normalize_value(SVal,Vtype,SeqVal,TopName)};
- {'SEQUENCE OF',Components} ->
- ok=validate_sequenceof(SVal,Value,Components,Constr),
- #newv{value=normalize_value(SVal,Vtype,Value,TopName)};
- {'CHOICE',Components} ->
- ok=validate_choice(SVal,Value,Components,Constr),
- #newv{value=normalize_value(SVal,Vtype,Value,TopName)};
- Set when is_record(Set,'SET') ->
- ok=validate_set(SVal,Value,Set#'SET'.components,
- Constr),
- #newv{value=normalize_value(SVal,Vtype,Value,TopName)};
- {'SET OF',Components} ->
- ok=validate_setof(SVal,Value,Components,Constr),
- #newv{value=normalize_value(SVal,Vtype,Value,TopName)};
- {'SelectionType',SelName,SelT} ->
- CheckedT = check_selectiontype(SVal,SelName,SelT),
- NewV = V#valuedef{type=CheckedT},
- SelVDef=check_value(S#state{value=NewV},NewV),
- #newv{value=SelVDef#valuedef.value};
- Other ->
- exit({'cannot check value of type' ,Other})
- end,
- case NewDef#newv.value of
- unchanged ->
- V#valuedef{checked=true,value=Value};
- ok ->
- V#valuedef{checked=true,value=Value};
- {error,Reason} ->
- V#valuedef{checked={error,Reason},value=Value};
- _V ->
- V#valuedef{checked=true,value=_V}
- end
+ #valuedef{checked=false} ->
+ check_valuedef(S, V)
+ end.
+
+check_valuedef(#state{recordtopname=TopName}=S0, V0) ->
+ #valuedef{name=Name,type=Vtype,value=Value,module=ModName} = V0,
+ V = V0#valuedef{checked=true},
+ Def = Vtype#type.def,
+ Constr = Vtype#type.constraint,
+ S1 = S0#state{type=Vtype,tname=Def,value=V0,vname=Name},
+ SVal = update_state(S1, ModName),
+ case Def of
+ #'Externaltypereference'{type=RecName}=Ext ->
+ {RefM,Type} = get_referenced_type(S1, Ext),
+ %% If V isn't a value but an object Type is a #classdef{}
+ S2 = update_state(S1, RefM),
+ case Type of
+ #classdef{} ->
+ throw({objectdef});
+ #typedef{typespec=TypeSpec} ->
+ S3 = case is_contextswitchtype(Type) of
+ true ->
+ S2;
+ false ->
+ S2#state{recordtopname=[RecName|TopName]}
+ end,
+ #valuedef{value=CheckedVal} =
+ check_value(S3, V0#valuedef{type=TypeSpec}),
+ V#valuedef{value=CheckedVal};
+ #type{} ->
+ %% A parameter that couldn't be categorized.
+ #valuedef{value=CheckedVal} =
+ check_value(S2#state{recordtopname=[RecName|TopName]},
+ V#valuedef{type=Type}),
+ V#valuedef{value=CheckedVal}
+ end;
+ 'ANY' ->
+ {opentypefieldvalue,ANYType,ANYValue} = Value,
+ CheckedV = check_value(SVal,#valuedef{name=Name,
+ type=ANYType,
+ value=ANYValue,
+ module=ModName}),
+ V#valuedef{value=CheckedV#valuedef.value};
+ 'INTEGER' ->
+ ok = validate_integer(SVal, Value, [], Constr),
+ V#valuedef{value=normalize_value(SVal, Vtype, Value, [])};
+ {'INTEGER',NamedNumberList} ->
+ ok = validate_integer(SVal, Value, NamedNumberList, Constr),
+ V#valuedef{value=normalize_value(SVal, Vtype, Value, [])};
+ #'SEQUENCE'{components=Components} ->
+ {ok,SeqVal} = validate_sequence(SVal, Value,
+ Components, Constr),
+ V#valuedef{value=normalize_value(SVal, Vtype,
+ SeqVal, TopName)};
+ {'SelectionType',SelName,SelT} ->
+ CheckedT = check_selectiontype(SVal, SelName, SelT),
+ NewV = V#valuedef{type=CheckedT},
+ SelVDef = check_value(S1#state{value=NewV}, NewV),
+ V#valuedef{value=SelVDef#valuedef.value};
+ _ ->
+ V#valuedef{value=normalize_value(SVal, Vtype, Value, TopName)}
end.
is_contextswitchtype(#typedef{name='EXTERNAL'})->
@@ -2358,23 +2188,7 @@ validate_integer_ref(S,Ref,NamedNumberList,Constr) ->
-check_integer_range(Int,Constr) when is_list(Constr) ->
- NewConstr = [X || #constraint{c=X} <- Constr],
- check_constr(Int,NewConstr);
-
-check_integer_range(_Int,_Constr) ->
- %%io:format("~p~n",[Constr]),
- ok.
-
-check_constr(Int,[{'ValueRange',Lb,Ub}|T]) when Int >= Lb, Int =< Ub ->
- check_constr(Int,T);
-check_constr(_Int,[]) ->
- ok.
-
-validate_bitstring(_S,_Value,_NamedNumberList,_Constr) ->
- ok.
-
-validate_null(_S,'NULL',_Constr) ->
+check_integer_range(_Int, Constr) when is_list(Constr) ->
ok.
%%------------
@@ -2390,9 +2204,6 @@ is_space_list([],Acc) ->
is_space_list([H|T],Acc) ->
is_space_list(T,[H|Acc]).
-validate_objectidentifier(S,ERef,C) ->
- validate_objectidentifier(S,o_id,ERef,C).
-
validate_objectidentifier(S,OID,ERef,C)
when is_record(ERef,'Externalvaluereference') ->
validate_objectidentifier(S,OID,[ERef],C);
@@ -2490,9 +2301,6 @@ validate_oid(_, S, OID, [Atom|Rest],Acc) when is_atom(Atom) ->
validate_oid(_, S, OID, V, Acc) ->
error({value, {"illegal "++to_string(OID),V,Acc},S}).
-validate_relative_oid(S,Value,Constr) ->
- validate_objectidentifier(S,rel_oid,Value,Constr).
-
is_object_id(OID,S,ERef=#'Externaltypereference'{}) ->
{_,OI} = get_referenced_type(S,ERef),
is_object_id(OID,S,OI#typedef.typespec);
@@ -2579,43 +2387,6 @@ valid_objectid(o_id,_I,[1]) -> false;
valid_objectid(o_id,_I,[2]) -> true;
valid_objectid(_,_,_) -> true.
-
-
-
-
-
-validate_objectdescriptor(_S,_Value,_Constr) ->
- ok.
-
-validate_real(_S,_Value,_Constr) ->
- ok.
-
-validate_enumerated(S,Id,NamedNumberList,_Constr) when is_atom(Id) ->
- case lists:keysearch(Id,1,NamedNumberList) of
- {value,_} -> ok;
- false -> error({value,"unknown ENUMERATED",S})
- end;
-validate_enumerated(S,{identifier,_Pos,Id},NamedNumberList,_Constr) ->
- case lists:keysearch(Id,1,NamedNumberList) of
- {value,_} -> ok;
- false -> error({value,"unknown ENUMERATED",S})
- end;
-validate_enumerated(S,#'Externalvaluereference'{value=Id},
- NamedNumberList,_Constr) ->
- case lists:keysearch(Id,1,NamedNumberList) of
- {value,_} -> ok;
- false -> error({value,"unknown ENUMERATED",S})
- end.
-
-validate_boolean(_S,_Value,_Constr) ->
- ok.
-
-validate_octetstring(_S,_Value,_Constr) ->
- ok.
-
-validate_restrictedstring(_S,_Value,_Def,_Constr) ->
- ok.
-
validate_sequence(S=#state{type=Vtype},Value,_Components,_Constr) ->
case Vtype of
#type{tag=[{tag,'UNIVERSAL',8,'IMPLICIT',32}]} ->
@@ -2630,18 +2401,6 @@ validate_sequence(S=#state{type=Vtype},Value,_Components,_Constr) ->
{ok,Value}
end.
-validate_sequenceof(_S,_Value,_Components,_Constr) ->
- ok.
-
-validate_choice(_S,_Value,_Components,_Constr) ->
- ok.
-
-validate_set(_S,_Value,_Components,_Constr) ->
- ok.
-
-validate_setof(_S,_Value,_Components,_Constr) ->
- ok.
-
to_EXTERNAL1990(S,[{identification,{'CHOICE',{syntax,Stx}}}|Rest]) ->
to_EXTERNAL1990(S,Rest,[{'direct-reference',Stx}]);
to_EXTERNAL1990(S,[{identification,{'CHOICE',{'presentation-context-id',I}}}|Rest]) ->
@@ -2667,7 +2426,8 @@ normalize_value(_,_,mandatory,_) ->
mandatory;
normalize_value(_,_,'OPTIONAL',_) ->
'OPTIONAL';
-normalize_value(S,Type,{'DEFAULT',Value},NameList) ->
+normalize_value(S0, Type, {'DEFAULT',Value}, NameList) ->
+ S = S0#state{value=Value},
case catch get_canonic_type(S,Type,NameList) of
{'BOOLEAN',CType,_} ->
normalize_boolean(S,Value,CType);
@@ -2892,12 +2652,12 @@ hstring_to_octetlist([H|T],BSL,Acc) when H >= $0; H =< $9 ->
hstring_to_octetlist([],_,Acc) ->
lists:reverse(Acc).
-normalize_objectidentifier(S,Value) ->
- {ok,Val}=validate_objectidentifier(S,Value,[]),
+normalize_objectidentifier(S, Value) ->
+ {ok,Val} = validate_objectidentifier(S, o_id, Value, []),
Val.
normalize_relative_oid(S,Value) ->
- {ok,Val} = validate_relative_oid(S,Value,[]),
+ {ok,Val} = validate_objectidentifier(S, rel_oid, Value, []),
Val.
normalize_objectdescriptor(Value) ->
@@ -2906,29 +2666,20 @@ normalize_objectdescriptor(Value) ->
normalize_real(Value) ->
Value.
-normalize_enumerated(S,#'Externalvaluereference'{value=V},CType)
- when is_list(CType) ->
- normalize_enumerated2(S,V,CType);
-normalize_enumerated(S,Value,CType) when is_atom(Value),is_list(CType) ->
- normalize_enumerated2(S,Value,CType);
-normalize_enumerated(S,{Name,EnumV},CType) when is_atom(Name) ->
- normalize_enumerated(S,EnumV,CType);
-normalize_enumerated(S,Value,{CType1,CType2}) when is_list(CType1), is_list(CType2)->
- normalize_enumerated(S,Value,CType1++CType2);
-normalize_enumerated(S,V,CType) ->
- asn1ct:warning("Enumerated unknown type ~p~n",[CType],S,
- "Enumerated unknown type"),
- V.
-normalize_enumerated2(S,V,Enum) ->
- case lists:keysearch(V,1,Enum) of
- {value,{Val,_}} -> Val;
- _ ->
- asn1ct:warning("enumerated value is not correct ~p~n",[V],S,
- "enumerated value is not correct"),
- V
+normalize_enumerated(S, Id, {Base,Ext}) ->
+ %% Extensible ENUMERATED.
+ normalize_enumerated(S, Id, Base++Ext);
+normalize_enumerated(S, #'Externalvaluereference'{value=Id},
+ NamedNumberList) ->
+ normalize_enumerated(S, Id, NamedNumberList);
+normalize_enumerated(S, Id, NamedNumberList) when is_atom(Id) ->
+ case lists:keymember(Id, 1, NamedNumberList) of
+ true ->
+ Id;
+ false ->
+ throw(asn1_error(S, S#state.value, {undefined,Id}))
end.
-
normalize_choice(S,{'CHOICE',{C,V}},CType,NameList) when is_atom(C) ->
case catch lists:keysearch(C,#'ComponentType'.name,CType) of
{value,#'ComponentType'{typespec=CT,name=Name}} ->
@@ -3535,10 +3286,6 @@ check_type(S=#state{recordtopname=TopName},Type,Ts) when is_record(Ts,type) ->
merge_tags(Tag,?TAG_CONSTRUCTED(?N_SET))};
%% This is a temporary hack until the full Information Obj Spec
%% in X.681 is supported
- {{typereference,_,'TYPE-IDENTIFIER'},[{typefieldreference,_,'Type'}]} ->
- Ct=maybe_illicit_implicit_tag(open_type,Tag),
- TempNewDef#newt{type='ASN1_OPEN_TYPE',tag=Ct};
-
{#'Externaltypereference'{type='TYPE-IDENTIFIER'},
[{typefieldreference,_,'Type'}]} ->
Ct=maybe_illicit_implicit_tag(open_type,Tag),
@@ -3575,7 +3322,15 @@ check_type(S=#state{recordtopname=TopName},Type,Ts) when is_record(Ts,type) ->
_ ->
MergedTag
end,
- TempNewDef#newt{type=NewTypeDef,tag=Ct};
+ case TopName of
+ [] when Type#typedef.name =/= undefined ->
+ %% This is a top-level type.
+ #type{def=Simplified} =
+ simplify_type(#type{def=NewTypeDef}),
+ TempNewDef#newt{type=Simplified,tag=Ct};
+ _ ->
+ TempNewDef#newt{type=NewTypeDef,tag=Ct}
+ end;
{'TypeFromObject',{object,Object},TypeField} ->
CheckedT = get_type_from_object(S,Object,TypeField),
@@ -3591,29 +3346,14 @@ check_type(S=#state{recordtopname=TopName},Type,Ts) when is_record(Ts,type) ->
Other ->
exit({'cant check' ,Other})
end,
- Ts2 = case NewDef of
- #newt{type=unchanged} ->
- Ts#type{def=Def};
- #newt{type=TDef}->
- Ts#type{def=TDef}
- end,
- NewTag = case NewDef of
- #newt{tag=unchanged} ->
- Tag;
- #newt{tag=TT} ->
- TT
- end,
- T3 = Ts2#type{tag = lists:map(fun(TempTag = #tag{type={default,TTx}}) ->
- TempTag#tag{type=TTx};
- (Else) -> Else end, NewTag)},
- T4 = case NewDef of
- #newt{constraint=unchanged} ->
- T3#type{constraint=Constr};
- #newt{constraint=NewConstr} ->
- T3#type{constraint=NewConstr}
- end,
- T5 = T4#type{inlined=NewDef#newt.inlined},
- T5#type{constraint=check_constraints(S,T5#type.constraint)};
+ #newt{type=TDef,tag=NewTags,constraint=NewConstr,inlined=Inlined} = NewDef,
+ Ts#type{def=TDef,
+ inlined=Inlined,
+ constraint=check_constraints(S, NewConstr),
+ tag=lists:map(fun(#tag{type={default,TTx}}=TempTag) ->
+ TempTag#tag{type=TTx};
+ (Other) -> Other
+ end, NewTags)};
check_type(_S,Type,Ts) ->
exit({error,{asn1,internal_error,Type,Ts}}).
@@ -3625,6 +3365,28 @@ get_non_typedef(S, Tref0) ->
Type
end.
+
+%%
+%% Simplify the backends by getting rid of an #'ObjectClassFieldType'{}
+%% with a type known at compile time.
+%%
+
+simplify_comps(Comps) ->
+ [simplify_comp(Comp) || Comp <- Comps].
+
+simplify_comp(#'ComponentType'{typespec=Type0}=C) ->
+ Type = simplify_type(Type0),
+ C#'ComponentType'{typespec=Type};
+simplify_comp(Other) -> Other.
+
+simplify_type(#type{tag=Tag,def=Inner}=T) ->
+ case Inner of
+ #'ObjectClassFieldType'{type={fixedtypevaluefield,_,Type}} ->
+ Type#type{tag=Tag};
+ _ ->
+ T
+ end.
+
%% tablecinf_choose. A SEQUENCE or SET may be inserted in another
%% SEQUENCE or SET by the COMPONENTS OF directive. If this inserted
%% type is a referenced type that already has been checked it already
@@ -4003,26 +3765,10 @@ categorize(_S,type,Def) when is_record(Def,type) ->
categorize(_,_,Def) ->
[Def].
categorize(S,object_set,Def,ClassRef) ->
- %% XXXXXXXXXX
- case Def of
- {'Externaltypereference',undefined,'MSAccessProtocol','AllOperations'} ->
- ok;
- _ ->
- ok
- end,
NewObjSetSpec =
check_object(S,Def,#'ObjectSet'{class = ClassRef,
set = parse_objectset(Def)}),
Name = new_reference_name("object_set_argument"),
- %% XXXXXXXXXX
- case Name of
- internal_object_set_argument_78 ->
- ok;
- internal_object_set_argument_77 ->
- ok;
- _ ->
- ok
- end,
[save_object_set_instance(S,Name,NewObjSetSpec)];
categorize(_S,object,Def,_ClassRef) ->
%% should be handled
@@ -4048,9 +3794,7 @@ parse_objectset(Set) ->
%% check_constraints/2
%%
check_constraints(S,C) when is_list(C) ->
- check_constraints(S, C, []);
-check_constraints(S,C) when is_record(C,constraint) ->
- check_constraints(S, C#constraint.c, []).
+ check_constraints(S, C, []).
resolv_tuple_or_list(S,List) when is_list(List) ->
lists:map(fun(X)->resolv_value(S,X) end, List);
@@ -4077,23 +3821,19 @@ resolv_value1(S, ERef = #'Externalvaluereference'{value=Name}) ->
resolv_value1(S,VDef)
end
end;
-resolv_value1(S,{gt,V}) ->
- case V of
+resolv_value1(S, {gt,V}) ->
+ case resolv_value1(S, V) of
Int when is_integer(Int) ->
- V + 1;
- #valuedef{value=Int} ->
- 1 + resolv_value(S,Int);
+ Int + 1;
Other ->
- throw({error,{asn1,{undefined_type_or_value,Other}}})
+ throw({error,{asn1,{not_integer_value,Other}}})
end;
-resolv_value1(S,{lt,V}) ->
- case V of
+resolv_value1(S, {lt,V}) ->
+ case resolv_value1(S, V) of
Int when is_integer(Int) ->
- V - 1;
- #valuedef{value=Int} ->
- resolv_value(S,Int) - 1;
+ Int - 1;
Other ->
- throw({error,{asn1,{undefined_type_or_value,Other}}})
+ throw({error,{asn1,{not_integer_value,Other}}})
end;
resolv_value1(S,{'ValueFromObject',{object,Object},[{valuefieldreference,
FieldName}]}) ->
@@ -4356,7 +4096,42 @@ normalize_cs([{'ValueRange',{Sv,Sv}}|Cs]) ->
[{'SingleValue',Sv}|normalize_cs(Cs)];
normalize_cs([{'ValueRange',{'MIN','MAX'}}|Cs]) ->
normalize_cs(Cs);
-normalize_cs(Other) -> Other.
+normalize_cs([{'SizeConstraint',C0}|Cs]) ->
+ case normalize_size_constraint(C0) of
+ none ->
+ normalize_cs(Cs);
+ C ->
+ [{'SizeConstraint',C}|normalize_cs(Cs)]
+ end;
+normalize_cs([H|T]) ->
+ [H|normalize_cs(T)];
+normalize_cs([]) -> [].
+
+%% Normalize a size constraint to make it non-ambiguous and
+%% easy to interpret for the backends.
+%%
+%% Returns one of the following terms:
+%% {LowerBound,UpperBound}
+%% {{LowerBound,UpperBound},[]} % Extensible
+%% none % Remove size constraint from list
+%%
+%% where:
+%% LowerBound = integer()
+%% UpperBound = integer() | 'MAX'
+
+normalize_size_constraint(Sv) when is_integer(Sv) ->
+ {Sv,Sv};
+normalize_size_constraint({Root,Ext}) when is_list(Ext) ->
+ {normalize_size_constraint(Root),[]};
+normalize_size_constraint({{_,_},Ext}) when is_integer(Ext) ->
+ normalize_size_constraint(Ext);
+normalize_size_constraint([H|T]) ->
+ {H,lists:last(T)};
+normalize_size_constraint({0,'MAX'}) ->
+ none;
+normalize_size_constraint({Lb,Ub}=Range)
+ when is_integer(Lb), is_integer(Ub) orelse Ub =:= 'MAX' ->
+ Range.
is_range(Prev, [H|T]) when Prev =:= H - 1 -> is_range(H, T);
is_range(_, [_|_]) -> false;
@@ -4925,19 +4700,7 @@ get_referenced(S,Emod,Ename,Pos) ->
end;
T when is_record(T,typedef) ->
?dbg("get_referenced T: ~p~n",[T]),
- Spec = T#typedef.typespec, %% XXXX Spec may be something else than #type
- case Spec of
- #type{def=#typereference{}} ->
- Tref = Spec#type.def,
- Def = #'Externaltypereference'{module=Emod,
- type=Tref#typereference.val,
- pos=Tref#typereference.pos},
-
-
- {Emod,T#typedef{typespec=Spec#type{def=Def}}};
- _ ->
- {Emod,T} % should add check that T is exported here
- end;
+ {Emod,T}; % should add check that T is exported here
V ->
?dbg("get_referenced V: ~p~n",[V]),
{Emod,V}
@@ -5385,14 +5148,14 @@ iof_associated_type1(S,C) ->
prop=mandatory,
tags=[{'CONTEXT',0}]}],
#'SEQUENCE'{tablecinf=TableCInf,
- components=IOFComponents}.
+ components=simplify_comps(IOFComponents)}.
%% returns the leading attribute, the constraint of the components and
%% the tablecinf value for the second component.
instance_of_constraints(_,[]) ->
{false,[],[],[]};
-instance_of_constraints(S,#constraint{c={simpletable,Type}}) ->
+instance_of_constraints(S, [{simpletable,Type}]) ->
#type{def=#'Externaltypereference'{type=Name}} = Type,
ModuleName = S#state.mname,
ObjectSetRef=#'Externaltypereference'{module=ModuleName,
@@ -5403,7 +5166,8 @@ instance_of_constraints(S,#constraint{c={simpletable,Type}}) ->
[{innermost,
[#'Externalvaluereference'{module=ModuleName,
value=type}]}]}],
- TableCInf=#simpletableattributes{objectsetname=Name,
+ Mod = S#state.mname,
+ TableCInf=#simpletableattributes{objectsetname={Mod,Name},
c_name='type-id',
c_index=1,
usedclassfield=id,
@@ -5539,46 +5303,37 @@ check_sequence(S,Type,Comps) ->
%% the involved class removed, as the class of the object
%% set.
CompListWithTblInf = get_tableconstraint_info(S,Type,NewComps2),
- %% If encoding rule is in the PER family the Root Components
- %% after the second extension mark should be encoded before
- %% all extensions i.e together with the first Root components
NewComps3 = textual_order(CompListWithTblInf),
- CompListTuple =
- complist_as_tuple(is_erule_per(S#state.erule),NewComps3),
+ NewComps4 = simplify_comps(NewComps3),
+ CompListTuple = complist_as_tuple(NewComps4),
{CRelInf,CompListTuple};
Dupl ->
throw({error,{asn1,{duplicate_components,Dupl}}})
end.
-complist_as_tuple(Per,CompList) ->
- complist_as_tuple(Per,CompList,[],[],[],root).
+complist_as_tuple(CompList) ->
+ complist_as_tuple(CompList, [], [], [], root).
-complist_as_tuple(Per,[#'EXTENSIONMARK'{}|T],Acc,Ext,Acc2,root) ->
- complist_as_tuple(Per,T,Acc,Ext,Acc2,ext);
-complist_as_tuple(Per,[#'EXTENSIONMARK'{}|T],Acc,Ext,Acc2,ext) ->
- complist_as_tuple(Per,T,Acc,Ext,Acc2,root2);
-complist_as_tuple(_Per,[#'EXTENSIONMARK'{}|_T],_Acc,_Ext,_Acc2,root2) ->
+complist_as_tuple([#'EXTENSIONMARK'{}|T], Acc, Ext, Acc2, root) ->
+ complist_as_tuple(T, Acc, Ext, Acc2, ext);
+complist_as_tuple([#'EXTENSIONMARK'{}|T], Acc, Ext, Acc2, ext) ->
+ complist_as_tuple(T, Acc, Ext, Acc2, root2);
+complist_as_tuple([#'EXTENSIONMARK'{}|_T], _Acc, _Ext, _Acc2, root2) ->
throw({error,{asn1,{too_many_extension_marks}}});
-complist_as_tuple(Per,[C|T],Acc,Ext,Acc2,root) ->
- complist_as_tuple(Per,T,[C|Acc],Ext,Acc2,root);
-complist_as_tuple(Per,[C|T],Acc,Ext,Acc2,ext) ->
- complist_as_tuple(Per,T,Acc,[C|Ext],Acc2,ext);
-complist_as_tuple(Per,[C|T],Acc,Ext,Acc2,root2) ->
- complist_as_tuple(Per,T,Acc,Ext,[C|Acc2],root2);
-complist_as_tuple(_Per,[],Acc,_Ext,_Acc2,root) ->
+complist_as_tuple([C|T], Acc, Ext, Acc2, root) ->
+ complist_as_tuple(T, [C|Acc], Ext, Acc2, root);
+complist_as_tuple([C|T], Acc, Ext, Acc2, ext) ->
+ complist_as_tuple(T, Acc, [C|Ext], Acc2, ext);
+complist_as_tuple([C|T], Acc, Ext, Acc2, root2) ->
+ complist_as_tuple(T, Acc, Ext, [C|Acc2], root2);
+complist_as_tuple([], Acc, _Ext, _Acc2, root) ->
lists:reverse(Acc);
-complist_as_tuple(_Per,[],Acc,Ext,_Acc2,ext) ->
+complist_as_tuple([], Acc, Ext, _Acc2, ext) ->
{lists:reverse(Acc),lists:reverse(Ext)};
-%%complist_as_tuple(_Per = true,[],Acc,Ext,Acc2,root2) ->
-%% {lists:reverse(Acc)++lists:reverse(Acc2),lists:reverse(Ext)};
-complist_as_tuple(_Per,[],Acc,Ext,Acc2,root2) ->
+complist_as_tuple([], Acc, Ext, Acc2, root2) ->
{lists:reverse(Acc),lists:reverse(Ext),lists:reverse(Acc2)}.
-is_erule_per(per) -> true;
-is_erule_per(uper) -> true;
-is_erule_per(ber) -> false.
-
expand_components(S, [{'COMPONENTS OF',Type}|T]) ->
CompList = expand_components2(S,get_referenced_type(S,Type#type.def)),
expand_components(S,CompList) ++ expand_components(S,T);
@@ -5622,7 +5377,7 @@ take_only_rootset([H|T]) ->
[H|take_only_rootset(T)].
check_unique_sequence_tags(S,CompList) ->
- TagComps = case complist_as_tuple(false,CompList) of
+ TagComps = case complist_as_tuple(CompList) of
{R1,Ext,R2} ->
R1 ++ [C#'ComponentType'{prop='OPTIONAL'}||
C = #'ComponentType'{} <- Ext]++R2;
@@ -5657,7 +5412,7 @@ check_unique_sequence_tags1(S,[],Acc) ->
check_unique_tags(S,lists:reverse(Acc)).
check_sequenceof(S,Type,Component) when is_record(Component,type) ->
- check_type(S,Type,Component).
+ simplify_type(check_type(S, Type, Component)).
check_set(S,Type,Components) ->
{TableCInf,NewComponents} = check_sequence(S,Type,Components),
@@ -5879,7 +5634,7 @@ extension({Root1,ExtList,Root2}) ->
X = #'ComponentType'{prop=Y}<-ExtList], Root2}.
check_setof(S,Type,Component) when is_record(Component,type) ->
- check_type(S,Type,Component).
+ simplify_type(check_type(S, Type, Component)).
check_selectiontype(S,Name,#type{def=Eref})
when is_record(Eref,'Externaltypereference') ->
@@ -5943,8 +5698,9 @@ check_choice(S,Type,Components) when is_list(Components) ->
('ExtensionAdditionGroupEnd') -> false;
(_) -> true
end,NewComps),
- check_unique_tags(S,NewComps2),
- complist_as_tuple(is_erule_per(S#state.erule),NewComps2);
+ NewComps3 = simplify_comps(NewComps2),
+ check_unique_tags(S, NewComps3),
+ complist_as_tuple(NewComps3);
Dupl ->
throw({error,{asn1,{duplicate_choice_alternatives,Dupl}}})
end;
@@ -6322,7 +6078,7 @@ get_simple_table_info1(S,#'ComponentType'{typespec=TS},Cnames,Path) ->
simple_table_info(S,#'ObjectClassFieldType'{classname=ClRef,
class=ObjectClass,
fieldname=FieldName},Path) ->
-
+
ObjectClassFieldName =
case FieldName of
{LastFieldName,[]} -> LastFieldName;
@@ -6875,9 +6631,6 @@ get_OCFType(S,Fields,[PrimFieldName|Rest]) ->
get_taglist(S,Ext) when is_record(Ext,'Externaltypereference') ->
{_,T} = get_referenced_type(S,Ext),
get_taglist(S,T#typedef.typespec);
-get_taglist(S,Tref) when is_record(Tref,typereference) ->
- {_,T} = get_referenced_type(S,Tref),
- get_taglist(S,T#typedef.typespec);
get_taglist(S,Type) when is_record(Type,type) ->
case Type#type.tag of
[] ->
@@ -7047,60 +6800,27 @@ storeindb(S,M) when is_record(M,module) ->
NewM = M#module{typeorval=findtypes_and_values(TVlist)},
asn1_db:dbnew(NewM#module.name),
asn1_db:dbput(NewM#module.name,'MODULE', NewM),
- Res = storeindb(NewM#module.name,TVlist,[]),
+ Res = storeindb(#state{mname=NewM#module.name}, TVlist, []),
include_default_class(S,NewM#module.name),
include_default_type(NewM#module.name),
Res.
-storeindb(Module,[H|T],ErrAcc) when is_record(H,typedef) ->
- storeindb(Module,H#typedef.name,H,T,ErrAcc);
-storeindb(Module,[H|T],ErrAcc) when is_record(H,valuedef) ->
- storeindb(Module,H#valuedef.name,H,T,ErrAcc);
-storeindb(Module,[H|T],ErrAcc) when is_record(H,ptypedef) ->
- storeindb(Module,H#ptypedef.name,H,T,ErrAcc);
-storeindb(Module,[H|T],ErrAcc) when is_record(H,classdef) ->
- storeindb(Module,H#classdef.name,H,T,ErrAcc);
-storeindb(Module,[H|T],ErrAcc) when is_record(H,pvaluesetdef) ->
- storeindb(Module,H#pvaluesetdef.name,H,T,ErrAcc);
-storeindb(Module,[H|T],ErrAcc) when is_record(H,pobjectdef) ->
- storeindb(Module,H#pobjectdef.name,H,T,ErrAcc);
-storeindb(Module,[H|T],ErrAcc) when is_record(H,pvaluedef) ->
- storeindb(Module,H#pvaluedef.name,H,T,ErrAcc);
-storeindb(_,[],[]) -> ok;
-storeindb(_,[],ErrAcc) ->
- {error,ErrAcc}.
-
-storeindb(Module,Name,H,T,ErrAcc) ->
- case asn1_db:dbget(Module,Name) of
+storeindb(#state{mname=Module}=S, [H|T], Errors) ->
+ Name = asn1ct:get_name_of_def(H),
+ case asn1_db:dbget(Module, Name) of
undefined ->
- asn1_db:dbput(Module,Name,H),
- storeindb(Module,T,ErrAcc);
- _ ->
- case H of
- _Type when is_record(H,typedef) ->
- error({type,"already defined",
- #state{mname=Module,type=H,tname=Name}});
- _Type when is_record(H,valuedef) ->
- error({value,"already defined",
- #state{mname=Module,value=H,vname=Name}});
- _Type when is_record(H,ptypedef) ->
- error({ptype,"already defined",
- #state{mname=Module,type=H,tname=Name}});
- _Type when is_record(H,pobjectdef) ->
- error({ptype,"already defined",
- #state{mname=Module,type=H,tname=Name}});
- _Type when is_record(H,pvaluesetdef) ->
- error({ptype,"already defined",
- #state{mname=Module,type=H,tname=Name}});
- _Type when is_record(H,pvaluedef) ->
- error({ptype,"already defined",
- #state{mname=Module,type=H,tname=Name}});
- _Type when is_record(H,classdef) ->
- error({class,"already defined",
- #state{mname=Module,value=H,vname=Name}})
- end,
- storeindb(Module,T,[H|ErrAcc])
- end.
+ asn1_db:dbput(Module, Name, H),
+ storeindb(S, T, Errors);
+ Prev ->
+ PrevLine = asn1ct:get_pos_of_def(Prev),
+ {error,Error} = asn1_error(S, H, {already_defined,Name,PrevLine}),
+ storeindb(S, T, [Error|Errors])
+ end;
+storeindb(_, [], []) ->
+ ok;
+storeindb(_, [], [_|_]=Errors) ->
+ {error,Errors}.
+
findtypes_and_values(TVList) ->
findtypes_and_values(TVList,[],[],[],[],[],[]).%% Types,Values,
@@ -7140,8 +6860,20 @@ findtypes_and_values([],Tacc,Vacc,Pacc,Cacc,Oacc,OSacc) ->
{lists:reverse(Tacc),lists:reverse(Vacc),lists:reverse(Pacc),
lists:reverse(Cacc),lists:reverse(Oacc),lists:reverse(OSacc)}.
-
-
+asn1_error(#state{mname=Where}, Item, Error) ->
+ Pos = asn1ct:get_pos_of_def(Item),
+ {error,{structured_error,{Where,Pos},?MODULE,Error}}.
+
+format_error({already_defined,Name,PrevLine}) ->
+ io_lib:format("the name ~p has already been defined at line ~p",
+ [Name,PrevLine]);
+format_error({undefined,Name}) ->
+ io_lib:format("'~s' is referenced, but is not defined", [Name]);
+format_error(Other) ->
+ io_lib:format("~p", [Other]).
+
+error({_,{structured_error,_,_,_}=SE,_}) ->
+ SE;
error({export,Msg,#state{mname=Mname,type=Ref,tname=Typename}}) ->
Pos = Ref#'Externaltypereference'.pos,
io:format("asn1error:~p:~p:~p~n~p~n",[Pos,Mname,Typename,Msg]),
@@ -7444,3 +7176,13 @@ insert_once(S,Tab,Key) ->
_ ->
skipped
end.
+
+check_fold(S, [H|T], Check) ->
+ Type = asn1_db:dbget(S#state.mname, H),
+ case Check(S, H, Type) of
+ ok ->
+ check_fold(S, T, Check);
+ Error ->
+ [Error|check_fold(S, T, Check)]
+ end;
+check_fold(_, [], Check) when is_function(Check, 3) -> [].
diff --git a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl
index 341a04761b..761faa53c5 100644
--- a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl
+++ b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl
@@ -114,30 +114,16 @@ gen_encode_sequence(Erules,Typename,D) when is_record(D,type) ->
usedclassfield=UniqueFieldName,
uniqueclassfield=UniqueFieldName,
valueindex=ValueIndex} -> %% N is index of attribute that determines constraint
- OSDef =
- case ObjectSetRef of
- {Module,OSName} ->
- asn1_db:dbget(Module,OSName);
- OSName ->
- asn1_db:dbget(get(currmod),OSName)
- end,
-% io:format("currmod: ~p~nOSName: ~p~nAttrN: ~p~nN: ~p~nUniqueFieldName: ~p~n",
-% [get(currmod),OSName,AttrN,N,UniqueFieldName]),
+ {ObjSetMod,ObjSetName} = ObjectSetRef,
+ OSDef = asn1_db:dbget(ObjSetMod, ObjSetName),
case (OSDef#typedef.typespec)#'ObjectSet'.gen of
true ->
ObjectEncode =
asn1ct_gen:un_hyphen_var(lists:concat(['Obj',
AttrN])),
- {ObjSetMod,ObjSetName} =
- case ObjectSetRef of
- {M,O} ->
- {{asis,M},O};
- _ ->
- {"?MODULE",ObjectSetRef}
- end,
- emit([ObjectEncode," = ",nl]),
- emit([" ",ObjSetMod,":'getenc_",ObjSetName,"'(",{asis,UniqueFieldName},
- ", ",nl]),
+ emit([ObjectEncode," = ",nl,
+ " ",{asis,ObjSetMod},":'getenc_",ObjSetName,
+ "'(",{asis,UniqueFieldName},", ",nl]),
ValueMatch = value_match(ValueIndex,
lists:concat(["Cindex",N])),
emit([indent(35),ValueMatch,"),",nl]),
@@ -183,7 +169,6 @@ gen_encode_sequence(Erules,Typename,D) when is_record(D,type) ->
gen_decode_sequence(Erules,Typename,D) when is_record(D,type) ->
asn1ct_name:start(),
- asn1ct_name:clear(),
asn1ct_name:new(tag),
#'SEQUENCE'{tablecinf=TableConsInfo,components=CList0} = D#type.def,
@@ -258,15 +243,9 @@ gen_decode_sequence(Erules,Typename,D) when is_record(D,type) ->
{[{ObjSetRef,LeadingAttr,Term}],PostponedDecArgs} ->
DecObj = asn1ct_gen:un_hyphen_var(lists:concat(['DecObj',LeadingAttr,Term])),
ValueMatch = value_match(ValueIndex,Term),
- {ObjSetMod,ObjSetName} =
- case ObjSetRef of
- {M,O} ->
- {{asis,M},O};
- _ ->
- {"?MODULE",ObjSetRef}
- end,
+ {ObjSetMod,ObjSetName} = ObjSetRef,
emit([DecObj," =",nl,
- " ",ObjSetMod,":'getdec_",ObjSetName,"'(",
+ " ",{asis,ObjSetMod},":'getdec_",ObjSetName,"'(",
{asis,UniqueFName},", ",ValueMatch,"),",nl]),
gen_dec_postponed_decs(DecObj,PostponedDecArgs)
end,
@@ -349,7 +328,6 @@ gen_encode_set(Erules,Typename,D) when is_record(D,type) ->
gen_decode_set(Erules,Typename,D) when is_record(D,type) ->
asn1ct_name:start(),
- asn1ct_name:clear(),
%% asn1ct_name:new(term),
asn1ct_name:new(tag),
#'SET'{tablecinf=TableConsInfo,components=TCompList0} = D#type.def,
@@ -444,15 +422,9 @@ gen_decode_set(Erules,Typename,D) when is_record(D,type) ->
{[{ObjSetRef,LeadingAttr,Term}],PostponedDecArgs} ->
DecObj = asn1ct_gen:un_hyphen_var(lists:concat(['DecObj',LeadingAttr,Term])),
ValueMatch = value_match(ValueIndex,Term),
- {ObjSetMod,ObjSetName} =
- case ObjSetRef of
- {M,O} ->
- {{asis,M},O};
- _ ->
- {"?MODULE",ObjSetRef}
- end,
+ {ObjSetMod,ObjSetName} = ObjSetRef,
emit([DecObj," =",nl,
- " ",ObjSetMod,":'getdec_",ObjSetName,"'(",
+ " ",{asis,ObjSetMod},":'getdec_",ObjSetName,"'(",
{asis,UniqueFName},", ",ValueMatch,"),",nl]),
gen_dec_postponed_decs(DecObj,PostponedDecArgs)
end,
@@ -504,7 +476,6 @@ gen_encode_sof(Erules,Typename,_InnerTypename,D) when is_record(D,type) ->
gen_decode_sof(Erules,TypeName,_InnerTypeName,D) when is_record(D,type) ->
asn1ct_name:start(),
- asn1ct_name:clear(),
{SeqOrSetOf, _TypeTag, Cont} =
case D#type.def of
{'SET OF',_Cont} -> {'SET OF','SET',_Cont};
@@ -1002,9 +973,7 @@ gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,Assign,EncObj)
{componentrelation,_,_}} ->
{_LeadingAttrName,Fun} = EncObj,
case RefedFieldName of
-%% {notype,T} ->
-%% throw({error,{notype,type_from_object,T}});
- {Name,RestFieldNames} when is_atom(Name), Name =/= notype ->
+ {Name,RestFieldNames} when is_atom(Name) ->
case OptOrMand of
mandatory -> ok;
_ ->
@@ -1035,17 +1004,8 @@ gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,Assign,EncObj)
_ ->
case WhatKind of
{primitive,bif} ->
- EncType =
- case Type#type.def of
- #'ObjectClassFieldType'{type={fixedtypevaluefield,_,Btype}} ->
- Btype;
- _ ->
- Type
- end,
- ?ASN1CT_GEN_BER:gen_encode_prim(ber,EncType,{asis,Tag},
- Element);
-%% {notype,_} ->
-%% emit(["'enc_",InnerType,"'(",Element,", ",{asis,Tag},")"]);
+ ?ASN1CT_GEN_BER:gen_encode_prim(ber, Type, {asis,Tag},
+ Element);
'ASN1_OPEN_TYPE' ->
case Type#type.def of
#'ObjectClassFieldType'{} -> %Open Type
@@ -1266,15 +1226,9 @@ gen_dec_call(InnerType,Erules,TopType,Cname,Type,BytesVar,Tag,PrimOptOrMand,
{Cname,{_,OSet,UniqueFName,ValIndex}} ->
Term = asn1ct_gen:mk_var(asn1ct_name:curr(term)),
ValueMatch = value_match(ValIndex,Term),
- {ObjSetMod,ObjSetName} =
- case OSet of
- {M,O} ->
- {{asis,M},O};
- _ ->
- {"?MODULE",OSet}
- end,
- emit([",",nl,"ObjFun = ",ObjSetMod,":'getdec_",ObjSetName,"'(",
- {asis,UniqueFName},", ",ValueMatch,")"]);
+ {ObjSetMod,ObjSetName} = OSet,
+ emit([",",nl,"ObjFun = ",{asis,ObjSetMod},":'getdec_",ObjSetName,
+ "'(",{asis,UniqueFName},", ",ValueMatch,")"]);
_ ->
ok
end,
@@ -1288,9 +1242,6 @@ gen_dec_call1({primitive,bif},InnerType,Erules,TopType,Cname,Type,BytesVar,
asn1ct:update_gen_state(namelist,Rest),
emit(["{'",asn1ct_gen:list2name([Cname|TopType]),"',",
BytesVar,"}"]);
- {_,{fixedtypevaluefield,_,Btype}} ->
- ?ASN1CT_GEN_BER:gen_dec_prim(Erules,Btype,BytesVar,Tag,[],
- ?PRIMITIVE,OptOrMand);
_ ->
?ASN1CT_GEN_BER:gen_dec_prim(Erules,Type,BytesVar,Tag,[],
?PRIMITIVE,OptOrMand)
@@ -1458,9 +1409,7 @@ print_attribute_comment(InnerType,Pos,Cname,Prop) ->
CommentLine = "%%-------------------------------------------------",
emit([nl,CommentLine]),
case InnerType of
- {typereference,_,Name} ->
- emit([nl,"%% attribute ",Cname,"(",Pos,") with type ",Name]);
- {'Externaltypereference',_,XModule,Name} ->
+ #'Externaltypereference'{module=XModule,type=Name} ->
emit([nl,"%% attribute ",Cname,"(",Pos,") External ",XModule,":",Name]);
_ ->
emit([nl,"%% attribute ",Cname,"(",Pos,") with type ",InnerType])
diff --git a/lib/asn1/src/asn1ct_constructed_per.erl b/lib/asn1/src/asn1ct_constructed_per.erl
index aa5ee18c80..efb55cf015 100644
--- a/lib/asn1/src/asn1ct_constructed_per.erl
+++ b/lib/asn1/src/asn1ct_constructed_per.erl
@@ -143,40 +143,21 @@ gen_encode_constructed(Erule,Typename,D) when is_record(D,type) ->
uniqueclassfield=UniqueFieldName,
valueindex=ValueIndex
} -> %% N is index of attribute that determines constraint
- {{ObjSetMod,ObjSetName},OSDef} =
- case ObjectSet of
- {Module,OSName} ->
- {{{asis,Module},OSName},asn1_db:dbget(Module,OSName)};
- OSName ->
- {{"?MODULE",OSName},asn1_db:dbget(get(currmod),OSName)}
- end,
- case (OSDef#typedef.typespec)#'ObjectSet'.gen of
+ {Module,ObjSetName} = ObjectSet,
+ #typedef{typespec=#'ObjectSet'{gen=Gen}} =
+ asn1_db:dbget(Module, ObjSetName),
+ case Gen of
true ->
ObjectEncode =
asn1ct_gen:un_hyphen_var(lists:concat(['Obj',AttrN])),
- emit([ObjectEncode," = ",nl]),
- emit([" ",ObjSetMod,":'getenc_",ObjSetName,"'(",
- {asis,UniqueFieldName},", ",nl]),
- El = make_element(N+1,asn1ct_gen:mk_var(asn1ct_name:curr(val))),
-
- Length = fun(X,_LFun) when is_atom(X) ->
- length(atom_to_list(X));
- (X,_LFun) when is_list(X) ->
- length(X);
- ({X1,X2},LFun) ->
- LFun(X1,LFun) + LFun(X2,LFun)
- end,
- Indent = 12 + Length(ObjectSet,Length),
- case ValueIndex of
- [] ->
- emit([indent(Indent),El,"),",nl]);
- _ ->
- emit([indent(Indent),"value_match(",
- {asis,ValueIndex},",",El,")),",nl]),
- notice_value_match()
- end,
+ El = make_element(N+1, asn1ct_gen:mk_var(asn1ct_name:curr(val))),
+ ValueMatch = value_match(ValueIndex, El),
+ emit([ObjectEncode," =",nl,
+ " ",{asis,Module},":'getenc_",ObjSetName,"'(",
+ {asis,UniqueFieldName},", ",nl,
+ " ",ValueMatch,"),",nl]),
{AttrN,ObjectEncode};
- _ ->
+ false ->
false
end;
_ ->
@@ -227,7 +208,6 @@ gen_decode_constructed(Erule, Typename, #type{}=D) ->
Imm0 = gen_dec_constructed_imm(Erule, Typename, #type{}=D),
Imm = opt_imm(Imm0),
asn1ct_name:start(),
- asn1ct_name:clear(),
emit_gen_dec_imm(Imm),
emit([".",nl,nl]).
@@ -365,14 +345,10 @@ gen_dec_constructed_imm_2(Typename, CompList,
{[{ObjSet,LeadingAttr,Term}],ListOfOpenTypes} ->
DecObj = asn1ct_gen:un_hyphen_var(lists:concat(['DecObj',LeadingAttr,Term])),
ValueMatch = value_match(ValueIndex,Term),
- {ObjSetMod,ObjSetName} =
- case ObjSet of
- {M,O} -> {{asis,M},O};
- _ -> {"?MODULE",ObjSet}
- end,
- emit({DecObj," =",nl," ",ObjSetMod,":'getdec_",ObjSetName,"'(",
-% {asis,UniqueFName},", ",Term,"),",nl}),
- {asis,UniqueFName},", ",ValueMatch,"),",nl}),
+ {ObjSetMod,ObjSetName} = ObjSet,
+ emit([DecObj," =",nl,
+ " ",{asis,ObjSetMod},":'getdec_",ObjSetName,"'(",
+ {asis,UniqueFName},", ",ValueMatch,"),",nl]),
gen_dec_listofopentypes(DecObj,ListOfOpenTypes,false)
end,
%% we don't return named lists any more Cnames = mkcnamelist(CompList),
@@ -489,7 +465,6 @@ gen_encode_choice(Erule,Typename,D) when is_record(D,type) ->
gen_decode_choice(Erules,Typename,D) when is_record(D,type) ->
asn1ct_name:start(),
- asn1ct_name:clear(),
asn1ct_name:new(bytes),
{'CHOICE',CompList} = D#type.def,
Ext = extensible_enc(CompList),
@@ -504,12 +479,8 @@ gen_encode_sof(Erule,Typename,SeqOrSetOf,D) when is_record(D,type) ->
asn1ct_name:start(),
{_SeqOrSetOf,ComponentType} = D#type.def,
emit({"[",nl}),
- SizeConstraint =
- case asn1ct_gen:get_constraint(D#type.constraint,
- 'SizeConstraint') of
- no -> undefined;
- Range -> Range
- end,
+ SizeConstraint = asn1ct_imm:effective_constraint(bitstring,
+ D#type.constraint),
ObjFun =
case D#type.tablecinf of
[{objfun,_}|_R] ->
@@ -521,13 +492,7 @@ gen_encode_sof(Erule,Typename,SeqOrSetOf,D) when is_record(D,type) ->
emit({indent(3),"'enc_",asn1ct_gen:list2name(Typename),
"_components'(Val",ObjFun,", [])"}),
emit({nl,"].",nl}),
- NewComponentType =
- case ComponentType#type.def of
- {'ENUMERATED',_,Component}->
- ComponentType#type{def={'ENUMERATED',Component}};
- _ -> ComponentType
- end,
- gen_encode_sof_components(Erule,Typename,SeqOrSetOf,NewComponentType).
+ gen_encode_sof_components(Erule, Typename, SeqOrSetOf, ComponentType).
%% Logic copied from asn1_per_bin_rt2ct:encode_constrained_number
@@ -565,7 +530,7 @@ gen_encode_length(per, {Lb,Ub}) when Ub =< 65535, Lb >= 0 ->
gen_encode_length(Erules, SizeConstraint) ->
emit([nl,indent(3),
case SizeConstraint of
- undefined ->
+ no ->
{call,Erules,encode_length,["length(Val)"]};
_ ->
{call,Erules,encode_length,
@@ -576,12 +541,8 @@ gen_encode_length(Erules, SizeConstraint) ->
gen_decode_sof(Erules,Typename,SeqOrSetOf,D) when is_record(D,type) ->
asn1ct_name:start(),
{_SeqOrSetOf,ComponentType} = D#type.def,
- SizeConstraint =
- case asn1ct_gen:get_constraint(D#type.constraint,
- 'SizeConstraint') of
- no -> undefined;
- Range -> Range
- end,
+ SizeConstraint = asn1ct_imm:effective_constraint(bitstring,
+ D#type.constraint),
ObjFun =
case D#type.tablecinf of
[{objfun,_}|_R] ->
@@ -593,13 +554,7 @@ gen_decode_sof(Erules,Typename,SeqOrSetOf,D) when is_record(D,type) ->
emit([",",nl,
"'dec_",asn1ct_gen:list2name(Typename),
"_components'(",Num,", ",Buf,ObjFun,", []).",nl,nl]),
- NewComponentType =
- case ComponentType#type.def of
- {'ENUMERATED',_,Component}->
- ComponentType#type{def={'ENUMERATED',Component}};
- _ -> ComponentType
- end,
- gen_decode_sof_components(Erules,Typename,SeqOrSetOf,NewComponentType).
+ gen_decode_sof_components(Erules, Typename, SeqOrSetOf, ComponentType).
is_aligned(per) -> true;
is_aligned(uper) -> false.
@@ -629,10 +584,9 @@ gen_encode_sof_components(Erule,Typename,SeqOrSetOf,Cont) ->
Conttype = asn1ct_gen:get_inner(Cont#type.def),
Currmod = get(currmod),
- Ctgenmod = asn1ct_gen:ct_gen_module(Erule),
case asn1ct_gen:type(Conttype) of
{primitive,bif} ->
- gen_encode_prim_wrapper(Ctgenmod,Erule,Cont,false,"H");
+ asn1ct_gen_per:gen_encode_prim(Erule, Cont, "H");
{constructed,bif} ->
NewTypename = [Constructed_Suffix|Typename],
emit({"'enc_",asn1ct_gen:list2name(NewTypename),"'(H",
@@ -642,9 +596,9 @@ gen_encode_sof_components(Erule,Typename,SeqOrSetOf,Cont) ->
#'Externaltypereference'{module=EMod,type=EType} ->
emit({"'",EMod,"':'enc_",EType,"'(H)",nl,nl});
'ASN1_OPEN_TYPE' ->
- gen_encode_prim_wrapper(Ctgenmod,Erule,
- #type{def='ASN1_OPEN_TYPE'},
- false,"H");
+ asn1ct_gen_per:gen_encode_prim(Erule,
+ #type{def='ASN1_OPEN_TYPE'},
+ "H");
_ ->
emit({"'enc_",Conttype,"'(H)",nl,nl})
end,
@@ -668,7 +622,6 @@ gen_decode_sof_components(Erule,Typename,SeqOrSetOf,Cont) ->
Cont#type.def),
Conttype = asn1ct_gen:get_inner(Cont#type.def),
Ctgenmod = asn1ct_gen:ct_gen_module(Erule),
- CurrMod = get(currmod),
case asn1ct_gen:type(Conttype) of
{primitive,bif} ->
Ctgenmod:gen_dec_prim(Erule,Cont,"Bytes"),
@@ -677,12 +630,9 @@ gen_decode_sof_components(Erule,Typename,SeqOrSetOf,Cont) ->
NewTypename = [Constructed_Suffix|Typename],
emit({"'dec_",asn1ct_gen:list2name(NewTypename),
"'(Bytes, telltype",ObjFun,"),",nl});
- #typereference{val=Dname} ->
- emit({"'dec_",Dname,"'(Bytes,telltype),",nl});
- #'Externaltypereference'{module=CurrMod,type=EType} ->
- emit({"'dec_",EType,"'(Bytes,telltype),",nl});
- #'Externaltypereference'{module=EMod,type=EType} ->
- emit({"'",EMod,"':'dec_",EType,"'(Bytes,telltype),",nl});
+ #'Externaltypereference'{}=Etype ->
+ asn1ct_gen_per:gen_dec_external(Etype, "Bytes"),
+ emit([com,nl]);
'ASN1_OPEN_TYPE' ->
Ctgenmod:gen_dec_prim(Erule,#type{def='ASN1_OPEN_TYPE'},
"Bytes"),
@@ -1004,7 +954,6 @@ gen_enc_line(Erule,TopType, Cname, Type, [], Pos,DynamicEnc,Ext) ->
Element = make_element(Pos+1,asn1ct_gen:mk_var(asn1ct_name:curr(val))),
gen_enc_line(Erule,TopType,Cname,Type,Element, Pos,DynamicEnc,Ext);
gen_enc_line(Erule,TopType,Cname,Type,Element, _Pos,DynamicEnc,Ext) ->
- Ctgenmod = asn1ct_gen:ct_gen_module(Erule),
Atype =
case Type of
#type{def=#'ObjectClassFieldType'{type=InnerType}} ->
@@ -1026,8 +975,6 @@ gen_enc_line(Erule,TopType,Cname,Type,Element, _Pos,DynamicEnc,Ext) ->
case DynamicEnc of
{_LeadingAttrName,Fun} ->
case (Type#type.def)#'ObjectClassFieldType'.fieldname of
- {notype,T} ->
- throw({error,{notype,type_from_object,T}});
{Name,RestFieldNames} when is_atom(Name) ->
asn1ct_func:need({Erule,complete,1}),
asn1ct_func:need({Erule,encode_open_type,1}),
@@ -1057,29 +1004,17 @@ gen_enc_line(Erule,TopType,Cname,Type,Element, _Pos,DynamicEnc,Ext) ->
#'Externaltypereference'{module=Mod,type=EType} ->
emit({"'",Mod,"':'enc_",
EType,"'(",Element,")"});
- #typereference{val=Ename} ->
- emit({"'enc_",Ename,"'(",Element,")"});
- {notype,_} ->
- emit({"'enc_",Atype,"'(",Element,")"});
{primitive,bif} ->
- EncType =
- case Atype of
- {fixedtypevaluefield,_,Btype} ->
- Btype;
- _ ->
- Type
- end,
- gen_encode_prim_wrapper(Ctgenmod,Erule,EncType,
- false,Element);
+ asn1ct_gen_per:gen_encode_prim(Erule, Type, Element);
'ASN1_OPEN_TYPE' ->
case Type#type.def of
#'ObjectClassFieldType'{type=OpenType} ->
- gen_encode_prim_wrapper(Ctgenmod,Erule,
- #type{def=OpenType},
- false,Element);
+ asn1ct_gen_per:gen_encode_prim(Erule,
+ #type{def=OpenType},
+ Element);
_ ->
- gen_encode_prim_wrapper(Ctgenmod,Erule,Type,
- false,Element)
+ asn1ct_gen_per:gen_encode_prim(Erule, Type,
+ Element)
end;
{constructed,bif} ->
NewTypename = [Cname|TopType],
@@ -1235,68 +1170,67 @@ gen_dec_comp_call(Comp, Erule, TopType, Tpos, OptTable, DecInfObj,
end
end
end,
-
- OptOrDef =
- case {Ext,Prop} of
- {noext,mandatory} ->
- ignore;
- {noext,_} -> %% OPTIONAL or DEFAULT
- OptPos = get_optionality_pos(TextPos, OptTable),
- Element = io_lib:format("Opt band (1 bsl ~w)",
- [NumberOfOptionals - OptPos]),
- fun(St) ->
- emit(["case ",Element," of",nl]),
- emit([" _Opt",TextPos," when _Opt",TextPos," > 0 ->"]),
- St
- end;
- {{ext,_,_},_} -> %Extension
- fun(St) ->
- emit(["case Extensions of",nl,
- " <<_:",Pos-1,",1:1,_/bitstring>> ->",nl]),
- St
- end
- end,
- Lines = gen_dec_line_imm(Erule, TopType, Comp, Tpos, DecInfObj, Ext),
- Postamble =
- case {Ext,Prop} of
- {noext,mandatory} ->
- ignore;
- {noext,_} ->
- fun(St) ->
- emit([";",nl,"0 ->"]),
- emit(["{"]),
- gen_dec_component_no_val(Ext,Prop),
- emit({",",{curr,bytes},"}",nl}),
- emit([nl,"end"]),
- St
- end;
- _ ->
- fun(St) ->
- emit([";",nl,"_ ->",nl]),
- emit(["{"]),
- case Type of
- #type{def=#'SEQUENCE'{
- extaddgroup=Number2,
- components=ExtGroupCompList2}}
- when is_integer(Number2)->
- emit({"{extAddGroup,"}),
- gen_dec_extaddGroup_no_val(Ext,ExtGroupCompList2),
- emit({"}"});
- _ ->
- gen_dec_component_no_val(Ext, Prop)
- end,
- emit({",",{curr,bytes},"}",nl}),
- emit([nl,"end"]),
- St
- end
- end,
+ {Pre,Post} = comp_call_pre_post(Ext, Prop, Pos, Type, TextPos,
+ OptTable, NumberOfOptionals, Ext),
+ Lines = gen_dec_seq_line_imm(Erule, TopType, Comp, Tpos, DecInfObj, Ext),
AdvBuffer = {ignore,fun(St) ->
asn1ct_name:new(bytes),
St
end},
- [{group,[{safe,Comment},{safe,Preamble},
- OptOrDef|Lines]++
- [Postamble,{safe,AdvBuffer}]}].
+ [{group,[{safe,Comment},{safe,Preamble}] ++ Pre ++
+ Lines ++ Post ++ [{safe,AdvBuffer}]}].
+
+comp_call_pre_post(noext, mandatory, _, _, _, _, _, _) ->
+ {[],[]};
+comp_call_pre_post(noext, Prop, _, _, TextPos, OptTable, NumOptionals, Ext) ->
+ %% OPTIONAL or DEFAULT
+ OptPos = get_optionality_pos(TextPos, OptTable),
+ Element = case NumOptionals - OptPos of
+ 0 ->
+ "Opt band 1";
+ Shift ->
+ lists:concat(["(Opt bsr ",Shift,") band 1"])
+ end,
+ {[fun(St) ->
+ emit(["case ",Element," of",nl,
+ "1 ->",nl]),
+ St
+ end],
+ [fun(St) ->
+ emit([";",nl,
+ "0 ->",nl,
+ "{"]),
+ gen_dec_component_no_val(Ext, Prop),
+ emit([",",{curr,bytes},"}",nl,
+ "end"]),
+ St
+ end]};
+comp_call_pre_post({ext,_,_}, Prop, Pos, Type, _, _, _, Ext) ->
+ %% Extension
+ {[fun(St) ->
+ emit(["case Extensions of",nl,
+ " <<_:",Pos-1,",1:1,_/bitstring>> ->",nl]),
+ St
+ end],
+ [fun(St) ->
+ emit([";",nl,
+ "_ ->",nl,
+ "{"]),
+ case Type of
+ #type{def=#'SEQUENCE'{
+ extaddgroup=Number2,
+ components=ExtGroupCompList2}}
+ when is_integer(Number2)->
+ emit("{extAddGroup,"),
+ gen_dec_extaddGroup_no_val(Ext, ExtGroupCompList2),
+ emit("}");
+ _ ->
+ gen_dec_component_no_val(Ext, Prop)
+ end,
+ emit([",",{curr,bytes},"}",nl,
+ "end"]),
+ St
+ end]}.
is_mandatory_predef_tab_c(noext, mandatory,
{"got objfun through args","ObjFun"}) ->
@@ -1324,13 +1258,17 @@ gen_dec_component_no_val({ext,_,_},mandatory) ->
emit({"asn1_NOVALUE"}).
-gen_dec_line(Erule, TopType, Comp, Pos, DecInfObj, Ext) ->
- Imm0 = gen_dec_line_imm(Erule, TopType, Comp, Pos, DecInfObj, Ext),
+gen_dec_choice_line(Erule, TopType, Comp, Pre) ->
+ Imm0 = gen_dec_line_imm(Erule, TopType, Comp, false, Pre),
Init = {ignore,fun(_) -> {[],[]} end},
Imm = [{group,[Init|Imm0]}],
emit_gen_dec_imm(Imm).
-gen_dec_line_imm(Erule, TopType, Comp, Pos, DecInfObj, Ext) ->
+gen_dec_seq_line_imm(Erule, TopType, Comp, Pos, DecInfObj, Ext) ->
+ Pre = gen_dec_line_open_type(Erule, Ext, Pos),
+ gen_dec_line_imm(Erule, TopType, Comp, DecInfObj, Pre).
+
+gen_dec_line_imm(Erule, TopType, Comp, DecInfObj, Pre) ->
#'ComponentType'{name=Cname,typespec=Type} = Comp,
Atype =
case Type of
@@ -1339,9 +1277,7 @@ gen_dec_line_imm(Erule, TopType, Comp, Pos, DecInfObj, Ext) ->
_ ->
asn1ct_gen:get_inner(Type#type.def)
end,
-
- Pre = gen_dec_line_open_type(Erule, Ext, Pos),
- Decode = gen_dec_line_special(Erule, Atype, TopType, Comp, DecInfObj, Ext),
+ Decode = gen_dec_line_special(Erule, Atype, TopType, Comp, DecInfObj),
Post =
fun({SaveBytes,Finish}) ->
{AccTerm,AccBytes} = Finish(),
@@ -1385,7 +1321,7 @@ gen_dec_line_open_type(_, _, _) ->
end}.
gen_dec_line_special(Erule, {typefield,_}, _TopType, Comp,
- DecInfObj, Ext) ->
+ DecInfObj) ->
#'ComponentType'{name=Cname,typespec=Type,prop=Prop} = Comp,
fun({_BytesVar,PrevSt}) ->
case DecInfObj of
@@ -1417,7 +1353,7 @@ gen_dec_line_special(Erule, {typefield,_}, _TopType, Comp,
%% objfun though arguments on function
%% invocation.
if
- Ext == noext andalso Prop == mandatory ->
+ Prop =:= mandatory ->
ok;
true ->
asn1ct_name:new(tmpterm),
@@ -1431,7 +1367,7 @@ gen_dec_line_special(Erule, {typefield,_}, _TopType, Comp,
asn1ct_imm:dec_code_gen(Imm, BytesVar),
emit([com,nl]),
if
- Ext == noext andalso Prop == mandatory ->
+ Prop =:= mandatory ->
emit([{curr,term}," =",nl," "]);
true ->
emit([" {"])
@@ -1448,7 +1384,7 @@ gen_dec_line_special(Erule, {typefield,_}, _TopType, Comp,
emit([indent(6),{curr,tmpterm},nl]),
emit([indent(2),"end"]),
if
- Ext == noext andalso Prop == mandatory ->
+ Prop =:= mandatory ->
ok;
true ->
emit([",",nl,{curr,tmpbytes},"}"])
@@ -1468,7 +1404,7 @@ gen_dec_line_special(Erule, {typefield,_}, _TopType, Comp,
end
end;
gen_dec_line_special(Erule, {objectfield,PrimFieldName1,PFNList}, _TopType,
- Comp, _DecInfObj, _Ext) ->
+ Comp, _DecInfObj) ->
fun({_BytesVar,PrevSt}) ->
Imm = asn1ct_imm:per_dec_open_type(is_aligned(Erule)),
BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
@@ -1480,7 +1416,7 @@ gen_dec_line_special(Erule, {objectfield,PrimFieldName1,PFNList}, _TopType,
Prop}],
{SaveBytes,PrevSt}
end;
-gen_dec_line_special(Erule, Atype, TopType, Comp, DecInfObj, _Ext) ->
+gen_dec_line_special(Erule, Atype, TopType, Comp, DecInfObj) ->
case gen_dec_line_other(Erule, Atype, TopType, Comp) of
Fun when is_function(Fun, 1) ->
fun({BytesVar,PrevSt}) ->
@@ -1503,38 +1439,24 @@ gen_dec_line_dec_inf(Comp, DecInfObj) ->
{Cname,{_,OSet,UniqueFName,ValIndex}} ->
Term = asn1ct_gen:mk_var(asn1ct_name:curr(term)),
ValueMatch = value_match(ValIndex,Term),
- {ObjSetMod,ObjSetName} =
- case OSet of
- {M,O} -> {{asis,M},O};
- _ -> {"?MODULE",OSet}
- end,
- emit({",",nl,"ObjFun = ",ObjSetMod,
+ {ObjSetMod,ObjSetName} = OSet,
+ emit([",",nl,
+ "ObjFun = ",{asis,ObjSetMod},
":'getdec_",ObjSetName,"'(",
- {asis,UniqueFName},", ",ValueMatch,")"});
+ {asis,UniqueFName},", ",ValueMatch,")"]);
_ ->
ok
end.
gen_dec_line_other(Erule, Atype, TopType, Comp) ->
#'ComponentType'{name=Cname,typespec=Type} = Comp,
- CurrMod = get(currmod),
case asn1ct_gen:type(Atype) of
- #'Externaltypereference'{module=CurrMod,type=EType} ->
+ #'Externaltypereference'{}=Etype ->
fun(BytesVar) ->
- emit({"'dec_",EType,"'(",BytesVar,",telltype)"})
- end;
- #'Externaltypereference'{module=Mod,type=EType} ->
- fun(BytesVar) ->
- emit({"'",Mod,"':'dec_",EType,"'(",BytesVar,
- ",telltype)"})
+ asn1ct_gen_per:gen_dec_external(Etype, BytesVar)
end;
{primitive,bif} ->
- case Atype of
- {fixedtypevaluefield,_,Btype} ->
- asn1ct_gen_per:gen_dec_imm(Erule, Btype);
- _ ->
- asn1ct_gen_per:gen_dec_imm(Erule, Type)
- end;
+ asn1ct_gen_per:gen_dec_imm(Erule, Type);
'ASN1_OPEN_TYPE' ->
case Type#type.def of
#'ObjectClassFieldType'{type=OpenType} ->
@@ -1542,14 +1464,6 @@ gen_dec_line_other(Erule, Atype, TopType, Comp) ->
_ ->
asn1ct_gen_per:gen_dec_imm(Erule, Type)
end;
- #typereference{val=Dname} ->
- fun(BytesVar) ->
- emit({"'dec_",Dname,"'(",BytesVar,",telltype)"})
- end;
- {notype,_} ->
- fun(BytesVar) ->
- emit({"'dec_",Atype,"'(",BytesVar,",telltype)"})
- end;
{constructed,bif} ->
NewTypename = [Cname|TopType],
case Type#type.tablecinf of
@@ -1605,16 +1519,14 @@ get_name_list([], Acc) ->
gen_enc_choice2(Erule,TopType, {L1,L2}, Ext) ->
- gen_enc_choice2(Erule,TopType, L1 ++ L2, 0, Ext);
-gen_enc_choice2(Erule,TopType, {L1,L2,L3}, Ext) ->
- gen_enc_choice2(Erule,TopType, L1 ++ L3 ++ L2, 0, Ext);
+ gen_enc_choice2(Erule, TopType, L1 ++ L2, 0, [], Ext);
+gen_enc_choice2(Erule, TopType, {L1,L2,L3}, Ext) ->
+ gen_enc_choice2(Erule, TopType, L1 ++ L3 ++ L2, 0, [], Ext);
gen_enc_choice2(Erule,TopType, L, Ext) ->
- gen_enc_choice2(Erule,TopType, L, 0, Ext).
+ gen_enc_choice2(Erule,TopType, L, 0, [], Ext).
-gen_enc_choice2(Erule,TopType,[H1,H2|T], Pos, Ext)
-when is_record(H1,'ComponentType'), is_record(H2,'ComponentType') ->
- Cname = H1#'ComponentType'.name,
- Type = H1#'ComponentType'.typespec,
+gen_enc_choice2(Erule, TopType, [H|T], Pos, Sep0, Ext) ->
+ #'ComponentType'{name=Cname,typespec=Type} = H,
EncObj =
case asn1ct_gen:get_constraint(Type#type.constraint,
componentrelation) of
@@ -1622,130 +1534,157 @@ when is_record(H1,'ComponentType'), is_record(H2,'ComponentType') ->
case Type#type.tablecinf of
[{objfun,_}|_] ->
{"got objfun through args","ObjFun"};
- _ ->false
- end;
- _ -> {no_attr,"ObjFun"}
- end,
- emit({{asis,Cname}," ->",nl}),
- DoExt = case Ext of
- {ext,ExtPos,_} when (Pos + 1) < ExtPos -> noext;
- _ -> Ext
- end,
- gen_enc_line(Erule,TopType,Cname,Type,"element(2,Val)",
- Pos+1,EncObj,DoExt),
- emit({";",nl}),
- gen_enc_choice2(Erule,TopType,[H2|T], Pos+1, Ext);
-gen_enc_choice2(Erule,TopType,[H1|T], Pos, Ext)
- when is_record(H1,'ComponentType') ->
- Cname = H1#'ComponentType'.name,
- Type = H1#'ComponentType'.typespec,
- EncObj =
- case asn1ct_gen:get_constraint(Type#type.constraint,
- componentrelation) of
- no ->
- case Type#type.tablecinf of
- [{objfun,_}|_] ->
- {"got objfun through args","ObjFun"};
- _ ->false
+ _ ->
+ false
end;
- _ -> {no_attr,"ObjFun"}
+ _ ->
+ {no_attr,"ObjFun"}
end,
- emit({{asis,H1#'ComponentType'.name}," ->",nl}),
+ emit([Sep0,{asis,Cname}," ->",nl]),
DoExt = case Ext of
- {ext,ExtPos,_} when (Pos + 1) < ExtPos -> noext;
+ {ext,ExtPos,_} when Pos + 1 < ExtPos -> noext;
_ -> Ext
end,
- gen_enc_line(Erule,TopType,Cname,Type,"element(2,Val)",
- Pos+1,EncObj,DoExt),
- gen_enc_choice2(Erule,TopType,T, Pos+1, Ext);
-gen_enc_choice2(_Erule,_,[], _, _) ->
- true.
+ gen_enc_line(Erule, TopType, Cname, Type, "element(2, Val)",
+ Pos+1, EncObj, DoExt),
+ Sep = [";",nl],
+ gen_enc_choice2(Erule, TopType, T, Pos+1, Sep, Ext);
+gen_enc_choice2(_, _, [], _, _, _) -> ok.
+
+%% Generate the code for CHOICE. If the CHOICE is extensible,
+%% the structure of the generated code is as follows:
+%%
+%% case Bytes of
+%% <<0:1,Bytes1/bitstring>> ->
+%% Choice = <Decode INTEGER (0..LastRootChoice) from Bytes1>
+%% case Choice of
+%% 0 -> <Decode>;
+%% :
+%% LastRootChoice -> <Decode>
+%% end;
+%% <<1:1,Bytes1/bitstring>> ->
+%% Choice = <Decode normally small number from Bytes1>
+%% TmpVal = <Decode open type>
+%% case Choice of
+%% 0 -> <Decode TmpVal>;
+%% :
+%% LastExtension -> <Decode TmpVal>;
+%% _ -> <Return TmpVal since the type is unknown>
+%% end
+%% end
+%%
+%% The return value from the generated function always looks like:
+%% {{ChoiceTag,Value},RemainingBuffer}
+%% where ChoiceTag will be 'asn1_ExtAlt' for an unknown extension.
+%%
+%% If the CHOICE is not extensible, the top-level case is omitted
+%% and only the code in the first case arm is generated.
-gen_dec_choice(Erule,TopType,CompList,{ext,Pos,NumExt}) ->
- emit(["{Ext,",{curr,bytes},"} = ",
- {call,Erule,getbit,["Bytes"]},com,nl]),
+gen_dec_choice(Erule, TopType, CompList, {ext,_,_}=Ext) ->
+ {RootList,ExtList} = split_complist(CompList),
+ emit(["case Bytes of",nl]),
+ case RootList of
+ [] ->
+ ok;
+ [_|_] ->
+ emit(["<<0:1,Bytes1/bitstring>> ->",nl]),
+ asn1ct_name:new(bytes),
+ gen_dec_choice1(Erule, TopType, RootList, noext),
+ emit([";",nl,nl])
+ end,
+ emit(["<<1:1,Bytes1/bitstring>> ->",nl]),
+ asn1ct_name:clear(),
+ asn1ct_name:new(bytes),
asn1ct_name:new(bytes),
- gen_dec_choice1(Erule,TopType,CompList,{ext,Pos,NumExt});
-gen_dec_choice(Erule,TopType,CompList,noext) ->
- gen_dec_choice1(Erule,TopType,CompList,noext).
-
-gen_dec_choice1(Erule,TopType,CompList,noext) ->
- emit(["{Choice,",{curr,bytes},
- "} = ",{call,Erule,getchoice,
- [{prev,bytes},length(CompList),"0"]},com,nl,
- "{Cname,{Val,NewBytes}} = case Choice of",nl]),
- gen_dec_choice2(Erule,TopType,CompList,noext),
- emit({nl,"end,",nl}),
- emit({nl,"{{Cname,Val},NewBytes}"});
-gen_dec_choice1(Erule,TopType,{RootList,ExtList},Ext) ->
- NewList = RootList ++ ExtList,
- gen_dec_choice1(Erule,TopType, NewList, Ext);
-gen_dec_choice1(Erule,TopType,{RootList,ExtList,RootList2},Ext) ->
- NewList = RootList ++ RootList2 ++ ExtList,
- gen_dec_choice1(Erule,TopType, NewList, Ext);
-gen_dec_choice1(Erule,TopType,CompList,{ext,ExtPos,ExtNum}) ->
- emit(["{Choice,",{curr,bytes},"} = ",
- {call,Erule,getchoice,
- [{prev,bytes},length(CompList)-ExtNum,"Ext"]},com,nl]),
- emit({"{Cname,{Val,NewBytes}} = case Choice + Ext*",ExtPos-1," of",nl}),
- gen_dec_choice2(Erule,TopType,CompList,{ext,ExtPos,ExtNum}),
+ gen_dec_choice1(Erule, TopType, ExtList, Ext),
+ emit([nl,"end"]);
+gen_dec_choice(Erule, TopType, CompList, noext) ->
+ gen_dec_choice1(Erule, TopType, CompList, noext).
+
+split_complist({Root1,Ext,Root2}) ->
+ {Root1++Root2,Ext};
+split_complist({_,_}=CompList) ->
+ CompList.
+
+gen_dec_choice1(Erule, TopType, CompList, noext=Ext) ->
+ emit_getchoice(Erule, CompList, Ext),
+ emit(["case Choice of",nl]),
+ Pre = {safe,fun(St) ->
+ {asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
+ fun() -> St end}
+ end},
+ gen_dec_choice2(Erule, TopType, CompList, Pre),
+ emit([nl,"end"]);
+gen_dec_choice1(Erule, TopType, CompList, {ext,_,_}=Ext) ->
+ emit_getchoice(Erule, CompList, Ext),
Imm = asn1ct_imm:per_dec_open_type(is_aligned(Erule)),
+ emit(["begin",nl]),
BytesVar = asn1ct_gen:mk_var(asn1ct_name:curr(bytes)),
- emit([";",nl,
- "_ ->",nl]),
- {TmpTerm,TmpBuf} = asn1ct_imm:dec_slim_cg(Imm, BytesVar),
- emit([com,nl,
- "{asn1_ExtAlt,{",TmpTerm,com,TmpBuf,"}}",nl,
- "end,",nl,nl,
- "{{Cname,Val},NewBytes}"]).
-
+ {Dst,DstBuf} = asn1ct_imm:dec_slim_cg(Imm, BytesVar),
+ emit([nl,
+ "end,",nl,
+ "case Choice of",nl]),
+ Pre = {safe,fun(St) ->
+ emit(["{TmpVal,_} = "]),
+ {Dst,
+ fun() ->
+ emit([",",nl,
+ "{TmpVal,",DstBuf,"}"]),
+ St
+ end}
+ end},
+ gen_dec_choice2(Erule, TopType, CompList, Pre),
+ case CompList of
+ [] -> ok;
+ [_|_] -> emit([";",nl])
+ end,
+ emit(["_ ->",nl,
+ "{{asn1_ExtAlt,",Dst,"},",DstBuf,"}",nl,
+ "end"]).
+
+emit_getchoice(Erule, CompList, Ext) ->
+ Al = is_aligned(Erule),
+ Imm = case {Ext,CompList} of
+ {noext,[_]} ->
+ {value,0};
+ {noext,_} ->
+ asn1ct_imm:per_dec_constrained(0, length(CompList)-1, Al);
+ {{ext,_,_},_} ->
+ asn1ct_imm:per_dec_normally_small_number(Al)
+ end,
+ emit(["{Choice,",{curr,bytes},"} = ",nl]),
+ BytesVar = asn1ct_gen:mk_var(asn1ct_name:prev(bytes)),
+ asn1ct_imm:dec_code_gen(Imm, BytesVar),
+ emit([com,nl]).
gen_dec_choice2(Erule,TopType,L,Ext) ->
- gen_dec_choice2(Erule,TopType,L,0,Ext).
+ gen_dec_choice2(Erule, TopType, L, 0, [], Ext).
-gen_dec_choice2(Erule,TopType,[H1,H2|T],Pos,Ext)
-when is_record(H1,'ComponentType'), is_record(H2,'ComponentType') ->
- Cname = H1#'ComponentType'.name,
- Type = H1#'ComponentType'.typespec,
+gen_dec_choice2(Erule, TopType, [H0|T], Pos, Sep0, Pre) ->
+ #'ComponentType'{name=Cname,typespec=Type} = H0,
+ H = H0#'ComponentType'{prop=mandatory},
+ emit([Sep0,Pos," ->",nl]),
case Type#type.def of
#'ObjectClassFieldType'{type={typefield,_}} ->
- emit({Pos," -> ",nl}),
- wrap_gen_dec_line(Erule,H1,TopType,Cname,Type,Pos+1,false,Ext),
- emit({";",nl});
- _ ->
- emit({Pos," -> {",{asis,Cname},",",nl}),
- wrap_gen_dec_line(Erule,H1,TopType,Cname,Type,Pos+1,false,Ext),
- emit({"};",nl})
- end,
- gen_dec_choice2(Erule,TopType,[H2|T],Pos+1,Ext);
-gen_dec_choice2(Erule,TopType,[H1,_H2|T],Pos,Ext) when is_record(H1,'ComponentType') ->
- gen_dec_choice2(Erule,TopType,[H1|T],Pos,Ext); % skip extensionmark
-gen_dec_choice2(Erule,TopType,[H1|T],Pos,Ext) when is_record(H1,'ComponentType') ->
- Cname = H1#'ComponentType'.name,
- Type = H1#'ComponentType'.typespec,
- case Type#type.def of
- #'ObjectClassFieldType'{type={typefield,_}} ->
- emit({Pos," -> ",nl}),
- wrap_gen_dec_line(Erule,H1,TopType,Cname,Type,Pos+1,false,Ext);
+ emit("{Cname,{Val,NewBytes}} = begin\n"),
+ gen_dec_choice_line(Erule, TopType, H, Pre),
+ emit([nl,
+ "end,",nl,
+ "{{Cname,Val},NewBytes}"]);
_ ->
- emit({Pos," -> {",{asis,Cname},",",nl}),
- wrap_gen_dec_line(Erule,H1,TopType,Cname,Type,Pos+1,false,Ext),
- emit("}")
+ emit("{Val,NewBytes} = begin\n"),
+ gen_dec_choice_line(Erule, TopType, H, Pre),
+ emit([nl,
+ "end,",nl,
+ "{{",{asis,Cname},",Val},NewBytes}"])
end,
- gen_dec_choice2(Erule,TopType,[T],Pos+1);
-gen_dec_choice2(Erule,TopType,[_|T],Pos,Ext) ->
- gen_dec_choice2(Erule,TopType,T,Pos,Ext);% skip extensionmark
-gen_dec_choice2(_,_,[],Pos,_) ->
- Pos.
+ Sep = [";",nl],
+ gen_dec_choice2(Erule, TopType, T, Pos+1, Sep, Pre);
+gen_dec_choice2(_, _, [], _, _, _) -> ok.
indent(N) ->
lists:duplicate(N,32). % 32 = space
-gen_encode_prim_wrapper(CtgenMod,Erule,Cont,DoTag,Value) ->
-% put(component_type,true), % add more info in component_type
- CtgenMod:gen_encode_prim(Erule,Cont,DoTag,Value).
-% erase(component_type).
-
make_elements(I,Val,ExtCnames) ->
make_elements(I,Val,ExtCnames,[]).
@@ -1816,14 +1755,6 @@ wrap_extensionAdditionGroups([H|T],ExtAddGrpLenPos,Acc,ExtAddGroupDiff,ExtGroupN
wrap_extensionAdditionGroups([],_,Acc,_,_) ->
lists:reverse(Acc).
-
-wrap_gen_dec_line(Erule,C,TopType,_Cname,_Type,Pos,DIO,Ext) ->
- put(component_type,{true,C}),
- gen_dec_line(Erule, TopType, C#'ComponentType'{prop=mandatory},
- Pos, DIO, Ext),
- erase(component_type).
-
-
value_match(Index,Value) when is_atom(Value) ->
value_match(Index,atom_to_list(Value));
value_match([],Value) ->
@@ -1835,9 +1766,5 @@ value_match1(Value,[],Acc,Depth) ->
value_match1(Value,[{VI,_}|VIs],Acc,Depth) ->
value_match1(Value,VIs,Acc++lists:concat(["element(",VI,","]),Depth+1).
-notice_value_match() ->
- Module = get(currmod),
- put(value_match,{true,Module}).
-
is_optimized(per) -> true;
is_optimized(uper) -> false.
diff --git a/lib/asn1/src/asn1ct_func.erl b/lib/asn1/src/asn1ct_func.erl
index 2d221ca1b9..262bef6862 100644
--- a/lib/asn1/src/asn1ct_func.erl
+++ b/lib/asn1/src/asn1ct_func.erl
@@ -37,9 +37,13 @@ need(MFA) ->
cast({need,MFA}).
generate(Fd) ->
- req({generate,Fd}),
+ Used0 = req(get_used),
erase(?MODULE),
- ok.
+ Used = sofs:set(Used0, [mfa]),
+ Code = sofs:relation(asn1ct_rtt:code(), [{mfa,code}]),
+ Funcs0 = sofs:image(Code, Used),
+ Funcs = sofs:to_external(Funcs0),
+ ok = file:write(Fd, Funcs).
req(Req) ->
gen_server:call(get(?MODULE), Req, infinity).
@@ -64,9 +68,8 @@ handle_cast({need,MFA}, #st{used=Used0}=St) ->
{noreply,St}
end.
-handle_call({generate,Fd}, _From, #st{used=Used}=St) ->
- generate(Fd, Used),
- {stop,normal,ok,St}.
+handle_call(get_used, _From, #st{used=Used}=St) ->
+ {stop,normal,gb_sets:to_list(Used),St}.
terminate(_, _) ->
ok.
@@ -75,14 +78,6 @@ call_args([A|As], Sep) ->
[Sep,A|call_args(As, ", ")];
call_args([], _) -> [].
-generate(Fd, Used0) ->
- Used1 = gb_sets:to_list(Used0),
- Used = sofs:set(Used1, [mfa]),
- Code = sofs:relation(asn1ct_rtt:code(), [{mfa,code}]),
- Funcs0 = sofs:image(Code, Used),
- Funcs = sofs:to_external(Funcs0),
- io:put_chars(Fd, Funcs).
-
pull_in_deps(Ws0, Used0) ->
case gb_sets:is_empty(Ws0) of
true ->
diff --git a/lib/asn1/src/asn1ct_gen.erl b/lib/asn1/src/asn1ct_gen.erl
index 76c4182160..9095e145a3 100644
--- a/lib/asn1/src/asn1ct_gen.erl
+++ b/lib/asn1/src/asn1ct_gen.erl
@@ -21,15 +21,9 @@
-include("asn1_records.hrl").
--export([pgen_exports/3,
- pgen_hrl/5,
- gen_head/3,
- demit/1,
+-export([demit/1,
emit/1,
get_inner/1,type/1,def_to_tag/1,prim_bif/1,
- type_from_object/1,
- get_typefromobject/1,get_fieldcategory/2,
- get_classfieldcategory/2,
list2name/1,
list2rname/1,
constructed_suffix/2,
@@ -41,7 +35,6 @@
index2suffix/1,
get_record_name_prefix/0]).
-export([pgen/5,
- pgen_module/6,
mk_var/1,
un_hyphen_var/1]).
-export([gen_encode_constructed/4,
@@ -75,7 +68,7 @@ pgen_module(OutFile,Erules,Module,
HrlGenerated = pgen_hrl(Erules,Module,TypeOrVal,Options,Indent),
asn1ct_name:start(),
ErlFile = lists:concat([OutFile,".erl"]),
- Fid = fopen(ErlFile,[write]),
+ Fid = fopen(ErlFile),
put(gen_file_out,Fid),
asn1ct_func:start_link(),
gen_head(Erules,Module,HrlGenerated),
@@ -115,8 +108,7 @@ pgen_values(Erules,Module,[H|T]) ->
gen_value(Valuedef),
pgen_values(Erules,Module,T).
-pgen_types(_,_,_,Module,[]) ->
- gen_value_match(Module),
+pgen_types(_, _, _, _, []) ->
true;
pgen_types(Rtmod,Erules,N2nConvEnums,Module,[H|T]) ->
asn1ct_name:clear(),
@@ -580,22 +572,6 @@ gen_types(Erules,Tname,Type) when is_record(Type,type) ->
asn1ct_name:clear(),
Rtmod:gen_decode(Erules,Tname,Type).
-gen_value_match(Module) ->
- case get(value_match) of
- {true,Module} ->
- emit(["value_match([{Index,Cname}|Rest],Value) ->",nl,
- " Value2 =",nl,
- " case element(Index,Value) of",nl,
- " {Cname,Val2} -> Val2;",nl,
- " X -> X",nl,
- " end,",nl,
- " value_match(Rest,Value2);",nl,
- "value_match([],Value) ->",nl,
- " Value.",nl]);
- _ -> ok
- end,
- put(value_match,undefined).
-
gen_check_defaultval(Erules,Module,[{Name,Type}|Rest]) ->
gen_check_func(Name,Type),
gen_check_defaultval(Erules,Module,Rest);
@@ -1131,7 +1107,7 @@ pgen_info() ->
open_hrl(OutFile,Module) ->
File = lists:concat([OutFile,".hrl"]),
- Fid = fopen(File,[write]),
+ Fid = fopen(File),
put(gen_file_out,Fid),
gen_hrlhead(Module).
@@ -1146,80 +1122,67 @@ demit(Term) ->
end.
% always generation
+emit(Term) ->
+ ok = file:write(get(gen_file_out), do_emit(Term)).
-emit({external,_M,T}) ->
- emit(T);
+do_emit({external,_M,T}) ->
+ do_emit(T);
-emit({prev,Variable}) when is_atom(Variable) ->
- emit({var,asn1ct_name:prev(Variable)});
+do_emit({prev,Variable}) when is_atom(Variable) ->
+ do_emit({var,asn1ct_name:prev(Variable)});
-emit({next,Variable}) when is_atom(Variable) ->
- emit({var,asn1ct_name:next(Variable)});
+do_emit({next,Variable}) when is_atom(Variable) ->
+ do_emit({var,asn1ct_name:next(Variable)});
-emit({curr,Variable}) when is_atom(Variable) ->
- emit({var,asn1ct_name:curr(Variable)});
+do_emit({curr,Variable}) when is_atom(Variable) ->
+ do_emit({var,asn1ct_name:curr(Variable)});
-emit({var,Variable}) when is_atom(Variable) ->
+do_emit({var,Variable}) when is_atom(Variable) ->
[Head|V] = atom_to_list(Variable),
- emit([Head-32|V]);
+ [Head-32|V];
-emit({var,Variable}) ->
+do_emit({var,Variable}) ->
[Head|V] = Variable,
- emit([Head-32|V]);
-
-emit({asis,What}) ->
- format(get(gen_file_out),"~w",[What]);
-
-emit({call,M,F,A}) ->
- asn1ct_func:call(M, F, A);
-
-emit(nl) ->
- nl(get(gen_file_out));
-
-emit(com) ->
- emit(",");
+ [Head-32|V];
-emit(tab) ->
- put_chars(get(gen_file_out)," ");
+do_emit({asis,What}) ->
+ io_lib:format("~w", [What]);
-emit(What) when is_integer(What) ->
- put_chars(get(gen_file_out),integer_to_list(What));
+do_emit({call,M,F,A}) ->
+ MFA = {M,F,length(A)},
+ asn1ct_func:need(MFA),
+ [atom_to_list(F),"(",call_args(A, "")|")"];
-emit(What) when is_list(What), is_integer(hd(What)) ->
- put_chars(get(gen_file_out),What);
+do_emit(nl) ->
+ "\n";
-emit(What) when is_atom(What) ->
- put_chars(get(gen_file_out),atom_to_list(What));
+do_emit(com) ->
+ ",";
-emit(What) when is_tuple(What) ->
- emit_parts(tuple_to_list(What));
+do_emit(tab) ->
+ " ";
-emit(What) when is_list(What) ->
- emit_parts(What);
+do_emit(What) when is_integer(What) ->
+ integer_to_list(What);
-emit(X) ->
- exit({'cant emit ',X}).
+do_emit(What) when is_list(What), is_integer(hd(What)) ->
+ What;
-emit_parts([]) -> true;
-emit_parts([H|T]) ->
- emit(H),
- emit_parts(T).
+do_emit(What) when is_atom(What) ->
+ atom_to_list(What);
-format(undefined,X,Y) ->
- io:format(X,Y);
-format(X,Y,Z) ->
- io:format(X,Y,Z).
+do_emit(What) when is_tuple(What) ->
+ [do_emit(E) || E <- tuple_to_list(What)];
-nl(undefined) -> io:nl();
-nl(X) -> io:nl(X).
+do_emit(What) when is_list(What) ->
+ [do_emit(E) || E <- What].
-put_chars(undefined,X) ->
- io:put_chars(X);
-put_chars(Y,X) ->
- io:put_chars(Y,X).
+call_args([A|As], Sep) ->
+ [Sep,do_emit(A)|call_args(As, ", ")];
+call_args([], _) -> [].
-fopen(F, ModeList) ->
- case file:open(F, ModeList) of
+fopen(F) ->
+ case file:open(F, [write,raw,delayed_write]) of
{ok, Fd} ->
Fd;
{error, Reason} ->
@@ -1671,7 +1634,6 @@ unify_if_string(PrimType) ->
get_inner(A) when is_atom(A) -> A;
get_inner(Ext) when is_record(Ext,'Externaltypereference') -> Ext;
-get_inner(Tref) when is_record(Tref,typereference) -> Tref;
get_inner({fixedtypevaluefield,_,Type}) ->
if
is_record(Type,type) ->
@@ -1704,8 +1666,6 @@ get_inner(T) when is_tuple(T) ->
type(X) when is_record(X,'Externaltypereference') ->
X;
-type(X) when is_record(X,typereference) ->
- X;
type('ASN1_OPEN_TYPE') ->
'ASN1_OPEN_TYPE';
type({fixedtypevaluefield,_Name,Type}) when is_record(Type,type) ->
@@ -1713,15 +1673,6 @@ type({fixedtypevaluefield,_Name,Type}) when is_record(Type,type) ->
type({typefield,_}) ->
'ASN1_OPEN_TYPE';
type(X) ->
- %% io:format("asn1_types:type(~p)~n",[X]),
- case catch type2(X) of
- {'EXIT',_} ->
- {notype,X};
- Normal ->
- Normal
- end.
-
-type2(X) ->
case prim_bif(X) of
true ->
{primitive,bif};
@@ -1740,7 +1691,6 @@ prim_bif(X) ->
'REAL',
'OBJECT IDENTIFIER',
'RELATIVE-OID',
- 'ANY',
'NULL',
'BIT STRING' ,
'OCTET STRING' ,
@@ -1784,15 +1734,6 @@ def_to_tag(Def) ->
%% Information Object Class
-type_from_object(X) ->
- case (catch lists:last(element(2,X))) of
- {'EXIT',_} ->
- {notype,X};
- Normal ->
- Normal
- end.
-
-
get_fieldtype([],_FieldName)->
{no_type,no_name};
get_fieldtype([Field|Rest],FieldName) ->
@@ -1808,34 +1749,6 @@ get_fieldtype([Field|Rest],FieldName) ->
get_fieldtype(Rest,FieldName)
end.
-get_fieldcategory([],_FieldName) ->
- no_cat;
-get_fieldcategory([Field|Rest],FieldName) ->
- case element(2,Field) of
- FieldName ->
- element(1,Field);
- _ ->
- get_fieldcategory(Rest,FieldName)
- end.
-
-get_typefromobject(Type) when is_record(Type,type) ->
- case Type#type.def of
- {{objectclass,_,_},TypeFrObj} when is_list(TypeFrObj) ->
- {_,FieldName} = lists:last(TypeFrObj),
- FieldName;
- _ ->
- {no_field}
- end.
-
-get_classfieldcategory(Type,FieldName) ->
- case (catch Type#type.def) of
- {{obejctclass,Fields,_},_} ->
- get_fieldcategory(Fields,FieldName);
- {'EXIT',_} ->
- no_cat;
- _ ->
- no_cat
- end.
%% Information Object Class
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1902,7 +1815,7 @@ index2suffix(N) ->
ct_gen_module(ber) ->
asn1ct_gen_ber_bin_v2;
ct_gen_module(per) ->
- asn1ct_gen_per_rt2ct;
+ asn1ct_gen_per;
ct_gen_module(uper) ->
asn1ct_gen_per.
diff --git a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl
index de0adef2b2..8ab49aec2c 100644
--- a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl
+++ b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl
@@ -24,9 +24,7 @@
-include("asn1_records.hrl").
--export([pgen/4]).
-export([decode_class/1, decode_type/1]).
--export([add_removed_bytes/0]).
-export([gen_encode/2,gen_encode/3,gen_decode/2,gen_decode/3]).
-export([gen_encode_prim/4]).
-export([gen_dec_prim/7]).
@@ -59,18 +57,6 @@
-define(T_VisibleString, ?UNIVERSAL bor ?PRIMITIVE bor 26). %can be constructed
-define(T_GeneralString, ?UNIVERSAL bor ?PRIMITIVE bor 27). %can be constructed
-%% pgen(Erules, Module, TypeOrVal)
-%% Generate Erlang module (.erl) and (.hrl) file corresponding to an ASN.1 module
-%% .hrl file is only generated if necessary
-%% Erules = per | ber
-%% Module = atom()
-%% TypeOrVal = {TypeList,ValueList,PTypeList}
-%% TypeList = ValueList = [atom()]
-
-pgen(OutFile,Erules,Module,TypeOrVal) ->
- asn1ct_gen:pgen_module(OutFile,Erules,Module,TypeOrVal,[],true).
-
-
%%===============================================================================
%%===============================================================================
%%===============================================================================
@@ -83,8 +69,8 @@ pgen(OutFile,Erules,Module,TypeOrVal) ->
%% encode #{typedef, {pos, name, typespec}}
%%===============================================================================
-gen_encode(Erules,Type) when is_record(Type,typedef) ->
- gen_encode_user(Erules,Type).
+gen_encode(Erules, #typedef{}=D) ->
+ gen_encode_user(Erules, #typedef{}=D, true).
%%===============================================================================
%% encode #{type, {tag, def, constraint}}
@@ -134,20 +120,28 @@ gen_encode(Erules,Tname,#'ComponentType'{name=Cname,typespec=Type}) ->
NewType = Type#type{tag=[]},
gen_encode(Erules,NewTname,NewType).
-gen_encode_user(Erules,D) when is_record(D,typedef) ->
+gen_encode_user(Erules, #typedef{}=D, Wrapper) ->
Typename = [D#typedef.name],
Type = D#typedef.typespec,
InnerType = asn1ct_gen:get_inner(Type#type.def),
- OTag = Type#type.tag,
- Tag = [encode_tag_val(decode_class(X#tag.class),X#tag.form,X#tag.number)|| X <- OTag],
emit([nl,nl,"%%================================"]),
emit([nl,"%% ",Typename]),
emit([nl,"%%================================",nl]),
- emit(["'enc_",asn1ct_gen:list2name(Typename),
- "'(Val",") ->",nl]),
- emit([" 'enc_",asn1ct_gen:list2name(Typename),
- "'(Val, ", {asis,lists:reverse(Tag)},").",nl,nl]),
- emit({"'enc_",asn1ct_gen:list2name(Typename),"'(Val, TagIn) ->",nl}),
+ FuncName = "'enc_" ++ asn1ct_gen:list2name(Typename) ++ "'",
+ case Wrapper of
+ true ->
+ %% This is a top-level type. Generate an 'enc_Type'/1
+ %% wrapper.
+ OTag = Type#type.tag,
+ Tag0 = [encode_tag_val(decode_class(Class), Form, Number) ||
+ #tag{class=Class,form=Form,number=Number} <- OTag],
+ Tag = lists:reverse(Tag0),
+ emit([FuncName,"(Val) ->",nl,
+ " ",FuncName,"(Val, ",{asis,Tag},").",nl,nl]);
+ false ->
+ ok
+ end,
+ emit([FuncName,"(Val, TagIn) ->",nl]),
CurrentMod = get(currmod),
case asn1ct_gen:type(InnerType) of
{constructed,bif} ->
@@ -155,8 +149,6 @@ gen_encode_user(Erules,D) when is_record(D,typedef) ->
{primitive,bif} ->
gen_encode_prim(ber,Type,"TagIn","Val"),
emit([".",nl]);
- #typereference{val=Ename} ->
- emit([" 'enc_",Ename,"'(Val, TagIn).",nl]);
#'Externaltypereference'{module=CurrentMod,type=Etype} ->
emit([" 'enc_",Etype,"'(Val, TagIn).",nl]);
#'Externaltypereference'{module=Emod,type=Etype} ->
@@ -169,8 +161,8 @@ gen_encode_user(Erules,D) when is_record(D,typedef) ->
emit([".",nl])
end.
-gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
- BitStringConstraint = D#type.constraint,
+gen_encode_prim(_Erules, #type{}=D, DoTag, Value) ->
+ BitStringConstraint = get_size_constraint(D#type.constraint),
asn1ct_name:new(enumval),
Type = case D#type.def of
'OCTET STRING' -> restricted_string;
@@ -184,6 +176,8 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
'GeneralString' -> restricted_string;
'PrintableString' -> restricted_string;
'IA5String' -> restricted_string;
+ 'UTCTime' -> restricted_string;
+ 'GeneralizedTime' -> restricted_string;
Other -> Other
end,
case Type of
@@ -208,8 +202,6 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
call(encode_bit_string,
[{asis,BitStringConstraint},Value,
{asis,NamedNumberList},DoTag]);
- 'ANY' ->
- call(encode_open_type, [Value,DoTag]);
'NULL' ->
call(encode_null, [Value,DoTag]);
'OBJECT IDENTIFIER' ->
@@ -222,19 +214,8 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
call(encode_UTF8_string, [Value,DoTag]);
'BMPString' ->
call(encode_BMP_string, [Value,DoTag]);
- 'UTCTime' ->
- call(encode_utc_time, [Value,DoTag]);
- 'GeneralizedTime' ->
- call(encode_generalized_time, [Value,DoTag]);
'ASN1_OPEN_TYPE' ->
- call(encode_open_type, [Value,DoTag]);
- #'ObjectClassFieldType'{} ->
- case asn1ct_gen:get_inner(D#type.def) of
- {fixedtypevaluefield,_,InnerType} ->
- gen_encode_prim(Erules,InnerType,DoTag,Value);
- 'ASN1_OPEN_TYPE' ->
- call(encode_open_type, [Value,DoTag])
- end
+ call(encode_open_type, [Value,DoTag])
end.
emit_enc_enumerated_cases({L1,L2}, Tags) ->
@@ -470,32 +451,18 @@ gen_decode_user(Erules,D) when is_record(D,typedef) ->
end.
-gen_dec_prim(Erules,Att,BytesVar,DoTag,TagIn,Form,OptOrMand) ->
+gen_dec_prim(_Erules, Att, BytesVar, DoTag, _TagIn, _Form, _OptOrMand) ->
Typename = Att#type.def,
%% Currently not used for BER replaced with [] as place holder
%% Constraint = Att#type.constraint,
%% Constraint = [],
- Constraint =
- case get_constraint(Att#type.constraint,'SizeConstraint') of
- no -> [];
- Tc -> Tc
- end,
- ValueRange =
- case get_constraint(Att#type.constraint,'ValueRange') of
- no -> [];
- Tv -> Tv
- end,
- SingleValue =
- case get_constraint(Att#type.constraint,'SingleValue') of
- no -> [];
- Sv -> Sv
- end,
+ Constraint = get_size_constraint(Att#type.constraint),
+ IntConstr = int_constr(Att#type.constraint),
AsBin = case get(binary_strings) of
true -> "_as_bin";
_ -> ""
end,
NewTypeName = case Typename of
- 'ANY' -> 'ASN1_OPEN_TYPE';
'OCTET STRING' -> restricted_string;
'NumericString' -> restricted_string;
'TeletexString' -> restricted_string;
@@ -506,6 +473,9 @@ gen_dec_prim(Erules,Att,BytesVar,DoTag,TagIn,Form,OptOrMand) ->
'GeneralString' -> restricted_string;
'PrintableString' -> restricted_string;
'IA5String' -> restricted_string;
+ 'ObjectDescriptor'-> restricted_string;
+ 'UTCTime' -> restricted_string;
+ 'GeneralizedTime' -> restricted_string;
_ -> Typename
end,
case NewTypeName of
@@ -513,14 +483,27 @@ gen_dec_prim(Erules,Att,BytesVar,DoTag,TagIn,Form,OptOrMand) ->
emit(["decode_boolean(",BytesVar,","]),
need(decode_boolean, 2);
'INTEGER' ->
- emit(["decode_integer(",BytesVar,",",
- {asis,int_constr(SingleValue,ValueRange)},","]),
- need(decode_integer, 3);
+ case IntConstr of
+ [] ->
+ emit(["decode_integer(",BytesVar,","]),
+ need(decode_integer, 2);
+ {_,_} ->
+ emit(["decode_integer(",BytesVar,",",
+ {asis,IntConstr},","]),
+ need(decode_integer, 3)
+ end;
{'INTEGER',NamedNumberList} ->
- emit(["decode_integer(",BytesVar,",",
- {asis,int_constr(SingleValue,ValueRange)},",",
- {asis,NamedNumberList},","]),
- need(decode_integer, 4);
+ case IntConstr of
+ [] ->
+ emit(["decode_named_integer(",BytesVar,",",
+ {asis,NamedNumberList},","]),
+ need(decode_named_integer, 3);
+ {_,_} ->
+ emit(["decode_named_integer(",BytesVar,",",
+ {asis,IntConstr},",",
+ {asis,NamedNumberList},","]),
+ need(decode_named_integer, 4)
+ end;
{'ENUMERATED',NamedNumberList} ->
emit(["decode_enumerated(",BytesVar,",",
{asis,NamedNumberList},","]),
@@ -538,10 +521,6 @@ gen_dec_prim(Erules,Att,BytesVar,DoTag,TagIn,Form,OptOrMand) ->
'RELATIVE-OID' ->
emit(["decode_relative_oid(",BytesVar,","]),
need(decode_relative_oid, 2);
- 'ObjectDescriptor' ->
- emit(["decode_restricted_string(",
- BytesVar,",",{asis,Constraint},","]),
- need(decode_restricted_string, 3);
restricted_string ->
emit(["decode_restricted_string",AsBin,"(",BytesVar,","]),
case Constraint of
@@ -563,31 +542,10 @@ gen_dec_prim(Erules,Att,BytesVar,DoTag,TagIn,Form,OptOrMand) ->
emit(["decode_BMP_string",AsBin,"(",
BytesVar,",",{asis,Constraint},","]),
need(decode_BMP_string, 3);
- 'UTCTime' ->
- emit(["decode_utc_time",AsBin,"(",
- BytesVar,",",{asis,Constraint},","]),
- need(decode_utc_time, 3);
- 'GeneralizedTime' ->
- emit(["decode_generalized_time",AsBin,"(",
- BytesVar,",",{asis,Constraint},","]),
- need(decode_generalized_time, 3);
'ASN1_OPEN_TYPE' ->
emit(["decode_open_type_as_binary(",
BytesVar,","]),
- need(decode_open_type_as_binary, 2);
- #'ObjectClassFieldType'{} ->
- case asn1ct_gen:get_inner(Att#type.def) of
- {fixedtypevaluefield,_,InnerType} ->
- gen_dec_prim(Erules,InnerType,BytesVar,DoTag,TagIn,Form,OptOrMand);
- 'ASN1_OPEN_TYPE' ->
- emit(["decode_open_type_as_binary(",
- BytesVar,","]),
- need(decode_open_type_as_binary, 2);
- Other ->
- exit({'cannot decode',Other})
- end;
- Other ->
- exit({'cannot decode',Other})
+ need(decode_open_type_as_binary, 2)
end,
TagStr = case DoTag of
@@ -604,25 +562,27 @@ gen_dec_prim(Erules,Att,BytesVar,DoTag,TagIn,Form,OptOrMand) ->
{call,ber,match_tags,[BytesVar,TagStr]},com,nl,
{call,real_common,decode_real,[{curr,tmpbuf}]},nl,
"end",nl]);
- #'ObjectClassFieldType'{} ->
- case asn1ct_gen:get_inner(Att#type.def) of
- 'ASN1_OPEN_TYPE' ->
- emit([TagStr,")"]);
- _ -> ok
- end;
_ ->
emit([TagStr,")"])
end.
-
-int_constr([],[]) ->
- [];
-int_constr([],ValueRange) ->
- ValueRange;
-int_constr(SingleValue,[]) ->
- SingleValue;
-int_constr(SV,VR) ->
- [SV,VR].
+%% Simplify an integer constraint so that we can efficiently test it.
+-spec int_constr(term()) -> [] | {integer(),integer()|'MAX'}.
+int_constr(C) ->
+ case asn1ct_imm:effective_constraint(integer, C) of
+ [{_,[]}] ->
+ %% Extension - ignore constraint.
+ [];
+ [{'ValueRange',{'MIN',_}}] ->
+ %% Tricky to implement efficiently - ignore it.
+ [];
+ [{'ValueRange',{_,_}=Range}] ->
+ Range;
+ [{'SingleValue',Sv}] ->
+ {Sv,Sv};
+ [] ->
+ []
+ end.
gen_dec_bit_string(BytesVar, _Constraint, [_|_]=NNL, TagStr) ->
call(decode_named_bit_string,
@@ -664,9 +624,7 @@ gen_obj_code(Erules,_Module,Obj) when is_record(Obj,typedef) ->
ObjName,Fields,[]),
emit(nl),
gen_decode_constr_type(Erules,DecConstructed),
- emit_tlv_format_function();
-gen_obj_code(_Erules,_Module,Obj) when is_record(Obj,pobjectdef) ->
- ok.
+ emit_tlv_format_function().
gen_encode_objectfields(ClassName,[{typefield,Name,OptOrMand}|Rest],
ObjName,ObjectFields,ConstrAcc) ->
@@ -757,7 +715,7 @@ gen_encode_objectfields(_,[],_,_,Acc) ->
gen_encode_constr_type(Erules,[TypeDef|Rest]) when is_record(TypeDef,typedef) ->
case is_already_generated(enc,TypeDef#typedef.name) of
true -> ok;
- _ -> gen_encode_user(Erules,TypeDef)
+ false -> gen_encode_user(Erules, TypeDef, false)
end,
gen_encode_constr_type(Erules,Rest);
gen_encode_constr_type(_,[]) ->
@@ -815,8 +773,8 @@ gen_encode_default_call(ClassName,FieldName,Type) ->
Tag = [encode_tag_val(decode_class(X#tag.class),X#tag.form,X#tag.number)|| X <- OTag],
case asn1ct_gen:type(InnerType) of
{constructed,bif} ->
-%% asn1ct_gen:gen_encode_constructed(Erules,Typename,InnerType,Type);
- emit([" 'enc_",ClassName,'_',FieldName,"'(Bytes)"]),
+ emit([" 'enc_",ClassName,'_',FieldName,"'",
+ "(Val, ",{asis,Tag},")"]),
[#typedef{name=list_to_atom(lists:concat([ClassName,'_',FieldName])),
typespec=Type}];
{primitive,bif} ->
@@ -964,7 +922,10 @@ gen_decode_constr_type(Erules,[TypeDef|Rest]) when is_record(TypeDef,typedef) ->
case is_already_generated(dec,TypeDef#typedef.name) of
true -> ok;
_ ->
- gen_decode(Erules,TypeDef)
+ emit([nl,nl,
+ "'dec_",TypeDef#typedef.name,
+ "'(Tlv, TagIn) ->",nl]),
+ gen_decode_user(Erules, TypeDef)
end,
gen_decode_constr_type(Erules,Rest);
gen_decode_constr_type(_,[]) ->
@@ -1108,54 +1069,29 @@ gen_objset_enc(_,_,{unique,undefined},_,_,_,_,_) ->
%% There is no unique field in the class of this object set
%% don't bother about the constraint
[];
-gen_objset_enc(Erules,ObjSName,UniqueName,
- [{ObjName,Val,Fields},T|Rest],ClName,ClFields,
+gen_objset_enc(Erules, ObjSetName, UniqueName,
+ [{ObjName,Val,Fields}|T], ClName, ClFields,
NthObj,Acc)->
- emit({"'getenc_",ObjSName,"'(",{asis,UniqueName},",",{asis,Val},
- ") ->",nl}),
+ emit(["'getenc_",ObjSetName,"'(",{asis,UniqueName},",",{asis,Val},
+ ") ->",nl]),
CurrMod = get(currmod),
{InternalFunc,NewNthObj}=
case ObjName of
{no_mod,no_name} ->
- gen_inlined_enc_funs(Fields,ClFields,ObjSName,NthObj);
- {CurrMod,Name} ->
- emit({" fun 'enc_",Name,"'/3"}),
- {[],NthObj};
- {ModuleName,Name} ->
- emit_ext_fun(enc,ModuleName,Name),
-% emit([" {'",ModuleName,"', 'enc_",Name,"'}"]),
- {[],NthObj};
- _ ->
- emit({" fun 'enc_",ObjName,"'/3"}),
- {[],NthObj}
- end,
- emit({";",nl}),
- gen_objset_enc(Erules,ObjSName,UniqueName,[T|Rest],ClName,ClFields,
- NewNthObj,InternalFunc ++ Acc);
-gen_objset_enc(_,ObjSetName,UniqueName,
- [{ObjName,Val,Fields}],_ClName,ClFields,NthObj,Acc) ->
- emit({"'getenc_",ObjSetName,"'(",{asis,UniqueName},",",
- {asis,Val},") ->",nl}),
- CurrMod = get(currmod),
- {InternalFunc,_} =
- case ObjName of
- {no_mod,no_name} ->
gen_inlined_enc_funs(Fields,ClFields,ObjSetName,NthObj);
{CurrMod,Name} ->
emit({" fun 'enc_",Name,"'/3"}),
{[],NthObj};
{ModuleName,Name} ->
emit_ext_fun(enc,ModuleName,Name),
-% emit([" {'",ModuleName,"', 'enc_",Name,"'}"]),
{[],NthObj};
_ ->
emit({" fun 'enc_",ObjName,"'/3"}),
{[],NthObj}
end,
- emit([";",nl]),
- emit_default_getenc(ObjSetName,UniqueName),
- emit({".",nl,nl}),
- InternalFunc ++ Acc;
+ emit({";",nl}),
+ gen_objset_enc(Erules, ObjSetName, UniqueName, T, ClName, ClFields,
+ NewNthObj, InternalFunc ++ Acc);
%% See X.681 Annex E for the following case
gen_objset_enc(_,ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName,
_ClFields,_NthObj,Acc) ->
@@ -1167,7 +1103,9 @@ gen_objset_enc(_,ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName,
emit({indent(6),"{Val,Len}",nl}),
emit({indent(3),"end.",nl,nl}),
Acc;
-gen_objset_enc(_,_,_,[],_,_,_,Acc) ->
+gen_objset_enc(_, ObjSetName, UniqueName, [], _, _, _, Acc) ->
+ emit_default_getenc(ObjSetName, UniqueName),
+ emit({".",nl,nl}),
Acc.
emit_ext_fun(EncDec,ModuleName,Name) ->
@@ -1181,78 +1119,34 @@ emit_default_getenc(ObjSetName,UniqueName) ->
%% gen_inlined_enc_funs for each object iterates over all fields of a
%% class, and for each typefield it checks if the object has that
%% field and emits the proper code.
-gen_inlined_enc_funs(Fields,[{typefield,Name,_}|Rest],
- ObjSetName,NthObj) ->
- CurrMod = get(currmod),
- InternalDefFunName = asn1ct_gen:list2name([NthObj,Name,ObjSetName]),
- case lists:keysearch(Name,1,Fields) of
- {value,{_,Type}} when is_record(Type,type) ->
- emit({indent(3),"fun(Type, Val, _RestPrimFieldName) ->",nl,
- indent(6),"case Type of",nl}),
- {Ret,N}=emit_inner_of_fun(Type,InternalDefFunName),
- gen_inlined_enc_funs1(Fields,Rest,ObjSetName,NthObj+N,Ret);
- {value,{_,Type}} when is_record(Type,typedef) ->
- emit({indent(3),"fun(Type, Val, _RestPrimFieldName) ->",nl,
- indent(6),"case Type of",nl}),
- emit({indent(9),{asis,Name}," ->",nl}),
- {Ret,N}=emit_inner_of_fun(Type,InternalDefFunName),
- gen_inlined_enc_funs1(Fields,Rest,ObjSetName,NthObj+N,Ret);
- {value,{_,#'Externaltypereference'{module=M,type=T}}} ->
- emit([indent(3),"fun(Type, Val, _RestPrimFieldName) ->",nl,
- indent(6),"case Type of",nl]),
- emit([indent(9),{asis,Name}," ->",nl]),
- if
- M == CurrMod ->
- emit([indent(12),"'enc_",T,"'(Val)"]);
- true ->
- #typedef{typespec=Type} = asn1_db:dbget(M,T),
- OTag = Type#type.tag,
-%% Tag = [encode_tag_val((decode_class(X#tag.class) bsl 10) +
-%% X#tag.number) ||
-%% X <- OTag],
- Tag = [encode_tag_val(decode_class(X#tag.class),
- X#tag.form,X#tag.number) ||
- X <- OTag],
- emit([indent(12),"'",M,"':'enc_",T,"'(Val, ",{asis,Tag},")"])
- end,
- gen_inlined_enc_funs1(Fields,Rest,ObjSetName,NthObj,[]);
- false ->
- %% This field was not present in the object thus there
- %% were no type in the table and we therefore generate
- %% code that returns the input for application treatment.
- emit([indent(3),"fun(Type, Val, _RestPrimFieldName) ->",nl,
- indent(6),"case Type of",nl,
- indent(9),{asis,Name}," ->",nl,
- indent(12),"Len = case Val of",nl,
- indent(15),"B when is_binary(B) -> size(B);",nl,
- indent(15),"_ -> length(Val)",nl,
- indent(12),"end,",nl,
- indent(12),"{Val,Len}"]),
- gen_inlined_enc_funs1(Fields,Rest,ObjSetName,NthObj,[])
- end;
+gen_inlined_enc_funs(Fields, [{typefield,_,_}|_]=T, ObjSetName, NthObj) ->
+ emit([indent(3),"fun(Type, Val, _RestPrimFieldName) ->",nl,
+ indent(6),"case Type of",nl]),
+ gen_inlined_enc_funs1(Fields, T, ObjSetName, [], NthObj, []);
gen_inlined_enc_funs(Fields,[_|Rest],ObjSetName,NthObj) ->
gen_inlined_enc_funs(Fields,Rest,ObjSetName,NthObj);
gen_inlined_enc_funs(_,[],_,NthObj) ->
{[],NthObj}.
-gen_inlined_enc_funs1(Fields,[{typefield,Name,_}|Rest],ObjSetName,
- NthObj,Acc) ->
+gen_inlined_enc_funs1(Fields, [{typefield,Name,_}|Rest], ObjSetName,
+ Sep0, NthObj, Acc0) ->
+ emit(Sep0),
+ Sep = [";",nl],
CurrMod = get(currmod),
InternalDefFunName = asn1ct_gen:list2name([NthObj,Name,ObjSetName]),
- {Acc2,NAdd}=
- case lists:keysearch(Name,1,Fields) of
- {value,{_,Type}} when is_record(Type,type) ->
- emit({";",nl}),
- {Ret,N}=emit_inner_of_fun(Type,InternalDefFunName),
- {Ret++Acc,N};
- {value,{_,Type}} when is_record(Type,typedef) ->
- emit({";",nl,indent(9),{asis,Name}," ->",nl}),
- {Ret,N}=emit_inner_of_fun(Type,InternalDefFunName),
- {Ret++Acc,N};
- {value,{_,#'Externaltypereference'{module=M,type=T}}} ->
- emit({";",nl,indent(9),{asis,Name}," ->",nl}),
+ {Acc,NAdd} =
+ case lists:keyfind(Name,1,Fields) of
+ {_,#type{}=Type} ->
+ {Ret,N} = emit_inner_of_fun(Type,InternalDefFunName),
+ {Ret++Acc0,N};
+ {_,#typedef{}=Type} ->
+ emit([indent(9),{asis,Name}," ->",nl]),
+ {Ret,N} = emit_inner_of_fun(Type, InternalDefFunName),
+ {Ret++Acc0,N};
+ {_,#'Externaltypereference'{module=M,type=T}} ->
+ emit([indent(9),{asis,Name}," ->",nl]),
if
- M == CurrMod ->
+ M =:= CurrMod ->
emit([indent(12),"'enc_",T,"'(Val)"]);
true ->
#typedef{typespec=Type} = asn1_db:dbget(M,T),
@@ -1260,27 +1154,30 @@ gen_inlined_enc_funs1(Fields,[{typefield,Name,_}|Rest],ObjSetName,
Tag = [encode_tag_val(decode_class(X#tag.class),
X#tag.form,X#tag.number) ||
X <- OTag],
- emit([indent(12),"'",M,"':'enc_",T,"'(Val, ",{asis,Tag},")"])
+ emit([indent(12),"'",M,"':'enc_",T,"'(Val, ",
+ {asis,Tag},")"])
end,
- {Acc,0};
+ {Acc0,0};
false ->
%% This field was not present in the object thus there
%% were no type in the table and we therefore generate
%% code that returns the input for application
%% treatment.
- emit([";",nl,indent(9),{asis,Name}," ->",nl]),
- emit([indent(12),"Len = case Val of",nl,
- indent(15),"Bin when is_binary(Bin) -> byte_size(Bin);",nl,
- indent(15),"_ -> length(Val)",nl,indent(12),"end,",nl,
+ emit([indent(9),{asis,Name}," ->",nl,
+ indent(12),"Len = case Val of",nl,
+ indent(15),"Bin when is_binary(Bin) -> "
+ "byte_size(Bin);",nl,
+ indent(15),"_ -> length(Val)",nl,
+ indent(12),"end,",nl,
indent(12),"{Val,Len}"]),
- {Acc,0}
+ {Acc0,0}
end,
- gen_inlined_enc_funs1(Fields,Rest,ObjSetName,NthObj+NAdd,Acc2);
-gen_inlined_enc_funs1(Fields,[_|Rest],ObjSetName,NthObj,Acc)->
- gen_inlined_enc_funs1(Fields,Rest,ObjSetName,NthObj,Acc);
-gen_inlined_enc_funs1(_,[],_,NthObj,Acc) ->
- emit({nl,indent(6),"end",nl}),
- emit({indent(3),"end"}),
+ gen_inlined_enc_funs1(Fields, Rest, ObjSetName, Sep, NthObj+NAdd, Acc);
+gen_inlined_enc_funs1(Fields,[_|Rest], ObjSetName, Sep, NthObj, Acc)->
+ gen_inlined_enc_funs1(Fields, Rest, ObjSetName, Sep, NthObj, Acc);
+gen_inlined_enc_funs1(_, [], _, _, NthObj, Acc) ->
+ emit([nl,indent(6),"end",nl,
+ indent(3),"end"]),
{Acc,NthObj}.
emit_inner_of_fun(TDef=#typedef{name={ExtMod,Name},typespec=Type},
@@ -1319,10 +1216,6 @@ emit_inner_of_fun(Type,_) when is_record(Type,type) ->
X#tag.form,X#tag.number)||X <- OTag],
emit([indent(9),Def," ->",nl,indent(12)]),
gen_encode_prim(ber,Type,{asis,lists:reverse(Tag)},"Val");
- TRef when is_record(TRef,typereference) ->
- T = TRef#typereference.val,
- emit([indent(9),T," ->",nl,indent(12),"'enc_",T,
- "'(Val)"]);
#'Externaltypereference'{module=CurrMod,type=T} ->
emit([indent(9),T," ->",nl,indent(12),"'enc_",T,
"'(Val)"]);
@@ -1345,8 +1238,8 @@ gen_objset_dec(_,_,{unique,undefined},_,_,_,_) ->
%% There is no unique field in the class of this object set
%% don't bother about the constraint
ok;
-gen_objset_dec(Erules,ObjSName,UniqueName,[{ObjName,Val,Fields},T|Rest],
- ClName,ClFields,NthObj)->
+gen_objset_dec(Erules, ObjSName, UniqueName, [{ObjName,Val,Fields}|T],
+ ClName, ClFields, NthObj)->
emit(["'getdec_",ObjSName,"'(",{asis,UniqueName},",",
{asis,Val},") ->",nl]),
CurrMod = get(currmod),
@@ -1359,35 +1252,14 @@ gen_objset_dec(Erules,ObjSName,UniqueName,[{ObjName,Val,Fields},T|Rest],
NthObj;
{ModuleName,Name} ->
emit_ext_fun(dec,ModuleName,Name),
-% emit([" {'",ModuleName,"', 'dec_",Name,"'}"]),
NthObj;
_ ->
emit([" fun 'dec_",ObjName,"'/3"]),
NthObj
end,
emit([";",nl]),
- gen_objset_dec(Erules,ObjSName,UniqueName,[T|Rest],ClName,
- ClFields,NewNthObj);
-gen_objset_dec(_,ObjSetName,UniqueName,[{ObjName,Val,Fields}],
- _ClName,ClFields,NthObj) ->
- emit(["'getdec_",ObjSetName,"'(",{asis,UniqueName},",",
- {asis,Val},") ->",nl]),
- CurrMod = get(currmod),
- case ObjName of
- {no_mod,no_name} ->
- gen_inlined_dec_funs(Fields,ClFields,ObjSetName,NthObj);
- {CurrMod,Name} ->
- emit([" fun 'dec_",Name,"'/3"]);
- {ModuleName,Name} ->
- emit_ext_fun(dec,ModuleName,Name);
-% emit([" {'",ModuleName,"', 'dec_",Name,"'}"]);
- _ ->
- emit([" fun 'dec_",ObjName,"'/3"])
- end,
- emit([";",nl]),
- emit_default_getdec(ObjSetName,UniqueName),
- emit([".",nl,nl]),
- ok;
+ gen_objset_dec(Erules, ObjSName, UniqueName, T, ClName,
+ ClFields, NewNthObj);
gen_objset_dec(_,ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName,
_ClFields,_NthObj) ->
emit(["'getdec_",ObjSetName,"'(_, _) ->",nl]),
@@ -1401,86 +1273,41 @@ gen_objset_dec(_,ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName,
indent(4),"end",nl]),
emit([indent(2),"end.",nl,nl]),
ok;
-gen_objset_dec(_,_,_,[],_,_,_) ->
+gen_objset_dec(_, ObjSetName, UniqueName, [], _, _, _) ->
+ emit_default_getdec(ObjSetName, UniqueName),
+ emit([".",nl,nl]),
ok.
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"]).
-gen_inlined_dec_funs(Fields,[{typefield,Name,Prop}|Rest],
- ObjSetName,NthObj) ->
- DecProp = case Prop of
- 'OPTIONAL' -> opt_or_default;
- {'DEFAULT',_} -> opt_or_default;
- _ -> mandatory
- end,
- CurrMod = get(currmod),
- InternalDefFunName = [NthObj,Name,ObjSetName],
- case lists:keysearch(Name,1,Fields) of
- {value,{_,Type}} when is_record(Type,type) ->
- emit([indent(3),"fun(Type, Bytes, _RestPrimFieldName) ->",
- nl,indent(6),"case Type of",nl]),
- N=emit_inner_of_decfun(Type,DecProp,InternalDefFunName),
- gen_inlined_dec_funs1(Fields,Rest,ObjSetName,NthObj+N);
- {value,{_,Type}} when is_record(Type,typedef) ->
- emit([indent(3),"fun(Type, Bytes, _RestPrimFieldName) ->",
- nl,indent(6),"case Type of",nl]),
- emit([indent(9),{asis,Name}," ->",nl]),
- N=emit_inner_of_decfun(Type,DecProp,InternalDefFunName),
- gen_inlined_dec_funs1(Fields,Rest,ObjSetName,NthObj+N);
- {value,{_,#'Externaltypereference'{module=M,type=T}}} ->
- emit([indent(3),"fun(Type, Bytes, _RestPrimFieldName) ->",
- nl,indent(6),"case Type of",nl]),
- emit([indent(9),{asis,Name}," ->",nl]),
- if
- M == CurrMod ->
- emit([indent(12),"'dec_",T,"'(Bytes)"]);
- true ->
- #typedef{typespec=Type} = asn1_db:dbget(M,T),
- OTag = Type#type.tag,
- Tag = [(decode_class(X#tag.class) bsl 10) + X#tag.number ||
- X <- OTag],
- emit([indent(12),"'",M,"':'dec_",T,"'(Bytes, ",{asis,Tag},")"])
- end,
- gen_inlined_dec_funs1(Fields,Rest,ObjSetName,NthObj);
- false ->
- emit([indent(3),"fun(Type, Bytes, _RestPrimFieldName) ->",
- nl,indent(6),"case Type of",nl,
- indent(9),{asis,Name}," ->",nl,
- indent(12),"Len = case Bytes of",nl,
- indent(15),"B when is_binary(B) -> byte_size(B);",nl,
- indent(15),"_ -> length(Bytes)",nl,
- indent(12),"end,",nl,
- indent(12),"{Bytes,[],Len}"]),
- gen_inlined_dec_funs1(Fields,Rest,ObjSetName,NthObj)
- end;
-gen_inlined_dec_funs(Fields,[_H|Rest],ObjSetName,NthObj) ->
- gen_inlined_dec_funs(Fields,Rest,ObjSetName,NthObj);
-gen_inlined_dec_funs(_,[],_,NthObj) ->
- NthObj.
+gen_inlined_dec_funs(Fields, ClFields, ObjSetName, NthObj) ->
+ emit([indent(3),"fun(Type, Bytes, _RestPrimFieldName) ->",nl,
+ indent(6),"case Type of",nl]),
+ gen_inlined_dec_funs1(Fields, ClFields, ObjSetName, "", NthObj).
-gen_inlined_dec_funs1(Fields,[{typefield,Name,Prop}|Rest],
- ObjSetName,NthObj) ->
+gen_inlined_dec_funs1(Fields, [{typefield,Name,Prop}|Rest],
+ ObjSetName, Sep0, NthObj) ->
+ emit(Sep0),
+ Sep = [";",nl],
DecProp = case Prop of
'OPTIONAL' -> opt_or_default;
{'DEFAULT',_} -> opt_or_default;
_ -> mandatory
end,
- CurrMod = get(currmod),
InternalDefFunName = [NthObj,Name,ObjSetName],
- N=
- case lists:keysearch(Name,1,Fields) of
- {value,{_,Type}} when is_record(Type,type) ->
- emit([";",nl]),
+ N = case lists:keyfind(Name, 1, Fields) of
+ {_,#type{}=Type} ->
emit_inner_of_decfun(Type,DecProp,InternalDefFunName);
- {value,{_,Type}} when is_record(Type,typedef) ->
- emit([";",nl,indent(9),{asis,Name}," ->",nl]),
+ {_,#typedef{}=Type} ->
+ emit([indent(9),{asis,Name}," ->",nl]),
emit_inner_of_decfun(Type,DecProp,InternalDefFunName);
- {value,{_,#'Externaltypereference'{module=M,type=T}}} ->
- emit([";",nl,indent(9),{asis,Name}," ->",nl]),
+ {_,#'Externaltypereference'{module=M,type=T}} ->
+ emit([indent(9),{asis,Name}," ->",nl]),
+ CurrMod = get(currmod),
if
- M == CurrMod ->
+ M =:= CurrMod ->
emit([indent(12),"'dec_",T,"'(Bytes)"]);
true ->
#typedef{typespec=Type} = asn1_db:dbget(M,T),
@@ -1491,21 +1318,20 @@ gen_inlined_dec_funs1(Fields,[{typefield,Name,Prop}|Rest],
end,
0;
false ->
- emit([";",nl,
- indent(9),{asis,Name}," ->",nl,
+ emit([indent(9),{asis,Name}," ->",nl,
indent(12),"Len = case Bytes of",nl,
- indent(15),"B when is_binary(B) -> size(B);",nl,
+ indent(15),"B when is_binary(B) -> byte_size(B);",nl,
indent(15),"_ -> length(Bytes)",nl,
indent(12),"end,",nl,
indent(12),"{Bytes,[],Len}"]),
0
end,
- gen_inlined_dec_funs1(Fields,Rest,ObjSetName,NthObj+N);
-gen_inlined_dec_funs1(Fields,[_|Rest],ObjSetName,NthObj)->
- gen_inlined_dec_funs1(Fields,Rest,ObjSetName,NthObj);
-gen_inlined_dec_funs1(_,[],_,NthObj) ->
- emit([nl,indent(6),"end",nl]),
- emit([indent(3),"end"]),
+ gen_inlined_dec_funs1(Fields, Rest, ObjSetName, Sep, NthObj+N);
+gen_inlined_dec_funs1(Fields, [_|Rest], ObjSetName, Sep, NthObj)->
+ gen_inlined_dec_funs1(Fields, Rest, ObjSetName, Sep, NthObj);
+gen_inlined_dec_funs1(_, [], _, _, NthObj) ->
+ emit([nl,indent(6),"end",nl,
+ indent(3),"end"]),
NthObj.
emit_inner_of_decfun(#typedef{name={ExtName,Name},typespec=Type},Prop,
@@ -1561,10 +1387,9 @@ emit_inner_of_decfun(Type,Prop,_) when is_record(Type,type) ->
gen_internal_funcs(_,[]) ->
ok;
gen_internal_funcs(Erules,[TypeDef|Rest]) ->
- gen_encode_user(Erules,TypeDef),
- emit([nl,nl,"'dec_",TypeDef#typedef.name,
-% "'(Tlv, OptOrMand, TagIn) ->",nl]),
- "'(Tlv, TagIn) ->",nl]),
+ gen_encode_user(Erules, TypeDef, false),
+ emit([nl,nl,
+ "'dec_",TypeDef#typedef.name,"'(Tlv, TagIn) ->",nl]),
gen_decode_user(Erules,TypeDef),
gen_internal_funcs(Erules,Rest).
@@ -1615,46 +1440,23 @@ decode_type('BMPString') -> 30;
decode_type('CHOICE') -> 'CHOICE'; % choice gets the tag from the actual alternative
decode_type(Else) -> exit({error,{asn1,{unrecognized_type,Else}}}).
-add_removed_bytes() ->
- asn1ct_name:delete(rb),
- add_removed_bytes(asn1ct_name:all(rb)).
-
-add_removed_bytes([H,T1|T]) ->
- emit({{var,H},"+"}),
- add_removed_bytes([T1|T]);
-add_removed_bytes([H|T]) ->
- emit({{var,H}}),
- add_removed_bytes(T);
-add_removed_bytes([]) ->
- true.
-
-mkfuncname(WhatKind,DecOrEnc) ->
- case WhatKind of
- #'Externaltypereference'{module=Mod,type=EType} ->
- CurrMod = get(currmod),
- case CurrMod of
- Mod ->
- lists:concat(["'",DecOrEnc,"_",EType,"'"]);
- _ ->
-% io:format("CurrMod: ~p, Mod: ~p~n",[CurrMod,Mod]),
- lists:concat(["'",Mod,"':'",DecOrEnc,"_",EType,"'"])
- end;
- #'typereference'{val=EType} ->
+mkfuncname(#'Externaltypereference'{module=Mod,type=EType}, DecOrEnc) ->
+ CurrMod = get(currmod),
+ case CurrMod of
+ Mod ->
lists:concat(["'",DecOrEnc,"_",EType,"'"]);
- 'ASN1_OPEN_TYPE' ->
- lists:concat(["'",DecOrEnc,"_",WhatKind,"'"])
-
+ _ ->
+ lists:concat(["'",Mod,"':'",DecOrEnc,"_",EType,"'"])
end.
-get_constraint(C,Key) ->
- case lists:keysearch(Key,1,C) of
- false ->
- no;
- {value,{_,V}} ->
- V
+get_size_constraint(C) ->
+ case lists:keyfind('SizeConstraint', 1, C) of
+ false -> [];
+ {_,{_,[]}} -> []; %Extensible.
+ {_,{Sv,Sv}} -> Sv;
+ {_,{_,_}=Tc} -> Tc
end.
-
get_class_fields(#classdef{typespec=ObjClass}) ->
ObjClass#objectclass.fields;
get_class_fields(#objectclass{fields=Fields}) ->
diff --git a/lib/asn1/src/asn1ct_gen_per.erl b/lib/asn1/src/asn1ct_gen_per.erl
index fac233532b..30c9ab9365 100644
--- a/lib/asn1/src/asn1ct_gen_per.erl
+++ b/lib/asn1/src/asn1ct_gen_per.erl
@@ -26,28 +26,16 @@
%-compile(export_all).
-export([gen_dec_imm/2]).
--export([pgen/4,gen_dec_prim/3,gen_encode_prim/4]).
+-export([gen_dec_prim/3,gen_encode_prim/3]).
-export([gen_obj_code/3,gen_objectset_code/2]).
-export([gen_decode/2, gen_decode/3]).
-export([gen_encode/2, gen_encode/3]).
--export([is_already_generated/2,more_genfields/1,get_class_fields/1,
- get_object_field/2]).
+-export([gen_dec_external/2]).
-export([extaddgroup2sequence/1]).
-import(asn1ct_gen, [emit/1,demit/1]).
-import(asn1ct_func, [call/3]).
-%% pgen(Erules, Module, TypeOrVal)
-%% Generate Erlang module (.erl) and (.hrl) file corresponding to an ASN.1 module
-%% .hrl file is only generated if necessary
-%% Erules = per | ber
-%% Module = atom()
-%% TypeOrVal = {TypeList,ValueList}
-%% TypeList = ValueList = [atom()]
-
-pgen(OutFile,Erules,Module,TypeOrVal) ->
- asn1ct_gen:pgen_module(OutFile,Erules,Module,TypeOrVal,[],true).
-
%% Generate ENCODING ******************************
%%****************************************x
@@ -96,36 +84,44 @@ gen_encode_user(Erules,D) when is_record(D,typedef) ->
emit({"'enc_",asn1ct_gen:list2name(Typename),"'(Val) ->",nl}),
case asn1ct_gen:type(InnerType) of
{primitive,bif} ->
- gen_encode_prim(Erules,Def,"false"),
+ gen_encode_prim(Erules, Def),
emit({".",nl});
'ASN1_OPEN_TYPE' ->
- gen_encode_prim(Erules,Def#type{def='ASN1_OPEN_TYPE'},"false"),
+ gen_encode_prim(Erules, Def#type{def='ASN1_OPEN_TYPE'}),
emit({".",nl});
{constructed,bif} ->
asn1ct_gen:gen_encode_constructed(Erules,Typename,InnerType,D);
#'Externaltypereference'{module=CurrMod,type=Etype} ->
emit({"'enc_",Etype,"'(Val).",nl,nl});
#'Externaltypereference'{module=Emod,type=Etype} ->
- emit({"'",Emod,"':'enc_",Etype,"'(Val).",nl,nl});
- #typereference{val=Ename} ->
- emit({"'enc_",Ename,"'(Val).",nl,nl});
- {notype,_} ->
- emit({"'enc_",InnerType,"'(Val).",nl,nl})
+ emit({"'",Emod,"':'enc_",Etype,"'(Val).",nl,nl})
end.
-gen_encode_prim(Erules,D,DoTag) ->
- Value = case asn1ct_name:active(val) of
- true ->
- asn1ct_gen:mk_var(asn1ct_name:curr(val));
- false ->
- "Val"
- end,
- gen_encode_prim(Erules,D,DoTag,Value).
-
-gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
+gen_encode_prim(Erules, D) ->
+ Value = asn1ct_gen:mk_var(asn1ct_name:curr(val)),
+ gen_encode_prim(Erules, D, Value).
+
+gen_encode_prim(Erules, #type{def={'ENUMERATED',{N1,N2}}}, Value) ->
+ NewList = [{0,X} || {X,_} <- N1] ++ ['EXT_MARK'] ++
+ [{1,X} || {X,_} <- N2],
+ NewC = {0,length(N1)-1},
+ emit(["case ",Value," of",nl]),
+ emit_enc_enumerated_cases(Erules, NewC, NewList, 0);
+gen_encode_prim(Erules, #type{def={'ENUMERATED',NNL}}, Value) ->
+ NewList = [X || {X,_} <- NNL],
+ NewC = {0,length(NewList)-1},
+ emit(["case ",Value," of",nl]),
+ emit_enc_enumerated_cases(Erules, NewC, NewList, 0);
+gen_encode_prim(per=Erules, D, Value) ->
+ asn1ct_gen_per_rt2ct:gen_encode_prim(Erules, D, Value);
+gen_encode_prim(Erules, #type{}=D, Value) ->
Constraint = D#type.constraint,
- asn1ct_name:new(enumval),
+ SizeConstr = asn1ct_imm:effective_constraint(bitstring, Constraint),
+ Pa = case lists:keyfind('PermittedAlphabet', 1, Constraint) of
+ false -> no;
+ {_,Pa0} -> Pa0
+ end,
case D#type.def of
'INTEGER' ->
Args = [{asis,asn1ct_imm:effective_constraint(integer,Constraint)},
@@ -135,23 +131,10 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
Args = [{asis,asn1ct_imm:effective_constraint(integer,Constraint)},
Value,{asis,NamedNumberList}],
call(Erules, encode_integer, Args);
- {'ENUMERATED',{Nlist1,Nlist2}} ->
- NewList = [{0,X} || {X,_} <- Nlist1] ++ ['EXT_MARK'] ++
- [{1,X} || {X,_} <- Nlist2],
- NewC = {0,length(Nlist1)-1},
- emit(["case ",Value," of",nl]),
- emit_enc_enumerated_cases(Erules, NewC, NewList, 0);
- {'ENUMERATED',NamedNumberList} ->
- NewList = [X || {X,_} <- NamedNumberList],
- NewC = {0,length(NewList)-1},
- emit(["case ",Value," of",nl]),
- emit_enc_enumerated_cases(Erules, NewC, NewList, 0);
-
'REAL' ->
emit_enc_real(Erules, Value);
{'BIT STRING',NamedNumberList} ->
- SizeConstr = get_constraint(Constraint, 'SizeConstraint'),
call(Erules, encode_bit_string,
[{asis,SizeConstr},Value,
{asis,NamedNumberList}]);
@@ -167,7 +150,7 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
'BOOLEAN' ->
call(Erules, encode_boolean, [Value]);
'OCTET STRING' ->
- case get_constraint(Constraint, 'SizeConstraint') of
+ case SizeConstr of
0 ->
emit("[]");
no ->
@@ -176,34 +159,40 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
call(Erules, encode_octet_string, [{asis,C},Value])
end;
'NumericString' ->
- call(Erules, encode_NumericString, [{asis,Constraint},Value]);
+ call(Erules, encode_NumericString, [{asis,SizeConstr},
+ {asis,Pa},Value]);
TString when TString == 'TeletexString';
TString == 'T61String' ->
call(Erules, encode_TeletexString, [{asis,Constraint},Value]);
'VideotexString' ->
call(Erules, encode_VideotexString, [{asis,Constraint},Value]);
'UTCTime' ->
- call(Erules, encode_VisibleString, [{asis,Constraint},Value]);
+ call(Erules, encode_VisibleString, [{asis,SizeConstr},
+ {asis,Pa},Value]);
'GeneralizedTime' ->
- call(Erules, encode_VisibleString, [{asis,Constraint},Value]);
+ call(Erules, encode_VisibleString, [{asis,SizeConstr},
+ {asis,Pa},Value]);
'GraphicString' ->
call(Erules, encode_GraphicString, [{asis,Constraint},Value]);
'VisibleString' ->
- call(Erules, encode_VisibleString, [{asis,Constraint},Value]);
+ call(Erules, encode_VisibleString, [{asis,SizeConstr},
+ {asis,Pa},Value]);
'GeneralString' ->
call(Erules, encode_GeneralString, [{asis,Constraint},Value]);
'PrintableString' ->
- call(Erules, encode_PrintableString, [{asis,Constraint},Value]);
+ call(Erules, encode_PrintableString, [{asis,SizeConstr},
+ {asis,Pa},Value]);
'IA5String' ->
- call(Erules, encode_IA5String, [{asis,Constraint},Value]);
+ call(Erules, encode_IA5String, [{asis,SizeConstr},
+ {asis,Pa},Value]);
'BMPString' ->
- call(Erules, encode_BMPString, [{asis,Constraint},Value]);
+ call(Erules, encode_BMPString, [{asis,SizeConstr},
+ {asis,Pa},Value]);
'UniversalString' ->
- call(Erules, encode_UniversalString, [{asis,Constraint},Value]);
+ call(Erules, encode_UniversalString, [{asis,SizeConstr},
+ {asis,Pa},Value]);
'UTF8String' ->
call(Erules, encode_UTF8String, [Value]);
- 'ANY' ->
- call(Erules, encode_open_type, [Value]);
'ASN1_OPEN_TYPE' ->
NewValue = case Constraint of
[#'Externaltypereference'{type=Tname}] ->
@@ -215,18 +204,11 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
io_lib:format(
"complete(enc_~s(~s))",
[Tname,Value]);
- _ -> Value
+ _ ->
+ io_lib:format("iolist_to_binary(~s)",
+ [Value])
end,
- call(Erules, encode_open_type, [NewValue]);
- #'ObjectClassFieldType'{} ->
- case asn1ct_gen:get_inner(D#type.def) of
- {fixedtypevaluefield,_,InnerType} ->
- gen_encode_prim(Erules,InnerType,DoTag,Value);
- T -> %% 'ASN1_OPEN_TYPE'
- gen_encode_prim(Erules,D#type{def=T},DoTag,Value)
- end;
- XX ->
- exit({asn1_error,nyi,XX})
+ call(Erules, encode_open_type, [NewValue])
end.
emit_enc_real(Erules, Real) ->
@@ -271,16 +253,6 @@ enc_ext_and_val(uper, E, F, Args) ->
<<E:1,(apply(asn1ct_eval_uper, F, Args))/bitstring>>.
-get_constraint([{Key,V}], Key) ->
- V;
-get_constraint([], _) ->
- no;
-get_constraint(C, Key) ->
- case lists:keyfind(Key, 1, C) of
- false -> no;
- {Key,V} -> V
- end.
-
%% Object code generating for encoding and decoding
%% ------------------------------------------------
@@ -301,17 +273,16 @@ gen_obj_code(Erules,_Module,Obj) when is_record(Obj,typedef) ->
gen_encode_constr_type(Erules,EncConstructed),
emit(nl),
DecConstructed =
- gen_decode_objectfields(ClassName,get_class_fields(Class),
- ObjName,Fields,[]),
+ gen_decode_objectfields(Erules, ClassName, get_class_fields(Class),
+ ObjName, Fields, []),
emit(nl),
gen_decode_constr_type(Erules,DecConstructed),
- emit(nl);
-gen_obj_code(_,_,Obj) when is_record(Obj,pobjectdef) ->
- ok.
+ emit(nl).
-gen_encode_objectfields(Erule,ClassName,[{typefield,Name,OptOrMand}|Rest],
- ObjName,ObjectFields,ConstrAcc) ->
+gen_encode_objectfields(Erule, ClassName,
+ [{typefield,Name,OptOrMand}|Rest],
+ ObjName, ObjectFields, ConstrAcc) ->
EmitFuncClause =
fun(V) ->
emit(["'enc_",ObjName,"'(",{asis,Name},
@@ -329,18 +300,24 @@ gen_encode_objectfields(Erule,ClassName,[{typefield,Name,OptOrMand}|Rest],
case Erule of
uper ->
emit(" Val");
- _ ->
- emit(" [{octets,Val}]")
+ per ->
+ emit([" if",nl,
+ " is_list(Val) ->",nl,
+ " NewVal = list_to_binary(Val),",nl,
+ " [20,byte_size(NewVal),NewVal];",nl,
+ " is_binary(Val) ->",nl,
+ " [20,byte_size(Val),Val]",nl,
+ " end"])
end,
[];
{false,{'DEFAULT',DefaultType}} ->
EmitFuncClause("Val"),
- gen_encode_default_call(ClassName,Name,DefaultType);
+ gen_encode_default_call(Erule, ClassName, Name, DefaultType);
{{Name,TypeSpec},_} ->
%% A specified field owerwrites any 'DEFAULT' or
%% 'OPTIONAL' field in the class
EmitFuncClause("Val"),
- gen_encode_field_call(ObjName,Name,TypeSpec)
+ gen_encode_field_call(Erule, ObjName, Name, TypeSpec)
end,
case more_genfields(Rest) of
true ->
@@ -416,7 +393,7 @@ gen_encode_constr_type(Erules,[TypeDef|Rest]) when is_record(TypeDef,typedef) ->
gen_encode_constr_type(_,[]) ->
ok.
-gen_encode_field_call(_ObjName,_FieldName,
+gen_encode_field_call(_Erules, _ObjName, _FieldName,
#'Externaltypereference'{module=M,type=T}) ->
CurrentMod = get(currmod),
if
@@ -427,12 +404,11 @@ gen_encode_field_call(_ObjName,_FieldName,
emit({" '",M,"':'enc_",T,"'(Val)"}),
[]
end;
-gen_encode_field_call(ObjName,FieldName,Type) ->
+gen_encode_field_call(Erules, ObjName, FieldName, Type) ->
Def = Type#typedef.typespec,
case Type#typedef.name of
{primitive,bif} ->
- gen_encode_prim(uper,Def,"false",
- "Val"),
+ gen_encode_prim(Erules, Def, "Val"),
[];
{constructed,bif} ->
emit({" 'enc_",ObjName,'_',FieldName,
@@ -448,7 +424,7 @@ gen_encode_field_call(ObjName,FieldName,Type) ->
[]
end.
-gen_encode_default_call(ClassName,FieldName,Type) ->
+gen_encode_default_call(Erules, ClassName, FieldName, Type) ->
CurrentMod = get(currmod),
InnerType = asn1ct_gen:get_inner(Type#type.def),
case asn1ct_gen:type(InnerType) of
@@ -459,7 +435,7 @@ gen_encode_default_call(ClassName,FieldName,Type) ->
[#typedef{name=[FieldName,ClassName],
typespec=Type}];
{primitive,bif} ->
- gen_encode_prim(per,Type,"false","Val"),
+ gen_encode_prim(Erules, Type, "Val"),
[];
#'Externaltypereference'{module=CurrentMod,type=Etype} ->
emit([" 'enc_",Etype,"'(Val)",nl]),
@@ -470,8 +446,9 @@ gen_encode_default_call(ClassName,FieldName,Type) ->
end.
-gen_decode_objectfields(ClassName,[{typefield,Name,OptOrMand}|Rest],
- ObjName,ObjectFields,ConstrAcc) ->
+gen_decode_objectfields(Erules, ClassName,
+ [{typefield,Name,OptOrMand}|Rest],
+ ObjName, ObjectFields, ConstrAcc) ->
EmitFuncClause =
fun(Bytes) ->
emit(["'dec_",ObjName,"'(",{asis,Name},",",Bytes,
@@ -488,12 +465,13 @@ gen_decode_objectfields(ClassName,[{typefield,Name,OptOrMand}|Rest],
[];
{false,{'DEFAULT',DefaultType}} ->
EmitFuncClause("Bytes"),
- gen_decode_default_call(ClassName,Name,"Bytes",DefaultType);
+ gen_decode_default_call(Erules, ClassName, Name, "Bytes",
+ DefaultType);
{{Name,TypeSpec},_} ->
%% A specified field owerwrites any 'DEFAULT' or
%% 'OPTIONAL' field in the class
EmitFuncClause("Bytes"),
- gen_decode_field_call(ObjName,Name,"Bytes",TypeSpec)
+ gen_decode_field_call(Erules, ObjName, Name, "Bytes", TypeSpec)
end,
case more_genfields(Rest) of
true ->
@@ -501,9 +479,11 @@ gen_decode_objectfields(ClassName,[{typefield,Name,OptOrMand}|Rest],
false ->
emit([".",nl])
end,
- gen_decode_objectfields(ClassName,Rest,ObjName,ObjectFields,MaybeConstr++ConstrAcc);
-gen_decode_objectfields(ClassName,[{objectfield,Name,_,_,OptOrMand}|Rest],
- ObjName,ObjectFields,ConstrAcc) ->
+ gen_decode_objectfields(Erules, ClassName, Rest, ObjName,
+ ObjectFields, MaybeConstr++ConstrAcc);
+gen_decode_objectfields(Erules, ClassName,
+ [{objectfield,Name,_,_,OptOrMand}|Rest],
+ ObjName, ObjectFields, ConstrAcc) ->
CurrentMod = get(currmod),
EmitFuncClause =
fun(Attrs) ->
@@ -546,30 +526,25 @@ gen_decode_objectfields(ClassName,[{objectfield,Name,_,_,OptOrMand}|Rest],
false ->
emit([".",nl])
end,
- gen_decode_objectfields(ClassName,Rest,ObjName,ObjectFields,ConstrAcc);
-gen_decode_objectfields(CN,[_C|Cs],O,OF,CAcc) ->
- gen_decode_objectfields(CN,Cs,O,OF,CAcc);
-gen_decode_objectfields(_,[],_,_,CAcc) ->
+ gen_decode_objectfields(Erules, ClassName, Rest, ObjName,
+ ObjectFields, ConstrAcc);
+gen_decode_objectfields(Erules, CN, [_C|Cs], O, OF, CAcc) ->
+ gen_decode_objectfields(Erules, CN, Cs, O, OF, CAcc);
+gen_decode_objectfields(_, _, [], _, _, CAcc) ->
CAcc.
-gen_decode_field_call(_ObjName,_FieldName,Bytes,
- #'Externaltypereference'{module=M,type=T}) ->
- CurrentMod = get(currmod),
- if
- M == CurrentMod ->
- emit([" 'dec_",T,"'(",Bytes,", telltype)"]),
- [];
- true ->
- emit([" '",M,"':'dec_",T,"'(",Bytes,", telltype)"]),
- []
- end;
-gen_decode_field_call(ObjName,FieldName,Bytes,Type) ->
+gen_decode_field_call(_Erules, _ObjName, _FieldName, Bytes,
+ #'Externaltypereference'{}=Etype) ->
+ emit(" "),
+ gen_dec_external(Etype, Bytes),
+ [];
+gen_decode_field_call(Erules, ObjName, FieldName, Bytes, Type) ->
Def = Type#typedef.typespec,
case Type#typedef.name of
{primitive,bif} ->
- gen_dec_prim(uper, Def, Bytes),
+ gen_dec_prim(Erules, Def, Bytes),
[];
{constructed,bif} ->
emit({" 'dec_",ObjName,'_',FieldName,
@@ -585,8 +560,7 @@ gen_decode_field_call(ObjName,FieldName,Bytes,Type) ->
[]
end.
-gen_decode_default_call(ClassName,FieldName,Bytes,Type) ->
- CurrentMod = get(currmod),
+gen_decode_default_call(Erules, ClassName, FieldName, Bytes, Type) ->
InnerType = asn1ct_gen:get_inner(Type#type.def),
case asn1ct_gen:type(InnerType) of
{constructed,bif} ->
@@ -595,13 +569,10 @@ gen_decode_default_call(ClassName,FieldName,Bytes,Type) ->
[#typedef{name=[FieldName,ClassName],
typespec=Type}];
{primitive,bif} ->
- gen_dec_prim(per,Type,Bytes),
+ gen_dec_prim(Erules, Type, Bytes),
[];
- #'Externaltypereference'{module=CurrentMod,type=Etype} ->
- emit([" 'dec_",Etype,"'(",Bytes,", telltype)",nl]),
- [];
- #'Externaltypereference'{module=Emod,type=Etype} ->
- emit([" '",Emod,"':'dec_",Etype,"'(",Bytes,", telltype)",nl]),
+ #'Externaltypereference'{}=Etype ->
+ asn1ct_gen_per:gen_dec_external(Etype, Bytes),
[]
end.
@@ -657,7 +628,7 @@ gen_objset_code(Erules,ObjSetName,UniqueFName,Set,ClassName,ClassDef)->
ClassFields = (ClassDef#classdef.typespec)#objectclass.fields,
InternalFuncs=
gen_objset_enc(Erules,ObjSetName,UniqueFName,Set,ClassName,ClassFields,1,[]),
- gen_objset_dec(ObjSetName,UniqueFName,Set,ClassName,ClassFields,1),
+ gen_objset_dec(Erules, ObjSetName,UniqueFName,Set,ClassName,ClassFields,1),
gen_internal_funcs(Erules,InternalFuncs).
%% gen_objset_enc iterates over the objects of the object set
@@ -665,67 +636,56 @@ gen_objset_enc(_,_,{unique,undefined},_,_,_,_,_) ->
%% There is no unique field in the class of this object set
%% don't bother about the constraint
[];
-gen_objset_enc(Erule,ObjSName,UniqueName,[{ObjName,Val,Fields},T|Rest],
- ClName,ClFields,NthObj,Acc)->
- emit({"'getenc_",ObjSName,"'(",{asis,UniqueName},",",{asis,Val},
- ") ->",nl}),
+gen_objset_enc(Erule, ObjSetName, UniqueName, [{ObjName,Val,Fields}|T],
+ ClName, ClFields, NthObj, Acc)->
+ emit(["'getenc_",ObjSetName,"'(",{asis,UniqueName},",",{asis,Val},
+ ") ->",nl]),
CurrMod = get(currmod),
{InternalFunc,NewNthObj}=
case ObjName of
{no_mod,no_name} ->
- gen_inlined_enc_funs(Erule,Fields,ClFields,ObjSName,NthObj);
+ gen_inlined_enc_funs(Erule, Fields, ClFields,
+ ObjSetName, NthObj);
{CurrMod,Name} ->
emit({" fun 'enc_",Name,"'/3"}),
{[],0};
{ModName,Name} ->
emit_ext_encfun(ModName,Name),
-% emit([" {'",ModName,"', 'enc_",Name,"'}"]),
{[],0};
_Other ->
emit({" fun 'enc_",ObjName,"'/3"}),
{[],0}
end,
emit({";",nl}),
- gen_objset_enc(Erule,ObjSName,UniqueName,[T|Rest],ClName,ClFields,
- NewNthObj,InternalFunc ++ Acc);
-gen_objset_enc(Erule,ObjSetName,UniqueName,
- [{ObjName,Val,Fields}],_ClName,ClFields,NthObj,Acc) ->
-
- emit({"'getenc_",ObjSetName,"'(",{asis,UniqueName},",",
- {asis,Val},") ->",nl}),
- CurrMod = get(currmod),
- {InternalFunc,_}=
- case ObjName of
- {no_mod,no_name} ->
- gen_inlined_enc_funs(Erule,Fields,ClFields,ObjSetName,NthObj);
- {CurrMod,Name} ->
- emit({" fun 'enc_",Name,"'/3"}),
- {[],NthObj};
- {ModName,Name} ->
- emit_ext_encfun(ModName,Name),
-% emit([" {'",ModName,"', 'enc_",Name,"'}"]),
- {[],NthObj};
- _Other ->
- emit({" fun 'enc_",ObjName,"'/3"}),
- {[],NthObj}
- end,
- emit([";",nl]),
- emit_default_getenc(ObjSetName,UniqueName),
- emit({".",nl,nl}),
- InternalFunc++Acc;
-gen_objset_enc(Erule,ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName,
- _ClFields,_NthObj,Acc) ->
+ gen_objset_enc(Erule, ObjSetName, UniqueName, T, ClName, ClFields,
+ NewNthObj, InternalFunc ++ Acc);
+gen_objset_enc(uper, ObjSetName, _UniqueName, ['EXTENSIONMARK'],
+ _ClName, _ClFields, _NthObj, Acc) ->
emit({"'getenc_",ObjSetName,"'(_, _) ->",nl}),
emit({indent(3),"fun(_, Val, _) ->",nl}),
- case Erule of
- uper ->
- emit([indent(6),"Val",nl]);
- _ ->
- emit([indent(6),"[{octets,Val}]",nl])
- end,
- emit({indent(3),"end.",nl,nl}),
+ emit([indent(6),"Val",nl,
+ indent(3),"end.",nl,nl]),
+ Acc;
+gen_objset_enc(per, ObjSetName, _UniqueName, ['EXTENSIONMARK'],
+ _ClName, _ClFields, _NthObj, Acc) ->
+ emit(["'getenc_",ObjSetName,"'(_, _) ->",nl,
+ indent(3),"fun(_, Val, _) ->",nl,
+ indent(6),"BinVal = if",nl,
+ indent(9),"is_list(Val) -> list_to_binary(Val);",nl,
+ indent(9),"true -> Val",nl,
+ indent(6),"end,",nl,
+ indent(6),"Size = byte_size(BinVal),",nl,
+ indent(6),"if",nl,
+ indent(9),"Size < 256 ->",nl,
+ indent(12),"[20,Size,BinVal];",nl,
+ indent(9),"true ->",nl,
+ indent(12),"[21,<<Size:16>>,Val]",nl,
+ indent(6),"end",nl,
+ indent(3),"end.",nl,nl]),
Acc;
-gen_objset_enc(_,_,_,[],_,_,_,Acc) ->
+gen_objset_enc(_, ObjSetName, UniqueName, [], _, _, _, Acc) ->
+ emit_default_getenc(ObjSetName, UniqueName),
+ emit([".",nl,nl]),
Acc.
emit_ext_encfun(ModuleName,Name) ->
@@ -740,97 +700,70 @@ emit_default_getenc(ObjSetName,UniqueName) ->
%% gen_inlined_enc_funs for each object iterates over all fields of a
%% class, and for each typefield it checks if the object has that
%% field and emits the proper code.
-gen_inlined_enc_funs(Erule,Fields,[{typefield,Name,_}|Rest],ObjSetName,NthObj) ->
- CurrMod = get(currmod),
- InternalDefFunName = asn1ct_gen:list2name([NthObj,Name,ObjSetName]),
- case lists:keysearch(Name,1,Fields) of
- {value,{_,Type}} when is_record(Type,type) ->
- emit({indent(3),"fun(Type, Val, _) ->",nl,
- indent(6),"case Type of",nl}),
- {Ret,N}=emit_inner_of_fun(Type,InternalDefFunName),
- gen_inlined_enc_funs1(Erule,Fields,Rest,ObjSetName,NthObj+N,Ret);
- {value,{_,Type}} when is_record(Type,typedef) ->
- emit({indent(3),"fun(Type, Val, _) ->",nl,
- indent(6),"case Type of",nl}),
- emit({indent(9),{asis,Name}," ->",nl}),
- {Ret,N} = emit_inner_of_fun(Type,InternalDefFunName),
- gen_inlined_enc_funs1(Erule,Fields,Rest,ObjSetName,NthObj+N,Ret);
- {value,{_,#'Externaltypereference'{module=CurrMod,type=T}}} ->
- emit({indent(3),"fun(Type, Val, _) ->",nl,
- indent(6),"case Type of",nl}),
- emit({indent(9),{asis,Name}," ->",nl}),
- emit([indent(12),"'enc_",T,"'(Val)"]),
-% {Ret,N} = emit_inner_of_fun(TDef,InternalDefFunName),
- gen_inlined_enc_funs1(Erule,Fields,Rest,ObjSetName,NthObj,[]);
- {value,{_,#'Externaltypereference'{module=M,type=T}}} ->
- emit({indent(3),"fun(Type, Val, _) ->",nl,
- indent(6),"case Type of",nl}),
- emit({indent(9),{asis,Name}," ->",nl}),
- emit([indent(12),"'",M,"'",":'enc_",T,"'(Val)"]),
- gen_inlined_enc_funs1(Erule,Fields,Rest,ObjSetName,NthObj,[]);
- false when Erule =:= uper ->
- emit([indent(3),"fun(Type,Val,_) ->",nl,
- indent(6),"case Type of",nl,
- indent(9),{asis,Name}," -> Val",nl]),
- gen_inlined_enc_funs1(Erule,Fields,Rest,ObjSetName,NthObj,[]);
- false ->
- emit([indent(3),"fun(Type,Val,_) ->",nl,
- indent(6),"case Type of",nl,
- indent(9),{asis,Name}," -> [{octets,Val}]",nl]),
- gen_inlined_enc_funs1(Erule,Fields,Rest,ObjSetName,NthObj,[])
- end;
+gen_inlined_enc_funs(Erule, Fields, [{typefield,_,_}|_]=T,
+ ObjSetName, NthObj) ->
+ emit([indent(3),"fun(Type, Val, _) ->",nl,
+ indent(6),"case Type of",nl]),
+ gen_inlined_enc_funs1(Erule, Fields, T, ObjSetName, [], NthObj, []);
gen_inlined_enc_funs(Erule,Fields,[_H|Rest],ObjSetName,NthObj) ->
gen_inlined_enc_funs(Erule,Fields,Rest,ObjSetName,NthObj);
gen_inlined_enc_funs(_,_,[],_,NthObj) ->
{[],NthObj}.
-gen_inlined_enc_funs1(Erule,Fields,[{typefield,Name,_}|Rest],ObjSetName,
- NthObj,Acc) ->
+gen_inlined_enc_funs1(Erule, Fields, [{typefield,Name,_}|Rest], ObjSetName,
+ Sep0, NthObj, Acc0) ->
+ emit(Sep0),
+ Sep = [";",nl],
CurrentMod = get(currmod),
InternalDefFunName = asn1ct_gen:list2name([NthObj,Name,ObjSetName]),
- {Acc2,NAdd}=
- case lists:keysearch(Name,1,Fields) of
- {value,{_,Type}} when is_record(Type,type) ->
- emit({";",nl}),
- {Ret,N}=emit_inner_of_fun(Type,InternalDefFunName),
- {Ret++Acc,N};
- {value,{_,Type}} when is_record(Type,typedef) ->
- emit({";",nl,indent(9),{asis,Name}," ->",nl}),
- {Ret,N}=emit_inner_of_fun(Type,InternalDefFunName),
- {Ret++Acc,N};
- {value,{_,#'Externaltypereference'{module=CurrentMod,type=T}}} ->
- emit({";",nl,indent(9),{asis,Name}," ->",nl}),
- emit([indent(12),"'enc_",T,"'(Val)"]),
- {Acc,0};
- {value,{_,#'Externaltypereference'{module=M,type=T}}} ->
- emit({";",nl,indent(9),{asis,Name}," ->",nl}),
- emit([indent(12),"'",M,"'",":'enc_",T,"'(Val)"]),
- {Acc,0};
+ {Acc,NAdd} =
+ case lists:keyfind(Name, 1, Fields) of
+ {_,#type{}=Type} ->
+ {Ret,N} = emit_inner_of_fun(Erule, Type, InternalDefFunName),
+ {Ret++Acc0,N};
+ {_,#typedef{}=Type} ->
+ emit([indent(9),{asis,Name}," ->",nl]),
+ {Ret,N} = emit_inner_of_fun(Erule, Type, InternalDefFunName),
+ {Ret++Acc0,N};
+ {_,#'Externaltypereference'{module=CurrentMod,type=T}} ->
+ emit([indent(9),{asis,Name}," ->",nl,
+ indent(12),"'enc_",T,"'(Val)"]),
+ {Acc0,0};
+ {_,#'Externaltypereference'{module=M,type=T}} ->
+ emit([indent(9),{asis,Name}," ->",nl,
+ indent(12),"'",M,"'",":'enc_",T,"'(Val)"]),
+ {Acc0,0};
false when Erule =:= uper ->
- emit([";",nl,
- indent(9),{asis,Name}," -> ",nl,
- "Val",nl]),
- {Acc,0};
- false ->
- emit([";",nl,
- indent(9),{asis,Name}," -> ",nl,
- "[{octets,Val}]",nl]),
- {Acc,0}
+ emit([indent(9),{asis,Name}," ->",nl,
+ indent(12),"Val",nl]),
+ {Acc0,0};
+ false when Erule =:= per ->
+ emit([indent(9),{asis,Name}," ->",nl,
+ indent(12),"Size = case Val of",nl,
+ indent(15),"B when is_binary(B) -> size(B);",nl,
+ indent(15),"_ -> length(Val)",nl,
+ indent(12),"end,",nl,
+ indent(12),"if",nl,
+ indent(15),"Size < 256 -> [20,Size,Val];",nl,
+ indent(15),"true -> [21,<<Size:16>>,Val]",nl,
+ indent(12),"end"]),
+ {Acc0,0}
end,
- gen_inlined_enc_funs1(Erule,Fields,Rest,ObjSetName,NthObj+NAdd,Acc2);
-gen_inlined_enc_funs1(Erule,Fields,[_H|Rest],ObjSetName,NthObj,Acc)->
- gen_inlined_enc_funs1(Erule,Fields,Rest,ObjSetName,NthObj,Acc);
-gen_inlined_enc_funs1(_,_,[],_,NthObj,Acc) ->
- emit({nl,indent(6),"end",nl}),
- emit({indent(3),"end"}),
+ gen_inlined_enc_funs1(Erule, Fields, Rest, ObjSetName, Sep,
+ NthObj+NAdd, Acc);
+gen_inlined_enc_funs1(Erule, Fields, [_|T], ObjSetName, Sep, NthObj, Acc)->
+ gen_inlined_enc_funs1(Erule, Fields, T, ObjSetName, Sep, NthObj, Acc);
+gen_inlined_enc_funs1(_, _, [], _, _, NthObj, Acc) ->
+ emit([nl,indent(6),"end",nl,
+ indent(3),"end"]),
{Acc,NthObj}.
-emit_inner_of_fun(TDef=#typedef{name={ExtMod,Name},typespec=Type},
+emit_inner_of_fun(Erule, #typedef{name={ExtMod,Name},typespec=Type}=TDef,
InternalDefFunName) ->
case {ExtMod,Name} of
{primitive,bif} ->
emit(indent(12)),
- gen_encode_prim(uper,Type,dotag,"Val"),
+ gen_encode_prim(Erule, Type, "Val"),
{[],0};
{constructed,bif} ->
emit([indent(12),"'enc_",
@@ -840,18 +773,15 @@ emit_inner_of_fun(TDef=#typedef{name={ExtMod,Name},typespec=Type},
emit({indent(12),"'",ExtMod,"':'enc_",Name,"'(Val)"}),
{[],0}
end;
-emit_inner_of_fun(#typedef{name=Name},_) ->
+emit_inner_of_fun(_Erule, #typedef{name=Name}, _) ->
emit({indent(12),"'enc_",Name,"'(Val)"}),
{[],0};
-emit_inner_of_fun(Type,_) when is_record(Type,type) ->
+emit_inner_of_fun(Erule, #type{}=Type, _) ->
CurrMod = get(currmod),
case Type#type.def of
Def when is_atom(Def) ->
emit({indent(9),Def," ->",nl,indent(12)}),
- gen_encode_prim(erules,Type,dotag,"Val");
- TRef when is_record(TRef,typereference) ->
- T = TRef#typereference.val,
- emit({indent(9),T," ->",nl,indent(12),"'enc_",T,"'(Val)"});
+ gen_encode_prim(Erule, Type, "Val");
#'Externaltypereference'{module=CurrMod,type=T} ->
emit({indent(9),T," ->",nl,indent(12),"'enc_",T,"'(Val)"});
#'Externaltypereference'{module=ExtMod,type=T} ->
@@ -864,62 +794,42 @@ indent(N) ->
lists:duplicate(N,32). % 32 = space
-gen_objset_dec(_,{unique,undefined},_,_,_,_) ->
+gen_objset_dec(_, _, {unique,undefined}, _, _, _, _) ->
%% There is no unique field in the class of this object set
%% don't bother about the constraint
ok;
-gen_objset_dec(ObjSName,UniqueName,[{ObjName,Val,Fields},T|Rest],ClName,
- ClFields,NthObj)->
-
+gen_objset_dec(Erule, ObjSName, UniqueName, [{ObjName,Val,Fields}|T], ClName,
+ ClFields, NthObj)->
emit({"'getdec_",ObjSName,"'(",{asis,UniqueName},",",{asis,Val},
") ->",nl}),
CurrMod = get(currmod),
NewNthObj=
case ObjName of
{no_mod,no_name} ->
- gen_inlined_dec_funs(Fields,ClFields,ObjSName,NthObj);
+ gen_inlined_dec_funs(Erule, Fields, ClFields,
+ ObjSName, NthObj);
{CurrMod,Name} ->
emit([" fun 'dec_",Name,"'/4"]),
NthObj;
{ModName,Name} ->
emit_ext_decfun(ModName,Name),
-% emit([" {'",ModName,"', 'dec_",Name,"'}"]),
NthObj;
_Other ->
emit({" fun 'dec_",ObjName,"'/4"}),
NthObj
end,
emit({";",nl}),
- gen_objset_dec(ObjSName,UniqueName,[T|Rest],ClName,ClFields,NewNthObj);
-gen_objset_dec(ObjSetName,UniqueName,[{ObjName,Val,Fields}],_ClName,
- ClFields,NthObj) ->
-
- emit({"'getdec_",ObjSetName,"'(",{asis,UniqueName},",",{asis,Val},
- ") ->",nl}),
- CurrMod=get(currmod),
- case ObjName of
- {no_mod,no_name} ->
- gen_inlined_dec_funs(Fields,ClFields,ObjSetName,NthObj);
- {CurrMod,Name} ->
- emit([" fun 'dec_",Name,"'/4"]);
- {ModName,Name} ->
- emit_ext_decfun(ModName,Name);
-% emit([" {'",ModName,"', 'dec_",Name,"'}"]);
- _Other ->
- emit({" fun 'dec_",ObjName,"'/4"})
- end,
- emit([";",nl]),
- emit_default_getdec(ObjSetName,UniqueName),
- emit({".",nl,nl}),
- ok;
-gen_objset_dec(ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName,_ClFields,
- _NthObj) ->
+ gen_objset_dec(Erule, ObjSName, UniqueName, T, ClName, ClFields, NewNthObj);
+gen_objset_dec(_Erule, ObjSetName, _UniqueName, ['EXTENSIONMARK'],
+ _ClName, _ClFields, _NthObj) ->
emit({"'getdec_",ObjSetName,"'(_, _) ->",nl}),
emit({indent(3),"fun(Attr1, Bytes, _,_) ->",nl}),
emit({indent(6),"{Bytes,Attr1}",nl}),
emit({indent(3),"end.",nl,nl}),
ok;
-gen_objset_dec(_,_,[],_,_,_) ->
+gen_objset_dec(_Erule, ObjSetName, UniqueName, [], _, _, _) ->
+ emit_default_getdec(ObjSetName, UniqueName),
+ emit([".",nl,nl]),
ok.
emit_ext_decfun(ModuleName,Name) ->
@@ -931,49 +841,46 @@ emit_default_getdec(ObjSetName,UniqueName) ->
emit([indent(2), "fun(C,V,_,_) -> exit({{component,C},{value,V},{unique_name_and_value,",{asis,UniqueName},",ErrV}}) end"]).
-gen_inlined_dec_funs(Fields, List, ObjSetName, NthObj0) ->
+gen_inlined_dec_funs(Erule, Fields, List, ObjSetName, NthObj0) ->
emit([indent(3),"fun(Type, Val, _, _) ->",nl,
indent(6),"case Type of",nl]),
- NthObj = gen_inlined_dec_funs1(Fields, List, ObjSetName, "", NthObj0),
+ NthObj = gen_inlined_dec_funs1(Erule, Fields, List,
+ ObjSetName, "", NthObj0),
emit([nl,indent(6),"end",nl,
indent(3),"end"]),
NthObj.
-gen_inlined_dec_funs1(Fields, [{typefield,Name,_}|Rest],
+gen_inlined_dec_funs1(Erule, Fields, [{typefield,Name,_}|Rest],
ObjSetName, Sep0, NthObj) ->
- CurrentMod = get(currmod),
InternalDefFunName = [NthObj,Name,ObjSetName],
emit(Sep0),
Sep = [";",nl],
N = case lists:keyfind(Name, 1, Fields) of
{_,#type{}=Type} ->
- emit_inner_of_decfun(Type, InternalDefFunName);
+ emit_inner_of_decfun(Erule, Type, InternalDefFunName);
{_,#typedef{}=Type} ->
emit([indent(9),{asis,Name}," ->",nl]),
- emit_inner_of_decfun(Type, InternalDefFunName);
- {_,#'Externaltypereference'{module=CurrentMod,type=T}} ->
+ emit_inner_of_decfun(Erule, Type, InternalDefFunName);
+ {_,#'Externaltypereference'{}=Etype} ->
emit([indent(9),{asis,Name}," ->",nl,
- indent(12),"'dec_",T,"'(Val,telltype)"]),
- 0;
- {_,#'Externaltypereference'{module=M,type=T}} ->
- emit([indent(9),{asis,Name}," ->",nl,
- indent(12),"'",M,"':'dec_",T,"'(Val,telltype)"]),
+ indent(12)]),
+ gen_dec_external(Etype, "Val"),
0;
false ->
emit([indent(9),{asis,Name}," -> {Val,Type}"]),
0
end,
- gen_inlined_dec_funs1(Fields, Rest, ObjSetName, Sep, NthObj+N);
-gen_inlined_dec_funs1(Fields, [_|Rest], ObjSetName, Sep, NthObj) ->
- gen_inlined_dec_funs1(Fields, Rest, ObjSetName, Sep, NthObj);
-gen_inlined_dec_funs1(_, [], _, _, NthObj) -> NthObj.
+ gen_inlined_dec_funs1(Erule, Fields, Rest, ObjSetName, Sep, NthObj+N);
+gen_inlined_dec_funs1(Erule, Fields, [_|Rest], ObjSetName, Sep, NthObj) ->
+ gen_inlined_dec_funs1(Erule, Fields, Rest, ObjSetName, Sep, NthObj);
+gen_inlined_dec_funs1(_, _, [], _, _, NthObj) -> NthObj.
-emit_inner_of_decfun(#typedef{name={ExtName,Name},typespec=Type},
+emit_inner_of_decfun(Erule, #typedef{name={ExtName,Name},typespec=Type},
InternalDefFunName) ->
case {ExtName,Name} of
{primitive,bif} ->
emit(indent(12)),
- gen_dec_prim(uper, Type, "Val"),
+ gen_dec_prim(Erule, Type, "Val"),
0;
{constructed,bif} ->
emit({indent(12),"'dec_",
@@ -983,18 +890,15 @@ emit_inner_of_decfun(#typedef{name={ExtName,Name},typespec=Type},
emit({indent(12),"'",ExtName,"':'dec_",Name,"'(Val, telltype)"}),
0
end;
-emit_inner_of_decfun(#typedef{name=Name},_) ->
+emit_inner_of_decfun(_Erule, #typedef{name=Name}, _) ->
emit({indent(12),"'dec_",Name,"'(Val, telltype)"}),
0;
-emit_inner_of_decfun(Type,_) when is_record(Type,type) ->
+emit_inner_of_decfun(Erule, #type{}=Type, _) ->
CurrMod = get(currmod),
case Type#type.def of
Def when is_atom(Def) ->
emit({indent(9),Def," ->",nl,indent(12)}),
- gen_dec_prim(uper, Type, "Val");
- TRef when is_record(TRef,typereference) ->
- T = TRef#typereference.val,
- emit({indent(9),T," ->",nl,indent(12),"'dec_",T,"'(Val)"});
+ gen_dec_prim(Erule, Type, "Val");
#'Externaltypereference'{module=CurrMod,type=T} ->
emit({indent(9),T," ->",nl,indent(12),"'dec_",T,"'(Val)"});
#'Externaltypereference'{module=ExtMod,type=T} ->
@@ -1017,7 +921,6 @@ gen_internal_funcs(Erules,[TypeDef|Rest]) ->
%% DECODING *****************************
%%***************************************
-
gen_decode(Erules,Type) when is_record(Type,typedef) ->
D = Type,
emit({nl,nl}),
@@ -1054,7 +957,6 @@ dbdec(Type) ->
demit({"io:format(\"decoding: ",{asis,Type},"~w~n\",[Bytes]),",nl}).
gen_decode_user(Erules,D) when is_record(D,typedef) ->
- CurrMod = get(currmod),
Typename = [D#typedef.name],
Def = D#typedef.typespec,
InnerType = asn1ct_gen:get_inner(Def#type.def),
@@ -1067,17 +969,21 @@ gen_decode_user(Erules,D) when is_record(D,typedef) ->
emit({".",nl,nl});
{constructed,bif} ->
asn1ct_gen:gen_decode_constructed(Erules,Typename,InnerType,D);
- #typereference{val=Dname} ->
- emit({"'dec_",Dname,"'(Bytes,telltype)"}),
- emit({".",nl,nl});
- #'Externaltypereference'{module=CurrMod,type=Etype} ->
- emit({"'dec_",Etype,"'(Bytes,telltype).",nl,nl});
- #'Externaltypereference'{module=Emod,type=Etype} ->
- emit({"'",Emod,"':'dec_",Etype,"'(Bytes,telltype).",nl,nl});
+ #'Externaltypereference'{}=Etype ->
+ gen_dec_external(Etype, "Bytes"),
+ emit([".",nl,nl]);
Other ->
exit({error,{asn1,{unknown,Other}}})
end.
+gen_dec_external(Ext, BytesVar) ->
+ CurrMod = get(currmod),
+ #'Externaltypereference'{module=Mod,type=Type} = Ext,
+ emit([case CurrMod of
+ Mod -> [];
+ _ -> ["'",Mod,"':"]
+ end,"'dec_",Type,"'(",BytesVar,",telltype)"]).
+
gen_dec_imm(Erule, #type{def=Name,constraint=C}) ->
Aligned = case Erule of
uper -> false;
@@ -1087,10 +993,8 @@ gen_dec_imm(Erule, #type{def=Name,constraint=C}) ->
gen_dec_imm_1('ASN1_OPEN_TYPE', Constraint, Aligned) ->
imm_decode_open_type(Constraint, Aligned);
-gen_dec_imm_1('ANY', _Constraint, Aligned) ->
- imm_decode_open_type([], Aligned);
gen_dec_imm_1({'BIT STRING',NNL}, Constr0, Aligned) ->
- Constr = get_constraint(Constr0, 'SizeConstraint'),
+ Constr = asn1ct_imm:effective_constraint(bitstring, Constr0),
Imm = asn1ct_imm:per_dec_raw_bitstring(Constr, Aligned),
case NNL of
[] ->
@@ -1143,7 +1047,7 @@ gen_dec_imm_1('UTCTime', Constraint, Aligned) ->
gen_dec_imm_1('GeneralizedTime', Constraint, Aligned) ->
gen_dec_k_m_string('VisibleString', Constraint, Aligned);
gen_dec_imm_1('OCTET STRING', Constraint, Aligned) ->
- SzConstr = get_constraint(Constraint, 'SizeConstraint'),
+ SzConstr = asn1ct_imm:effective_constraint(bitstring, Constraint),
Imm = asn1ct_imm:per_dec_octet_string(SzConstr, Aligned),
{convert,binary_to_list,Imm};
gen_dec_imm_1('TeletexString', _Constraint, Aligned) ->
@@ -1173,14 +1077,7 @@ gen_dec_imm_1('RELATIVE-OID', _Constraint, Aligned) ->
gen_dec_imm_1('UTF8String', _Constraint, Aligned) ->
asn1ct_imm:per_dec_restricted_string(Aligned);
gen_dec_imm_1('REAL', _Constraint, Aligned) ->
- asn1ct_imm:per_dec_real(Aligned);
-gen_dec_imm_1(#'ObjectClassFieldType'{}=TypeName, _Constraint, Aligned) ->
- case asn1ct_gen:get_inner(TypeName) of
- {fixedtypevaluefield,_,#type{def=InnerType,constraint=C}} ->
- gen_dec_imm_1(InnerType, C, Aligned);
- #type{def=T,constraint=C} ->
- gen_dec_imm_1(T, C, Aligned)
- end.
+ asn1ct_imm:per_dec_real(Aligned).
gen_dec_bit_string(F, Imm) ->
D = fun(V, Buf) ->
diff --git a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl
index 81d8cdcae6..012d54e7a1 100644
--- a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl
+++ b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl
@@ -19,105 +19,16 @@
%%
-module(asn1ct_gen_per_rt2ct).
-%% Generate erlang module which handles (PER) encode and decode for
-%% all types in an ASN.1 module
+%% Handle encoding of primitives for aligned PER.
-include("asn1_records.hrl").
-%-compile(export_all).
--export([pgen/4,gen_dec_prim/3,gen_encode_prim/4]).
--export([gen_obj_code/3,gen_objectset_code/2]).
--export([gen_decode/2, gen_decode/3]).
--export([gen_encode/2, gen_encode/3]).
--export([extaddgroup2sequence/1]).
+-export([gen_encode_prim/3]).
-import(asn1ct_gen, [emit/1,demit/1]).
--import(asn1ct_gen_per, [is_already_generated/2,more_genfields/1,
- get_class_fields/1,get_object_field/2]).
-import(asn1ct_func, [call/3]).
-%% pgen(Erules, Module, TypeOrVal)
-%% Generate Erlang module (.erl) and (.hrl) file corresponding to an ASN.1 module
-%% .hrl file is only generated if necessary
-%% Erules = per | ber
-%% Module = atom()
-%% TypeOrVal = {TypeList,ValueList}
-%% TypeList = ValueList = [atom()]
-
-pgen(OutFile,Erules,Module,TypeOrVal) ->
- asn1ct_gen:pgen_module(OutFile,Erules,Module,TypeOrVal,[],true).
-
-
-%% Generate ENCODING ******************************
-%%****************************************x
-
-
-gen_encode(Erules,Type) when is_record(Type,typedef) ->
- gen_encode_user(Erules,Type).
-
-gen_encode(Erules,Typename,#'ComponentType'{name=Cname,typespec=Type}) ->
- NewTypename = [Cname|Typename],
- gen_encode(Erules,NewTypename,Type);
-
-gen_encode(Erules,Typename,Type) when is_record(Type,type) ->
- InnerType = asn1ct_gen:get_inner(Type#type.def),
- ObjFun =
- case lists:keysearch(objfun,1,Type#type.tablecinf) of
- {value,{_,_Name}} ->
- ", ObjFun";
- false ->
- ""
- end,
- case asn1ct_gen:type(InnerType) of
- {constructed,bif} ->
- emit({"'enc_",asn1ct_gen:list2name(Typename),"'(Val",ObjFun,
- ") ->",nl}),
- asn1ct_gen:gen_encode_constructed(Erules,Typename,InnerType,Type);
- _ ->
- true
- end.
-
-
-gen_encode_user(Erules,D) when is_record(D,typedef) ->
- CurrMod = get(currmod),
- Typename = [D#typedef.name],
- Def = D#typedef.typespec,
- InnerType = asn1ct_gen:get_inner(Def#type.def),
- emit({"'enc_",asn1ct_gen:list2name(Typename),"'(Val) ->",nl}),
- case asn1ct_gen:type(InnerType) of
- {primitive,bif} ->
- gen_encode_prim(Erules,Def,"false"),
- emit({".",nl});
- 'ASN1_OPEN_TYPE' ->
- gen_encode_prim(Erules,Def#type{def='ASN1_OPEN_TYPE'},"false"),
- emit({".",nl});
- {constructed,bif} ->
- asn1ct_gen:gen_encode_constructed(Erules,Typename,InnerType,D);
- #'Externaltypereference'{module=CurrMod,type=Etype} ->
- emit({"'enc_",Etype,"'(Val).",nl,nl});
- #'Externaltypereference'{module=Emod,type=Etype} ->
- emit({"'",Emod,"':'enc_",Etype,"'(Val).",nl,nl});
- #typereference{val=Ename} ->
- emit({"'enc_",Ename,"'(Val).",nl,nl});
- {notype,_} ->
- emit({"'enc_",InnerType,"'(Val).",nl,nl})
- end.
-
-
-gen_encode_prim(Erules,D,DoTag) ->
- Value = case asn1ct_name:active(val) of
- true ->
- asn1ct_gen:mk_var(asn1ct_name:curr(val));
- false ->
- "Val"
- end,
- gen_encode_prim(Erules,D,DoTag,Value).
-
-
-
-
-
-gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
+gen_encode_prim(Erules, #type{}=D, Value) ->
Constraint = D#type.constraint,
case D#type.def of
'INTEGER' ->
@@ -131,8 +42,6 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
emit([" %%INTEGER with effective constraint: ",
{asis,EffectiveConstr},nl]),
emit_enc_integer_NNL(Erules,EffectiveConstr,Value,NamedNumberList);
- {'ENUMERATED',_} ->
- asn1ct_gen_per:gen_encode_prim(Erules, D, DoTag, Value);
'REAL' ->
emit_enc_real(Erules, Value);
@@ -191,8 +100,6 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
emit_enc_known_multiplier_string('UniversalString',Constraint,Value);
'UTF8String' ->
call(Erules, encode_UTF8String, [Value]);
- 'ANY' ->
- call(Erules, encode_open_type, [Value]);
'ASN1_OPEN_TYPE' ->
NewValue = case Constraint of
[#'Externaltypereference'{type=Tname}] ->
@@ -204,18 +111,11 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
io_lib:format(
"complete(enc_~s(~s))",
[Tname,Value]);
- _ -> Value
+ _ ->
+ io_lib:format("iolist_to_binary(~s)",
+ [Value])
end,
- call(Erules, encode_open_type, [NewValue]);
- #'ObjectClassFieldType'{} ->
- case asn1ct_gen:get_inner(D#type.def) of
- {fixedtypevaluefield,_,InnerType} ->
- gen_encode_prim(Erules,InnerType,DoTag,Value);
- T -> %% 'ASN1_OPEN_TYPE'
- gen_encode_prim(Erules,D#type{def=T},DoTag,Value)
- end;
- XX ->
- exit({asn1_error,nyi,XX})
+ call(Erules, encode_open_type, [NewValue])
end.
emit_enc_real(Erules, Real) ->
@@ -230,11 +130,7 @@ emit_enc_real(Erules, Real) ->
"end"]).
emit_enc_known_multiplier_string(StringType,C,Value) ->
- SizeC =
- case get_constraint(C,'SizeConstraint') of
- L when is_list(L) -> {lists:min(L),lists:max(L)};
- L -> L
- end,
+ SizeC = effective_constraint(bitstring, C),
PAlphabC = get_constraint(C,'PermittedAlphabet'),
case {StringType,PAlphabC} of
{'UniversalString',{_,_}} ->
@@ -359,7 +255,7 @@ charbits1(NumOfChars) ->
%% copied from run time module
emit_enc_octet_string(Erules, Constraint, Value) ->
- case get_constraint(Constraint,'SizeConstraint') of
+ case effective_constraint(bitstring, Constraint) of
0 ->
emit({" []"});
1 ->
@@ -408,7 +304,7 @@ emit_enc_octet_string(Erules, Constraint, Value) ->
" end"]);
C ->
call(Erules, encode_octet_string,
- [{asis,C},false,Value])
+ [{asis,C},Value])
end.
emit_enc_integer_case(Value) ->
@@ -563,825 +459,3 @@ no_bits(N) when N=<32 -> 5;
no_bits(N) when N=<64 -> 6;
no_bits(N) when N=<128 -> 7;
no_bits(N) when N=<255 -> 8.
-
-%% Object code generating for encoding and decoding
-%% ------------------------------------------------
-
-gen_obj_code(Erules,_Module,Obj) when is_record(Obj,typedef) ->
- ObjName = Obj#typedef.name,
- Def = Obj#typedef.typespec,
- #'Externaltypereference'{module=Mod,type=ClassName} =
- Def#'Object'.classname,
- Class = asn1_db:dbget(Mod,ClassName),
- {object,_,Fields} = Def#'Object'.def,
- emit({nl,nl,nl,"%%================================"}),
- emit({nl,"%% ",ObjName}),
- emit({nl,"%%================================",nl}),
- EncConstructed =
- gen_encode_objectfields(Erules,ClassName,get_class_fields(Class),
- ObjName,Fields,[]),
- emit(nl),
- gen_encode_constr_type(Erules,EncConstructed),
- emit(nl),
- DecConstructed =
- gen_decode_objectfields(ClassName,get_class_fields(Class),
- ObjName,Fields,[]),
- emit(nl),
- gen_decode_constr_type(Erules,DecConstructed),
- emit(nl);
-gen_obj_code(_Erules,_Module,Obj) when is_record(Obj,pobjectdef) ->
- ok.
-
-gen_encode_objectfields(Erules,ClassName,[{typefield,Name,OptOrMand}|Rest],
- ObjName,ObjectFields,ConstrAcc) ->
- EmitFuncClause =
- fun(V) ->
- emit(["'enc_",ObjName,"'(",{asis,Name},
- ",",V,",_RestPrimFieldName) ->",nl])
- end,
-
- MaybeConstr =
- case {get_object_field(Name,ObjectFields),OptOrMand} of
- {false,'MANDATORY'} -> %% this case is illegal
- exit({error,{asn1,{"missing mandatory field in object",
- ObjName}}});
- {false,'OPTIONAL'} ->
- EmitFuncClause("Val"),
- emit([" if",nl,
- " is_list(Val) ->",nl,
- " NewVal = list_to_binary(Val),",nl,
- " [20,byte_size(NewVal),NewVal];",nl,
- " is_binary(Val) ->",nl,
- " [20,byte_size(Val),Val]",nl,
- " end"]),
- [];
- {false,{'DEFAULT',DefaultType}} ->
- EmitFuncClause("Val"),
- gen_encode_default_call(Erules,ClassName,Name,DefaultType);
- {{Name,TypeSpec},_} ->
- %% A specified field owerwrites any 'DEFAULT' or
- %% 'OPTIONAL' field in the class
- EmitFuncClause("Val"),
- gen_encode_field_call(Erules,ObjName,Name,TypeSpec)
- end,
- case more_genfields(Rest) of
- true ->
- emit([";",nl]);
- false ->
- emit([".",nl])
- end,
- gen_encode_objectfields(Erules,ClassName,Rest,ObjName,ObjectFields,
- MaybeConstr++ConstrAcc);
-gen_encode_objectfields(Erules,ClassName,[{objectfield,Name,_,_,OptOrMand}|Rest],
- ObjName,ObjectFields,ConstrAcc) ->
- CurrentMod = get(currmod),
- EmitFuncClause =
- fun(Attrs) ->
- emit(["'enc_",ObjName,"'(",{asis,Name},
- ",",Attrs,") ->",nl])
- end,
-% emit(["'enc_",ObjName,"'(",{asis,Name},
-% ", Val,[H|T]) ->",nl]),
- case {get_object_field(Name,ObjectFields),OptOrMand} of
- {false,'MANDATORY'} ->
- exit({error,{asn1,{"missing mandatory field in object",
- ObjName}}});
- {false,'OPTIONAL'} ->
- EmitFuncClause("_,_"),
- emit([" exit({error,{'use of missing field in object', ",{asis,Name},
- "}})"]);
- {false,{'DEFAULT',_DefaultObject}} ->
- exit({error,{asn1,{"not implemented yet",Name}}});
- {{Name,#'Externalvaluereference'{module=CurrentMod,
- value=TypeName}},_} ->
- EmitFuncClause(" Val, [H|T]"),
- emit({indent(3),"'enc_",TypeName,"'(H, Val, T)"});
- {{Name,#'Externalvaluereference'{module=M,value=TypeName}},_} ->
- EmitFuncClause(" Val, [H|T]"),
- emit({indent(3),"'",M,"':'enc_",TypeName,"'(H, Val, T)"});
- {{Name,TypeSpec},_} ->
- EmitFuncClause("Val,[H|T]"),
- case TypeSpec#typedef.name of
- {ExtMod,TypeName} ->
- emit({indent(3),"'",ExtMod,"':'enc_",TypeName,
- "'(H, Val, T)"});
- TypeName ->
- emit({indent(3),"'enc_",TypeName,"'(H, Val, T)"})
- end
- end,
- case more_genfields(Rest) of
- true ->
- emit([";",nl]);
- false ->
- emit([".",nl])
- end,
- gen_encode_objectfields(Erules,ClassName,Rest,ObjName,ObjectFields,ConstrAcc);
-gen_encode_objectfields(Erules,ClassName,[_C|Cs],O,OF,Acc) ->
- gen_encode_objectfields(Erules,ClassName,Cs,O,OF,Acc);
-gen_encode_objectfields(_Erules,_,[],_,_,Acc) ->
- Acc.
-
-
-
-gen_encode_constr_type(Erules,[TypeDef|Rest]) when is_record(TypeDef,typedef) ->
- case is_already_generated(enc,TypeDef#typedef.name) of
- true -> ok;
- _ ->
- Name = lists:concat(["enc_",TypeDef#typedef.name]),
- emit({Name,"(Val) ->",nl}),
- Def = TypeDef#typedef.typespec,
- InnerType = asn1ct_gen:get_inner(Def#type.def),
- asn1ct_gen:gen_encode_constructed(Erules,Name,InnerType,Def),
- gen_encode_constr_type(Erules,Rest)
- end;
-gen_encode_constr_type(_,[]) ->
- ok.
-
-gen_encode_field_call(_Erule,_ObjName,_FieldName,
- #'Externaltypereference'{module=M,type=T}) ->
- CurrentMod = get(currmod),
- if
- M == CurrentMod ->
- emit({" 'enc_",T,"'(Val)"}),
- [];
- true ->
- emit({" '",M,"':'enc_",T,"'(Val)"}),
- []
- end;
-gen_encode_field_call(Erule,ObjName,FieldName,Type) ->
- Def = Type#typedef.typespec,
- case Type#typedef.name of
- {primitive,bif} ->
- gen_encode_prim(Erule,Def,"false",
- "Val"),
- [];
- {constructed,bif} ->
- emit({" 'enc_",ObjName,'_',FieldName,
- "'(Val)"}),
- [Type#typedef{name=list_to_atom(lists:concat([ObjName,'_',FieldName]))}];
- {ExtMod,TypeName} ->
- emit({" '",ExtMod,"':'enc_",TypeName,
- "'(Val)"}),
- [];
- TypeName ->
- emit({" 'enc_",TypeName,"'(Val)"}),
- []
- end.
-
-gen_encode_default_call(Erules,ClassName,FieldName,Type) ->
- CurrentMod = get(currmod),
- InnerType = asn1ct_gen:get_inner(Type#type.def),
- case asn1ct_gen:type(InnerType) of
- {constructed,bif} ->
-%% asn1ct_gen:gen_encode_constructed(Erules,Typename,InnerType,Type);
- emit([" 'enc_",ClassName,'_',FieldName,"'(Val)"]),
- [#typedef{name=list_to_atom(lists:concat([ClassName,'_',FieldName])),
- typespec=Type}];
- {primitive,bif} ->
- gen_encode_prim(Erules,Type,"false","Val"),
- [];
- #'Externaltypereference'{module=CurrentMod,type=Etype} ->
- emit([" 'enc_",Etype,"'(Val)",nl]),
- [];
- #'Externaltypereference'{module=Emod,type=Etype} ->
- emit([" '",Emod,"':'enc_",Etype,"'(Val)",nl]),
- []
- end.
-
-
-
-gen_decode_objectfields(ClassName,[{typefield,Name,OptOrMand}|Rest],
- ObjName,ObjectFields,ConstrAcc) ->
- EmitFuncClause =
- fun(Bytes) ->
- emit(["'dec_",ObjName,"'(",{asis,Name},",",Bytes,
- ",_,_RestPrimFieldName) ->",nl])
- end,
-% emit(["'dec_",ObjName,"'(",{asis,Name},
-% ", Bytes, _, RestPrimFieldName) ->",nl]),
- MaybeConstr=
- case {get_object_field(Name,ObjectFields),OptOrMand} of
- {false,'MANDATORY'} -> %% this case is illegal
- exit({error,{asn1,{"missing mandatory field in object",
- ObjName}}});
- {false,'OPTIONAL'} ->
- EmitFuncClause("Bytes"),
- emit([" {Bytes,[]}"]),
- [];
- {false,{'DEFAULT',DefaultType}} ->
- EmitFuncClause("Bytes"),
- gen_decode_default_call(ClassName,Name,"Bytes",DefaultType);
- {{Name,TypeSpec},_} ->
- %% A specified field owerwrites any 'DEFAULT' or
- %% 'OPTIONAL' field in the class
- EmitFuncClause("Bytes"),
- gen_decode_field_call(ObjName,Name,"Bytes",TypeSpec)
- end,
- case more_genfields(Rest) of
- true ->
- emit([";",nl]);
- false ->
- emit([".",nl])
- end,
- gen_decode_objectfields(ClassName,Rest,ObjName,ObjectFields,MaybeConstr++ConstrAcc);
-gen_decode_objectfields(ClassName,[{objectfield,Name,_,_,OptOrMand}|Rest],
- ObjName,ObjectFields,ConstrAcc) ->
- CurrentMod = get(currmod),
- EmitFuncClause =
- fun(Attrs) ->
- emit(["'dec_",ObjName,"'(",{asis,Name},
- ",",Attrs,") ->",nl])
- end,
-% emit(["'dec_",ObjName,"'(",{asis,Name},
-% ", Bytes,_,[H|T]) ->",nl]),
- case {get_object_field(Name,ObjectFields),OptOrMand} of
- {false,'MANDATORY'} ->
- exit({error,{asn1,{"missing mandatory field in object",
- ObjName}}});
- {false,'OPTIONAL'} ->
- EmitFuncClause("_,_,_"),
- emit([" exit({error,{'illegal use of missing field in object', ",{asis,Name},
- "}})"]);
- {false,{'DEFAULT',_DefaultObject}} ->
- exit({error,{asn1,{"not implemented yet",Name}}});
- {{Name,#'Externalvaluereference'{module=CurrentMod,
- value=TypeName}},_} ->
- EmitFuncClause("Bytes,_,[H|T]"),
- emit({indent(3),"'dec_",TypeName,"'(H, Bytes, telltype, T)"});
- {{Name,#'Externalvaluereference'{module=M,value=TypeName}},_} ->
- EmitFuncClause("Bytes,_,[H|T]"),
- emit({indent(3),"'",M,"':'dec_",TypeName,
- "'(H, Bytes, telltype, T)"});
- {{Name,TypeSpec},_} ->
- EmitFuncClause("Bytes,_,[H|T]"),
- case TypeSpec#typedef.name of
- {ExtMod,TypeName} ->
- emit({indent(3),"'",ExtMod,"':'dec_",TypeName,
- "'(H, Bytes, telltype, T)"});
- TypeName ->
- emit({indent(3),"'dec_",TypeName,"'(H, Bytes, telltype, T)"})
- end
- end,
- case more_genfields(Rest) of
- true ->
- emit([";",nl]);
- false ->
- emit([".",nl])
- end,
- gen_decode_objectfields(ClassName,Rest,ObjName,ObjectFields,ConstrAcc);
-gen_decode_objectfields(CN,[_C|Cs],O,OF,CAcc) ->
- gen_decode_objectfields(CN,Cs,O,OF,CAcc);
-gen_decode_objectfields(_,[],_,_,CAcc) ->
- CAcc.
-
-
-gen_decode_field_call(_ObjName,_FieldName,Bytes,
- #'Externaltypereference'{module=M,type=T}) ->
- CurrentMod = get(currmod),
- if
- M == CurrentMod ->
- emit([" 'dec_",T,"'(",Bytes,", telltype)"]),
- [];
- true ->
- emit([" '",M,"':'dec_",T,"'(",Bytes,", telltype)"]),
- []
- end;
-gen_decode_field_call(ObjName,FieldName,Bytes,Type) ->
- Def = Type#typedef.typespec,
- case Type#typedef.name of
- {primitive,bif} ->
- gen_dec_prim(per,Def,Bytes),
- [];
- {constructed,bif} ->
- emit({" 'dec_",ObjName,'_',FieldName,
- "'(",Bytes,",telltype)"}),
- [Type#typedef{name=list_to_atom(lists:concat([ObjName,'_',FieldName]))}];
- {ExtMod,TypeName} ->
- emit({" '",ExtMod,"':'dec_",TypeName,
- "'(",Bytes,", telltype)"}),
- [];
- TypeName ->
- emit({" 'dec_",TypeName,"'(",Bytes,", telltype)"}),
- []
- end.
-
-gen_decode_default_call(ClassName,FieldName,Bytes,Type) ->
- CurrentMod = get(currmod),
- InnerType = asn1ct_gen:get_inner(Type#type.def),
- case asn1ct_gen:type(InnerType) of
- {constructed,bif} ->
- emit([" 'dec_",ClassName,'_',FieldName,"'(",Bytes,", telltype)"]),
- [#typedef{name=list_to_atom(lists:concat([ClassName,'_',FieldName])),
- typespec=Type}];
- {primitive,bif} ->
- gen_dec_prim(per,Type,Bytes),
- [];
- #'Externaltypereference'{module=CurrentMod,type=Etype} ->
- emit([" 'dec_",Etype,"'(",Bytes,", telltype)",nl]),
- [];
- #'Externaltypereference'{module=Emod,type=Etype} ->
- emit([" '",Emod,"':'dec_",Etype,"'(",Bytes,", telltype)",nl]),
- []
- end.
-
-%%%%%%%%%%%%%%%
-
-
-gen_decode_constr_type(Erules,[TypeDef|Rest]) when is_record(TypeDef,typedef) ->
- case is_already_generated(dec,TypeDef#typedef.name) of
- true -> ok;
- _ ->
- gen_decode(Erules,TypeDef)
- end,
- gen_decode_constr_type(Erules,Rest);
-gen_decode_constr_type(_,[]) ->
- ok.
-
-%% Object Set code generating for encoding and decoding
-%% ----------------------------------------------------
-gen_objectset_code(Erules,ObjSet) ->
- ObjSetName = ObjSet#typedef.name,
- Def = ObjSet#typedef.typespec,
-%% {ClassName,ClassDef} = Def#'ObjectSet'.class,
- #'Externaltypereference'{module=ClassModule,
- type=ClassName} = Def#'ObjectSet'.class,
- ClassDef = asn1_db:dbget(ClassModule,ClassName),
- UniqueFName = Def#'ObjectSet'.uniquefname,
- Set = Def#'ObjectSet'.set,
- emit({nl,nl,nl,"%%================================"}),
- emit({nl,"%% ",ObjSetName}),
- emit({nl,"%%================================",nl}),
- case ClassName of
- {_Module,ExtClassName} ->
- gen_objset_code(Erules,ObjSetName,UniqueFName,Set,
- ExtClassName,ClassDef);
- _ ->
- gen_objset_code(Erules,ObjSetName,UniqueFName,Set,
- ClassName,ClassDef)
- end,
- emit(nl).
-
-gen_objset_code(Erule,ObjSetName,UniqueFName,Set,ClassName,ClassDef)->
- ClassFields = (ClassDef#classdef.typespec)#objectclass.fields,
- InternalFuncs=
- gen_objset_enc(Erule,ObjSetName,UniqueFName,Set,ClassName,
- ClassFields,1,[]),
- gen_objset_dec(ObjSetName,UniqueFName,Set,ClassName,ClassFields,1),
- gen_internal_funcs(Erule,InternalFuncs).
-
-gen_objset_enc(_Erule,_,{unique,undefined},_,_,_,_,_) ->
- %% There is no unique field in the class of this object set
- %% don't bother about the constraint
- [];
-gen_objset_enc(Erule,ObjSName,UniqueName,[{ObjName,Val,Fields},T|Rest],
- ClName,ClFields,NthObj,Acc)->
- emit({"'getenc_",ObjSName,"'(",{asis,UniqueName},",",
- {asis,Val},") ->",nl}),
- CurrMod = get(currmod),
- {InternalFunc,NewNthObj}=
- case ObjName of
- {no_mod,no_name} ->
- gen_inlined_enc_funs(Erule,Fields,ClFields,ObjSName,NthObj);
- {CurrMod,Name} ->
- emit({" fun 'enc_",Name,"'/3"}),
- {[],NthObj};
- {ModName,Name} ->
- emit_ext_encfun(ModName,Name),
-% emit([" {'",ModName,"', 'enc_",Name,"'}"]),
- {[],NthObj};
- _ ->
- emit({" fun 'enc_",ObjName,"'/3"}),
- {[],NthObj}
- end,
- emit({";",nl}),
- gen_objset_enc(Erule,ObjSName,UniqueName,[T|Rest],ClName,ClFields,
- NewNthObj,InternalFunc++Acc);
-gen_objset_enc(Erule,ObjSetName,UniqueName,
- [{ObjName,Val,Fields}],_ClName,ClFields,NthObj,Acc) ->
-
- emit({"'getenc_",ObjSetName,"'(",{asis,UniqueName},",",
- {asis,Val},") ->",nl}),
- CurrMod = get(currmod),
- {InternalFunc,_}=
- case ObjName of
- {no_mod,no_name} ->
- gen_inlined_enc_funs(Erule,Fields,ClFields,ObjSetName,NthObj);
- {CurrMod,Name} ->
- emit({" fun 'enc_",Name,"'/3"}),
- {[],NthObj};
- {ModName,Name} ->
- emit_ext_encfun(ModName,Name),
-% emit([" {'",ModName,"', 'enc_",Name,"'}"]),
- {[],NthObj};
- _ ->
- emit({" fun 'enc_",ObjName,"'/3"}),
- {[],NthObj}
- end,
- emit([";",nl]),
- emit_default_getenc(ObjSetName,UniqueName),
- emit({".",nl,nl}),
- InternalFunc++Acc;
-gen_objset_enc(_Erule,ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName,
- _ClFields,_NthObj,Acc) ->
- emit({"'getenc_",ObjSetName,"'(_, _) ->",nl}),
- emit({indent(3),"fun(_, Val, _) ->",nl}),
- emit({indent(6),"BinVal = if",nl}),
- emit({indent(9),"is_list(Val) -> list_to_binary(Val);",nl}),
- emit({indent(9),"true -> Val",nl}),
- emit({indent(6),"end,",nl}),
- emit({indent(6),"Size = byte_size(BinVal),",nl}),
- emit({indent(6),"if",nl}),
- emit({indent(9),"Size < 256 ->",nl}),
- emit({indent(12),"[20,Size,BinVal];",nl}),
- emit({indent(9),"true ->",nl}),
- emit({indent(12),"[21,<<Size:16>>,Val]",nl}),
- emit({indent(6),"end",nl}),
- emit({indent(3),"end.",nl,nl}),
- Acc;
-gen_objset_enc(_Erule,_,_,[],_,_,_,Acc) ->
- Acc.
-
-emit_ext_encfun(ModuleName,Name) ->
- emit([indent(4),"fun(T,V,O) -> '",ModuleName,"':'enc_",
- Name,"'(T,V,O) end"]).
-
-emit_default_getenc(ObjSetName,UniqueName) ->
- emit(["'getenc_",ObjSetName,"'(",{asis,UniqueName},", ErrV) ->",nl]),
- emit([indent(4),"fun(C,V,_) -> exit({'Type not compatible with table constraint',{component,C},{value,V},{unique_name_and_value,",{asis,UniqueName},",ErrV}}) end"]).
-
-
-%% gen_inlined_enc_funs for each object iterates over all fields of a
-%% class, and for each typefield it checks if the object has that
-%% field and emits the proper code.
-gen_inlined_enc_funs(Erule,Fields,[{typefield,Name,_}|Rest],ObjSetName,NthObj) ->
- CurrMod = get(currmod),
- InternalDefFunName=asn1ct_gen:list2name([NthObj,Name,ObjSetName]),
- case lists:keysearch(Name,1,Fields) of
- {value,{_,Type}} when is_record(Type,type) ->
- emit({indent(3),"fun(Type, Val, _) ->",nl,
- indent(6),"case Type of",nl}),
- {Ret,N}=emit_inner_of_fun(Erule,Type,InternalDefFunName),
- gen_inlined_enc_funs1(Erule,Fields,Rest,ObjSetName,NthObj+N,Ret);
- {value,{_,Type}} when is_record(Type,typedef) ->
- emit({indent(3),"fun(Type, Val, _) ->",nl,
- indent(6),"case Type of",nl}),
- emit({indent(9),{asis,Name}," ->",nl}),
- {Ret,N}=emit_inner_of_fun(Erule,Type,InternalDefFunName),
- gen_inlined_enc_funs1(Erule,Fields,Rest,ObjSetName,NthObj+N,Ret);
- {value,{_,#'Externaltypereference'{module=CurrMod,type=T}}} ->
- emit({indent(3),"fun(Type, Val, _) ->",nl,
- indent(6),"case Type of",nl}),
- emit({indent(9),{asis,Name}," ->",nl}),
- emit([indent(12),"'enc_",T,"'(Val)"]),
-% {Ret,N} = emit_inner_of_fun(Erule,TDef,InternalDefFunName),
- gen_inlined_enc_funs1(Erule,Fields,Rest,ObjSetName,NthObj,[]);
- {value,{_,#'Externaltypereference'{module=M,type=T}}} ->
- emit({indent(3),"fun(Type, Val, _) ->",nl,
- indent(6),"case Type of",nl}),
- emit({indent(9),{asis,Name}," ->",nl}),
- emit([indent(12),"'",M,"'",":'enc_",T,"'(Val)"]),
- gen_inlined_enc_funs1(Erule,Fields,Rest,ObjSetName,NthObj,[]);
- false ->
- emit([indent(3),"fun(Type, Val, _) ->",nl,
- indent(6),"case Type of",nl,
- indent(9),{asis,Name}," ->",nl,
- indent(12),"Size = case Val of",nl,
- indent(15),"B when is_binary(B) -> size(B);",nl,
- indent(15),"_ -> length(Val)",nl,
- indent(12),"end,",nl,
- indent(12),"if",nl,
- indent(15),"Size < 256 -> [20,Size,Val];",nl,
- indent(15),"true -> [21,<<Size:16>>,Val]",nl,
- indent(12),"end"]),
- gen_inlined_enc_funs1(Erule,Fields,Rest,ObjSetName,NthObj,[])
- end;
-gen_inlined_enc_funs(Erule,Fields,[_|Rest],ObjSetName,NthObj) ->
- gen_inlined_enc_funs(Erule,Fields,Rest,ObjSetName,NthObj);
-gen_inlined_enc_funs(_Erule,_,[],_,NthObj) ->
- {[],NthObj}.
-
-gen_inlined_enc_funs1(Erule,Fields,[{typefield,Name,_}|Rest],ObjSetName,
- NthObj,Acc) ->
- CurrentMod = get(currmod),
- InternalDefFunName = asn1ct_gen:list2name([NthObj,Name,ObjSetName]),
- {Acc2,NAdd}=
- case lists:keysearch(Name,1,Fields) of
- {value,{_,Type}} when is_record(Type,type) ->
- emit({";",nl}),
- {Ret,N}=emit_inner_of_fun(Erule,Type,InternalDefFunName),
- {Ret++Acc,N};
- {value,{_,Type}} when is_record(Type,typedef) ->
- emit({";",nl,indent(9),{asis,Name}," ->",nl}),
- {Ret,N}=emit_inner_of_fun(Erule,Type,InternalDefFunName),
- {Ret++Acc,N};
- {value,{_,#'Externaltypereference'{module=CurrentMod,type=T}}} ->
- emit({";",nl,indent(9),{asis,Name}," ->",nl}),
- emit([indent(12),"'enc_",T,"'(Val)"]),
- {Acc,0};
- {value,{_,#'Externaltypereference'{module=M,type=T}}} ->
- emit({";",nl,indent(9),{asis,Name}," ->",nl}),
- emit([indent(12),"'",M,"'",":'enc_",T,"'(Val)"]),
- {Acc,0};
- false ->
- emit([";",nl,
- indent(9),{asis,Name}," ->",nl,
- indent(12),"Size = case Val of",nl,
- indent(15),"B when is_binary(B) -> size(B);",nl,
- indent(15),"_ -> length(Val)",nl,
- indent(12),"end,",nl,
- indent(12),"if",nl,
- indent(15),"Size < 256 -> [20,Size,Val];",nl,
- indent(15),"true -> [21,<<Size:16>>,Val]",nl,
- indent(12),"end"]),
- {Acc,0}
- end,
- gen_inlined_enc_funs1(Erule,Fields,Rest,ObjSetName,NthObj+NAdd,Acc2);
-gen_inlined_enc_funs1(Erule,Fields,[_|Rest],ObjSetName,NthObj,Acc)->
- gen_inlined_enc_funs1(Erule,Fields,Rest,ObjSetName,NthObj,Acc);
-gen_inlined_enc_funs1(_Erule,_,[],_,NthObj,Acc) ->
- emit({nl,indent(6),"end",nl}),
- emit({indent(3),"end"}),
- {Acc,NthObj}.
-
-emit_inner_of_fun(Erule,TDef=#typedef{name={ExtMod,Name},typespec=Type},
- InternalDefFunName) ->
- case {ExtMod,Name} of
- {primitive,bif} ->
- emit(indent(12)),
- gen_encode_prim(Erule,Type,dotag,"Val"),
- {[],0};
- {constructed,bif} ->
- emit([indent(12),"'enc_",
- InternalDefFunName,"'(Val)"]),
- {[TDef#typedef{name=InternalDefFunName}],1};
- _ ->
- emit({indent(12),"'",ExtMod,"':'enc_",Name,"'(Val)"}),
- {[],0}
- end;
-emit_inner_of_fun(_Erule,#typedef{name=Name},_) ->
- emit({indent(12),"'enc_",Name,"'(Val)"}),
- {[],0};
-emit_inner_of_fun(Erule,Type,_) when is_record(Type,type) ->
- CurrMod = get(currmod),
- case Type#type.def of
- Def when is_atom(Def) ->
- emit({indent(9),Def," ->",nl,indent(12)}),
- gen_encode_prim(Erule,Type,dotag,"Val");
- TRef when is_record(TRef,typereference) ->
- T = TRef#typereference.val,
- emit({indent(9),T," ->",nl,indent(12),"'enc_",T,"'(Val)"});
- #'Externaltypereference'{module=CurrMod,type=T} ->
- emit({indent(9),T," ->",nl,indent(12),"'enc_",T,"'(Val)"});
- #'Externaltypereference'{module=ExtMod,type=T} ->
- emit({indent(9),T," ->",nl,indent(12),ExtMod,":'enc_",
- T,"'(Val)"})
- end,
- {[],0}.
-
-indent(N) ->
- lists:duplicate(N,32). % 32 = space
-
-
-gen_objset_dec(_,{unique,undefined},_,_,_,_) ->
- %% There is no unique field in the class of this object set
- %% don't bother about the constraint
- ok;
-gen_objset_dec(ObjSName,UniqueName,[{ObjName,Val,Fields},T|Rest],ClName,
- ClFields,NthObj)->
-
- emit({"'getdec_",ObjSName,"'(",{asis,UniqueName},",",
- {asis,Val},") ->",nl}),
- CurrMod = get(currmod),
- NewNthObj=
- case ObjName of
- {no_mod,no_name} ->
- gen_inlined_dec_funs(Fields,ClFields,ObjSName,NthObj);
- {CurrMod,Name} ->
- emit([" fun 'dec_",Name,"'/4"]),
- NthObj;
- {ModName,Name} ->
- emit_ext_decfun(ModName,Name),
-% emit([" {'",ModName,"', 'dec_",Name,"'}"]),
- NthObj;
- _ ->
- emit({" fun 'dec_",ObjName,"'/4"}),
- NthObj
- end,
- emit({";",nl}),
- gen_objset_dec(ObjSName,UniqueName,[T|Rest],ClName,ClFields,NewNthObj);
-gen_objset_dec(ObjSetName,UniqueName,[{ObjName,Val,Fields}],_ClName,
- ClFields,NthObj) ->
-
- emit({"'getdec_",ObjSetName,"'(",{asis,UniqueName},",",
- {asis,Val},") ->",nl}),
- CurrMod=get(currmod),
- case ObjName of
- {no_mod,no_name} ->
- gen_inlined_dec_funs(Fields,ClFields,ObjSetName,NthObj);
- {CurrMod,Name} ->
- emit([" fun 'dec_",Name,"'/4"]);
- {ModName,Name} ->
- emit_ext_decfun(ModName,Name);
-% emit([" {'",ModName,"', 'dec_",Name,"'}"]);
- _ ->
- emit({" fun 'dec_",ObjName,"'/4"})
- end,
- emit([";",nl]),
- emit_default_getdec(ObjSetName,UniqueName),
- emit({".",nl,nl}),
- ok;
-gen_objset_dec(ObjSetName,_,['EXTENSIONMARK'],_ClName,_ClFields,
- _NthObj) ->
- emit({"'getdec_",ObjSetName,"'(_, _) ->",nl}),
- emit({indent(3),"fun(Attr1, Bytes, _, _) ->",nl}),
- emit({indent(6),"{Bytes,Attr1}",nl}),
- emit({indent(3),"end.",nl,nl}),
- ok;
-gen_objset_dec(_,_,[],_,_,_) ->
- ok.
-
-emit_ext_decfun(ModuleName,Name) ->
- emit([indent(3),"fun(T,V,O1,O2) -> '",ModuleName,"':'dec_",
- Name,"'(T,V,O1,O2) 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"]).
-
-
-gen_inlined_dec_funs(Fields, List, ObjSetName, NthObj0) ->
- emit([indent(3),"fun(Type, Val, _, _) ->",nl,
- indent(6),"case Type of",nl]),
- NthObj = gen_inlined_dec_funs1(Fields, List, ObjSetName, "", NthObj0),
- emit([nl,indent(6),"end",nl,
- indent(3),"end"]),
- NthObj.
-
-gen_inlined_dec_funs1(Fields, [{typefield,Name,_}|Rest],
- ObjSetName, Sep0, NthObj) ->
- CurrentMod = get(currmod),
- InternalDefFunName = [NthObj,Name,ObjSetName],
- emit(Sep0),
- Sep = [";",nl],
- N = case lists:keyfind(Name, 1, Fields) of
- {_,#type{}=Type} ->
- emit_inner_of_decfun(Type, InternalDefFunName);
- {_,#typedef{}=Type} ->
- emit([indent(9),{asis,Name}," ->",nl]),
- emit_inner_of_decfun(Type, InternalDefFunName);
- {_,#'Externaltypereference'{module=CurrentMod,type=T}} ->
- emit([indent(9),{asis,Name}," ->",nl,
- indent(12),"'dec_",T,"'(Val,telltype)"]),
- 0;
- {_,#'Externaltypereference'{module=M,type=T}} ->
- emit([indent(9),{asis,Name}," ->",nl,
- indent(12),"'",M,"':'dec_",T,"'(Val,telltype)"]),
- 0;
- false ->
- emit([indent(9),{asis,Name}," -> {Val,Type}"]),
- 0
- end,
- gen_inlined_dec_funs1(Fields, Rest, ObjSetName, Sep, NthObj+N);
-gen_inlined_dec_funs1(Fields, [_|Rest], ObjSetName, Sep, NthObj) ->
- gen_inlined_dec_funs1(Fields, Rest, ObjSetName, Sep, NthObj);
-gen_inlined_dec_funs1(_, [], _, _, NthObj) -> NthObj.
-
-emit_inner_of_decfun(#typedef{name={ExtName,Name},typespec=Type},
- InternalDefFunName) ->
- case {ExtName,Name} of
- {primitive,bif} ->
- emit(indent(12)),
- gen_dec_prim(per,Type,"Val"),
- 0;
- {constructed,bif} ->
- emit({indent(12),"'dec_",
- asn1ct_gen:list2name(InternalDefFunName),"'(Val)"}),
- 1;
- _ ->
- emit({indent(12),"'",ExtName,"':'dec_",Name,
- "'(Val, telltype)"}),
- 0
- end;
-emit_inner_of_decfun(#typedef{name=Name},_) ->
- emit({indent(12),"'dec_",Name,"'(Val, telltype)"}),
- 0;
-emit_inner_of_decfun(Type,_) when is_record(Type,type) ->
- CurrMod = get(currmod),
- case Type#type.def of
- Def when is_atom(Def) ->
- emit({indent(9),Def," ->",nl,indent(12)}),
- gen_dec_prim(per, Type, "Val");
- TRef when is_record(TRef,typereference) ->
- T = TRef#typereference.val,
- emit({indent(9),T," ->",nl,indent(12),"'dec_",T,"'(Val)"});
- #'Externaltypereference'{module=CurrMod,type=T} ->
- emit({indent(9),T," ->",nl,indent(12),"'dec_",T,"'(Val)"});
- #'Externaltypereference'{module=ExtMod,type=T} ->
- emit({indent(9),T," ->",nl,indent(12),ExtMod,":'dec_",
- T,"'(Val)"})
- end,
- 0.
-
-
-gen_internal_funcs(_Erules,[]) ->
- ok;
-gen_internal_funcs(Erules,[TypeDef|Rest]) ->
- gen_encode_user(Erules,TypeDef),
- emit([nl,nl,"'dec_",TypeDef#typedef.name,"'(Bytes) ->",nl]),
- gen_decode_user(Erules,TypeDef),
- gen_internal_funcs(Erules,Rest).
-
-
-
-%% DECODING *****************************
-%%***************************************
-
-
-gen_decode(Erules,Type) when is_record(Type,typedef) ->
- D = Type,
- emit({nl,nl}),
- emit({"'dec_",Type#typedef.name,"'(Bytes,_) ->",nl}),
- dbdec(Type#typedef.name),
- gen_decode_user(Erules,D).
-
-gen_decode(Erules,Tname,#'ComponentType'{name=Cname,typespec=Type}) ->
- NewTname = [Cname|Tname],
- gen_decode(Erules,NewTname,Type);
-
-gen_decode(Erules,Typename,Type) when is_record(Type,type) ->
- InnerType = asn1ct_gen:get_inner(Type#type.def),
- case asn1ct_gen:type(InnerType) of
- {constructed,bif} ->
- ObjFun =
- case Type#type.tablecinf of
- [{objfun,_}|_R] ->
- ", ObjFun";
- _ ->
- ""
- end,
- emit({nl,"'dec_",asn1ct_gen:list2name(Typename),
- "'(Bytes,_",ObjFun,") ->",nl}),
- dbdec(Typename),
- asn1ct_gen:gen_decode_constructed(Erules,Typename,InnerType,Type);
- _ ->
- true
- end.
-
-dbdec(Type) when is_list(Type)->
- demit({"io:format(\"decoding: ",asn1ct_gen:list2name(Type),"~w~n\",[Bytes]),",nl});
-dbdec(Type) ->
- demit({"io:format(\"decoding: ",{asis,Type},"~w~n\",[Bytes]),",nl}).
-
-gen_decode_user(Erules,D) when is_record(D,typedef) ->
- CurrMod = get(currmod),
- Typename = [D#typedef.name],
- Def = D#typedef.typespec,
- InnerType = asn1ct_gen:get_inner(Def#type.def),
- case asn1ct_gen:type(InnerType) of
- {primitive,bif} ->
- gen_dec_prim(Erules,Def,"Bytes"),
- emit({".",nl,nl});
- 'ASN1_OPEN_TYPE' ->
- gen_dec_prim(Erules,Def#type{def='ASN1_OPEN_TYPE'},"Bytes"),
- emit({".",nl,nl});
- {constructed,bif} ->
- asn1ct_gen:gen_decode_constructed(Erules,Typename,InnerType,D);
- #typereference{val=Dname} ->
- emit({"'dec_",Dname,"'(Bytes,telltype)"}),
- emit({".",nl,nl});
- #'Externaltypereference'{module=CurrMod,type=Etype} ->
- emit({"'dec_",Etype,"'(Bytes,telltype).",nl,nl});
- #'Externaltypereference'{module=Emod,type=Etype} ->
- emit({"'",Emod,"':'dec_",Etype,"'(Bytes,telltype).",nl,nl});
- Other ->
- exit({error,{asn1,{unknown,Other}}})
- end.
-
-
-
-gen_dec_prim(Erules, Att, BytesVar) ->
- asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar).
-
-%% For PER the ExtensionAdditionGroup notation has significance for the encoding and decoding
-%% the components within the ExtensionAdditionGroup is treated in a similar way as if they
-%% have been specified within a SEQUENCE, therefore we construct a fake sequence type here
-%% so that we can generate code for it
-extaddgroup2sequence(ExtList) ->
- extaddgroup2sequence(ExtList,0,[]).
-
-extaddgroup2sequence([{'ExtensionAdditionGroup',Number0}|T],ExtNum,Acc) ->
- Number = case Number0 of undefined -> 1; _ -> Number0 end,
- {ExtGroupComps,['ExtensionAdditionGroupEnd'|T2]} =
- lists:splitwith(fun(Elem) -> is_record(Elem,'ComponentType') end,T),
- extaddgroup2sequence(T2,ExtNum+1,
- [#'ComponentType'{
- name=list_to_atom("ExtAddGroup"++
- integer_to_list(ExtNum+1)),
- typespec=#type{def=#'SEQUENCE'{
- extaddgroup=Number,
- components=ExtGroupComps}},
- prop='OPTIONAL'}|Acc]);
-extaddgroup2sequence([C|T],ExtNum,Acc) ->
- extaddgroup2sequence(T,ExtNum,[C|Acc]);
-extaddgroup2sequence([],_,Acc) ->
- lists:reverse(Acc).
diff --git a/lib/asn1/src/asn1ct_imm.erl b/lib/asn1/src/asn1ct_imm.erl
index 4b2c3b1b65..c6803a0f96 100644
--- a/lib/asn1/src/asn1ct_imm.erl
+++ b/lib/asn1/src/asn1ct_imm.erl
@@ -25,6 +25,7 @@
per_dec_length/3,per_dec_named_integer/3,
per_dec_octet_string/2,per_dec_open_type/1,per_dec_real/1,
per_dec_restricted_string/1]).
+-export([per_dec_constrained/3,per_dec_normally_small_number/1]).
-export([optimize_alignment/1,optimize_alignment/2,
dec_slim_cg/2,dec_code_gen/2]).
-export([effective_constraint/2]).
@@ -94,18 +95,16 @@ per_dec_integer(Constraint0, Aligned) ->
per_dec_length(SingleValue, _, _Aligned) when is_integer(SingleValue) ->
{value,SingleValue};
-per_dec_length({S,S}, _, _Aligned) when is_integer(S) ->
- {value,S};
-per_dec_length({{_,_}=Constr,_}, AllowZero, Aligned) ->
+per_dec_length({{Fixed,Fixed},[]}, AllowZero, Aligned) ->
+ bit_case(per_dec_length(Fixed, AllowZero, Aligned),
+ per_dec_length(no, AllowZero, Aligned));
+per_dec_length({{_,_}=Constr,[]}, AllowZero, Aligned) ->
bit_case(per_dec_length(Constr, AllowZero, Aligned),
- per_dec_length(undefined, AllowZero, Aligned));
+ per_dec_length(no, AllowZero, Aligned));
per_dec_length({Lb,Ub}, _AllowZero, Aligned) when is_integer(Lb),
- is_integer(Lb),
- Ub =< 65535 ->
+ is_integer(Lb) ->
per_dec_constrained(Lb, Ub, Aligned);
-per_dec_length({_,_}, AllowZero, Aligned) ->
- decode_unconstrained_length(AllowZero, Aligned);
-per_dec_length(undefined, AllowZero, Aligned) ->
+per_dec_length(no, AllowZero, Aligned) ->
decode_unconstrained_length(AllowZero, Aligned).
per_dec_named_integer(Constraint, NamedList0, Aligned) ->
@@ -114,17 +113,27 @@ per_dec_named_integer(Constraint, NamedList0, Aligned) ->
{map,Int,NamedList}.
per_dec_k_m_string(StringType, Constraint, Aligned) ->
- SzConstr = get_constraint(Constraint, 'SizeConstraint'),
+ SzConstr = effective_constraint(bitstring, Constraint),
N = string_num_bits(StringType, Constraint, Aligned),
- Imm = dec_string(SzConstr, N, Aligned),
+ %% X.691 (07/2002) 27.5.7 says if the upper bound times the number
+ %% of bits is greater than or equal to 16, then the bit field should
+ %% be aligned.
+ Imm = dec_string(SzConstr, N, Aligned, fun(_, Ub) -> Ub >= 16 end),
Chars = char_tab(Constraint, StringType, N),
convert_string(N, Chars, Imm).
per_dec_octet_string(Constraint, Aligned) ->
- dec_string(Constraint, 8, Aligned).
+ dec_string(Constraint, 8, Aligned,
+ %% Aligned unless the size is fixed and =< 16.
+ fun(Sv, Sv) -> Sv > 16;
+ (_, _) -> true
+ end).
per_dec_raw_bitstring(Constraint, Aligned) ->
- dec_string(Constraint, 1, Aligned).
+ dec_string(Constraint, 1, Aligned,
+ fun(Sv, Sv) -> Sv > 16;
+ (_, _) -> true
+ end).
per_dec_open_type(Aligned) ->
{get_bits,decode_unconstrained_length(true, Aligned),
@@ -148,21 +157,21 @@ per_dec_restricted_string(Aligned) ->
%%% Local functions.
%%%
-dec_string(Sv, U, _Aligned) when is_integer(Sv), U*Sv =< 16 ->
- {get_bits,Sv,[U,binary]};
-dec_string(Sv, U, Aligned) when is_integer(Sv), Sv < 16#10000 ->
+dec_string(Sv, U, Aligned0, AF) when is_integer(Sv) ->
+ Bits = U*Sv,
+ Aligned = Aligned0 andalso AF(Bits, Bits),
{get_bits,Sv,[U,binary,{align,Aligned}]};
-dec_string([_|_]=C, U, Aligned) when is_list(C) ->
- dec_string({hd(C),lists:max(C)}, U, Aligned);
-dec_string({Sv,Sv}, U, Aligned) ->
- dec_string(Sv, U, Aligned);
-dec_string({{_,_}=C,_}, U, Aligned) ->
- bit_case(dec_string(C, U, Aligned),
- dec_string(no, U, Aligned));
-dec_string({Lb,Ub}, U, Aligned) when Ub < 16#10000 ->
- Len = per_dec_constrained(Lb, Ub, Aligned),
+dec_string({{Sv,Sv},[]}, U, Aligned, AF) ->
+ bit_case(dec_string(Sv, U, Aligned, AF),
+ dec_string(no, U, Aligned, AF));
+dec_string({{_,_}=C,[]}, U, Aligned, AF) ->
+ bit_case(dec_string(C, U, Aligned, AF),
+ dec_string(no, U, Aligned, AF));
+dec_string({Lb,Ub}, U, Aligned0, AF) ->
+ Len = per_dec_constrained(Lb, Ub, Aligned0),
+ Aligned = Aligned0 andalso AF(Lb*U, Ub*U),
{get_bits,Len,[U,binary,{align,Aligned}]};
-dec_string(_, U, Aligned) ->
+dec_string(_, U, Aligned, _AF) ->
Al = [{align,Aligned}],
DecRest = fun(V, Buf) ->
asn1ct_func:call(per_common,
@@ -189,7 +198,7 @@ per_dec_enumerated_fix_list([], Tail, _) -> Tail.
per_dec_integer_1([{'SingleValue',Value}], _Aligned) ->
{value,Value};
per_dec_integer_1([{'ValueRange',{Lb,'MAX'}}], Aligned) when is_integer(Lb) ->
- per_dec_unconstrained(Aligned);
+ per_decode_semi_constrained(Lb, Aligned);
per_dec_integer_1([{'ValueRange',{Lb,Ub}}], Aligned) when is_integer(Lb),
is_integer(Ub) ->
per_dec_constrained(Lb, Ub, Aligned);
@@ -700,7 +709,27 @@ effective_constraint(integer, C) ->
VR = effective_constr('ValueRange', VRs),
greatest_common_range(SV, VR);
effective_constraint(bitstring, C) ->
- get_constraint(C, 'SizeConstraint').
+ case get_constraint(C, 'SizeConstraint') of
+ {{Lb,Ub},[]}=Range when is_integer(Lb) ->
+ if
+ is_integer(Ub), Ub < 16#10000 ->
+ Range;
+ true ->
+ no
+ end;
+ {Lb,Ub}=Range when is_integer(Lb) ->
+ if
+ is_integer(Ub), Ub < 16#10000 ->
+ if
+ Lb =:= Ub -> Lb;
+ true -> Range
+ end;
+ true ->
+ no
+ end;
+ no ->
+ no
+ end.
effective_constr(_, []) -> [];
effective_constr('SingleValue', List) ->
diff --git a/lib/asn1/src/asn1ct_name.erl b/lib/asn1/src/asn1ct_name.erl
index 3ab6f7b0ed..c0c2ed302c 100644
--- a/lib/asn1/src/asn1ct_name.erl
+++ b/lib/asn1/src/asn1ct_name.erl
@@ -21,13 +21,8 @@
%%-compile(export_all).
-export([start/0,
- stop/0,
- push/1,
- pop/1,
curr/1,
clear/0,
- delete/1,
- active/1,
prev/1,
next/1,
all/1,
@@ -43,30 +38,19 @@ start() ->
end)),
ok;
_Pid ->
- already_started
+ %% Already started. Clear the variables.
+ clear()
end.
-stop() ->
- req(stop),
- erase(?MODULE).
-
name_server_loop({Ref, Parent} = Monitor,Vars) ->
%% io:format("name -- ~w~n",[Vars]),
receive
+ {_From,clear} ->
+ name_server_loop(Monitor, []);
{From,{current,Variable}} ->
From ! {?MODULE,get_curr(Vars,Variable)},
name_server_loop(Monitor,Vars);
- {From,{pop,Variable}} ->
- From ! {?MODULE,done},
- name_server_loop(Monitor,pop_var(Vars,Variable));
- {From,{push,Variable}} ->
- From ! {?MODULE,done},
- name_server_loop(Monitor,push_var(Vars,Variable));
- {From,{delete,Variable}} ->
- From ! {?MODULE,done},
- name_server_loop(Monitor,delete_var(Vars,Variable));
- {From,{new,Variable}} ->
- From ! {?MODULE,done},
+ {_From,{new,Variable}} ->
name_server_loop(Monitor,new_var(Vars,Variable));
{From,{prev,Variable}} ->
From ! {?MODULE,get_prev(Vars,Variable)},
@@ -74,32 +58,29 @@ name_server_loop({Ref, Parent} = Monitor,Vars) ->
{From,{next,Variable}} ->
From ! {?MODULE,get_next(Vars,Variable)},
name_server_loop(Monitor,Vars);
- {'DOWN', Ref, process, Parent, Reason} ->
- exit(Reason);
- {From,stop} ->
- From ! {?MODULE,stopped}
- end.
-
-active(V) ->
- case curr(V) of
- nil -> false;
- _ -> true
+ {'DOWN', Ref, process, Parent, Reason} ->
+ exit(Reason)
end.
req(Req) ->
- get(?MODULE) ! {self(), Req},
+ Pid = get(?MODULE),
+ Ref = monitor(process, Pid),
+ Pid ! {self(), Req},
receive
- {?MODULE, Reply} -> Reply
- after 5000 ->
- exit(name_server_timeout)
+ {?MODULE, Reply} ->
+ Reply;
+ {'DOWN', Ref, process, Pid, Reason} ->
+ error({name_server_died,Reason})
end.
-pop(V) -> req({pop,V}).
-push(V) -> req({push,V}).
-clear() -> stop(), start().
+cast(Req) ->
+ get(?MODULE) ! {self(), Req},
+ ok.
+
+clear() -> cast(clear).
curr(V) -> req({current,V}).
-new(V) -> req({new,V}).
-delete(V) -> req({delete,V}).
+new(V) -> cast({new,V}).
+
prev(V) ->
case req({prev,V}) of
none ->
@@ -108,11 +89,7 @@ prev(V) ->
end.
next(V) ->
- case req({next,V}) of
- none ->
- exit('cant get next of none');
- Rep -> Rep
- end.
+ req({next,V}).
all(V) ->
Curr = curr(V),
@@ -146,81 +123,36 @@ get_digs([H|T]) ->
[]
end.
-push_var(Vars,Variable) ->
- case lists:keysearch(Variable,1,Vars) of
- false ->
- [{Variable,[0]}|Vars];
- {value,{Variable,[Digit|Drest]}} ->
- NewVars = lists:keydelete(Variable,1,Vars),
- [{Variable,[Digit,Digit|Drest]}|NewVars]
- end.
-
-pop_var(Vars,Variable) ->
- case lists:keysearch(Variable,1,Vars) of
- false ->
- ok;
- {value,{Variable,[_Dig]}} ->
- lists:keydelete(Variable,1,Vars);
- {value,{Variable,[_Dig|Digits]}} ->
- NewVars = lists:keydelete(Variable,1,Vars),
- [{Variable,Digits}|NewVars]
- end.
-
-get_curr([],Variable) ->
+get_curr([], Variable) ->
Variable;
-get_curr([{Variable,[0|_Drest]}|_Tail],Variable) ->
- Variable;
-get_curr([{Variable,[Digit|_Drest]}|_Tail],Variable) ->
- list_to_atom(lists:concat([Variable,integer_to_list(Digit)]));
-
-get_curr([_|Tail],Variable) ->
- get_curr(Tail,Variable).
-
-new_var(Vars,Variable) ->
- case lists:keysearch(Variable,1,Vars) of
- false ->
- [{Variable,[1]}|Vars];
- {value,{Variable,[Digit|Drest]}} ->
- NewVars = lists:keydelete(Variable,1,Vars),
- [{Variable,[Digit+1|Drest]}|NewVars]
- end.
+get_curr([{Variable,Digit}|_Tail], Variable) ->
+ list_to_atom(lists:concat([Variable,Digit]));
+get_curr([_|Tail], Variable) ->
+ get_curr(Tail, Variable).
-delete_var(Vars,Variable) ->
- case lists:keysearch(Variable,1,Vars) of
+new_var(Vars, Variable) ->
+ case lists:keyfind(Variable, 1, Vars) of
false ->
- Vars;
- {value,{Variable,[N]}} when N =< 1 ->
- lists:keydelete(Variable,1,Vars);
- {value,{Variable,[Digit|Drest]}} ->
- case Digit of
- 0 ->
- Vars;
- _ ->
- NewVars = lists:keydelete(Variable,1,Vars),
- [{Variable,[Digit-1|Drest]}|NewVars]
- end
+ [{Variable,1}|Vars];
+ {Variable,Digit} ->
+ NewVars = lists:keydelete(Variable, 1, Vars),
+ [{Variable,Digit+1}|NewVars]
end.
-get_prev(Vars,Variable) ->
- case lists:keysearch(Variable,1,Vars) of
+get_prev(Vars, Variable) ->
+ case lists:keyfind(Variable, 1, Vars) of
false ->
none;
- {value,{Variable,[Digit|_]}} when Digit =< 1 ->
+ {Variable,Digit} when Digit =< 1 ->
Variable;
- {value,{Variable,[Digit|_]}} when Digit > 1 ->
- list_to_atom(lists:concat([Variable,
- integer_to_list(Digit-1)]));
- _ ->
- none
+ {Variable,Digit} when Digit > 1 ->
+ list_to_atom(lists:concat([Variable,Digit-1]))
end.
-get_next(Vars,Variable) ->
- case lists:keysearch(Variable,1,Vars) of
+get_next(Vars, Variable) ->
+ case lists:keyfind(Variable, 1, Vars) of
false ->
list_to_atom(lists:concat([Variable,"1"]));
- {value,{Variable,[Digit|_]}} when Digit >= 0 ->
- list_to_atom(lists:concat([Variable,
- integer_to_list(Digit+1)]));
- _ ->
- none
+ {Variable,Digit} when Digit >= 0 ->
+ list_to_atom(lists:concat([Variable,Digit+1]))
end.
diff --git a/lib/asn1/src/asn1ct_parser2.erl b/lib/asn1/src/asn1ct_parser2.erl
index 9e1fcce2b1..344fdf44dd 100644
--- a/lib/asn1/src/asn1ct_parser2.erl
+++ b/lib/asn1/src/asn1ct_parser2.erl
@@ -23,6 +23,10 @@
-export([parse/1]).
-include("asn1_records.hrl").
+%% Only used internally within this module.
+-record(typereference, {pos,val}).
+-record(constraint,{c,e}).
+
%% parse all types in module
parse(Tokens) ->
case catch parse_ModuleDefinition(Tokens) of
@@ -458,7 +462,8 @@ parse_BuiltinType([{'INSTANCE',_},{'OF',_}|Rest]) ->
{DefinedObjectClass,Rest2} = parse_DefinedObjectClass(Rest),
case Rest2 of
[{'(',_}|_] ->
- {Constraint,Rest3} = parse_Constraint(Rest2),
+ {Constraint0,Rest3} = parse_Constraint(Rest2),
+ Constraint = merge_constraints([Constraint0]),
{#type{def={'INSTANCE OF',DefinedObjectClass,Constraint}},Rest3};
_ ->
{#type{def={'INSTANCE OF',DefinedObjectClass,[]}},Rest2}
diff --git a/lib/asn1/src/asn1ct_value.erl b/lib/asn1/src/asn1ct_value.erl
index 764555c4d2..ecdfa3f645 100644
--- a/lib/asn1/src/asn1ct_value.erl
+++ b/lib/asn1/src/asn1ct_value.erl
@@ -51,8 +51,6 @@ from_type(M,Typename,Type) when is_record(Type,type) ->
from_type(Emod,Etype);
{_,user} ->
from_type(M,InnerType);
- {notype,_} ->
- true;
{primitive,bif} ->
from_type_prim(M, Type);
'ASN1_OPEN_TYPE' ->
@@ -216,8 +214,6 @@ from_type_prim(M, D) ->
_ ->
[lists:nth(random(length(NN)),NN)]
end;
- 'ANY' ->
- exit({asn1_error,nyi,'ANY'});
'NULL' ->
'NULL';
'OBJECT IDENTIFIER' ->
diff --git a/lib/asn1/src/asn1rtt_ber.erl b/lib/asn1/src/asn1rtt_ber.erl
index 5fbf116747..b5429fe324 100644
--- a/lib/asn1/src/asn1rtt_ber.erl
+++ b/lib/asn1/src/asn1rtt_ber.erl
@@ -27,7 +27,8 @@
skip_ExtensionAdditions/2]).
-export([encode_boolean/2,decode_boolean/2,
encode_integer/2,encode_integer/3,
- decode_integer/3,decode_integer/4,
+ decode_integer/2,decode_integer/3,
+ decode_named_integer/3,decode_named_integer/4,
encode_enumerated/2,decode_enumerated/3,
encode_bit_string/4,
decode_named_bit_string/3,
@@ -41,9 +42,7 @@
decode_restricted_string/2,decode_restricted_string/3,
encode_universal_string/2,decode_universal_string/3,
encode_UTF8_string/2,decode_UTF8_string/2,
- encode_BMP_string/2,decode_BMP_string/3,
- encode_generalized_time/2,decode_generalized_time/3,
- encode_utc_time/2,decode_utc_time/3]).
+ encode_BMP_string/2,decode_BMP_string/3]).
-export([encode_open_type/2,decode_open_type/2,
decode_open_type_as_binary/2]).
@@ -700,11 +699,20 @@ encode_integer_neg(N, Acc) ->
%% (Buffer, Range, NamedNumberList, HasTag, TotalLen) -> {Integer, Remain, RemovedBytes}
%%===============================================================================
-decode_integer(Tlv, Range, NamedNumberList, TagIn) ->
+decode_named_integer(Tlv, NamedNumberList, TagIn) ->
+ V = match_tags(Tlv, TagIn),
+ Int = decode_integer(V),
+ number2name(Int, NamedNumberList).
+
+decode_named_integer(Tlv, Range, NamedNumberList, TagIn) ->
V = match_tags(Tlv, TagIn),
Int = range_check_integer(decode_integer(V), Range),
number2name(Int, NamedNumberList).
+decode_integer(Tlv, TagIn) ->
+ V = match_tags(Tlv, TagIn),
+ decode_integer(V).
+
decode_integer(Tlv, Range, TagIn) ->
V = match_tags(Tlv, TagIn),
Int = decode_integer(V),
@@ -715,21 +723,10 @@ decode_integer(Bin) ->
<<Int:Len/signed-unit:8>> = Bin,
Int.
+range_check_integer(Int, {Lb,Ub}) when Lb =< Int, Int =< Ub ->
+ Int;
range_check_integer(Int, Range) ->
- case Range of
- [] -> % No length constraint
- Int;
- {Lb,Ub} when Int >= Lb, Ub >= Int -> % variable length constraint
- Int;
- {_,_} ->
- exit({error,{asn1,{integer_range,Range,Int}}});
- Int -> % fixed value constraint
- Int;
- SingleValue when is_integer(SingleValue) ->
- exit({error,{asn1,{integer_range,Range,Int}}});
- _ -> % some strange constraint that we don't support yet
- Int
- end.
+ exit({error,{asn1,{integer_range,Range,Int}}}).
number2name(Int, []) ->
Int;
@@ -838,8 +835,8 @@ int_to_bitlist(Int) when is_integer(Int), Int >= 0 ->
%% and BinBits is a binary representing the BIT STRING.
%%=================================================================
encode_bin_bit_string(C,{Unused,BinBits},_NamedBitList,TagIn)->
- case get_constraint(C,'SizeConstraint') of
- no ->
+ case C of
+ [] ->
remove_unused_then_dotag(TagIn, Unused, BinBits);
{_Min,Max} ->
BBLen = (byte_size(BinBits)*8)-Unused,
@@ -885,8 +882,8 @@ remove_unused_then_dotag(TagIn,Unused,BinBits) ->
encode_bit_string_named(C, [FirstVal | RestVal], NamedBitList, TagIn) ->
ToSetPos = get_all_bitposes([FirstVal | RestVal], NamedBitList, []),
Size =
- case get_constraint(C,'SizeConstraint') of
- no ->
+ case C of
+ [] ->
lists:max(ToSetPos)+1;
{_Min,Max} ->
Max;
@@ -943,8 +940,8 @@ make_and_set_list(Len, [], XPos) ->
%% Encode bit string for lists of ones and zeroes
%%=================================================================
encode_bit_string_bits(C, BitListVal, _NamedBitList, TagIn) when is_list(BitListVal) ->
- case get_constraint(C,'SizeConstraint') of
- no ->
+ case C of
+ [] ->
{Len, Unused, OctetList} = encode_bitstring(BitListVal),
%%add unused byte to the Len
encode_tags(TagIn, [Unused | OctetList], Len+1);
@@ -957,7 +954,7 @@ encode_bit_string_bits(C, BitListVal, _NamedBitList, TagIn) when is_list(BitList
Constr={{_,_},{_,_}} ->%{{Min1,Max1},{Min2,Max2}}
%% constraint with extension mark
encode_constr_bit_str_bits(Constr,BitListVal,TagIn);
- Size ->
+ Size when is_integer(Size) ->
case length(BitListVal) of
BitSize when BitSize == Size ->
{Len, Unused, OctetList} = encode_bitstring(BitListVal),
@@ -1266,27 +1263,14 @@ decode_restricted_string(Tlv, Range, TagsIn) ->
Bin = match_and_collect(Tlv, TagsIn),
check_restricted_string(binary_to_list(Bin), byte_size(Bin), Range).
-check_restricted_string(Val, StrLen, Range) ->
- case Range of
- {Lb,Ub} when StrLen >= Lb, Ub >= StrLen -> % variable length constraint
- Val;
- {{Lb,_Ub},[]} when StrLen >= Lb ->
- Val;
- {{Lb,_Ub},_Ext=[Min|_]} when StrLen >= Lb; StrLen >= Min ->
- Val;
- {{Lb1,Ub1},{Lb2,Ub2}} when StrLen >= Lb1, StrLen =< Ub1;
- StrLen =< Ub2, StrLen >= Lb2 ->
- Val;
- StrLen -> % fixed length constraint
- Val;
- {_,_} ->
- exit({error,{asn1,{length,Range,Val}}});
- _Len when is_integer(_Len) ->
- exit({error,{asn1,{length,Range,Val}}});
- _ -> % some strange constraint that we don't support yet
- Val
- end.
-
+check_restricted_string(Val, _Len, []) ->
+ Val;
+check_restricted_string(Val, Len, {Lb,Ub}) when Lb =< Len, Len =< Ub ->
+ Val;
+check_restricted_string(Val, Len, Len) ->
+ Val;
+check_restricted_string(Val, _Len, Range) ->
+ exit({error,{asn1,{length,Range,Val}}}).
%%============================================================================
%% encode Universal string
@@ -1390,56 +1374,6 @@ mk_BMP_string([0,B|T], US) ->
mk_BMP_string([C,D|T], US) ->
mk_BMP_string(T, [{0,0,C,D}|US]).
-
-%%============================================================================
-%% Generalized time, ITU_T X.680 Chapter 39
-%%
-%% encode Generalized time
-%%============================================================================
-
-encode_generalized_time(OctetList, TagIn) ->
- encode_tags(TagIn, OctetList, length(OctetList)).
-
-%%============================================================================
-%% decode Generalized time
-%% (Buffer, Range, HasTag, TotalLen) -> {String, Remain, RemovedBytes}
-%%============================================================================
-
-decode_generalized_time(Tlv, _Range, Tags) ->
- Val = match_tags(Tlv, Tags),
- NewVal = case Val of
- [_H|_T]=PartList -> % constructed
- collect_parts(PartList);
- Bin ->
- Bin
- end,
- binary_to_list(NewVal).
-
-%%============================================================================
-%% Universal time, ITU_T X.680 Chapter 40
-%%
-%% encode UTC time
-%%============================================================================
-
-encode_utc_time(OctetList, TagIn) ->
- encode_tags(TagIn, OctetList, length(OctetList)).
-
-%%============================================================================
-%% decode UTC time
-%% (Buffer, Range, HasTag, TotalLen) -> {String, Remain, RemovedBytes}
-%%============================================================================
-
-decode_utc_time(Tlv, _Range, Tags) ->
- Val = match_tags(Tlv, Tags),
- NewVal = case Val of
- [_|_]=PartList -> % constructed
- collect_parts(PartList);
- Bin ->
- Bin
- end,
- binary_to_list(NewVal).
-
-
%%============================================================================
%% Length handling
%%
@@ -1535,14 +1469,6 @@ match_and_collect(Tlv, TagsIn) ->
Bin
end.
-get_constraint(C, Key) ->
- case lists:keyfind(Key, 1, C) of
- false ->
- no;
- {_,V} ->
- V
- end.
-
collect_parts(TlvList) ->
collect_parts(TlvList, []).
diff --git a/lib/asn1/src/asn1rtt_per.erl b/lib/asn1/src/asn1rtt_per.erl
index aa6cf4da0a..9f4b7500d8 100644
--- a/lib/asn1/src/asn1rtt_per.erl
+++ b/lib/asn1/src/asn1rtt_per.erl
@@ -19,7 +19,7 @@
-module(asn1rtt_per).
-export([setext/1, fixextensions/2,
- skipextensions/3, getbit/1, getchoice/3,
+ skipextensions/3,
set_choice/3,encode_integer/2,
encode_small_number/1,
encode_constrained_number/2,
@@ -36,7 +36,7 @@
encode_VideotexString/2,
encode_ObjectDescriptor/2,
encode_UTF8String/1,
- encode_octet_string/3,
+ encode_octet_string/2,
encode_known_multiplier_string/4,
octets_to_complete/2]).
@@ -88,23 +88,6 @@ skipextensions(Bytes0, Nr, ExtensionBitstr) when is_bitstring(ExtensionBitstr) -
Bytes0
end.
-
-getchoice(Bytes, 1, 0) -> % only 1 alternative is not encoded
- {0,Bytes};
-getchoice(Bytes, _, 1) ->
- decode_small_number(Bytes);
-getchoice(Bytes, NumChoices, 0) ->
- decode_constrained_number(Bytes, {0,NumChoices-1}).
-
-
-getbit(Buffer) ->
- <<B:1,Rest/bitstring>> = Buffer,
- {B,Rest}.
-
-getbits(Buffer, Num) when is_bitstring(Buffer) ->
- <<Bs:Num,Rest/bitstring>> = Buffer,
- {Bs,Rest}.
-
align(Bin) when is_binary(Bin) ->
Bin;
align(BitStr) when is_bitstring(BitStr) ->
@@ -112,28 +95,6 @@ align(BitStr) when is_bitstring(BitStr) ->
<<_:AlignBits,Rest/binary>> = BitStr,
Rest.
-
-%% First align buffer, then pick the first Num octets.
-%% Returns octets as an integer with bit significance as in buffer.
-getoctets(Buffer, Num) when is_binary(Buffer) ->
- <<Val:Num/integer-unit:8,RestBin/binary>> = Buffer,
- {Val,RestBin};
-getoctets(Buffer, Num) when is_bitstring(Buffer) ->
- AlignBits = bit_size(Buffer) rem 8,
- <<_:AlignBits,Val:Num/integer-unit:8,RestBin/binary>> = Buffer,
- {Val,RestBin}.
-
-
-%% First align buffer, then pick the first Num octets.
-%% Returns octets as a binary
-getoctets_as_bin(Bin,Num) when is_binary(Bin) ->
- <<Octets:Num/binary,RestBin/binary>> = Bin,
- {Octets,RestBin};
-getoctets_as_bin(Bin,Num) when is_bitstring(Bin) ->
- AlignBits = bit_size(Bin) rem 8,
- <<_:AlignBits,Val:Num/binary,RestBin/binary>> = Bin,
- {Val,RestBin}.
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% set_choice(Alt,Choices,Altnum) -> ListofBitSettings
%% Alt = atom()
@@ -185,15 +146,7 @@ set_choice_tag(_Alt,[],_Tag) ->
%% | binary
%% Contraint = not used in this version
%%
-encode_open_type(Val) when is_list(Val) ->
- Bin = list_to_binary(Val),
- case byte_size(Bin) of
- Size when Size > 255 ->
- [encode_length(Size),21,<<Size:16>>,Bin];
- Size ->
- [encode_length(Size),20,Size,Bin]
- end;
-encode_open_type(Val) when is_binary(Val) ->
+encode_open_type(Val) ->
case byte_size(Val) of
Size when Size > 255 ->
[encode_length(Size),21,<<Size:16>>,Val]; % octets implies align
@@ -220,7 +173,7 @@ encode_integer([{'ValueRange',{Lb,Ub}=VR,Range,PreEnc}],Val)
when Val >= Lb, Ub >= Val ->
%% this case when NamedNumberList
encode_constrained_number(VR, Range, PreEnc, Val);
-encode_integer([{'ValueRange',{Lb,'MAX'}}], Val) ->
+encode_integer([{'ValueRange',{Lb,'MAX'}}], Val) when Lb =< Val ->
encode_semi_constrained_number(Lb, Val);
encode_integer([{'ValueRange',{'MIN',_}}], Val) ->
encode_unconstrained_number(Val);
@@ -238,15 +191,6 @@ encode_small_number(Val) when Val < 64 ->
encode_small_number(Val) ->
[1|encode_semi_constrained_number(0, Val)].
-decode_small_number(Bytes) ->
- {Bit,Bytes2} = getbit(Bytes),
- case Bit of
- 0 ->
- getbits(Bytes2, 6);
- 1 ->
- decode_semi_constrained_number(Bytes2)
- end.
-
%% X.691:10.7 Encoding of a semi-constrained whole number
encode_semi_constrained_number(Lb, Val) ->
Val2 = Val - Lb,
@@ -261,10 +205,6 @@ encode_semi_constrained_number(Lb, Val) ->
[encode_length(Len),21,<<Len:16>>|Oct]
end.
-decode_semi_constrained_number(Bytes) ->
- {Len,Bytes2} = decode_length(Bytes),
- getoctets(Bytes2, Len).
-
encode_constrained_number({Lb,_Ub},_Range,{bits,N},Val) ->
Val2 = Val-Lb,
[10,N,Val2];
@@ -333,47 +273,6 @@ encode_constrained_number({Lb,Ub}, Val) when Val >= Lb, Ub >= Val ->
encode_constrained_number({_,_},Val) ->
exit({error,{asn1,{illegal_value,Val}}}).
-decode_constrained_number(Buffer,VR={Lb,Ub}) ->
- Range = Ub - Lb + 1,
- decode_constrained_number(Buffer,VR,Range).
-
-decode_constrained_number(Buffer,{Lb,_Ub},Range) ->
- % Val2 = Val - Lb,
- {Val,Remain} =
- if
- Range == 1 ->
- {0,Buffer};
- Range == 2 ->
- getbits(Buffer,1);
- Range =< 4 ->
- getbits(Buffer,2);
- Range =< 8 ->
- getbits(Buffer,3);
- Range =< 16 ->
- getbits(Buffer,4);
- Range =< 32 ->
- getbits(Buffer,5);
- Range =< 64 ->
- getbits(Buffer,6);
- Range =< 128 ->
- getbits(Buffer,7);
- Range =< 255 ->
- getbits(Buffer,8);
- Range =< 256 ->
- getoctets(Buffer,1);
- Range =< 65536 ->
- getoctets(Buffer,2);
- Range =< (1 bsl (255*8)) ->
- OList = binary:bin_to_list(binary:encode_unsigned(Range - 1)),
- RangeOctLen = length(OList),
- {Len, Bytes} = decode_length(Buffer, {1, RangeOctLen}),
- {Octs, RestBytes} = getoctets_as_bin(Bytes, Len),
- {binary:decode_unsigned(Octs), RestBytes};
- true ->
- exit({not_supported,{integer_range,Range}})
- end,
- {Val+Lb,Remain}.
-
%% For some reason the minimum bits needed in the length field in
%% the encoding of constrained whole numbers must always be at least 2?
minimum_bits(N) when N < 4 -> 2;
@@ -440,22 +339,17 @@ encode_length(Len) -> % unconstrained
exit({error,{asn1,{encode_length,{nyi,above_16k}}}})
end.
-encode_length(undefined, Len) -> % un-constrained
- encode_length(Len);
-encode_length({0,'MAX'},Len) ->
- encode_length(undefined,Len);
-encode_length({Lb,Ub}=Vr, Len) when Ub =< 65535 ,Lb >= 0 -> % constrained
- encode_constrained_number(Vr,Len);
-encode_length({Lb,_Ub}, Len) when is_integer(Lb), Lb >= 0 -> % Ub > 65535
- encode_length(Len);
-encode_length({{Lb,Ub}=Vr,Ext}, Len)
- when Ub =< 65535 ,Lb >= 0,Len=<Ub, is_list(Ext) ->
- %% constrained extensible
- [0|encode_constrained_number(Vr,Len)];
-encode_length({{Lb,_},Ext},Len) when is_list(Ext) ->
- [1|encode_semi_constrained_number(Lb, Len)];
-encode_length(SingleValue, _Len) when is_integer(SingleValue) ->
- [].
+encode_length({C,[]}, Len) ->
+ case C of
+ {Lb,Ub}=Vr when Lb =< Len, Len =< Ub ->
+ [0|encode_constrained_number(Vr, Len)];
+ _ ->
+ [1|encode_length(Len)]
+ end;
+encode_length(Len, Len) ->
+ [];
+encode_length(Vr, Len) ->
+ encode_constrained_number(Vr, Len).
%% X.691 10.9.3.4 (only used for length of bitmap that prefixes extension
%% additions in a sequence or set
@@ -476,11 +370,6 @@ decode_length(Buffer) -> % un-constrained
exit({error,{asn1,{decode_length,{nyi,above_16k}}}})
end.
-decode_length(Buffer, {Lb,Ub}) when Ub =< 65535, Lb >= 0 -> % constrained
- decode_constrained_number(Buffer, {Lb,Ub});
-decode_length(Buffer, {Lb,_Ub}) when is_integer(Lb), Lb >= 0 -> % Ub > 65535
- decode_length(Buffer).
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% bitstring NamedBitList
%% Val can be of:
@@ -758,40 +647,40 @@ make_and_set_list([], _) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% X.691:16
-%% encode_octet_string(Constraint,ExtensionMarker,Val)
+%% encode_octet_string(Constraint, Val)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-encode_octet_string(_C, true, _Val) ->
- exit({error,{asn1,{'not_supported',extensionmarker}}});
-encode_octet_string({_,_}=SZ, false, Val) ->
+encode_octet_string({{Sv,Sv},Ext}=SZ, Val) when is_list(Ext), Sv =< 2 ->
Len = length(Val),
try
- [encode_length(SZ, Len),2|octets_to_complete(Len, Val)]
+ case encode_length(SZ, Len) of
+ [0|_]=EncLen ->
+ [EncLen,45,Sv*8,Sv,Val];
+ [_|_]=EncLen ->
+ [EncLen|octets_to_complete(Len, Val)]
+ end
catch
exit:{error,{asn1,{encode_length,_}}} ->
encode_fragmented_octet_string(Val)
end;
-encode_octet_string(SZ, false, Val) when is_list(SZ) ->
+encode_octet_string({_,_}=SZ, Val) ->
Len = length(Val),
try
- [encode_length({hd(SZ),lists:max(SZ)},Len),2|
- octets_to_complete(Len,Val)]
+ [encode_length(SZ, Len),2|octets_to_complete(Len, Val)]
catch
exit:{error,{asn1,{encode_length,_}}} ->
encode_fragmented_octet_string(Val)
end;
-encode_octet_string(Sv, false, Val) when is_integer(Sv) ->
+encode_octet_string(Sv, Val) when is_integer(Sv) ->
encode_fragmented_octet_string(Val);
-encode_octet_string(no, false, Val) ->
+encode_octet_string(no, Val) ->
Len = length(Val),
try
[encode_length(Len),2|octets_to_complete(Len, Val)]
catch
exit:{error,{asn1,{encode_length,_}}} ->
encode_fragmented_octet_string(Val)
- end;
-encode_octet_string(C, _, _) ->
- exit({error,{not_implemented,C}}).
+ end.
encode_fragmented_octet_string(Val) ->
Bin = iolist_to_binary(Val),
@@ -825,12 +714,24 @@ encode_restricted_string(Val) when is_list(Val)->
encode_known_multiplier_string(SizeC, NumBits, CharOutTab, Val) ->
Result = chars_encode2(Val, NumBits, CharOutTab),
case SizeC of
- Ub when is_integer(Ub), Ub*NumBits =< 16 ->
+ Ub when is_integer(Ub), Ub*NumBits < 16 ->
Result;
- Ub when is_integer(Ub), Ub =<65535 -> % fixed length
+ Ub when is_integer(Ub) ->
[2,Result];
- {Ub,Lb} ->
- [encode_length({Ub,Lb},length(Val)),2,Result];
+ {{_,Ub},Ext}=SZ when is_list(Ext) ->
+ Len = length(Val),
+ case encode_length(SZ, Len) of
+ [0|_]=EncLen when Ub*NumBits < 16 ->
+ [EncLen,45,Len*NumBits,Len,Val];
+ [_|_]=EncLen ->
+ [EncLen,2|Result]
+ end;
+ {_,Ub}=Range ->
+ [encode_length(Range, length(Val))|
+ if
+ Ub*NumBits < 16 -> Result;
+ true -> [2|Result]
+ end];
no ->
[encode_length(length(Val)),2,Result]
end.
diff --git a/lib/asn1/src/asn1rtt_uper.erl b/lib/asn1/src/asn1rtt_uper.erl
index 8efe9a7b0f..a5035c6660 100644
--- a/lib/asn1/src/asn1rtt_uper.erl
+++ b/lib/asn1/src/asn1rtt_uper.erl
@@ -21,7 +21,7 @@
-export([setext/1, fixoptionals/3,
fixextensions/2,
- skipextensions/3, getbit/1, getchoice/3 ]).
+ skipextensions/3]).
-export([set_choice/3, encode_integer/2, encode_integer/3]).
-export([encode_small_number/1, encode_constrained_number/2,
encode_boolean/1,
@@ -34,17 +34,17 @@
-export([encode_open_type/1]).
- -export([encode_UniversalString/2,
- encode_PrintableString/2,
+ -export([encode_UniversalString/3,
+ encode_PrintableString/3,
encode_GeneralString/2,
encode_GraphicString/2,
encode_TeletexString/2,
encode_VideotexString/2,
- encode_VisibleString/2,
+ encode_VisibleString/3,
encode_UTF8String/1,
- encode_BMPString/2,
- encode_IA5String/2,
- encode_NumericString/2,
+ encode_BMPString/3,
+ encode_IA5String/3,
+ encode_NumericString/3,
encode_ObjectDescriptor/2
]).
@@ -123,29 +123,6 @@ skipextensions(Bytes0, Nr, ExtensionBitstr) when is_bitstring(ExtensionBitstr) -
end.
-getchoice(Bytes,1,0) -> % only 1 alternative is not encoded
- {0,Bytes};
-getchoice(Bytes,_,1) ->
- decode_small_number(Bytes);
-getchoice(Bytes,NumChoices,0) ->
- decode_constrained_number(Bytes,{0,NumChoices-1}).
-
-
-getbit(Buffer) ->
- <<B:1,Rest/bitstring>> = Buffer,
- {B,Rest}.
-
-getbits(Buffer, Num) when is_bitstring(Buffer) ->
- <<Bs:Num,Rest/bitstring>> = Buffer,
- {Bs,Rest}.
-
-
-%% Pick the first Num octets.
-%% Returns octets as an integer with bit significance as in buffer.
-getoctets(Buffer, Num) when is_bitstring(Buffer) ->
- <<Val:Num/integer-unit:8,RestBitStr/bitstring>> = Buffer,
- {Val,RestBitStr}.
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% set_choice(Alt,Choices,Altnum) -> ListofBitSettings
%% Alt = atom()
@@ -198,9 +175,7 @@ set_choice_tag(_Alt,[],_Tag) ->
%% | binary
%% Contraint = not used in this version
%%
-encode_open_type(Val) when is_list(Val) ->
- encode_open_type(list_to_binary(Val));
-encode_open_type(Val) when is_binary(Val) ->
+encode_open_type(Val) ->
[encode_length(byte_size(Val)),Val].
@@ -248,7 +223,7 @@ encode_integer1(C, Val) ->
case VR = get_constraint(C, 'ValueRange') of
no ->
encode_unconstrained_number(Val);
- {Lb,'MAX'} ->
+ {Lb,'MAX'} when Lb =< Val ->
encode_semi_constrained_number(Lb, Val);
%% positive with range
{Lb,Ub} when Val >= Lb, Ub >= Val ->
@@ -265,15 +240,6 @@ encode_small_number(Val) when Val < 64 ->
encode_small_number(Val) ->
[<<1:1>>|encode_semi_constrained_number(0, Val)].
-decode_small_number(Bytes) ->
- {Bit,Bytes2} = getbit(Bytes),
- case Bit of
- 0 ->
- getbits(Bytes2,6);
- 1 ->
- decode_semi_constrained_number(Bytes2)
- end.
-
%% X.691:10.7 Encoding of a semi-constrained whole number
encode_semi_constrained_number(Lb, Val) ->
%% encoding in minimum number of octets preceeded by a length
@@ -289,11 +255,6 @@ encode_semi_constrained_number(Lb, Val) ->
[encode_length(Size),Bin]
end.
-decode_semi_constrained_number(Bytes) ->
- {Len,Bytes2} = decode_length(Bytes),
- {V,Bytes3} = getoctets(Bytes2,Len),
- {V,Bytes3}.
-
encode_constrained_number({Lb,Ub}, Val) when Val >= Lb, Ub >= Val ->
Range = Ub - Lb + 1,
Val2 = Val - Lb,
@@ -302,13 +263,6 @@ encode_constrained_number({Lb,Ub}, Val) when Val >= Lb, Ub >= Val ->
encode_constrained_number(Range,Val) ->
exit({error,{asn1,{integer_range,Range,value,Val}}}).
-
-decode_constrained_number(Buffer, {Lb,Ub}) ->
- Range = Ub - Lb + 1,
- NumBits = num_bits(Range),
- {Val,Remain} = getbits(Buffer,NumBits),
- {Val+Lb,Remain}.
-
%% X.691:10.8 Encoding of an unconstrained whole number
encode_unconstrained_number(Val) when Val >= 0 ->
@@ -390,22 +344,18 @@ encode_length(Len) -> % un-constrained
error({error,{asn1,{encode_length,{nyi,above_16k}}}})
end.
-encode_length(undefined, Len) -> % unconstrained
- encode_length(Len);
-encode_length({0,'MAX'},Len) ->
- encode_length(undefined, Len);
-encode_length({Lb,Ub}=Vr, Len) when Ub =< 65535, Lb >= 0 -> % constrained
- encode_constrained_number(Vr,Len);
-encode_length({Lb,_Ub}, Len) when is_integer(Lb), Lb >= 0 -> % Ub > 65535
- encode_length(Len);
-encode_length({{Lb,Ub}=Vr,Ext},Len)
- when Ub =< 65535, Lb >= 0, Len =< Ub, is_list(Ext) ->
- %% constrained extensible
- [<<0:1>>,encode_constrained_number(Vr,Len)];
-encode_length({{Lb,_Ub},Ext}, Len) when is_list(Ext) ->
- [<<1:1>>,encode_semi_constrained_number(Lb, Len)];
-encode_length(SingleValue, _Len) when is_integer(SingleValue) ->
- [].
+encode_length({C,[]}, Len) ->
+ case C of
+ {Lb,Ub}=Vr when Lb =< Len, Len =< Ub ->
+ [<<0:1>>|encode_constrained_number(Vr, Len)];
+ _ ->
+ [<<1:1>>|encode_length(Len)]
+ end;
+encode_length(Len, Len) ->
+ [];
+encode_length(Vr, Len) ->
+ encode_constrained_number(Vr, Len).
+
%% X.691 10.9.3.4 (only used for length of bitmap that prefixes extension
%% additions in a sequence or set
@@ -687,10 +637,6 @@ encode_octet_string(Val) ->
encode_octet_string(C, Val) ->
case C of
- 1 ->
- list_to_binary(Val);
- 2 ->
- list_to_binary(Val);
{_,_}=VR ->
try
[encode_length(VR, length(Val)),list_to_binary(Val)]
@@ -699,20 +645,7 @@ encode_octet_string(C, Val) ->
encode_fragmented_octet_string(Val)
end;
Sv when is_integer(Sv), Sv =:= length(Val) -> % fixed length
- if
- Sv =< 65535 ->
- list_to_binary(Val);
- true ->
- encode_fragmented_octet_string(Val)
- end;
- Sv when is_list(Sv) ->
- try
- [encode_length({hd(Sv),lists:max(Sv)},
- length(Val)),list_to_binary(Val)]
- catch
- error:{error,{asn1,{encode_length,_}}} ->
- encode_fragmented_octet_string(Val)
- end
+ list_to_binary(Val)
end.
@@ -742,41 +675,34 @@ efos_1(<<B/bitstring>>) ->
encode_restricted_string(Val) when is_list(Val)->
[encode_length(length(Val)),list_to_binary(Val)].
-encode_known_multiplier_string(StringType, C, Val) ->
- Result = chars_encode(C, StringType, Val),
- NumBits = get_NumBits(C, StringType),
- case get_constraint(C, 'SizeConstraint') of
- Ub when is_integer(Ub), Ub*NumBits =< 16 ->
- Result;
- 0 ->
- [];
- Ub when is_integer(Ub),Ub =<65535 -> % fixed length
+encode_known_multiplier_string(StringType, C, Pa, Val) ->
+ Result = chars_encode(Pa, StringType, Val),
+ case C of
+ Ub when is_integer(Ub) ->
Result;
- {Ub,Lb} ->
- [encode_length({Ub,Lb}, length(Val)),Result];
- Vl when is_list(Vl) ->
- [encode_length({lists:min(Vl),lists:max(Vl)}, length(Val)),Result];
+ {_,_}=Range ->
+ [encode_length(Range, length(Val)),Result];
no ->
[encode_length(length(Val)),Result]
end.
-encode_NumericString(C,Val) ->
- encode_known_multiplier_string('NumericString',C,Val).
+encode_NumericString(C, Pa, Val) ->
+ encode_known_multiplier_string('NumericString', C, Pa, Val).
-encode_PrintableString(C,Val) ->
- encode_known_multiplier_string('PrintableString',C,Val).
+encode_PrintableString(C, Pa, Val) ->
+ encode_known_multiplier_string('PrintableString', C, Pa, Val).
-encode_VisibleString(C,Val) -> % equivalent with ISO646String
- encode_known_multiplier_string('VisibleString',C,Val).
+encode_VisibleString(C, Pa, Val) -> % equivalent with ISO646String
+ encode_known_multiplier_string('VisibleString', C, Pa, Val).
-encode_IA5String(C,Val) ->
- encode_known_multiplier_string('IA5String',C,Val).
+encode_IA5String(C, Pa, Val) ->
+ encode_known_multiplier_string('IA5String', C, Pa, Val).
-encode_BMPString(C,Val) ->
- encode_known_multiplier_string('BMPString',C,Val).
+encode_BMPString(C, Pa, Val) ->
+ encode_known_multiplier_string('BMPString', C, Pa, Val).
-encode_UniversalString(C,Val) ->
- encode_known_multiplier_string('UniversalString',C,Val).
+encode_UniversalString(C, Pa, Val) ->
+ encode_known_multiplier_string('UniversalString', C, Pa, Val).
%% end of known-multiplier strings for which PER visible constraints are
@@ -805,14 +731,15 @@ encode_VideotexString(_C,Val) ->
%% into account.
%% This function does only encode the value part and NOT the length
-chars_encode(C,StringType,Value) ->
- case {StringType,get_constraint(C,'PermittedAlphabet')} of
+chars_encode(Pa, StringType, Value) ->
+ case {StringType,Pa} of
{'UniversalString',{_,_Sv}} ->
exit({error,{asn1,{'not implemented',"UniversalString with PermittedAlphabet constraint"}}});
{'BMPString',{_,_Sv}} ->
exit({error,{asn1,{'not implemented',"BMPString with PermittedAlphabet constraint"}}});
_ ->
- {NumBits,CharOutTab} = {get_NumBits(C,StringType),get_CharOutTab(C,StringType)},
+ {NumBits,CharOutTab} = {get_NumBits(Pa, StringType),
+ get_CharOutTab(Pa, StringType)},
chars_encode2(Value,NumBits,CharOutTab)
end.
@@ -839,8 +766,8 @@ exit_if_false(V,false)->
exit_if_false(_,V) ->V.
-get_NumBits(C,StringType) ->
- case get_constraint(C,'PermittedAlphabet') of
+get_NumBits(Pa, StringType) ->
+ case Pa of
{'SingleValue',Sv} ->
charbits(length(Sv));
no ->
@@ -860,22 +787,23 @@ get_NumBits(C,StringType) ->
end
end.
-get_CharOutTab(C,StringType) ->
- case get_constraint(C,'PermittedAlphabet') of
+get_CharOutTab(Pa, StringType) ->
+ case Pa of
{'SingleValue',Sv} ->
- get_CharTab2(C,StringType,hd(Sv),lists:max(Sv),Sv);
+ get_CharTab2(Pa, StringType, hd(Sv), lists:max(Sv), Sv);
no ->
case StringType of
'IA5String' ->
{0,16#7F,notab};
'VisibleString' ->
- get_CharTab2(C,StringType,16#20,16#7F,notab);
+ get_CharTab2(Pa, StringType, 16#20, 16#7F, notab);
'PrintableString' ->
Chars = lists:sort(
" '()+,-./0123456789:=?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"),
- get_CharTab2(C,StringType,hd(Chars),lists:max(Chars),Chars);
+ get_CharTab2(Pa, StringType, hd(Chars),
+ lists:max(Chars), Chars);
'NumericString' ->
- get_CharTab2(C,StringType,16#20,$9," 0123456789");
+ get_CharTab2(Pa, StringType, 16#20, $9, " 0123456789");
'UniversalString' ->
{0,16#FFFFFFFF,notab};
'BMPString' ->
diff --git a/lib/asn1/test/Makefile b/lib/asn1/test/Makefile
index 6e6ab4639c..15b97df972 100644
--- a/lib/asn1/test/Makefile
+++ b/lib/asn1/test/Makefile
@@ -114,7 +114,8 @@ MODULES= \
asn1_app_test \
asn1_appup_test \
asn1_wrapper \
- asn1_SUITE
+ asn1_SUITE \
+ error_SUITE
SUITE= asn1_SUITE.erl
diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl
index 8deabece37..6be493320c 100644
--- a/lib/asn1/test/asn1_SUITE.erl
+++ b/lib/asn1/test/asn1_SUITE.erl
@@ -139,7 +139,6 @@ groups() ->
testSetOfCho,
testEnumExt,
value_test,
- value_bad_enum_test,
testSeq2738,
% Uses 'Constructed'
{group, [], [constructed,
@@ -177,6 +176,7 @@ groups() ->
testX420]},
testTcapsystem,
testNBAPsystem,
+ testS1AP,
test_compile_options,
testDoubleEllipses,
test_x691,
@@ -655,7 +655,6 @@ constraint_equivalence(Config) ->
AbsFile = filename:join(CaseDir, Asn1Spec++".abs"),
{ok,Terms} = file:consult(AbsFile),
Cs = [begin
- 'INTEGER' = element(3, Type), %Assertion.
Constraints = element(4, Type),
Name1 = atom_to_list(Name0),
{Name,_} = lists:splitwith(fun(C) -> C =/= $X end, Name1),
@@ -741,11 +740,6 @@ value_test(Config, Rule, Opts) ->
{ok, _} = asn1ct:test('ObjIdValues', 'ObjIdType',
'ObjIdValues':'mobileDomainId'()).
-value_bad_enum_test(Config) ->
- {error, _} = asn1ct:compile(?config(data_dir, Config) ++
- "BadEnumValue1",
- [{outdir, ?config(case_dir, Config)}]).
-
constructed(Config) ->
test(Config, fun constructed/3, [ber]).
constructed(Config, Rule, Opts) ->
@@ -860,7 +854,7 @@ testInvokeMod(Config, Rule, Opts) ->
{ok, _Result2} = 'PrimStrings':encode('Bs1', [1, 0, 1, 0]).
testExport(Config) ->
- {error, {asn1, _Reason}} =
+ {error, _} =
asn1ct:compile(filename:join(?config(data_dir, Config),
"IllegalExport"),
[{outdir, ?config(case_dir, Config)}]).
@@ -906,8 +900,8 @@ testOpenTypeImplicitTag(Config, Rule, Opts) ->
duplicate_tags(Config) ->
DataDir = ?config(data_dir, Config),
CaseDir = ?config(case_dir, Config),
- {error, {asn1, [{error, {type, _, _, 'SeqOpt1Imp',
- {asn1, {duplicates_of_the_tags, _}}}}]}} =
+ {error, [{error, {type, _, _, 'SeqOpt1Imp',
+ {asn1, {duplicates_of_the_tags, _}}}}]} =
asn1ct:compile(filename:join(DataDir, "SeqOptional2"),
[abs, {outdir, CaseDir}]).
@@ -1024,6 +1018,16 @@ testNBAPsystem(Config, Rule, Opts) ->
testNBAPsystem:compile(Config, [Rule|Opts]),
testNBAPsystem:test(Rule, Config).
+testS1AP(Config) -> test(Config, fun testS1AP/3).
+testS1AP(Config, Rule, Opts) ->
+ S1AP = ["S1AP-CommonDataTypes",
+ "S1AP-Constants",
+ "S1AP-Containers",
+ "S1AP-IEs",
+ "S1AP-PDU-Contents",
+ "S1AP-PDU-Descriptions"],
+ asn1_test_lib:compile_all(S1AP, Config, [Rule|Opts]).
+
test_compile_options(Config) ->
ok = test_compile_options:wrong_path(Config),
ok = test_compile_options:path(Config),
@@ -1077,17 +1081,14 @@ ticket_6143(Config) ->
ok = test_compile_options:ticket_6143(Config).
testExtensionAdditionGroup(Config) ->
- %% FIXME problems with automatic tags [ber_bin], [ber_bin, optimize]
- test(Config, fun testExtensionAdditionGroup/3, [per, uper]).
+ test(Config, fun testExtensionAdditionGroup/3).
testExtensionAdditionGroup(Config, Rule, Opts) ->
asn1_test_lib:compile("Extension-Addition-Group", Config, [Rule|Opts]),
asn1_test_lib:compile_erlang("extensionAdditionGroup", Config,
[debug_info]),
- extensionAdditionGroup:run([Rule|Opts]),
- extensionAdditionGroup:run2([Rule|Opts]),
- extensionAdditionGroup:run3(),
- asn1_test_lib:compile("EUTRA-RRC-Definitions", Config, [Rule, {record_name_prefix, "RRC-"}|Opts]),
- extensionAdditionGroup:run3([Rule|Opts]).
+ asn1_test_lib:compile("EUTRA-RRC-Definitions", Config,
+ [Rule,{record_name_prefix,"RRC-"}|Opts]),
+ extensionAdditionGroup:run(Rule).
% parse_modules() ->
% ["ImportsFrom"].
@@ -1097,11 +1098,8 @@ per_modules() ->
ber_modules() ->
[X || X <- test_modules(),
- X =/= "CommonDataTypes",
- X =/= "DS-EquipmentUser-CommonFunctionOrig-TransmissionPath",
X =/= "H323-MESSAGES",
- X =/= "H235-SECURITY-MESSAGES",
- X =/= "MULTIMEDIA-SYSTEM-CONTROL"].
+ X =/= "H235-SECURITY-MESSAGES"].
test_modules() ->
["BitStr",
diff --git a/lib/asn1/test/asn1_SUITE_data/BadEnumValue1.asn b/lib/asn1/test/asn1_SUITE_data/BadEnumValue1.asn
deleted file mode 100644
index dbc224a74b..0000000000
--- a/lib/asn1/test/asn1_SUITE_data/BadEnumValue1.asn
+++ /dev/null
@@ -1,8 +0,0 @@
-BadEnumValue1 DEFINITIONS AUTOMATIC TAGS ::=
-
-BEGIN
-
-E3 ::= ENUMERATED {monday,thuesday(0)}
-enumWrongVal E3 ::= sunday
-
-END
diff --git a/lib/asn1/test/asn1_SUITE_data/Certificate.asn b/lib/asn1/test/asn1_SUITE_data/Certificate.asn
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/asn1/test/asn1_SUITE_data/Certificate.asn
+++ /dev/null
diff --git a/lib/asn1/test/asn1_SUITE_data/ChoExtension.asn1 b/lib/asn1/test/asn1_SUITE_data/ChoExtension.asn1
index 18473bae30..f6fe18be10 100644
--- a/lib/asn1/test/asn1_SUITE_data/ChoExtension.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/ChoExtension.asn1
@@ -41,4 +41,10 @@ ChoExt4 ::= CHOICE
str OCTET STRING
}
+ChoEmptyRoot ::= CHOICE {
+ ...,
+ bool BOOLEAN,
+ int INTEGER (0..7)
+}
+
END
diff --git a/lib/asn1/test/asn1_SUITE_data/ConstraintEquivalence.asn1 b/lib/asn1/test/asn1_SUITE_data/ConstraintEquivalence.asn1
index 6a97c1b38e..8b3d151502 100644
--- a/lib/asn1/test/asn1_SUITE_data/ConstraintEquivalence.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/ConstraintEquivalence.asn1
@@ -8,6 +8,9 @@ BEGIN
SingleValueX5 ::= INTEGER ((42) INTERSECTION (MIN..MAX))
SingleValueX6 ::= INTEGER ((42) INTERSECTION (40..49))
SingleValueX7 ::= INTEGER (42..42)
+ SingleValueX8 ::= INTEGER (integer42)
+ SingleValueX9 ::= INTEGER (integer42..integer42)
+ SingleValueX10 ::= INTEGER ((integer42) INTERSECTION (40..49))
UnconstrainedX0 ::= INTEGER
UnconstrainedX1 ::= INTEGER (MIN..MAX)
@@ -24,6 +27,7 @@ BEGIN
RangeX04 ::= INTEGER (5|6|7|8|9|10)
RangeX05 ::= INTEGER (10|9|8|7|6|5)
RangeX06 ::= INTEGER (5|6|7..10)
+ RangeX07 ::= INTEGER (integer4<..<integer11)
RangeX10 ::= INTEGER ((5..6) UNION (7..8) UNION (9|10))
RangeX11 ::= INTEGER ((5|6) UNION (7..8) UNION (9|10))
@@ -39,4 +43,20 @@ BEGIN
RangeX23 ::= INTEGER ((0..10) INTERSECTION (5..20) ^ (MIN..MAX))
RangeX24 ::= INTEGER ((5|6|7|8|9|10) INTERSECTION (5..20) ^ (MIN..MAX))
+ UnconstrainedStringX00 ::= IA5String
+ UnconstrainedStringX01 ::= IA5String (SIZE (0..MAX))
+
+ ConstrainedStringX00 ::= IA5String (SIZE (0..5))
+ ConstrainedStringX01 ::= IA5String (SIZE (0|1|2|3|4|5))
+
+ -- Note: None of the back-ends care about the exact values
+ -- outside of the root range.
+ ExtConstrainedStringX00 ::= IA5String (SIZE (1..2, ...))
+ ExtConstrainedStringX01 ::= IA5String (SIZE (1|2, ..., 3))
+ ExtConstrainedStringX02 ::= IA5String (SIZE (1|2, ..., 3|4|5))
+
+ integer4 INTEGER ::= 4
+ integer11 INTEGER ::= 11
+ integer42 INTEGER ::= 42
+
END
diff --git a/lib/asn1/test/asn1_SUITE_data/Constraints.py b/lib/asn1/test/asn1_SUITE_data/Constraints.py
index 87243121f7..e4bc987e4c 100644
--- a/lib/asn1/test/asn1_SUITE_data/Constraints.py
+++ b/lib/asn1/test/asn1_SUITE_data/Constraints.py
@@ -12,6 +12,12 @@ ContainedSubtype ::= INTEGER (INCLUDES Range10to20)
-- Some ranges for additional constrained number testing.
LongLong ::= INTEGER (0..18446744073709551615)
Range256to65536 ::= INTEGER (256..65536)
+SemiConstrained ::= INTEGER (100..MAX)
+NegSemiConstrained ::= INTEGER (-128..MAX)
+SemiConstrainedExt ::= INTEGER (42..MAX, ...)
+NegSemiConstrainedExt ::= INTEGER (-128..MAX, ...)
+
+-- Other constraints
FixedSize ::= OCTET STRING (SIZE(10))
FixedSize2 ::= OCTET STRING (SIZE(10|20))
VariableSize ::= OCTET STRING (SIZE(1..10))
@@ -86,5 +92,6 @@ Document ::= OCTET STRING (ENCODED BY pdf)
pdf OBJECT IDENTIFIER ::= {1,2,3,4,5}
+ShorterExt ::= IA5String (SIZE (5, ...))
END
diff --git a/lib/asn1/test/asn1_SUITE_data/EUTRA-InterNodeDefinitions.asn b/lib/asn1/test/asn1_SUITE_data/EUTRA-InterNodeDefinitions.asn
deleted file mode 100644
index 5e6313dc02..0000000000
--- a/lib/asn1/test/asn1_SUITE_data/EUTRA-InterNodeDefinitions.asn
+++ /dev/null
@@ -1,123 +0,0 @@
--- 3GPP TS 36.331 V8.8.0 (2009-12)
--- $Id$
---
-EUTRA-InterNodeDefinitions DEFINITIONS AUTOMATIC TAGS ::=
-
-BEGIN
-
-
-HandoverCommand ::= SEQUENCE {
- criticalExtensions CHOICE {
- c1 CHOICE{
- handoverCommand-r8 HandoverCommand-r8-IEs,
- spare7 NULL,
- spare6 NULL, spare5 NULL, spare4 NULL,
- spare3 NULL, spare2 NULL, spare1 NULL
- },
- criticalExtensionsFuture SEQUENCE {}
- }
-}
-
-HandoverCommand-r8-IEs ::= SEQUENCE {
- handoverCommandMessage OCTET STRING (CONTAINING DL-DCCH-Message),
- nonCriticalExtension SEQUENCE {} OPTIONAL
-}
-
-
-HandoverPreparationInformation ::= SEQUENCE {
- criticalExtensions CHOICE {
- c1 CHOICE{
- handoverPreparationInformation-r8 HandoverPreparationInformation-r8-IEs,
- spare7 NULL,
- spare6 NULL, spare5 NULL, spare4 NULL,
- spare3 NULL, spare2 NULL, spare1 NULL
- },
- criticalExtensionsFuture SEQUENCE {}
- }
-}
-
-HandoverPreparationInformation-r8-IEs ::= SEQUENCE {
- ue-RadioAccessCapabilityInfo UE-CapabilityRAT-ContainerList,
- as-Config AS-Config OPTIONAL, -- Cond HO
- rrm-Config RRM-Config OPTIONAL,
- as-Context AS-Context OPTIONAL, -- Cond HO
- nonCriticalExtension SEQUENCE {} OPTIONAL
-}
-
-
-UERadioAccessCapabilityInformation ::= SEQUENCE {
- criticalExtensions CHOICE {
- c1 CHOICE{
- ueRadioAccessCapabilityInformation-r8
- UERadioAccessCapabilityInformation-r8-IEs,
- spare7 NULL,
- spare6 NULL, spare5 NULL, spare4 NULL,
- spare3 NULL, spare2 NULL, spare1 NULL
- },
- criticalExtensionsFuture SEQUENCE {}
- }
-}
-
-UERadioAccessCapabilityInformation-r8-IEs ::= SEQUENCE {
- ue-RadioAccessCapabilityInfo OCTET STRING (CONTAINING UECapabilityInformation),
- nonCriticalExtension SEQUENCE {} OPTIONAL
-}
-
-
-AS-Config ::= SEQUENCE {
- sourceMeasConfig MeasConfig,
- sourceRadioResourceConfig RadioResourceConfigDedicated,
- sourceSecurityAlgorithmConfig SecurityAlgorithmConfig,
- sourceUE-Identity C-RNTI,
- sourceMasterInformationBlock MasterInformationBlock,
- sourceSystemInformationBlockType1 SystemInformationBlockType1,
- sourceSystemInformationBlockType2 SystemInformationBlockType2,
- antennaInfoCommon AntennaInfoCommon,
- sourceDl-CarrierFreq ARFCN-ValueEUTRA,
- ...
-}
-
-
-AS-Context ::= SEQUENCE {
- reestablishmentInfo ReestablishmentInfo OPTIONAL -- Cond HO
-}
-
-
-ReestablishmentInfo ::= SEQUENCE {
- sourcePhysCellId PhysCellId,
- targetCellShortMAC-I ShortMAC-I,
- additionalReestabInfoList AdditionalReestabInfoList OPTIONAL,
- ...
-}
-
-AdditionalReestabInfoList ::= SEQUENCE ( SIZE (1..maxReestabInfo) ) OF AdditionalReestabInfo
-
-AdditionalReestabInfo ::= SEQUENCE{
- cellIdentity CellIdentity,
- key-eNodeB-Star Key-eNodeB-Star,
- shortMAC-I ShortMAC-I
-}
-
-Key-eNodeB-Star ::= BIT STRING (SIZE (256))
-
-
-RRM-Config ::= SEQUENCE {
- ue-InactiveTime ENUMERATED {
- s1, s2, s3, s5, s7, s10, s15, s20,
- s25, s30, s40, s50, min1, min1s20c, min1s40,
- min2, min2s30, min3, min3s30, min4, min5, min6,
- min7, min8, min9, min10, min12, min14, min17, min20,
- min24, min28, min33, min38, min44, min50, hr1,
- hr1min30, hr2, hr2min30, hr3, hr3min30, hr4, hr5, hr6,
- hr8, hr10, hr13, hr16, hr20, day1, day1hr12, day2,
- day2hr12, day3, day4, day5, day7, day10, day14, day19,
- day24, day30, dayMoreThan30} OPTIONAL,
- ...
-}
-
-
-maxReestabInfo INTEGER ::= 32 -- Maximum number of KeNB* and shortMAC-I forwarded
- -- at handover for re-establishment preparation
-
-
-END
diff --git a/lib/asn1/test/asn1_SUITE_data/EUTRA-UE-Variables.asn b/lib/asn1/test/asn1_SUITE_data/EUTRA-UE-Variables.asn
deleted file mode 100644
index 414140a6fb..0000000000
--- a/lib/asn1/test/asn1_SUITE_data/EUTRA-UE-Variables.asn
+++ /dev/null
@@ -1,49 +0,0 @@
--- 3GPP TS 36.331 V8.8.0 (2009-12)
--- $Id$
---
-EUTRA-UE-Variables DEFINITIONS AUTOMATIC TAGS ::=
-
-BEGIN
-
-
-VarMeasConfig ::= SEQUENCE {
- -- Measurement identities
- measIdList MeasIdToAddModList OPTIONAL,
- -- Measurement objects
- measObjectList MeasObjectToAddModList OPTIONAL,
- -- Reporting configurations
- reportConfigList ReportConfigToAddModList OPTIONAL,
- -- Other parameters
- quantityConfig QuantityConfig OPTIONAL,
- s-Measure RSRP-Range OPTIONAL,
- speedStatePars CHOICE {
- release NULL,
- setup SEQUENCE {
- mobilityStateParameters MobilityStateParameters,
- timeToTrigger-SF SpeedStateScaleFactors
- }
- } OPTIONAL
-}
-
-
-VarMeasReportList ::= SEQUENCE (SIZE (1..maxMeasId)) OF VarMeasReport
-
-VarMeasReport ::= SEQUENCE {
- -- List of measurement that have been triggered
- measId MeasId,
- cellsTriggeredList CellsTriggeredList OPTIONAL,
- numberOfReportsSent INTEGER
-}
-
-CellsTriggeredList ::= SEQUENCE (SIZE (1..maxCellMeas)) OF PhysCellId
-
-
-VarShortMAC-Input ::= SEQUENCE {
- cellIdentity CellIdentity,
- physCellId PhysCellId,
- c-RNTI C-RNTI
-}
-
-
-
-END \ No newline at end of file
diff --git a/lib/asn1/test/asn1_SUITE_data/EnumExt.asn1 b/lib/asn1/test/asn1_SUITE_data/EnumExt.asn1
index 9ad1f6299e..3a727e46bb 100644
--- a/lib/asn1/test/asn1_SUITE_data/EnumExt.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/EnumExt.asn1
@@ -1,28 +1,35 @@
-EnumExt DEFINITIONS AUTOMATIC TAGS ::=
-BEGIN
-
-Ext ::= ENUMERATED {
- blue(0),
- red(1),
- green(2),
- ...
-}
-
-Ext1 ::= ENUMERATED {
- blue(0),
- red(1),
- green(2),
- ...,
- orange(7)
-}
-
-Noext ::= ENUMERATED {
- blue(0),
- red(1),
- green(2)
-}
-
-Globalstate ::= ENUMERATED {def(1),com(2),preop(3),oper(4),noop(5),fail(6)}
-
-END
-
+EnumExt DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+Ext ::= ENUMERATED {
+ blue(0),
+ red(1),
+ green(2),
+ ...
+}
+
+Ext1 ::= ENUMERATED {
+ blue(0),
+ red(1),
+ green(2),
+ ...,
+ orange(7),
+ black(8),
+ magenta(9)
+}
+
+Noext ::= ENUMERATED {
+ blue(0),
+ red(1),
+ green(2)
+}
+
+Globalstate ::= ENUMERATED {def(1),com(2),preop(3),oper(4),noop(5),fail(6)}
+
+Seq ::= SEQUENCE {
+ e Ext1,
+ i INTEGER
+}
+
+END
+
diff --git a/lib/asn1/test/asn1_SUITE_data/InfObj.asn b/lib/asn1/test/asn1_SUITE_data/InfObj.asn
index 0a437e12df..53e5043cb7 100644
--- a/lib/asn1/test/asn1_SUITE_data/InfObj.asn
+++ b/lib/asn1/test/asn1_SUITE_data/InfObj.asn
@@ -39,21 +39,6 @@ RANAP-PDU ::= CHOICE {
CLASS2 ::= RANAP-ELEMENTARY-PROCEDURE
-MY-CLASS ::= CLASS {
- &integerValue INTEGER UNIQUE,
- &booleanValue BOOLEAN,
- &stringValue PrintableString
- }
-
-myobject MY-CLASS ::= {
- &integerValue 12,
- &booleanValue TRUE,
- &stringValue "hejsan"
- }
-MyObjectSet MY-CLASS ::= {
- myobject
- }
-
InitiatingMessage ::= SEQUENCE {
procedureCode RANAP-ELEMENTARY-PROCEDURE.&procedureCode ({RANAP-ELEMENTARY-PROCEDURES}),
criticality RANAP-ELEMENTARY-PROCEDURE.&criticality ({RANAP-ELEMENTARY-PROCEDURES}{@procedureCode}),
@@ -148,6 +133,83 @@ id-Iu-Release3 INTEGER ::= 3
id-Iu-Release4 INTEGER ::= 4
id-Iu-Release5 INTEGER ::= 5
+--
+-- MY-CLASS
+--
+
+Seq ::= SEQUENCE {
+ int INTEGER,
+ str OCTET STRING
+}
+
+MY-CLASS ::= CLASS {
+ &Count DEFAULT INTEGER,
+ &integerValue INTEGER UNIQUE,
+ &booleanValue BOOLEAN,
+ &stringValue PrintableString
+}
+
+myobject MY-CLASS ::= {
+ &integerValue 12,
+ &booleanValue TRUE,
+ &stringValue "hejsan"
+}
+
+myotherobject MY-CLASS ::= {
+ &Count Seq,
+ &integerValue 42,
+ &booleanValue FALSE,
+ &stringValue "hoppsan"
+}
+
+MyObjectSet MY-CLASS ::= {
+ myobject | myotherobject |
+ {
+ -- Each character will be encoded in 3 bits in UPER, 4 bits in PER.
+ &Count NumericString (FROM("01234567") ^ SIZE(8)),
+ &integerValue 43,
+ &booleanValue TRUE,
+ &stringValue "tjosan"
+ }
+}
+
+MyPdu ::= SEQUENCE {
+ count MY-CLASS.&Count ({MyObjectSet}{@int}),
+ int MY-CLASS.&integerValue ({MyObjectSet}),
+ bool MY-CLASS.&booleanValue ({MyObjectSet}{@int}),
+ str MY-CLASS.&stringValue ({MyObjectSet}{@int})
+}
+
+Seq2 ::= SEQUENCE {
+ int MY-CLASS.&integerValue ({MyObjectSet}),
+ seqof SEQUENCE (1..10) OF MY-CLASS.&booleanValue ({MyObjectSet}{@int}),
+ setof SET (1..10) OF MY-CLASS.&booleanValue ({MyObjectSet}{@int})
+}
+
+--
+-- Class with constructed default
+--
+
+CONSTRUCTED-DEFAULT ::= CLASS {
+ &id INTEGER UNIQUE,
+ &Type DEFAULT SEQUENCE { a INTEGER, b BOOLEAN },
+ &ok BOOLEAN DEFAULT TRUE
+}
+
+constructed1 CONSTRUCTED-DEFAULT ::= { &id 1 }
+constructed2 CONSTRUCTED-DEFAULT ::= { &id 2, &ok false }
+
+ConstructedDefaultSet CONSTRUCTED-DEFAULT ::= {
+ constructed1 |
+ constructed2 |
+ { &id 3, &Type BOOLEAN }
+}
+
+ConstructedPdu ::= SEQUENCE {
+ id CONSTRUCTED-DEFAULT.&id ({ConstructedDefaultSet}),
+ content CONSTRUCTED-DEFAULT.&Type ({ConstructedDefaultSet}{@id})
+}
+
END
diff --git a/lib/asn1/test/asn1_SUITE_data/InfObj2.asn b/lib/asn1/test/asn1_SUITE_data/InfObj2.asn
deleted file mode 100644
index faba7371a4..0000000000
--- a/lib/asn1/test/asn1_SUITE_data/InfObj2.asn
+++ /dev/null
@@ -1,156 +0,0 @@
-InfObj2 DEFINITIONS ::=
-BEGIN
-
-
-RANAP-ELEMENTARY-PROCEDURE ::= CLASS {
- &InitiatingMessage ,
- &SuccessfulOutcome OPTIONAL,
- &Outcome DEFAULT NULL,
- &vartypvalue &Outcome,
- &FixTypeValSet PrintableString,
- &VarTypeValSet &InitiatingMessage,
- &infoObject RANAP-ELEMENTARY-PROCEDURE,
- &InfObjectSet CLASS2,
- &UnsuccessfulOutcome OPTIONAL,
- &procedureCode ProcedureCode UNIQUE,
- &criticality Criticality DEFAULT ignore
-}
-WITH SYNTAX {
- INITIATING MESSAGE &InitiatingMessage
- [SUCCESSFUL OUTCOME &SuccessfulOutcome]
- [UNSUCCESSFUL OUTCOME &UnsuccessfulOutcome]
- [OUTCOME &Outcome]
- PROCEDURE CODE &procedureCode
- [CRITICALITY &criticality]
-}
-
-RANAP-PDU ::= CHOICE {
- initiatingMessage [0] InitiatingMessage,
- substrings [1] SEQUENCE {
- type RANAP-ELEMENTARY-PROCEDURE.&procedureCode({RANAP-ELEMENTARY-PROCEDURES}),
- strings SEQUENCE OF CHOICE {
- initial [0] RANAP-ELEMENTARY-PROCEDURE.&Outcome({
- RANAP-ELEMENTARY-PROCEDURES}{@substrings.type}),
- final [1] RANAP-ELEMENTARY-PROCEDURE.&Outcome({RANAP-ELEMENTARY-PROCEDURES}{@substrings.type})
- }
- },
--- successfulOutcome SuccessfulOutcome,
--- unsuccessfulOutcome UnsuccessfulOutcome,
--- outcome Outcome,
- ...
- }
-
-CLASS2 ::= RANAP-ELEMENTARY-PROCEDURE
-
-MY-CLASS ::= CLASS {
- &integerValue INTEGER UNIQUE,
- &booleanValue BOOLEAN,
- &stringValue PrintableString
- }
-
-myobject MY-CLASS ::= {
- &integerValue 12,
- &booleanValue TRUE,
- &stringValue "hejsan"
- }
-MyObjectSet MY-CLASS ::= {
- myobject
- }
-
-InitiatingMessage ::= SEQUENCE {
- procedureCode RANAP-ELEMENTARY-PROCEDURE.&procedureCode ({RANAP-ELEMENTARY-PROCEDURES}),
- criticality RANAP-ELEMENTARY-PROCEDURE.&criticality ({RANAP-ELEMENTARY-PROCEDURES}{@procedureCode}),
- value RANAP-ELEMENTARY-PROCEDURE.&InitiatingMessage ({RANAP-ELEMENTARY-PROCEDURES}{@procedureCode})
- }
-
-iu-Release RANAP-ELEMENTARY-PROCEDURE ::= {
- INITIATING MESSAGE Iu-ReleaseCommand
- SUCCESSFUL OUTCOME Iu-ReleaseComplete
- PROCEDURE CODE id-Iu-Release1
- CRITICALITY ignore
- }
-
-relocationPreparation RANAP-ELEMENTARY-PROCEDURE ::= {
- INITIATING MESSAGE INTEGER --Iu-ReleaseCommand
- SUCCESSFUL OUTCOME Iu-ReleaseComplete
- PROCEDURE CODE id-Iu-Release2
- CRITICALITY notify
- }
-
-object3 RANAP-ELEMENTARY-PROCEDURE ::= {
- &InitiatingMessage Iu-ReleaseCommand,
- &SuccessfulOutcome Iu-ReleaseComplete,
- &procedureCode id-Iu-Release3,
- &criticality reject
- }
-
-object4 RANAP-ELEMENTARY-PROCEDURE ::= {
- &InitiatingMessage INTEGER,
- &SuccessfulOutcome PrintableString,
- &procedureCode id-Iu-Release4,
- &criticality reject
- }
-
-object5 RANAP-ELEMENTARY-PROCEDURE ::= {
- &InitiatingMessage INTEGER,
- &SuccessfulOutcome PrintableString,
- &Outcome ProcedureCode,
- &vartypvalue 12,
- &infoObject object4,
- &InfObjectSet MyObjectSet,
- &procedureCode id-Iu-Release5,
- &criticality reject
- }
-
-
-RANAP-ELEMENTARY-PROCEDURES RANAP-ELEMENTARY-PROCEDURE ::= {
- iu-Release |
- relocationPreparation ,
- ...
- }
-
-RANAP-ELEMENTARY-PROCEDURES2 RANAP-ELEMENTARY-PROCEDURE ::= {
- iu-Release |
- relocationPreparation
- }
-
-
-OBJECTSET1 RANAP-ELEMENTARY-PROCEDURE ::= {
- {INITIATING MESSAGE Iu-ReleaseCommand SUCCESSFUL OUTCOME Iu-ReleaseComplete PROCEDURE CODE id-Iu-Release1 CRITICALITY ignore} | {INITIATING MESSAGE Iu-ReleaseCommand PROCEDURE CODE id-Iu-Release2}
- }
-
-OBJECTSET2 RANAP-ELEMENTARY-PROCEDURE ::= {
- iu-Release |
- {INITIATING MESSAGE Iu-ReleaseCommand SUCCESSFUL OUTCOME Iu-ReleaseComplete PROCEDURE CODE id-Iu-Release4 CRITICALITY ignore} |
- relocationPreparation |
- {INITIATING MESSAGE Iu-ReleaseCommand PROCEDURE CODE id-Iu-Release5} ,
- ...
- }
-
-OBJECTSET3 RANAP-ELEMENTARY-PROCEDURE ::= {
- iu-Release,
- ...
- }
-
-OBJECTSET4 RANAP-ELEMENTARY-PROCEDURE ::= {
- iu-Release
- }
-
-Iu-ReleaseCommand ::= SEQUENCE {
- first INTEGER,
- second BOOLEAN
- }
-
-Iu-ReleaseComplete ::= INTEGER (1..510)
-
-ProcedureCode ::= INTEGER (0..255)
-Criticality ::= ENUMERATED { reject, ignore, notify }
-id-Iu-Release1 INTEGER ::= 1
-id-Iu-Release2 INTEGER ::= 2
-id-Iu-Release3 INTEGER ::= 3
-id-Iu-Release4 INTEGER ::= 4
-id-Iu-Release5 INTEGER ::= 5
-
-END
-
-
diff --git a/lib/asn1/test/asn1_SUITE_data/MAP-insertSubscriberData-def.py b/lib/asn1/test/asn1_SUITE_data/MAP-insertSubscriberData-def.py
deleted file mode 100644
index 298319b0ed..0000000000
--- a/lib/asn1/test/asn1_SUITE_data/MAP-insertSubscriberData-def.py
+++ /dev/null
@@ -1,102 +0,0 @@
-MAP-insertSubscriberData-def
- { ccitt (0) identified-organization( 4) etsi( 0) mobileDomain(0)
- gsm-Network( 1) modules( 3) map-Protocol( 4) version2(2) }
-DEFINITIONS ::=
-
-BEGIN
-
-EXPORTS
-InsertSubsDataArg, InsertSubsDatRes;
-IMPORTS
-IMSI, ISDN-AddressString, LMSI FROM MAP-commonDataTypes;
-
-InsertSubsDataArg ::= SEQUENCE{
- imsi [0] IMPLICIT IMSI OPTIONAL,
- msisdn [1] IMPLICIT ISDN-AddressString OPTIONAL,
- category [2] IMPLICIT OCTET STRING (SIZE(1)) OPTIONAL,
- subscriberStatus [3] IMPLICIT SubscriberStatus OPTIONAL,
- bearerServiceList [4] IMPLICIT SEQUENCE OF
- OCTET STRING(SIZE(1)) OPTIONAL,
- teleServiceList [6] IMPLICIT SEQUENCE OF
- OCTET STRING(SIZE(1)) OPTIONAL,
- provisionedSS [7] IMPLICIT SEQUENCE OF SS-Information OPTIONAL
- }
-
-SS-Information ::= CHOICE{
- forwardingInfo [0] IMPLICIT ForwardingInfo,
- callBarringInfoInfo [1] IMPLICIT CallBarringInfoInfo,
- ss-Data [3] IMPLICIT SS-Data }
-
-SS-Data ::= SEQUENCE {
- ss-Code OCTET STRING (SIZE(1)),
- ss-Status [4] IMPLICIT OCTET STRING (SIZE(1))
- }
-
-
-ForwardingInfo ::= SEQUENCE {
- ss-Code OCTET STRING(SIZE(1)) OPTIONAL,
- forwardingFeatureList ForwardingFeatureList
- }
-
-CallBarringInfoInfo ::= SEQUENCE {
- ss-Code OCTET STRING(SIZE(1)) OPTIONAL,
- callBarringFeatureList CallBarringFeatureList}
-
-CallBarringFeatureList ::= SEQUENCE OF CallBarringFeature
-
-CallBarringFeature ::= SEQUENCE{
- basicService BasicServiceCode OPTIONAL,
- ss-Status [2] IMPLICIT OCTET STRING(SIZE(1)) OPTIONAL
- }
-
-InsertSubsDatRes ::=
- SEQUENCE {
- teleServiceList [1] IMPLICIT SEQUENCE OF
- OCTET STRING (SIZE(1)) OPTIONAL,
- bearerServiceList [2] IMPLICIT SEQUENCE OF
- OCTET STRING (SIZE(1)) OPTIONAL,
- ss-List [3] IMPLICIT SEQUENCE OF
- OCTET STRING (SIZE(1)) OPTIONAL,
- odb-GeneralData [4] IMPLICIT BIT STRING {
- allOG-CallsBarred (0),
- internationalOGCallsBarred (1),
- internationalOGCallsNotToHPLMN-CountryBarred (2),
- premiumRateInformationOGCallsBarred (3),
- premiumRateEntertainementOGCallsBarred (4),
- ss-AccessBarred (5) } (SIZE(6)) OPTIONAL,
- regionalSubscriptionResponse [5] IMPLICIT ENUMERATED{
- msc-AreaRestricted (0),
- tooManyZoneCodes (1),
- zoneCodeConflict (2),
- regionalSubscNotSupported (3) } OPTIONAL
- }
-
-
-ForwardingFeatureList ::= SEQUENCE OF ForwardingFeature
-
-ForwardingFeature ::= SEQUENCE{
- basicService BasicServiceCode OPTIONAL,
- ss-Status [4] IMPLICIT OCTET STRING(SIZE(1)) OPTIONAL,
- forwardedToNumber [5] ISDN-AddressString OPTIONAL,
- forwardingOptions [6] IMPLICIT OCTET STRING(SIZE(1)) OPTIONAL,
- noReplyConditionTime [7] IMPLICIT INTEGER(5..30) OPTIONAL
- }
-
-
-BasicServiceCode ::= CHOICE {
- bearerService [2] IMPLICIT OCTET STRING(SIZE(1)),
- teleService [3] IMPLICIT OCTET STRING(SIZE(1))
- }
-
-
-BasicServiceGroupList ::= SEQUENCE OF
- BasicServiceCode
-
-
-SubscriberStatus ::= ENUMERATED {
- serviceGranted (0),
- operatorDeterminedBarring (1)
- }
-
-END -- of MAP-insertSubscriberData-def
-
diff --git a/lib/asn1/test/asn1_SUITE_data/Mod.set.asn b/lib/asn1/test/asn1_SUITE_data/Mod.set.asn
deleted file mode 100644
index 5dcd8706ae..0000000000
--- a/lib/asn1/test/asn1_SUITE_data/Mod.set.asn
+++ /dev/null
@@ -1,5 +0,0 @@
-Mod1.asn
-Mod2.asn
-Mod3.asn
-Mod4.asn
-Mod5.asn
diff --git a/lib/asn1/test/asn1_SUITE_data/Mod1.asn b/lib/asn1/test/asn1_SUITE_data/Mod1.asn
deleted file mode 100644
index cb29997985..0000000000
--- a/lib/asn1/test/asn1_SUITE_data/Mod1.asn
+++ /dev/null
@@ -1,18 +0,0 @@
-Mod1 DEFINITIONS AUTOMATIC TAGS ::=
-
-BEGIN
-
-IMPORTS
- Co,Reg
- FROM Mod5
- Name
- FROM Mod4;
-
-
-L ::= SEQUENCE {
- country Co,
- region Reg,
- name Name
-}
-
-END
diff --git a/lib/asn1/test/asn1_SUITE_data/Mod2.asn b/lib/asn1/test/asn1_SUITE_data/Mod2.asn
deleted file mode 100644
index cc22c6f13c..0000000000
--- a/lib/asn1/test/asn1_SUITE_data/Mod2.asn
+++ /dev/null
@@ -1,43 +0,0 @@
-Mod2 DEFINITIONS AUTOMATIC TAGS ::=
-
-BEGIN
-
-IMPORTS
- Stat,Country
- FROM Mod3
- L
- FROM Mod1
- Time,LocName,ThingName,Name
- FROM Mod4;
-
-T ::= SEQUENCE {
- unit ENUMERATED{celsius,fahrenheit,kelvin},
- degree INTEGER,
- location L,
- time Time,
- statistics Stat
-}
-
-OtherName ::= SEQUENCE {
- locationName LocName,
- thingName ThingName
-}
-
-FirstName ::= CHOICE {
- firstname PrintableString,
- nickname PrintableString
-}
-
-FamilyName ::= SEQUENCE{
- prefix ENUMERATED{none,von,af},
- secondname PrintableString
-}
-
-Lang ::= SEQUENCE{
- l PrintableString}
-
-Inhabitant ::= SEQUENCE {
- name Name,
- country Country}
-
-END
diff --git a/lib/asn1/test/asn1_SUITE_data/Mod3.asn b/lib/asn1/test/asn1_SUITE_data/Mod3.asn
deleted file mode 100644
index 8069bedcf9..0000000000
--- a/lib/asn1/test/asn1_SUITE_data/Mod3.asn
+++ /dev/null
@@ -1,33 +0,0 @@
-Mod3 DEFINITIONS AUTOMATIC TAGS ::=
-
-BEGIN
-
-IMPORTS
- Name
- FROM Mod4
- Lang, Inhabitant,FirstName,FamilyName
- FROM Mod2
- TS, RFS, WS, HS
- FROM Mod5;
-
-Stat ::= SEQUENCE {
- tempstat TS,
- rainfallstat RFS,
- windstat WS,
- humiditystat HS
-}
-
-Country ::= SEQUENCE{
- name Name,
- language Lang
-}
-
-RegionName ::= Name
-Inhabitants ::= SEQUENCE OF Inhabitant
-
-PersonName ::= SEQUENCE {
- name1 FirstName,
- name2 FamilyName
-}
-
-END
diff --git a/lib/asn1/test/asn1_SUITE_data/Mod4.asn b/lib/asn1/test/asn1_SUITE_data/Mod4.asn
deleted file mode 100644
index 4a1aaff9dc..0000000000
--- a/lib/asn1/test/asn1_SUITE_data/Mod4.asn
+++ /dev/null
@@ -1,33 +0,0 @@
-Mod4 DEFINITIONS AUTOMATIC TAGS ::=
-
-
-BEGIN
-
-IMPORTS
- PersonName
- FROM Mod3
- OtherName,FirstName,FamilyName
- FROM Mod2;
-
-Time ::= SEQUENCE {
- year OCTET STRING(SIZE(4)),
- month OCTET STRING(SIZE(2)),
- hour INTEGER,
- minute INTEGER
-}
-
-Name ::= CHOICE {
- person PersonName,
- othername OtherName
-}
-
-
-
-LocName ::= SEQUENCE {
- region ENUMERATED{gotaland,svealand,norrland},
- name PrintableString
-}
-
-ThingName ::= PrintableString
-
-END
diff --git a/lib/asn1/test/asn1_SUITE_data/Mod5.asn b/lib/asn1/test/asn1_SUITE_data/Mod5.asn
deleted file mode 100644
index 71b483d0e0..0000000000
--- a/lib/asn1/test/asn1_SUITE_data/Mod5.asn
+++ /dev/null
@@ -1,37 +0,0 @@
-Mod5 DEFINITIONS AUTOMATIC TAGS ::=
-
-BEGIN
-
-IMPORTS
- Country,RegionName,Inhabitants
- FROM Mod3;
-TS ::= SEQUENCE {
- average INTEGER,
- highest INTEGER,
- lowest INTEGER
-}
-
-RFS ::= SEQUENCE {
- average INTEGER,
- highest INTEGER
-}
-
-WS ::= SEQUENCE {
- average INTEGER,
- highest INTEGER
-}
-
-HS ::= SEQUENCE {
- average INTEGER,
- highest INTEGER,
- lowest INTEGER
-}
-
-Co ::= Country
-
-Reg ::= SEQUENCE {
- name RegionName,
- inhabitants Inhabitants
-}
-
-END
diff --git a/lib/asn1/test/asn1_SUITE_data/Mvrasn.set.asn b/lib/asn1/test/asn1_SUITE_data/Mvrasn.set.asn
deleted file mode 100644
index 8a61da0160..0000000000
--- a/lib/asn1/test/asn1_SUITE_data/Mvrasn.set.asn
+++ /dev/null
@@ -1,7 +0,0 @@
-Mvrasn-11-6.asn
-Mvrasn-21-4.asn
-Mvrasn-20-6.asn
-Mvrasn-19-6.asn
-Mvrasn-15-6.asn
-Mvrasn-18-6.asn
-Mvrasn-14-6.asn
diff --git a/lib/asn1/test/asn1_SUITE_data/P-Record.asn1db b/lib/asn1/test/asn1_SUITE_data/P-Record.asn1db
deleted file mode 100644
index 13e1162c64..0000000000
--- a/lib/asn1/test/asn1_SUITE_data/P-Record.asn1db
+++ /dev/null
Binary files differ
diff --git a/lib/asn1/test/asn1_SUITE_data/P-Record.erl b/lib/asn1/test/asn1_SUITE_data/P-Record.erl
deleted file mode 100644
index 9fc6f50d64..0000000000
--- a/lib/asn1/test/asn1_SUITE_data/P-Record.erl
+++ /dev/null
@@ -1,244 +0,0 @@
-%% Generated by the Erlang ASN.1 BER-compiler version, utilizing bit-syntax:1.3.1.4
-%% Purpose: encoder and decoder to the types in mod P-Record
-
--module('P-Record').
--include("P-Record.hrl").
--define('RT_PER',asn1rt_per_bin).
--export([encoding_rule/0]).
--export([
-'enc_PersonnelRecord'/1,
-'enc_ChildInformation'/1,
-'enc_Name'/1,
-'enc_EmployeeNumber'/1,
-'enc_Date'/1
-]).
-
--export([
-'dec_PersonnelRecord'/2,
-'dec_ChildInformation'/2,
-'dec_Name'/2,
-'dec_EmployeeNumber'/2,
-'dec_Date'/2
-]).
-
--export([
-'v'/0
-]).
-
-
-
--export([encode/2,decode/2,encode_disp/2,decode_disp/2]).
-
-encoding_rule() ->
- per_bin.
-
-encode(Type,Data) ->
-case catch ?RT_PER:complete(encode_disp(Type,Data)) of
- {'EXIT',{error,Reason}} ->
- {error,Reason};
- {'EXIT',Reason} ->
- {error,{asn1,Reason}};
- {Bytes,Len} ->
- {ok,Bytes};
- X ->
- {ok,X}
-end.
-
-decode(Type,Data) ->
-case catch decode_disp(Type,Data) of
- {'EXIT',{error,Reason}} ->
- {error,Reason};
- {'EXIT',Reason} ->
- {error,{asn1,Reason}};
- {X,_Rest} ->
- {ok,X};
- {X,_Rest,_Len} ->
- {ok,X}
-end.
-
-encode_disp('PersonnelRecord',Data) -> 'enc_PersonnelRecord'(Data);
-encode_disp('ChildInformation',Data) -> 'enc_ChildInformation'(Data);
-encode_disp('Name',Data) -> 'enc_Name'(Data);
-encode_disp('EmployeeNumber',Data) -> 'enc_EmployeeNumber'(Data);
-encode_disp('Date',Data) -> 'enc_Date'(Data);
-encode_disp(Type,Data) -> exit({error,{asn1,{undefined_type,Type}}}).
-
-
-decode_disp('PersonnelRecord',Data) -> 'dec_PersonnelRecord'(Data,mandatory);
-decode_disp('ChildInformation',Data) -> 'dec_ChildInformation'(Data,mandatory);
-decode_disp('Name',Data) -> 'dec_Name'(Data,mandatory);
-decode_disp('EmployeeNumber',Data) -> 'dec_EmployeeNumber'(Data,mandatory);
-decode_disp('Date',Data) -> 'dec_Date'(Data,mandatory);
-decode_disp(Type,Data) -> exit({error,{asn1,{undefined_type,Type}}}).
-
-
-
-
-
-'enc_PersonnelRecord'(Val) ->
-{Val1,Opt} = ?RT_PER:fixoptionals([{children,6}],Val),
-[
-?RT_PER:setoptionals(Opt),
-
-%% attribute number 1 with type Externaltypereference6P-RecordName
-'enc_Name'(?RT_PER:cindex(2,Val1,name)),
-
-%% attribute number 2 with type VisibleString
-?RT_PER:encode_VisibleString([],?RT_PER:cindex(3,Val1,title)),
-
-%% attribute number 3 with type INTEGER
-?RT_PER:encode_integer([],?RT_PER:cindex(4,Val1,number)),
-
-%% attribute number 4 with type VisibleString
-?RT_PER:encode_VisibleString([],?RT_PER:cindex(5,Val1,dateOfHire)),
-
-%% attribute number 5 with type Externaltypereference10P-RecordName
-'enc_Name'(?RT_PER:cindex(6,Val1,nameOfSpouse)),
-case ?RT_PER:cindex(7,Val1,children) of
-asn1_DEFAULT -> [];
-_ ->
-
-%% attribute number 6 with type SEQUENCE OF
-'enc_PersonnelRecord_children'(?RT_PER:cindex(7,Val1,children))
-end].
-
-'enc_PersonnelRecord_children'({'PersonnelRecord_children',Val}) ->
-'enc_PersonnelRecord_children'(Val);
-
-'enc_PersonnelRecord_children'(Val) ->
-[
-
- ?RT_PER:encode_length(undefined,length(Val)),
- 'enc_PersonnelRecord_children_components'(Val, [])
-].
-'enc_PersonnelRecord_children_components'([], Acc) -> lists:reverse(Acc);
-
-'enc_PersonnelRecord_children_components'([H|T], Acc) ->
-'enc_PersonnelRecord_children_components'(T, ['enc_ChildInformation'(H)
-
- | Acc]).
-
-'dec_PersonnelRecord_children'(Bytes,Telltype) ->
-
-{Num,Bytes1} = ?RT_PER:decode_length(Bytes,undefined),
-'dec_PersonnelRecord_children_components'(Num, Bytes1, Telltype, []).
-'dec_PersonnelRecord_children_components'(0, Bytes, Telltype, Acc) ->
- {lists:reverse(Acc), Bytes};
-'dec_PersonnelRecord_children_components'(Num, Bytes, Telltype, Acc) ->
- {Term,Remain} = 'P-Record':'dec_ChildInformation'(Bytes,Telltype),
- 'dec_PersonnelRecord_children_components'(Num-1, Remain, Telltype, [Term|Acc]).
-
-
-'dec_PersonnelRecord'(Bytes,Telltype) ->
-{Opt,Bytes1} = ?RT_PER:getoptionals(Bytes,1),
-%% attribute number 1 with type Name
-{Term1,Bytes2} = 'dec_Name'(Bytes1,telltype),
-
-%% attribute number 2 with type VisibleString
-{Term2,Bytes3} = ?RT_PER:decode_VisibleString(Bytes2,[]),
-
-%% attribute number 3 with type INTEGER
-{Term3,Bytes4} = ?RT_PER:decode_integer(Bytes3,[]),
-
-%% attribute number 4 with type VisibleString
-{Term4,Bytes5} = ?RT_PER:decode_VisibleString(Bytes4,[]),
-
-%% attribute number 5 with type Name
-{Term5,Bytes6} = 'dec_Name'(Bytes5,telltype),
-
-%% attribute number 6 with type SEQUENCE OF
-{Term6,Bytes7} = case element(1,Opt) of
-1 ->'dec_PersonnelRecord_children'(Bytes6, Telltype);
-0 ->{[],Bytes6}
-
-end,
-{{'PersonnelRecord',Term1,Term2,Term3,Term4,Term5,Term6},Bytes7}.
-
-'enc_ChildInformation'(Val) ->
-{Val1,Opt} = ?RT_PER:fixoptionals([{name,1},{dateOfBirth,2}],Val),
-[
-?RT_PER:setoptionals(Opt),
-case ?RT_PER:cindex(2,Val1,name) of
-asn1_NOVALUE -> [];
-_ ->
-
-%% attribute number 1 with type Externaltypereference15P-RecordName
-'enc_Name'(?RT_PER:cindex(2,Val1,name))
-end,
-case ?RT_PER:cindex(3,Val1,dateOfBirth) of
-asn1_NOVALUE -> [];
-_ ->
-
-%% attribute number 2 with type VisibleString
-?RT_PER:encode_VisibleString([],?RT_PER:cindex(3,Val1,dateOfBirth))
-end].
-
-
-'dec_ChildInformation'(Bytes,Telltype) ->
-{Opt,Bytes1} = ?RT_PER:getoptionals(Bytes,2),
-%% attribute number 1 with type Name
-{Term1,Bytes2} = case element(1,Opt) of
-1 ->'dec_Name'(Bytes1,telltype);
-0 ->{asn1_NOVALUE,Bytes1}
-
-end,
-
-%% attribute number 2 with type VisibleString
-{Term2,Bytes3} = case element(2,Opt) of
-1 ->?RT_PER:decode_VisibleString(Bytes2,[]);
-0 ->{asn1_NOVALUE,Bytes2}
-
-end,
-{{'ChildInformation',Term1,Term2},Bytes3}.
-
-'enc_Name'(Val) ->
-Val1 = ?RT_PER:list_to_record('Name', Val),
-[
-
-%% attribute number 1 with type VisibleString
-?RT_PER:encode_VisibleString([],?RT_PER:cindex(2,Val1,givenName)),
-
-%% attribute number 2 with type VisibleString
-?RT_PER:encode_VisibleString([],?RT_PER:cindex(3,Val1,initial)),
-
-%% attribute number 3 with type VisibleString
-?RT_PER:encode_VisibleString([],?RT_PER:cindex(4,Val1,familyName))].
-
-
-'dec_Name'(Bytes,Telltype) ->
-
-%% attribute number 1 with type VisibleString
-{Term1,Bytes1} = ?RT_PER:decode_VisibleString(Bytes,[]),
-
-%% attribute number 2 with type VisibleString
-{Term2,Bytes2} = ?RT_PER:decode_VisibleString(Bytes1,[]),
-
-%% attribute number 3 with type VisibleString
-{Term3,Bytes3} = ?RT_PER:decode_VisibleString(Bytes2,[]),
-{{'Name',Term1,Term2,Term3},Bytes3}.
-
-
-'enc_EmployeeNumber'({'EmployeeNumber',Val}) ->
-'enc_EmployeeNumber'(Val);
-
-'enc_EmployeeNumber'(Val) ->
-?RT_PER:encode_integer([],Val).
-
-
-'dec_EmployeeNumber'(Bytes,Telltype) ->
-?RT_PER:decode_integer(Bytes,[]).
-
-
-'enc_Date'({'Date',Val}) ->
-'enc_Date'(Val);
-
-'enc_Date'(Val) ->
-?RT_PER:encode_VisibleString([],Val).
-
-
-'dec_Date'(Bytes,Telltype) ->
-?RT_PER:decode_VisibleString(Bytes,[]).
-
-'v'() ->
-{'PersonnelRecord',{'Name',{74,111,104,110},[80],[83,109,105,116,104]},[68,105,114,101,99,116,111,114],51,[49,57,55,49,48,57,49,55],{'Name',{77,97,114,121},[84],[83,109,105,116,104]},[{'ChildInformation',{'Name',[82,97,108,112,104],[84],[83,109,105,116,104]},[49,57,53,55,49,49,49,49]},{'ChildInformation',{'Name',[83,117,115,97,110],[66],[74,111,110,101,115]},[49,57,53,57,48,55,49,55]}]}.
-
diff --git a/lib/asn1/test/asn1_SUITE_data/P-Record.hrl b/lib/asn1/test/asn1_SUITE_data/P-Record.hrl
deleted file mode 100644
index 92aa1a44e2..0000000000
--- a/lib/asn1/test/asn1_SUITE_data/P-Record.hrl
+++ /dev/null
@@ -1,17 +0,0 @@
-%% Generated by the Erlang ASN.1 compiler version:1.3.1.4
-%% Purpose: Erlang record definitions for each named and unnamed
-%% SEQUENCE and SET, and macro definitions for each value
-%% definition,in module P-Record
-
-
-
--record('PersonnelRecord',{
-name, title, number, dateOfHire, nameOfSpouse, children = asn1_DEFAULT}).
-
--record('ChildInformation',{
-name = asn1_NOVALUE, dateOfBirth = asn1_NOVALUE}).
-
--record('Name',{
-givenName, initial, familyName}).
-
--define('v', {'PersonnelRecord',{'Name',{74,111,104,110},[80],[83,109,105,116,104]},[68,105,114,101,99,116,111,114],51,[49,57,55,49,48,57,49,55],{'Name',{77,97,114,121},[84],[83,109,105,116,104]},[{'ChildInformation',{'Name',[82,97,108,112,104],[84],[83,109,105,116,104]},[49,57,53,55,49,49,49,49]},{'ChildInformation',{'Name',[83,117,115,97,110],[66],[74,111,110,101,115]},[49,57,53,57,48,55,49,55]}]}).
diff --git a/lib/asn1/test/asn1_SUITE_data/PDUs.py b/lib/asn1/test/asn1_SUITE_data/PDUs.py
deleted file mode 100644
index 907348193f..0000000000
--- a/lib/asn1/test/asn1_SUITE_data/PDUs.py
+++ /dev/null
@@ -1,325 +0,0 @@
-PDUs DEFINITIONS ::=
-
--- Search for 'org' to find changes for erlang.
-
--- SnmpMgmtCom and PDUs only for dbg.
-
-
-BEGIN
-EXPORTS SnmpPrivMsg, SnmpAuthMsg, SnmpMgmtCom, PDUs;
-
--- From RFC 1442
-
- -- names of objects
-
- ObjectName ::=
- OBJECT IDENTIFIER
-
-
- -- syntax of objects
-
- ObjectSyntax ::=
- CHOICE {
- simple
- SimpleSyntax,
-
- -- note that SEQUENCEs for conceptual tables and
- -- rows are not mentioned here...
-
- applicationWide
- ApplicationSyntax
- }
-
-
- -- built-in ASN.1 types
-
- SimpleSyntax ::=
- CHOICE {
- -- INTEGERs with a more restrictive range
- -- may also be used
- integerValue
- INTEGER,
-
- stringValue
- OCTET STRING,
-
- objectIDValue
- OBJECT IDENTIFIER,
-
- -- only the enumerated form is allowed
- bitValue
- BIT STRING
- }
-
-
- -- indistinguishable from INTEGER, but never needs more than
- -- 32Bits for a two's complement representation
- Integer32 ::=
- [UNIVERSAL 2]
- IMPLICIT INTEGER (-2147483648..2147483647)
-
-
- -- applicationWide types
-
- ApplicationSyntax ::=
- CHOICE {
- ipAddressValue
- IpAddress,
-
- counterValue
- Counter32,
-
- gaugeValue
- Gauge32,
-
- timeticksValue
- TimeTicks,
-
- arbitraryValue
- Opaque,
-
- nsapAddressValue
- NsapAddress,
-
- bigCounterValue
- Counter64,
-
- unsignedIntegerValue
- UInteger32
- }
-
- -- in networkByte order
- -- (this is a tagged type for historical reasons)
- IpAddress ::=
- [APPLICATION 0]
- IMPLICIT OCTET STRING (SIZE (4))
-
-
-
-
- -- this wraps
- Counter32 ::=
- [APPLICATION 1]
- IMPLICIT INTEGER (0..4294967295)
-
- -- this doesn't wrap
- Gauge32 ::=
- [APPLICATION 2]
- IMPLICIT INTEGER (0..4294967295)
-
- -- hundredths of seconds since an epoch
- TimeTicks ::=
- [APPLICATION 3]
- IMPLICIT INTEGER (0..4294967295)
-
- -- for backwardCompatibility only
- Opaque ::=
- [APPLICATION 4]
- IMPLICIT OCTET STRING
-
- -- for OSI NSAP addresses
- -- (this is a tagged type for historical reasons)
- NsapAddress ::=
- [APPLICATION 5]
--- org: IMPLICIT OCTET STRING (SIZE (1 | 4..21))
- IMPLICIT OCTET STRING
-
- -- for counters that wrap in less than one hour with only 32 bits
- Counter64 ::=
- [APPLICATION 6]
- IMPLICIT INTEGER (0..18446744073709551615)
-
- -- an unsigned 32Bit quantity
- UInteger32 ::=
- [APPLICATION 7]
- IMPLICIT INTEGER (0..4294967295)
-
-
--- From RFC 1445
-
- SnmpPrivMsg ::= [1] IMPLICIT SEQUENCE {
- privDst
- OBJECT IDENTIFIER,
- privData
- [1] IMPLICIT OCTET STRING
- }
-
- SnmpAuthMsg ::= [1] IMPLICIT SEQUENCE {
- authInfo
- ANY, -- defined by authentication protocol
- authData
- SnmpMgmtCom
- }
-
- SnmpMgmtCom ::= [2] IMPLICIT SEQUENCE {
- dstParty
- OBJECT IDENTIFIER,
- srcParty
- OBJECT IDENTIFIER,
- context
- OBJECT IDENTIFIER,
- pdu
- PDUs
- }
-
-
--- From RFC 1448
-
- -- org: no tag at all. we need a tag to test 'PDUs'.
- PDUs ::= [PRIVATE 1]
- -- remove tag when 'PDUs' only is used in another type.
- CHOICE {
- getRequest
- GetRequestPdu,
-
- getNextRequest
- GetNextRequestPdu,
-
- getBulkRequest
- GetBulkRequestPdu,
-
- response
- ResponsePdu,
-
- setRequest
- SetRequestPdu,
-
- informRequest
- InformRequestPdu,
-
- snmpV2Trap
- SNMPv2TrapPdu
- }
-
- -- PDUs
-
- GetRequestPdu ::=
- [0]
- IMPLICIT PDU
-
- GetNextRequestPdu ::=
- [1]
- IMPLICIT PDU
-
- ResponsePdu ::=
- [2]
- IMPLICIT PDU
-
- SetRequestPdu ::=
- [3]
- IMPLICIT PDU
-
- -- [4] is obsolete
-
- GetBulkRequestPdu ::=
- [5]
- IMPLICIT BulkPDU
-
- InformRequestPdu ::=
- [6]
- IMPLICIT PDU
-
- SNMPv2TrapPdu ::=
- [7]
- IMPLICIT PDU
-
-
- maxBindings
- INTEGER ::= 2147483647
-
- PDU ::=
- SEQUENCE {
- requestId
- Integer32,
-
- errorStatus -- sometimes ignored
- INTEGER {
- noError(0),
- tooBig(1),
- noSuchName(2), -- for proxy compatibility
- badValue(3), -- for proxy compatibility
- readOnly(4), -- for proxy compatibility
- genErr(5),
- noAccess(6),
- wrongType(7),
- wrongLength(8),
- wrongEncoding(9),
- wrongValue(10),
- noCreation(11),
- inconsistentValue(12),
- resourceUnavailable(13),
- commitFailed(14),
- undoFailed(15),
- authorizationError(16),
- notWritable(17),
- inconsistentName(18)
- },
-
- errorIndex -- sometimes ignored
- INTEGER (0..maxBindings),
-
- variableBindings -- values are sometimes ignored
- VarBindList
- }
-
-
- BulkPDU ::= -- MUST be identical in
- SEQUENCE { -- structure to PDU
- requestId
- Integer32,
-
- nonRepeaters
- INTEGER (0..maxBindings),
-
- maxRepetitions
- INTEGER (0..maxBindings),
-
- variableBindings -- values are ignored
- VarBindList
- }
-
-
- VarBind ::=
- SEQUENCE {
- name
- ObjectName,
-
- data CHOICE {
- value
- ObjectSyntax,
-
- unSpecified -- in retrieval requests
- NULL,
-
- -- exceptions in responses
- noSuchObject[0]
- IMPLICIT NULL,
-
- noSuchInstance[1]
- IMPLICIT NULL,
-
- endOfMibView[2]
- IMPLICIT NULL
- }
- }
-
-
- -- variableBinding list
-
- VarBindList ::=
- SEQUENCE OF VarBind
-
--- org:
--- VarBindList ::=
--- SEQUENCE (SIZE (0..maxBindings)) OF
--- VarBind
-
-END
-
-
-
-
-
-
-
-
diff --git a/lib/asn1/test/asn1_SUITE_data/Pattern.asn b/lib/asn1/test/asn1_SUITE_data/Pattern.asn
deleted file mode 100644
index 730b4ba32a..0000000000
--- a/lib/asn1/test/asn1_SUITE_data/Pattern.asn
+++ /dev/null
@@ -1,8 +0,0 @@
-Pattern DEFINITIONS AUTOMATIC TAGS ::=
-
-BEGIN
-
-DateAndTime ::= VisibleString (PATTERN "\d#2/\d#2/\d#4-\d#2:\d#2")
--- DD/MM/YYY-HH:MM
-
-END \ No newline at end of file
diff --git a/lib/asn1/test/asn1_SUITE_data/Prim.asn1 b/lib/asn1/test/asn1_SUITE_data/Prim.asn1
index c3d54dbbb3..cc0e61422a 100644
--- a/lib/asn1/test/asn1_SUITE_data/Prim.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/Prim.asn1
@@ -47,5 +47,15 @@ BEGIN
b Bool,
i4 INTEGER (0..63)
}
-
+
+ ASeq ::= SEQUENCE {
+ e254 BOOLEAN,
+ i254 INTEGER (0..254),
+ e255 BOOLEAN,
+ i255 INTEGER (0..255),
+ e256 BOOLEAN,
+ i256 INTEGER (0..256),
+ e BOOLEAN,
+ magic INTEGER
+ }
END
diff --git a/lib/asn1/test/asn1_SUITE_data/PrimStrings.asn1 b/lib/asn1/test/asn1_SUITE_data/PrimStrings.asn1
index cfaf4cf034..08e7f94ab6 100644
--- a/lib/asn1/test/asn1_SUITE_data/PrimStrings.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/PrimStrings.asn1
@@ -5,7 +5,7 @@ BEGIN
Bs1 ::= BIT STRING
Bs2 ::= BIT STRING {su(0), mo(1), tu(2), we(3), th(4), fr(5), sa(6) } (SIZE (7))
Bs3 ::= BIT STRING {su(0), mo(1), tu(2), we(3), th(4), fr(5), sa(6) } (SIZE (1..7))
- Bs4 ::= BIT STRING {su(0), mo(1), tu(2), we(3), th(4), fr(5), sa(6) } (SIZE (1..32))
+ Bs4 ::= BIT STRING {su(0), mo(1), tu(2), we(3), th(4), fr(5), sa(6) }
Bs5 ::= BIT STRING {su(0), mo(17), tu(2), we(3), th(4), fr(5), sa(6) } (SIZE (1..32))
Bs6 ::= BIT STRING {su(0), mo(17), tu(2), we(3), th(4), fr(5), sa(6)} (SIZE (16..32))
Bs7 ::= BIT STRING (SIZE (24))
@@ -55,10 +55,15 @@ BS1024 ::= BIT STRING (SIZE (1024))
OsExpCon ::= [60] EXPLICIT OCTET STRING
OsExpPri ::= [PRIVATE 61] EXPLICIT OCTET STRING
OsExpApp ::= [APPLICATION 62] EXPLICIT OCTET STRING
+
OsFrag ::= OCTET STRING (SIZE (0..100000))
FixedOs65536 ::= OCTET STRING (SIZE (65536))
FixedOs65537 ::= OCTET STRING (SIZE (65537))
+ OsFragExt ::= OCTET STRING (SIZE (0..100000, ...))
+ FixedOs65536Ext ::= OCTET STRING (SIZE (65536, ...))
+ FixedOs65537Ext ::= OCTET STRING (SIZE (65537, ...))
+
OsFixedStrings ::= SEQUENCE {
b1 BOOLEAN, -- Unalign
s0 OCTET STRING (SIZE (0)),
@@ -72,6 +77,32 @@ BS1024 ::= BIT STRING (SIZE (1024))
i INTEGER (0..1024)
}
+ OsFixedStringsExt ::= SEQUENCE {
+ b1 BOOLEAN, -- Unalign
+ s0 OCTET STRING (SIZE (0, ...)),
+ s1 OCTET STRING (SIZE (1, ...)),
+ s2 OCTET STRING (SIZE (2, ...)),
+ s3 OCTET STRING (SIZE (3, ...)),
+ b2 BOOLEAN, -- Unalign
+ s255 OCTET STRING (SIZE (255, ...)),
+ s256 OCTET STRING (SIZE (256, ...)),
+ s257 OCTET STRING (SIZE (257, ...)),
+ i INTEGER (0..1024)
+ }
+
+ OsVarStringsExt ::= SEQUENCE {
+ b1 BOOLEAN, -- Unalign
+ s0 OCTET STRING (SIZE (0, ...)),
+ s1 OCTET STRING (SIZE (0..1, ...)),
+ s2 OCTET STRING (SIZE (1..2, ...)),
+ s3 OCTET STRING (SIZE (2..3, ...)),
+ b2 BOOLEAN, -- Unalign
+ s255 OCTET STRING (SIZE (254..255, ...)),
+ s256 OCTET STRING (SIZE (255..256, ...)),
+ s257 OCTET STRING (SIZE (256..257, ...)),
+ i INTEGER (0..1024)
+ }
+
OsAlignment ::= SEQUENCE {
b1 BOOLEAN,
s1 Os,
@@ -82,6 +113,52 @@ BS1024 ::= BIT STRING (SIZE (1024))
i INTEGER (0..63)
}
+ IA5FixedStrings ::= SEQUENCE {
+ b1 BOOLEAN, -- Unalign
+ s0 IA5String (SIZE (0)),
+ s1 IA5String (SIZE (1)),
+ s2 IA5String (SIZE (2)),
+ s3 IA5String (SIZE (3)),
+ b2 BOOLEAN, -- Unalign
+ s4 IA5String (SIZE (4)),
+ b3 BOOLEAN, -- Unalign
+ s255 IA5String (SIZE (255)),
+ s256 IA5String (SIZE (256)),
+ s257 IA5String (SIZE (257)),
+ i INTEGER (0..1024)
+ }
+
+ IA5FixedStringsExt ::= SEQUENCE {
+ b1 BOOLEAN, -- Unalign
+ s0 IA5String (SIZE (0, ...)),
+ s1 IA5String (SIZE (1, ...)),
+ s2 IA5String (SIZE (2, ...)),
+ s3 IA5String (SIZE (3, ...)),
+ b2 BOOLEAN, -- Unalign
+ s4 IA5String (SIZE (4, ...)),
+ b3 BOOLEAN, -- Unalign
+ s255 IA5String (SIZE (255, ...)),
+ s256 IA5String (SIZE (256, ...)),
+ s257 IA5String (SIZE (257, ...)),
+ i INTEGER (0..1024)
+ }
+
+ IA5VarStringsExt ::= SEQUENCE {
+ b1 BOOLEAN, -- Unalign
+ s0 IA5String (SIZE (0, ...)),
+ s1 IA5String (SIZE (0..1, ...)),
+ s2 IA5String (SIZE (1..2, ...)),
+ s3 IA5String (SIZE (2..3, ...)),
+ b2 BOOLEAN, -- Unalign
+ s4 IA5String (SIZE (3..4, ...)),
+ b3 BOOLEAN, -- Unalign
+ s255 IA5String (SIZE (254..255, ...)),
+ s256 IA5String (SIZE (255..256, ...)),
+ s257 IA5String (SIZE (256..257, ...)),
+ i INTEGER (0..1024)
+ }
+
+
Ns ::= NumericString
NsCon ::= [70] NumericString
NsExpCon ::= [71] EXPLICIT NumericString
diff --git a/lib/asn1/test/asn1_SUITE_data/ROSE.asn1 b/lib/asn1/test/asn1_SUITE_data/ROSE.asn1
deleted file mode 100644
index 2fefae3caf..0000000000
--- a/lib/asn1/test/asn1_SUITE_data/ROSE.asn1
+++ /dev/null
@@ -1,449 +0,0 @@
-ROSE DEFINITIONS IMPLICIT TAGS ::=
-
-
-BEGIN
-
-OPERATION ::= CLASS
-{
- &ArgumentType OPTIONAL,
- &argumentTypeOptional BOOLEAN OPTIONAL,
- &returnResult BOOLEAN DEFAULT TRUE,
- &ResultType OPTIONAL,
- &resultTypeOptional BOOLEAN OPTIONAL,
- &Errors ERROR OPTIONAL,
- &Linked OPERATION OPTIONAL,
- &synchronous BOOLEAN DEFAULT FALSE,
- &idempotent BOOLEAN DEFAULT FALSE,
- &alwaysReturns BOOLEAN DEFAULT TRUE,
- &InvokePriority Priority OPTIONAL,
- &ResultPriority Priority OPTIONAL,
- &operationCode Code UNIQUE OPTIONAL
- }
-WITH SYNTAX
- {
- [ARGUMENT &ArgumentType [OPTIONAL &argumentTypeOptional]]
- [RESULT &ResultType [OPTIONAL &resultTypeOptional]]
- [RETURN RESULT &returnResult]
- [ERRORS &Errors]
- [LINKED &Linked]
- [SYNCHRONOUS &synchronous]
- [IDEMPOTENT &idempotent]
- [ALWAYS RESPONDS &alwaysReturns]
- [INVOKE PRIORITY &InvokePriority]
- [RESULT-PRIORITY &ResultPriority]
- [CODE &operationCode]
- }
-
-ERROR ::= CLASS
-{
- &ParameterType OPTIONAL,
- &parameterTypeOptional BOOLEAN OPTIONAL,
- &ErrorPriority Priority OPTIONAL,
- &errorCode Code UNIQUE OPTIONAL
- }
-WITH SYNTAX
-{
- [PARAMETER &ParameterType [OPTIONAL &parameterTypeOptional]]
- [PRIORITY &ErrorPriority]
- [CODE &errorCode]
- }
-
-OPERATION-PACKAGE ::= CLASS
-{
- &Both OPERATION OPTIONAL,
- &Consumer OPERATION OPTIONAL,
- &Supplier OPERATION OPTIONAL,
- &id OBJECT IDENTIFIER UNIQUE OPTIONAL
- }
-WITH SYNTAX
-{
- [OPERATIONS &Both]
- [CONSUMER INVOKES &Supplier]
- [SUPPLIER INVOKES &Consumer]
- [ID &id]
- }
-
-CONNECTION-PACKAGE ::= CLASS
-{
- &bind OPERATION DEFAULT emptyBind,
- &unbind OPERATION DEFAULT emptyUnbind,
- &responderCanUnbind BOOLEAN DEFAULT FALSE,
- &unbindCanFail BOOLEAN DEFAULT FALSE,
- &id OBJECT IDENTIFIER UNIQUE OPTIONAL
- }
-WITH SYNTAX
-{
- [BIND &bind]
- [UNBIND &unbind]
- [RESPONDER UNBIND &responderCanUnbind]
- [FAILURE TO UNBIND &unbindCanFail]
- [ID &id]
- }
-
-CONTRACT ::= CLASS
-{
- &connection CONNECTION-PACKAGE OPTIONAL,
- &OperationsOf OPERATION-PACKAGE OPTIONAL,
- &InitiatorConsumerOf OPERATION-PACKAGE OPTIONAL,
- &InitiatorSupplierOf OPERATION-PACKAGE OPTIONAL,
- &id OBJECT IDENTIFIER UNIQUE OPTIONAL
- }
-WITH SYNTAX
-{
- [CONNECTION &connection]
- [OPERATIONS OF &OperationsOf]
- [INITIATOR CONSUMER OF &InitiatorConsumerOf]
- [RESPONDER CONSUMER OF &InitiatorSupplierOf]
- [ID &id]
-}
-
-ROS-OBJECT-CLASS ::= CLASS
-{
- &Is ROS-OBJECT-CLASS OPTIONAL,
- &Initiates CONTRACT OPTIONAL,
- &Responds CONTRACT OPTIONAL,
- &InitiatesAndResponds CONTRACT OPTIONAL,
- &id OBJECT IDENTIFIER UNIQUE
- }
-WITH SYNTAX
-{
- [IS &Is]
- [BOTH &InitiatesAndResponds]
- [INITIATES &Initiates]
- [RESPONDS &Responds]
- ID &id
- }
-
-Code ::= CHOICE
-{
- local INTEGER,
- global OBJECT IDENTIFIER
- }
-
-Priority ::= INTEGER (0..MAX)
-
-ROS {InvokeId:InvokeIdSet,OPERATION:Invokable,OPERATION:Returnable} ::= CHOICE
- {
- invoke [1] Invoke {{InvokeIdSet}, {Invokable}},
- returnResult [2] ReturnResult {{Returnable}},
- returnError [3] ReturnError {{Errors{{Returnable}}}},
- reject [4] Reject
- }
-(CONSTRAINED BY {-- must conform to the above definition --}
- ! RejectProblem : general-unrecognizedPDU)
-
-Invoke {InvokeId:InvokeIdSet, OPERATION:Operations} ::= SEQUENCE
-{
- invokeId InvokeId (InvokeIdSet)
- (CONSTRAINED BY {-- must be unambiguous --}
- ! RejectProblem : invoke-duplicateInvocation),
- linkedId CHOICE {
- present [0] IMPLICIT present < InvokeId,
- absent [1] IMPLICIT NULL
- }
- (CONSTRAINED BY {-- must identify an outstanding operation --}
- ! RejectProblem : invoke-unrecognizedLinkedId)
- (CONSTRAINED BY {-- which has one or more linked operations--}
- ! RejectProblem : invoke-linkedResponseUnexpected)
- OPTIONAL,
- opcode OPERATION.&operationCode
- ({Operations}
- ! RejectProblem : invoke-unrecognizedOperation),
- argument OPERATION.&ArgumentType
- ({Operations} {@opcode}
- ! RejectProblem : invoke-mistypedArgument)
- OPTIONAL
- }
-(CONSTRAINED BY {-- must conform to the above definition --}
- ! RejectProblem : general-mistypedPDU)
-(
-WITH COMPONENTS
-{...,
- linkedId ABSENT
- }
-| WITH COMPONENTS
-{...,
- linkedId PRESENT,
- opcode
- (CONSTRAINED BY {-- must be in the &Linked field of the associated operation --
- }
- ! RejectProblem : invoke-unexpectedLinkedOperation)
- }
-)
-
-ReturnResult {OPERATION:Operations}::= SEQUENCE
-{
- invokeId InvokeId
- (CONSTRAINED BY {-- must be that for an outstanding operation --}
- ! RejectProblem:returnResult-unrecognizedInvocation)
- (CONSTRAINED BY {-- which returns a result --}
- ! RejectProblem:returnResult-resultResponseUnexpected),
- result SEQUENCE
- {
- opcode OPERATION.&operationCode
- ({Operations})(CONSTRAINED BY {-- identified by invokeId --}
- ! RejectProblem:returnResult-unrecognizedInvocation),
- result OPERATION.&ResultType ({Operations} {@.opcode}
- ! RejectProblem:returnResult-mistypedResult)
- }
- OPTIONAL
- }
-(CONSTRAINED BY {-- must conform to the above definition --
- }
-! RejectProblem:general-mistypedPDU)
-
-ReturnError {ERROR:Errors} ::= SEQUENCE
-{
- invokeId InvokeId
- (CONSTRAINED BY {-- must be that for an outstanding operation --
- }
- ! RejectProblem : returnError-unrecognizedInvocation)
- (CONSTRAINED BY {-- which returns an error --
- }
- ! RejectProblem : returnError-errorResponseUnexpected),
- errcode ERROR.&errorCode
- ({Errors}
- ! RejectProblem : returnError-unrecognizedError)
- (CONSTRAINED BY {-- must be in the &Errors field of the associated operation --
- }
- ! RejectProblem : returnError-unexpectedError),
- parameter ERROR.&ParameterType
- ({Errors}{@errcode}
- ! RejectProblem : returnError-mistypedParameter) OPTIONAL
- }
-(CONSTRAINED BY {-- must conform to the above definition --
- }
-! RejectProblem : general-mistypedPDU)
-
-Reject ::= SEQUENCE
-{
- invokeId InvokeId,
- problem CHOICE
- {
- general [0] GeneralProblem,
- invoke [1] InvokeProblem,
- returnResult [2] ReturnResultProblem,
- returnError [3] ReturnErrorProblem
- }
- }
-(CONSTRAINED BY {-- must conform to the above definition --
- }
-! RejectProblem : general-mistypedPDU)
-
-GeneralProblem ::= INTEGER
-{
- unrecognizedPDU (0),
- mistypedPDU (1),
- badlyStructuredPDU (2)
- }
-
-InvokeProblem ::= INTEGER
-{
- duplicateInvocation (0),
- unrecognizedOperation (1),
- mistypedArgument (2),
- resourceLimitation (3),
- releaseInProgress (4),
- unrecognizedLinkedId (5),
- linkedResponseUnexpected (6),
- unexpectedLinkedOperation (7)
- }
-
-ReturnResultProblem ::= INTEGER
-{
- unrecognizedInvocation (0),
- resultResponseUnexpected (1),
- mistypedResult (2)
- }
-
-ReturnErrorProblem ::= INTEGER
-{
- unrecognizedInvocation (0),
- errorResponseUnexpected (1),
- unrecognizedError (2),
- unexpectedError (3),
- mistypedParameter (4)
- }
-
-RejectProblem ::= INTEGER
-{
- general-unrecognizedPDU (0),
- general-mistypedPDU (1),
- general-badlyStructuredPDU (2),
- invoke-duplicateInvocation (10),
- invoke-unrecognizedOperation (11),
- invoke-mistypedArgument (12),
- invoke-resourceLimitation (13),
- invoke-releaseInProgress (14),
- invoke-unrecognizedLinkedId (15),
- invoke-linkedResponseUnexpected (16),
- invoke-unexpectedLinkedOperation (17),
- returnResult-unrecognizedInvocation (20),
- returnResult-resultResponseUnexpected (21),
- returnResult-mistypedResult (22),
- returnError-unrecognizedInvocation (30),
- returnError-errorResponseUnexpected (31),
- returnError-unrecognizedError (32),
- returnError-unexpectedError (33),
- returnError-mistypedParameter (34)
- }
-
-InvokeId ::= CHOICE
-{
- present INTEGER,
- absent NULL
- }
-
-noInvokeId InvokeId ::= absent:NULL
-
-NoInvokeId InvokeId ::= {noInvokeId}
-
-Errors {OPERATION:Operations} ERROR ::= {Operations.&Errors}
-
-Bind {OPERATION:operation} ::= CHOICE
-{
- bind-invoke [16] OPERATION.&ArgumentType({operation}),
- bind-result [17] OPERATION.&ResultType ({operation}),
- bind-error [18] OPERATION.&Errors.&ParameterType ({operation})
- }
-
-Unbind {OPERATION:operation} ::= CHOICE
-{
- unbind-invoke [19] OPERATION.&ArgumentType({operation}),
- unbind-result [20] OPERATION.&ResultType ({operation}),
- unbind-error [21] OPERATION.&Errors.&ParameterType ({operation})
- }
-
-emptyBind OPERATION ::= {ERRORS {refuse} SYNCHRONOUS TRUE}
-
-emptyUnbind OPERATION ::= { SYNCHRONOUS TRUE }
-
-refuse ERROR ::= {CODE local:-1}
-
-no-op OPERATION ::=
- {
- IDEMPOTENT TRUE
- ALWAYS RESPONDS FALSE
- CODE local:-1
- }
-
-Forward {OPERATION:OperationSet} OPERATION ::=
-{
- OperationSet |
- OperationSet.&Linked.&Linked |
- OperationSet.&Linked.&Linked.&Linked.&Linked
- }
-
-Reverse {OPERATION:OperationSet} OPERATION ::=
-{Forward{{OperationSet.&Linked}}}
-
-ConsumerPerforms {OPERATION-PACKAGE:package} OPERATION ::=
-{
- Forward{{package.&Consumer}} |
- Forward{{package.&Both}} |
- Reverse{{package.&Supplier}} |
- Reverse{{package.&Both}}
- }
-
-SupplierPerforms {OPERATION-PACKAGE:package} OPERATION ::=
-{
- Forward{{package.&Supplier}} |
- Forward{{package.&Both}} |
- Reverse{{package.&Consumer}} |
- Reverse{{package.&Both}}
- }
-
-AllOperations {OPERATION-PACKAGE:package} OPERATION ::=
-{
- ConsumerPerforms {package} |
- SupplierPerforms {package}
- }
-
-recode {OPERATION:operation, Code:code} OPERATION ::=
-{
- ARGUMENT operation.&ArgumentType
- OPTIONAL operation.&argumentTypeOptional
- RESULT operation.&ResultType
- OPTIONAL operation.&resultTypeOptional
- RETURN RESULT operation.&returnResult
- ERRORS {operation.&Errors}
- LINKED {operation.&Linked}
- SYNCHRONOUS operation.&synchronous
- ALWAYS RESPONDS operation.&alwaysReturns
- INVOKE PRIORITY {operation.&InvokePriority}
- RESULT-PRIORITY {operation.&ResultPriority}
- CODE code
- }
-
-switch {OPERATION-PACKAGE:package, OBJECT IDENTIFIER:id} OPERATION-PACKAGE ::=
-{
- OPERATIONS {package.&Both}
- CONSUMER INVOKES {package.&Consumer}
- SUPPLIER INVOKES {package.&Supplier}
- ID id
- }
-
-combine {OPERATION-PACKAGE:ConsumerConsumes,OPERATION-PACKAGE:ConsumerSupplies,
- OPERATION-PACKAGE:base
- } OPERATION-PACKAGE ::=
-{
- OPERATIONS {ConsumerConsumes.&Both | ConsumerSupplies.&Both}
- CONSUMER INVOKES {ConsumerConsumes.&Consumer | ConsumerSupplies.&Supplier}
- SUPPLIER INVOKES {ConsumerConsumes.&Supplier | ConsumerSupplies.&Consumer}
- ID base.&id
- }
-
-ROS-SingleAS {InvokeId:InvokeIdSet, OPERATION-PACKAGE:package} ::= ROS
-{{InvokeIdSet}, {AllOperations{package}}, {AllOperations{package}}}
-
-ROS-ConsumerAS {InvokeId:InvokeIdSet, OPERATION-PACKAGE:package} ::= ROS
-{{InvokeIdSet}, {ConsumerPerforms{package}}, {SupplierPerforms{package}}}
-
-ROS-SupplierAS {InvokeId:InvokeIdSet, OPERATION-PACKAGE:package} ::= ROS
-{{InvokeIdSet}, {SupplierPerforms{package}}, {ConsumerPerforms{package}}}
-
-probe OPERATION ::=
- {
- ARGUMENT SEQUENCE
- {
- invokeId [0] InvokeId
- }
- RESULT ENUMERATED{running(0), finished(1), unknown(2), ...}
- IDEMPOTENT TRUE
- CODE local:-2
- }
-
-acknowledge OPERATION ::=
- {
- ARGUMENT InvokeId
- RESULT ENUMERATED{acknowledged(0), unknown(1), ...}
- IDEMPOTENT TRUE
- CODE local:-3
- }
-
-ProbeAndAcknowledge OPERATION ::= {probe | acknowledge}
-
-cancel OPERATION ::=
- {
- ARGUMENT InvokeId
- ERRORS {cancelFailed}
- IDEMPOTENT TRUE
- CODE local:-4
- }
-
-cancelFailed ERROR ::=
- {
- PARAMETER SET
- {
- problem [0] CancelProblem,
- operation [1] InvokeId
- }
- CODE local:-2
- }
-
-CancelProblem ::= ENUMERATED
-{unknownOperation(0), tooLate(1), operationNotCancellable(2), ...}
-
-cancelled ERROR ::= {CODE local:-3}
-
-END -- end of useful definitions.
diff --git a/lib/asn1/test/asn1_SUITE_data/SeqDefault.asn1 b/lib/asn1/test/asn1_SUITE_data/SeqDefault.asn1
index 99e79da972..5c8583884a 100644
--- a/lib/asn1/test/asn1_SUITE_data/SeqDefault.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/SeqDefault.asn1
@@ -74,4 +74,15 @@ SeqIn ::= SEQUENCE
intIn INTEGER DEFAULT 12
}
+SeqExp ::= SEQUENCE
+{
+ bool BOOLEAN,
+ ...,
+ int INTEGER
+}
+
+SeqDef4 ::= SEQUENCE {
+ seq SeqExp DEFAULT { bool TRUE, int 42 }
+}
+
END
diff --git a/lib/asn1/test/asn1_SUITE_data/SeqOf.asn1 b/lib/asn1/test/asn1_SUITE_data/SeqOf.asn1
index 330944cf5c..888dbe5dd7 100644
--- a/lib/asn1/test/asn1_SUITE_data/SeqOf.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/SeqOf.asn1
@@ -62,4 +62,13 @@ Empty ::= SEQUENCE
{
}
+SeqExt ::= SEQUENCE
+{
+ b1 BOOLEAN,
+ s1 SEQUENCE SIZE (1..3, ...) OF SeqIn,
+ b2 BOOLEAN,
+ s2 SEQUENCE SIZE (0..1024, ...) OF SeqIn,
+ magic INTEGER
+}
+
END
diff --git a/lib/asn1/test/asn1_SUITE_data/SetDefault.asn1 b/lib/asn1/test/asn1_SUITE_data/SetDefault.asn1
index cb9e0ead62..0bbe301ae7 100644
--- a/lib/asn1/test/asn1_SUITE_data/SetDefault.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/SetDefault.asn1
@@ -30,4 +30,15 @@ SetIn ::= SET
intIn INTEGER DEFAULT 12
}
+SetDef4 ::= SET {
+ set SetExt DEFAULT { intIn 42, boolIn TRUE }
+}
+
+SetExt ::= SET
+{
+ boolIn BOOLEAN,
+ ...,
+ intIn INTEGER
+}
+
END
diff --git a/lib/asn1/test/asn1_SUITE_data/TConstr.asn1 b/lib/asn1/test/asn1_SUITE_data/TConstr.asn1
index 63f5dbde77..e2e0a11dc4 100644
--- a/lib/asn1/test/asn1_SUITE_data/TConstr.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/TConstr.asn1
@@ -51,6 +51,12 @@ Seq2 ::= SEQUENCE {
}
}
+Deeper ::= SEQUENCE {
+ a SEQUENCE {aa INTEGER,
+ s SEQUENCE { ab MYCLASS.&id ({ObjectSet}),
+ ac INTEGER }},
+ b SEQUENCE {ba INTEGER, bb MYCLASS.&Type ({ObjectSet}{@a.s.ab})}
+}
-- following from Peter's definitions
diff --git a/lib/asn1/test/asn1_SUITE_data/Tst.py b/lib/asn1/test/asn1_SUITE_data/Tst.py
deleted file mode 100644
index d80b32dad5..0000000000
--- a/lib/asn1/test/asn1_SUITE_data/Tst.py
+++ /dev/null
@@ -1,153 +0,0 @@
-Tst { 2 6 6 24 7 1 } DEFINITIONS IMPLICIT TAGS ::=
-
-BEGIN
-
---EXPORTS SomeSet , Id0 , Aset,Id1 ,A,B,C,
--- Uhh ,Foo ,Cho,Person,Hobbe,Robbe,X,Y;
-
-IMPORTS Fooo FROM Bobby;
-
-
-Robbe ::= SET {
- ttt TT }
-
-Koo ::= SET {
- c CHOICE {
- a INTEGER,
- b BOOLEAN },
- s SET OF Id0 }
-
-
-Hobbe ::= [APPLICATION 1] SET {
- aaa [0] SET OF INTEGER,
- bbb [1] UU
- }
-
-UU ::= PP
-PP ::= CHOICE {
- cc [1] CHOICE {
- a [0] INTEGER,
- b [1] BOOLEAN,
- c [2] BIT STRING },
- ii [0] Id0
- }
-
-
-TT ::= SS
-SS ::= SET {
- b BOOLEAN DEFAULT TRUE
- }
-
-Aset ::= [PRIVATE 2] SET OF Uhh
-
-
-
-SomeSet ::= [PRIVATE 3] IMPLICIT SET {
- aaaa [2] SET{
- ggg [0] INTEGER},
- kkkk [1] SET OF Id2,
- booby [4] OCTET STRING,
- puck [3] INTEGER {red(0),blue(1),yellow(-2)},
- baby [5] IMPLICIT Id1,
- bool [6] BOOLEAN }
-
-
-Id0 ::= INTEGER (4 .. 99)
-
-Id1 ::= Id0
-
-Id2 ::= [PRIVATE 4] EXPLICIT Id1
-
-
-Uhh ::= SET {
- a [1] IMPLICIT Id1}
-
-
-
-Soon ::= [PRIVATE 5] Moon
-
-Moon ::= [PRIVATE 6] IMPLICIT Person
-
-
-Person ::= [PRIVATE 7] IMPLICIT SEQUENCE {
- szzzs SET OF SET {
- aaa [0] INTEGER,
- bbb [1] Id0},
- cho Cho,
- name OCTET STRING ,
- location INTEGER,
- asss Aset,
- oops [2] IMPLICIT SET {
- q [0] INTEGER,
- p [1] Uhh},
- on INTEGER,
- mybits [3] IMPLICIT BIT STRING,
- foo Foo,
- age INTEGER,
- hobbe [5] SEQUENCE {
- a [4] CHOICE {
- a INTEGER,
- b BOOLEAN },
- b [5] Id0}}
-
-
-
-
-
-Foo ::= [PRIVATE 8] IMPLICIT SEQUENCE {
- goofy [3] INTEGER OPTIONAL,
- somestring [10] IMPLICIT OCTET STRING DEFAULT '77BB'H,
- hoohoo [11] IMPLICIT SEQUENCE {
- bar [1] Id1 OPTIONAL,
- foo INTEGER,
- zombie [9] CHOICE {
- a [1] IMPLICIT INTEGER,
- b [2] IMPLICIT BOOLEAN }
- },
- moon [4] IMPLICIT INTEGER }
-
-
-
-Cho ::= [PRIVATE 9] EXPLICIT CHOICE {
- somestring [2] IMPLICIT OCTET STRING,
- goofy [9] INTEGER,
- moon [4] IMPLICIT INTEGER }
-
-
-A ::= [APPLICATION 2] SET {
- ppp IA5String ,
- a [0] INTEGER {aaa(6),bbb(77)} DEFAULT 998,
- b [1] Id1 OPTIONAL,
- c [2] OCTET STRING (SIZE(8)),
- dd [3] BIT STRING DEFAULT '11001'B }
-
-B ::= [APPLICATION 3] SET {
- ww [1] SET {
- a A OPTIONAL,
- goofy [3] INTEGER OPTIONAL,
- somestring [10] IMPLICIT OCTET STRING DEFAULT '77BB'H }
- }
-
-
-C::= [APPLICATION 4] SEQUENCE OF X
-
-Y ::= OBJECT IDENTIFIER
-
-X ::= SET {
- a NULL,
- b GeneralString,
- c UTCTime,
- d VideotexString,
- g GeneralizedTime,
- h GraphicString,
- i VisibleString,
- j IA5String,
- k PrintableString,
- l OCTET STRING,
- e TeletexString,
- m ANY,
- n ObjectDescriptor,
- o OBJECT IDENTIFIER,
- f NumericString }
-
-END
diff --git a/lib/asn1/test/asn1_SUITE_data/Two.py b/lib/asn1/test/asn1_SUITE_data/Two.py
deleted file mode 100644
index c8e6f1a55b..0000000000
--- a/lib/asn1/test/asn1_SUITE_data/Two.py
+++ /dev/null
@@ -1,34 +0,0 @@
-Two { 1 2 3} DEFINITIONS EXPLICIT TAGS ::=
-
-BEGIN
-EXPORTS A, D,Boo,Szz;
-
-
-
-D ::= [PRIVATE 1] SEQUENCE {
- a INTEGER,
- b Boo,
- c ANY DEFINED BY a ,
- d ANY }
-
-
-Boo ::= SEQUENCE OF INTEGER (198..200)
-
-A ::= [PRIVATE 2] SEQUENCE {
- a INTEGER (1..1),
- b INTEGER (3..3) }
-
-
-Szz ::= CHOICE {
- one INTEGER,
- two BOOLEAN }
-
-C ::= SET {
- a [0] INTEGER (0..8),
- xx [4] CHOICE {
- [7] INTEGER (9..10),
- a INTEGER (11 ..13) },
- f Boo,
- r [2] INTEGER (20..22)}
-END
-
diff --git a/lib/asn1/test/asn1_SUITE_data/UPERDefault.asn b/lib/asn1/test/asn1_SUITE_data/UPERDefault.asn
deleted file mode 100644
index 7b81a0e09f..0000000000
--- a/lib/asn1/test/asn1_SUITE_data/UPERDefault.asn
+++ /dev/null
@@ -1,18 +0,0 @@
-UPERDefault DEFINITIONS AUTOMATIC TAGS ::=
-
-BEGIN
-
--- OTP-7681
-Int ::= INTEGER (0..32767)
-
-Seq ::= SEQUENCE {
- a Int,
- b INTEGER (-27..27) DEFAULT 0, -- OTP-7678
- c INTEGER OPTIONAL
-}
-
-seq Seq ::=
-{a 12,
- b 0}
-
-END \ No newline at end of file
diff --git a/lib/asn1/test/asn1_SUITE_data/UndefType.py b/lib/asn1/test/asn1_SUITE_data/UndefType.py
deleted file mode 100644
index cdbe083803..0000000000
--- a/lib/asn1/test/asn1_SUITE_data/UndefType.py
+++ /dev/null
@@ -1,14 +0,0 @@
-Person DEFINITIONS IMPLICIT TAGS ::=
-BEGIN
-EXPORTS Person;
-IMPORTS
- ImportedFromUndefined FROM UndefinedModule;
-
-Feltyp ::= UndefinedType
-Feltyp2 ::= ImportedFromUndefined
-Person ::= [PRIVATE 19] SEQUENCE {
- name Undefined,
- location INTEGER {home(0),field(1),roving(2)},
- age ImportedFromUndefined OPTIONAL
- }
-END
diff --git a/lib/asn1/test/asn1_SUITE_data/extensionAdditionGroup.erl b/lib/asn1/test/asn1_SUITE_data/extensionAdditionGroup.erl
index d46560979d..00e4c707dd 100644
--- a/lib/asn1/test/asn1_SUITE_data/extensionAdditionGroup.erl
+++ b/lib/asn1/test/asn1_SUITE_data/extensionAdditionGroup.erl
@@ -1,9 +1,3 @@
-%%%-------------------------------------------------------------------
-%%% File : extensionAdditionGroup.erl
-%%% Author : Kenneth Lundin
-%%% Description :
-%%%
-%%% Created : 18 May 2010 by kenneth
%%
%% %CopyrightBegin%
%%
@@ -25,36 +19,38 @@
%%%-------------------------------------------------------------------
-module(extensionAdditionGroup).
-include("Extension-Addition-Group.hrl").
-
+-export([run/1]).
-compile(export_all).
run(Erule) ->
- Val = #'Ax'{a=253, b = true, c= {e,true}, g="123", h = true},
- io:format("~p:~p~n",[Erule,Val]),
- {ok,List}= asn1rt:encode('Extension-Addition-Group','Ax',Val),
- Enc = iolist_to_binary(List),
- io:format("~p~n",[Enc]),
- {ok,Val2} = asn1rt:decode('Extension-Addition-Group','Ax',Enc),
- io:format("~p~n",[Val2]),
- case Val2 of
- Val -> ok;
- _ -> exit({expected,Val, got, Val2})
- end.
+ Val = #'Ax'{a=253,b=true,c={e,true},g="123",h=true},
+ Enc = hex_to_binary(encoded_ax(Erule)),
+ roundtrip('Ax', Val, Enc),
-run2(Erule) ->
- Val = #'Ax3'{a=253, b = true, s = #'Ax3_s'{sa = 11, sb = true, sextaddgroup = 17}},
- io:format("~p:~p~n",[Erule,Val]),
- {ok,List}= asn1rt:encode('Extension-Addition-Group','Ax3',Val),
- Enc = iolist_to_binary(List),
- io:format("~p~n",[Enc]),
- {ok,Val2} = asn1rt:decode('Extension-Addition-Group','Ax3',Enc),
- io:format("~p~n",[Val2]),
- case Val2 of
- Val -> ok;
- _ -> exit({expected,Val, got, Val2})
- end.
+ Val2 = #'Ax3'{a=253,b=true,s=#'Ax3_s'{sa=11,sb=true,sextaddgroup=17}},
+ roundtrip('Ax3', Val2),
+
+ run3(),
+ run3(Erule),
+
+ ok.
+
+%% From X.691 (07/2002) A.4.
+encoded_ax(per) -> "9E000180 010291A4";
+encoded_ax(uper) -> "9E000600 040A4690";
+encoded_ax(ber) -> none.
+hex_to_binary(none) ->
+ none;
+hex_to_binary(L) ->
+ << <<(hex_digit_to_binary(D)):4>> || D <- L, D =/= $\s >>.
+
+hex_digit_to_binary(D) ->
+ if
+ $0 =< D, D =< $9 -> D - $0;
+ $A =< D, D =< $F -> D - ($A-10)
+ end.
run3(Erule) ->
Val =
{'RRC-DL-DCCH-Message',
@@ -141,15 +137,23 @@ run3() ->
'ac-BarringFactor' = p00,
'ac-BarringTime' = s4,
'ac-BarringForSpecialAC' = <<0:5>>},
- roundtrip(SI),
- roundtrip(SI#'SystemInformationBlockType2'{
- 'ssac-BarringForMMTEL-Voice-r9'=Barring}),
- roundtrip(SI#'SystemInformationBlockType2'{
+ T = 'SystemInformationBlockType2',
+ roundtrip(T, SI),
+ roundtrip(T, SI#'SystemInformationBlockType2'{
+ 'ssac-BarringForMMTEL-Voice-r9'=Barring}),
+ roundtrip(T, SI#'SystemInformationBlockType2'{
'ssac-BarringForMMTEL-Video-r9'=Barring}),
- roundtrip(SI#'SystemInformationBlockType2'{
- 'ac-BarringForCSFB-r10'=Barring}).
+ roundtrip(T, SI#'SystemInformationBlockType2'{
+ 'ac-BarringForCSFB-r10'=Barring}).
-roundtrip(V) ->
+roundtrip(T, V) ->
+ roundtrip(T, V, none).
+
+roundtrip(T, V, Expected) ->
Mod = 'Extension-Addition-Group',
- {ok,E} = Mod:encode('SystemInformationBlockType2', V),
- {ok,V} = Mod:decode('SystemInformationBlockType2', iolist_to_binary(E)).
+ {ok,E} = Mod:encode(T, V),
+ {ok,V} = Mod:decode(T, E),
+ case Expected of
+ none -> ok;
+ E -> ok
+ end.
diff --git a/lib/asn1/test/asn1_test_lib.erl b/lib/asn1/test/asn1_test_lib.erl
index 1e40fd7b9e..b839dfcf2a 100644
--- a/lib/asn1/test/asn1_test_lib.erl
+++ b/lib/asn1/test/asn1_test_lib.erl
@@ -39,17 +39,18 @@ compile_all(Files, Config, Options) ->
compile_file(File, Options) ->
try
- ok = asn1ct:compile(File, Options),
+ ok = asn1ct:compile(File, [warnings_as_errors|Options]),
case should_load(File, Options) of
false ->
ok;
{module, Module} ->
code:purge(Module),
- true = code:soft_purge(Module),
- {module, Module} = code:load_file(Module)
+ {module, Module} = code:load_file(Module),
+ code:purge(Module)
end
catch
Class:Reason ->
+ ct:print("Failed to compile ~s\n", [File]),
erlang:error({compile_failed, {File, Options}, {Class, Reason}})
end.
@@ -58,7 +59,7 @@ compile_erlang(Mod, Config, Options) ->
CaseDir = ?config(case_dir, Config),
M = list_to_atom(Mod),
{ok, M} = compile:file(filename:join(DataDir, Mod),
- [{i, CaseDir}, {outdir, CaseDir}|Options]).
+ [report,{i,CaseDir},{outdir,CaseDir}|Options]).
should_load(File, Options) ->
case lists:member(abs, Options) of
diff --git a/lib/asn1/test/error_SUITE.erl b/lib/asn1/test/error_SUITE.erl
new file mode 100644
index 0000000000..a94a6d95a0
--- /dev/null
+++ b/lib/asn1/test/error_SUITE.erl
@@ -0,0 +1,104 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(error_SUITE).
+-export([suite/0,all/0,groups/0,
+ already_defined/1,enumerated/1]).
+
+-include_lib("test_server/include/test_server.hrl").
+
+suite() -> [{ct_hooks, [ts_install_cth]}].
+
+all() ->
+ [{group,p}].
+
+groups() ->
+ [{p,parallel(),[already_defined,
+ enumerated]}].
+
+parallel() ->
+ case erlang:system_info(schedulers) > 1 of
+ true -> [parallel];
+ false -> []
+ end.
+
+already_defined(Config) ->
+ M = 'Already',
+ P = {M,
+ <<"Already DEFINITIONS ::= BEGIN\n"
+ " I ::= INTEGER\n"
+ " i I ::= 42\n"
+ " I ::= OCTET STRING\n"
+ " I ::= CLASS { &Type }\n"
+ " MYCLASS ::= CLASS { &Type }\n"
+ " i MYCLASS ::= { &Type INTEGER }\n"
+ " o MYCLASS ::= { &Type INTEGER }\n"
+ " I MYCLASS ::= { o }\n"
+ " I{T} ::= SEQUENCE OF T\n"
+ " I{INTEGER:x} INTEGER ::= { 1 | 2 | x }\n"
+ " i{T} MYCLASS ::= { &Type T }\n"
+ "END\n">>},
+ {error,
+ [
+ {structured_error,{M,4},asn1ct_check,{already_defined,'I',2}},
+ {structured_error,{M,5},asn1ct_check,{already_defined,'I',2}},
+ {structured_error,{M,7},asn1ct_check,{already_defined,'i',3}},
+ {structured_error,{M,9},asn1ct_check,{already_defined,'I',2}},
+ {structured_error,{M,10},asn1ct_check,{already_defined,'I',2}},
+ {structured_error,{M,11},asn1ct_check,{already_defined,'I',2}},
+ {structured_error,{M,12},asn1ct_check,{already_defined,'i',3}}
+ ]
+ } = run(P, Config),
+ ok.
+
+enumerated(Config) ->
+ M = 'Enumerated',
+ P = {M,
+ <<"Enumerated DEFINITIONS AUTOMATIC TAGS ::= BEGIN\n"
+ " Enum ::= ENUMERATED { a, b, c }\n"
+ " e Enum ::= d\n"
+ " EnumExt ::= ENUMERATED { x, ..., y }\n"
+ " ext EnumExt ::= z\n"
+ " S1 ::= SEQUENCE {\n"
+ " ge1 Enum DEFAULT a,\n"
+ " ge2 EnumExt DEFAULT x,\n"
+ " ge3 EnumExt DEFAULT y,\n"
+ " e Enum DEFAULT aa\n"
+ " }\n"
+ " S2 ::= SEQUENCE {\n"
+ " e2 EnumExt DEFAULT xyz\n"
+ " }\n"
+ "END\n">>},
+ {error,
+ [
+ {structured_error,{'Enumerated',3},asn1ct_check,{undefined,d}},
+ {structured_error,{'Enumerated',5},asn1ct_check,{undefined,z}},
+ {structured_error,{'Enumerated',10},asn1ct_check,{undefined,aa}},
+ {structured_error,{'Enumerated',13},asn1ct_check,{undefined,xyz}}
+ ]
+ } = run(P, Config),
+ ok.
+
+
+
+run({Mod,Spec}, Config) ->
+ Base = atom_to_list(Mod) ++ ".asn1",
+ File = filename:join(?config(priv_dir, Config), Base),
+ ok = file:write_file(File, Spec),
+ asn1ct:compile(File).
diff --git a/lib/asn1/test/testChoExtension.erl b/lib/asn1/test/testChoExtension.erl
index 067d4d2bf7..5c67ff62ce 100644
--- a/lib/asn1/test/testChoExtension.erl
+++ b/lib/asn1/test/testChoExtension.erl
@@ -42,6 +42,11 @@ extension(_Rules) ->
roundtrip('ChoExt3', {int,33}),
roundtrip('ChoExt4', {str,"abc"}),
+ roundtrip('ChoEmptyRoot', {bool,false}),
+ roundtrip('ChoEmptyRoot', {bool,true}),
+ roundtrip('ChoEmptyRoot', {int,0}),
+ roundtrip('ChoEmptyRoot', {int,7}),
+
ok.
diff --git a/lib/asn1/test/testCompactBitString.erl b/lib/asn1/test/testCompactBitString.erl
index 96d9f0fdcb..28ab2464e9 100644
--- a/lib/asn1/test/testCompactBitString.erl
+++ b/lib/asn1/test/testCompactBitString.erl
@@ -150,4 +150,6 @@ roundtrip(Type, Val1, Val2) ->
roundtrip_1(Mod, Type, In, Out) ->
{ok,Encoded} = Mod:encode(Type, In),
{ok,Out} = Mod:decode(Type, Encoded),
+ %% Test that compact BIT STRINGs can be encoded.
+ {ok,Encoded} = Mod:encode(Type, Out),
ok.
diff --git a/lib/asn1/test/testConstraints.erl b/lib/asn1/test/testConstraints.erl
index c8d9008641..e825302629 100644
--- a/lib/asn1/test/testConstraints.erl
+++ b/lib/asn1/test/testConstraints.erl
@@ -122,13 +122,61 @@ int_constraints(Rules) ->
range_error(Rules, 'X1', 21),
%%==========================================================
+ %% SemiConstrained
+ %%==========================================================
+
+ roundtrip('SemiConstrained', 100),
+ roundtrip('SemiConstrained', 397249742397243),
+ roundtrip('NegSemiConstrained', -128),
+ roundtrip('NegSemiConstrained', -1),
+ roundtrip('NegSemiConstrained', 500),
+
+ roundtrip('SemiConstrainedExt', -65536),
+ roundtrip('SemiConstrainedExt', 0),
+ roundtrip('SemiConstrainedExt', 42),
+ roundtrip('SemiConstrainedExt', 100),
+ roundtrip('SemiConstrainedExt', 47777789),
+ roundtrip('NegSemiConstrainedExt', -1023),
+ roundtrip('NegSemiConstrainedExt', -128),
+ roundtrip('NegSemiConstrainedExt', -1),
+ roundtrip('NegSemiConstrainedExt', 500),
+
+ %%==========================================================
%% SIZE Constraint (Duboisson p. 268)
%% T ::= IA5String (SIZE (1|2, ..., SIZE (1|2|3)))
%% T2 ::= IA5String (SIZE (1|2, ..., 3))
%%==========================================================
roundtrip('T', "IA"),
- roundtrip('T2', "IA").
+ roundtrip('T', "IAB"),
+ roundtrip('T', "IABC"),
+ roundtrip('T2', "IA"),
+ roundtrip('T2', "IAB"),
+ roundtrip('T2', "IABC"),
+
+ %%==========================================================
+ %% More SIZE Constraints
+ %%==========================================================
+
+ roundtrip('FixedSize', "0123456789"),
+ roundtrip('FixedSize2', "0123456789"),
+ roundtrip('FixedSize2', "0123456789abcdefghij"),
+
+ range_error(Rules, 'FixedSize', "short"),
+ range_error(Rules, 'FixedSize2', "short"),
+
+ [roundtrip('VariableSize', lists:seq($A, $A+L-1)) ||
+ L <- lists:seq(1, 10)],
+
+ roundtrip_enc('ShorterExt', "a", shorter_ext(Rules, "a")),
+ roundtrip('ShorterExt', "abcde"),
+ roundtrip('ShorterExt', "abcdef"),
+
+ ok.
+
+shorter_ext(per, "a") -> <<16#80,16#01,16#61>>;
+shorter_ext(uper, "a") -> <<16#80,16#E1>>;
+shorter_ext(ber, _) -> none.
refed_NNL_name(_Erule) ->
?line {ok,_} = asn1_wrapper:encode('Constraints','AnotherThing',fred),
@@ -143,11 +191,20 @@ roundtrip(Module, Type, Value) ->
{ok,Value} = Module:decode(Type, Encoded),
ok.
+roundtrip_enc(Type, Value, Enc) ->
+ Module = 'Constraints',
+ {ok,Encoded} = Module:encode(Type, Value),
+ {ok,Value} = Module:decode(Type, Encoded),
+ case Enc of
+ none -> ok;
+ Encoded -> ok
+ end.
+
range_error(ber, Type, Value) ->
%% BER: Values outside the effective range should be rejected
%% on decode.
{ok,Encoded} = 'Constraints':encode(Type, Value),
- {error,{asn1,{integer_range,_,_}}} = 'Constraints':decode(Type, Encoded),
+ {error,{asn1,_}} = 'Constraints':decode(Type, Encoded),
ok;
range_error(Per, Type, Value) when Per =:= per; Per =:= uper ->
%% (U)PER: Values outside the effective range should be rejected
diff --git a/lib/asn1/test/testDeepTConstr.erl b/lib/asn1/test/testDeepTConstr.erl
index 3df7bcbaa0..e826cafa0c 100644
--- a/lib/asn1/test/testDeepTConstr.erl
+++ b/lib/asn1/test/testDeepTConstr.erl
@@ -40,53 +40,40 @@ main(_Erule) ->
{any,"DK"},
{final,"NO"}]}},
- ?line {ok,Bytes1} =
- asn1_wrapper:encode('TConstrChoice','FilterItem',Val1),
-
- ?line {error,Reason} = asn1_wrapper:decode('TConstrChoice','FilterItem',Bytes1),
-
+ {ok,Bytes1} = 'TConstrChoice':encode('FilterItem', Val1),
+ {error,Reason} = asn1_wrapper:decode('TConstrChoice','FilterItem',Bytes1),
io:format("Reason: ~p~n~n",[Reason]),
-
- ?line {ok,Bytes2} =
- asn1_wrapper:encode('TConstrChoice','FilterItem',Val2),
-
- ?line {ok,Res} = asn1_wrapper:decode('TConstrChoice','FilterItem',Bytes2),
-
-
+ {ok,Bytes2} = 'TConstrChoice':encode('FilterItem', Val2),
+ {ok,Res} = 'TConstrChoice':decode('FilterItem', Bytes2),
%% test of OTP-4248.
- ?line {ok,Bytes3} =
- asn1_wrapper:encode('TConstrChoice','Seq',{'Seq',3,Bytes2}),
-
- ?line {ok,{'Seq',3,Bytes4}} =
- asn1_wrapper:decode('TConstrChoice','Seq',Bytes3),
-
- ?line {ok,Res} = asn1_wrapper:decode('TConstrChoice','FilterItem',Bytes4),
+ {ok,Bytes3} = 'TConstrChoice':encode('Seq', {'Seq',3,Bytes2}),
+ {ok,{'Seq',3,Bytes4}} = 'TConstrChoice':decode('Seq', Bytes3),
+ {ok,Res} = 'TConstrChoice':decode('FilterItem', Bytes4),
%% test of TConstr
- Seq1Val = {'Seq1',{'Seq1_a',12,{2,4}},{'Seq1_b',13,{'Type-object1',14,true}}},
- ?line {ok,Bytes5} =
- asn1_wrapper:encode('TConstr','Seq1',Seq1Val),
-
- ?line {ok,Seq1Val} =
- asn1_wrapper:decode('TConstr','Seq1',Bytes5),
+ Seq1Val = {'Seq1',{'Seq1_a',12,{2,4}},
+ {'Seq1_b',13,{'Type-object1',14,true}}},
+ roundtrip('TConstr', 'Seq1', Seq1Val),
Seq2Val = {'Seq2',123,{'Seq2_content',{2,6,7},
{first,{'Type-object3_first',false,47}},
false}},
-
- ?line {ok,Bytes6} =
- asn1_wrapper:encode('TConstr','Seq2',Seq2Val),
+ roundtrip('TConstr', 'Seq2', Seq2Val),
- ?line {ok,Seq2Val} =
- asn1_wrapper:decode('TConstr','Seq2',Bytes6),
+ roundtrip('TConstr', 'Info', {'Info',{'Info_xyz',{1,2}},1234}),
+
+ roundtrip('TConstr', 'Deeper',
+ {'Deeper',
+ {'Deeper_a',12,
+ {'Deeper_a_s',{2,4},42}},
+ {'Deeper_b',13,{'Type-object1',14,true}}}),
+ ok.
- InfoVal = {'Info',{'Info_xyz',{1,2}},1234},
-
- ?line {ok,Bytes7} =
- asn1_wrapper:encode('TConstr','Info',InfoVal),
- ?line {ok,InfoVal} =
- asn1_wrapper:decode('TConstr','Info',Bytes7).
+roundtrip(M, T, V) ->
+ {ok,E} = M:encode(T, V),
+ {ok,V} = M:decode(T, E),
+ ok.
diff --git a/lib/asn1/test/testEnumExt.erl b/lib/asn1/test/testEnumExt.erl
index 0811f20571..8840ed6d2f 100644
--- a/lib/asn1/test/testEnumExt.erl
+++ b/lib/asn1/test/testEnumExt.erl
@@ -38,8 +38,7 @@ main(Rule) when Rule =:= per; Rule =:= uper ->
%% ENUMERATED no extensionmark
B64 = <<64>>,
B64 = roundtrip('Noext', red),
- ok;
-
+ common();
main(ber) ->
io:format("main(ber)~n",[]),
%% ENUMERATED with extensionmark (value is in root set)
@@ -57,6 +56,15 @@ main(ber) ->
roundtrip('Globalstate', preop),
roundtrip('Globalstate', com),
+ common().
+
+common() ->
+ roundtrip('Seq', {'Seq',blue,42}),
+ roundtrip('Seq', {'Seq',red,42}),
+ roundtrip('Seq', {'Seq',green,42}),
+ roundtrip('Seq', {'Seq',orange,47}),
+ roundtrip('Seq', {'Seq',black,4711}),
+ roundtrip('Seq', {'Seq',magenta,4712}),
ok.
roundtrip(Type, Value) ->
diff --git a/lib/asn1/test/testInfObj.erl b/lib/asn1/test/testInfObj.erl
index 03e70c730a..75f4dae310 100644
--- a/lib/asn1/test/testInfObj.erl
+++ b/lib/asn1/test/testInfObj.erl
@@ -22,8 +22,6 @@
-export([main/1]).
--include_lib("test_server/include/test_server.hrl").
-
-record('InitiatingMessage',{procedureCode,criticality,value}).
-record('InitiatingMessage2',{procedureCode,criticality,value}).
-record('Iu-ReleaseCommand',{first,second}).
@@ -34,22 +32,11 @@ main(_Erule) ->
value=#'Iu-ReleaseCommand'{
first=13,
second=true}},
- ?line {ok,Bytes1} =
- asn1_wrapper:encode('RANAPextract1','InitiatingMessage',Val1),
-
- ?line {ok,{'InitiatingMessage',1,ignore,{'Iu-ReleaseCommand',13,true}}}=
- asn1_wrapper:decode('RANAPextract1','InitiatingMessage',Bytes1),
-
- ?line {ok,Bytes2} =
- asn1_wrapper:encode('InfObj','InitiatingMessage',Val1),
-
- ?line {ok,Val1} =
- asn1_wrapper:decode('InfObj','InitiatingMessage',Bytes2),
+ roundtrip('RANAPextract1', 'InitiatingMessage', Val1),
+ roundtrip('InfObj', 'InitiatingMessage', Val1),
Val2 = Val1#'InitiatingMessage'{procedureCode=2},
-
- ?line {error,_R1} =
- asn1_wrapper:encode('InfObj','InitiatingMessage',Val2),
+ {error,_R1} = 'InfObj':encode('InitiatingMessage', Val2),
%% Test case for OTP-4275
@@ -59,10 +46,26 @@ main(_Erule) ->
first=13,
second=true}},
- ?line {ok,Bytes3} =
- asn1_wrapper:encode('RANAPextract1','InitiatingMessage2',Val3),
+ roundtrip('RANAPextract1', 'InitiatingMessage2', Val3),
-
- ?line {ok,{'InitiatingMessage2',3,reject,{'Iu-ReleaseCommand',13,true}}}=
- asn1_wrapper:decode('RANAPextract1','InitiatingMessage2',Bytes3).
-
+ roundtrip('InfObj', 'MyPdu', {'MyPdu',42,12,false,"string"}),
+ roundtrip('InfObj', 'MyPdu', {'MyPdu',{'Seq',1023,"hello"},
+ 42,true,"longer string"}),
+ roundtrip('InfObj', 'MyPdu', {'MyPdu',"75712346",43,true,"string"}),
+
+ roundtrip('InfObj', 'ConstructedPdu',
+ {'ConstructedPdu',1,{'CONSTRUCTED-DEFAULT_Type',-2001,true}}),
+ roundtrip('InfObj', 'ConstructedPdu',
+ {'ConstructedPdu',2,{'CONSTRUCTED-DEFAULT_Type',999,false}}),
+ roundtrip('InfObj', 'ConstructedPdu',
+ {'ConstructedPdu',3,true}),
+
+ roundtrip('InfObj', 'Seq2',
+ {'Seq2',42,[true,false,false,true],
+ [false,true,false]}).
+
+
+roundtrip(M, T, V) ->
+ {ok,Enc} = M:encode(T, V),
+ {ok,V} = M:decode(T, Enc),
+ ok.
diff --git a/lib/asn1/test/testPrim.erl b/lib/asn1/test/testPrim.erl
index 91fb9fffca..990e7adcd9 100644
--- a/lib/asn1/test/testPrim.erl
+++ b/lib/asn1/test/testPrim.erl
@@ -30,465 +30,57 @@
-include_lib("test_server/include/test_server.hrl").
bool(Rules) ->
-
- %%==========================================================
- %% Bool ::= BOOLEAN
- %%==========================================================
-
- ?line {ok,Bytes1} = asn1_wrapper:encode('Prim','Bool',true),
- ?line {ok,true} = asn1_wrapper:decode('Prim','Bool',lists:flatten(Bytes1)),
-
- ?line {ok,Bytes2} = asn1_wrapper:encode('Prim','Bool',false),
- ?line {ok,false} = asn1_wrapper:decode('Prim','Bool',lists:flatten(Bytes2)),
-
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line {error,{asn1,{encode_boolean,517}}} =
- (catch asn1_wrapper:encode('Prim','Bool',517)),
- ok;
- per ->
- ok
- end,
-
-
-
-
-
- %%==========================================================
- %% BoolCon ::= [20] BOOLEAN
- %%==========================================================
-
-
- ?line {ok,BytesCon1} = asn1_wrapper:encode('Prim','BoolCon',true),
- ?line {ok,true} = asn1_wrapper:decode('Prim','BoolCon',lists:flatten(BytesCon1)),
-
- ?line {ok,BytesCon2} = asn1_wrapper:encode('Prim','BoolCon',false),
- ?line {ok,false} = asn1_wrapper:decode('Prim','BoolCon',lists:flatten(BytesCon2)),
-
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line {error,{asn1,{encode_boolean,517}}} =
- (catch asn1_wrapper:encode('Prim','BoolCon',517)),
- ok;
- per ->
- ok
- end,
-
-
-
-
-
- %%==========================================================
- %% BoolPri ::= [PRIVATE 21] BOOLEAN
- %%==========================================================
-
- ?line {ok,BytesPri1} = asn1_wrapper:encode('Prim','BoolPri',true),
- ?line {ok,true} = asn1_wrapper:decode('Prim','BoolPri',lists:flatten(BytesPri1)),
-
- ?line {ok,BytesPri2} = asn1_wrapper:encode('Prim','BoolPri',false),
- ?line {ok,false} = asn1_wrapper:decode('Prim','BoolPri',lists:flatten(BytesPri2)),
-
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line {error,{asn1,{encode_boolean,517}}} =
- (catch asn1_wrapper:encode('Prim','BoolPri',517)),
- ok;
- per ->
- ok
- end,
-
-
- %%==========================================================
- %% BoolApp ::= [APPLICATION 22] BOOLEAN
- %%==========================================================
-
- ?line {ok,BytesApp1} = asn1_wrapper:encode('Prim','BoolApp',true),
- ?line {ok,true} = asn1_wrapper:decode('Prim','BoolApp',lists:flatten(BytesApp1)),
-
- ?line {ok,BytesApp2} = asn1_wrapper:encode('Prim','BoolApp',false),
- ?line {ok,false} = asn1_wrapper:decode('Prim','BoolApp',lists:flatten(BytesApp2)),
-
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line {error,{asn1,{encode_boolean,517}}} =
- (catch asn1_wrapper:encode('Prim','BoolApp',517)),
- ok;
- per ->
- ok
- end,
-
-
- %%==========================================================
- %% BoolExpCon ::= [30] EXPLICIT BOOLEAN
- %%==========================================================
-
- ?line {ok,BytesExpCon1} = asn1_wrapper:encode('Prim','BoolExpCon',true),
- ?line {ok,true} = asn1_wrapper:decode('Prim','BoolExpCon',lists:flatten(BytesExpCon1)),
-
- ?line {ok,BytesExpCon2} = asn1_wrapper:encode('Prim','BoolExpCon',false),
- ?line {ok,false} = asn1_wrapper:decode('Prim','BoolExpCon',lists:flatten(BytesExpCon2)),
-
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line {error,{asn1,{encode_boolean,517}}} =
- (catch asn1_wrapper:encode('Prim','BoolExpCon',517)),
- ok;
- per ->
- ok
- end,
-
-
-
- %%==========================================================
- %% BoolExpPri ::= [PRIVATE 31] EXPLICIT BOOLEAN
- %%==========================================================
-
- ?line {ok,BytesExpPri1} = asn1_wrapper:encode('Prim','BoolExpPri',true),
- ?line {ok,true} = asn1_wrapper:decode('Prim','BoolExpPri',lists:flatten(BytesExpPri1)),
-
- ?line {ok,BytesExpPri2} = asn1_wrapper:encode('Prim','BoolExpPri',false),
- ?line {ok,false} = asn1_wrapper:decode('Prim','BoolExpPri',lists:flatten(BytesExpPri2)),
-
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line {error,{asn1,{encode_boolean,517}}} =
- (catch asn1_wrapper:encode('Prim','BoolExpPri',517)),
- ok;
- per ->
- ok
- end,
-
-
- %%==========================================================
- %% BoolExpApp ::= [APPLICATION 32] EXPLICIT BOOLEAN
- %%==========================================================
-
- ?line {ok,BytesExpApp1} = asn1_wrapper:encode('Prim','BoolExpApp',true),
- ?line {ok,true} = asn1_wrapper:decode('Prim','BoolExpApp',lists:flatten(BytesExpApp1)),
-
- ?line {ok,BytesExpApp2} = asn1_wrapper:encode('Prim','BoolExpApp',false),
- ?line {ok,false} = asn1_wrapper:decode('Prim','BoolExpApp',lists:flatten(BytesExpApp2)),
-
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line {error,{asn1,{encode_boolean,517}}} =
- (catch asn1_wrapper:encode('Prim','BoolExpApp',517)),
- ok;
- per ->
- ok
- end,
-
- ok.
+ Types = ['Bool','BoolCon','BoolPri','BoolApp',
+ 'BoolExpCon','BoolExpPri','BoolExpApp'],
+ [roundtrip(T, V) || T <- Types, V <- [true,false]],
+ case Rules of
+ ber ->
+ [begin
+ {error,{asn1,{encode_boolean,517}}} =
+ (catch 'Prim':encode(T, 517))
+ end || T <- Types],
+ ok;
+ _ ->
+ ok
+ end.
int(Rules) ->
-
-
- %%==========================================================
- %% Int ::= INTEGER
- %%==========================================================
-
- %% test of OTP-2666 encoding should use minimum number of octets x.690 8.3.2
- ?line {ok,Bytes0} = asn1_wrapper:encode('Prim','Int',-128),
- ?line L0 = lists:flatten(Bytes0),
- ?line {ok,-128} = asn1_wrapper:decode('Prim','Int',lists:flatten(L0)),
- case asn1_wrapper:erule(Rules) of
+ %% OTP-2666: encoding should use minimum number of octets; x.690 8.3.2
+ Bytes0 = roundtrip('Int', -128),
+ case Rules of
ber ->
- ?line [_,1,128] = L0;
- per -> ok
+ <<_,1,128>> = Bytes0;
+ _ ->
+ ok
end,
- ?line {ok,Bytes1} = asn1_wrapper:encode('Prim','Int',4),
- ?line {ok,4} = asn1_wrapper:decode('Prim','Int',lists:flatten(Bytes1)),
-
- ?line {ok,Bytes2} = asn1_wrapper:encode('Prim','Int',444),
- ?line {ok,444} = asn1_wrapper:decode('Prim','Int',lists:flatten(Bytes2)),
-
- ?line {ok,Bytes3} = asn1_wrapper:encode('Prim','Int',123456789),
- ?line {ok,123456789} = asn1_wrapper:decode('Prim','Int',lists:flatten(Bytes3)),
-
- ?line {ok,Bytes4} = asn1_wrapper:encode('Prim','Int',12345678901234567890),
- ?line {ok,12345678901234567890} = asn1_wrapper:decode('Prim','Int',lists:flatten(Bytes4)),
-
- ?line {ok,Bytes5} = asn1_wrapper:encode('Prim','Int',-100),
- ?line {ok,-100} = asn1_wrapper:decode('Prim','Int',lists:flatten(Bytes5)),
-
- ?line {ok,Bytes6} = asn1_wrapper:encode('Prim','Int',-255),
- ?line {ok,-255} = asn1_wrapper:decode('Prim','Int',lists:flatten(Bytes6)),
-
- ?line {ok,Bytes7} = asn1_wrapper:encode('Prim','Int',-256),
- ?line {ok,-256} = asn1_wrapper:decode('Prim','Int',lists:flatten(Bytes7)),
-
- ?line {ok,Bytes8} = asn1_wrapper:encode('Prim','Int',-257),
- ?line {ok,-257} = asn1_wrapper:decode('Prim','Int',lists:flatten(Bytes8)),
-
- ?line {ok,Bytes9} = asn1_wrapper:encode('Prim','Int',-1234567890),
- ?line {ok,-1234567890} = asn1_wrapper:decode('Prim','Int',lists:flatten(Bytes9)),
-
- ?line {ok,Bytes10} = asn1_wrapper:encode('Prim','Int',-2147483648),
- ?line {ok,-2147483648} = asn1_wrapper:decode('Prim','Int',lists:flatten(Bytes10)),
-
-
-
-
-
- %%==========================================================
- %% IntCon ::= [40] INTEGER
- %%==========================================================
-
- ?line {ok,BytesCon1} = asn1_wrapper:encode('Prim','IntCon',4),
- ?line {ok,4} = asn1_wrapper:decode('Prim','IntCon',lists:flatten(BytesCon1)),
-
- ?line {ok,BytesCon2} = asn1_wrapper:encode('Prim','IntCon',444),
- ?line {ok,444} = asn1_wrapper:decode('Prim','IntCon',lists:flatten(BytesCon2)),
-
- ?line {ok,BytesCon3} = asn1_wrapper:encode('Prim','IntCon',123456789),
- ?line {ok,123456789} = asn1_wrapper:decode('Prim','IntCon',lists:flatten(BytesCon3)),
-
- ?line {ok,BytesCon4} = asn1_wrapper:encode('Prim','IntCon',12345678901234567890),
- ?line {ok,12345678901234567890} = asn1_wrapper:decode('Prim','IntCon',lists:flatten(BytesCon4)),
-
- ?line {ok,BytesCon5} = asn1_wrapper:encode('Prim','IntCon',-100),
- ?line {ok,-100} = asn1_wrapper:decode('Prim','IntCon',lists:flatten(BytesCon5)),
-
- ?line {ok,BytesCon6} = asn1_wrapper:encode('Prim','IntCon',-255),
- ?line {ok,-255} = asn1_wrapper:decode('Prim','IntCon',lists:flatten(BytesCon6)),
-
- ?line {ok,BytesCon7} = asn1_wrapper:encode('Prim','IntCon',-256),
- ?line {ok,-256} = asn1_wrapper:decode('Prim','IntCon',lists:flatten(BytesCon7)),
-
- ?line {ok,BytesCon8} = asn1_wrapper:encode('Prim','IntCon',-257),
- ?line {ok,-257} = asn1_wrapper:decode('Prim','IntCon',lists:flatten(BytesCon8)),
-
- ?line {ok,BytesCon9} = asn1_wrapper:encode('Prim','IntCon',-1234567890),
- ?line {ok,-1234567890} = asn1_wrapper:decode('Prim','IntCon',lists:flatten(BytesCon9)),
-
- ?line {ok,BytesCon10} = asn1_wrapper:encode('Prim','Int',-2147483648),
- ?line {ok,-2147483648} = asn1_wrapper:decode('Prim','Int',lists:flatten(BytesCon10)),
-
-
-
- %%==========================================================
- %% IntPri ::= [PRIVATE 41] INTEGER
- %%==========================================================
-
- ?line {ok,BytesPri1} = asn1_wrapper:encode('Prim','IntPri',4),
- ?line {ok,4} = asn1_wrapper:decode('Prim','IntPri',lists:flatten(BytesPri1)),
-
- ?line {ok,BytesPri2} = asn1_wrapper:encode('Prim','IntPri',444),
- ?line {ok,444} = asn1_wrapper:decode('Prim','IntPri',lists:flatten(BytesPri2)),
-
- ?line {ok,BytesPri3} = asn1_wrapper:encode('Prim','IntPri',123456789),
- ?line {ok,123456789} = asn1_wrapper:decode('Prim','IntPri',lists:flatten(BytesPri3)),
-
- ?line {ok,BytesPri4} = asn1_wrapper:encode('Prim','IntPri',12345678901234567890),
- ?line {ok,12345678901234567890} = asn1_wrapper:decode('Prim','IntPri',lists:flatten(BytesPri4)),
-
- ?line {ok,BytesPri5} = asn1_wrapper:encode('Prim','IntPri',-100),
- ?line {ok,-100} = asn1_wrapper:decode('Prim','IntPri',lists:flatten(BytesPri5)),
-
- ?line {ok,BytesPri6} = asn1_wrapper:encode('Prim','IntPri',-255),
- ?line {ok,-255} = asn1_wrapper:decode('Prim','IntPri',lists:flatten(BytesPri6)),
-
- ?line {ok,BytesPri7} = asn1_wrapper:encode('Prim','IntPri',-256),
- ?line {ok,-256} = asn1_wrapper:decode('Prim','IntPri',lists:flatten(BytesPri7)),
-
- ?line {ok,BytesPri8} = asn1_wrapper:encode('Prim','IntPri',-257),
- ?line {ok,-257} = asn1_wrapper:decode('Prim','IntPri',lists:flatten(BytesPri8)),
-
- ?line {ok,BytesPri9} = asn1_wrapper:encode('Prim','IntPri',-1234567890),
- ?line {ok,-1234567890} = asn1_wrapper:decode('Prim','IntPri',lists:flatten(BytesPri9)),
-
- ?line {ok,BytesPri10} = asn1_wrapper:encode('Prim','Int',-2147483648),
- ?line {ok,-2147483648} = asn1_wrapper:decode('Prim','Int',lists:flatten(BytesPri10)),
-
-
-
- %%==========================================================
- %% IntApp ::= [APPLICATION 42] INTEGER
- %%==========================================================
-
- ?line {ok,BytesApp1} = asn1_wrapper:encode('Prim','IntApp',4),
- ?line {ok,4} = asn1_wrapper:decode('Prim','IntApp',lists:flatten(BytesApp1)),
-
- ?line {ok,BytesApp2} = asn1_wrapper:encode('Prim','IntApp',444),
- ?line {ok,444} = asn1_wrapper:decode('Prim','IntApp',lists:flatten(BytesApp2)),
-
- ?line {ok,BytesApp3} = asn1_wrapper:encode('Prim','IntApp',123456789),
- ?line {ok,123456789} = asn1_wrapper:decode('Prim','IntApp',lists:flatten(BytesApp3)),
-
- ?line {ok,BytesApp4} = asn1_wrapper:encode('Prim','IntApp',12345678901234567890),
- ?line {ok,12345678901234567890} = asn1_wrapper:decode('Prim','IntApp',lists:flatten(BytesApp4)),
-
- ?line {ok,BytesApp5} = asn1_wrapper:encode('Prim','IntApp',-100),
- ?line {ok,-100} = asn1_wrapper:decode('Prim','IntApp',lists:flatten(BytesApp5)),
-
- ?line {ok,BytesApp6} = asn1_wrapper:encode('Prim','IntApp',-255),
- ?line {ok,-255} = asn1_wrapper:decode('Prim','IntApp',lists:flatten(BytesApp6)),
-
- ?line {ok,BytesApp7} = asn1_wrapper:encode('Prim','IntApp',-256),
- ?line {ok,-256} = asn1_wrapper:decode('Prim','IntApp',lists:flatten(BytesApp7)),
-
- ?line {ok,BytesApp8} = asn1_wrapper:encode('Prim','IntApp',-257),
- ?line {ok,-257} = asn1_wrapper:decode('Prim','IntApp',lists:flatten(BytesApp8)),
-
- ?line {ok,BytesApp9} = asn1_wrapper:encode('Prim','IntApp',-1234567890),
- ?line {ok,-1234567890} = asn1_wrapper:decode('Prim','IntApp',lists:flatten(BytesApp9)),
-
- ?line {ok,BytesApp10} = asn1_wrapper:encode('Prim','Int',-2147483648),
- ?line {ok,-2147483648} = asn1_wrapper:decode('Prim','Int',lists:flatten(BytesApp10)),
-
-
- %%==========================================================
- %% IntExpCon ::= [50] EXPLICIT INTEGER
- %%==========================================================
-
- ?line {ok,BytesExpCon1} = asn1_wrapper:encode('Prim','IntExpCon',4),
- ?line {ok,4} = asn1_wrapper:decode('Prim','IntExpCon',lists:flatten(BytesExpCon1)),
-
- ?line {ok,BytesExpCon2} = asn1_wrapper:encode('Prim','IntExpCon',444),
- ?line {ok,444} = asn1_wrapper:decode('Prim','IntExpCon',lists:flatten(BytesExpCon2)),
-
- ?line {ok,BytesExpCon3} = asn1_wrapper:encode('Prim','IntExpCon',123456789),
- ?line {ok,123456789} = asn1_wrapper:decode('Prim','IntExpCon',lists:flatten(BytesExpCon3)),
-
- ?line {ok,BytesExpCon4} = asn1_wrapper:encode('Prim','IntExpCon',12345678901234567890),
- ?line {ok,12345678901234567890} = asn1_wrapper:decode('Prim','IntExpCon',lists:flatten(BytesExpCon4)),
-
- ?line {ok,BytesExpCon5} = asn1_wrapper:encode('Prim','IntExpCon',-100),
- ?line {ok,-100} = asn1_wrapper:decode('Prim','IntExpCon',lists:flatten(BytesExpCon5)),
-
- ?line {ok,BytesExpCon6} = asn1_wrapper:encode('Prim','IntExpCon',-255),
- ?line {ok,-255} = asn1_wrapper:decode('Prim','IntExpCon',lists:flatten(BytesExpCon6)),
-
- ?line {ok,BytesExpCon7} = asn1_wrapper:encode('Prim','IntExpCon',-256),
- ?line {ok,-256} = asn1_wrapper:decode('Prim','IntExpCon',lists:flatten(BytesExpCon7)),
-
- ?line {ok,BytesExpCon8} = asn1_wrapper:encode('Prim','IntExpCon',-257),
- ?line {ok,-257} = asn1_wrapper:decode('Prim','IntExpCon',lists:flatten(BytesExpCon8)),
-
- ?line {ok,BytesExpCon9} = asn1_wrapper:encode('Prim','IntExpCon',-1234567890),
- ?line {ok,-1234567890} = asn1_wrapper:decode('Prim','IntExpCon',lists:flatten(BytesExpCon9)),
-
- ?line {ok,BytesExpCon10} = asn1_wrapper:encode('Prim','Int',-2147483648),
- ?line {ok,-2147483648} = asn1_wrapper:decode('Prim','Int',lists:flatten(BytesExpCon10)),
-
- %%==========================================================
- %% IntExpPri ::= [PRIVATE 51] EXPLICIT INTEGER
- %%==========================================================
-
- ?line {ok,BytesExpPri1} = asn1_wrapper:encode('Prim','IntExpPri',4),
- ?line {ok,4} = asn1_wrapper:decode('Prim','IntExpPri',lists:flatten(BytesExpPri1)),
-
- ?line {ok,BytesExpPri2} = asn1_wrapper:encode('Prim','IntExpPri',444),
- ?line {ok,444} = asn1_wrapper:decode('Prim','IntExpPri',lists:flatten(BytesExpPri2)),
-
- ?line {ok,BytesExpPri3} = asn1_wrapper:encode('Prim','IntExpPri',123456789),
- ?line {ok,123456789} = asn1_wrapper:decode('Prim','IntExpPri',lists:flatten(BytesExpPri3)),
-
- ?line {ok,BytesExpPri4} = asn1_wrapper:encode('Prim','IntExpPri',12345678901234567890),
- ?line {ok,12345678901234567890} = asn1_wrapper:decode('Prim','IntExpPri',lists:flatten(BytesExpPri4)),
-
- ?line {ok,BytesExpPri5} = asn1_wrapper:encode('Prim','IntExpPri',-100),
- ?line {ok,-100} = asn1_wrapper:decode('Prim','IntExpPri',lists:flatten(BytesExpPri5)),
-
- ?line {ok,BytesExpPri6} = asn1_wrapper:encode('Prim','IntExpPri',-255),
- ?line {ok,-255} = asn1_wrapper:decode('Prim','IntExpPri',lists:flatten(BytesExpPri6)),
-
- ?line {ok,BytesExpPri7} = asn1_wrapper:encode('Prim','IntExpPri',-256),
- ?line {ok,-256} = asn1_wrapper:decode('Prim','IntExpPri',lists:flatten(BytesExpPri7)),
-
- ?line {ok,BytesExpPri8} = asn1_wrapper:encode('Prim','IntExpPri',-257),
- ?line {ok,-257} = asn1_wrapper:decode('Prim','IntExpPri',lists:flatten(BytesExpPri8)),
-
- ?line {ok,BytesExpPri9} = asn1_wrapper:encode('Prim','IntExpPri',-1234567890),
- ?line {ok,-1234567890} = asn1_wrapper:decode('Prim','IntExpPri',lists:flatten(BytesExpPri9)),
-
- ?line {ok,BytesExpPri10} = asn1_wrapper:encode('Prim','Int',-2147483648),
- ?line {ok,-2147483648} = asn1_wrapper:decode('Prim','Int',lists:flatten(BytesExpPri10)),
-
- %%==========================================================
- %% IntExpApp ::= [APPLICATION 52] EXPLICIT INTEGER
- %%==========================================================
-
- ?line {ok,BytesExpApp1} = asn1_wrapper:encode('Prim','IntExpApp',4),
- ?line {ok,4} = asn1_wrapper:decode('Prim','IntExpApp',lists:flatten(BytesExpApp1)),
-
- ?line {ok,BytesExpApp2} = asn1_wrapper:encode('Prim','IntExpApp',444),
- ?line {ok,444} = asn1_wrapper:decode('Prim','IntExpApp',lists:flatten(BytesExpApp2)),
-
- ?line {ok,BytesExpApp3} = asn1_wrapper:encode('Prim','IntExpApp',123456789),
- ?line {ok,123456789} = asn1_wrapper:decode('Prim','IntExpApp',lists:flatten(BytesExpApp3)),
-
- ?line {ok,BytesExpApp4} = asn1_wrapper:encode('Prim','IntExpApp',12345678901234567890),
- ?line {ok,12345678901234567890} = asn1_wrapper:decode('Prim','IntExpApp',lists:flatten(BytesExpApp4)),
-
- ?line {ok,BytesExpApp5} = asn1_wrapper:encode('Prim','IntExpApp',-100),
- ?line {ok,-100} = asn1_wrapper:decode('Prim','IntExpApp',lists:flatten(BytesExpApp5)),
-
- ?line {ok,BytesExpApp6} = asn1_wrapper:encode('Prim','IntExpApp',-255),
- ?line {ok,-255} = asn1_wrapper:decode('Prim','IntExpApp',lists:flatten(BytesExpApp6)),
-
- ?line {ok,BytesExpApp7} = asn1_wrapper:encode('Prim','IntExpApp',-256),
- ?line {ok,-256} = asn1_wrapper:decode('Prim','IntExpApp',lists:flatten(BytesExpApp7)),
-
- ?line {ok,BytesExpApp8} = asn1_wrapper:encode('Prim','IntExpApp',-257),
- ?line {ok,-257} = asn1_wrapper:decode('Prim','IntExpApp',lists:flatten(BytesExpApp8)),
-
- ?line {ok,BytesExpApp9} = asn1_wrapper:encode('Prim','IntExpApp',-1234567890),
- ?line {ok,-1234567890} = asn1_wrapper:decode('Prim','IntExpApp',lists:flatten(BytesExpApp9)),
-
- ?line {ok,BytesExpApp10} = asn1_wrapper:encode('Prim','Int',-2147483648),
- ?line {ok,-2147483648} = asn1_wrapper:decode('Prim','Int',lists:flatten(BytesExpApp10)),
-
+ Values = [0,2,3,4,127,128,254,255,256,257,444,
+ 16383,16384,16385,65534,65535,65536,65537,
+ 123456789,12345678901234567890,
+ -1,-2,-3,-4,-100,-127,-255,-256,-257,
+ -1234567890,-2147483648],
+ [roundtrip(T, V) ||
+ T <- ['Int','IntCon','IntPri','IntApp',
+ 'IntExpCon','IntExpPri','IntExpApp'],
+ V <- [1|Values]],
%%==========================================================
%% IntEnum ::= INTEGER {first(1),last(31)}
%%==========================================================
- ?line {ok,BytesEnum1} = asn1_wrapper:encode('Prim','IntEnum',4),
- ?line {ok,4} = asn1_wrapper:decode('Prim','IntEnum',lists:flatten(BytesEnum1)),
-
- ?line {ok,BytesEnum2} = asn1_wrapper:encode('Prim','IntEnum',444),
- ?line {ok,444} = asn1_wrapper:decode('Prim','IntEnum',lists:flatten(BytesEnum2)),
-
- ?line {ok,BytesEnum3} = asn1_wrapper:encode('Prim','IntEnum',123456789),
- ?line {ok,123456789} = asn1_wrapper:decode('Prim','IntEnum',lists:flatten(BytesEnum3)),
-
- ?line {ok,BytesEnum4} = asn1_wrapper:encode('Prim','IntEnum',12345678901234567890),
- ?line {ok,12345678901234567890} = asn1_wrapper:decode('Prim','IntEnum',lists:flatten(BytesEnum4)),
+ [roundtrip('IntEnum', V) || V <- Values],
- ?line {ok,BytesEnum5} = asn1_wrapper:encode('Prim','IntEnum',-100),
- ?line {ok,-100} = asn1_wrapper:decode('Prim','IntEnum',lists:flatten(BytesEnum5)),
-
- ?line {ok,BytesEnum6} = asn1_wrapper:encode('Prim','IntEnum',-255),
- ?line {ok,-255} = asn1_wrapper:decode('Prim','IntEnum',lists:flatten(BytesEnum6)),
-
- ?line {ok,BytesEnum7} = asn1_wrapper:encode('Prim','IntEnum',-256),
- ?line {ok,-256} = asn1_wrapper:decode('Prim','IntEnum',lists:flatten(BytesEnum7)),
-
- ?line {ok,BytesEnum8} = asn1_wrapper:encode('Prim','IntEnum',-257),
- ?line {ok,-257} = asn1_wrapper:decode('Prim','IntEnum',lists:flatten(BytesEnum8)),
-
- ?line {ok,BytesEnum9} = asn1_wrapper:encode('Prim','IntEnum',-1234567890),
- ?line {ok,-1234567890} = asn1_wrapper:decode('Prim','IntEnum',lists:flatten(BytesEnum9)),
-
- ?line {ok,BytesEnum910} = asn1_wrapper:encode('Prim','Int',-2147483648),
- ?line {ok,-2147483648} = asn1_wrapper:decode('Prim','Int',lists:flatten(BytesEnum910)),
-
-
- ?line {ok,BytesEnum10} = asn1_wrapper:encode('Prim','IntEnum',first),
- ?line {ok,first} = asn1_wrapper:decode('Prim','IntEnum',lists:flatten(BytesEnum10)),
-
- ?line {ok,BytesEnum11} = asn1_wrapper:encode('Prim','IntEnum',last),
- ?line {ok,last} = asn1_wrapper:decode('Prim','IntEnum',lists:flatten(BytesEnum11)),
-
+ roundtrip('IntEnum', first),
+ roundtrip('IntEnum', last),
+ roundtrip('ASeq', {'ASeq',true,254,false,255,true,256,true,68789}),
+ roundtrip('ASeq', {'ASeq',false,250,true,200,true,199,true,77788}),
+ roundtrip('ASeq', {'ASeq',true,0,false,0,true,0,true,68789}),
ok.
-
enum(Rules) ->
%%==========================================================
@@ -496,23 +88,9 @@ enum(Rules) ->
%% friday(5),saturday(6),sunday(7)}
%%==========================================================
- ?line {ok,BytesEnum1} = asn1_wrapper:encode('Prim','Enum',monday),
- ?line {ok,monday} = asn1_wrapper:decode('Prim','Enum',lists:flatten(BytesEnum1)),
-
- ?line {ok,BytesEnum2} = asn1_wrapper:encode('Prim','Enum',thursday),
- ?line {ok,thursday} = asn1_wrapper:decode('Prim','Enum',lists:flatten(BytesEnum2)),
-
-
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line {error,{asn1,{_,4}}} =
- case catch asn1_wrapper:encode('Prim','Enum',4) of Enum -> Enum end,
- ok;
- per ->
- ?line {error,{asn1,{_,4}}} =
- case catch asn1_wrapper:encode('Prim','Enum',4) of Enum -> Enum end,
- ok
- end,
+ roundtrip('Enum', monday),
+ roundtrip('Enum', thursday),
+ {error,{asn1,{_,4}}} = (catch 'Prim':encode('Enum', 4)),
case Rules of
Per when Per =:= per; Per =:= uper ->
@@ -524,88 +102,41 @@ enum(Rules) ->
ok.
-
-obj_id(Rules) ->
+obj_id(_) ->
%%==========================================================
%% ObjId ::= OBJECT IDENTIFIER
%%==========================================================
- ?line {ok,Bytes1} = asn1_wrapper:encode('Prim','ObjId',{0,22,3}),
- ?line {ok,{0,22,3}} = asn1_wrapper:decode('Prim','ObjId',lists:flatten(Bytes1)),
-
- ?line {ok,Bytes2} = asn1_wrapper:encode('Prim','ObjId',{1,39,3}),
- ?line {ok,{1,39,3}} = asn1_wrapper:decode('Prim','ObjId',lists:flatten(Bytes2)),
-
- ?line {ok,Bytes3} = asn1_wrapper:encode('Prim','ObjId',{2,100,3}),
- ?line {ok,{2,100,3}} = asn1_wrapper:decode('Prim','ObjId',lists:flatten(Bytes3)),
-
- ?line {ok,Bytes4} = asn1_wrapper:encode('Prim','ObjId',{2,16303,3}),
- ?line {ok,{2,16303,3}} = asn1_wrapper:decode('Prim','ObjId',lists:flatten(Bytes4)),
-
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line {ok,Bytes5} = asn1_wrapper:encode('Prim','ObjId',{2,16304,3}),
- ?line {ok,{2,16304,3}} = asn1_wrapper:decode('Prim','ObjId',lists:flatten(Bytes5)),
- ok;
- per ->
- ?line {ok,Bytes5} = asn1_wrapper:encode('Prim','ObjId',{2,16304,3}),
- ?line {ok,{2,16304,3}} = asn1_wrapper:decode('Prim','ObjId',lists:flatten(Bytes5)),
-%% ?line test_server:format("~p~n",[Kurt]),
-% ?line {ok,{2,16304,3}} = asn1_wrapper:decode('Prim','ObjId',lists:flatten(Bytes5)),
- ok
- end,
-
-
-
+ [roundtrip('ObjId', V) ||
+ V <- [{0,22,3},{1,39,3},{2,100,3},{2,16303,3},{2,16304,3}]],
ok.
rel_oid(_Rules) ->
-
%%==========================================================
%% RelOid ::= RELATIVE-OID
%%==========================================================
- ?line {ok,Bytes1} = asn1_wrapper:encode('Prim','RelOid',{0,22,3}),
- ?line {ok,{0,22,3}} = asn1_wrapper:decode('Prim','RelOid',lists:flatten(Bytes1)),
-
- ?line {ok,Bytes2} = asn1_wrapper:encode('Prim','RelOid',{1,39,3}),
- ?line {ok,{1,39,3}} = asn1_wrapper:decode('Prim','RelOid',lists:flatten(Bytes2)),
-
- ?line {ok,Bytes3} = asn1_wrapper:encode('Prim','RelOid',{2,100,3}),
- ?line {ok,{2,100,3}} = asn1_wrapper:decode('Prim','RelOid',lists:flatten(Bytes3)),
-
- ?line {ok,Bytes4} = asn1_wrapper:encode('Prim','RelOid',{2,16303,3}),
- ?line {ok,{2,16303,3}} = asn1_wrapper:decode('Prim','RelOid',lists:flatten(Bytes4)),
-
- ?line {ok,Bytes5} = asn1_wrapper:encode('Prim','RelOid',{2,16304,3}),
- ?line {ok,{2,16304,3}} = asn1_wrapper:decode('Prim','RelOid',lists:flatten(Bytes5)),
-
- ?line {ok,Bytes6} = asn1_wrapper:encode('Prim','RelOid',{8,16304,16#ffff}),
- ?line {ok,{8,16304,16#ffff}} = asn1_wrapper:decode('Prim','RelOid',lists:flatten(Bytes6)),
-
-
-
+ [roundtrip('RelOid', V) ||
+ V <- [{0,22,3},{1,39,3},{2,100,3},{2,16303,3},
+ {2,16304,3},{8,16304,16#ffff}]],
ok.
-
-
-
null(_Rules) ->
%%==========================================================
%% Null ::= NULL
%%==========================================================
- ?line {ok,Bytes1} = asn1_wrapper:encode('Prim','Null',monday),
- ?line {ok,'NULL'} = asn1_wrapper:decode('Prim','Null',lists:flatten(Bytes1)),
-
-
-
-ok.
-
+ {ok,Bytes1} = asn1_wrapper:encode('Prim','Null',monday),
+ {ok,'NULL'} = asn1_wrapper:decode('Prim','Null',lists:flatten(Bytes1)),
+ ok.
+roundtrip(T, V) ->
+ {ok,E} = 'Prim':encode(T, V),
+ {ok,V} = 'Prim':decode(T, E),
+ E.
real(_Rules) ->
%%==========================================================
diff --git a/lib/asn1/test/testPrimStrings.erl b/lib/asn1/test/testPrimStrings.erl
index f8b0c5b05a..e2322c92a9 100644
--- a/lib/asn1/test/testPrimStrings.erl
+++ b/lib/asn1/test/testPrimStrings.erl
@@ -54,7 +54,7 @@ bit_string(Rules) ->
bs_roundtrip('Bs1', [1,0,0,0,0,0,0,0,0]),
bs_roundtrip('Bs1', [0,1,0,0,1,0,1,1,1,1,1,0,0,0,1,0,0,1,1]),
- case asn1_wrapper:erule(Rules) of
+ case Rules of
ber ->
bs_decode('Bs1', <<35,8,3,2,0,73,3,2,4,32>>,
[0,1,0,0,1,0,0,1,0,0,1,0]),
@@ -62,7 +62,7 @@ bit_string(Rules) ->
[1,1,1,0,1,0,1,0,1,0,0,1,1,1,0,0,0]),
bs_decode('Bs1', <<35,128,3,2,0,234,3,3,7,156,0,0,0>>,
[1,1,1,0,1,0,1,0,1,0,0,1,1,1,0,0,0]);
- per ->
+ _ ->
ok
end,
@@ -71,35 +71,16 @@ bit_string(Rules) ->
%% Bs2 ::= BIT STRING {su(0), mo(1), tu(2), we(3), th(4), fr(5), sa(6) } (SIZE (7))
%%==========================================================
- ?line {ok,Bytes21} = asn1_wrapper:encode('PrimStrings','Bs2',[mo,tu,fr]),
- ?line {ok,[mo,tu,fr]} = asn1_wrapper:decode('PrimStrings','Bs2',lists:flatten(Bytes21)),
-
- ?line {ok,Bytes22} = asn1_wrapper:encode('PrimStrings','Bs2',[0,1,1,0,0,1,0]),
- ?line {ok,[mo,tu,fr]} = asn1_wrapper:decode('PrimStrings','Bs2',lists:flatten(Bytes22)),
- ok,
-%% skip this because it is wrong
-% ?line case asn1_wrapper:erule(Rules) of
-% ber ->
-% ?line {ok,[mo,tu,fr,su,mo,th]} =
-% asn1_wrapper:decode('PrimStrings','Bs2',[35,8,3,2,0,101,3,2,2,200]),
-
-% ?line {ok,[mo,tu,fr,su,mo,th]} =
-% asn1_wrapper:decode('PrimStrings','Bs2',[35,128,3,2,1,100,3,2,2,200,0,0]),
-% ok;
-
-% per ->
-% ok
-% end,
-
-
-
+ roundtrip('Bs2', [mo,tu,fr]),
+ roundtrip('Bs2', [0,1,1,0,0,1,0], [mo,tu,fr]),
+
%%==========================================================
%% Bs3 ::= BIT STRING {su(0), mo(1), tu(2), we(3), th(4), fr(5), sa(6) } (SIZE (1..7))
%%==========================================================
roundtrip('Bs3', [mo,tu,fr]),
bs_roundtrip('Bs3', [0,1,1,0,0,1,0], [mo,tu,fr]),
-
+
%%==========================================================
%% Bs7 ::= BIT STRING (SIZE (24))
%%==========================================================
@@ -114,10 +95,9 @@ bit_string(Rules) ->
%%==========================================================
bs_roundtrip('BsPri', 45, [1,0,1,1,0,1]),
-
bs_roundtrip('BsPri', 211, [1,1,0,0,1,0,1,1]),
- case asn1_wrapper:erule(Rules) of
+ case Rules of
ber ->
bs_decode('BsPri', <<223,61,4,5,75,226,96>>,
[0,1,0,0,1,0,1,1,1,1,1,0,0,0,1,0,0,1,1]),
@@ -127,7 +107,7 @@ bit_string(Rules) ->
[0,1,0,0,1,0,1,1,1,1,1,0,0,0,1,0,0,1,1]),
bs_decode('BsPri', <<255,61,128,3,2,0,75,3,3,5,226,96,0,0>>,
[0,1,0,0,1,0,1,1,1,1,1,0,0,0,1,0,0,1,1]);
- per ->
+ _ ->
ok
end,
@@ -139,11 +119,11 @@ bit_string(Rules) ->
bs_roundtrip('BsExpPri', 45, [1,0,1,1,0,1]),
bs_roundtrip('BsExpPri', 211, [1,1,0,0,1,0,1,1]),
- case asn1_wrapper:erule(Rules) of
+ case Rules of
ber ->
bs_decode('BsExpPri', <<255,61,6,3,4,5,75,226,96>>,
[0,1,0,0,1,0,1,1,1,1,1,0,0,0,1,0,0,1,1]);
- per ->
+ _ ->
ok
end,
@@ -151,24 +131,22 @@ bit_string(Rules) ->
%% TestS ::= BIT STRING {a(0),b(1)} (SIZE (3..8)), test case for OTP-4353
%%==========================================================
- ?line {ok,Bytes53} = asn1_wrapper:encode('PrimStrings','TestS',[a]),
- ?line {ok,[a]} =
- asn1_wrapper:decode('PrimStrings','TestS',lists:flatten(Bytes53)),
+ roundtrip('TestS', [a]),
%%==========================================================
%% PersonalStatus ::= BIT STRING {married(0),employed(1),
%% veteran(2), collegeGraduate(3)}, test case for OTP-5710
%%==========================================================
- ?line {ok,Bytes54} = asn1_wrapper:encode('BitStr','PersonalStatus',[]),
- ?line {ok,[]} = asn1_wrapper:decode('BitStr','PersonalStatus',Bytes54),
+ {ok,Bytes54} = 'BitStr':encode('PersonalStatus', []),
+ {ok,[]} = 'BitStr':decode('PersonalStatus', Bytes54),
%%==========================================================
%% BS5932 ::= BIT STRING (SIZE (5..MAX))
%% test case for OTP-5932
%%==========================================================
bs_roundtrip('BSMAX', [1,0,1,0,1]),
- case asn1_wrapper:erule(Rules) of
+ case Rules of
ber ->
{error,_} = 'PrimStrings':encode('BSMAX', [1,0,1]);
_ ->
@@ -195,7 +173,91 @@ bit_string(Rules) ->
BSList1024 = BSmaker(BSmaker,0,1024,{1,0},[]),
bs_roundtrip('BS1024', BSList1024),
- bs_roundtrip('TransportLayerAddress', [0,1,1,0]).
+ bs_roundtrip('TransportLayerAddress', [0,1,1,0]),
+
+ case Rules of
+ ber -> ok;
+ _ -> per_bs_strings()
+ end.
+
+%% The PER encoding rules requires that a BIT STRING with
+%% named positions should never have any trailing zeroes
+%% (except to reach the minimum number of bits as given by
+%% a SIZE constraint).
+
+per_bs_strings() ->
+ bs_roundtrip('Bs3', [0,0,1,0,0,0,0], [tu]),
+ bs_roundtrip('Bs3', <<2#0010000:7>>, [tu]),
+ bs_roundtrip('Bs3', {1,<<2#00100000:8>>}, [tu]),
+
+ bs_roundtrip('Bs4', [0,1,1,0,0,1,0], [mo,tu,fr]),
+ bs_roundtrip('Bs4', <<2#0110010:7>>, [mo,tu,fr]),
+ bs_roundtrip('Bs4', {1,<<2#01100100:8>>}, [mo,tu,fr]),
+
+ bs_roundtrip('Bs4', [0,1,1,0,0,0,0], [mo,tu]),
+ bs_roundtrip('Bs4', <<2#011:3,0:32>>, [mo,tu]),
+ bs_roundtrip('Bs4', {5,<<2#011:3,0:32,0:5>>}, [mo,tu]),
+
+ [per_trailing_zeroes(B) || B <- lists:seq(0, 255)],
+ ok.
+
+%% Trailing zeroes should be removed from BIT STRINGs with named
+%% bit positions.
+
+per_trailing_zeroes(Byte) ->
+ L = lists:reverse(make_bit_list(Byte+16#10000)),
+ L = make_bit_list(Byte+16#10000, []),
+ Pos = positions(L, 0),
+ ExpectedSz = case lists:last(Pos) of
+ su -> 1;
+ {bit,LastBitPos} -> LastBitPos+1
+ end,
+
+ %% List of zeroes and ones.
+ named_roundtrip(L, Pos, ExpectedSz),
+ named_roundtrip(L++[0,0,0,0,0], Pos, ExpectedSz),
+
+ %% Bitstrings.
+ Bs = << <<B:1>> || B <- L >>,
+ Sz = bit_size(Bs),
+ named_roundtrip(Bs, Pos, ExpectedSz),
+ Bin = <<Bs:Sz/bits,0:16,0:7>>,
+ named_roundtrip(Bin, Pos, ExpectedSz),
+
+ %% Compact bitstring.
+ named_roundtrip({7,Bin}, Pos, ExpectedSz),
+
+ %% Integer bitstring (obsolete).
+ IntBs = intlist_to_integer(L, 0, 0),
+ named_roundtrip(IntBs, Pos, ExpectedSz),
+
+ ok.
+
+make_bit_list(0) -> [];
+make_bit_list(B) -> [B band 1|make_bit_list(B bsr 1)].
+
+make_bit_list(0, Acc) -> Acc;
+make_bit_list(B, Acc) -> make_bit_list(B bsr 1, [B band 1|Acc]).
+
+positions([1|T], 0) -> [su|positions(T, 1)];
+positions([1|T], Pos) -> [{bit,Pos}|positions(T, Pos+1)];
+positions([0|T], Pos) -> positions(T, Pos+1);
+positions([], _) -> [].
+
+intlist_to_integer([B|T], Shift, Acc) ->
+ intlist_to_integer(T, Shift+1, (B bsl Shift) + Acc);
+intlist_to_integer([], _, Acc) -> Acc.
+
+named_roundtrip(Value, Expected, ExpectedSz) ->
+ M = 'PrimStrings',
+ Type = 'Bs4',
+ {ok,Encoded} = M:encode(Type, Value),
+ {ok,Encoded} = M:encode(Type, Expected),
+ {ok,Expected} = M:decode(Type, Encoded),
+
+ %% Verify the size in the first byte.
+ <<ExpectedSz:8,_/bits>> = Encoded,
+ ok.
octet_string(Rules) ->
@@ -203,21 +265,18 @@ octet_string(Rules) ->
%% Os ::= OCTET STRING
%%==========================================================
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line {ok,"Jones"} =
- asn1_wrapper:decode('PrimStrings','Os',[4,5,16#4A,16#6F,16#6E,16#65,16#73]),
-
- ?line {ok,"Jones"} =
- asn1_wrapper:decode('PrimStrings','Os',[36,9,4,3,16#4A,16#6F,16#6E,4,2,16#65,16#73]),
-
- ?line {ok,"Jones"} =
- asn1_wrapper:decode('PrimStrings','Os',[36,128,4,3,16#4A,16#6F,16#6E,4,2,16#65,16#73,0,0]),
- ok;
-
- per ->
- ok
- end,
+ case Rules of
+ ber ->
+ {ok,"Jones"} =
+ 'PrimStrings':decode('Os', <<4,5,16#4A,16#6F,16#6E,16#65,16#73>>),
+ {ok,"Jones"} =
+ 'PrimStrings':decode('Os', <<36,9,4,3,16#4A,16#6F,16#6E,4,2,16#65,16#73>>),
+ {ok,"Jones"} =
+ 'PrimStrings':decode('Os', <<36,128,4,3,16#4A,16#6F,16#6E,4,2,16#65,16#73,0,0>>),
+ ok;
+ _ ->
+ ok
+ end,
roundtrip('Os', [47,23,99,255,1]),
roundtrip('OsCon', [47,23,99,255,1]),
@@ -239,27 +298,32 @@ octet_string(Rules) ->
roundtrip('OsExpApp', OsR),
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line {ok,"Jones"} = asn1_wrapper:decode('PrimStrings','OsExpApp',[127,62,7,4,5,16#4A,16#6F,16#6E,16#65,16#73]),
- ?line {ok,"Jones"} = asn1_wrapper:decode('PrimStrings','OsExpApp',[127,62,11,36,9,4,3,16#4A,16#6F,16#6E,4,2,16#65,16#73]),
- ?line {ok,"Jones"} = asn1_wrapper:decode('PrimStrings','OsExpApp',[127,62,13,36,128,4,3,16#4A,16#6F,16#6E,4,2,16#65,16#73,0,0]),
- ?line {ok,"Jones"} = asn1_wrapper:decode('PrimStrings','OsExpApp',[127,62,128,36,128,4,3,16#4A,16#6F,16#6E,4,2,16#65,16#73,0,0,0,0]),
- ?line {ok,"JonesJones"} = asn1_wrapper:decode('PrimStrings','OsExpApp',[127,62,128,36,128,4,3,16#4A,16#6F,16#6E,4,2,16#65,16#73,0,0,36,128,4,3,16#4A,16#6F,16#6E,4,2,16#65,16#73,0,0,0,0]),
- ok;
-
- per ->
- ok
- end,
+ case Rules of
+ ber ->
+ {ok,"Jones"} = 'PrimStrings':decode('OsExpApp', <<127,62,7,4,5,16#4A,16#6F,16#6E,16#65,16#73>>),
+ {ok,"Jones"} = 'PrimStrings':decode('OsExpApp', <<127,62,11,36,9,4,3,16#4A,16#6F,16#6E,4,2,16#65,16#73>>),
+ {ok,"Jones"} = 'PrimStrings':decode('OsExpApp', <<127,62,13,36,128,4,3,16#4A,16#6F,16#6E,4,2,16#65,16#73,0,0>>),
+ {ok,"Jones"} = 'PrimStrings':decode('OsExpApp', <<127,62,128,36,128,4,3,16#4A,16#6F,16#6E,4,2,16#65,16#73,0,0,0,0>>),
+ {ok,"JonesJones"} = 'PrimStrings':decode('OsExpApp', <<127,62,128,36,128,4,3,16#4A,16#6F,16#6E,4,2,16#65,16#73,0,0,36,128,4,3,16#4A,16#6F,16#6E,4,2,16#65,16#73,0,0,0,0>>),
+ ok;
+
+ _->
+ ok
+ end,
fragmented_octet_string(Rules),
S255 = lists:seq(1, 255),
- FixedStrings = {'OsFixedStrings',true,"","1","12","345",true,
- S255,[$a|S255],[$a,$b|S255],397},
- roundtrip('OsFixedStrings', FixedStrings),
+ Strings = {type,true,"","1","12","345",true,
+ S255,[$a|S255],[$a,$b|S255],397},
+ p_roundtrip('OsFixedStrings', Strings),
+ p_roundtrip('OsFixedStringsExt', Strings),
+ p_roundtrip('OsVarStringsExt', Strings),
+ ShortenedStrings = shorten_by_two(Strings),
+ p_roundtrip('OsFixedStringsExt', ShortenedStrings),
+ p_roundtrip('OsVarStringsExt', ShortenedStrings),
ok.
-
+
fragmented_octet_string(Erules) ->
K16 = 1 bsl 14,
K32 = K16 + K16,
@@ -271,10 +335,12 @@ fragmented_octet_string(Erules) ->
K48-1,K48,K48+1,K48+(1 bsl 7)-1,K48+(1 bsl 7),K48+(1 bsl 7)+1,
K64-1,K64,K64+1,K64+(1 bsl 7)-1,K64+(1 bsl 7),K64+(1 bsl 7)+1,
K64+K16-1,K64+K16,K64+K16+1],
- Types = ['Os','OsFrag'],
+ Types = ['Os','OsFrag','OsFragExt'],
[fragmented_octet_string(Erules, Types, L) || L <- Lens],
fragmented_octet_string(Erules, ['FixedOs65536'], 65536),
fragmented_octet_string(Erules, ['FixedOs65537'], 65537),
+ fragmented_octet_string(Erules, ['FixedOs65536Ext'], 65536),
+ fragmented_octet_string(Erules, ['FixedOs65537Ext'], 65537),
%% Make sure that octet alignment works.
roundtrip('OsAlignment',
@@ -336,75 +402,58 @@ numeric_string(Rules) ->
%%==========================================================
roundtrip('Ns', []),
+ roundtrip('Ns', "01 34"),
+ case Rules of
+ ber ->
+ {ok,"Jones"} = 'PrimStrings':decode('Ns',
+ <<16#12,5,16#4A,16#6F,
+ 16#6E,16#65,16#73>>),
+ {ok,"Jones"} = 'PrimStrings':decode('Ns',
+ <<16#32,9,18,3,16#4A,16#6F,
+ 16#6E,18,2,16#65,16#73>>),
+ {ok,"Jones"} = 'PrimStrings':decode('Ns',
+ <<16#32,128,18,3,16#4A,16#6F,
+ 16#6E,18,2,16#65,16#73,0,0>>),
+ ok;
+ _ ->
+ ok
+ end,
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line {ok,BytesNs1} = asn1_wrapper:encode('PrimStrings','Ns',[48,49,32,51,52]),
- ?line {ok,[48,49,32,51,52]} = asn1_wrapper:decode('PrimStrings','Ns',lists:flatten(BytesNs1)),
-
- ?line {ok,"Jones"} = asn1_wrapper:decode('PrimStrings','Ns',[16#12,5,16#4A,16#6F,16#6E,16#65,16#73]),
- ?line {ok,"Jones"} = asn1_wrapper:decode('PrimStrings','Ns',[16#32,9,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73]),
- ?line {ok,"Jones"} = asn1_wrapper:decode('PrimStrings','Ns',[16#32,128,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73,0,0]),
- ok;
-
- per ->
- ?line {ok,BytesNs1} = asn1_wrapper:encode('PrimStrings','Ns',[48,49,32,51,52]),
- ?line {ok,"01 34"} = asn1_wrapper:decode('PrimStrings','Ns',lists:flatten(BytesNs1)),
- ok
- end,
-
-
-
-
%%==========================================================
%% NsCon ::= [70] NumericString
%%==========================================================
roundtrip('NsCon', []),
+ roundtrip('NsCon', "01 34"),
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line {ok,BytesNs11} = asn1_wrapper:encode('PrimStrings','NsCon',[48,49,32,51,52]),
- ?line {ok,[48,49,32,51,52]} = asn1_wrapper:decode('PrimStrings','NsCon',lists:flatten(BytesNs11)),
-
- ?line {ok,"Jones"} = asn1_wrapper:decode('PrimStrings','NsCon',[16#9F,16#46,5,16#4A,16#6F,16#6E,16#65,16#73]),
- ?line {ok,"Jones"} = asn1_wrapper:decode('PrimStrings','NsCon',[16#BF,16#46,9,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73]),
- ?line {ok,"Jones"} = asn1_wrapper:decode('PrimStrings','NsCon',[16#BF,16#46,128,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73,0,0]),
- ok;
-
- per ->
- ?line {ok,BytesNs11} = asn1_wrapper:encode('PrimStrings','NsCon',[48,49,32,51,52]),
- ?line {ok,"01 34"} = asn1_wrapper:decode('PrimStrings','NsCon',lists:flatten(BytesNs11)),
- ok
- end,
-
+ case Rules of
+ ber ->
+ {ok,"Jones"} = 'PrimStrings':decode('NsCon', <<16#9F,16#46,5,16#4A,16#6F,16#6E,16#65,16#73>>),
+ {ok,"Jones"} = 'PrimStrings':decode('NsCon', <<16#BF,16#46,9,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73>>),
+ {ok,"Jones"} = 'PrimStrings':decode('NsCon', <<16#BF,16#46,128,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73,0,0>>),
+ ok;
+ _ ->
+ ok
+ end,
-
%%==========================================================
%% NsExpCon ::= [71] EXPLICIT NumericString
%%==========================================================
roundtrip('NsExpCon', []),
+ roundtrip('NsExpCon', "01 34"),
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line {ok,BytesNs21} = asn1_wrapper:encode('PrimStrings','NsExpCon',[48,49,32,51,52]),
- ?line {ok,[48,49,32,51,52]} = asn1_wrapper:decode('PrimStrings','NsExpCon',lists:flatten(BytesNs21)),
-
- ?line {ok,"Jones"} = asn1_wrapper:decode('PrimStrings','NsExpCon',[16#BF,16#47,16#07,16#12,16#05,16#4A,16#6F,16#6E,16#65,16#73]),
- ?line {ok,"Jones"} = asn1_wrapper:decode('PrimStrings','NsExpCon',[16#BF,16#47,11,16#32,9,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73]),
- ?line {ok,"Jones"} = asn1_wrapper:decode('PrimStrings','NsExpCon',[16#BF,16#47,128,16#32,128,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73,0,0,0,0]),
- ?line {ok,"JonesJones"} = asn1_wrapper:decode('PrimStrings','NsExpCon',[16#BF,16#47,26,16#32,128,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73,0,0,16#32,128,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73,0,0]),
- ?line {ok,"JonesJones"} = asn1_wrapper:decode('PrimStrings','NsExpCon',[16#BF,16#47,128,16#32,128,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73,0,0,16#32,128,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73,0,0,0,0]),
- ok;
-
- per ->
- ?line {ok,BytesNs21} = asn1_wrapper:encode('PrimStrings','NsExpCon',[48,49,32,51,52]),
- ?line {ok,"01 34"} = asn1_wrapper:decode('PrimStrings','NsExpCon',lists:flatten(BytesNs21)),
- ok
- end,
-
- ok.
+ case Rules of
+ ber ->
+ {ok,"Jones"} = 'PrimStrings':decode('NsExpCon', <<16#BF,16#47,16#07,16#12,16#05,16#4A,16#6F,16#6E,16#65,16#73>>),
+ {ok,"Jones"} = 'PrimStrings':decode('NsExpCon', <<16#BF,16#47,11,16#32,9,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73>>),
+ {ok,"Jones"} = 'PrimStrings':decode('NsExpCon', <<16#BF,16#47,128,16#32,128,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73,0,0,0,0>>),
+ {ok,"JonesJones"} = 'PrimStrings':decode('NsExpCon', <<16#BF,16#47,26,16#32,128,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73,0,0,16#32,128,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73,0,0>>),
+ {ok,"JonesJones"} = 'PrimStrings':decode('NsExpCon', <<16#BF,16#47,128,16#32,128,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73,0,0,16#32,128,18,3,16#4A,16#6F,16#6E,18,2,16#65,16#73,0,0,0,0>>),
+ ok;
+ _ ->
+ ok
+ end.
other_strings(_Rules) ->
@@ -438,6 +487,15 @@ other_strings(_Rules) ->
roundtrip('IA5Visible', lists:seq($\s, $~)),
+ S255 = lists:seq(0, 127) ++ lists:seq(1, 127),
+ Strings = {type,true,"","1","12","345",true,"6789",true,
+ S255,[$a|S255],[$a,$b|S255],397},
+ p_roundtrip('IA5FixedStrings', Strings),
+ p_roundtrip('IA5FixedStringsExt', Strings),
+ p_roundtrip('IA5VarStringsExt', Strings),
+ ShortenedStrings = shorten_by_two(Strings),
+ p_roundtrip('IA5VarStringsExt', ShortenedStrings),
+
ok.
@@ -491,23 +549,19 @@ universal_string(Rules) ->
%%==========================================================
roundtrip('Us', [{47,23,99,47},{0,0,55,66}]),
-
- ?line {ok,Bytes2} =
- asn1_wrapper:encode('PrimStrings','Us',[{47,23,99,255},{0,0,0,201}]),
- ?line {ok,[{47,23,99,255},201]} =
- asn1_wrapper:decode('PrimStrings','Us',lists:flatten(Bytes2)),
-
+ roundtrip('Us',
+ [{47,23,99,255},{0,0,0,201}],
+ [{47,23,99,255},201]),
roundtrip('Us', "Universal String"),
roundtrip('Us', []),
roundtrip('Us', [{47,23,99,47}]),
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
-
- ?line {ok,[{47,23,99,255},{0,0,2,201}]} =
- asn1_wrapper:decode('PrimStrings','Us',lists:flatten([16#3C,12,28,4,47,23,99,255,28,4,0,0,2,201])),
- ?line {ok,[{47,23,99,255},{0,0,2,201}]} =
- asn1_wrapper:decode('PrimStrings','Us',lists:flatten([16#3C,16#80,28,4,47,23,99,255,28,4,0,0,2,201,0,0]));
+ case Rules of
+ ber ->
+ {ok,[{47,23,99,255},{0,0,2,201}]} =
+ 'PrimStrings':decode('Us', <<16#3C,12,28,4,47,23,99,255,28,4,0,0,2,201>>),
+ {ok,[{47,23,99,255},{0,0,2,201}]} =
+ 'PrimStrings':decode('Us', <<16#3C,16#80,28,4,47,23,99,255,28,4,0,0,2,201,0,0>>);
_ ->
ok
end,
@@ -522,24 +576,21 @@ universal_string(Rules) ->
%%==========================================================
roundtrip('UsCon', [{47,23,99,255},{0,0,2,201}]),
-
- ?line {ok,Bytes12} =
- asn1_wrapper:encode('PrimStrings','UsCon',[{47,23,99,255},{0,0,0,201}]),
- ?line {ok,[{47,23,99,255},201]} =
- asn1_wrapper:decode('PrimStrings','UsCon',lists:flatten(Bytes12)),
-
+ roundtrip('UsCon',
+ [{47,23,99,255},{0,0,0,201}],
+ [{47,23,99,255},201]),
roundtrip('UsCon', "Universal String"),
roundtrip('UsCon', []),
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line {ok,[{47,23,99,255},{0,0,2,201}]} =
- asn1_wrapper:decode('PrimStrings','UsCon',lists:flatten([16#BF,16#46,12,28,4,47,23,99,255,28,4,0,0,2,201])),
- ?line {ok,[{47,23,99,255},{0,0,2,201}]} =
- asn1_wrapper:decode('PrimStrings','UsCon',lists:flatten([16#BF,16#46,16#80,28,4,47,23,99,255,28,4,0,0,2,201,0,0]));
- _ -> ok
- end,
-
+ case Rules of
+ ber ->
+ {ok,[{47,23,99,255},{0,0,2,201}]} =
+ 'PrimStrings':decode('UsCon', <<16#BF,16#46,12,28,4,47,23,99,255,28,4,0,0,2,201>>),
+ {ok,[{47,23,99,255},{0,0,2,201}]} =
+ 'PrimStrings':decode('UsCon', <<16#BF,16#46,16#80,28,4,47,23,99,255,28,4,0,0,2,201,0,0>>);
+ _ ->
+ ok
+ end,
%%==========================================================
@@ -547,25 +598,21 @@ universal_string(Rules) ->
%%==========================================================
roundtrip('UsExpCon', [{47,23,99,255},{0,0,2,201}]),
-
- ?line {ok,Bytes22} =
- asn1_wrapper:encode('PrimStrings','UsExpCon',[{47,23,99,255},{0,0,0,201}]),
- ?line {ok,[{47,23,99,255},201]} =
- asn1_wrapper:decode('PrimStrings','UsExpCon',lists:flatten(Bytes22)),
-
+ roundtrip('UsExpCon',
+ [{47,23,99,255},{0,0,0,201}],
+ [{47,23,99,255},201]),
roundtrip('UsExpCon', "Universal String"),
roundtrip('UsExpCon', []),
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line {ok,[{47,23,99,255},{0,0,2,201}]} =
- asn1_wrapper:decode('PrimStrings','UsExpCon',lists:flatten([16#BF,16#47,14,60,12,28,4,47,23,99,255,28,4,0,0,2,201])),
- ?line {ok,[{47,23,99,255},{0,0,2,201}]} =
- asn1_wrapper:decode('PrimStrings','UsExpCon',lists:flatten([16#BF,16#47,16,60,16#80,28,4,47,23,99,255,28,4,0,0,2,201,0,0]));
- _ -> ok
- end,
-
- ok.
+ case Rules of
+ ber ->
+ {ok,[{47,23,99,255},{0,0,2,201}]} =
+ 'PrimStrings':decode('UsExpCon', <<16#BF,16#47,14,60,12,28,4,47,23,99,255,28,4,0,0,2,201>>),
+ {ok,[{47,23,99,255},{0,0,2,201}]} =
+ 'PrimStrings':decode('UsExpCon', <<16#BF,16#47,16,60,16#80,28,4,47,23,99,255,28,4,0,0,2,201,0,0>>);
+ _ ->
+ ok
+ end.
bmp_string(_Rules) ->
@@ -575,12 +622,9 @@ bmp_string(_Rules) ->
%%==========================================================
roundtrip('BMP', [{0,0,99,48},{0,0,2,201}]),
-
- ?line {ok,Bytes2} =
- asn1_wrapper:encode('PrimStrings','BMP',[{0,0,0,48},{0,0,2,201}]),
- ?line {ok,[48,{0,0,2,201}]} =
- asn1_wrapper:decode('PrimStrings','BMP',lists:flatten(Bytes2)),
-
+ roundtrip('BMP',
+ [{0,0,0,48},{0,0,2,201}],
+ [48,{0,0,2,201}]),
roundtrip('BMP', "BMP String"),
roundtrip('BMP', []),
@@ -589,9 +633,6 @@ bmp_string(_Rules) ->
ok.
-
-
-
times(_Rules) ->
@@ -620,106 +661,58 @@ utf8_string(_Rules) ->
%% UTF ::= UTF8String
%%==========================================================
- %% test values in all ranges
-
- ValLbR1 = [16#00],
- ValUbR1 = [16#7f],
- ValLbR2 = [16#80],
- ValUbR2 = [16#7ff],
- ValLbR3 = [16#800],
- ValUbR3 = [16#ffff],
- ValLbR4 = [16#10000],
- ValUbR4 = [16#1fffff],
- ValLbR5 = [16#200000],
- ValUbR5 = [16#3ffffff],
- ValLbR6 = [16#4000000],
- ValUbR6 = [16#7fffffff],
-
- ?line {ok,UTF8L1} = asn1rt:utf8_list_to_binary(ValLbR1),
- ?line {ok,Bytes1} = asn1_wrapper:encode('PrimStrings','UTF',UTF8L1),
- ?line {ok,Bin1} = asn1_wrapper:decode('PrimStrings','UTF',Bytes1),
- ?line {ok,ValLbR1} = wrapper_utf8_binary_to_list(Bin1),
-
- ?line {ok,UTF8L2} = asn1rt:utf8_list_to_binary(ValUbR1),
- ?line {ok,Bytes2} = asn1_wrapper:encode('PrimStrings','UTF',UTF8L2),
- ?line {ok,Bin2} = asn1_wrapper:decode('PrimStrings','UTF',Bytes2),
- ?line {ok,ValUbR1} = wrapper_utf8_binary_to_list(Bin2),
-
- ?line {ok,UTF8L3} = asn1rt:utf8_list_to_binary(ValLbR2),
- ?line {ok,Bytes3} = asn1_wrapper:encode('PrimStrings','UTF',UTF8L3),
- ?line {ok,Bin3} = asn1_wrapper:decode('PrimStrings','UTF',Bytes3),
- ?line {ok,ValLbR2} = wrapper_utf8_binary_to_list(Bin3),
-
- ?line {ok,UTF8L4} = asn1rt:utf8_list_to_binary(ValUbR2),
- ?line {ok,Bytes4} = asn1_wrapper:encode('PrimStrings','UTF',UTF8L4),
- ?line {ok,Bin4} = asn1_wrapper:decode('PrimStrings','UTF',Bytes4),
- ?line {ok,ValUbR2} = wrapper_utf8_binary_to_list(Bin4),
-
- ?line {ok,UTF8L5} = asn1rt:utf8_list_to_binary(ValLbR3),
- ?line {ok,Bytes5} = asn1_wrapper:encode('PrimStrings','UTF',UTF8L5),
- ?line {ok,Bin5} = asn1_wrapper:decode('PrimStrings','UTF',Bytes5),
- ?line {ok,ValLbR3} = wrapper_utf8_binary_to_list(Bin5),
-
- ?line {ok,UTF8L6} = asn1rt:utf8_list_to_binary(ValUbR3),
- ?line {ok,Bytes6} = asn1_wrapper:encode('PrimStrings','UTF',UTF8L6),
- ?line {ok,Bin6} = asn1_wrapper:decode('PrimStrings','UTF',Bytes6),
- ?line {ok,ValUbR3} = wrapper_utf8_binary_to_list(Bin6),
-
- ?line {ok,UTF8L7} = asn1rt:utf8_list_to_binary(ValLbR4),
- ?line {ok,Bytes7} = asn1_wrapper:encode('PrimStrings','UTF',UTF8L7),
- ?line {ok,Bin7} = asn1_wrapper:decode('PrimStrings','UTF',Bytes7),
- ?line {ok,ValLbR4} = wrapper_utf8_binary_to_list(Bin7),
-
- ?line {ok,UTF8L8} = asn1rt:utf8_list_to_binary(ValUbR4),
- ?line {ok,Bytes8} = asn1_wrapper:encode('PrimStrings','UTF',UTF8L8),
- ?line {ok,Bin8} = asn1_wrapper:decode('PrimStrings','UTF',Bytes8),
- ?line {ok,ValUbR4} = wrapper_utf8_binary_to_list(Bin8),
-
- ?line {ok,UTF8L9} = asn1rt:utf8_list_to_binary(ValLbR5),
- ?line {ok,Bytes9} = asn1_wrapper:encode('PrimStrings','UTF',UTF8L9),
- ?line {ok,Bin9} = asn1_wrapper:decode('PrimStrings','UTF',Bytes9),
- ?line {ok,ValLbR5} = wrapper_utf8_binary_to_list(Bin9),
-
- ?line {ok,UTF8L10} = asn1rt:utf8_list_to_binary(ValUbR5),
- ?line {ok,Bytes10} = asn1_wrapper:encode('PrimStrings','UTF',UTF8L10),
- ?line {ok,Bin10} = asn1_wrapper:decode('PrimStrings','UTF',Bytes10),
- ?line {ok,ValUbR5} = wrapper_utf8_binary_to_list(Bin10),
-
- ?line {ok,UTF8L11} = asn1rt:utf8_list_to_binary(ValLbR6),
- ?line {ok,Bytes11} = asn1_wrapper:encode('PrimStrings','UTF',UTF8L11),
- ?line {ok,Bin11} = asn1_wrapper:decode('PrimStrings','UTF',Bytes11),
- ?line {ok,ValLbR6} = wrapper_utf8_binary_to_list(Bin11),
-
- ?line {ok,UTF8L12} = asn1rt:utf8_list_to_binary(ValUbR6),
- ?line {ok,Bytes12} = asn1_wrapper:encode('PrimStrings','UTF',UTF8L12),
- ?line {ok,Bin12} = asn1_wrapper:decode('PrimStrings','UTF',Bytes12),
- ?line {ok,ValUbR6} = wrapper_utf8_binary_to_list(Bin12),
-
- LVal = ValLbR1++ValUbR1++ValLbR2++ValUbR2++ValLbR3++ValUbR3++
- ValLbR4++ValUbR4++ValLbR5++ValUbR5++ValLbR6++ValUbR6,
- LongVal = LVal++LVal++LVal++LVal++LVal++LVal++LVal++"hello",
-
- ?line {ok,UTF8L13} = asn1rt:utf8_list_to_binary(LongVal),
- ?line {ok,Bytes13} = asn1_wrapper:encode('PrimStrings','UTF',UTF8L13),
- ?line {ok,Bin13} = asn1_wrapper:decode('PrimStrings','UTF',Bytes13),
- ?line {ok,LongVal} = wrapper_utf8_binary_to_list(Bin13).
+ AllRanges = [16#00,
+ 16#7f,
+ 16#80,
+ 16#7ff,
+ 16#800,
+ 16#ffff,
+ 16#10000,
+ 16#1fffff,
+ 16#200000,
+ 16#3ffffff,
+ 16#4000000,
+ 16#7fffffff],
+ [begin
+ {ok,UTF8} = asn1rt:utf8_list_to_binary([Char]),
+ {ok,[Char]} = asn1rt:utf8_binary_to_list(UTF8),
+ roundtrip('UTF', UTF8)
+ end || Char <- AllRanges],
+
+ {ok,UTF8} = asn1rt:utf8_list_to_binary(AllRanges),
+ {ok,AllRanges} = asn1rt:utf8_binary_to_list(UTF8),
+ roundtrip('UTF', UTF8),
+ ok.
+
+
+shorten_by_two(Tuple) ->
+ L = [case E of
+ [_,_|T] -> T;
+ _ -> E
+ end || E <- tuple_to_list(Tuple)],
+ list_to_tuple(L).
-wrapper_utf8_binary_to_list(L) when is_list(L) ->
- asn1rt:utf8_binary_to_list(list_to_binary(L));
-wrapper_utf8_binary_to_list(B) ->
- asn1rt:utf8_binary_to_list(B).
+p_roundtrip(Type, Value0) ->
+ Value = setelement(1, Value0, Type),
+ roundtrip(Type, Value).
roundtrip(Type, Value) ->
{ok,Encoded} = 'PrimStrings':encode(Type, Value),
{ok,Value} = 'PrimStrings':decode(Type, Encoded),
ok.
+roundtrip(Type, Value, Expected) ->
+ {ok,Encoded} = 'PrimStrings':encode(Type, Value),
+ {ok,Expected} = 'PrimStrings':decode(Type, Encoded),
+ ok.
+
bs_roundtrip(Type, Value) ->
bs_roundtrip(Type, Value, Value).
bs_roundtrip(Type, Value, Expected) ->
M = 'PrimStrings',
{ok,Encoded} = M:encode(Type, Value),
+ {ok,Encoded} = M:encode(Type, Expected),
case M:decode(Type, Encoded) of
{ok,Expected} ->
ok;
diff --git a/lib/asn1/test/testSeqOf.erl b/lib/asn1/test/testSeqOf.erl
index 1aa1eab26d..c1af0d7a32 100644
--- a/lib/asn1/test/testSeqOf.erl
+++ b/lib/asn1/test/testSeqOf.erl
@@ -28,193 +28,110 @@
-record('Seq3',{bool3, seq3 = asn1_DEFAULT, int3}).
-record('Seq4',{seq41 = asn1_DEFAULT, seq42 = asn1_DEFAULT, seq43 = asn1_DEFAULT}).
-record('SeqIn',{boolIn, intIn}).
-%-record('SeqCho',{bool1, int1, seq1 = asn1_DEFAULT}).
-%-record('SeqChoInline',{bool1, int1, seq1 = asn1_DEFAULT}).
-%-record('SeqChoOfInline_SEQOF',{bool1, int1, seq1 = asn1_DEFAULT}).
-record('SeqEmp',{seq1}).
-record('Empty',{}).
-main(Rules) ->
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SeqOf','Seq1',#'Seq1'{bool1 = true,
- int1 = 17}),
- ?line {ok,{'Seq1',true,17,[]}} =
- asn1_wrapper:decode('SeqOf','Seq1',lists:flatten(Bytes11)),
-
-
- ?line {ok,Bytes12} =
- asn1_wrapper:encode('SeqOf','Seq1',#'Seq1'{bool1 = true,
- int1 = 17,
- seq1 = [#'SeqIn'{boolIn = true,
- intIn = 25}]}),
- ?line {ok,{'Seq1',true,17,[{'SeqIn',true,25}]}} =
- asn1_wrapper:decode('SeqOf','Seq1',lists:flatten(Bytes12)),
-
-
-
- ?line {ok,Bytes13} =
- asn1_wrapper:encode('SeqOf','Seq1',#'Seq1'{bool1 = true,
- int1 = 17,
- seq1 = [#'SeqIn'{boolIn = true,
- intIn = 25},
- #'SeqIn'{boolIn = false,
- intIn = 125},
- #'SeqIn'{boolIn = false,
- intIn = 225}]}),
- ?line {ok,{'Seq1',true,17,[{'SeqIn',true,25},{'SeqIn',false,125},{'SeqIn',false,225}]}} =
- asn1_wrapper:decode('SeqOf','Seq1',lists:flatten(Bytes13)),
-
-
-
-
-
-
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('SeqOf','Seq2',#'Seq2'{bool2 = true,
- int2 = 17}),
-
- ?line {ok,{'Seq2',[],true,17}} =
- asn1_wrapper:decode('SeqOf','Seq2',lists:flatten(Bytes21)),
-
-
- ?line {ok,Bytes22} =
- asn1_wrapper:encode('SeqOf','Seq2',#'Seq2'{bool2 = true,
- int2 = 17,
- seq2 = [#'SeqIn'{boolIn = true,
- intIn = 25}]}),
- ?line {ok,{'Seq2',[{'SeqIn',true,25}],true,17}} =
- asn1_wrapper:decode('SeqOf','Seq2',lists:flatten(Bytes22)),
-
-
- ?line {ok,Bytes23} =
- asn1_wrapper:encode('SeqOf','Seq2',#'Seq2'{bool2 = true,
- int2 = 17,
- seq2 = [#'SeqIn'{boolIn = true,
- intIn = 25},
- #'SeqIn'{boolIn = false,
- intIn = 125},
- #'SeqIn'{boolIn = false,
- intIn = 225}]}),
- ?line {ok,{'Seq2',[{'SeqIn',true,25},{'SeqIn',false,125},{'SeqIn',false,225}],true,17}} =
- asn1_wrapper:decode('SeqOf','Seq2',lists:flatten(Bytes23)),
-
-
-
-
-
-
- ?line {ok,Bytes31} =
- asn1_wrapper:encode('SeqOf','Seq3',#'Seq3'{bool3 = true,
- int3 = 17}),
- ?line {ok,{'Seq3',true,[],17}} =
- asn1_wrapper:decode('SeqOf','Seq3',lists:flatten(Bytes31)),
-
-
- ?line {ok,Bytes32} =
- asn1_wrapper:encode('SeqOf','Seq3',#'Seq3'{bool3 = true,
- int3 = 17,
- seq3 = [#'SeqIn'{boolIn = true,
- intIn = 25}]}),
- ?line {ok,{'Seq3',true,[{'SeqIn',true,25}],17}} =
- asn1_wrapper:decode('SeqOf','Seq3',lists:flatten(Bytes32)),
-
-
- ?line {ok,Bytes33} =
- asn1_wrapper:encode('SeqOf','Seq3',#'Seq3'{bool3 = true,
- int3 = 17,
- seq3 = [#'SeqIn'{boolIn = true,
- intIn = 25},
- #'SeqIn'{boolIn = false,
- intIn = 125},
- #'SeqIn'{boolIn = false,
- intIn = 225}]}),
- ?line {ok,{'Seq3',true,[{'SeqIn',true,25},{'SeqIn',false,125},{'SeqIn',false,225}],17}} =
- asn1_wrapper:decode('SeqOf','Seq3',lists:flatten(Bytes33)),
-
-
+main(_Rules) ->
+ SeqIn3 = [#'SeqIn'{boolIn=true,intIn=25},
+ #'SeqIn'{boolIn=false,intIn=125},
+ #'SeqIn'{boolIn=false,intIn=225}],
+
+ roundtrip('Seq1', #'Seq1'{bool1=true,int1=17},
+ #'Seq1'{bool1=true,int1=17,seq1=[]}),
+
+ roundtrip('Seq1', #'Seq1'{bool1=true,int1 = 17,
+ seq1=[#'SeqIn'{boolIn=true,
+ intIn=25}]}),
+ roundtrip('Seq1', #'Seq1'{bool1=true,
+ int1=17,
+ seq1=SeqIn3}),
+
+ roundtrip('Seq2', #'Seq2'{bool2=true,int2=17},
+ #'Seq2'{seq2=[],bool2=true,int2=17}),
+ roundtrip('Seq2',#'Seq2'{bool2=true,int2=17,
+ seq2=[#'SeqIn'{boolIn=true,
+ intIn=25}]}),
+ roundtrip('Seq2', #'Seq2'{bool2=true,
+ int2=17,
+ seq2=SeqIn3}),
+
+ roundtrip('Seq3', #'Seq3'{bool3=true,int3=17},
+ #'Seq3'{bool3=true,seq3=[],int3=17}),
+ roundtrip('Seq3',#'Seq3'{bool3=true,
+ int3=17,
+ seq3=[#'SeqIn'{boolIn=true,
+ intIn=25}]}),
+ roundtrip('Seq3', #'Seq3'{bool3=true,int3=17,seq3=SeqIn3}),
+
+ roundtrip('Seq4', #'Seq4'{}, #'Seq4'{seq41=[],seq42=[],seq43=[]}),
+
+ roundtrip('Seq4', #'Seq4'{seq41=[#'SeqIn'{boolIn=true,intIn=25}]},
+ #'Seq4'{seq41=[#'SeqIn'{boolIn=true,intIn=25}],
+ seq42=[],seq43=[]}),
+
+ roundtrip('Seq4', #'Seq4'{seq41=SeqIn3},
+ #'Seq4'{seq41=SeqIn3,seq42=[],seq43=[]}),
+ roundtrip('Seq4', #'Seq4'{seq42=[#'SeqIn'{boolIn=true,intIn=25}]},
+ #'Seq4'{seq41=[],seq42=[#'SeqIn'{boolIn=true,intIn=25}],
+ seq43=[]}),
+ roundtrip('Seq4', #'Seq4'{seq42=SeqIn3},
+ #'Seq4'{seq41=[],seq42=SeqIn3,seq43=[]}),
+
+ roundtrip('Seq4', #'Seq4'{seq43=[#'SeqIn'{boolIn=true,intIn=25}]},
+ #'Seq4'{seq41=[],seq42=[],
+ seq43=[#'SeqIn'{boolIn=true,intIn=25}]}),
+ roundtrip('Seq4', #'Seq4'{seq43=SeqIn3},
+ #'Seq4'{seq41=[],seq42=[],
+ seq43=SeqIn3}),
+
+ roundtrip('SeqEmp', #'SeqEmp'{seq1=[#'Empty'{}]}),
+
+ %% Test constrained, extensible size.
+
+ SeqIn = #'SeqIn'{boolIn=true,intIn=978654321},
+ roundtrip('SeqExt', {'SeqExt',true,[],true,[],789}),
+ roundtrip('SeqExt', {'SeqExt',true,lists:duplicate(1, SeqIn),
+ true,lists:duplicate(0, SeqIn),777}),
+ roundtrip('SeqExt', {'SeqExt',true,lists:duplicate(1, SeqIn),
+ true,lists:duplicate(1, SeqIn),777}),
+ roundtrip('SeqExt', {'SeqExt',true,lists:duplicate(1, SeqIn),
+ true,lists:duplicate(127, SeqIn),777}),
+ roundtrip('SeqExt', {'SeqExt',true,lists:duplicate(2, SeqIn),
+ true,lists:duplicate(128, SeqIn),1777}),
+ roundtrip('SeqExt', {'SeqExt',true,lists:duplicate(2, SeqIn),
+ true,lists:duplicate(255, SeqIn),7773}),
+ roundtrip('SeqExt', {'SeqExt',true,lists:duplicate(2, SeqIn),
+ true,lists:duplicate(256, SeqIn),77755}),
+ roundtrip('SeqExt', {'SeqExt',true,lists:duplicate(2, SeqIn),
+ true,lists:duplicate(257, SeqIn),8888}),
+ roundtrip('SeqExt', {'SeqExt',true,lists:duplicate(3, SeqIn),
+ true,lists:duplicate(1024, SeqIn),999988888}),
+ roundtrip('SeqExt', {'SeqExt',true,lists:duplicate(15, SeqIn),
+ true,lists:duplicate(2000, SeqIn),555555}),
+
+ %% Test OTP-4590: correct encoding of the length of SEQUENC OF.
+ DayNames = ["Monday","Tuesday","Wednesday",
+ "Thursday","Friday","Saturday","Sunday"],
+ xroundtrip('DayNames1', 'DayNames3', DayNames),
+ xroundtrip('DayNames2', 'DayNames4', DayNames),
+ xroundtrip('DayNames2', 'DayNames4', [hd(DayNames)]),
+ xroundtrip('DayNames2', 'DayNames4', tl(DayNames)),
+ ok.
+roundtrip(T, V) ->
+ roundtrip(T, V, V).
-
-
- ?line {ok,Bytes41} = asn1_wrapper:encode('SeqOf','Seq4',#'Seq4'{}),
- ?line {ok,{'Seq4',[],[],[]}} = asn1_wrapper:decode('SeqOf','Seq4',lists:flatten(Bytes41)),
-
-
- ?line {ok,Bytes42} =
- asn1_wrapper:encode('SeqOf','Seq4',#'Seq4'{seq41 = [#'SeqIn'{boolIn = true,
- intIn = 25}]}),
- ?line {ok,{'Seq4',[{'SeqIn',true,25}],[],[]}} =
- asn1_wrapper:decode('SeqOf','Seq4',lists:flatten(Bytes42)),
-
-
- ?line {ok,Bytes43} =
- asn1_wrapper:encode('SeqOf','Seq4',#'Seq4'{seq41 = [#'SeqIn'{boolIn = true,
- intIn = 25},
- #'SeqIn'{boolIn = false,
- intIn = 125},
- #'SeqIn'{boolIn = false,
- intIn = 225}]}),
- ?line {ok,{'Seq4',[{'SeqIn',true,25},{'SeqIn',false,125},{'SeqIn',false,225}],[],[]}} =
- asn1_wrapper:decode('SeqOf','Seq4',lists:flatten(Bytes43)),
-
-
- ?line {ok,Bytes44} =
- asn1_wrapper:encode('SeqOf','Seq4',#'Seq4'{seq42 = [#'SeqIn'{boolIn = true,
- intIn = 25}]}),
- ?line {ok,{'Seq4',[],[{'SeqIn',true,25}],[]}} =
- asn1_wrapper:decode('SeqOf','Seq4',lists:flatten(Bytes44)),
-
-
- ?line {ok,Bytes45} =
- asn1_wrapper:encode('SeqOf','Seq4',#'Seq4'{seq42 = [#'SeqIn'{boolIn = true,
- intIn = 25},
- #'SeqIn'{boolIn = false,
- intIn = 125},
- #'SeqIn'{boolIn = false,
- intIn = 225}]}),
- ?line {ok,{'Seq4',[],[{'SeqIn',true,25},{'SeqIn',false,125},{'SeqIn',false,225}],[]}} =
- asn1_wrapper:decode('SeqOf','Seq4',lists:flatten(Bytes45)),
-
-
- ?line {ok,Bytes46} =
- asn1_wrapper:encode('SeqOf','Seq4',#'Seq4'{seq43 = [#'SeqIn'{boolIn = true,
- intIn = 25}]}),
- ?line {ok,{'Seq4',[],[],[{'SeqIn',true,25}]}} =
- asn1_wrapper:decode('SeqOf','Seq4',lists:flatten(Bytes46)),
-
-
- ?line {ok,Bytes47} =
- asn1_wrapper:encode('SeqOf','Seq4',#'Seq4'{seq43 = [#'SeqIn'{boolIn = true,
- intIn = 25},
- #'SeqIn'{boolIn = false,
- intIn = 125},
- #'SeqIn'{boolIn = false,
- intIn = 225}]}),
- ?line {ok,{'Seq4',[],[],[{'SeqIn',true,25},{'SeqIn',false,125},{'SeqIn',false,225}]}} =
- asn1_wrapper:decode('SeqOf','Seq4',lists:flatten(Bytes47)),
-
-
- ?line {ok,Bytes51} = asn1_wrapper:encode('SeqOf','SeqEmp',#'SeqEmp'{seq1 = [#'Empty'{}]}),
- ?line {ok,{'SeqEmp',[{'Empty'}]}} = asn1_wrapper:decode('SeqOf','SeqEmp',lists:flatten(Bytes51)),
-
- %% tests of OTP-4590
- case Rules of
- per ->
- DayNames = ["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],
- ?line {ok,Bytes60} = asn1_wrapper:encode('XSeqOf','DayNames2',DayNames),
- ?line {ok,Bytes60} = asn1_wrapper:encode('XSeqOf','DayNames4',DayNames),
- ?line {ok,DayNames} = asn1_wrapper:decode('XSeqOf','DayNames2',Bytes60),
- ?line {ok,DayNames} = asn1_wrapper:decode('XSeqOf','DayNames4',Bytes60),
- ?line {ok,Bytes61} = asn1_wrapper:encode('XSeqOf','DayNames1',DayNames),
- ?line {ok,Bytes61} = asn1_wrapper:encode('XSeqOf','DayNames3',DayNames),
- ?line {ok,DayNames} = asn1_wrapper:decode('XSeqOf','DayNames1',Bytes61),
- ?line {ok,DayNames} = asn1_wrapper:decode('XSeqOf','DayNames3',Bytes61);
- _ ->
- ok
- end,
-
+roundtrip(Type, Val, Expected) ->
+ M = 'SeqOf',
+ {ok,Enc} = M:encode(Type, Val),
+ {ok,Expected} = M:decode(Type, Enc),
ok.
-
+xroundtrip(T1, T2, Val) ->
+ M = 'XSeqOf',
+ {ok,Enc} = M:encode(T1, Val),
+ {ok,Enc} = M:encode(T2, Val),
+ {ok,Val} = M:decode(T1, Enc),
+ {ok,Val} = M:decode(T2, Enc),
+ ok.
diff --git a/lib/common_test/src/ct_config.erl b/lib/common_test/src/ct_config.erl
index c35cbd3c08..9bb9817001 100644
--- a/lib/common_test/src/ct_config.erl
+++ b/lib/common_test/src/ct_config.erl
@@ -599,7 +599,7 @@ encrypt_config_file(SrcFileName, EncryptFileName, {file,KeyFile}) ->
encrypt_config_file(SrcFileName, EncryptFileName, {key,Key}) ->
crypto:start(),
- {K1,K2,K3,IVec} = make_crypto_key(Key),
+ {Key,IVec} = make_crypto_key(Key),
case file:read_file(SrcFileName) of
{ok,Bin0} ->
Bin1 = term_to_binary({SrcFileName,Bin0}),
@@ -607,7 +607,7 @@ encrypt_config_file(SrcFileName, EncryptFileName, {key,Key}) ->
0 -> Bin1;
N -> list_to_binary([Bin1,random_bytes(8-N)])
end,
- EncBin = crypto:des3_cbc_encrypt(K1, K2, K3, IVec, Bin2),
+ EncBin = crypto:block_encrypt(des3_cbc, Key, IVec, Bin2),
case file:write_file(EncryptFileName, EncBin) of
ok ->
io:format("~ts --(encrypt)--> ~ts~n",
@@ -638,10 +638,10 @@ decrypt_config_file(EncryptFileName, TargetFileName, {file,KeyFile}) ->
decrypt_config_file(EncryptFileName, TargetFileName, {key,Key}) ->
crypto:start(),
- {K1,K2,K3,IVec} = make_crypto_key(Key),
+ {Key,IVec} = make_crypto_key(Key),
case file:read_file(EncryptFileName) of
{ok,Bin} ->
- DecBin = crypto:des3_cbc_decrypt(K1, K2, K3, IVec, Bin),
+ DecBin = crypto:block_decrypt(des3_cbc, Key, IVec, Bin),
case catch binary_to_term(DecBin) of
{'EXIT',_} ->
{error,bad_file};
@@ -713,7 +713,7 @@ get_crypt_key_from_file() ->
make_crypto_key(String) ->
<<K1:8/binary,K2:8/binary>> = First = erlang:md5(String),
<<K3:8/binary,IVec:8/binary>> = erlang:md5([First|lists:reverse(String)]),
- {K1,K2,K3,IVec}.
+ {[K1,K2,K3],IVec}.
random_bytes(N) ->
{A,B,C} = now(),
diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl
index 6a8b37bf3b..b77845eb5b 100644
--- a/lib/common_test/src/ct_util.erl
+++ b/lib/common_test/src/ct_util.erl
@@ -421,6 +421,8 @@ loop(Mode,TestData,StartDir) ->
"Reason: ~p\n\n",
[Pid,A,CB,Reason]),
catch CB:close(Pid),
+ %% in case CB:close failed to do this:
+ unregister_connection(Pid),
loop(Mode,TestData,StartDir);
_ ->
%% Let process crash in case of error, this shouldn't happen!
diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
index 54526e8e83..0535eb924b 100644
--- a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
+++ b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012. All Rights Reserved.
+%% Copyright Ericsson AB 2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1035,10 +1035,12 @@ make_dsa_files(Config, Type) ->
file:write_file(DSAPrivateFile, PemBin),
ok.
+
%%--------------------------------------------------------------------
-%% Creates a dsa key (OBS: for testing only)
+%% @doc Creates a dsa key (OBS: for testing only)
%% the sizes are in bytes
-%% gen_dsa(::integer()) -> {::atom(), ::binary(), ::opaque()}
+%% @spec (::integer()) -> {::atom(), ::binary(), ::opaque()}
+%% @end
%%--------------------------------------------------------------------
gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) ->
Key = gen_dsa2(LSize, NSize),
@@ -1048,7 +1050,6 @@ encode_key(Key = #'DSAPrivateKey'{}) ->
Der = public_key:der_encode('DSAPrivateKey', Key),
{'DSAPrivateKey', Der, not_encrypted}.
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% DSA key generation (OBS: for testing only)
%% See http://en.wikipedia.org/wiki/Digital_Signature_Algorithm
@@ -1058,67 +1059,70 @@ gen_dsa2(LSize, NSize) ->
Q = prime(NSize), %% Choose N-bit prime Q
X0 = prime(LSize),
P0 = prime((LSize div 2) +1),
-
+
%% Choose L-bit prime modulus P such that p-1 is a multiple of q.
case dsa_search(X0 div (2*Q*P0), P0, Q, 1000) of
- error ->
+ error ->
gen_dsa2(LSize, NSize);
- P ->
- G = crypto:mod_exp(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q.
+ P ->
+ G = crypto:mod_pow(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q.
%% such that This may be done by setting g = h^(p-1)/q mod p, commonly h=2 is used.
-
+
X = prime(20), %% Choose x by some random method, where 0 < x < q.
- Y = crypto:mod_exp(G, X, P), %% Calculate y = g^x mod p.
-
- #'DSAPrivateKey'{version=0, p=P, q=Q, g=G, y=Y, x=X}
+ Y = crypto:mod_pow(G, X, P), %% Calculate y = g^x mod p.
+
+ #'DSAPrivateKey'{version=0, p = P, q = Q,
+ g = crypto:bytes_to_integer(G), y = crypto:bytes_to_integer(Y), x = X}
end.
-
+
%% See fips_186-3.pdf
dsa_search(T, P0, Q, Iter) when Iter > 0 ->
P = 2*T*Q*P0 + 1,
- case is_prime(crypto:mpint(P), 50) of
+ case is_prime(P, 50) of
true -> P;
false -> dsa_search(T+1, P0, Q, Iter-1)
end;
-dsa_search(_,_,_,_) ->
+dsa_search(_,_,_,_) ->
error.
%%%%%%% Crypto Math %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
prime(ByteSize) ->
Rand = odd_rand(ByteSize),
- crypto:erlint(prime_odd(Rand, 0)).
+ prime_odd(Rand, 0).
prime_odd(Rand, N) ->
case is_prime(Rand, 50) of
- true ->
+ true ->
Rand;
- false ->
- NotPrime = crypto:erlint(Rand),
- prime_odd(crypto:mpint(NotPrime+2), N+1)
+ false ->
+ prime_odd(Rand+2, N+1)
end.
%% see http://en.wikipedia.org/wiki/Fermat_primality_test
is_prime(_, 0) -> true;
-is_prime(Candidate, Test) ->
- CoPrime = odd_rand(<<0,0,0,4, 10000:32>>, Candidate),
- case crypto:mod_exp(CoPrime, Candidate, Candidate) of
- CoPrime -> is_prime(Candidate, Test-1);
- _ -> false
- end.
+is_prime(Candidate, Test) ->
+ CoPrime = odd_rand(10000, Candidate),
+ Result = crypto:mod_pow(CoPrime, Candidate, Candidate) ,
+ is_prime(CoPrime, crypto:bytes_to_integer(Result), Candidate, Test).
+
+is_prime(CoPrime, CoPrime, Candidate, Test) ->
+ is_prime(Candidate, Test-1);
+is_prime(_,_,_,_) ->
+ false.
odd_rand(Size) ->
Min = 1 bsl (Size*8-1),
Max = (1 bsl (Size*8))-1,
- odd_rand(crypto:mpint(Min), crypto:mpint(Max)).
+ odd_rand(Min, Max).
odd_rand(Min,Max) ->
- Rand = <<Sz:32, _/binary>> = crypto:rand_uniform(Min,Max),
- BitSkip = (Sz+4)*8-1,
- case Rand of
- Odd = <<_:BitSkip, 1:1>> -> Odd;
- Even = <<_:BitSkip, 0:1>> ->
- crypto:mpint(crypto:erlint(Even)+1)
+ Rand = crypto:rand_uniform(Min,Max),
+ case Rand rem 2 of
+ 0 ->
+ Rand + 1;
+ _ ->
+ Rand
end.
copyfile(SrcDir, DstDir, Fn) ->
diff --git a/lib/common_test/test/ct_telnet_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE.erl
index 17617f59eb..e2ee207754 100644
--- a/lib/common_test/test/ct_telnet_SUITE.erl
+++ b/lib/common_test/test/ct_telnet_SUITE.erl
@@ -72,7 +72,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[
unix_telnet,
- own_server
+ own_server,
+ timetrap
].
%%--------------------------------------------------------------------
@@ -88,6 +89,10 @@ own_server(Config) ->
all_tests_in_suite(own_server,"ct_telnet_own_server_SUITE",
"telnet2.cfg",Config).
+timetrap(Config) ->
+ all_tests_in_suite(timetrap,"ct_telnet_timetrap_SUITE",
+ "telnet3.cfg",Config).
+
%%%-----------------------------------------------------------------
%%% HELP FUNCTIONS
%%%-----------------------------------------------------------------
@@ -143,7 +148,13 @@ telnet_config(_) ->
events_to_check(unix_telnet,Config) ->
all_cases(ct_telnet_basic_SUITE,Config);
events_to_check(own_server,Config) ->
- all_cases(ct_telnet_own_server_SUITE,Config).
+ all_cases(ct_telnet_own_server_SUITE,Config);
+events_to_check(timetrap,_Config) ->
+ [{?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,tc_done,{ct_telnet_timetrap_SUITE,expect_timetrap,
+ {failed,{timetrap_timeout,7000}}}},
+ {?eh,tc_done,{ct_telnet_timetrap_SUITE,expect_success,ok}},
+ {?eh,stop_logging,[]}].
all_cases(Suite,Config) ->
{module,_} = code:load_abs(filename:join(?config(data_dir,Config),
diff --git a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_timetrap_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_timetrap_SUITE.erl
new file mode 100644
index 0000000000..f274fb9112
--- /dev/null
+++ b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_timetrap_SUITE.erl
@@ -0,0 +1,76 @@
+-module(ct_telnet_timetrap_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+-define(name,erl_telnet_server).
+
+%%--------------------------------------------------------------------
+%% TEST SERVER CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+suite() -> [{require,?name,{unix,[telnet]}},
+ {timetrap,{seconds,7}}].
+
+all() ->
+ [expect_timetrap,
+ expect_success].
+
+groups() ->
+ [].
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+init_per_testcase(_,Config) ->
+ ct:log("init_per_testcase: opening telnet connection...",[]),
+ {ok,_} = ct_telnet:open(?name),
+ ct:log("...done",[]),
+ Config.
+
+end_per_testcase(_,_Config) ->
+ ct:log("end_per_testcase: closing telnet connection...",[]),
+ _ = ct_telnet:close(?name),
+ ct:log("...done",[]),
+ ok.
+
+
+%% OTP-10648
+%% This test case should fail with timetrap timeout.
+%%
+%% The long timetrap timeout and timeout option in the expect call
+%% also causes the telnet client to hang so long that the attempt at
+%% closing it (in end_per_testcase) will time out (close timeout is 5
+%% sec) without a timetrap timeout occuring in end_per_testcase.
+%%
+%% The point is to see that the connection is thoroughly removed and
+%% unregistered anyway so that the next test case can successfully
+%% open a connection with the same name.
+%%
+%% Note!!! that if end_per_testcase reaches a timetrap timeout before
+%% the connection is closed, then the connection will survive until
+%% the hanging expect times out, after which it will be closed in a
+%% seemingly normal way due to the close message which was sent by the
+%% close attempt. This could happen any time during the subsequent
+%% test cases and cause confusion... There is however not much to do
+%% about this, except writing test cases with timetrap timeout longer
+%% than the close timeout (as this test case does)
+expect_timetrap(_) ->
+ {error,timeout} = ct_telnet:expect(?name, ["ayt"], [{timeout,20000}]),
+ ok.
+
+%% This should succeed
+expect_success(_) ->
+ ok = ct_telnet:send(?name, "echo ayt"),
+ {ok,["ayt"]} = ct_telnet:expect(?name, ["ayt"]),
+ ok.
diff --git a/lib/compiler/src/beam_a.erl b/lib/compiler/src/beam_a.erl
index 1c51226314..b348e854a0 100644
--- a/lib/compiler/src/beam_a.erl
+++ b/lib/compiler/src/beam_a.erl
@@ -70,8 +70,8 @@ rename_instr({bs_put_utf16=I,F,Fl,Src}) ->
{bs_put,F,{I,Fl},[Src]};
rename_instr({bs_put_utf32=I,F,Fl,Src}) ->
{bs_put,F,{I,Fl},[Src]};
-%% rename_instr({bs_put_string,_,_}=I) ->
-%% {bs_put,{f,0},I,[]};
+rename_instr({bs_put_string,_,_}=I) ->
+ {bs_put,{f,0},I,[]};
rename_instr({bs_add=I,F,[Src1,Src2,U],Dst}) when is_integer(U) ->
{bif,I,F,[Src1,Src2,{integer,U}],Dst};
rename_instr({bs_utf8_size=I,F,Src,Dst}) ->
diff --git a/lib/compiler/src/beam_utils.erl b/lib/compiler/src/beam_utils.erl
index 554c14f57a..e623bcc6a5 100644
--- a/lib/compiler/src/beam_utils.erl
+++ b/lib/compiler/src/beam_utils.erl
@@ -734,6 +734,8 @@ live_opt([{loop_rec,_Fail,_Dst}=I|Is], _, D, Acc) ->
live_opt(Is, 0, D, [I|Acc]);
live_opt([timeout=I|Is], _, D, Acc) ->
live_opt(Is, 0, D, [I|Acc]);
+live_opt([{wait,_}=I|Is], _, D, Acc) ->
+ live_opt(Is, 0, D, [I|Acc]);
%% Transparent instructions - they neither use nor modify x registers.
live_opt([{deallocate,_}=I|Is], Regs, D, Acc) ->
@@ -744,8 +746,6 @@ live_opt([{try_end,_}=I|Is], Regs, D, Acc) ->
live_opt(Is, Regs, D, [I|Acc]);
live_opt([{loop_rec_end,_}=I|Is], Regs, D, Acc) ->
live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{wait,_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
live_opt([{wait_timeout,_,{Tag,_}}=I|Is], Regs, D, Acc) when Tag =/= x ->
live_opt(Is, Regs, D, [I|Acc]);
live_opt([{line,_}=I|Is], Regs, D, Acc) ->
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index 745f1d5cf9..2ca403de54 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -1197,9 +1197,9 @@ abstract_code(#compile{code=Code,options=Opts,ofile=OFile}) ->
encrypt_abs_code(Abstr, Key0) ->
try
- {Mode,RealKey} = generate_key(Key0),
+ RealKey = generate_key(Key0),
case start_crypto() of
- ok -> {ok,encrypt(Mode, RealKey, Abstr)};
+ ok -> {ok,encrypt(RealKey, Abstr)};
{error,_}=E -> E
end
catch
@@ -1216,19 +1216,19 @@ start_crypto() ->
{error,[{none,?MODULE,no_crypto}]}
end.
-generate_key({Mode,String}) when is_atom(Mode), is_list(String) ->
- {Mode,beam_lib:make_crypto_key(Mode, String)};
+generate_key({Type,String}) when is_atom(Type), is_list(String) ->
+ beam_lib:make_crypto_key(Type, String);
generate_key(String) when is_list(String) ->
generate_key({des3_cbc,String}).
-encrypt(des3_cbc=Mode, {K1,K2,K3, IVec}, Bin0) ->
- Bin1 = case byte_size(Bin0) rem 8 of
+encrypt({des3_cbc=Type,Key,IVec,BlockSize}, Bin0) ->
+ Bin1 = case byte_size(Bin0) rem BlockSize of
0 -> Bin0;
- N -> list_to_binary([Bin0,random_bytes(8-N)])
+ N -> list_to_binary([Bin0,random_bytes(BlockSize-N)])
end,
- Bin = crypto:des3_cbc_encrypt(K1, K2, K3, IVec, Bin1),
- ModeString = atom_to_list(Mode),
- list_to_binary([0,length(ModeString),ModeString,Bin]).
+ Bin = crypto:block_encrypt(Type, Key, IVec, Bin1),
+ TypeString = atom_to_list(Type),
+ list_to_binary([0,length(TypeString),TypeString,Bin]).
random_bytes(N) ->
{A,B,C} = now(),
diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl
index 229e5a98a1..c635d13c89 100644
--- a/lib/compiler/test/compile_SUITE.erl
+++ b/lib/compiler/test/compile_SUITE.erl
@@ -492,6 +492,16 @@ encrypted_abstr_1(Simple, Target) ->
?line {error,beam_lib,{key_missing_or_invalid,"simple.beam",abstract_code}} =
beam_lib:chunks("simple.beam", [abstract_code]),
?line ok = file:set_cwd(OldCwd),
+
+ %% Test key compatibility by reading a BEAM file produced before
+ %% the update to the new crypto functions.
+ install_crypto_key("an old key"),
+ KeyCompat = filename:join(filename:dirname(Simple),
+ "key_compatibility"),
+ {ok,{key_compatibility,[Chunk]}} = beam_lib:chunks(KeyCompat,
+ [abstract_code]),
+ {abstract_code,{raw_abstract_v1,_}} = Chunk,
+
ok.
diff --git a/lib/compiler/test/compile_SUITE_data/key_compatibility.beam b/lib/compiler/test/compile_SUITE_data/key_compatibility.beam
new file mode 100644
index 0000000000..28329d2423
--- /dev/null
+++ b/lib/compiler/test/compile_SUITE_data/key_compatibility.beam
Binary files differ
diff --git a/lib/compiler/test/compile_SUITE_data/key_compatibility.erl b/lib/compiler/test/compile_SUITE_data/key_compatibility.erl
new file mode 100644
index 0000000000..e2931f1b12
--- /dev/null
+++ b/lib/compiler/test/compile_SUITE_data/key_compatibility.erl
@@ -0,0 +1,8 @@
+-module(key_compatibility).
+-export([main/0]).
+
+%% Compile like this:
+%% erlc +'{debug_info_key,"an old key"}' key_compatibility.erl
+
+main() ->
+ ok.
diff --git a/lib/compiler/test/receive_SUITE.erl b/lib/compiler/test/receive_SUITE.erl
index e60584d4ab..ec49267ded 100644
--- a/lib/compiler/test/receive_SUITE.erl
+++ b/lib/compiler/test/receive_SUITE.erl
@@ -23,7 +23,8 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
- export/1,recv/1,coverage/1,otp_7980/1,ref_opt/1]).
+ export/1,recv/1,coverage/1,otp_7980/1,ref_opt/1,
+ wait/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -44,7 +45,7 @@ all() ->
groups() ->
[{p,test_lib:parallel(),
- [recv,coverage,otp_7980,ref_opt,export]}].
+ [recv,coverage,otp_7980,ref_opt,export,wait]}].
init_per_suite(Config) ->
@@ -252,4 +253,20 @@ export_1(Reference) ->
id({build,self()}),
Result.
+wait(Config) when is_list(Config) ->
+ self() ! <<42>>,
+ <<42>> = wait_1(r, 1, 2),
+ {1,2,3} = wait_1(1, 2, 3),
+ ok.
+
+wait_1(r, _, _) ->
+ receive
+ B when byte_size(B) > 0 ->
+ B
+ end;
+%% beam_utils would wrongly assume that wait/1 could fall through
+%% to the next clause.
+wait_1(A, B, C) ->
+ {A,B,C}.
+
id(I) -> I.
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 9d43a1d907..98ebb21f29 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -3087,7 +3087,7 @@ static ERL_NIF_TERM ec_key_to_term_nif(ErlNifEnv* env, int argc, const ERL_NIF_T
pub_key = point2term(env, group, public_key, EC_KEY_get_conv_form(obj->key));
}
- return enif_make_tuple2(env, bn2term(env, priv_key), pub_key);
+ return enif_make_tuple2(env, pub_key, bn2term(env, priv_key));
#else
return atom_notsup;
#endif
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index df765ade87..bdccfee341 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -60,6 +60,7 @@
<title>DATA TYPES </title>
<p><code>key_value() = integer() | binary() </code></p>
+ <p>Always <c>binary()</c> when used as return value</p>
<p><code>rsa_public() = [key_value()] = [E, N] </code></p>
<p> Where E is the public exponent and N is public modulus. </p>
@@ -77,21 +78,14 @@
<p><code>dss_private() = [key_value()] = [P, Q, G, X] </code></p>
<p>Where P, Q and G are the dss parameters and X is the private key.</p>
- <p><code>dss_public() = [key_value()] =[P, Q, G, Y] </code></p>
-
- <p><code>srp_public() = key_value() </code></p>
+ <p><code>srp_public() = key_value() </code></p>
<p>Where is <c>A</c> or <c>B</c> from <url href="http://srp.stanford.edu/design.html">SRP design</url></p>
<p><code>srp_private() = key_value() </code></p>
<p>Where is <c>a</c> or <c>b</c> from <url href="http://srp.stanford.edu/design.html">SRP design</url></p>
- <p><code>srp_params() = {user, [Generator::binary(), Prime::binary(), Version::atom()]} |
- {host, [Verifier::binary(), Generator::binary(), Prime::binary(), Version::atom()]}
- | {user, [DerivedKey::binary(), Prime::binary(), Generator::binary(), Version::atom() | [Scrambler:binary()]]}
- | {host,[Verifier::binary(), Prime::binary(), Version::atom() | [Scrambler::binary]]} </code></p>
-
<p>Where Verifier is <c>v</c>, Generator is <c>g</c> and Prime is<c> N</c>, DerivedKey is <c>X</c>, and Scrambler is
- <c>u</c> (optional will be genrated if not provided) from <url href="http://srp.stanford.edu/design.html">SRP design</url>
+ <c>u</c> (optional will be generated if not provided) from <url href="http://srp.stanford.edu/design.html">SRP design</url>
Version = '3' | '6' | '6a'
</p>
@@ -142,25 +136,23 @@
<p><code>des3_key() = [binary(), binary(), binary()] </code> Each key part is 64 bits (in CBC mode only 8 bits are used)</p>
- <p><code> message_digest_algorithms() = md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512 </code> md4 is aslo supported for hash_init/1 and hash/2.
+ <p><code>digest_type() = md5 | sha | sha224 | sha256 | sha384 | sha512</code></p>
+
+ <p><code> hash_algorithms() = md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512 </code> md4 is also supported for hash_init/1 and hash/2.
Note that both md4 and md5 are recommended only for compatibility with existing applications.
</p>
+ <p><code> cipher_algorithms() = des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 |
+ blowfish_cbc | blowfish_cfb64 | aes_cbc128 | aes_cfb128| aes_cbc256 | rc2_cbc | aes_ctr| rc4 </code> </p>
+ <p><code> public_key_algorithms() = rsa |dss | ecdsa | dh | ecdh </code> </p>
+
</section>
<funcs>
- <func>
- <name>algorithms() -> [message_digest_algorithms() | md4 | ec]</name>
- <fsummary>Provide a list of available crypto algorithms.</fsummary>
- <desc>
- <p> Can be used to determine if the crypto library has support for elliptic curve (ec) and
- which message digest algorithms that are supported.</p>
- </desc>
- </func>
-
<func>
<name>block_encrypt(Type, Key, Ivec, PlainText) -> CipherText</name>
<fsummary>Encrypt <c>PlainText</c>according to <c>Type</c> block cipher</fsummary>
<type>
+ <v>Type = block_cipher() </v>
<v>Key = block_key() </v>
<v>PlainText = iodata() </v>
<v>IVec = CipherText = binary()</v>
@@ -176,6 +168,7 @@
<name>block_decrypt(Type, Key, Ivec, CipherText) -> PlainText</name>
<fsummary>Decrypt <c>CipherText</c>according to <c>Type</c> block cipher</fsummary>
<type>
+ <v>Type = block_cipher() </v>
<v>Key = block_key() </v>
<v>PlainText = iodata() </v>
<v>IVec = CipherText = binary()</v>
@@ -186,15 +179,31 @@
</p>
</desc>
</func>
+
+ <func>
+ <name>bytes_to_integer(Bin) -> Integer </name>
+ <fsummary>Convert binary representation, of an integer, to an Erlang integer.</fsummary>
+ <type>
+ <v>Bin = binary() - as returned by crypto functions</v>
+
+ <v>Integer = integer() </v>
+ </type>
+ <desc>
+ <p>Convert binary representation, of an integer, to an Erlang integer.
+ </p>
+ </desc>
+ </func>
<func>
- <name>compute_key(Type, OthersPublicKey, MyPrivateKey, Params) -> SharedSecret</name>
+ <name>compute_key(Type, OthersPublicKey, MyKey, Params) -> SharedSecret</name>
<fsummary>Computes the shared secret</fsummary>
<type>
<v> Type = dh | ecdh | srp </v>
<v>OthersPublicKey = dh_public() | ecdh_public() | srp_public() </v>
- <v>MyPrivate = dh_private() | ecdh_private() | srp_private() </v>
- <v>Params = dh_params() | edhc_params() | srp_params() </v>
+ <v>MyKey = dh_private() | ecdh_private() | {srp_public(),srp_private()}</v>
+ <v>Params = dh_params() | ecdh_params() | SrpUserParams | SrpHostParams</v>
+ <v>SrpUserParams = {user, [DerivedKey::binary(), Prime::binary(), Generator::binary(), Version::atom() | [Scrambler:binary()]]} </v>
+ <v>SrpHostParams = {host, [Verifier::binary(), Prime::binary(), Version::atom() | [Scrambler::binary]]} </v>
<v>SharedSecret = binary()</v>
</type>
<desc>
@@ -217,14 +226,17 @@
</func>
<func>
- <name>generate_key(Type, Params) -> {PublicKey, PrivateKey} </name>
- <name>generate_key(Type, Params, PrivateKey) -> {PublicKey, PrivateKey} </name>
+ <name>generate_key(Type, Params) -> {PublicKey, PrivKeyOut} </name>
+ <name>generate_key(Type, Params, PrivKeyIn) -> {PublicKey, PrivKeyOut} </name>
<fsummary>Generates a public keys of type <c>Type</c></fsummary>
<type>
<v> Type = dh | ecdh | srp </v>
- <v>Params = dh_params() | edhc_params() | srp_params() </v>
+ <v>Params = dh_params() | ecdh_params() | SrpUserParams | SrpHostParams </v>
+ <v>SrpUserParams = {user, [Generator::binary(), Prime::binary(), Version::atom()]}</v>
+ <v>SrpHostParams = {host, [Verifier::binary(), Generator::binary(), Prime::binary(), Version::atom()]}</v>
<v>PublicKey = dh_public() | ecdh_public() | srp_public() </v>
- <v>PrivateKey = dh_private() | ecdh_private() | srp_private() </v>
+ <v>PrivKeyIn = undefined | dh_private() | srp_private() </v>
+ <v>PrivKeyOut = dh_private() | ecdh_private() | srp_private() </v>
</type>
<desc>
<p>Generates public keys of type <c>Type</c>.
@@ -407,16 +419,20 @@
</func>
<func>
- <name>next_iv(Type, Data) -> </name>
+ <name>next_iv(Type, Data) -> NextIVec</name>
+ <name>next_iv(Type, Data, IVec) -> NextIVec</name>
<fsummary></fsummary>
<type>
- <v>Type = des_cbc | aes_cbc</v>
+ <v>Type = des_cbc | des3_cbc | aes_cbc | des_cfb</v>
<v>Data = iodata()</v>
+ <v>IVec = NextIVec = binary()</v>
</type>
<desc>
<p>Returns the initialization vector to be used in the next
- iteration of encrypt/decrypt of type <c>Type</c>. Data is the
- encrypted data from the previous iteration step.</p>
+ iteration of encrypt/decrypt of type <c>Type</c>. <c>Data</c> is the
+ encrypted data from the previous iteration step. The <c>IVec</c>
+ argument is only needed for <c>des_cfb</c> as the vector used
+ in the previous iteration step.</p>
</desc>
</func>
@@ -549,10 +565,12 @@
signed or it is the hashed value of "plain text" i.e. the
digest.</d>
<v>DigestType = digest_type()</v>
- <v>Key = rsa_private_key() | dsa_private_key() | ec_private_key()</v>
+ <v>Key = rsa_private() | dss_private() | [ecdh_private(),ecdh_params()]</v>
</type>
<desc>
- <p> Creates a digital signature.</p>
+ <p>Creates a digital signature.</p>
+ <p>Algorithm <c>dss</c> can only be used together with digest type
+ <c>sha</c>.</p>
See also <seealso marker="public_key:public_key#sign/3">public_key:sign/3</seealso>
</desc>
</func>
@@ -591,10 +609,9 @@
<name>stream_init(Type, Key) -> State</name>
<fsummary></fsummary>
<type>
- <v>Type rc4 </v>
+ <v>Type = rc4 </v>
<v>State = opaque() </v>
<v>Key = iodata()</v>
- <v>IVec = binary()</v>
</type>
<desc>
<p>Initializes the state for use in RC4 stream encryption
@@ -607,7 +624,7 @@
<name>stream_init(Type, Key, IVec) -> State</name>
<fsummary></fsummary>
<type>
- <v>Type aes_ctr </v>
+ <v>Type = aes_ctr </v>
<v>State = opaque() </v>
<v>Key = iodata()</v>
<v>IVec = binary()</v>
@@ -651,6 +668,22 @@
</desc>
</func>
+ <func>
+ <name>supports() -> AlgorithmList </name>
+ <fsummary>Provide a list of available crypto algorithms.</fsummary>
+ <type>
+ <v> AlgorithmList = [{hashs, [hash_algorithms()]},
+ {ciphers, [cipher_algorithms()]},
+ {public_keys, [public_key_algorithms()]}
+ </v>
+ </type>
+ <desc>
+ <p> Can be used to determine which crypto algorithms that are supported
+ by the underlying OpenSSL library</p>
+ </desc>
+ </func>
+
+
<func>
<name>verify(Algorithm, DigestType, Msg, Signature, Key) -> boolean()</name>
<fsummary>Verifies a digital signature.</fsummary>
@@ -661,10 +694,13 @@
or it is the hashed value of "plain text" i.e. the digest.</d>
<v>DigestType = digest_type()</v>
<v>Signature = binary()</v>
- <v>Key = rsa_public_key() | dsa_public_key() | ec_public_key()</v>
+ <v>Key = rsa_public() | dss_public() | [ecdh_public(),ecdh_params()]</v>
</type>
<desc>
<p>Verifies a digital signature</p>
+ <p>Algorithm <c>dss</c> can only be used together with digest type
+ <c>sha</c>.</p>
+
See also <seealso marker="public_key:public_key#sign/3">public_key:verify/3</seealso>
</desc>
</func>
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index f4e157198c..e042545094 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -21,7 +21,7 @@
-module(crypto).
--export([start/0, stop/0, info_lib/0, algorithms/0, version/0]).
+-export([start/0, stop/0, info_lib/0, supports/0, version/0, bytes_to_integer/1]).
-export([hash/2, hash_init/1, hash_update/2, hash_final/1]).
-export([sign/4, verify/5]).
-export([generate_key/2, generate_key/3, compute_key/4]).
@@ -33,9 +33,9 @@
-export([stream_init/2, stream_init/3, stream_encrypt/2, stream_decrypt/2]).
-export([public_encrypt/4, private_decrypt/4]).
-export([private_encrypt/4, public_decrypt/4]).
-
-export([dh_generate_parameters/2, dh_check/1]). %% Testing see
+
%% DEPRECATED
%% Replaced by hash_*
-export([md4/1, md4_init/0, md4_update/2, md4_final/1]).
@@ -218,7 +218,7 @@
des_cbc_ivec, des_cfb_ivec,
info,
%%
- info_lib, algorithms]).
+ info_lib, supports]).
-type mpint() :: binary().
-type rsa_digest_type() :: 'md5' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'.
@@ -226,15 +226,14 @@
%%-type ecdsa_digest_type() :: 'md5' | 'sha' | 'sha256' | 'sha384' | 'sha512'.
-type data_or_digest() :: binary() | {digest, binary()}.
-type crypto_integer() :: binary() | integer().
--type ec_key_res() :: any(). %% nif resource
--type ec_named_curve() :: atom().
--type ec_point() :: crypto_integer().
--type ec_basis() :: {tpbasis, K :: non_neg_integer()} | {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()} | onbasis.
--type ec_field() :: {prime_field, Prime :: integer()} | {characteristic_two_field, M :: integer(), Basis :: ec_basis()}.
--type ec_prime() :: {A :: crypto_integer(), B :: crypto_integer(), Seed :: binary() | none}.
--type ec_curve_spec() :: {Field :: ec_field(), Prime :: ec_prime(), Point :: crypto_integer(), Order :: integer(), CoFactor :: none | integer()}.
--type ec_curve() :: ec_named_curve() | ec_curve_spec().
--type ec_key() :: {Curve :: ec_curve(), PrivKey :: binary() | undefined, PubKey :: ec_point() | undefined}.
+%%-type ec_named_curve() :: atom().
+%%-type ec_point() :: crypto_integer().
+%%-type ec_basis() :: {tpbasis, K :: non_neg_integer()} | {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()} | onbasis.
+%%-type ec_field() :: {prime_field, Prime :: integer()} | {characteristic_two_field, M :: integer(), Basis :: ec_basis()}.
+%%-type ec_prime() :: {A :: crypto_integer(), B :: crypto_integer(), Seed :: binary() | none}.
+%%-type ec_curve_spec() :: {Field :: ec_field(), Prime :: ec_prime(), Point :: crypto_integer(), Order :: integer(), CoFactor :: none | integer()}.
+%%-type ec_curve() :: ec_named_curve() | ec_curve_spec().
+%%-type ec_key() :: {Curve :: ec_curve(), PrivKey :: binary() | undefined, PubKey :: ec_point() | undefined}.
-define(nif_stub,nif_stub_error(?LINE)).
@@ -306,6 +305,22 @@ info_lib() -> ?nif_stub.
algorithms() -> ?nif_stub.
+supports()->
+ Algs = algorithms(),
+ PubKeyAlgs =
+ case lists:member(ec, Algs) of
+ true ->
+ {public_keys, [rsa, dss, ecdsa, dh, srp, ecdh]};
+ false ->
+ {public_keys, [rsa, dss, dh, srp]}
+ end,
+ [{hashs, Algs -- [ec]},
+ {ciphers, [des_cbc, des_cfb, des3_cbc, des3_cbf, des_ede3, blowfish_cbc,
+ blowfish_cfb64, blowfish_ofb64, blowfish_ecb, aes_cbc128, aes_cfb128, aes_cbc256, rc2_cbc, aes_ctr, rc4
+ ]},
+ PubKeyAlgs
+ ].
+
%% Crypto app version history:
%% (no version): Driver implementation
%% 2.0 : NIF implementation, requires OTP R14
@@ -575,7 +590,7 @@ hmac(sha384, Key, Data) -> sha384_mac(Key, Data);
hmac(sha512, Key, Data) -> sha512_mac(Key, Data).
hmac(md5, Key, Data, Size) -> md5_mac_n(Key, Data, Size);
-hmac(sha, Key, Data, Size) -> sha_mac(Key, Data, Size);
+hmac(sha, Key, Data, Size) -> sha_mac_n(Key, Data, Size);
hmac(sha224, Key, Data, Size) -> sha224_mac(Key, Data, Size);
hmac(sha256, Key, Data, Size) -> sha256_mac(Key, Data, Size);
hmac(sha384, Key, Data, Size) -> sha384_mac(Key, Data, Size);
@@ -731,7 +746,7 @@ block_decrypt(blowfish_cbc, Key, Ivec, Data) ->
blowfish_cbc_decrypt(Key, Ivec, Data);
block_decrypt(blowfish_cfb64, Key, Ivec, Data) ->
blowfish_cfb64_decrypt(Key, Ivec, Data);
-block_decrypt(blowfish_ofb, Key, Ivec, Data) ->
+block_decrypt(blowfish_ofb64, Key, Ivec, Data) ->
blowfish_ofb64_decrypt(Key, Ivec, Data);
block_decrypt(aes_cbc128, Key, Ivec, Data) ->
aes_cbc_128_decrypt(Key, Ivec, Data);
@@ -756,24 +771,28 @@ block_decrypt(des_ecb, Key, Data) ->
block_decrypt(blowfish_ecb, Key, Data) ->
blowfish_ecb_decrypt(Key, Data).
--spec next_iv(des_cbc | aes_cbc, Data::iodata()) -> binary().
+-spec next_iv(des_cbc | des3_cbc | aes_cbc, Data::iodata()) -> binary().
next_iv(des_cbc, Data) ->
des_cbc_ivec(Data);
+next_iv(des3_cbc, Data) ->
+ des_cbc_ivec(Data);
next_iv(aes_cbc, Data) ->
aes_cbc_ivec(Data).
--spec next_iv(des_cbf, Ivec::binary(), Data::iodata()) -> binary().
+-spec next_iv(des_cfb, Data::iodata(), Ivec::binary()) -> binary().
-next_iv(des_cbf, Ivec, Data) ->
- des_cfb_ivec(Ivec, Data).
+next_iv(des_cfb, Data, Ivec) ->
+ des_cfb_ivec(Ivec, Data);
+next_iv(Type, Data, _Ivec) ->
+ next_iv(Type, Data).
stream_init(aes_ctr, Key, Ivec) ->
{aes_ctr, aes_ctr_stream_init(Key, Ivec)}.
stream_init(rc4, Key) ->
{rc4, rc4_set_key(Key)}.
-stream_encrypt({aes_ctr, State}, Data) ->
- {State, Cipher} = aes_ctr_stream_encrypt(State, Data),
+stream_encrypt({aes_ctr, State0}, Data) ->
+ {State, Cipher} = aes_ctr_stream_encrypt(State0, Data),
{{aes_ctr, State}, Cipher};
stream_encrypt({rc4, State0}, Data) ->
{State, Cipher} = rc4_encrypt_with_state(State0, Data),
@@ -1068,7 +1087,7 @@ verify(rsa, Type, DataOrDigest, Signature, Key) ->
Bool -> Bool
end;
verify(ecdsa, Type, DataOrDigest, Signature, [Key, Curve]) ->
- case ecdsa_verify_nif(Type, DataOrDigest, Signature, term_to_ec_key({Curve, undefined, Key})) of
+ case ecdsa_verify_nif(Type, DataOrDigest, Signature, term_to_ec_key(Curve, undefined, Key)) of
notsup -> erlang:error(notsup);
Bool -> Bool
end.
@@ -1135,7 +1154,7 @@ sign(dss, Type, DataOrDigest, Key) ->
Sign -> Sign
end;
sign(ecdsa, Type, DataOrDigest, [Key, Curve]) ->
- case ecdsa_sign_nif(Type, DataOrDigest, term_to_ec_key({Curve, Key, undefined})) of
+ case ecdsa_sign_nif(Type, DataOrDigest, term_to_ec_key(Curve, Key, undefined)) of
error -> erlang:error(badkey, [Type,DataOrDigest,Key]);
Sign -> Sign
end.
@@ -1397,13 +1416,14 @@ generate_key(Type, Params) ->
generate_key(Type, Params, undefined).
generate_key(dh, DHParameters, PrivateKey) ->
- dh_generate_key_nif(PrivateKey, map_ensure_int_as_bin(DHParameters), 0);
+ dh_generate_key_nif(ensure_int_as_bin(PrivateKey),
+ map_ensure_int_as_bin(DHParameters), 0);
generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, PrivArg)
when is_binary(Verifier), is_binary(Generator), is_binary(Prime), is_atom(Version) ->
Private = case PrivArg of
undefined -> random_bytes(32);
- _ -> PrivArg
+ _ -> ensure_int_as_bin(PrivArg)
end,
host_srp_gen_key(Private, Verifier, Generator, Prime, Version);
@@ -1416,14 +1436,16 @@ generate_key(srp, {user, [Generator, Prime, Version]}, PrivateArg)
user_srp_gen_key(Private, Generator, Prime);
generate_key(ecdh, Curve, undefined) ->
- ec_key_to_term(ec_key_generate(Curve)).
+ ec_key_to_term_nif(ec_key_generate(Curve)).
ec_key_generate(_Key) -> ?nif_stub.
compute_key(dh, OthersPublicKey, MyPrivateKey, DHParameters) ->
- case dh_compute_key_nif(OthersPublicKey,MyPrivateKey, map_ensure_int_as_bin(DHParameters)) of
+ case dh_compute_key_nif(ensure_int_as_bin(OthersPublicKey),
+ ensure_int_as_bin(MyPrivateKey),
+ map_ensure_int_as_bin(DHParameters)) of
error -> erlang:error(computation_failed,
[OthersPublicKey,MyPrivateKey,DHParameters]);
Ret -> Ret
@@ -1433,34 +1455,33 @@ compute_key(srp, HostPublic, {UserPublic, UserPrivate},
{user, [DerivedKey, Prime, Generator, Version | ScramblerArg]}) when
is_binary(Prime),
is_binary(Generator),
- is_binary(UserPublic),
- is_binary(UserPrivate),
- is_binary(HostPublic),
is_atom(Version) ->
+ HostPubBin = ensure_int_as_bin(HostPublic),
Multiplier = srp_multiplier(Version, Generator, Prime),
Scrambler = case ScramblerArg of
- [] -> srp_scrambler(Version, UserPublic, HostPublic, Prime);
+ [] -> srp_scrambler(Version, ensure_int_as_bin(UserPublic),
+ HostPubBin, Prime);
[S] -> S
end,
- srp_user_secret_nif(UserPrivate, Scrambler, HostPublic, Multiplier,
- Generator, DerivedKey, Prime);
+ srp_user_secret_nif(ensure_int_as_bin(UserPrivate), Scrambler, HostPubBin,
+ Multiplier, Generator, DerivedKey, Prime);
compute_key(srp, UserPublic, {HostPublic, HostPrivate},
{host,[Verifier, Prime, Version | ScramblerArg]}) when
is_binary(Verifier),
is_binary(Prime),
- is_binary(UserPublic),
- is_binary(HostPublic),
- is_binary(HostPrivate),
is_atom(Version) ->
+ UserPubBin = ensure_int_as_bin(UserPublic),
Scrambler = case ScramblerArg of
- [] -> srp_scrambler(Version, UserPublic, HostPublic, Prime);
+ [] -> srp_scrambler(Version, UserPubBin, ensure_int_as_bin(HostPublic), Prime);
[S] -> S
end,
- srp_host_secret_nif(Verifier, HostPrivate, Scrambler, UserPublic, Prime);
+ srp_host_secret_nif(Verifier, ensure_int_as_bin(HostPrivate), Scrambler,
+ UserPubBin, Prime);
compute_key(ecdh, Others, My, Curve) ->
- ecdh_compute_key_nif(Others, term_to_ec_key({Curve,My,undefined})).
+ ecdh_compute_key_nif(ensure_int_as_bin(Others),
+ term_to_ec_key(Curve,My,undefined)).
ecdh_compute_key_nif(_Others, _My) -> ?nif_stub.
@@ -1468,14 +1489,6 @@ ecdh_compute_key_nif(_Others, _My) -> ?nif_stub.
%%
%% EC
%%
-ec_key_to_term(Key) ->
- case ec_key_to_term_nif(Key) of
- {PrivKey, PubKey} ->
- {bin_to_int(PrivKey), PubKey};
- _ ->
- erlang:error(conversion_failed)
- end.
-
ec_key_to_term_nif(_Key) -> ?nif_stub.
term_to_nif_prime({prime_field, Prime}) ->
@@ -1490,11 +1503,10 @@ term_to_nif_curve_parameters(Curve) when is_atom(Curve) ->
%% named curve
Curve.
--spec term_to_ec_key(ec_key()) -> ec_key_res().
-term_to_ec_key({Curve, undefined, PubKey}) ->
- term_to_ec_key_nif(term_to_nif_curve_parameters(Curve), undefined, PubKey);
-term_to_ec_key({Curve, PrivKey, PubKey}) ->
- term_to_ec_key_nif(term_to_nif_curve_parameters(Curve), int_to_bin(PrivKey), PubKey).
+term_to_ec_key(Curve, PrivKey, PubKey) ->
+ term_to_ec_key_nif(term_to_nif_curve_parameters(Curve),
+ ensure_int_as_bin(PrivKey),
+ ensure_int_as_bin(PubKey)).
term_to_ec_key_nif(_Curve, _PrivKey, _PubKey) -> ?nif_stub.
@@ -1598,6 +1610,8 @@ int_to_bin_neg(-1, Ds=[MSB|_]) when MSB >= 16#80 ->
int_to_bin_neg(X,Ds) ->
int_to_bin_neg(X bsr 8, [(X band 255)|Ds]).
+bytes_to_integer(Bin) ->
+ bin_to_int(Bin).
bin_to_int(Bin) when is_binary(Bin) ->
Bits = bit_size(Bin),
diff --git a/lib/crypto/test/Makefile b/lib/crypto/test/Makefile
index ec8136b455..07e5c1b754 100644
--- a/lib/crypto/test/Makefile
+++ b/lib/crypto/test/Makefile
@@ -7,7 +7,8 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
MODULES = \
blowfish_SUITE \
- crypto_SUITE
+ crypto_SUITE \
+ old_crypto_SUITE
ERL_FILES= $(MODULES:%=%.erl)
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index eddb6b83f9..c007ecac86 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -18,106 +18,104 @@
%%
-module(crypto_SUITE).
--include_lib("test_server/include/test_server.hrl").
-
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2,
- init_per_testcase/2,
- end_per_testcase/2,
- info/1,
- link_test/1,
- md5/1,
- md5_update/1,
- md4/1,
- md4_update/1,
- sha/1,
- sha_update/1,
- hmac_update_sha/1,
- hmac_update_sha_n/1,
- hmac_update_sha256/1,
- hmac_update_sha512/1,
- hmac_update_md5/1,
- hmac_update_md5_io/1,
- hmac_update_md5_n/1,
- hmac_rfc2202/1,
- hmac_rfc4231_sha224/1,
- hmac_rfc4231_sha256/1,
- hmac_rfc4231_sha384/1,
- hmac_rfc4231_sha512/1,
- ripemd160/1,
- ripemd160_update/1,
- sha256/1,
- sha256_update/1,
- sha512/1,
- sha512_update/1,
- md5_mac/1,
- md5_mac_io/1,
- des_cbc/1,
- des_cbc_iter/1,
- des_cfb/1,
- des_cfb_iter/1,
- des_ecb/1,
- des3_cbc/1,
- des3_cfb/1,
- rc2_cbc/1,
- aes_cfb/1,
- aes_cbc/1,
- aes_cbc_iter/1,
- aes_ctr/1,
- aes_ctr_stream/1,
- mod_exp_test/1,
- rand_uniform_test/1,
- strong_rand_test/1,
- rsa_verify_test/1,
- dsa_verify_test/1,
- rsa_sign_test/1,
- rsa_sign_hash_test/1,
- dsa_sign_test/1,
- dsa_sign_hash_test/1,
- rsa_encrypt_decrypt/1,
- dh/1,
- srp3/1, srp6/1, srp6a/1,
- ec/1,
- exor_test/1,
- rc4_test/1,
- rc4_stream_test/1,
- blowfish_cfb64/1,
- smp/1]).
-
--export([hexstr2bin/1]).
+-include_lib("common_test/include/ct.hrl").
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [link_test, {group, info}].
-
-groups() ->
- [{info, [sequence],[info, {group, rest}]},
- {rest, [],
- [md5, md5_update, md4, md4_update, md5_mac,
- md5_mac_io, ripemd160, ripemd160_update, sha, sha_update,
- sha256, sha256_update, sha512, sha512_update,
- hmac_update_sha, hmac_update_sha_n, hmac_update_sha256, hmac_update_sha512,
- hmac_update_md5_n, hmac_update_md5_io, hmac_update_md5,
- hmac_rfc2202, hmac_rfc4231_sha224, hmac_rfc4231_sha256,
- hmac_rfc4231_sha384, hmac_rfc4231_sha512,
- des_cbc, aes_cfb, aes_cbc,
- des_cfb, des_cfb_iter, des3_cbc, des3_cfb, rc2_cbc,
- aes_cbc_iter, aes_ctr, aes_ctr_stream, des_cbc_iter, des_ecb,
- rand_uniform_test, strong_rand_test,
- rsa_verify_test, dsa_verify_test, rsa_sign_test,
- rsa_sign_hash_test, dsa_sign_test, dsa_sign_hash_test,
- rsa_encrypt_decrypt, dh, srp3, srp6, srp6a, ec, exor_test,
- rc4_test, rc4_stream_test, mod_exp_test, blowfish_cfb64,
- smp]}].
-
+ [app,
+ {group, md4},
+ {group, md5},
+ {group, ripemd160},
+ {group, sha},
+ {group, sha224},
+ {group, sha256},
+ {group, sha384},
+ {group, sha512},
+ {group, rsa},
+ {group, dss},
+ {group, ecdsa},
+ {group, dh},
+ {group, ecdh},
+ {group, srp},
+ {group, des_cbc},
+ {group, des_cfb},
+ {group, des3_cbc},
+ {group, des3_cbf},
+ %%{group, des_ede3},
+ {group, blowfish_cbc},
+ {group, blowfish_ecb},
+ {group, blowfish_cfb64},
+ {group, blowfish_ofb64},
+ {group, aes_cbc128},
+ {group, aes_cfb128},
+ {group, aes_cbc256},
+ {group, rc2_cbc},
+ {group, rc4},
+ {group, aes_ctr},
+ mod_pow,
+ exor
+ ].
+
+groups() ->
+ [{md4, [], [hash]},
+ {md5, [], [hash, hmac]},
+ {ripemd160, [], [hash]},
+ {sha, [], [hash, hmac]},
+ {sha224, [], [hash, hmac]},
+ {sha256, [], [hash, hmac]},
+ {sha384, [], [hash, hmac]},
+ {sha512, [], [hash, hmac]},
+ {rsa, [], [sign_verify,
+ public_encrypt
+ ]},
+ {dss, [], [sign_verify]},
+ {ecdsa, [], [sign_verify]},
+ {dh, [], [generate_compute]},
+ {ecdh, [], [compute]},
+ {srp, [], [generate_compute]},
+ {des_cbc, [], [block]},
+ {des_cfb, [], [block]},
+ {des3_cbc,[], [block]},
+ {des3_cbf,[], [block]},
+ {rc2_cbc,[], [block]},
+ {aes_cbc128,[], [block]},
+ {aes_cfb128,[], [block]},
+ {aes_cbc256,[], [block]},
+ {blowfish_cbc, [], [block]},
+ {blowfish_ecb, [], [block]},
+ {blowfish_cfb64, [], [block]},
+ {blowfish_ofb64,[], [block]},
+ {rc4, [], [stream]},
+ {aes_ctr, [], [stream]}
+ ].
+
+%%-------------------------------------------------------------------
init_per_suite(Config) ->
- Config.
+ try crypto:start() of
+ ok ->
+ Config
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
end_per_suite(_Config) ->
- ok.
+ application:stop(crypto).
-init_per_group(_GroupName, Config) ->
- Config.
+%%-------------------------------------------------------------------
+init_per_group(GroupName, Config) ->
+ case is_supported(GroupName) of
+ true ->
+ group_config(GroupName, Config);
+ false ->
+ {skip, "Group not supported"}
+ end.
end_per_group(_GroupName, Config) ->
Config.
@@ -125,1821 +123,1098 @@ end_per_group(_GroupName, Config) ->
init_per_testcase(info, Config) ->
Config;
init_per_testcase(_Name,Config) ->
- io:format("init_per_testcase\n"),
- ?line crypto:start(),
Config.
end_per_testcase(info, Config) ->
Config;
end_per_testcase(_Name,Config) ->
- io:format("end_per_testcase\n"),
- ?line crypto:stop(),
Config.
-%%
-%%
-link_test(doc) ->
- ["Test that the library is statically linked to libcrypto.a."];
-link_test(suite) ->
- [];
-link_test(Config) when is_list(Config) ->
- ?line case os:type() of
- {unix,darwin} -> {skipped,"Darwin cannot link statically"};
- {unix,_} -> link_test_1();
- _ -> {skip,"Only runs on Unix"}
- end.
-
-link_test_1() ->
- ?line CryptoPriv = code:priv_dir(crypto),
- ?line Wc = filename:join([CryptoPriv,"lib","crypto.*"]),
- ?line case filelib:wildcard(Wc) of
- [] -> {skip,"Didn't find the crypto driver"};
- [Drv] -> link_test_2(Drv)
- end.
-
-link_test_2(Drv) ->
- case ldd_program() of
- none ->
- {skip,"No ldd-like program found"};
- Ldd ->
- Cmd = Ldd ++ " " ++ Drv,
- Libs = os:cmd(Cmd),
- io:format("~p\n", [Libs]),
- case string:str(Libs, "libcrypto") of
- 0 ->
- case ?t:is_commercial() of
- true ->
- ?t:fail({libcrypto,statically_linked});
- false ->
- {comment,"Statically linked (OK for open-source platform)"}
- end;
- _ ->
- ok
- end
- end.
-
-ldd_program() ->
- case os:find_executable("ldd") of
- false ->
- case os:type() of
- {unix,darwin} ->
- case os:find_executable("otool") of
- false -> none;
- Otool -> Otool ++ " -L"
- end
- end;
- Ldd when is_list(Ldd) -> Ldd
- end.
-
-
-
-info(doc) ->
- ["Call the info function."];
-info(suite) ->
- [];
-info(Config) when is_list(Config) ->
- case {code:lib_dir(crypto),?t:is_commercial()} of
- {{error,bad_name},false} ->
- {skip,"Missing crypto application"};
- {_,_} ->
- ?line crypto:start(),
- ?line Info = crypto:info(),
- ?line Exports = lists:usort([F || {F,_} <- crypto:module_info(exports)]),
- ?line [] = Info -- Exports,
- ?line NotInInfo = Exports -- Info,
- io:format("NotInInfo = ~p\n", [NotInInfo]),
- %% BlackList = lists:sort([des_ede3_cbc_decrypt, des_ede3_cbc_encrypt,
- %% dh_check, dh_generate_parameters,
- %% module_info, start, stop, version]),
- %% ?line BlackList = NotInInfo,
-
- ?line InfoLib = crypto:info_lib(),
- ?line [_|_] = InfoLib,
- F = fun([{Name,VerN,VerS}|T],Me) ->
- ?line true = is_binary(Name),
- ?line true = is_integer(VerN),
- ?line true = is_binary(VerS),
- Me(T,Me);
- ([],_) ->
- ok
- end,
- ?line F(InfoLib,F),
- ?line crypto:stop()
- end.
-
-%%
-%%
-md5(doc) ->
- ["Generate MD5 message digests and check the result. Examples are "
- "from RFC-1321."];
-md5(suite) ->
- [];
-md5(Config) when is_list(Config) ->
- ?line m(crypto:md5(""),
- hexstr2bin("d41d8cd98f00b204e9800998ecf8427e")),
- ?line m(crypto:md5("a"),
- hexstr2bin("0cc175b9c0f1b6a831c399e269772661")),
- ?line m(crypto:md5("abc"),
- hexstr2bin("900150983cd24fb0d6963f7d28e17f72")),
- ?line m(crypto:md5("message digest"),
- hexstr2bin("f96b697d7cb7938d525a2f31aaf161d0")),
- ?line m(crypto:md5("abcdefghijklmnopqrstuvwxyz"),
- hexstr2bin("c3fcd3d76192e4007dfb496cca67e13b")),
- ?line m(crypto:md5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
- "0123456789"),
- hexstr2bin("d174ab98d277d9f5a5611c2c9f419d9f")),
- ?line m(crypto:md5("12345678901234567890123456789012345678901234567890"
- "123456789012345678901234567890"),
- hexstr2bin("57edf4a22be3c955ac49da2e2107b67a")).
-
-%%
-%%
-md5_update(doc) ->
- ["Generate MD5 message using md5_init, md5_update, and md5_final, and"
- "check the result. Examples are from RFC-1321."];
-md5_update(suite) ->
- [];
-md5_update(Config) when is_list(Config) ->
- ?line Ctx = crypto:md5_init(),
- ?line Ctx1 = crypto:md5_update(Ctx, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
- ?line Ctx2 = crypto:md5_update(Ctx1, "abcdefghijklmnopqrstuvwxyz"
- "0123456789"),
- ?line m(crypto:md5_final(Ctx2),
- hexstr2bin("d174ab98d277d9f5a5611c2c9f419d9f")).
-
-%%
-%%
-md4(doc) ->
- ["Generate MD4 message digests and check the result. Examples are "
- "from RFC-1321."];
-md4(suite) ->
- [];
-md4(Config) when is_list(Config) ->
- ?line m(crypto:md4(""),
- hexstr2bin("31d6cfe0d16ae931b73c59d7e0c089c0")),
- ?line m(crypto:md4("a"),
- hexstr2bin("bde52cb31de33e46245e05fbdbd6fb24")),
- ?line m(crypto:md4("abc"),
- hexstr2bin("a448017aaf21d8525fc10ae87aa6729d")),
- ?line m(crypto:md4("message digest"),
- hexstr2bin("d9130a8164549fe818874806e1c7014b")),
- ?line m(crypto:md4("abcdefghijklmnopqrstuvwxyz"),
- hexstr2bin("d79e1c308aa5bbcdeea8ed63df412da9")),
- ?line m(crypto:md4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
- "0123456789"),
- hexstr2bin("043f8582f241db351ce627e153e7f0e4")),
- ?line m(crypto:md4("12345678901234567890123456789012345678901234567890"
- "123456789012345678901234567890"),
- hexstr2bin("e33b4ddc9c38f2199c3e7b164fcc0536")).
-
-%%
-%%
-md4_update(doc) ->
- ["Generate MD5 message using md5_init, md5_update, and md5_final, and"
- "check the result. Examples are from RFC-1321."];
-md4_update(suite) ->
- [];
-md4_update(Config) when is_list(Config) ->
- ?line Ctx = crypto:md4_init(),
- ?line Ctx1 = crypto:md4_update(Ctx, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
- ?line Ctx2 = crypto:md4_update(Ctx1, "abcdefghijklmnopqrstuvwxyz"
- "0123456789"),
- ?line m(crypto:md4_final(Ctx2),
- hexstr2bin("043f8582f241db351ce627e153e7f0e4")).
-
-%%
-%%
-sha(doc) ->
- ["Generate SHA message digests and check the result. Examples are "
- "from FIPS-180-1."];
-sha(suite) ->
- [];
-sha(Config) when is_list(Config) ->
- ?line m(crypto:sha("abc"),
- hexstr2bin("A9993E364706816ABA3E25717850C26C9CD0D89D")),
- ?line m(crypto:sha("abcdbcdecdefdefgefghfghighijhijkijkljklmklm"
- "nlmnomnopnopq"),
- hexstr2bin("84983E441C3BD26EBAAE4AA1F95129E5E54670F1")).
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+app() ->
+ [{doc, "Test that the crypto app file is ok"}].
+app(Config) when is_list(Config) ->
+ ok = ?t:app_test(crypto).
+%%--------------------------------------------------------------------
+hash() ->
+ [{doc, "Test all different hash functions"}].
+hash(Config) when is_list(Config) ->
+ {Type, Msgs, Digests} = proplists:get_value(hash, Config),
+ [LongMsg | _] = lists:reverse(Msgs),
+ Inc = iolistify(LongMsg),
+ [IncrDigest | _] = lists:reverse(Digests),
+ hash(Type, Msgs, Digests),
+ hash(Type, lists:map(fun iolistify/1, Msgs), Digests),
+ hash_increment(Type, Inc, IncrDigest).
+%%--------------------------------------------------------------------
+hmac() ->
+ [{doc, "Test all different hmac functions"}].
+hmac(Config) when is_list(Config) ->
+ {Type, Keys, Data, Expected} = proplists:get_value(hmac, Config),
+ hmac(Type, Keys, Data, Expected),
+ hmac(Type, lists:map(fun iolistify/1, Keys), lists:map(fun iolistify/1, Data), Expected),
+ hmac_increment(Type).
+%%--------------------------------------------------------------------
+block() ->
+ [{doc, "Test block ciphers"}].
+block(Config) when is_list(Config) ->
+ Blocks = proplists:get_value(block, Config),
+ lists:foreach(fun block_cipher/1, Blocks),
+ lists:foreach(fun block_cipher/1, block_iolistify(Blocks)),
+ lists:foreach(fun block_cipher_increment/1, block_iolistify(Blocks)).
+
+%%--------------------------------------------------------------------
+stream() ->
+ [{doc, "Test stream ciphers"}].
+stream(Config) when is_list(Config) ->
+ Streams = proplists:get_value(stream, Config),
+ lists:foreach(fun stream_cipher/1, Streams),
+ lists:foreach(fun stream_cipher/1, stream_iolistify(Streams)),
+ lists:foreach(fun stream_cipher_incment/1, stream_iolistify(Streams)).
+
+%%--------------------------------------------------------------------
+sign_verify() ->
+ [{doc, "Sign/verify digital signatures"}].
+sign_verify(Config) when is_list(Config) ->
+ SignVerify = proplists:get_value(sign_verify, Config),
+ lists:foreach(fun do_sign_verify/1, SignVerify).
+
+%%--------------------------------------------------------------------
+public_encrypt() ->
+ [{doc, "Test public_encrypt/decrypt and private_encrypt/decrypt functions. "}].
+public_encrypt(Config) when is_list(Config) ->
+ Params = proplists:get_value(pub_priv_encrypt, Config),
+ lists:foreach(fun do_public_encrypt/1, Params),
+ lists:foreach(fun do_private_encrypt/1, Params).
+
+%%--------------------------------------------------------------------
+generate_compute() ->
+ [{doc, " Test crypto:genarate_key and crypto:compute_key"}].
+generate_compute(Config) when is_list(Config) ->
+ GenCom = proplists:get_value(generate_compute, Config),
+ lists:foreach(fun do_generate_compute/1, GenCom).
+%%--------------------------------------------------------------------
+compute() ->
+ [{doc, " Test crypto:compute_key"}].
+compute(Config) when is_list(Config) ->
+ Gen = proplists:get_value(compute, Config),
+ lists:foreach(fun do_compute/1, Gen).
+%%--------------------------------------------------------------------
+mod_pow() ->
+ [{doc, "mod_pow testing (A ^ M % P with bignums)"}].
+mod_pow(Config) when is_list(Config) ->
+ mod_pow_aux_test(2, 5, 10, 8).
+%%--------------------------------------------------------------------
+exor() ->
+ [{doc, "Test the exor function"}].
+exor(Config) when is_list(Config) ->
+ B = <<1, 2, 3, 4, 5, 6, 7, 8, 9, 10>>,
+ Z1 = zero_bin(B),
+ Z1 = crypto:exor(B, B),
+ B1 = crypto:rand_bytes(100),
+ B2 = crypto:rand_bytes(100),
+ Z2 = zero_bin(B1),
+ Z2 = crypto:exor(B1, B1),
+ Z2 = crypto:exor(B2, B2),
+ R = xor_bytes(B1, B2),
+ R = crypto:exor(B1, B2).
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
-%%
-hmac_update_sha_n(doc) ->
- ["Request a larger-than-allowed SHA1 HMAC using hmac_init, hmac_update, and hmac_final_n. "
- "Expected values for examples are generated using crypto:sha_mac." ];
-hmac_update_sha_n(suite) ->
- [];
-hmac_update_sha_n(Config) when is_list(Config) ->
- ?line Key = hexstr2bin("00010203101112132021222330313233"
- "04050607141516172425262734353637"
- "08090a0b18191a1b28292a2b38393a3b"
- "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f"),
- ?line Data = "Sampl",
- ?line Data2 = "e #1",
- ?line Ctx = crypto:hmac_init(sha, Key),
- ?line Ctx2 = crypto:hmac_update(Ctx, Data),
- ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
- ?line Mac = crypto:hmac_final_n(Ctx3, 1024),
- ?line Exp = crypto:sha_mac(Key, lists:flatten([Data, Data2])),
- ?line m(Exp, Mac),
- ?line m(size(Exp), size(Mac)).
-
-
-hmac_update_sha(doc) ->
- ["Generate an SHA1 HMAC using hmac_init, hmac_update, and hmac_final. "
- "Expected values for examples are generated using crypto:sha_mac." ];
-hmac_update_sha(suite) ->
- [];
-hmac_update_sha(Config) when is_list(Config) ->
- ?line Key = hexstr2bin("00010203101112132021222330313233"
- "04050607141516172425262734353637"
- "08090a0b18191a1b28292a2b38393a3b"
- "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f"),
- ?line Data = "Sampl",
- ?line Data2 = "e #1",
- ?line Ctx = crypto:hmac_init(sha, Key),
- ?line Ctx2 = crypto:hmac_update(Ctx, Data),
- ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
- ?line Mac = crypto:hmac_final(Ctx3),
- ?line Exp = crypto:hmac(sha, Key, lists:flatten([Data, Data2])),
- ?line m(Exp, Mac).
-
-hmac_update_sha256(doc) ->
- ["Generate an SHA256 HMAC using hmac_init, hmac_update, and hmac_final. "
- "Expected values for examples are generated using crypto:sha256_mac." ];
-hmac_update_sha256(suite) ->
- [];
-hmac_update_sha256(Config) when is_list(Config) ->
- if_supported(sha256, fun() -> hmac_update_sha256_do() end).
-
-hmac_update_sha256_do() ->
- ?line Key = hexstr2bin("00010203101112132021222330313233"
- "04050607141516172425262734353637"
- "08090a0b18191a1b28292a2b38393a3b"
- "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f"),
- ?line Data = "Sampl",
- ?line Data2 = "e #1",
- ?line Ctx = crypto:hmac_init(sha256, Key),
- ?line Ctx2 = crypto:hmac_update(Ctx, Data),
- ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
- ?line Mac = crypto:hmac_final(Ctx3),
- ?line Exp = crypto:hmac(sha256, Key, lists:flatten([Data, Data2])),
- ?line m(Exp, Mac).
-
-hmac_update_sha512(doc) ->
- ["Generate an SHA512 HMAC using hmac_init, hmac_update, and hmac_final. "
- "Expected values for examples are generated using crypto:sha512_mac." ];
-hmac_update_sha512(suite) ->
- [];
-hmac_update_sha512(Config) when is_list(Config) ->
- if_supported(sha512, fun() -> hmac_update_sha512_do() end).
-
-hmac_update_sha512_do() ->
- ?line Key = hexstr2bin("00010203101112132021222330313233"
- "04050607141516172425262734353637"
- "08090a0b18191a1b28292a2b38393a3b"
- "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f"),
- ?line Data = "Sampl",
- ?line Data2 = "e #1",
- ?line Ctx = crypto:hmac_init(sha512, Key),
- ?line Ctx2 = crypto:hmac_update(Ctx, Data),
- ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
- ?line Mac = crypto:hmac_final(Ctx3),
- ?line Exp = crypto:hmac(sha512, Key, lists:flatten([Data, Data2])),
- ?line m(Exp, Mac).
-
-hmac_update_md5(doc) ->
- ["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. "
- "Expected values for examples are generated using crypto:md5_mac." ];
-hmac_update_md5(suite) ->
- [];
-hmac_update_md5(Config) when is_list(Config) ->
- % ?line Key2 = ["A fine speach", "by a fine man!"],
- Key2 = "A fine speach by a fine man!",
- ?line Long1 = "Four score and seven years ago our fathers brought forth on this continent a new nation, conceived in liberty, and dedicated to the proposition that all men are created equal.",
- ?line Long2 = "Now we are engaged in a great civil war, testing whether that nation, or any nation, so conceived and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this.",
- ?line Long3 = "But, in a larger sense, we can not dedicate, we can not consecrate, we can not hallow this ground. The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us-that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion that we here highly resolve that these dead shall not have died in vain-that this nation, under God, shall have a new birth of freedom-and that government of the people, by the people, for the people, shall not perish from the earth.",
- ?line CtxA = crypto:hmac_init(md5, Key2),
- ?line CtxB = crypto:hmac_update(CtxA, Long1),
- ?line CtxC = crypto:hmac_update(CtxB, Long2),
- ?line CtxD = crypto:hmac_update(CtxC, Long3),
- ?line Mac2 = crypto:hmac_final(CtxD),
- ?line Exp2 = crypto:md5_mac(Key2, lists:flatten([Long1, Long2, Long3])),
- ?line m(Exp2, Mac2).
-
-hmac_rfc2202(doc) ->
- ["Generate an HMAC using hmac, md5_mac, and sha_mac."
- "Test vectors are taken from RFC-2202."];
-hmac_rfc2202(suite) ->
- [];
-hmac_rfc2202(Config) when is_list(Config) ->
- hmac_rfc2202_md5(),
- hmac_rfc2202_sha().
-
-hmac_rfc2202_md5() ->
- %% Test case 1
- Case1Key = binary:copy(<<16#0b>>, 16),
- Case1Data = <<"Hi There">>,
- Case1Exp = hexstr2bin("9294727a3638bb1c13f48ef8158bfc9d"),
-
- ?line Case1Mac_1 = crypto:md5_mac(Case1Key, Case1Data),
- ?line Case1Mac_2 = crypto:hmac(md5, Case1Key, Case1Data),
- ?line m(Case1Exp, Case1Mac_1),
- ?line m(Case1Exp, Case1Mac_2),
-
- %% Test case 2
- Case2Key = <<"Jefe">>,
- Case2Data = <<"what do ya want for nothing?">>,
- Case2Exp = hexstr2bin("750c783e6ab0b503eaa86e310a5db738"),
-
- ?line Case2Mac_1 = crypto:md5_mac(Case2Key, Case2Data),
- ?line Case2Mac_2 = crypto:hmac(md5, Case2Key, Case2Data),
- ?line m(Case2Exp, Case2Mac_1),
- ?line m(Case2Exp, Case2Mac_2),
-
- %% Test case 3
- Case3Key = binary:copy(<<16#aa>>, 16),
- Case3Data = binary:copy(<<16#dd>>, 50),
- Case3Exp = hexstr2bin("56be34521d144c88dbb8c733f0e8b3f6"),
-
- ?line Case3Mac_1 = crypto:md5_mac(Case3Key, Case3Data),
- ?line Case3Mac_2 = crypto:hmac(md5, Case3Key, Case3Data),
- ?line m(Case3Exp, Case3Mac_1),
- ?line m(Case3Exp, Case3Mac_2),
-
- %% Test case 4
- Case4Key = list_to_binary(lists:seq(1, 16#19)),
- Case4Data = binary:copy(<<16#cd>>, 50),
- Case4Exp = hexstr2bin("697eaf0aca3a3aea3a75164746ffaa79"),
-
- ?line Case4Mac_1 = crypto:md5_mac(Case4Key, Case4Data),
- ?line Case4Mac_2 = crypto:hmac(md5, Case4Key, Case4Data),
- ?line m(Case4Exp, Case4Mac_1),
- ?line m(Case4Exp, Case4Mac_2),
-
- %% Test case 5
- Case5Key = binary:copy(<<16#0c>>, 16),
- Case5Data = "Test With Truncation",
- Case5Exp = hexstr2bin("56461ef2342edc00f9bab995690efd4c"),
- Case5Exp96 = hexstr2bin("56461ef2342edc00f9bab995"),
-
- ?line Case5Mac_1 = crypto:md5_mac(Case5Key, Case5Data),
- ?line Case5Mac_2 = crypto:hmac(md5, Case5Key, Case5Data),
- ?line Case5Mac96_1 = crypto:md5_mac_96(Case5Key, Case5Data),
- ?line Case5Mac96_2 = crypto:hmac(md5, Case5Key, Case5Data, 12),
- ?line m(Case5Exp, Case5Mac_1),
- ?line m(Case5Exp, Case5Mac_2),
- ?line m(Case5Exp96, Case5Mac96_1),
- ?line m(Case5Exp96, Case5Mac96_2),
-
- %% Test case 6
- Case6Key = binary:copy(<<16#aa>>, 80),
- Case6Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
- Case6Exp = hexstr2bin("6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd"),
-
- ?line Case6Mac_1 = crypto:md5_mac(Case6Key, Case6Data),
- ?line Case6Mac_2 = crypto:hmac(md5, Case6Key, Case6Data),
- ?line m(Case6Exp, Case6Mac_1),
- ?line m(Case6Exp, Case6Mac_2),
-
- %% Test case 7
- Case7Key = binary:copy(<<16#aa>>, 80),
- Case7Data = <<"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data">>,
- Case7Exp = hexstr2bin("6f630fad67cda0ee1fb1f562db3aa53e"),
-
- ?line Case7Mac_1 = crypto:md5_mac(Case7Key, Case7Data),
- ?line Case7Mac_2 = crypto:hmac(md5, Case7Key, Case7Data),
- ?line m(Case7Exp, Case7Mac_1),
- ?line m(Case7Exp, Case7Mac_2).
-
-hmac_rfc2202_sha() ->
- %% Test case 1
- Case1Key = binary:copy(<<16#0b>>, 20),
- Case1Data = <<"Hi There">>,
- Case1Exp = hexstr2bin("b617318655057264e28bc0b6fb378c8ef146be00"),
-
- ?line Case1Mac_1 = crypto:sha_mac(Case1Key, Case1Data),
- ?line Case1Mac_2 = crypto:hmac(sha, Case1Key, Case1Data),
- ?line m(Case1Exp, Case1Mac_1),
- ?line m(Case1Exp, Case1Mac_2),
-
- %% Test case 2
- Case2Key = <<"Jefe">>,
- Case2Data = <<"what do ya want for nothing?">>,
- Case2Exp = hexstr2bin("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79"),
-
- ?line Case2Mac_1 = crypto:sha_mac(Case2Key, Case2Data),
- ?line Case2Mac_2 = crypto:hmac(sha, Case2Key, Case2Data),
- ?line m(Case2Exp, Case2Mac_1),
- ?line m(Case2Exp, Case2Mac_2),
-
- %% Test case 3
- Case3Key = binary:copy(<<16#aa>>, 20),
- Case3Data = binary:copy(<<16#dd>>, 50),
- Case3Exp = hexstr2bin("125d7342b9ac11cd91a39af48aa17b4f63f175d3"),
-
- ?line Case3Mac_1 = crypto:sha_mac(Case3Key, Case3Data),
- ?line Case3Mac_2 = crypto:hmac(sha, Case3Key, Case3Data),
- ?line m(Case3Exp, Case3Mac_1),
- ?line m(Case3Exp, Case3Mac_2),
-
- %% Test case 4
- Case4Key = list_to_binary(lists:seq(1, 16#19)),
- Case4Data = binary:copy(<<16#cd>>, 50),
- Case4Exp = hexstr2bin("4c9007f4026250c6bc8414f9bf50c86c2d7235da"),
-
- ?line Case4Mac_1 = crypto:sha_mac(Case4Key, Case4Data),
- ?line Case4Mac_2 = crypto:hmac(sha, Case4Key, Case4Data),
- ?line m(Case4Exp, Case4Mac_1),
- ?line m(Case4Exp, Case4Mac_2),
-
- %% Test case 5
- Case5Key = binary:copy(<<16#0c>>, 20),
- Case5Data = "Test With Truncation",
- Case5Exp = hexstr2bin("4c1a03424b55e07fe7f27be1d58bb9324a9a5a04"),
- Case5Exp96 = hexstr2bin("4c1a03424b55e07fe7f27be1"),
-
- ?line Case5Mac_1 = crypto:sha_mac(Case5Key, Case5Data),
- ?line Case5Mac_2 = crypto:hmac(sha, Case5Key, Case5Data),
- ?line Case5Mac96_1 = crypto:sha_mac_96(Case5Key, Case5Data),
- ?line Case5Mac96_2 = crypto:hmac(sha, Case5Key, Case5Data, 12),
- ?line m(Case5Exp, Case5Mac_1),
- ?line m(Case5Exp, Case5Mac_2),
- ?line m(Case5Exp96, Case5Mac96_1),
- ?line m(Case5Exp96, Case5Mac96_2),
-
- %% Test case 6
- Case6Key = binary:copy(<<16#aa>>, 80),
- Case6Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
- Case6Exp = hexstr2bin("aa4ae5e15272d00e95705637ce8a3b55ed402112"),
-
- ?line Case6Mac_1 = crypto:sha_mac(Case6Key, Case6Data),
- ?line Case6Mac_2 = crypto:hmac(sha, Case6Key, Case6Data),
- ?line m(Case6Exp, Case6Mac_1),
- ?line m(Case6Exp, Case6Mac_2),
-
- %% Test case 7
- Case7Key = binary:copy(<<16#aa>>, 80),
- Case7Data = <<"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data">>,
- Case7Exp = hexstr2bin("e8e99d0f45237d786d6bbaa7965c7808bbff1a91"),
-
- ?line Case7Mac_1 = crypto:sha_mac(Case7Key, Case7Data),
- ?line Case7Mac_2 = crypto:hmac(sha, Case7Key, Case7Data),
- ?line m(Case7Exp, Case7Mac_1),
- ?line m(Case7Exp, Case7Mac_2).
-
-hmac_rfc4231_sha224(doc) ->
- ["Generate an HMAC using crypto:sha224_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
- "Testvectors are take from RFC4231." ];
-hmac_rfc4231_sha224(suite) ->
- [];
-hmac_rfc4231_sha224(Config) when is_list(Config) ->
- if_supported(sha224, fun() -> hmac_rfc4231_sha224_do() end).
-
-hmac_rfc4231_sha256(doc) ->
- ["Generate an HMAC using crypto:sha256_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
- "Testvectors are take from RFC4231." ];
-hmac_rfc4231_sha256(suite) ->
- [];
-hmac_rfc4231_sha256(Config) when is_list(Config) ->
- if_supported(sha256, fun() -> hmac_rfc4231_sha256_do() end).
-
-hmac_rfc4231_sha384(doc) ->
- ["Generate an HMAC using crypto:sha384_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
- "Testvectors are take from RFC4231." ];
-hmac_rfc4231_sha384(suite) ->
- [];
-hmac_rfc4231_sha384(Config) when is_list(Config) ->
- if_supported(sha384, fun() -> hmac_rfc4231_sha384_do() end).
-
-hmac_rfc4231_sha512(doc) ->
- ["Generate an HMAC using crypto:sha512_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
- "Testvectors are take from RFC4231." ];
-hmac_rfc4231_sha512(suite) ->
- [];
-hmac_rfc4231_sha512(Config) when is_list(Config) ->
- if_supported(sha512, fun() -> hmac_rfc4231_sha512_do() end).
-
-hmac_rfc4231_case(Hash, case1, Exp) ->
- %% Test 1
- Key = binary:copy(<<16#0b>>, 20),
- Data = <<"Hi There">>,
- hmac_rfc4231_case(Hash, Key, Data, Exp);
-
-hmac_rfc4231_case(Hash, case2, Exp) ->
- %% Test 2
- Key = <<"Jefe">>,
- Data = <<"what do ya want for nothing?">>,
- hmac_rfc4231_case(Hash, Key, Data, Exp);
-
-hmac_rfc4231_case(Hash, case3, Exp) ->
- %% Test 3
- Key = binary:copy(<<16#aa>>, 20),
- Data = binary:copy(<<16#dd>>, 50),
- hmac_rfc4231_case(Hash, Key, Data, Exp);
-
-hmac_rfc4231_case(Hash, case4, Exp) ->
- %% Test 4
- Key = list_to_binary(lists:seq(1, 16#19)),
- Data = binary:copy(<<16#cd>>, 50),
- hmac_rfc4231_case(Hash, Key, Data, Exp);
-
-hmac_rfc4231_case(Hash, case5, Exp) ->
- %% Test 5
- Key = binary:copy(<<16#0c>>, 20),
- Data = <<"Test With Truncation">>,
- hmac_rfc4231_case(Hash, Key, Data, 16, Exp);
-
-hmac_rfc4231_case(Hash, case6, Exp) ->
- %% Test 6
- Key = binary:copy(<<16#aa>>, 131),
- Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
- hmac_rfc4231_case(Hash, Key, Data, Exp);
-
-hmac_rfc4231_case(Hash, case7, Exp) ->
- %% Test Case 7
- Key = binary:copy(<<16#aa>>, 131),
- Data = <<"This is a test using a larger than block-size key and a larger t",
- "han block-size data. The key needs to be hashed before being use",
- "d by the HMAC algorithm.">>,
- hmac_rfc4231_case(Hash, Key, Data, Exp).
-
-hmac_rfc4231_case(Hash, Key, Data, Exp) ->
- ?line Ctx = crypto:hmac_init(Hash, Key),
- ?line Ctx2 = crypto:hmac_update(Ctx, Data),
- ?line Mac1 = crypto:hmac_final(Ctx2),
- ?line Mac3 = crypto:hmac(Hash, Key, Data),
- ?line m(Exp, Mac1),
- ?line m(Exp, Mac3).
-
-hmac_rfc4231_case(Hash, Key, Data, Trunc, Exp) ->
- ?line Ctx = crypto:hmac_init(Hash, Key),
- ?line Ctx2 = crypto:hmac_update(Ctx, Data),
- ?line Mac1 = crypto:hmac_final_n(Ctx2, Trunc),
- ?line Mac3 = crypto:hmac(Hash, Key, Data, Trunc),
- ?line m(Exp, Mac1),
- ?line m(Exp, Mac3).
-
-hmac_rfc4231_sha224_do() ->
- Case1 = hexstr2bin("896fb1128abbdf196832107cd49df33f"
- "47b4b1169912ba4f53684b22"),
- Case2 = hexstr2bin("a30e01098bc6dbbf45690f3a7e9e6d0f"
- "8bbea2a39e6148008fd05e44"),
- Case3 = hexstr2bin("7fb3cb3588c6c1f6ffa9694d7d6ad264"
- "9365b0c1f65d69d1ec8333ea"),
- Case4 = hexstr2bin("6c11506874013cac6a2abc1bb382627c"
- "ec6a90d86efc012de7afec5a"),
- Case5 = hexstr2bin("0e2aea68a90c8d37c988bcdb9fca6fa8"),
- Case6 = hexstr2bin("95e9a0db962095adaebe9b2d6f0dbce2"
- "d499f112f2d2b7273fa6870e"),
- Case7 = hexstr2bin("3a854166ac5d9f023f54d517d0b39dbd"
- "946770db9c2b95c9f6f565d1"),
- hmac_rfc4231_cases_do(sha224, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
-
-hmac_rfc4231_sha256_do() ->
- Case1 = hexstr2bin("b0344c61d8db38535ca8afceaf0bf12b"
- "881dc200c9833da726e9376c2e32cff7"),
- Case2 = hexstr2bin("5bdcc146bf60754e6a042426089575c7"
- "5a003f089d2739839dec58b964ec3843"),
- Case3 = hexstr2bin("773ea91e36800e46854db8ebd09181a7"
- "2959098b3ef8c122d9635514ced565fe"),
- Case4 = hexstr2bin("82558a389a443c0ea4cc819899f2083a"
- "85f0faa3e578f8077a2e3ff46729665b"),
- Case5 = hexstr2bin("a3b6167473100ee06e0c796c2955552b"),
- Case6 = hexstr2bin("60e431591ee0b67f0d8a26aacbf5b77f"
- "8e0bc6213728c5140546040f0ee37f54"),
- Case7 = hexstr2bin("9b09ffa71b942fcb27635fbcd5b0e944"
- "bfdc63644f0713938a7f51535c3a35e2"),
- hmac_rfc4231_cases_do(sha256, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
-
-hmac_rfc4231_sha384_do() ->
- Case1 = hexstr2bin("afd03944d84895626b0825f4ab46907f"
- "15f9dadbe4101ec682aa034c7cebc59c"
- "faea9ea9076ede7f4af152e8b2fa9cb6"),
- Case2 = hexstr2bin("af45d2e376484031617f78d2b58a6b1b"
- "9c7ef464f5a01b47e42ec3736322445e"
- "8e2240ca5e69e2c78b3239ecfab21649"),
- Case3 = hexstr2bin("88062608d3e6ad8a0aa2ace014c8a86f"
- "0aa635d947ac9febe83ef4e55966144b"
- "2a5ab39dc13814b94e3ab6e101a34f27"),
- Case4 = hexstr2bin("3e8a69b7783c25851933ab6290af6ca7"
- "7a9981480850009cc5577c6e1f573b4e"
- "6801dd23c4a7d679ccf8a386c674cffb"),
- Case5 = hexstr2bin("3abf34c3503b2a23a46efc619baef897"),
- Case6 = hexstr2bin("4ece084485813e9088d2c63a041bc5b4"
- "4f9ef1012a2b588f3cd11f05033ac4c6"
- "0c2ef6ab4030fe8296248df163f44952"),
- Case7 = hexstr2bin("6617178e941f020d351e2f254e8fd32c"
- "602420feb0b8fb9adccebb82461e99c5"
- "a678cc31e799176d3860e6110c46523e"),
- hmac_rfc4231_cases_do(sha384, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
-
-hmac_rfc4231_sha512_do() ->
- Case1 = hexstr2bin("87aa7cdea5ef619d4ff0b4241a1d6cb0"
- "2379f4e2ce4ec2787ad0b30545e17cde"
- "daa833b7d6b8a702038b274eaea3f4e4"
- "be9d914eeb61f1702e696c203a126854"),
- Case2 = hexstr2bin("164b7a7bfcf819e2e395fbe73b56e0a3"
- "87bd64222e831fd610270cd7ea250554"
- "9758bf75c05a994a6d034f65f8f0e6fd"
- "caeab1a34d4a6b4b636e070a38bce737"),
- Case3 = hexstr2bin("fa73b0089d56a284efb0f0756c890be9"
- "b1b5dbdd8ee81a3655f83e33b2279d39"
- "bf3e848279a722c806b485a47e67c807"
- "b946a337bee8942674278859e13292fb"),
- Case4 = hexstr2bin("b0ba465637458c6990e5a8c5f61d4af7"
- "e576d97ff94b872de76f8050361ee3db"
- "a91ca5c11aa25eb4d679275cc5788063"
- "a5f19741120c4f2de2adebeb10a298dd"),
- Case5 = hexstr2bin("415fad6271580a531d4179bc891d87a6"),
- Case6 = hexstr2bin("80b24263c7c1a3ebb71493c1dd7be8b4"
- "9b46d1f41b4aeec1121b013783f8f352"
- "6b56d037e05f2598bd0fd2215d6a1e52"
- "95e64f73f63f0aec8b915a985d786598"),
- Case7 = hexstr2bin("e37b6a775dc87dbaa4dfa9f96e5e3ffd"
- "debd71f8867289865df5a32d20cdc944"
- "b6022cac3c4982b10d5eeb55c3e4de15"
- "134676fb6de0446065c97440fa8c6a58"),
- hmac_rfc4231_cases_do(sha512, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
-
-hmac_rfc4231_cases_do(Hash, CasesData) ->
- hmac_rfc4231_cases_do(Hash, [case1, case2, case3, case4, case5, case6, case7], CasesData).
-
-hmac_rfc4231_cases_do(_Hash, _, []) ->
+hash(_, [], []) ->
ok;
-hmac_rfc4231_cases_do(Hash, [C|Cases], [D|CasesData]) ->
- hmac_rfc4231_case(Hash, C, D),
- hmac_rfc4231_cases_do(Hash, Cases, CasesData).
-
-hmac_update_md5_io(doc) ->
- ["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. "
- "Expected values for examples are generated using crypto:md5_mac." ];
-hmac_update_md5_io(suite) ->
- [];
-hmac_update_md5_io(Config) when is_list(Config) ->
- ?line Key = ["A fine speach", "by a fine man!"],
- ?line Data = "Sampl",
- ?line Data2 = "e #1",
- ?line Ctx = crypto:hmac_init(md5, Key),
- ?line Ctx2 = crypto:hmac_update(Ctx, Data),
- ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
- ?line Mac = crypto:hmac_final(Ctx3),
- ?line Exp = crypto:md5_mac(Key, lists:flatten([Data, Data2])),
- ?line m(Exp, Mac).
-
-
-hmac_update_md5_n(doc) ->
- ["Generate a shortened MD5 HMAC using hmac_init, hmac_update, and hmac_final. "
- "Expected values for examples are generated using crypto:md5_mac." ];
-hmac_update_md5_n(suite) ->
- [];
-hmac_update_md5_n(Config) when is_list(Config) ->
- ?line Key = ["A fine speach", "by a fine man!"],
- ?line Data = "Sampl",
- ?line Data2 = "e #1",
- ?line Ctx = crypto:hmac_init(md5, Key),
- ?line Ctx2 = crypto:hmac_update(Ctx, Data),
- ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
- ?line Mac = crypto:hmac_final_n(Ctx3, 12),
- ?line Exp = crypto:md5_mac_96(Key, lists:flatten([Data, Data2])),
- ?line m(Exp, Mac).
-%%
-%%
-ripemd160(doc) ->
- ["Generate RIPEMD160 message digests and check the result."];
-ripemd160(suite) ->
- [];
-ripemd160(Config) when is_list(Config) ->
- ?line m(crypto:hash(ripemd160,"abc"),
- hexstr2bin("8EB208F7E05D987A9B044A8E98C6B087F15A0BFC")),
- ?line m(crypto:hash(ripemd160,"abcdbcdecdefdefgefghfghighijhijkijkljklmklm"
- "nlmnomnopnopq"),
- hexstr2bin("12A053384A9C0C88E405A06C27DCF49ADA62EB2B")).
-
-
-%%
-%%
-ripemd160_update(doc) ->
- ["Generate RIPEMD160 message digests by using ripemd160_init,"
- "ripemd160_update, and ripemd160_final and check the result."];
-ripemd160_update(suite) ->
- [];
-ripemd160_update(Config) when is_list(Config) ->
- ?line Ctx = crypto:hash_init(ripemd160),
- ?line Ctx1 = crypto:hash_update(Ctx, "abcdbcdecdefdefgefghfghighi"),
- ?line Ctx2 = crypto:hash_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"),
- ?line m(crypto:hash_final(Ctx2),
- hexstr2bin("12A053384A9C0C88E405A06C27DCF49ADA62EB2B")).
-
-%%
-%%
-sha_update(doc) ->
- ["Generate SHA message digests by using sha_init, sha_update, and"
- "sha_final, and check the result. Examples are from FIPS-180-1."];
-sha_update(suite) ->
- [];
-sha_update(Config) when is_list(Config) ->
- ?line Ctx = crypto:sha_init(),
- ?line Ctx1 = crypto:sha_update(Ctx, "abcdbcdecdefdefgefghfghighi"),
- ?line Ctx2 = crypto:sha_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"),
- ?line m(crypto:sha_final(Ctx2),
- hexstr2bin("84983E441C3BD26EBAAE4AA1F95129E5E54670F1")).
-
-%%
-%%
-sha256(doc) ->
- ["Generate SHA-256 message digests and check the result. Examples are "
- "from rfc-4634."];
-sha256(suite) ->
- [];
-sha256(Config) when is_list(Config) ->
- if_supported(sha256, fun() -> sha256_do() end).
-
-sha256_do() ->
- ?line m(crypto:hash(sha256, "abc"),
- hexstr2bin("BA7816BF8F01CFEA4141"
- "40DE5DAE2223B00361A396177A9CB410FF61F20015AD")),
- ?line m(crypto:hash(sha256, "abcdbcdecdefdefgefghfghighijhijkijkljklmklm"
- "nlmnomnopnopq"),
- hexstr2bin("248D6A61D20638B8"
- "E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")).
-
-%%
-%%
-sha256_update(doc) ->
- ["Generate SHA256 message digests by using sha256_init, sha256_update, and"
- "sha256_final, and check the result. Examples are from rfc-4634."];
-sha256_update(suite) ->
- [];
-sha256_update(Config) when is_list(Config) ->
- if_supported(sha256, fun() -> sha256_update_do() end).
-
-sha256_update_do() ->
- ?line Ctx = crypto:hash_init(sha256),
- ?line Ctx1 = crypto:hash_update(Ctx, "abcdbcdecdefdefgefghfghighi"),
- ?line Ctx2 = crypto:hash_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"),
- ?line m(crypto:hash_final(Ctx2),
- hexstr2bin("248D6A61D20638B8"
- "E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")).
-
-
-%%
-%%
-sha512(doc) ->
- ["Generate SHA-512 message digests and check the result. Examples are "
- "from rfc-4634."];
-sha512(suite) ->
- [];
-sha512(Config) when is_list(Config) ->
- if_supported(sha512, fun() -> sha512_do() end).
-
-sha512_do() ->
- ?line m(crypto:hash(sha512, "abc"),
- hexstr2bin("DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA2"
- "0A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD"
- "454D4423643CE80E2A9AC94FA54CA49F")),
- ?line m(crypto:hash(sha512, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
- "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"),
- hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1"
- "7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A"
- "C7D329EEB6DD26545E96E55B874BE909")).
-
-%%
-%%
-sha512_update(doc) ->
- ["Generate SHA512 message digests by using sha512_init, sha512_update, and"
- "sha512_final, and check the result. Examples are from rfc=4634."];
-sha512_update(suite) ->
- [];
-sha512_update(Config) when is_list(Config) ->
- if_supported(sha512, fun() -> sha512_update_do() end).
-
-sha512_update_do() ->
- ?line Ctx = crypto:hash_init(sha512),
- ?line Ctx1 = crypto:hash_update(Ctx, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"),
- ?line Ctx2 = crypto:hash_update(Ctx1, "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"),
- ?line m(crypto:hash_final(Ctx2),
- hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1"
- "7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A"
- "C7D329EEB6DD26545E96E55B874BE909")).
-
-%%
-%%
-md5_mac(doc) ->
- ["Generate some HMACs, using MD5, and check the result. Examples are "
- "from RFC-2104."];
-md5_mac(suite) ->
- [];
-md5_mac(Config) when is_list(Config) ->
- ?line m(crypto:md5_mac(hexstr2bin("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
- "Hi There"),
- hexstr2bin("9294727a3638bb1c13f48ef8158bfc9d")),
- ?line m(crypto:md5_mac(list_to_binary("Jefe"),
- "what do ya want for nothing?"),
- hexstr2bin("750c783e6ab0b503eaa86e310a5db738")),
- ?line m(crypto:md5_mac(hexstr2bin("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"),
- hexstr2bin("DDDDDDDDDDDDDDDDDDDD"
- "DDDDDDDDDDDDDDDDDDDD"
- "DDDDDDDDDDDDDDDDDDDD"
- "DDDDDDDDDDDDDDDDDDDD"
- "DDDDDDDDDDDDDDDDDDDD")),
- hexstr2bin("56be34521d144c88dbb8c733f0e8b3f6")).
-
-%%
-%%
-md5_mac_io(doc) ->
- ["Generate some HMACs, using MD5, with Key an IO-list, and check the "
- "result. Examples are from RFC-2104."];
-md5_mac_io(suite) ->
- [];
-md5_mac_io(Config) when is_list(Config) ->
- ?line Key1 = hexstr2bin("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
- ?line {B11, B12} = split_binary(Key1, 4),
- ?line Key11 = [B11,binary_to_list(B12)],
- ?line m(crypto:md5_mac(Key11, "Hi There"),
- hexstr2bin("9294727a3638bb1c13f48ef8158bfc9d")).
-
-%%
-%%
-des_cbc(doc) ->
- "Encrypt and decrypt according to CBC DES. and check the result. "
- "Example are from FIPS-81.";
-des_cbc(suite) ->
- [];
-des_cbc(Config) when is_list(Config) ->
- ?line Key = hexstr2bin("0123456789abcdef"),
- ?line IVec = hexstr2bin("1234567890abcdef"),
- ?line Plain = "Now is the time for all ",
- ?line Cipher = crypto:des_cbc_encrypt(Key, IVec, Plain),
- ?line m(Cipher, hexstr2bin("e5c7cdde872bf27c43e934008c389c"
- "0f683788499a7c05f6")),
- ?line m(list_to_binary(Plain),
- crypto:des_cbc_decrypt(Key, IVec, Cipher)),
- ?line Plain2 = "7654321 Now is the time for " ++ [0, 0, 0, 0],
- ?line Cipher2 = crypto:des_cbc_encrypt(Key, IVec, Plain2),
- ?line m(Cipher2, hexstr2bin("b9916b8ee4c3da64b4f44e3cbefb9"
- "9484521388fa59ae67d58d2e77e86062733")),
- ?line m(list_to_binary(Plain2),
- crypto:des_cbc_decrypt(Key, IVec, Cipher2)).
-
-%%
-%%
-des_cbc_iter(doc) ->
- "Encrypt and decrypt according to CBC DES in two steps, and "
- "check the result. Example are from FIPS-81.";
-des_cbc_iter(suite) ->
- [];
-des_cbc_iter(Config) when is_list(Config) ->
- ?line Key = hexstr2bin("0123456789abcdef"),
- ?line IVec = hexstr2bin("1234567890abcdef"),
- ?line Plain1 = "Now is the time ",
- ?line Plain2 = "for all ",
- ?line Cipher1 = crypto:des_cbc_encrypt(Key, IVec, Plain1),
- ?line IVec2 = crypto:des_cbc_ivec(Cipher1),
- ?line Cipher2 = crypto:des_cbc_encrypt(Key, IVec2, Plain2),
- ?line Cipher = list_to_binary([Cipher1, Cipher2]),
- ?line m(Cipher, hexstr2bin("e5c7cdde872bf27c43e934008c389c"
- "0f683788499a7c05f6")).
-
-%%
-%%
-des_cfb(doc) ->
- "Encrypt and decrypt according to CFB DES. and check the result. "
- "Example is from FIPS-81.";
-des_cfb(suite) ->
- [];
-des_cfb(Config) when is_list(Config) ->
- ?line Key = hexstr2bin("0123456789abcdef"),
- ?line IVec = hexstr2bin("1234567890abcdef"),
- ?line Plain = "Now is the",
- ?line Cipher = crypto:des_cfb_encrypt(Key, IVec, Plain),
- ?line m(Cipher, hexstr2bin("f31fda07011462ee187f")),
- ?line m(list_to_binary(Plain),
- crypto:des_cfb_decrypt(Key, IVec, Cipher)).
-
-%%
-%%
-des_cfb_iter(doc) ->
- "Encrypt and decrypt according to CFB DES in two steps, and "
- "check the result. Example is from FIPS-81.";
-des_cfb_iter(suite) ->
- [];
-des_cfb_iter(Config) when is_list(Config) ->
- ?line Key = hexstr2bin("0123456789abcdef"),
- ?line IVec = hexstr2bin("1234567890abcdef"),
- ?line Plain1 = "Now i",
- ?line Plain2 = "s the",
- ?line Cipher1 = crypto:des_cfb_encrypt(Key, IVec, Plain1),
- ?line IVec2 = crypto:des_cfb_ivec(IVec, Cipher1),
- ?line Cipher2 = crypto:des_cfb_encrypt(Key, IVec2, Plain2),
- ?line Cipher = list_to_binary([Cipher1, Cipher2]),
- ?line m(Cipher, hexstr2bin("f31fda07011462ee187f")).
-
-%%
-%%
-des_ecb(doc) ->
- "Encrypt and decrypt according to ECB DES and check the result. "
- "Example are from FIPS-81.";
-des_ecb(suite) ->
- [];
-des_ecb(Config) when is_list(Config) ->
- ?line Key = hexstr2bin("0123456789abcdef"),
- ?line Cipher1 = crypto:des_ecb_encrypt(Key, "Now is t"),
- ?line m(Cipher1, hexstr2bin("3fa40e8a984d4815")),
- ?line Cipher2 = crypto:des_ecb_encrypt(Key, "he time "),
- ?line m(Cipher2, hexstr2bin("6a271787ab8883f9")),
- ?line Cipher3 = crypto:des_ecb_encrypt(Key, "for all "),
- ?line m(Cipher3, hexstr2bin("893d51ec4b563b53")),
- ?line Cipher4 = crypto:des_ecb_decrypt(Key, hexstr2bin("3fa40e8a984d4815")),
- ?line m(Cipher4, <<"Now is t">>),
- ?line Cipher5 = crypto:des_ecb_decrypt(Key, hexstr2bin("6a271787ab8883f9")),
- ?line m(Cipher5, <<"he time ">>),
- ?line Cipher6 = crypto:des_ecb_decrypt(Key, hexstr2bin("893d51ec4b563b53")),
- ?line m(Cipher6, <<"for all ">>).
-%%
-%%
-rc2_cbc(doc) ->
- "Encrypt and decrypt according to RC2 CBC and check the result. "
- "Example stripped out from public_key application test";
-rc2_cbc(Config) when is_list(Config) ->
-
- Key = <<146,210,160,124,215,227,153,239,227,17,222,140,3,93,27,191>>,
- IV = <<72,91,135,182,25,42,35,210>>,
-
- Cipher = <<36,245,206,158,168,230,58,69,148,137,32,192,250,41,237,181,181,251, 192,2,175,135,177,171,57,30,111,117,159,149,15,28,88,158,28,81,28,115, 85,219,241,82,117,222,91,85,73,117,164,25,182,52,191,64,123,57,26,19, 211,27,253,31,194,219,231,104,247,240,172,130,119,21,225,154,101,247, 32,216,42,216,133,169,78,22,97,27,227,26,196,224,172,168,17,9,148,55, 203,91,252,40,61,226,236,221,215,160,78,63,13,181,68,57,196,241,185, 207, 116,129,152,237,60,139,247,153,27,146,161,246,222,98,185,222,152, 187,135, 236,86,34,7,110,91,230,173,34,160,242,202,222,121,127,181,140, 101,203,195, 190,88,250,86,147,127,87,72,126,171,16,71,47,110,248,88, 14,29,143,161,152, 129,236,148,22,152,186,208,119,70,8,174,193,203,100, 193,203,200,117,102,242, 134,142,96,125,135,200,217,190,76,117,50,70, 209,186,101,241,200,91,40,193,54, 90,195,38,47,59,197,38,234,86,223,16, 51,253,204,129,20,171,66,21,241,26,135,216, 196,114,110,91,15,53,40, 164,201,136,113,95,247,51,181,208,241,68,168,98,151,36, 155,72,24,57, 42,191,14,125,204,10,167,214,233,138,115,125,234,121,134,227,26,247, 77,200,117,110,117,111,168,156,206,67,159,149,189,173,150,193,91,199, 216,153,22, 189,137,185,89,160,13,131,132,58,109,28,110,246,252,251,14, 232,91,38,52,29,101,188,69,123,50,0,130,178,93,73,239,118,7,77,35,59, 253,10,159,45,86,142,37,78,232,48>>,
- Text = <<48,130,1,85,2,1,0,48,13,6,9,42,134,72,134,247,13,1,1,1,5,0,4,130,1,63,48,130, 1,59,2,1,0,2,65,0,222,187,252,44,9,214,27,173,162,169,70,47,36,34,78,84,204, 107,60,192,117,95,21,206,49,142,245,126,121,223,23,2,107,106,133,204,161,36, 40,2,114,69,4,93,242,5,42,50,154,47,154,211,209,123,120,161,5,114,173,155,34, 191,52,59,2,3,1,0,1,2,64,45,144,169,106,220,236,71,39,67,82,123,192,35,21,61, 143,13,110,150,180,12,142,210,40,39,109,70,125,132,51,6,66,159,134,112,85, 155,243,118,221,65,133,127,99,151,194,252,141,149,224,229,62,214,45,228,32, 184,85,67,14,228,161,184,161,2,33,0,255,202,240,131,130,57,49,224,115,255,83, 79,6,165,212,21,179,212,20,188,97,74,69,68,163,223,247,237,39,24,23,235,2,33, 0,222,234,48,36,33,23,219,45,59,136,55,245,143,29,165,48,255,131,207,146,131, 104,13,163,54,131,236,78,88,54,16,241,2,33,0,230,2,99,129,173,176,166,131, 241,106,143,76,9,107,70,41,121,185,228,39,124,200,159,62,216,169,5,180,111, 169,255,159,2,33,0,151,193,70,212,209,210,179,219,175,83,165,4,255,81,103,76, 92,39,24,0,222,132,208,3,244,241,10,198,171,54,227,129,2,32,43,250,20,31,16, 189,168,116,225,1,125,132,94,130,118,124,28,56,232,39,69,218,244,33,240,200, 205,9,215,101,35,135,7,7,7,7,7,7,7>>,
-
- Text = crypto:rc2_cbc_decrypt(Key, IV, Cipher),
- Cipher = crypto:rc2_cbc_encrypt(Key, IV, Text).
-
-%%
-%%
-des3_cbc(doc) ->
- "Encrypt and decrypt according to CBC 3DES, and check the result.";
-des3_cbc(suite) ->
- [];
-des3_cbc(Config) when is_list(Config) ->
- ?line Key1 = hexstr2bin("0123456789abcdef"),
- ?line Key2 = hexstr2bin("fedcba9876543210"),
- ?line Key3 = hexstr2bin("0f2d4b6987a5c3e1"),
- ?line IVec = hexstr2bin("1234567890abcdef"),
- ?line Plain = "Now is the time for all ",
- ?line Cipher = crypto:des3_cbc_encrypt(Key1, Key2, Key3, IVec, Plain),
- ?line m(Cipher, hexstr2bin("8a2667ee5577267cd9b1af2c5a0480"
- "0bac1ae66970fb2b89")),
- ?line m(list_to_binary(Plain),
- crypto:des3_cbc_decrypt(Key1, Key2, Key3, IVec, Cipher)),
- ?line Plain2 = "7654321 Now is the time for " ++ [0, 0, 0, 0],
- ?line Cipher2 = crypto:des3_cbc_encrypt(Key1, Key2, Key3, IVec, Plain2),
- ?line m(Cipher2, hexstr2bin("eb33ec6ede2c8e90f6877e77b95d5"
- "4c83cee22907f7f0041ca1b7abe202bfafe")),
- ?line m(list_to_binary(Plain2),
- crypto:des3_cbc_decrypt(Key1, Key2, Key3, IVec, Cipher2)),
-
- ?line Key = hexstr2bin("0123456789abcdef"),
- ?line DESCipher = crypto:des3_cbc_encrypt(Key, Key, Key, IVec, Plain),
- ?line m(DESCipher, hexstr2bin("e5c7cdde872bf27c43e934008c389c"
- "0f683788499a7c05f6")),
- ?line m(list_to_binary(Plain),
- crypto:des3_cbc_decrypt(Key, Key, Key, IVec, DESCipher)),
- ?line DESCipher2 = crypto:des3_cbc_encrypt(Key, Key, Key, IVec, Plain2),
- ?line m(DESCipher2, hexstr2bin("b9916b8ee4c3da64b4f44e3cbefb9"
- "9484521388fa59ae67d58d2e77e86062733")),
- ?line m(list_to_binary(Plain2),
- crypto:des3_cbc_decrypt(Key, Key, Key, IVec, DESCipher2)).
-
-%%
-%%
-des3_cfb(doc) ->
- "Encrypt and decrypt according to CFB 3DES, and check the result.";
-des3_cfb(suite) ->
- [];
-des3_cfb(Config) when is_list(Config) ->
- case openssl_version() of
- V when V < 16#90705F -> {skipped,"OpenSSL version too old"};
- _ -> des3_cfb_do()
+hash(Type, [Msg | RestMsg], [Digest| RestDigest]) ->
+ case crypto:hash(Type, Msg) of
+ Digest ->
+ hash(Type, RestMsg, RestDigest);
+ Other ->
+ ct:fail({{crypto, hash, [Type, Msg]}, {expected, Digest}, {got, Other}})
end.
-des3_cfb_do() ->
- ?line Key1 = hexstr2bin("0123456789abcdef"),
- ?line Key2 = hexstr2bin("fedcba9876543210"),
- ?line Key3 = hexstr2bin("0f2d4b6987a5c3e1"),
- ?line IVec = hexstr2bin("1234567890abcdef"),
- ?line Plain = "Now is the time for all ",
- ?line Cipher = crypto:des3_cfb_encrypt(Key1, Key2, Key3, IVec, Plain),
- ?line m(Cipher, hexstr2bin("fc0ba7a20646ba53cc8bff263f0937"
- "1deab42a00666db02c")),
- ?line m(list_to_binary(Plain),
- crypto:des3_cfb_decrypt(Key1, Key2, Key3, IVec, Cipher)),
- ?line Plain2 = "7654321 Now is the time for " ++ [0, 0, 0, 0],
- ?line Cipher2 = crypto:des3_cfb_encrypt(Key1, Key2, Key3, IVec, Plain2),
- ?line m(Cipher2, hexstr2bin("8582c59ac01897422632c0accb66c"
- "e413f5efab838fce7e41e2ba67705bad5bc")),
- ?line m(list_to_binary(Plain2),
- crypto:des3_cfb_decrypt(Key1, Key2, Key3, IVec, Cipher2)).
-
-%%
-%%
-aes_cfb(doc) ->
- "Encrypt and decrypt according to AES CFB 128 bit and check "
- "the result. Example are from NIST SP 800-38A.";
-
-aes_cfb(suite) ->
- [];
-aes_cfb(Config) when is_list(Config) ->
-
-%% Sample data from NIST Spec.Publ. 800-38A
-%% F.3.13 CFB128-AES128.Encrypt
-%% Key 2b7e151628aed2a6abf7158809cf4f3c
-%% IV 000102030405060708090a0b0c0d0e0f
-%% Segment #1
-%% Input Block 000102030405060708090a0b0c0d0e0f
-%% Output Block 50fe67cc996d32b6da0937e99bafec60
-%% Plaintext 6bc1bee22e409f96e93d7e117393172a
-%% Ciphertext 3b3fd92eb72dad20333449f8e83cfb4a
-%% Segment #2
-%% Input Block 3b3fd92eb72dad20333449f8e83cfb4a
-%% Output Block 668bcf60beb005a35354a201dab36bda
-%% Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
-%% Ciphertext c8a64537a0b3a93fcde3cdad9f1ce58b
-%% Segment #3
-%% Input Block c8a64537a0b3a93fcde3cdad9f1ce58b
-%% Output Block 16bd032100975551547b4de89daea630
-%% Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
-%% Ciphertext 26751f67a3cbb140b1808cf187a4f4df
-%% Segment #4
-%% Input Block 26751f67a3cbb140b1808cf187a4f4df
-%% Output Block 36d42170a312871947ef8714799bc5f6
-%% Plaintext f69f2445df4f9b17ad2b417be66c3710
-%% Ciphertext c04b05357c5d1c0eeac4c66f9ff7f2e6
-
- ?line Key = hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
- ?line IVec = hexstr2bin("000102030405060708090a0b0c0d0e0f"),
- ?line Plain = hexstr2bin("6bc1bee22e409f96e93d7e117393172a"),
- ?line Cipher = hexstr2bin("3b3fd92eb72dad20333449f8e83cfb4a"),
-
- %% Try all prefixes of plain and cipher.
- aes_cfb_do(byte_size(Plain), Plain, Cipher, Key, IVec).
-
-aes_cfb_do(N, Plain, Cipher, Key, IVec) when N >= 0 ->
- <<P:N/binary, _/binary>> = Plain,
- <<C:N/binary, _/binary>> = Cipher,
- ?line C = crypto:aes_cfb_128_encrypt(Key, IVec, P),
- ?line P = crypto:aes_cfb_128_decrypt(Key, IVec, C),
- aes_cfb_do(N-1, Plain, Cipher, Key, IVec);
-aes_cfb_do(_, _, _, _, _) -> ok.
-
-
-%%
-%%
-aes_cbc(doc) ->
- "Encrypt and decrypt according to AES CBC 128 bit. and check the result. "
- "Example are from NIST SP 800-38A.";
-
-aes_cbc(suite) ->
- [];
-aes_cbc(Config) when is_list(Config) ->
-
-%% Sample data from NIST Spec.Publ. 800-38A
-%% F.2.1 CBC-AES128.Encrypt
-%% Key 2b7e151628aed2a6abf7158809cf4f3c
-%% IV 000102030405060708090a0b0c0d0e0f
-%% Block #1
-%% Plaintext 6bc1bee22e409f96e93d7e117393172a
-%% Input Block 6bc0bce12a459991e134741a7f9e1925
-%% Output Block 7649abac8119b246cee98e9b12e9197d
-%% Ciphertext 7649abac8119b246cee98e9b12e9197d
-%% Block #2
-%% Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
-%% Input Block d86421fb9f1a1eda505ee1375746972c
-%% Output Block 5086cb9b507219ee95db113a917678b2
-%% Ciphertext 5086cb9b507219ee95db113a917678b2
-%% Block #3
-%% Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
-%% Input Block 604ed7ddf32efdff7020d0238b7c2a5d
-%% Output Block 73bed6b8e3c1743b7116e69e22229516
-%% Ciphertext 73bed6b8e3c1743b7116e69e22229516
-%% Block #4
-%% Plaintext f69f2445df4f9b17ad2b417be66c3710
-%% Input Block 8521f2fd3c8eef2cdc3da7e5c44ea206
-%% Output Block 3ff1caa1681fac09120eca307586e1a7
-%% Ciphertext 3ff1caa1681fac09120eca307586e1a7
-%%
-%% F.2.2 CBC-AES128.Decrypt
-%% Key 2b7e151628aed2a6abf7158809cf4f3c
-%% IV 000102030405060708090a0b0c0d0e0f
- %% Block #1
-%% Ciphertext 7649abac8119b246cee98e9b12e9197d
-%% Input Block 7649abac8119b246cee98e9b12e9197d
-%% Output Block 6bc0bce12a459991e134741a7f9e1925
-%% Plaintext 6bc1bee22e409f96e93d7e117393172a
-%% Block #2
-%% Ciphertext 5086cb9b507219ee95db113a917678b2
-%% Input Block 5086cb9b507219ee95db113a917678b2
-%% Output Block d86421fb9f1a1eda505ee1375746972c
-%% Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
-%% Block #3
-%% Ciphertext 73bed6b8e3c1743b7116e69e22229516
-%% Input Block 73bed6b8e3c1743b7116e69e22229516
-%% Output Block 604ed7ddf32efdff7020d0238b7c2a5d
-%% Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
-%% Block #4
-%% Ciphertext 3ff1caa1681fac09120eca307586e1a7
-%% Input Block 3ff1caa1681fac09120eca307586e1a7
-%% Output Block 8521f2fd3c8eef2cdc3da7e5c44ea206
-%% Plaintext f69f2445df4f9b17ad2b417be66c3710
-
- ?line Key = hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
- ?line IVec = hexstr2bin("000102030405060708090a0b0c0d0e0f"),
- ?line Plain = hexstr2bin("6bc1bee22e409f96e93d7e117393172a"),
- ?line Cipher = crypto:aes_cbc_128_encrypt(Key, IVec, Plain),
- ?line m(Cipher, hexstr2bin("7649abac8119b246cee98e9b12e9197d")),
- ?line m(Plain,
- crypto:aes_cbc_128_decrypt(Key, IVec, Cipher)).
-
-aes_cbc_iter(doc) ->
- "Encrypt and decrypt according to CBC AES in steps";
-aes_cbc_iter(suite) -> [];
-aes_cbc_iter(Config) when is_list(Config) ->
- Key = list_to_binary(lists:seq(255,256-16*17,-17)),
- IVec = list_to_binary(lists:seq(1,16*7,7)),
- Plain = <<"One, two, three o'clock, four o'clock, rock"
- "Five, six, seven o'clock, eight o'clock, rock"
- "Nine, ten, eleven o'clock, twelve o'clock, rock"
- "We're gonna rock around the clock tonight">>,
- ?line 0 = size(Plain) rem 16,
-
- ?line Cipher = crypto:aes_cbc_128_encrypt(Key, IVec, Plain),
- ?line Plain = crypto:aes_cbc_128_decrypt(Key, IVec, Cipher),
-
- ?line Cipher = aes_cbc_encrypt_iter(Key,IVec,Plain,<<>>),
- ?line Plain = aes_cbc_decrypt_iter(Key,IVec,Cipher,<<>>),
- ok.
+hash_increment(Type, Increments, Digest) ->
+ State = crypto:hash_init(Type),
+ case hash_increment(State, Increments) of
+ Digest ->
+ ok;
+ Other ->
+ ct:fail({{crypto, "hash_init/update/final", [Type, Increments]}, {expected, Digest}, {got, Other}})
+ end.
-aes_cbc_encrypt_iter(_,_,<<>>, Acc) ->
- Acc;
-aes_cbc_encrypt_iter(Key,IVec,Data, Acc) ->
- Bytes = 16 * (1 + size(Data) div (16*3)),
- <<Chunk:Bytes/binary, Rest/binary>> = Data,
- %%io:format("encrypt iter Chunk=~p Rest=~p\n",[Chunk,Rest]),
- ?line Cipher = crypto:aes_cbc_128_encrypt(Key, IVec, Chunk),
- ?line IVec2 = crypto:aes_cbc_ivec(Cipher),
- aes_cbc_encrypt_iter(Key,IVec2,Rest, <<Acc/binary, Cipher/binary>>).
-
-aes_cbc_decrypt_iter(_,_,<<>>, Acc) ->
- Acc;
-aes_cbc_decrypt_iter(Key,IVec,Data, Acc) ->
- Bytes = 16 * (1 + size(Data) div (16*5)),
- <<Chunk:Bytes/binary, Rest/binary>> = Data,
- %%io:format("decrypt iter Chunk=~p Rest=~p\n",[Chunk,Rest]),
- ?line Plain = crypto:aes_cbc_128_decrypt(Key, IVec, Chunk),
- ?line IVec2 = crypto:aes_cbc_ivec(Chunk),
- aes_cbc_decrypt_iter(Key,IVec2,Rest, <<Acc/binary, Plain/binary>>).
-
-
-aes_ctr(doc) -> "CTR";
-aes_ctr(Config) when is_list(Config) ->
- %% Sample data from NIST Spec.Publ. 800-38A
- %% F.5.1 CTR-AES128.Encrypt
- Key128 = hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
- Samples128 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
- "6bc1bee22e409f96e93d7e117393172a", % Plaintext
- "874d6191b620e3261bef6864990db6ce"},% Ciphertext
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
- "ae2d8a571e03ac9c9eb76fac45af8e51",
- "9806f66b7970fdff8617187bb9fffdff"},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
- "30c81c46a35ce411e5fbc1191a0a52ef",
- "5ae4df3edbd5d35e5b4f09020db03eab"},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
- "f69f2445df4f9b17ad2b417be66c3710",
- "1e031dda2fbe03d1792170a0f3009cee"}],
- lists:foreach(fun(S) -> aes_ctr_do(Key128,S) end, Samples128),
-
- %% F.5.3 CTR-AES192.Encrypt
- Key192 = hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
- Samples192 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
- "6bc1bee22e409f96e93d7e117393172a", % Plaintext
- "1abc932417521ca24f2b0459fe7e6e0b"},% Ciphertext
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
- "ae2d8a571e03ac9c9eb76fac45af8e51",
- "090339ec0aa6faefd5ccc2c6f4ce8e94"},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
- "30c81c46a35ce411e5fbc1191a0a52ef",
- "1e36b26bd1ebc670d1bd1d665620abf7"},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
- "f69f2445df4f9b17ad2b417be66c3710",
- "4f78a7f6d29809585a97daec58c6b050"}],
- lists:foreach(fun(S) -> aes_ctr_do(Key192,S) end, Samples192),
-
- %% F.5.5 CTR-AES256.Encrypt
- Key256 = hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
- Samples256 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
- "6bc1bee22e409f96e93d7e117393172a", % Plaintext
- "601ec313775789a5b7a7f504bbf3d228"},% Ciphertext
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
- "ae2d8a571e03ac9c9eb76fac45af8e51",
- "f443e3ca4d62b59aca84e990cacaf5c5"},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
- "30c81c46a35ce411e5fbc1191a0a52ef",
- "2b0930daa23de94ce87017ba2d84988d"},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
- "f69f2445df4f9b17ad2b417be66c3710",
- "dfc9c58db67aada613c2dd08457941a6"}],
- lists:foreach(fun(S) -> aes_ctr_do(Key256,S) end, Samples256).
-
-
-aes_ctr_do(Key,{IVec, Plain, Cipher}) ->
- ?line I = hexstr2bin(IVec),
- ?line P = hexstr2bin(Plain),
- ?line C = crypto:aes_ctr_encrypt(Key, I, P),
- ?line m(C, hexstr2bin(Cipher)),
- ?line m(P, crypto:aes_ctr_decrypt(Key, I, C)).
-
-aes_ctr_stream(doc) -> "CTR Streaming";
-aes_ctr_stream(Config) when is_list(Config) ->
- %% Sample data from NIST Spec.Publ. 800-38A
- %% F.5.1 CTR-AES128.Encrypt
- Key128 = hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
- Samples128 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
- ["6bc1bee22e409f", "96e93d7e117393172a"], % Plaintext
- ["874d6191b620e3261bef6864990db6ce"]}, % Ciphertext
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
- ["ae2d8a57", "1e03ac9c", "9eb76fac", "45af8e51"],
- ["9806f66b7970fdff","8617187bb9fffdff"]},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
- ["30c81c46a35c", "e411e5fbc119", "1a0a52ef"],
- ["5ae4df3e","dbd5d3","5e5b4f0902","0db03eab"]},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
- ["f69f2445df4f9b17ad2b417be66c3710"],
- ["1e031dda2fbe","03d1792170a0","f3009cee"]}],
- lists:foreach(fun(S) -> aes_ctr_stream_do(Key128,S) end, Samples128),
-
- %% F.5.3 CTR-AES192.Encrypt
- Key192 = hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
- Samples192 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
- ["6bc1bee22e409f96e93d7e117393172a"], % Plaintext
- ["1abc9324","17521c","a24f2b04","59fe7e6e0b"]}, % Ciphertext
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
- ["ae2d8a57", "1e03ac9c9eb76fac", "45af8e51"],
- ["090339ec0aa6faefd5ccc2c6f4ce8e94"]},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
- ["30c81c46a35ce411", "e5fbc1191a0a52ef"],
- ["1e36b26bd1","ebc670d1bd1d","665620abf7"]},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
- ["f69f2445", "df4f9b17ad", "2b417be6", "6c3710"],
- ["4f78a7f6d2980958","5a97daec58c6b050"]}],
- lists:foreach(fun(S) -> aes_ctr_stream_do(Key192,S) end, Samples192),
-
- %% F.5.5 CTR-AES256.Encrypt
- Key256 = hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
- Samples256 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
- ["6bc1bee22e409f96", "e93d7e117393172a"], % Plaintext
- ["601ec313775789", "a5b7a7f504bbf3d228"]}, % Ciphertext
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
- ["ae2d8a571e03ac9c9eb76fac45af8e51"],
- ["f443e3ca","4d62b59aca84","e990cacaf5c5"]},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
- ["30c81c46","a35ce411","e5fbc119","1a0a52ef"],
- ["2b0930daa23de94ce87017ba2d84988d"]},
- {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
- ["f69f2445df4f","9b17ad2b41","7be66c3710"],
- ["dfc9c5","8db67aada6","13c2dd08","457941a6"]}],
- lists:foreach(fun(S) -> aes_ctr_stream_do(Key256,S) end, Samples256).
-
-
-aes_ctr_stream_do(Key,{IVec, PlainList, CipherList}) ->
- ?line I = hexstr2bin(IVec),
- ?line S = crypto:aes_ctr_stream_init(Key, I),
- ?line C = aes_ctr_stream_do_iter(
- S, PlainList, [],
- fun(S2,P) -> crypto:aes_ctr_stream_encrypt(S2, P) end),
- ?line m(C, hexstr2bin(lists:flatten(CipherList))),
- ?line P = aes_ctr_stream_do_iter(
- S, CipherList, [],
- fun(S2,C2) -> crypto:aes_ctr_stream_decrypt(S2, C2) end),
- ?line m(P, hexstr2bin(lists:flatten(PlainList))).
-
-aes_ctr_stream_do_iter(_State, [], Acc, _CipherFun) ->
- iolist_to_binary(lists:reverse(Acc));
-aes_ctr_stream_do_iter(State, [Plain|Rest], Acc, CipherFun) ->
- ?line P = hexstr2bin(Plain),
- ?line {S2, C} = CipherFun(State, P),
- aes_ctr_stream_do_iter(S2, Rest, [C | Acc], CipherFun).
+hash_increment(State, []) ->
+ crypto:hash_final(State);
+hash_increment(State0, [Increment | Rest]) ->
+ State = crypto:hash_update(State0, Increment),
+ hash_increment(State, Rest).
-%%
-%%
-mod_exp_test(doc) ->
- "mod_exp testing (A ^ M % P with bignums)";
-mod_exp_test(suite) ->
- [];
-mod_exp_test(Config) when is_list(Config) ->
- mod_exp_aux_test(2, 5, 10, 8).
-
-mod_exp_aux_test(_, _, _, 0) ->
+hmac(_, [],[],[]) ->
ok;
-mod_exp_aux_test(B, E, M, N) ->
- ?line R1 = crypto:mod_exp(B, E, M),
- ?line R2 = ipow(B, E, M),
- ?line m(R1, R2),
- ?line mod_exp_aux_test(B, E*E+1, M*M+1, N-1).
-
-%%
-%%
-rand_uniform_test(doc) ->
- "rand_uniform and random_bytes testing";
-rand_uniform_test(suite) ->
- [];
-rand_uniform_test(Config) when is_list(Config) ->
- rand_uniform_aux_test(10),
- ?line 10 = size(crypto:rand_bytes(10)).
-
-rand_uniform_aux_test(0) ->
- ok;
-rand_uniform_aux_test(N) ->
- ?line L = N*1000,
- ?line H = N*100000+1,
- ?line crypto_rand_uniform(L, H),
- ?line crypto_rand_uniform(-L, L),
- ?line crypto_rand_uniform(-H, -L),
- ?line crypto_rand_uniform(-H, L),
- ?line rand_uniform_aux_test(N-1).
-
-crypto_rand_uniform(L,H) ->
- ?line R1 = crypto:rand_uniform(L, H),
- ?line t(R1 >= L),
- ?line t(R1 < H).
+hmac(sha = Type, [Key | Keys], [ <<"Test With Truncation">> = Data| Rest], [Expected | Expects]) ->
+ case crypto:hmac(Type, Key, Data, 20) of
+ Expected ->
+ ok;
+ Other ->
+ ct:fail({{crypto, hmac, [Type, Key, Data]}, {expected, Expected}, {got, Other}})
+ end,
+ hmac(Type, Keys, Rest, Expects);
+
+hmac(Type, [Key | Keys], [ <<"Test With Truncation">> = Data| Rest], [Expected | Expects]) ->
+ case crypto:hmac(Type, Key, Data, 16) of
+ Expected ->
+ ok;
+ Other ->
+ ct:fail({{crypto, hmac, [Type, Key, Data]}, {expected, Expected}, {got, Other}})
+ end,
+ hmac(Type, Keys, Rest, Expects);
+
+hmac(Type, [Key | Keys], [Data| Rest], [Expected | Expects]) ->
+ case crypto:hmac(Type, Key, Data) of
+ Expected ->
+ ok;
+ Other ->
+ ct:fail({{crypto, hmac, [Type, Key, Data]}, {expected, Expected}, {got, Other}})
+ end,
+ hmac(Type, Keys, Rest, Expects).
+
+hmac_increment(Type) ->
+ Key = hmac_key(Type),
+ Increments = hmac_inc(Type),
+ Expected = crypto:hmac(Type, Key, lists:flatten(Increments)),
+ State = crypto:hmac_init(Type, Key),
+ case hmac_increment(State, Increments) of
+ Expected ->
+ ok;
+ Other ->
+ ct:fail({{crypto, "hmac_init/update/final", [Type, Increments]}, {expected, Expected}, {got, Other}})
+ end.
+hmac_increment(State, []) ->
+ crypto:hmac_final(State);
+hmac_increment(State0, [Increment | Rest]) ->
+ State = crypto:hmac_update(State0, Increment),
+ hmac_increment(State, Rest).
+
+block_cipher({Type, Key, PlainText}) ->
+ Plain = iolist_to_binary(PlainText),
+ CipherText = crypto:block_encrypt(Type, Key, PlainText),
+ case crypto:block_decrypt(Type, Key, CipherText) of
+ Plain ->
+ ok;
+ Other ->
+ ct:fail({{crypto, block_decrypt, [Type, Key, CipherText]}, {expected, Plain}, {got, Other}})
+ end;
+
+block_cipher({Type, Key, IV, PlainText}) ->
+ Plain = iolist_to_binary(PlainText),
+ CipherText = crypto:block_encrypt(Type, Key, IV, PlainText),
+ case crypto:block_decrypt(Type, Key, IV, CipherText) of
+ Plain ->
+ ok;
+ Other ->
+ ct:fail({{crypto, block_decrypt, [Type, Key, IV, CipherText]}, {expected, Plain}, {got, Other}})
+ end.
-%%
-%%
-strong_rand_test(doc) ->
- "strong_rand_mpint and strong_random_bytes testing";
-strong_rand_test(suite) ->
- [];
-strong_rand_test(Config) when is_list(Config) ->
- strong_rand_aux_test(180),
- ?line 10 = byte_size(crypto:strong_rand_bytes(10)).
-
-strong_rand_aux_test(0) ->
- ?line t(crypto:strong_rand_mpint(0,0,0) =:= <<0,0,0,0>>),
+block_cipher_increment({Type, Key, IV, PlainTexts}) when Type == des_cbc;
+ Type == des3_cbc;
+ Type == aes_cbc;
+ Type == des_cbf
+ ->
+ block_cipher_increment(Type, Key, IV, IV, PlainTexts, iolist_to_binary(PlainTexts), []);
+block_cipher_increment({_Type, _, _, _}) ->
ok;
-strong_rand_aux_test(1) ->
- ?line t(crypto:erlint(crypto:strong_rand_mpint(1,0,1)) =:= 1),
- ?line strong_rand_aux_test(0);
-strong_rand_aux_test(N) ->
- ?line t(sru_length(crypto:strong_rand_mpint(N,-1,0)) =< N),
- ?line t(sru_length(crypto:strong_rand_mpint(N,0,0)) =:= N),
- ?line t(crypto:erlint(crypto:strong_rand_mpint(N,0,1)) band 1 =:= 1),
- ?line t(crypto:erlint(crypto:strong_rand_mpint(N,1,0)) bsr (N - 2) =:= 2#11),
- ?line strong_rand_aux_test(N-1).
-
-sru_length(Mpint) ->
- I = crypto:erlint(Mpint),
- length(erlang:integer_to_list(I, 2)).
-
-%%
-%%
-%%
-%%
-rsa_verify_test(doc) ->
- "rsa_verify testing (A ^ M % P with bignums)";
-rsa_verify_test(suite) ->
- [];
-rsa_verify_test(Config) when is_list(Config) ->
- ?line H = <<178,28,54,104,36,80,144,66,140,201,135,17,36,97,114,124,
- 194,164,172,147>>,
- ?line SigBlob = <<153,44,121,71,132,1,192,159,78,33,29,62,153,64,191,70,
- 208,239,166,208,220,167,49,111,128,67,91,253,24,63,194,241,
- 97,157,135,226,121,162,150,156,60,49,236,90,151,67,239,23,
- 92,103,89,254,17,165,78,181,64,128,13,210,86,111,209,76,
- 115,34,107,227,151,47,80,185,143,85,202,55,245,163,226,26,
- 139,104,196,6,96,82,108,197,13,0,12,70,153,109,107,180,
- 130,246,156,182,56,96,31,220,227,218,136,211,252,43,8,14,
- 145,155,191,206,72,194,80,52,54,206,53,27,6,188,195,29>>,
- ?line BadSigBlob = <<153,44,121,71,132,1,192,159,78,33,29,62,153,64,191,70,
- 208,239,166,208,220,167,49,111,128,67,91,253,24,63,194,241,
- 97,157,135,226,121,162,150,156,60,49,236,90,151,67,239,23,
- 92,103,89,254,17,165,78,181,64,128,13,210,86,111,209,76,
- 115,107,34,227,151,47,80,185,143,85,202,55,245,163,226,26,
- 139,104,196,6,96,82,108,197,13,0,12,70,153,109,107,180,
- 130,246,156,182,56,96,31,220,227,218,136,211,252,43,8,14,
- 145,155,191,206,72,194,80,52,54,206,53,27,6,188,195,29>>,
- ?line E = <<35>>,
- ?line N = <<0,199,209,142,191,86,92,148,103,37,250,217,175,169,109,10,
- 130,139,34,237,174,90,97,118,7,185,57,137,252,236,177,193,
- 228,16,62,29,153,144,64,207,152,240,152,206,136,89,64,6,
- 3,187,89,57,241,219,88,215,75,70,120,20,145,229,37,1,
- 67,138,204,17,39,231,249,239,116,142,169,99,149,41,65,123,
- 26,225,133,0,41,85,77,181,35,100,162,223,92,220,207,50,
- 63,168,193,171,174,199,23,214,201,63,157,76,125,6,54,73,
- 76,89,40,33,147,208,189,76,98,24,61,8,10,110,165,119,165>>,
- ?line Nbad = <<0,199,209,142,191,86,92,148,103,37,250,217,175,169,109,10,
- 130,139,34,237,174,90,97,118,7,185,57,137,252,236,177,193,
- 228,16,62,29,153,144,64,207,152,240,152,206,136,89,64,6,
- 3,187,89,57,241,219,88,215,75,70,120,20,145,229,37,1,
- 67,138,204,17,39,231,249,239,116,142,169,99,149,41,65,123,
- 26,225,133,0,41,85,77,181,35,100,162,223,92,220,207,50,
- 63,168,193,171,174,199,23,214,201,63,157,76,125,6,54,73,
- 76,89,40,33,147,189,208,76,98,24,61,8,10,110,165,119,165>>,
- ?line Ebad = <<77>>,
- ?line m(crypto:rsa_verify(sized_binary(H), sized_binary(SigBlob),
- [sized_binary(E), sized_binary(N)]), true),
- ?line m(crypto:rsa_verify(sized_binary(H), sized_binary(SigBlob),
- [sized_binary(Ebad), sized_binary(N)]), false),
- ?line m(crypto:rsa_verify(sized_binary(H), sized_binary(SigBlob),
- [sized_binary(E), sized_binary(Nbad)]), false),
- ?line m(crypto:rsa_verify(sized_binary(H), sized_binary(BadSigBlob),
- [sized_binary(E), sized_binary(N)]), false).
-
-%%
-%%
-dsa_verify_test(doc) ->
- "dsa_verify testing (A ^ M % P with bignums)";
-dsa_verify_test(suite) ->
- [];
-dsa_verify_test(Config) when is_list(Config) ->
- ?line Msg = <<48,130,2,245,160,3,2,1,2,2,1,1,48,9,6,7,42,134,72,206,56,4,3,48,
- 58,49,11,48,9,6,3,85,4,6,19,2,85,83,49,26,48,24,6,3,85,4,10,19,17,
- 84,101,115,116,32,67,101,114,116,105,102,105,99,97,116,101,115,49,
- 15,48,13,6,3,85,4,3,19,6,68,83,65,32,67,65,48,30,23,13,48,49,48,
- 52,49,57,49,52,53,55,50,48,90,23,13,49,49,48,52,49,57,49,52,53,55,
- 50,48,90,48,93,49,11,48,9,6,3,85,4,6,19,2,85,83,49,26,48,24,6,3,
- 85,4,10,19,17,84,101,115,116,32,67,101,114,116,105,102,105,99,97,
- 116,101,115,49,50,48,48,6,3,85,4,3,19,41,86,97,108,105,100,32,68,
- 83,65,32,83,105,103,110,97,116,117,114,101,115,32,69,69,32,67,101,
- 114,116,105,102,105,99,97,116,101,32,84,101,115,116,52,48,130,1,
- 182,48,130,1,43,6,7,42,134,72,206,56,4,1,48,130,1,30,2,129,129,0,
- 228,139,175,64,140,21,215,61,124,238,3,150,18,104,193,32,5,232,23,
- 202,158,116,101,75,154,84,151,42,120,51,218,165,197,114,234,52,
- 179,148,104,66,213,27,253,119,240,168,66,158,100,147,144,182,194,
- 2,49,70,19,122,3,105,204,152,45,86,157,94,35,95,40,191,173,127,15,
- 208,105,149,98,92,26,7,42,94,140,115,73,126,253,18,34,142,85,229,
- 86,233,174,114,41,150,135,8,39,215,119,67,240,134,184,9,10,27,20,
- 165,230,3,230,69,121,77,233,250,83,95,193,9,189,126,197,195,2,21,
- 0,128,63,228,252,243,76,229,62,203,15,23,10,42,84,108,208,103,108,
- 13,59,2,129,128,102,212,22,138,32,173,254,209,50,159,165,127,167,
- 179,208,234,119,63,235,108,162,228,41,216,216,188,33,221,154,247,
- 204,229,180,119,77,223,236,218,162,140,156,117,18,90,31,254,102,
- 211,17,194,239,132,67,236,169,136,110,76,186,76,63,53,150,199,103,
- 252,153,189,15,153,41,19,145,78,216,2,174,254,107,175,80,86,170,
- 47,30,181,42,200,238,34,71,37,120,107,33,221,20,63,206,240,16,129,
- 247,150,29,156,65,187,94,68,146,93,46,198,30,184,205,105,200,143,
- 63,59,62,208,79,162,206,217,3,129,132,0,2,129,128,15,83,40,172,56,
- 47,61,243,17,97,65,195,61,167,214,122,247,246,1,50,211,33,113,16,
- 20,213,195,62,77,235,25,162,140,175,158,8,61,65,10,255,204,162,71,
- 130,122,86,161,163,253,236,178,139,183,57,181,202,160,25,133,130,
- 155,150,104,168,187,107,186,144,164,225,173,101,182,68,49,210,30,
- 34,47,83,65,79,250,156,248,47,232,44,67,36,22,126,43,216,100,247,
- 100,250,240,121,72,29,185,2,109,144,54,204,235,54,15,242,57,171,
- 125,39,236,247,71,111,221,51,196,126,77,238,36,87,163,107,48,105,
- 48,29,6,3,85,29,14,4,22,4,20,179,51,215,81,162,4,13,68,251,157,64,
- 241,18,98,113,176,83,246,105,13,48,31,6,3,85,29,35,4,24,48,22,128,
- 20,116,21,213,36,28,189,94,101,136,31,225,139,9,126,127,234,25,72,
- 78,97,48,23,6,3,85,29,32,4,16,48,14,48,12,6,10,96,134,72,1,101,3,
- 2,1,48,1,48,14,6,3,85,29,15,1,1,255,4,4,3,2,6,192>>,
-
- ?line SigBlob = <<48,45,2,21,0,140,167,200,210,153,212,64,155,249,33,146,104,243,
- 39,38,9,115,162,89,24,2,20,76,254,31,128,187,48,128,215,216,
- 112,198,78,118,160,217,157,180,246,64,234>>,
- ?line P_p = 157224271412839155721795253728878055347359513988016145491388196653004661857517720927482198111104095793441029858267073789634147217022008635826863307553453131345099940951090826856271796188522037524757740796268675508118348391218066949174594918958269259937813776150149068811425194955973128428675945283593831134219,
- ?line Q_p = 1181895316321540581845959276009400765315408342791,
- ?line G_p = 143872196713149000950547166575757355261637863805587906227228163275557375159769599033632918292482002186641475268486598023281100659643528846513898847919251032731261718358900479488287933293278745715922865499005559197328388506945134386346185262919258658109015074718441639029135304654725637911172671711310801418648,
-
- ?line Key = 12603618348903387232593303690286336220738319446775939686476278478034365380027994899970214309288018488811754534229198764622077544117034174589418477472887827980332636062691833965078594576024299807057520016043084384987871640003684704483975314128362610573625803532737054022545217931847268776098203204571431581966,
-
- ValidKey = [crypto:mpint(P_p),
- crypto:mpint(Q_p),
- crypto:mpint(G_p),
- crypto:mpint(Key)
- ],
-
- ?line m(my_dss_verify(sized_binary(Msg), sized_binary(SigBlob),
- ValidKey), true),
-
- BadMsg = one_bit_wrong(Msg),
- ?line m(my_dss_verify(sized_binary(BadMsg), sized_binary(SigBlob),
- ValidKey), false),
- BadSig = one_bit_wrong(SigBlob),
- ?line m(my_dss_verify(sized_binary(Msg), sized_binary(BadSig),
- ValidKey), false),
- SizeErr = size(SigBlob) - 13,
-
- BadArg = (catch my_dss_verify(sized_binary(Msg), <<SizeErr:32, SigBlob/binary>>,
- ValidKey)),
- badarg = case element(1,element(2,BadArg)) of
- badarg -> badarg;
- function_clause -> badarg;
- X -> X
- end,
- InValidKey = [crypto:mpint(P_p),
- crypto:mpint(Q_p),
- crypto:mpint(G_p),
- crypto:mpint(Key+17)
- ],
-
- ?line m(my_dss_verify(sized_binary(Msg), sized_binary(SigBlob),
- InValidKey), false).
-
-
-one_bit_wrong(List) when is_list(List) ->
- lists:map(fun(Bin) -> one_bit_wrong(Bin) end, List);
-one_bit_wrong(Bin) ->
- Half = size(Bin) div 2,
- <<First:Half/binary, Byte:8, Last/binary>> = Bin,
- <<First/binary, (Byte+1):8, Last/binary>>.
-
-
-%%
-%% Sign tests
-
-rsa_sign_test(doc) ->
- "rsa_sign testing";
-rsa_sign_test(suite) ->
- [];
-rsa_sign_test(Config) when is_list(Config) ->
- PubEx = 65537,
- PrivEx = 7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945,
- Mod = 7919488123861148172698919999061127847747888703039837999377650217570191053151807772962118671509138346758471459464133273114654252861270845708312601272799123,
- Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
- "09812312908312378623487263487623412039812 huagasd">>,
-
- PrivKey = [PubEx, Mod, PrivEx],
- PubKey = [PubEx, Mod],
- PubKeyMpint = map_int_to_mpint(PubKey),
- Sig1 = crypto:rsa_sign(sized_binary(Msg), map_int_to_mpint(PrivKey)),
- Sig1 = crypto:sign(rsa, sha, Msg, PrivKey),
- true = crypto:rsa_verify(sized_binary(Msg), sized_binary(Sig1), PubKeyMpint),
- true = crypto:verify(rsa, sha, Msg, Sig1, PubKey),
-
- Sig2 = crypto:rsa_sign(md5, sized_binary(Msg), map_int_to_mpint(PrivKey)),
- Sig2 = crypto:sign(rsa, md5, Msg, PrivKey),
- true = crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig2), PubKeyMpint),
- true = crypto:verify(rsa, md5, Msg, Sig2, PubKey),
-
- false = (Sig1 =:= Sig2),
- false = crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig1), PubKeyMpint),
- false = crypto:verify(rsa, md5, Msg, Sig1, PubKey),
- true = crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig1), PubKeyMpint),
- true = crypto:verify(rsa, sha, Msg, Sig1, PubKey),
-
+block_cipher_increment({_,_,_}) ->
ok.
-map_int_to_mpint(List) ->
- lists:map(fun(E) -> crypto:mpint(E) end, List).
-
-rsa_sign_hash_test(doc) ->
- "rsa_sign_hash testing";
-rsa_sign_hash_test(suite) ->
- [];
-rsa_sign_hash_test(Config) when is_list(Config) ->
- PubEx = 65537,
- PrivEx = 7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945,
- Mod = 7919488123861148172698919999061127847747888703039837999377650217570191053151807772962118671509138346758471459464133273114654252861270845708312601272799123,
- Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
- "09812312908312378623487263487623412039812 huagasd">>,
-
- PrivKey = [crypto:mpint(PubEx), crypto:mpint(Mod), crypto:mpint(PrivEx)],
- PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)],
- MD5 = crypto:md5(sized_binary(Msg)),
- SHA = crypto:sha(sized_binary(Msg)),
- ?line Sig1 = crypto:rsa_sign(sha, {digest,SHA}, PrivKey),
- ?line m(crypto:rsa_verify(sha, {digest,SHA}, sized_binary(Sig1),PubKey), true),
-
- ?line Sig2 = crypto:rsa_sign(md5, {digest,MD5}, PrivKey),
- ?line m(crypto:rsa_verify(md5, {digest,MD5}, sized_binary(Sig2),PubKey), true),
-
- ?line m(Sig1 =:= Sig2, false),
- ?line m(crypto:rsa_verify(md5, {digest,MD5}, sized_binary(Sig1),PubKey), false),
- ?line m(crypto:rsa_verify(sha, {digest,SHA}, sized_binary(Sig2),PubKey), false),
+block_cipher_increment(Type, Key, IV0, _IV, [], Plain, Acc) ->
+ CipherText = iolist_to_binary(lists:reverse(Acc)),
+ case crypto:block_decrypt(Type, Key, IV0, CipherText) of
+ Plain ->
+ ok;
+ Other ->
+ ct:fail({{crypto, block_decrypt, [Type, Key, IV0, CipherText]}, {expected, Plain}, {got, Other}})
+ end;
+block_cipher_increment(Type, Key, IV0, IV, [PlainText | PlainTexts], Plain, Acc) ->
+ CipherText = crypto:block_encrypt(Type, Key, IV, PlainText),
+ NextIV = crypto:next_iv(Type, CipherText),
+ block_cipher_increment(Type, Key, IV0, NextIV, PlainTexts, Plain, [CipherText | Acc]).
+
+stream_cipher({Type, Key, PlainText}) ->
+ Plain = iolist_to_binary(PlainText),
+ State = crypto:stream_init(Type, Key),
+ {_, CipherText} = crypto:stream_encrypt(State, PlainText),
+ case crypto:stream_decrypt(State, CipherText) of
+ {_, Plain} ->
+ ok;
+ Other ->
+ ct:fail({{crypto, stream_decrypt, [State, CipherText]}, {expected, PlainText}, {got, Other}})
+ end;
+stream_cipher({Type, Key, IV, PlainText}) ->
+ Plain = iolist_to_binary(PlainText),
+ State = crypto:stream_init(Type, Key, IV),
+ {_, CipherText} = crypto:stream_encrypt(State, PlainText),
+ case crypto:stream_decrypt(State, CipherText) of
+ {_, Plain} ->
+ ok;
+ Other ->
+ ct:fail({{crypto, stream_decrypt, [State, CipherText]}, {expected, PlainText}, {got, Other}})
+ end.
- ok.
+stream_cipher_incment({Type, Key, PlainTexts}) ->
+ State = crypto:stream_init(Type, Key),
+ stream_cipher_incment(State, State, PlainTexts, [], iolist_to_binary(PlainTexts));
+stream_cipher_incment({Type, Key, IV, PlainTexts}) ->
+ State = crypto:stream_init(Type, Key, IV),
+ stream_cipher_incment(State, State, PlainTexts, [], iolist_to_binary(PlainTexts)).
+
+stream_cipher_incment(_State, OrigState, [], Acc, Plain) ->
+ CipherText = iolist_to_binary(lists:reverse(Acc)),
+ case crypto:stream_decrypt(OrigState, CipherText) of
+ {_, Plain} ->
+ ok;
+ Other ->
+ ct:fail({{crypto, stream_decrypt, [OrigState, CipherText]}, {expected, Plain}, {got, Other}})
+ end;
+stream_cipher_incment(State0, OrigState, [PlainText | PlainTexts], Acc, Plain) ->
+ {State, CipherText} = crypto:stream_encrypt(State0, PlainText),
+ stream_cipher_incment(State, OrigState, PlainTexts, [CipherText | Acc], Plain).
+
+do_sign_verify({Type, Hash, Public, Private, Msg}) ->
+ Signature = crypto:sign(Type, Hash, Msg, Private),
+ case crypto:verify(Type, Hash, Msg, Signature, Public) of
+ true ->
+ negative_verify(Type, Hash, Msg, <<10,20>>, Public);
+ false ->
+ ct:fail({{crypto, verify, [Type, Hash, Msg, Signature, Public]}})
+ end.
-dsa_sign_test(doc) ->
- "dsa_sign testing";
-dsa_sign_test(suite) ->
- [];
-dsa_sign_test(Config) when is_list(Config) ->
- Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
- "09812312908312378623487263487623412039812 huagasd">>,
-
- PubKey = _Y = 25854665488880835237281628794585130313500176551981812527054397586638455298000483144002221850980183404910190346416063318160497344811383498859129095184158800144312512447497510551471331451396405348497845813002058423110442376886564659959543650802132345311573634832461635601376738282831340827591903548964194832978,
- PrivKey = _X = 441502407453038284293378221372000880210588566361,
- ParamP = 109799869232806890760655301608454668257695818999841877165019612946154359052535682480084145133201304812979481136659521529774182959764860329095546511521488413513097576425638476458000255392402120367876345280670101492199681798674053929238558140260669578407351853803102625390950534052428162468100618240968893110797,
- ParamQ = 1349199015905534965792122312016505075413456283393,
- ParamG = 18320614775012672475365915366944922415598782131828709277168615511695849821411624805195787607930033958243224786899641459701930253094446221381818858674389863050420226114787005820357372837321561754462061849169568607689530279303056075793886577588606958623645901271866346406773590024901668622321064384483571751669,
-
- Params = [crypto:mpint(ParamP), crypto:mpint(ParamQ), crypto:mpint(ParamG)],
- ?line Sig1 = my_dss_sign(sized_binary(Msg), Params ++ [crypto:mpint(PrivKey)]),
-
- ?line m(my_dss_verify(sized_binary(Msg), Sig1,
- Params ++ [crypto:mpint(PubKey)]), true),
-
- ?line m(my_dss_verify(sized_binary(one_bit_wrong(Msg)), Sig1,
- Params ++ [crypto:mpint(PubKey)]), false),
-
- ?line m(my_dss_verify(sized_binary(Msg), one_bit_wrong(Sig1),
- Params ++ [crypto:mpint(PubKey)]), false),
+negative_verify(Type, Hash, Msg, Signature, Public) ->
+ case crypto:verify(Type, Hash, Msg, Signature, Public) of
+ true ->
+ ct:fail({{crypto, verify, [Type, Hash, Msg, Signature, Public]}, should_fail});
+ false ->
+ ok
+ end.
- %%?line Bad = crypto:dss_sign(sized_binary(Msg), [Params, crypto:mpint(PubKey)]),
+do_public_encrypt({Type, Public, Private, Msg, Padding}) ->
+ PublicEcn = crypto:public_encrypt(Type, Msg, Public, Padding),
+ case crypto:private_decrypt(Type, PublicEcn, Private, Padding) of
+ Msg ->
+ ok;
+ Other ->
+ ct:fail({{crypto, private_decrypt, [Type, PublicEcn, Private, Padding]}, {expected, Msg}, {got, Other}})
+ end.
+do_private_encrypt({Type, Public, Private, Msg, Padding}) ->
+ PrivEcn = crypto:private_encrypt(Type, Msg, Private, Padding),
+ case crypto:public_decrypt(Type, PrivEcn, Public, Padding) of
+ Msg ->
+ ok;
+ Other ->
+ ct:fail({{crypto, public_decrypt, [Type, PrivEcn, Public, Padding]}, {expected, Msg}, {got, Other}})
+ end.
+
+do_generate_compute({srp = Type, UserPrivate, UserGenParams, UserComParams,
+ HostPublic, HostPrivate, HostGenParams, HostComParam, SessionKey}) ->
+ {UserPublic, UserPrivate} = crypto:generate_key(Type, UserGenParams, UserPrivate),
+ {HostPublic, HostPrivate} = crypto:generate_key(Type, HostGenParams, HostPrivate),
+ SessionKey = crypto:compute_key(Type, HostPublic, {UserPublic, UserPrivate},
+ UserComParams),
+ SessionKey = crypto:compute_key(Type, UserPublic, {HostPublic, HostPrivate},
+ HostComParam);
+do_generate_compute({dh, P, G}) ->
+ {UserPub, UserPriv} = crypto:generate_key(dh, [P, G]),
+ {HostPub, HostPriv} = crypto:generate_key(dh, [P, G]),
+ SharedSecret = crypto:compute_key(dh, HostPub, UserPriv, [P, G]),
+ SharedSecret = crypto:compute_key(dh, UserPub, HostPriv, [P, G]).
- ok.
-
-dsa_sign_hash_test(doc) ->
- "dsa_sign_hash testing";
-dsa_sign_hash_test(suite) ->
- [];
-dsa_sign_hash_test(Config) when is_list(Config) ->
- Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
- "09812312908312378623487263487623412039812 huagasd">>,
- SHA = crypto:sha(sized_binary(Msg)),
-
- PubKey = _Y = 25854665488880835237281628794585130313500176551981812527054397586638455298000483144002221850980183404910190346416063318160497344811383498859129095184158800144312512447497510551471331451396405348497845813002058423110442376886564659959543650802132345311573634832461635601376738282831340827591903548964194832978,
- PrivKey = _X = 441502407453038284293378221372000880210588566361,
- ParamP = 109799869232806890760655301608454668257695818999841877165019612946154359052535682480084145133201304812979481136659521529774182959764860329095546511521488413513097576425638476458000255392402120367876345280670101492199681798674053929238558140260669578407351853803102625390950534052428162468100618240968893110797,
- ParamQ = 1349199015905534965792122312016505075413456283393,
- ParamG = 18320614775012672475365915366944922415598782131828709277168615511695849821411624805195787607930033958243224786899641459701930253094446221381818858674389863050420226114787005820357372837321561754462061849169568607689530279303056075793886577588606958623645901271866346406773590024901668622321064384483571751669,
-
- Params = [crypto:mpint(ParamP), crypto:mpint(ParamQ), crypto:mpint(ParamG)],
- ?line Sig1 = crypto:dss_sign(sha, {digest,SHA}, Params ++ [crypto:mpint(PrivKey)]),
+do_compute({ecdh = Type, Pub, Priv, Curve, SharedSecret}) ->
+ Secret = crypto:bytes_to_integer(crypto:compute_key(Type, Pub, Priv, Curve)),
+ case Secret of
+ SharedSecret ->
+ ok;
+ Other ->
+ ct:fail({{crypto, compute_key, [Type, Pub, Priv, Curve]}, {expected, SharedSecret}, {got, Other}})
+ end.
- ?line m(crypto:dss_verify(none, SHA, sized_binary(Sig1),
- Params ++ [crypto:mpint(PubKey)]), true),
+hexstr2bin(S) ->
+ list_to_binary(hexstr2list(S)).
- ?line m(crypto:dss_verify(sized_binary(one_bit_wrong(Msg)), sized_binary(Sig1),
- Params ++ [crypto:mpint(PubKey)]), false),
+hexstr2list([X,Y|T]) ->
+ [mkint(X)*16 + mkint(Y) | hexstr2list(T)];
+hexstr2list([]) ->
+ [].
+mkint(C) when $0 =< C, C =< $9 ->
+ C - $0;
+mkint(C) when $A =< C, C =< $F ->
+ C - $A + 10;
+mkint(C) when $a =< C, C =< $f ->
+ C - $a + 10.
- ?line m(crypto:dss_verify(sized_binary(Msg), sized_binary(one_bit_wrong(Sig1)),
- Params ++ [crypto:mpint(PubKey)]), false),
+is_supported(cipher) ->
+ true;
+is_supported(Group) ->
+ lists:member(Group, lists:append([Algo || {_, Algo} <- crypto:supports()])).
+
+block_iolistify(Blocks) ->
+ lists:map(fun do_block_iolistify/1, Blocks).
+stream_iolistify(Streams) ->
+ lists:map(fun do_stream_iolistify/1, Streams).
+
+do_stream_iolistify({Type, Key, PlainText}) ->
+ {Type, iolistify(Key), iolistify(PlainText)};
+do_stream_iolistify({Type, Key, IV, PlainText}) ->
+ {Type, iolistify(Key), IV, iolistify(PlainText)}.
+
+do_block_iolistify({des_cbc = Type, Key, IV, PlainText}) ->
+ {Type, Key, IV, des_iolistify(PlainText)};
+do_block_iolistify({des3_cbc = Type, Key, IV, PlainText}) ->
+ {Type, Key, IV, des_iolistify(PlainText)};
+do_block_iolistify({des3_cbf = Type, Key, IV, PlainText}) ->
+ {Type, Key, IV, des_iolistify(PlainText)};
+do_block_iolistify({Type, Key, PlainText}) ->
+ {Type, iolistify(Key), iolistify(PlainText)};
+do_block_iolistify({Type, Key, IV, PlainText}) ->
+ {Type, iolistify(Key), IV, iolistify(PlainText)}.
+
+iolistify(<<"Test With Truncation">>)->
+ %% Do not iolistify as it spoils this special case
+ <<"Test With Truncation">>;
+iolistify(Msg)->
+ Length = erlang:byte_size(Msg),
+ Split = Length div 2,
+ List0 = binary_to_list(Msg),
+ case lists:split(Split, List0) of
+ {[Element | List1], List2} ->
+ [[Element], List1, List2];
+ {List1, List2}->
+ [List1, List2]
+ end.
+
+des_iolistify(Msg) ->
+ des_iolist(erlang:byte_size(Msg) div 8, Msg, []).
+
+des_iolist(1, Msg, Acc) ->
+ lists:reverse([Msg | Acc]);
+des_iolist(Split, Msg, Acc) ->
+ <<Part:8/binary, Rest/binary>> = Msg,
+ des_iolist(Split-1, Rest, [Part | Acc]).
+
+%%--------------------------------------------------------------------
+mod_pow_aux_test(_, _, _, 0) ->
+ ok;
+mod_pow_aux_test(B, E, M, N) ->
+ Result = crypto:bytes_to_integer(crypto:mod_pow(B, E, M)),
+ Result = ipow(B, E, M),
+ mod_pow_aux_test(B, E*E+1, M*M+1, N-1).
- %%?line Bad = crypto:dss_sign(sized_binary(Msg), [Params, crypto:mpint(PubKey)]),
+%% mod_exp in erlang (copied from jungerl's ssh_math.erl)
+ipow(A, B, M) when M > 0, B >= 0 ->
+ if A == 1 ->
+ 1;
+ true ->
+ ipow(A, B, M, 1)
+ end.
- ok.
+ipow(A, 1, M, Prod) ->
+ (A*Prod) rem M;
+ipow(_A, 0, _M, Prod) ->
+ Prod;
+ipow(A, B, M, Prod) ->
+ B1 = B bsr 1,
+ A1 = (A*A) rem M,
+ if B - B1 == B1 ->
+ ipow(A1, B1, M, Prod);
+ true ->
+ ipow(A1, B1, M, (A*Prod) rem M)
+ end.
+zero_bin(N) when is_integer(N) ->
+ N8 = N * 8,
+ <<0:N8/integer>>;
+zero_bin(B) when is_binary(B) ->
+ zero_bin(size(B)).
+xor_bytes(Bin1, Bin2) when is_binary(Bin1), is_binary(Bin2) ->
+ L1 = binary_to_list(Bin1),
+ L2 = binary_to_list(Bin2),
+ list_to_binary(xor_bytes(L1, L2));
+xor_bytes(L1, L2) ->
+ xor_bytes(L1, L2, []).
-rsa_encrypt_decrypt(doc) ->
- ["Test rsa_public_encrypt and rsa_private_decrypt functions."];
-rsa_encrypt_decrypt(suite) -> [];
-rsa_encrypt_decrypt(Config) when is_list(Config) ->
- PubEx = 65537,
- PrivEx = 7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945,
- Mod = 7919488123861148172698919999061127847747888703039837999377650217570191053151807772962118671509138346758471459464133273114654252861270845708312601272799123,
-
- PrivKey = [PubEx, Mod, PrivEx],
- PubKey = [PubEx, Mod],
+xor_bytes([], [], Acc) ->
+ lists:reverse(Acc);
+xor_bytes([N1 | Tl1], [N2 | Tl2], Acc) ->
+ xor_bytes(Tl1, Tl2, [N1 bxor N2 | Acc]).
- Msg = <<"7896345786348 Asldi">>,
+%%--------------------------------------------------------------------
+%% Test data ------------------------------------------------
+%%--------------------------------------------------------------------
+group_config(md4 = Type, Config) ->
+ Msgs = rfc_1321_msgs(),
+ Digests = rfc_1321_md4_digests(),
+ [{hash, {Type, Msgs, Digests}} | Config];
+group_config(md5 = Type, Config) ->
+ Msgs = rfc_1321_msgs(),
+ Digests = rfc_1321_md5_digests(),
+ Keys = rfc_2202_md5_keys(),
+ Data = rfc_2202_msgs(),
+ Hmac = rfc_2202_hmac_md5(),
+ [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config];
+group_config(ripemd160 = Type, Config) ->
+ Msgs = ripemd160_msgs(),
+ Digests = ripemd160_digests(),
+ [{hash, {Type, Msgs, Digests}} | Config];
+group_config(sha = Type, Config) ->
+ Msgs = [rfc_4634_test1(), rfc_4634_test2_1()],
+ Digests = rfc_4634_sha_digests(),
+ Keys = rfc_2202_sha_keys(),
+ Data = rfc_2202_msgs(),
+ Hmac = rfc_2202_hmac_sha(),
+ [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config];
+group_config(sha224 = Type, Config) ->
+ Msgs = [rfc_4634_test1(), rfc_4634_test2_1()],
+ Digests = rfc_4634_sha224_digests(),
+ Keys = rfc_4231_keys(),
+ Data = rfc_4231_msgs(),
+ Hmac = rfc4231_hmac_sha224(),
+ [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config];
+group_config(sha256 = Type, Config) ->
+ Msgs = [rfc_4634_test1(), rfc_4634_test2_1()],
+ Digests = rfc_4634_sha256_digests(),
+ Keys = rfc_4231_keys(),
+ Data = rfc_4231_msgs(),
+ Hmac = rfc4231_hmac_sha256(),
+ [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config];
+group_config(sha384 = Type, Config) ->
+ Msgs = [rfc_4634_test1(), rfc_4634_test2()],
+ Digests = rfc_4634_sha384_digests(),
+ Keys = rfc_4231_keys(),
+ Data = rfc_4231_msgs(),
+ Hmac = rfc4231_hmac_sha384(),
+ [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config];
+group_config(sha512 = Type, Config) ->
+ Msgs = [rfc_4634_test1(), rfc_4634_test2()],
+ Digests = rfc_4634_sha512_digests(),
+ Keys = rfc_4231_keys(),
+ Data = rfc_4231_msgs(),
+ Hmac = rfc4231_hmac_sha512(),
+ [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config];
+group_config(rsa = Type, Config) ->
+ Msg = rsa_plain(),
+ Public = rsa_public(),
+ Private = rsa_private(),
+ SignVerify = [{Type, md5, Public, Private, Msg},
+ {Type, sha, Public, Private, Msg},
+ {Type, sha224, Public, Private,Msg},
+ {Type, sha256, Public, Private,Msg}
+ %% {Type, sha384, Public, Private,Msg},
+ %% {Type, sha512, Public, Private, Msg}
+ ],
+ MsgPubEnc = <<"7896345786348 Asldi">>,
+ PubPrivEnc = [{rsa, Public, Private, MsgPubEnc, rsa_pkcs1_padding}
+ %%{rsa, Public, Private, MsgPubEnc, rsa_pkcs1_oaep_padding}
+ %%{rsa, Public, Private, MsgPubEnc, rsa_no_padding}
+ ],
+ [{sign_verify, SignVerify}, {pub_priv_encrypt, PubPrivEnc} | Config];
+group_config(dss = Type, Config) ->
+ Msg = dss_plain(),
+ Public = dss_params() ++ [dss_public()],
+ Private = dss_params() ++ [dss_private()],
+ SignVerify = [{Type, sha, Public, Private, Msg}],
+ [{sign_verify, SignVerify} | Config];
+
+group_config(ecdsa = Type, Config) ->
+ {Private, Public} = ec_key_named(),
+ Msg = ec_msg(),
+ SignVerify = [{Type, sha, Public, Private, Msg}],
+ [{sign_verify, SignVerify} | Config];
+group_config(srp, Config) ->
+ GenerateCompute = [srp3(), srp6(), srp6a()],
+ [{generate_compute, GenerateCompute} | Config];
+group_config(ecdh, Config) ->
+ Compute = [ecdh()],
+ [{compute, Compute} | Config];
+group_config(dh, Config) ->
+ GenerateCompute = [dh()],
+ [{generate_compute, GenerateCompute} | Config];
+group_config(des_cbc, Config) ->
+ Block = des_cbc(),
+ [{block, Block} | Config];
+group_config(des_cfb, Config) ->
+ Block = des_cfb(),
+ [{block, Block} | Config];
+group_config(des3_cbc, Config) ->
+ Block = des3_cbc(),
+ [{block, Block} | Config];
+group_config(des3_cbf, Config) ->
+ Block = des3_cbf(),
+ [{block, Block} | Config];
+group_config(rc2_cbc, Config) ->
+ Block = rc2_cbc(),
+ [{block, Block} | Config];
+group_config(aes_cbc128, Config) ->
+ Block = aes_cbc128(),
+ [{block, Block} | Config];
+group_config(aes_cbc256, Config) ->
+ Block = aes_cbc256(),
+ [{block, Block} | Config];
+group_config(aes_cfb128, Config) ->
+ Block = aes_cfb128(),
+ [{block, Block} | Config];
+group_config(blowfish_cbc, Config) ->
+ Block = blowfish_cbc(),
+ [{block, Block} | Config];
+group_config(blowfish_ecb, Config) ->
+ Block = blowfish_ecb(),
+ [{block, Block} | Config];
+group_config(blowfish_cfb64, Config) ->
+ Block = blowfish_cfb64(),
+ [{block, Block} | Config];
+group_config(blowfish_ofb64, Config) ->
+ Block = blowfish_ofb64(),
+ [{block, Block} | Config];
+group_config(rc4, Config) ->
+ Stream = rc4(),
+ [{stream, Stream} | Config];
+group_config(aes_ctr, Config) ->
+ Stream = aes_ctr(),
+ [{stream, Stream} | Config];
+group_config(_, Config) ->
+ Config.
- ?line PKCS1 = rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_padding),
- ?line PKCS1Dec = rsa_private_decrypt(PKCS1, PrivKey, rsa_pkcs1_padding),
- io:format("PKCS1Dec ~p~n",[PKCS1Dec]),
- ?line Msg = PKCS1Dec,
-
- ?line OAEP = rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_oaep_padding),
- ?line Msg = rsa_private_decrypt(OAEP, PrivKey, rsa_pkcs1_oaep_padding),
-
- <<Msg2Len:32,_/binary>> = crypto:mpint(Mod),
- Msg2 = list_to_binary(lists:duplicate(Msg2Len-1, $X)),
- ?line NoPad = rsa_public_encrypt(Msg2, PubKey, rsa_no_padding),
- ?line NoPadDec = rsa_private_decrypt(NoPad, PrivKey, rsa_no_padding),
- ?line NoPadDec = Msg2,
-
- ShouldBeError = (catch rsa_public_encrypt(Msg, PubKey, rsa_no_padding)),
- ?line {'EXIT', {encrypt_failed,_}} = ShouldBeError,
-
-%% ?line SSL = rsa_public_encrypt(Msg, PubKey, rsa_sslv23_padding),
-%% ?line Msg = rsa_private_decrypt(SSL, PrivKey, rsa_sslv23_padding),
-
- ?line PKCS1_2 = rsa_private_encrypt(Msg, PrivKey, rsa_pkcs1_padding),
- ?line PKCS1_2Dec = rsa_public_decrypt(PKCS1_2, PubKey, rsa_pkcs1_padding),
- io:format("PKCS2Dec ~p~n",[PKCS1_2Dec]),
- ?line Msg = PKCS1_2Dec,
-
- ?line PKCS1_3 = rsa_private_encrypt(Msg2, PrivKey, rsa_no_padding),
- ?line PKCS1_3Dec = rsa_public_decrypt(PKCS1_3, PubKey, rsa_no_padding),
- io:format("PKCS2Dec ~p~n",[PKCS1_3Dec]),
- ?line Msg2 = PKCS1_3Dec,
+rfc_1321_msgs() ->
+ [<<"">>,
+ <<"a">>,
+ <<"abc">>,
+ <<"message digest">>,
+ <<"abcdefghijklmnopqrstuvwxyz">>,
+ <<"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789">>,
+ <<"12345678901234567890123456789012345678901234567890123456789012345678901234567890">>
+ ].
+
+rfc_1321_md4_digests() ->
+ [hexstr2bin("31d6cfe0d16ae931b73c59d7e0c089c0"),
+ hexstr2bin("bde52cb31de33e46245e05fbdbd6fb24"),
+ hexstr2bin("a448017aaf21d8525fc10ae87aa6729d"),
+ hexstr2bin("d9130a8164549fe818874806e1c7014b"),
+ hexstr2bin("d79e1c308aa5bbcdeea8ed63df412da9"),
+ hexstr2bin("043f8582f241db351ce627e153e7f0e4"),
+ hexstr2bin("e33b4ddc9c38f2199c3e7b164fcc0536")].
+
+rfc_1321_md5_digests() ->
+ [hexstr2bin("d41d8cd98f00b204e9800998ecf8427e"),
+ hexstr2bin("0cc175b9c0f1b6a831c399e269772661"),
+ hexstr2bin("900150983cd24fb0d6963f7d28e17f72"),
+ hexstr2bin("f96b697d7cb7938d525a2f31aaf161d0"),
+ hexstr2bin("c3fcd3d76192e4007dfb496cca67e13b"),
+ hexstr2bin("d174ab98d277d9f5a5611c2c9f419d9f"),
+ hexstr2bin("57edf4a22be3c955ac49da2e2107b67a")].
+
+rfc_4634_test1() ->
+ <<"abc">>.
+rfc_4634_test2_1() ->
+ <<"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq">>.
+rfc_4634_test2_2a() ->
+ <<"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn">>.
+rfc_4634_test2_2b() ->
+ <<"hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu">>.
+rfc_4634_test2() ->
+ A2 =rfc_4634_test2_2a(),
+ B2 = rfc_4634_test2_2b(),
+ <<A2/binary, B2/binary>>.
+
+rfc_4634_sha_digests()->
+ [hexstr2bin("A9993E364706816ABA3E25717850C26C9CD0D89D"),
+ hexstr2bin("84983E441C3BD26EBAAE4AA1F95129E5E54670F1")].
+rfc_4634_sha224_digests() ->
+ [hexstr2bin("23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7"),
+ hexstr2bin("75388B16512776CC5DBA5DA1FD890150B0C6455CB4F58B1952522525")].
+rfc_4634_sha256_digests() ->
+ [
+ hexstr2bin("BA7816BF8F01CFEA4141"
+ "40DE5DAE2223B00361A396177A9CB410FF61F20015AD"),
+ hexstr2bin("248D6A61D20638B8"
+ "E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")
+ ].
+rfc_4634_sha384_digests() ->
+ [hexstr2bin("CB00753F45A35E8BB5A03D699AC65007272C32AB0EDED1631A8B605A43FF5BED8086072BA1E7CC2358BAECA134C825A7"),
+ hexstr2bin("09330C33F71147E83D192FC782CD1B4753111B173B3B05D22FA08086E3B0F712FCC7C71A557E2DB966C3E9FA91746039")
+ ].
+rfc_4634_sha512_digests() ->
+ [hexstr2bin("DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA2"
+ "0A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD"
+ "454D4423643CE80E2A9AC94FA54CA49F"),
+ hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA17299AEADB6889018501D289E4900F7E4331B99DEC4B5433AC7D329EEB6DD26545E96E55B874BE909")].
+
+ripemd160_msgs() ->
+ [<<"">>,
+ <<"a">>,
+ <<"abc">>,
+ <<"message digest">>,
+ <<"abcdefghijklmnopqrstuvwxyz">>,
+ <<"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq">>,
+ <<"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789">>
+ ].
+
+ripemd160_digests() ->
+ [hexstr2bin("9c1185a5c5e9fc54612808977ee8f548b2258d31"),
+ hexstr2bin("0bdc9d2d256b3ee9daae347be6f4dc835a467ffe"),
+ hexstr2bin("8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"),
+ hexstr2bin("5d0689ef49d2fae572b881b123a85ffa21595f36"),
+ hexstr2bin("f71c27109c692c1b56bbdceb5b9d2865b3708dbc"),
+ hexstr2bin("12a053384a9c0c88e405a06c27dcf49ada62eb2b"),
+ hexstr2bin("b0e20b6e3116640286ed3a87a5713079b21f5189")
+ ].
+
+ripemd160_incr_msgs() ->
+ [<<"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefg">>,<<"hijklmnopqrstuvwxyz0123456789">>].
+ripemd160_incr_digest() ->
+ hexstr2bin("b0e20b6e3116640286ed3a87a5713079b21f5189").
+
+rfc_2202_md5_keys() ->
+ [binary:copy(<<16#0b>>, 16),
+ <<"Jefe">>,
+ binary:copy(<<16#aa>>, 16),
+ list_to_binary(lists:seq(1, 16#19)),
+ binary:copy(<<16#0c>>, 16),
+ binary:copy(<<16#aa>>, 80),
+ binary:copy(<<16#aa>>, 80)].
+
+rfc_2202_sha_keys() ->
+ [binary:copy(<<16#0b>>, 20),
+ <<"Jefe">>,
+ binary:copy(<<16#aa>>, 20),
+ list_to_binary(lists:seq(1, 16#19)),
+ binary:copy(<<16#0c>>, 20),
+ binary:copy(<<16#aa>>, 80),
+ binary:copy(<<16#aa>>, 80)].
+
+rfc_2202_msgs()->
+ [<<"Hi There">>,
+ <<"what do ya want for nothing?">>,
+ binary:copy(<<16#dd>>, 50),
+ binary:copy(<<16#cd>>, 50),
+ <<"Test With Truncation">>,
+ <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
+ <<"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data">>
+ ].
+
+hmac_key(md5) ->
+ [<<"A fine speach">>, <<"by a fine man!">>];
+hmac_key(_) ->
+ hexstr2bin("00010203101112132021222330313233"
+ "04050607141516172425262734353637"
+ "08090a0b18191a1b28292a2b38393a3b"
+ "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f").
+hmac_inc(_) ->
+ [<<"Sampl">>, <<"e #1">>].
+
+rfc_2202_hmac_md5() ->
+ [
+ hexstr2bin("9294727a3638bb1c13f48ef8158bfc9d"),
+ hexstr2bin("750c783e6ab0b503eaa86e310a5db738"),
+ hexstr2bin("56be34521d144c88dbb8c733f0e8b3f6"),
+ hexstr2bin("697eaf0aca3a3aea3a75164746ffaa79"),
+ hexstr2bin("56461ef2342edc00f9bab995690efd4c"),
+ hexstr2bin("6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd"),
+ hexstr2bin("6f630fad67cda0ee1fb1f562db3aa53e")
+ ].
+
+rfc_2202_hmac_sha() ->
+ [
+ hexstr2bin("b617318655057264e28bc0b6fb378c8ef146be00"),
+ hexstr2bin("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79"),
+ hexstr2bin("125d7342b9ac11cd91a39af48aa17b4f63f175d3"),
+ hexstr2bin("4c9007f4026250c6bc8414f9bf50c86c2d7235da"),
+ hexstr2bin("4c1a03424b55e07fe7f27be1d58bb9324a9a5a04"),
+ hexstr2bin("aa4ae5e15272d00e95705637ce8a3b55ed402112"),
+ hexstr2bin("e8e99d0f45237d786d6bbaa7965c7808bbff1a91")
+ ].
+
+
+rfc_4231_keys() ->
+ [binary:copy(<<16#0b>>, 20),
+ <<"Jefe">>,
+ binary:copy(<<16#aa>>, 20),
+ list_to_binary(lists:seq(1, 16#19)),
+ binary:copy(<<16#0c>>, 20),
+ binary:copy(<<16#aa>>, 131),
+ binary:copy(<<16#aa>>, 131)
+ ].
- ?line {'EXIT', {encrypt_failed,_}} =
- (catch rsa_private_encrypt(Msg, PrivKey, rsa_no_padding)),
+rfc_4231_msgs() ->
+ [<<"Hi There">>,
+ <<"what do ya want for nothing?">>,
+ binary:copy(<<16#dd>>, 50),
+ binary:copy(<<16#cd>>, 50),
+ <<"Test With Truncation">>,
+ <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
+ <<"This is a test using a larger than block-size key and a larger t",
+ "han block-size data. The key needs to be hashed before being use",
+ "d by the HMAC algorithm.">>
+ ].
- ok.
-
-rsa_public_encrypt(Msg, Key, Pad) ->
- C1 = crypto:rsa_public_encrypt(Msg, Key, Pad),
- C2 = crypto:rsa_public_encrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad),
- {C1,C2}.
-
-rsa_public_decrypt(Msg, Key, Pad) ->
- R = crypto:rsa_public_decrypt(Msg, Key, Pad),
- R = crypto:rsa_public_decrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad).
-
-rsa_private_encrypt(Msg, Key, Pad) ->
- R = crypto:rsa_private_encrypt(Msg, Key, Pad),
- R = crypto:rsa_private_encrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad).
-
-rsa_private_decrypt({C1,C2}, Key, Pad) ->
- R = crypto:rsa_private_decrypt(C1, Key, Pad),
- R = crypto:rsa_private_decrypt(C2, Key, Pad),
- R = crypto:rsa_private_decrypt(C1, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad),
- R = crypto:rsa_private_decrypt(C2, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad).
-
-
-dh(doc) ->
- ["Test dh (Diffie-Hellman) functions."];
-dh(suite) -> [];
-dh(Config) when is_list(Config) ->
- Self = self(),
- GenP = fun() ->
- %% Gen Param may take arbitrary long time to finish
- %% That's not a bug in erlang crypto application.
- ?line DHPs = crypto:dh_generate_parameters(512,2),
- ?line ok = crypto:dh_check(DHPs),
- Self ! {param, DHPs}
- end,
- Pid = spawn(GenP),
- receive
- {param, DHPs} ->
- timer:sleep(100),
- io:format("DHP ~p~n", [DHPs]),
- DHPs_mpint = lists:map(fun(E) -> sized_binary(E) end, DHPs),
- ?line {Pub1,Priv1} = crypto:generate_key(dh, DHPs),
- io:format("Key1:~n~p~n~p~n~n", [Pub1,Priv1]),
- ?line {Pub2,Priv2} = crypto:dh_generate_key(DHPs_mpint),
- io:format("Key2:~n~p~n~p~n~n", [Pub2,Priv2]),
- ?line A = crypto:compute_key(dh, Pub1, unsized_binary(Priv2), DHPs),
- ?line A = crypto:dh_compute_key(sized_binary(Pub1), Priv2, DHPs_mpint),
- timer:sleep(100), %% Get another thread see if that triggers problem
- ?line B = crypto:compute_key(dh, unsized_binary(Pub2), Priv1, DHPs),
- ?line B = crypto:dh_compute_key(Pub2, sized_binary(Priv1), DHPs_mpint),
- io:format("A ~p~n",[A]),
- io:format("B ~p~n",[B]),
- ?line A = B
- after 50000 ->
- io:format("Killing Param generation which took to long ~p~n",[Pid]),
- exit(Pid, kill)
- end.
-
-
-ec(doc) ->
- ["Test ec (Ecliptic Curve) functions."];
-ec(suite) -> [];
-ec(Config) when is_list(Config) ->
- if_supported(ec, fun() -> ec_do() end).
-
-ec_do() ->
- %% test for a name curve
- {D2_priv, D2_pub} = crypto:generate_key(ecdh, sect113r2),
- PrivECDH = [D2_priv, sect113r2],
- PubECDH = [D2_pub, sect113r2],
- %%TODO: find a published test case for a EC key
-
- %% test for a full specified curve and public key,
- %% taken from csca-germany_013_self_signed_cer.pem
- PubKey = <<16#04, 16#4a, 16#94, 16#49, 16#81, 16#77, 16#9d, 16#df,
- 16#1d, 16#a5, 16#e7, 16#c5, 16#27, 16#e2, 16#7d, 16#24,
- 16#71, 16#a9, 16#28, 16#eb, 16#4d, 16#7b, 16#67, 16#75,
- 16#ae, 16#09, 16#0a, 16#51, 16#45, 16#19, 16#9b, 16#d4,
- 16#7e, 16#a0, 16#81, 16#e5, 16#5e, 16#d4, 16#a4, 16#3f,
- 16#60, 16#7c, 16#6a, 16#50, 16#ee, 16#36, 16#41, 16#8a,
- 16#87, 16#ff, 16#cd, 16#a6, 16#10, 16#39, 16#ca, 16#95,
- 16#76, 16#7d, 16#ae, 16#ca, 16#c3, 16#44, 16#3f, 16#e3, 16#2c>>,
- <<P:264/integer>> = <<16#00, 16#a9, 16#fb, 16#57, 16#db, 16#a1, 16#ee, 16#a9,
- 16#bc, 16#3e, 16#66, 16#0a, 16#90, 16#9d, 16#83, 16#8d,
- 16#72, 16#6e, 16#3b, 16#f6, 16#23, 16#d5, 16#26, 16#20,
- 16#28, 16#20, 16#13, 16#48, 16#1d, 16#1f, 16#6e, 16#53, 16#77>>,
- <<A:256/integer>> = <<16#7d, 16#5a, 16#09, 16#75, 16#fc, 16#2c, 16#30, 16#57,
- 16#ee, 16#f6, 16#75, 16#30, 16#41, 16#7a, 16#ff, 16#e7,
- 16#fb, 16#80, 16#55, 16#c1, 16#26, 16#dc, 16#5c, 16#6c,
- 16#e9, 16#4a, 16#4b, 16#44, 16#f3, 16#30, 16#b5, 16#d9>>,
- <<B:256/integer>> = <<16#26, 16#dc, 16#5c, 16#6c, 16#e9, 16#4a, 16#4b, 16#44,
- 16#f3, 16#30, 16#b5, 16#d9, 16#bb, 16#d7, 16#7c, 16#bf,
- 16#95, 16#84, 16#16, 16#29, 16#5c, 16#f7, 16#e1, 16#ce,
- 16#6b, 16#cc, 16#dc, 16#18, 16#ff, 16#8c, 16#07, 16#b6>>,
- BasePoint = <<16#04, 16#8b, 16#d2, 16#ae, 16#b9, 16#cb, 16#7e, 16#57,
- 16#cb, 16#2c, 16#4b, 16#48, 16#2f, 16#fc, 16#81, 16#b7,
- 16#af, 16#b9, 16#de, 16#27, 16#e1, 16#e3, 16#bd, 16#23,
- 16#c2, 16#3a, 16#44, 16#53, 16#bd, 16#9a, 16#ce, 16#32,
- 16#62, 16#54, 16#7e, 16#f8, 16#35, 16#c3, 16#da, 16#c4,
- 16#fd, 16#97, 16#f8, 16#46, 16#1a, 16#14, 16#61, 16#1d,
- 16#c9, 16#c2, 16#77, 16#45, 16#13, 16#2d, 16#ed, 16#8e,
- 16#54, 16#5c, 16#1d, 16#54, 16#c7, 16#2f, 16#04, 16#69, 16#97>>,
- <<Order:264/integer>> = <<16#00, 16#a9, 16#fb, 16#57, 16#db, 16#a1, 16#ee, 16#a9,
- 16#bc, 16#3e, 16#66, 16#0a, 16#90, 16#9d, 16#83, 16#8d,
- 16#71, 16#8c, 16#39, 16#7a, 16#a3, 16#b5, 16#61, 16#a6,
- 16#f7, 16#90, 16#1e, 16#0e, 16#82, 16#97, 16#48, 16#56, 16#a7>>,
- CoFactor = 1,
- Curve = {{prime_field,P},{A,B,none},BasePoint, Order,CoFactor},
-
- Msg = <<99,234,6,64,190,237,201,99,80,248,58,40,70,45,149,218,5,246,242,63>>,
- Sign = crypto:sign(ecdsa, sha, Msg, PrivECDH),
- ?line true = crypto:verify(ecdsa, sha, Msg, Sign, PubECDH),
- ?line false = crypto:verify(ecdsa, sha, Msg, <<10,20>>, PubECDH),
-
- ok.
-
-srp3(doc) ->
- ["SRP-3 test vectors generated by http://srp.stanford.edu/demo/demo.html"];
-srp3(suite) -> [];
-srp3(Config) when is_list(Config) ->
+rfc4231_hmac_sha224() ->
+ [hexstr2bin("896fb1128abbdf196832107cd49df33f"
+ "47b4b1169912ba4f53684b22"),
+ hexstr2bin("a30e01098bc6dbbf45690f3a7e9e6d0f"
+ "8bbea2a39e6148008fd05e44"),
+ hexstr2bin("7fb3cb3588c6c1f6ffa9694d7d6ad264"
+ "9365b0c1f65d69d1ec8333ea"),
+ hexstr2bin("6c11506874013cac6a2abc1bb382627c"
+ "ec6a90d86efc012de7afec5a"),
+ hexstr2bin("0e2aea68a90c8d37c988bcdb9fca6fa8"),
+ hexstr2bin("95e9a0db962095adaebe9b2d6f0dbce2"
+ "d499f112f2d2b7273fa6870e"),
+ hexstr2bin("3a854166ac5d9f023f54d517d0b39dbd"
+ "946770db9c2b95c9f6f565d1")].
+rfc4231_hmac_sha256() ->
+ [hexstr2bin("b0344c61d8db38535ca8afceaf0bf12b"
+ "881dc200c9833da726e9376c2e32cff7"),
+ hexstr2bin("5bdcc146bf60754e6a042426089575c7"
+ "5a003f089d2739839dec58b964ec3843"),
+ hexstr2bin("773ea91e36800e46854db8ebd09181a7"
+ "2959098b3ef8c122d9635514ced565fe"),
+ hexstr2bin("82558a389a443c0ea4cc819899f2083a"
+ "85f0faa3e578f8077a2e3ff46729665b"),
+ hexstr2bin("a3b6167473100ee06e0c796c2955552b"),
+ hexstr2bin("60e431591ee0b67f0d8a26aacbf5b77f"
+ "8e0bc6213728c5140546040f0ee37f54"),
+ hexstr2bin("9b09ffa71b942fcb27635fbcd5b0e944"
+ "bfdc63644f0713938a7f51535c3a35e2")].
+
+rfc4231_hmac_sha384() ->
+ [hexstr2bin("afd03944d84895626b0825f4ab46907f"
+ "15f9dadbe4101ec682aa034c7cebc59c"
+ "faea9ea9076ede7f4af152e8b2fa9cb6"),
+ hexstr2bin("af45d2e376484031617f78d2b58a6b1b"
+ "9c7ef464f5a01b47e42ec3736322445e"
+ "8e2240ca5e69e2c78b3239ecfab21649"),
+ hexstr2bin("88062608d3e6ad8a0aa2ace014c8a86f"
+ "0aa635d947ac9febe83ef4e55966144b"
+ "2a5ab39dc13814b94e3ab6e101a34f27"),
+ hexstr2bin("3e8a69b7783c25851933ab6290af6ca7"
+ "7a9981480850009cc5577c6e1f573b4e"
+ "6801dd23c4a7d679ccf8a386c674cffb"),
+ hexstr2bin("3abf34c3503b2a23a46efc619baef897"),
+ hexstr2bin("4ece084485813e9088d2c63a041bc5b4"
+ "4f9ef1012a2b588f3cd11f05033ac4c6"
+ "0c2ef6ab4030fe8296248df163f44952"),
+ hexstr2bin("6617178e941f020d351e2f254e8fd32c"
+ "602420feb0b8fb9adccebb82461e99c5"
+ "a678cc31e799176d3860e6110c46523e")].
+rfc4231_hmac_sha512() ->
+ [hexstr2bin("87aa7cdea5ef619d4ff0b4241a1d6cb0"
+ "2379f4e2ce4ec2787ad0b30545e17cde"
+ "daa833b7d6b8a702038b274eaea3f4e4"
+ "be9d914eeb61f1702e696c203a126854"),
+ hexstr2bin("164b7a7bfcf819e2e395fbe73b56e0a3"
+ "87bd64222e831fd610270cd7ea250554"
+ "9758bf75c05a994a6d034f65f8f0e6fd"
+ "caeab1a34d4a6b4b636e070a38bce737"),
+ hexstr2bin("fa73b0089d56a284efb0f0756c890be9"
+ "b1b5dbdd8ee81a3655f83e33b2279d39"
+ "bf3e848279a722c806b485a47e67c807"
+ "b946a337bee8942674278859e13292fb"),
+ hexstr2bin("b0ba465637458c6990e5a8c5f61d4af7"
+ "e576d97ff94b872de76f8050361ee3db"
+ "a91ca5c11aa25eb4d679275cc5788063"
+ "a5f19741120c4f2de2adebeb10a298dd"),
+ hexstr2bin("415fad6271580a531d4179bc891d87a6"),
+ hexstr2bin("80b24263c7c1a3ebb71493c1dd7be8b4"
+ "9b46d1f41b4aeec1121b013783f8f352"
+ "6b56d037e05f2598bd0fd2215d6a1e52"
+ "95e64f73f63f0aec8b915a985d786598"),
+ hexstr2bin("e37b6a775dc87dbaa4dfa9f96e5e3ffd"
+ "debd71f8867289865df5a32d20cdc944"
+ "b6022cac3c4982b10d5eeb55c3e4de15"
+ "134676fb6de0446065c97440fa8c6a58")].
+des_cbc() ->
+ [{des_cbc,
+ hexstr2bin("0123456789abcdef"),
+ hexstr2bin("1234567890abcdef"),
+ <<"Now is the time for all ">> }].
+
+des_cfb() ->
+ [{des_cfb,
+ hexstr2bin("0123456789abcdef"),
+ hexstr2bin("1234567890abcdef"),
+ <<"Now is the">>}].
+
+des3_cbc() ->
+ [{des3_cbc,
+ [hexstr2bin("0123456789abcdef"),
+ hexstr2bin("fedcba9876543210"),
+ hexstr2bin("0f2d4b6987a5c3e1")],
+ hexstr2bin("1234567890abcdef"),
+ <<"Now is the time for all ">>
+ }].
+
+des3_cbf() ->
+ [{des3_cbf,
+ [hexstr2bin("0123456789abcdef"),
+ hexstr2bin("fedcba9876543210"),
+ hexstr2bin("0f2d4b6987a5c3e1")],
+ hexstr2bin("1234567890abcdef"),
+ <<"Now is the time for all ">>
+ }].
+
+rc2_cbc() ->
+ [{rc2_cbc,
+ <<146,210,160,124,215,227,153,239,227,17,222,140,3,93,27,191>>,
+ <<72,91,135,182,25,42,35,210>>,
+ <<36,245,206,158,168,230,58,69,148,137,32,192,250,41,237,181,181,251, 192,2,175,135,177,171,57,30,111,117,159,149,15,28,88,158,28,81,28,115, 85,219,241,82,117,222,91,85,73,117,164,25,182,52,191,64,123,57,26,19, 211,27,253,31,194,219,231,104,247,240,172,130,119,21,225,154,101,247, 32,216,42,216,133,169,78,22,97,27,227,26,196,224,172,168,17,9,148,55, 203,91,252,40,61,226,236,221,215,160,78,63,13,181,68,57,196,241,185, 207, 116,129,152,237,60,139,247,153,27,146,161,246,222,98,185,222,152, 187,135, 236,86,34,7,110,91,230,173,34,160,242,202,222,121,127,181,140, 101,203,195, 190,88,250,86,147,127,87,72,126,171,16,71,47,110,248,88, 14,29,143,161,152, 129,236,148,22,152,186,208,119,70,8,174,193,203,100, 193,203,200,117,102,242, 134,142,96,125,135,200,217,190,76,117,50,70, 209,186,101,241,200,91,40,193,54, 90,195,38,47,59,197,38,234,86,223,16, 51,253,204,129,20,171,66,21,241,26,135,216, 196,114,110,91,15,53,40, 164,201,136,113,95,247,51,181,208,241,68,168,98,151,36, 155,72,24,57, 42,191,14,125,204,10,167,214,233,138,115,125,234,121,134,227,26,247, 77,200,117,110,117,111,168,156,206,67,159,149,189,173,150,193,91,199, 216,153,22, 189,137,185,89,160,13,131,132,58,109,28,110,246,252,251,14, 232,91,38,52,29,101,188,69,123,50,0,130,178,93,73,239,118,7,77,35,59, 253,10,159,45,86,142,37,78,232,48>>
+ }].
+aes_cbc128() ->
+ [{aes_cbc128,
+ hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("000102030405060708090a0b0c0d0e0f"),
+ hexstr2bin("6bc1bee22e409f96e93d7e117393172a")},
+ {aes_cbc128,
+ hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("7649ABAC8119B246CEE98E9B12E9197D"),
+ hexstr2bin("ae2d8a571e03ac9c9eb76fac45af8e51")},
+ {aes_cbc128,
+ hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("5086CB9B507219EE95DB113A917678B2"),
+ hexstr2bin("30c81c46a35ce411e5fbc1191a0a52ef")},
+ {aes_cbc128,
+ hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("73BED6B8E3C1743B7116E69E22229516"),
+ hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")}
+ ].
+
+aes_cbc256() ->
+ [{aes_cbc256,
+ hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("000102030405060708090A0B0C0D0E0F"),
+ hexstr2bin("6bc1bee22e409f96e93d7e117393172a")},
+ {aes_cbc256,
+ hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("F58C4C04D6E5F1BA779EABFB5F7BFBD6"),
+ hexstr2bin("ae2d8a571e03ac9c9eb76fac45af8e51")},
+ {aes_cbc256,
+ hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("9CFC4E967EDB808D679F777BC6702C7D"),
+ hexstr2bin("30c81c46a35ce411e5fbc1191a0a52ef")},
+ {aes_cbc256,
+ hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("39F23369A9D9BACFA530E26304231461"),
+ hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")}
+ ].
+
+aes_cfb128() ->
+ [{aes_cfb128,
+ hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("000102030405060708090a0b0c0d0e0f"),
+ hexstr2bin("6bc1bee22e409f96e93d7e117393172a")},
+ {aes_cfb128,
+ hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("3B3FD92EB72DAD20333449F8E83CFB4A"),
+ hexstr2bin("ae2d8a571e03ac9c9eb76fac45af8e51")},
+ {aes_cfb128,
+ hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("C8A64537A0B3A93FCDE3CDAD9F1CE58B"),
+ hexstr2bin("30c81c46a35ce411e5fbc1191a0a52ef")},
+ {aes_cfb128,
+ hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("26751F67A3CBB140B1808CF187A4F4DF"),
+ hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")}
+ ].
+
+blowfish_cbc() ->
+ [{blowfish_cbc,
+ hexstr2bin("0123456789ABCDEFF0E1D2C3B4A59687"),
+ hexstr2bin("FEDCBA9876543210"),
+ hexstr2bin("37363534333231204E6F77206973207468652074696D6520666F722000000000")
+ }].
+
+blowfish_ecb() ->
+ [
+ {blowfish_ecb,
+ hexstr2bin("0000000000000000"),
+ hexstr2bin("0000000000000000")},
+ {blowfish_ecb,
+ hexstr2bin("FFFFFFFFFFFFFFFF"),
+ hexstr2bin("FFFFFFFFFFFFFFFF")},
+ {blowfish_ecb,
+ hexstr2bin("3000000000000000"),
+ hexstr2bin("1000000000000001")},
+ {blowfish_ecb,
+ hexstr2bin("1111111111111111"),
+ hexstr2bin("1111111111111111")},
+ {blowfish_ecb,
+ hexstr2bin("0123456789ABCDEF"),
+ hexstr2bin("1111111111111111")},
+ {blowfish_ecb,
+ hexstr2bin("0000000000000000"),
+ hexstr2bin("0000000000000000")},
+ {blowfish_ecb,
+ hexstr2bin("FEDCBA9876543210"),
+ hexstr2bin("0123456789ABCDEF")},
+ {blowfish_ecb,
+ hexstr2bin("7CA110454A1A6E57"),
+ hexstr2bin("01A1D6D039776742")},
+ {blowfish_ecb,
+ hexstr2bin("0131D9619DC1376E"),
+ hexstr2bin("5CD54CA83DEF57DA")},
+ {blowfish_ecb,
+ hexstr2bin("07A1133E4A0B2686"),
+ hexstr2bin("0248D43806F67172")},
+ {blowfish_ecb,
+ hexstr2bin("3849674C2602319E"),
+ hexstr2bin("51454B582DDF440A")},
+ {blowfish_ecb,
+ hexstr2bin("04B915BA43FEB5B6"),
+ hexstr2bin("42FD443059577FA2")},
+ {blowfish_ecb,
+ hexstr2bin("0113B970FD34F2CE"),
+ hexstr2bin("059B5E0851CF143A")},
+ {blowfish_ecb,
+ hexstr2bin("0170F175468FB5E6"),
+ hexstr2bin("0756D8E0774761D2")},
+ {blowfish_ecb,
+ hexstr2bin("43297FAD38E373FE"),
+ hexstr2bin("762514B829BF486A")},
+ {blowfish_ecb,
+ hexstr2bin("07A7137045DA2A16"),
+ hexstr2bin("3BDD119049372802")},
+ {blowfish_ecb,
+ hexstr2bin("04689104C2FD3B2F"),
+ hexstr2bin("26955F6835AF609A")},
+ {blowfish_ecb,
+ hexstr2bin("37D06BB516CB7546"),
+ hexstr2bin("164D5E404F275232")},
+ {blowfish_ecb,
+ hexstr2bin("1F08260D1AC2465E"),
+ hexstr2bin("6B056E18759F5CCA")},
+ {blowfish_ecb,
+ hexstr2bin("584023641ABA6176"),
+ hexstr2bin("004BD6EF09176062")},
+ {blowfish_ecb,
+ hexstr2bin("025816164629B007"),
+ hexstr2bin("480D39006EE762F2")},
+ {blowfish_ecb,
+ hexstr2bin("49793EBC79B3258F"),
+ hexstr2bin("437540C8698F3CFA")},
+ {blowfish_ecb,
+ hexstr2bin("018310DC409B26D6"),
+ hexstr2bin("1D9D5C5018F728C2")},
+ {blowfish_ecb,
+ hexstr2bin("1C587F1C13924FEF"),
+ hexstr2bin("305532286D6F295A")},
+ {blowfish_ecb,
+ hexstr2bin("0101010101010101"),
+ hexstr2bin("0123456789ABCDEF")},
+ {blowfish_ecb,
+ hexstr2bin("1F1F1F1F0E0E0E0E"),
+ hexstr2bin("0123456789ABCDEF")},
+ {blowfish_ecb,
+ hexstr2bin("E0FEE0FEF1FEF1FE"),
+ hexstr2bin("0123456789ABCDEF")},
+ {blowfish_ecb,
+ hexstr2bin("0000000000000000"),
+ hexstr2bin("FFFFFFFFFFFFFFFF")},
+ {blowfish_ecb,
+ hexstr2bin("FFFFFFFFFFFFFFFF"),
+ hexstr2bin("0000000000000000")},
+ {blowfish_ecb,
+ hexstr2bin("0123456789ABCDEF"),
+ hexstr2bin("0000000000000000")},
+ {blowfish_ecb,
+ hexstr2bin("FEDCBA9876543210"),
+ hexstr2bin("FFFFFFFFFFFFFFFF")}
+ ].
+
+blowfish_cfb64() ->
+ [{blowfish_cfb64,
+ hexstr2bin("0123456789ABCDEFF0E1D2C3B4A59687"),
+ hexstr2bin("FEDCBA9876543210"),
+ hexstr2bin("37363534333231204E6F77206973207468652074696D6520666F722000")
+ }].
+blowfish_ofb64() ->
+ [{blowfish_ofb64,
+ hexstr2bin("0123456789ABCDEFF0E1D2C3B4A59687"),
+ hexstr2bin("FEDCBA9876543210"),
+ hexstr2bin("37363534333231204E6F77206973207468652074696D6520666F722000")
+ }].
+
+rc4() ->
+ [{rc4, <<"apaapa">>, <<"Yo baby yo">>},
+ {rc4, <<"apaapa">>, list_to_binary(lists:seq(0, 255))}
+ ].
+
+aes_ctr() ->
+ [ %% F.5.3 CTR-AES192.Encrypt
+ {aes_ctr, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
+ hexstr2bin("6bc1bee22e409f96e93d7e117393172a")},
+ {aes_ctr, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff00"),
+ hexstr2bin("ae2d8a571e03ac9c9eb76fac45af8e51")},
+ {aes_ctr, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff01"),
+ hexstr2bin("30c81c46a35ce411e5fbc1191a0a52ef") },
+ {aes_ctr, hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff02"),
+ hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")},
+
+ %% F.5.3 CTR-AES192.Encrypt
+ {aes_ctr, hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
+ hexstr2bin("6bc1bee22e409f96e93d7e117393172a")},
+ {aes_ctr, hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff00"),
+ hexstr2bin("ae2d8a571e03ac9c9eb76fac45af8e51")},
+ {aes_ctr, hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff01"),
+ hexstr2bin("30c81c46a35ce411e5fbc1191a0a52ef")},
+ {aes_ctr, hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff02"),
+ hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")},
+
+ %% F.5.5 CTR-AES256.Encrypt
+ {aes_ctr, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
+ hexstr2bin("6bc1bee22e409f96e93d7e117393172a")},
+ {aes_ctr, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff00"),
+ hexstr2bin("ae2d8a571e03ac9c9eb76fac45af8e51")},
+ {aes_ctr, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff01"),
+ hexstr2bin("30c81c46a35ce411e5fbc1191a0a52ef")},
+ {aes_ctr, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff02"),
+ hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")}
+ ].
+
+rsa_plain() ->
+ <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
+ "09812312908312378623487263487623412039812 huagasd">>.
+rsa_public() ->
+ [65537, 7919488123861148172698919999061127847747888703039837999377650217570191053151807772962118671509138346758471459464133273114654252861270845708312601272799123].
+rsa_private() ->
+ rsa_public() ++ [7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945].
+
+dss_plain() ->
+ rsa_plain().
+dss_public() ->
+ 25854665488880835237281628794585130313500176551981812527054397586638455298000483144002221850980183404910190346416063318160497344811383498859129095184158800144312512447497510551471331451396405348497845813002058423110442376886564659959543650802132345311573634832461635601376738282831340827591903548964194832978.
+dss_private() ->
+ 441502407453038284293378221372000880210588566361.
+dss_params() ->
+ [109799869232806890760655301608454668257695818999841877165019612946154359052535682480084145133201304812979481136659521529774182959764860329095546511521488413513097576425638476458000255392402120367876345280670101492199681798674053929238558140260669578407351853803102625390950534052428162468100618240968893110797,
+ 1349199015905534965792122312016505075413456283393,
+ 18320614775012672475365915366944922415598782131828709277168615511695849821411624805195787607930033958243224786899641459701930253094446221381818858674389863050420226114787005820357372837321561754462061849169568607689530279303056075793886577588606958623645901271866346406773590024901668622321064384483571751669].
+
+ec_key_named() ->
+ {D2_pub, D2_priv} = crypto:generate_key(ecdh, sect113r2),
+ {[D2_priv, sect113r2], [D2_pub, sect113r2]}.
+
+ec_msg() ->
+ <<99,234,6,64,190,237,201,99,80,248,58,40,70,45,149,218,5,246,242,63>>.
+
+srp3() ->
Username = <<"alice">>,
Password = <<"password123">>,
Salt = hexstr2bin("2857827A19266A1F2BC6"),
@@ -1978,21 +1253,12 @@ srp3(Config) when is_list(Config) ->
"46ABF4FF39498DAFDD2C82924F7D7BD76CDFCE688C77D93F18A65409"
"9176A9192615DC0277AE7C12F1F6A7F6563FCA11675D809AF578BDE5"
"2B51E05D440B63099A017A0B45044801"),
- UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
+ UserPassHash = crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, Password])]),
Verifier = crypto:mod_pow(Generator, UserPassHash, Prime),
- ClientPublic = crypto:mod_pow(Generator, ClientPrivate, Prime),
+ ClientPublic = crypto:mod_pow(Generator, ClientPrivate, Prime),
+ srp(ClientPrivate, Generator, Prime, Version, Verifier, ServerPublic, ServerPrivate, UserPassHash, Scrambler, SessionKey).
- {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate),
- {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate),
- SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate},
- {user, [UserPassHash, Prime, Generator, Version, Scrambler]}),
- SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate},
- {host, [Verifier, Prime, Version, Scrambler]}).
-
-srp6(doc) ->
- ["SRP-6 test vectors generated by http://srp.stanford.edu/demo/demo.html"];
-srp6(suite) -> [];
-srp6(Config) when is_list(Config) ->
+srp6() ->
Username = <<"alice">>,
Password = <<"password123">>,
Salt = hexstr2bin("2857827A19266A1F2BC6"),
@@ -2029,21 +1295,12 @@ srp6(Config) when is_list(Config) ->
"7216F9CD8A4AC39F0429857D8D1023066614BDFCBCB89F59A0FEB81C"
"72E992AAD89095A84B6A5FADA152369AB1E350A03693BEF044DF3EDF"
"0C34741F4696C30E9F675D09F58ACBEB"),
- UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
+ UserPassHash = crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, Password])]),
Verifier = crypto:mod_pow(Generator, UserPassHash, Prime),
ClientPublic = crypto:mod_pow(Generator, ClientPrivate, Prime),
+ srp(ClientPrivate, Generator, Prime, Version, Verifier, ServerPublic, ServerPrivate, UserPassHash, Scrambler, SessionKey).
- {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate),
- {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate),
- SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate},
- {user, [UserPassHash, Prime, Generator, Version, Scrambler]}),
- SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate},
- {host, [Verifier, Prime, Version, Scrambler]}).
-
-srp6a(doc) ->
- ["SRP-6a test vectors from RFC5054."];
-srp6a(suite) -> [];
-srp6a(Config) when is_list(Config) ->
+srp6a() ->
Username = <<"alice">>,
Password = <<"password123">>,
Salt = hexstr2bin("BEB25379D1A8581EB5A727673A2441EE"),
@@ -2065,278 +1322,36 @@ srp6a(Config) when is_list(Config) ->
ServerPrivate = hexstr2bin("E487CB59D31AC550471E81F00F6928E01DDA08E974A004F49E61F5D1"
"05284D20"),
ClientPublic = hexstr2bin("61D5E490F6F1B79547B0704C436F523DD0E560F0C64115BB72557EC4"
- "4352E8903211C04692272D8B2D1A5358A2CF1B6E0BFCF99F921530EC"
- "8E39356179EAE45E42BA92AEACED825171E1E8B9AF6D9C03E1327F44"
- "BE087EF06530E69F66615261EEF54073CA11CF5858F0EDFDFE15EFEA"
- "B349EF5D76988A3672FAC47B0769447B"),
+ "4352E8903211C04692272D8B2D1A5358A2CF1B6E0BFCF99F921530EC"
+ "8E39356179EAE45E42BA92AEACED825171E1E8B9AF6D9C03E1327F44"
+ "BE087EF06530E69F66615261EEF54073CA11CF5858F0EDFDFE15EFEA"
+ "B349EF5D76988A3672FAC47B0769447B"),
ServerPublic = hexstr2bin("BD0C61512C692C0CB6D041FA01BB152D4916A1E77AF46AE105393011"
- "BAF38964DC46A0670DD125B95A981652236F99D9B681CBF87837EC99"
- "6C6DA04453728610D0C6DDB58B318885D7D82C7F8DEB75CE7BD4FBAA"
- "37089E6F9C6059F388838E7A00030B331EB76840910440B1B27AAEAE"
- "EB4012B7D7665238A8E3FB004B117B58"),
-
+ "BAF38964DC46A0670DD125B95A981652236F99D9B681CBF87837EC99"
+ "6C6DA04453728610D0C6DDB58B318885D7D82C7F8DEB75CE7BD4FBAA"
+ "37089E6F9C6059F388838E7A00030B331EB76840910440B1B27AAEAE"
+ "EB4012B7D7665238A8E3FB004B117B58"),
+
SessionKey = hexstr2bin("B0DC82BABCF30674AE450C0287745E7990A3381F63B387AAF271A10D"
"233861E359B48220F7C4693C9AE12B0A6F67809F0876E2D013800D6C"
"41BB59B6D5979B5C00A172B4A2A5903A0BDCAF8A709585EB2AFAFA8F"
"3499B200210DCC1F10EB33943CD67FC88A2F39A4BE5BEC4EC0A3212D"
"C346D7E474B29EDE8A469FFECA686E5A"),
- UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
+ UserPassHash = crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, Password])]),
Verifier = crypto:mod_pow(Generator, UserPassHash, Prime),
-
- {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate),
- {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate),
-
- SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate},
- {user, [UserPassHash, Prime, Generator, Version, Scrambler]}),
- SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate},
- {host, [Verifier, Prime, Version, Scrambler]}).
-
-%%
-%%
-exor_test(doc) ->
- ["Test the exor function."];
-exor_test(suite) ->
- [];
-exor_test(Config) when is_list(Config) ->
- B = <<1, 2, 3, 4, 5, 6, 7, 8, 9, 10>>,
- Z1 = zero_bin(B),
- Z1 = crypto:exor(B, B),
- B1 = crypto:rand_bytes(100),
- B2 = crypto:rand_bytes(100),
- Z2 = zero_bin(B1),
- Z2 = crypto:exor(B1, B1),
- Z2 = crypto:exor(B2, B2),
- R = xor_bytes(B1, B2),
- R = crypto:exor(B1, B2),
- ok.
-
-%%
-%%
-rc4_test(doc) ->
- ["Test rc4 encryption ."];
-rc4_test(suite) ->
- [];
-rc4_test(Config) when is_list(Config) ->
- CT1 = <<"Yo baby yo">>,
- R1 = <<118,122,68,110,157,166,141,212,139,39>>,
- K = "apaapa",
- R1 = crypto:rc4_encrypt(K, CT1),
- CT1 = crypto:rc4_encrypt(K, R1),
- CT2 = lists:seq(0, 255),
- R2 = crypto:rc4_encrypt(K, CT2),
- CT2 = binary_to_list(crypto:rc4_encrypt(K, R2)),
- ok.
-
-rc4_stream_test(doc) ->
- ["Test rc4 stream encryption ."];
-rc4_stream_test(suite) ->
- [];
-rc4_stream_test(Config) when is_list(Config) ->
- CT1 = <<"Yo ">>,
- CT2 = <<"baby yo">>,
- K = "apaapa",
- State0 = crypto:rc4_set_key(K),
- {State1, R1} = crypto:rc4_encrypt_with_state(State0, CT1),
- {_State2, R2} = crypto:rc4_encrypt_with_state(State1, CT2),
- R = list_to_binary([R1, R2]),
- <<118,122,68,110,157,166,141,212,139,39>> = R,
- ok.
-
-blowfish_cfb64(doc) -> ["Test Blowfish encrypt/decrypt."];
-blowfish_cfb64(suite) -> [];
-blowfish_cfb64(Config) when is_list(Config) ->
- Key = <<1,35,69,103,137,171,205,239,240,225,210,195,180,165,150,135>>,
-
- IVec = <<254,220,186,152,118,84,50,16>>,
- Plain = <<"7654321 Now is the time for ">>,
- Enc = <<231,50,20,162,130,33,57,202,242,110,207,109,46,185,231,110,61,163,222,4,209,81,114,0,81,157,87,166>>,
-
- Enc = crypto:blowfish_cfb64_encrypt(Key, IVec, Plain),
- Plain = crypto:blowfish_cfb64_decrypt(Key, IVec, Enc),
-
- Key2 = <<"A2B4C">>,
- IVec2 = <<"12345678">>,
- Plain2 = <<"badger at my table....!">>,
- Enc2 = <<173,76,128,155,70,81,79,228,4,162,188,92,119,53,144,89,93,236,28,164,176,16,138>>,
-
- Enc2 = crypto:blowfish_cfb64_encrypt(Key2, IVec2, Plain2),
- Plain2 = crypto:blowfish_cfb64_decrypt(Key2, IVec2, Enc2).
-
-
-smp(doc) -> "Check concurrent access to crypto driver";
-smp(suite) -> [];
-smp(Config) ->
- case erlang:system_info(smp_support) of
- true ->
- NumOfProcs = erlang:system_info(schedulers),
- io:format("smp starting ~p workers\n",[NumOfProcs]),
- Seeds = [random:uniform(9999) || _ <- lists:seq(1,NumOfProcs)],
- Parent = self(),
- Pids = [spawn_link(fun()-> worker(Seed,Config,Parent) end)
- || Seed <- Seeds],
- wait_pids(Pids);
-
- false ->
- {skipped,"No smp support"}
- end.
-
-worker(Seed, Config, Parent) ->
- io:format("smp worker ~p, seed=~p~n",[self(),Seed]),
- random:seed(Seed,Seed,Seed),
- worker_loop(100, Config),
- %%io:format("worker ~p done\n",[self()]),
- Parent ! self().
-
-worker_loop(0, _) ->
- ok;
-worker_loop(N, Config) ->
- Funcs = { md5, md5_update, md5_mac, md5_mac_io, sha, sha_update, des_cbc,
- aes_cfb, aes_cbc, des_cbc_iter, rand_uniform_test, strong_rand_test,
- rsa_verify_test, exor_test, rc4_test, rc4_stream_test, mod_exp_test,
- hmac_update_md5, hmac_update_sha, hmac_update_sha256, hmac_update_sha512,
- hmac_rfc2202, hmac_rfc4231_sha224, hmac_rfc4231_sha256, hmac_rfc4231_sha384,
- hmac_rfc4231_sha512, aes_ctr_stream },
-
- F = element(random:uniform(size(Funcs)),Funcs),
- %%io:format("worker ~p calling ~p\n",[self(),F]),
- ?MODULE:F(Config),
- worker_loop(N-1,Config).
-
-wait_pids([]) ->
- ok;
-wait_pids(Pids) ->
- receive
- Pid ->
- ?line true = lists:member(Pid,Pids),
- Others = lists:delete(Pid,Pids),
- io:format("wait_pid got ~p, still waiting for ~p\n",[Pid,Others]),
- wait_pids(Others)
- end.
-
-%%
-%% Help functions
-%%
-
-% match
-m(X, X) ->
- ?line true.
-t(true) ->
- true.
-
-% hexstr2bin
-hexstr2bin(S) ->
- list_to_binary(hexstr2list(S)).
-
-hexstr2list([X,Y|T]) ->
- [mkint(X)*16 + mkint(Y) | hexstr2list(T)];
-hexstr2list([]) ->
- [].
-
-mkint(C) when $0 =< C, C =< $9 ->
- C - $0;
-mkint(C) when $A =< C, C =< $F ->
- C - $A + 10;
-mkint(C) when $a =< C, C =< $f ->
- C - $a + 10.
-
-%% mod_exp in erlang (copied from jungerl's ssh_math.erl)
-ipow(A, B, M) when M > 0, B >= 0 ->
- if A == 1 ->
- 1;
- true ->
- ipow(A, B, M, 1)
- end.
-
-ipow(A, 1, M, Prod) ->
- (A*Prod) rem M;
-ipow(_A, 0, _M, Prod) ->
- Prod;
-ipow(A, B, M, Prod) ->
- B1 = B bsr 1,
- A1 = (A*A) rem M,
- if B - B1 == B1 ->
- ipow(A1, B1, M, Prod);
- true ->
- ipow(A1, B1, M, (A*Prod) rem M)
- end.
-
-%%
-%% Invert an element X mod P
-%% Calculated as {1, {A,B}} = egcd(X,P),
-%% 1 == P*A + X*B == X*B (mod P) i.e B is the inverse element
-%%
-%% X > 0, P > 0, X < P (P should be prime)
-%%
-%% invert(X,P) when X > 0, P > 0, X < P ->
-%% I = inv(X,P,1,0),
-%% if
-%% I < 0 -> P + I;
-%% true -> I
-%% end.
-
-%% inv(0,_,_,Q) -> Q;
-%% inv(X,P,R1,Q1) ->
-%% D = P div X,
-%% inv(P rem X, X, Q1 - D*R1, R1).
-
-sized_binary(Binary) when is_binary(Binary) ->
- <<(size(Binary)):32/integer, Binary/binary>>;
-sized_binary(List) ->
- sized_binary(list_to_binary(List)).
-
-unsized_binary(<<Sz:32/integer, Binary:Sz/binary>>) ->
- Binary.
-
-xor_bytes(Bin1, Bin2) when is_binary(Bin1), is_binary(Bin2) ->
- L1 = binary_to_list(Bin1),
- L2 = binary_to_list(Bin2),
- list_to_binary(xor_bytes(L1, L2));
-xor_bytes(L1, L2) ->
- xor_bytes(L1, L2, []).
-
-xor_bytes([], [], Acc) ->
- lists:reverse(Acc);
-xor_bytes([N1 | Tl1], [N2 | Tl2], Acc) ->
- xor_bytes(Tl1, Tl2, [N1 bxor N2 | Acc]).
-
-zero_bin(N) when is_integer(N) ->
- N8 = N * 8,
- <<0:N8/integer>>;
-zero_bin(B) when is_binary(B) ->
- zero_bin(size(B)).
-
-my_dss_verify(Data,[Sign|Tail],Key) ->
- Res = my_dss_verify(Data,sized_binary(Sign),Key),
- case Tail of
- [] -> Res;
- _ -> ?line Res = my_dss_verify(Data,Tail,Key)
- end;
-my_dss_verify(Data,Sign,Key) ->
- ?line Res = crypto:dss_verify(Data, Sign, Key),
- ?line Res = crypto:dss_verify(sha, Data, Sign, Key),
- ?line <<_:32,Raw/binary>> = Data,
- ?line Res = crypto:dss_verify(none, crypto:sha(Raw), Sign, Key),
- Res.
-
-my_dss_sign(Data,Key) ->
- ?line S1 = crypto:dss_sign(Data, Key),
- ?line S2 = crypto:dss_sign(sha, Data, Key),
- ?line <<_:32,Raw/binary>> = Data,
- ?line S3 = crypto:dss_sign(none, crypto:sha(Raw), Key),
- [S1,S2,S3].
-
-openssl_version() ->
- case crypto:info_lib() of
- [{<<"OpenSSL">>,LibVer,_}] when is_integer(LibVer) ->
- LibVer;
- _ ->
- undefined
- end.
-
-if_supported(Algorithm, Fun) ->
- case proplists:get_bool(Algorithm, crypto:algorithms()) of
- true ->
- Fun();
- _ ->
- {skipped, io:format("~s not spupported", [Algorithm])}
- end.
+ ClientPublic = crypto:mod_pow(Generator, ClientPrivate, Prime),
+ srp(ClientPrivate, Generator, Prime, Version, Verifier, ServerPublic, ServerPrivate, UserPassHash, Scrambler, SessionKey).
+
+srp(ClientPrivate, Generator, Prime, Version, Verifier, ServerPublic, ServerPrivate, UserPassHash, Scrambler, SessionKey)->
+ {srp, ClientPrivate,
+ {user, [Generator, Prime, Version]}, {user, [UserPassHash, Prime, Generator, Version, Scrambler]},
+ ServerPublic, ServerPrivate, {host, [Verifier, Generator, Prime, Version]},
+ {host, [Verifier, Prime, Version, Scrambler]},
+ SessionKey}.
+ecdh() ->
+ {ecdh, 10053111454769593468622878414300213417816614162107065345116848162553478019161427871683337786549966,
+ 1373339791687564785573162818422814591820885704654,
+ secp160r1, 990333295438215762119481641129490894973766052278}.
+
+dh() ->
+ {dh, 0087761979513264537414556992123116644042638206717762626089877284926656954974893442000747478454809111207351620687968672207938731607963470779396984752680274820156266685080223616226905101126463253150237669547023934604953898814222890239130021414026118792251620881355456432549881723310342870016961804255746630219, 2}.
diff --git a/lib/crypto/test/old_crypto_SUITE.erl b/lib/crypto/test/old_crypto_SUITE.erl
new file mode 100644
index 0000000000..040edbf092
--- /dev/null
+++ b/lib/crypto/test/old_crypto_SUITE.erl
@@ -0,0 +1,2342 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(old_crypto_SUITE).
+
+-include_lib("test_server/include/test_server.hrl").
+
+-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2,
+ init_per_testcase/2,
+ end_per_testcase/2,
+ info/1,
+ link_test/1,
+ md5/1,
+ md5_update/1,
+ md4/1,
+ md4_update/1,
+ sha/1,
+ sha_update/1,
+ hmac_update_sha/1,
+ hmac_update_sha_n/1,
+ hmac_update_sha256/1,
+ hmac_update_sha512/1,
+ hmac_update_md5/1,
+ hmac_update_md5_io/1,
+ hmac_update_md5_n/1,
+ hmac_rfc2202/1,
+ hmac_rfc4231_sha224/1,
+ hmac_rfc4231_sha256/1,
+ hmac_rfc4231_sha384/1,
+ hmac_rfc4231_sha512/1,
+ ripemd160/1,
+ ripemd160_update/1,
+ sha256/1,
+ sha256_update/1,
+ sha512/1,
+ sha512_update/1,
+ md5_mac/1,
+ md5_mac_io/1,
+ des_cbc/1,
+ des_cbc_iter/1,
+ des_cfb/1,
+ des_cfb_iter/1,
+ des_ecb/1,
+ des3_cbc/1,
+ des3_cfb/1,
+ rc2_cbc/1,
+ aes_cfb/1,
+ aes_cbc/1,
+ aes_cbc_iter/1,
+ aes_ctr/1,
+ aes_ctr_stream/1,
+ mod_exp_test/1,
+ rand_uniform_test/1,
+ strong_rand_test/1,
+ rsa_verify_test/1,
+ dsa_verify_test/1,
+ rsa_sign_test/1,
+ rsa_sign_hash_test/1,
+ dsa_sign_test/1,
+ dsa_sign_hash_test/1,
+ rsa_encrypt_decrypt/1,
+ dh/1,
+ srp3/1, srp6/1, srp6a/1,
+ ec/1,
+ exor_test/1,
+ rc4_test/1,
+ rc4_stream_test/1,
+ blowfish_cfb64/1,
+ smp/1]).
+
+-export([hexstr2bin/1]).
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [link_test, {group, info}].
+
+groups() ->
+ [{info, [sequence],[info, {group, rest}]},
+ {rest, [],
+ [md5, md5_update, md4, md4_update, md5_mac,
+ md5_mac_io, ripemd160, ripemd160_update, sha, sha_update,
+ sha256, sha256_update, sha512, sha512_update,
+ hmac_update_sha, hmac_update_sha_n, hmac_update_sha256, hmac_update_sha512,
+ hmac_update_md5_n, hmac_update_md5_io, hmac_update_md5,
+ hmac_rfc2202, hmac_rfc4231_sha224, hmac_rfc4231_sha256,
+ hmac_rfc4231_sha384, hmac_rfc4231_sha512,
+ des_cbc, aes_cfb, aes_cbc,
+ des_cfb, des_cfb_iter, des3_cbc, des3_cfb, rc2_cbc,
+ aes_cbc_iter, aes_ctr, aes_ctr_stream, des_cbc_iter, des_ecb,
+ rand_uniform_test, strong_rand_test,
+ rsa_verify_test, dsa_verify_test, rsa_sign_test,
+ rsa_sign_hash_test, dsa_sign_test, dsa_sign_hash_test,
+ rsa_encrypt_decrypt, dh, srp3, srp6, srp6a, ec, exor_test,
+ rc4_test, rc4_stream_test, mod_exp_test, blowfish_cfb64,
+ smp]}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+init_per_testcase(info, Config) ->
+ Config;
+init_per_testcase(_Name,Config) ->
+ io:format("init_per_testcase\n"),
+ ?line crypto:start(),
+ Config.
+
+end_per_testcase(info, Config) ->
+ Config;
+end_per_testcase(_Name,Config) ->
+ io:format("end_per_testcase\n"),
+ ?line crypto:stop(),
+ Config.
+
+%%
+%%
+link_test(doc) ->
+ ["Test that the library is statically linked to libcrypto.a."];
+link_test(suite) ->
+ [];
+link_test(Config) when is_list(Config) ->
+ ?line case os:type() of
+ {unix,darwin} -> {skipped,"Darwin cannot link statically"};
+ {unix,_} -> link_test_1();
+ _ -> {skip,"Only runs on Unix"}
+ end.
+
+link_test_1() ->
+ ?line CryptoPriv = code:priv_dir(crypto),
+ ?line Wc = filename:join([CryptoPriv,"lib","crypto.*"]),
+ ?line case filelib:wildcard(Wc) of
+ [] -> {skip,"Didn't find the crypto driver"};
+ [Drv] -> link_test_2(Drv)
+ end.
+
+link_test_2(Drv) ->
+ case ldd_program() of
+ none ->
+ {skip,"No ldd-like program found"};
+ Ldd ->
+ Cmd = Ldd ++ " " ++ Drv,
+ Libs = os:cmd(Cmd),
+ io:format("~p\n", [Libs]),
+ case string:str(Libs, "libcrypto") of
+ 0 ->
+ case ?t:is_commercial() of
+ true ->
+ ?t:fail({libcrypto,statically_linked});
+ false ->
+ {comment,"Statically linked (OK for open-source platform)"}
+ end;
+ _ ->
+ ok
+ end
+ end.
+
+ldd_program() ->
+ case os:find_executable("ldd") of
+ false ->
+ case os:type() of
+ {unix,darwin} ->
+ case os:find_executable("otool") of
+ false -> none;
+ Otool -> Otool ++ " -L"
+ end
+ end;
+ Ldd when is_list(Ldd) -> Ldd
+ end.
+
+
+
+info(doc) ->
+ ["Call the info function."];
+info(suite) ->
+ [];
+info(Config) when is_list(Config) ->
+ case {code:lib_dir(crypto),?t:is_commercial()} of
+ {{error,bad_name},false} ->
+ {skip,"Missing crypto application"};
+ {_,_} ->
+ ?line crypto:start(),
+ ?line Info = crypto:info(),
+ ?line Exports = lists:usort([F || {F,_} <- crypto:module_info(exports)]),
+ ?line [] = Info -- Exports,
+ ?line NotInInfo = Exports -- Info,
+ io:format("NotInInfo = ~p\n", [NotInInfo]),
+ %% BlackList = lists:sort([des_ede3_cbc_decrypt, des_ede3_cbc_encrypt,
+ %% dh_check, dh_generate_parameters,
+ %% module_info, start, stop, version]),
+ %% ?line BlackList = NotInInfo,
+
+ ?line InfoLib = crypto:info_lib(),
+ ?line [_|_] = InfoLib,
+ F = fun([{Name,VerN,VerS}|T],Me) ->
+ ?line true = is_binary(Name),
+ ?line true = is_integer(VerN),
+ ?line true = is_binary(VerS),
+ Me(T,Me);
+ ([],_) ->
+ ok
+ end,
+ ?line F(InfoLib,F),
+ ?line crypto:stop()
+ end.
+
+%%
+%%
+md5(doc) ->
+ ["Generate MD5 message digests and check the result. Examples are "
+ "from RFC-1321."];
+md5(suite) ->
+ [];
+md5(Config) when is_list(Config) ->
+ ?line m(crypto:md5(""),
+ hexstr2bin("d41d8cd98f00b204e9800998ecf8427e")),
+ ?line m(crypto:md5("a"),
+ hexstr2bin("0cc175b9c0f1b6a831c399e269772661")),
+ ?line m(crypto:md5("abc"),
+ hexstr2bin("900150983cd24fb0d6963f7d28e17f72")),
+ ?line m(crypto:md5("message digest"),
+ hexstr2bin("f96b697d7cb7938d525a2f31aaf161d0")),
+ ?line m(crypto:md5("abcdefghijklmnopqrstuvwxyz"),
+ hexstr2bin("c3fcd3d76192e4007dfb496cca67e13b")),
+ ?line m(crypto:md5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789"),
+ hexstr2bin("d174ab98d277d9f5a5611c2c9f419d9f")),
+ ?line m(crypto:md5("12345678901234567890123456789012345678901234567890"
+ "123456789012345678901234567890"),
+ hexstr2bin("57edf4a22be3c955ac49da2e2107b67a")).
+
+%%
+%%
+md5_update(doc) ->
+ ["Generate MD5 message using md5_init, md5_update, and md5_final, and"
+ "check the result. Examples are from RFC-1321."];
+md5_update(suite) ->
+ [];
+md5_update(Config) when is_list(Config) ->
+ ?line Ctx = crypto:md5_init(),
+ ?line Ctx1 = crypto:md5_update(Ctx, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
+ ?line Ctx2 = crypto:md5_update(Ctx1, "abcdefghijklmnopqrstuvwxyz"
+ "0123456789"),
+ ?line m(crypto:md5_final(Ctx2),
+ hexstr2bin("d174ab98d277d9f5a5611c2c9f419d9f")).
+
+%%
+%%
+md4(doc) ->
+ ["Generate MD4 message digests and check the result. Examples are "
+ "from RFC-1321."];
+md4(suite) ->
+ [];
+md4(Config) when is_list(Config) ->
+ ?line m(crypto:md4(""),
+ hexstr2bin("31d6cfe0d16ae931b73c59d7e0c089c0")),
+ ?line m(crypto:md4("a"),
+ hexstr2bin("bde52cb31de33e46245e05fbdbd6fb24")),
+ ?line m(crypto:md4("abc"),
+ hexstr2bin("a448017aaf21d8525fc10ae87aa6729d")),
+ ?line m(crypto:md4("message digest"),
+ hexstr2bin("d9130a8164549fe818874806e1c7014b")),
+ ?line m(crypto:md4("abcdefghijklmnopqrstuvwxyz"),
+ hexstr2bin("d79e1c308aa5bbcdeea8ed63df412da9")),
+ ?line m(crypto:md4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789"),
+ hexstr2bin("043f8582f241db351ce627e153e7f0e4")),
+ ?line m(crypto:md4("12345678901234567890123456789012345678901234567890"
+ "123456789012345678901234567890"),
+ hexstr2bin("e33b4ddc9c38f2199c3e7b164fcc0536")).
+
+%%
+%%
+md4_update(doc) ->
+ ["Generate MD5 message using md5_init, md5_update, and md5_final, and"
+ "check the result. Examples are from RFC-1321."];
+md4_update(suite) ->
+ [];
+md4_update(Config) when is_list(Config) ->
+ ?line Ctx = crypto:md4_init(),
+ ?line Ctx1 = crypto:md4_update(Ctx, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
+ ?line Ctx2 = crypto:md4_update(Ctx1, "abcdefghijklmnopqrstuvwxyz"
+ "0123456789"),
+ ?line m(crypto:md4_final(Ctx2),
+ hexstr2bin("043f8582f241db351ce627e153e7f0e4")).
+
+%%
+%%
+sha(doc) ->
+ ["Generate SHA message digests and check the result. Examples are "
+ "from FIPS-180-1."];
+sha(suite) ->
+ [];
+sha(Config) when is_list(Config) ->
+ ?line m(crypto:sha("abc"),
+ hexstr2bin("A9993E364706816ABA3E25717850C26C9CD0D89D")),
+ ?line m(crypto:sha("abcdbcdecdefdefgefghfghighijhijkijkljklmklm"
+ "nlmnomnopnopq"),
+ hexstr2bin("84983E441C3BD26EBAAE4AA1F95129E5E54670F1")).
+
+
+%%
+hmac_update_sha_n(doc) ->
+ ["Request a larger-than-allowed SHA1 HMAC using hmac_init, hmac_update, and hmac_final_n. "
+ "Expected values for examples are generated using crypto:sha_mac." ];
+hmac_update_sha_n(suite) ->
+ [];
+hmac_update_sha_n(Config) when is_list(Config) ->
+ ?line Key = hexstr2bin("00010203101112132021222330313233"
+ "04050607141516172425262734353637"
+ "08090a0b18191a1b28292a2b38393a3b"
+ "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f"),
+ ?line Data = "Sampl",
+ ?line Data2 = "e #1",
+ ?line Ctx = crypto:hmac_init(sha, Key),
+ ?line Ctx2 = crypto:hmac_update(Ctx, Data),
+ ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
+ ?line Mac = crypto:hmac_final_n(Ctx3, 1024),
+ ?line Exp = crypto:sha_mac(Key, lists:flatten([Data, Data2])),
+ ?line m(Exp, Mac),
+ ?line m(size(Exp), size(Mac)).
+
+
+hmac_update_sha(doc) ->
+ ["Generate an SHA1 HMAC using hmac_init, hmac_update, and hmac_final. "
+ "Expected values for examples are generated using crypto:sha_mac." ];
+hmac_update_sha(suite) ->
+ [];
+hmac_update_sha(Config) when is_list(Config) ->
+ ?line Key = hexstr2bin("00010203101112132021222330313233"
+ "04050607141516172425262734353637"
+ "08090a0b18191a1b28292a2b38393a3b"
+ "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f"),
+ ?line Data = "Sampl",
+ ?line Data2 = "e #1",
+ ?line Ctx = crypto:hmac_init(sha, Key),
+ ?line Ctx2 = crypto:hmac_update(Ctx, Data),
+ ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
+ ?line Mac = crypto:hmac_final(Ctx3),
+ ?line Exp = crypto:hmac(sha, Key, lists:flatten([Data, Data2])),
+ ?line m(Exp, Mac).
+
+hmac_update_sha256(doc) ->
+ ["Generate an SHA256 HMAC using hmac_init, hmac_update, and hmac_final. "
+ "Expected values for examples are generated using crypto:sha256_mac." ];
+hmac_update_sha256(suite) ->
+ [];
+hmac_update_sha256(Config) when is_list(Config) ->
+ if_supported(sha256, fun() -> hmac_update_sha256_do() end).
+
+hmac_update_sha256_do() ->
+ ?line Key = hexstr2bin("00010203101112132021222330313233"
+ "04050607141516172425262734353637"
+ "08090a0b18191a1b28292a2b38393a3b"
+ "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f"),
+ ?line Data = "Sampl",
+ ?line Data2 = "e #1",
+ ?line Ctx = crypto:hmac_init(sha256, Key),
+ ?line Ctx2 = crypto:hmac_update(Ctx, Data),
+ ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
+ ?line Mac = crypto:hmac_final(Ctx3),
+ ?line Exp = crypto:hmac(sha256, Key, lists:flatten([Data, Data2])),
+ ?line m(Exp, Mac).
+
+hmac_update_sha512(doc) ->
+ ["Generate an SHA512 HMAC using hmac_init, hmac_update, and hmac_final. "
+ "Expected values for examples are generated using crypto:sha512_mac." ];
+hmac_update_sha512(suite) ->
+ [];
+hmac_update_sha512(Config) when is_list(Config) ->
+ if_supported(sha512, fun() -> hmac_update_sha512_do() end).
+
+hmac_update_sha512_do() ->
+ ?line Key = hexstr2bin("00010203101112132021222330313233"
+ "04050607141516172425262734353637"
+ "08090a0b18191a1b28292a2b38393a3b"
+ "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f"),
+ ?line Data = "Sampl",
+ ?line Data2 = "e #1",
+ ?line Ctx = crypto:hmac_init(sha512, Key),
+ ?line Ctx2 = crypto:hmac_update(Ctx, Data),
+ ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
+ ?line Mac = crypto:hmac_final(Ctx3),
+ ?line Exp = crypto:hmac(sha512, Key, lists:flatten([Data, Data2])),
+ ?line m(Exp, Mac).
+
+hmac_update_md5(doc) ->
+ ["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. "
+ "Expected values for examples are generated using crypto:md5_mac." ];
+hmac_update_md5(suite) ->
+ [];
+hmac_update_md5(Config) when is_list(Config) ->
+ % ?line Key2 = ["A fine speach", "by a fine man!"],
+ Key2 = "A fine speach by a fine man!",
+ ?line Long1 = "Four score and seven years ago our fathers brought forth on this continent a new nation, conceived in liberty, and dedicated to the proposition that all men are created equal.",
+ ?line Long2 = "Now we are engaged in a great civil war, testing whether that nation, or any nation, so conceived and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this.",
+ ?line Long3 = "But, in a larger sense, we can not dedicate, we can not consecrate, we can not hallow this ground. The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us-that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion that we here highly resolve that these dead shall not have died in vain-that this nation, under God, shall have a new birth of freedom-and that government of the people, by the people, for the people, shall not perish from the earth.",
+ ?line CtxA = crypto:hmac_init(md5, Key2),
+ ?line CtxB = crypto:hmac_update(CtxA, Long1),
+ ?line CtxC = crypto:hmac_update(CtxB, Long2),
+ ?line CtxD = crypto:hmac_update(CtxC, Long3),
+ ?line Mac2 = crypto:hmac_final(CtxD),
+ ?line Exp2 = crypto:md5_mac(Key2, lists:flatten([Long1, Long2, Long3])),
+ ?line m(Exp2, Mac2).
+
+hmac_rfc2202(doc) ->
+ ["Generate an HMAC using hmac, md5_mac, and sha_mac."
+ "Test vectors are taken from RFC-2202."];
+hmac_rfc2202(suite) ->
+ [];
+hmac_rfc2202(Config) when is_list(Config) ->
+ hmac_rfc2202_md5(),
+ hmac_rfc2202_sha().
+
+hmac_rfc2202_md5() ->
+ %% Test case 1
+ Case1Key = binary:copy(<<16#0b>>, 16),
+ Case1Data = <<"Hi There">>,
+ Case1Exp = hexstr2bin("9294727a3638bb1c13f48ef8158bfc9d"),
+
+ ?line Case1Mac_1 = crypto:md5_mac(Case1Key, Case1Data),
+ ?line Case1Mac_2 = crypto:hmac(md5, Case1Key, Case1Data),
+ ?line m(Case1Exp, Case1Mac_1),
+ ?line m(Case1Exp, Case1Mac_2),
+
+ %% Test case 2
+ Case2Key = <<"Jefe">>,
+ Case2Data = <<"what do ya want for nothing?">>,
+ Case2Exp = hexstr2bin("750c783e6ab0b503eaa86e310a5db738"),
+
+ ?line Case2Mac_1 = crypto:md5_mac(Case2Key, Case2Data),
+ ?line Case2Mac_2 = crypto:hmac(md5, Case2Key, Case2Data),
+ ?line m(Case2Exp, Case2Mac_1),
+ ?line m(Case2Exp, Case2Mac_2),
+
+ %% Test case 3
+ Case3Key = binary:copy(<<16#aa>>, 16),
+ Case3Data = binary:copy(<<16#dd>>, 50),
+ Case3Exp = hexstr2bin("56be34521d144c88dbb8c733f0e8b3f6"),
+
+ ?line Case3Mac_1 = crypto:md5_mac(Case3Key, Case3Data),
+ ?line Case3Mac_2 = crypto:hmac(md5, Case3Key, Case3Data),
+ ?line m(Case3Exp, Case3Mac_1),
+ ?line m(Case3Exp, Case3Mac_2),
+
+ %% Test case 4
+ Case4Key = list_to_binary(lists:seq(1, 16#19)),
+ Case4Data = binary:copy(<<16#cd>>, 50),
+ Case4Exp = hexstr2bin("697eaf0aca3a3aea3a75164746ffaa79"),
+
+ ?line Case4Mac_1 = crypto:md5_mac(Case4Key, Case4Data),
+ ?line Case4Mac_2 = crypto:hmac(md5, Case4Key, Case4Data),
+ ?line m(Case4Exp, Case4Mac_1),
+ ?line m(Case4Exp, Case4Mac_2),
+
+ %% Test case 5
+ Case5Key = binary:copy(<<16#0c>>, 16),
+ Case5Data = "Test With Truncation",
+ Case5Exp = hexstr2bin("56461ef2342edc00f9bab995690efd4c"),
+ Case5Exp96 = hexstr2bin("56461ef2342edc00f9bab995"),
+
+ ?line Case5Mac_1 = crypto:md5_mac(Case5Key, Case5Data),
+ ?line Case5Mac_2 = crypto:hmac(md5, Case5Key, Case5Data),
+ ?line Case5Mac96_1 = crypto:md5_mac_96(Case5Key, Case5Data),
+ ?line Case5Mac96_2 = crypto:hmac(md5, Case5Key, Case5Data, 12),
+ ?line m(Case5Exp, Case5Mac_1),
+ ?line m(Case5Exp, Case5Mac_2),
+ ?line m(Case5Exp96, Case5Mac96_1),
+ ?line m(Case5Exp96, Case5Mac96_2),
+
+ %% Test case 6
+ Case6Key = binary:copy(<<16#aa>>, 80),
+ Case6Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
+ Case6Exp = hexstr2bin("6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd"),
+
+ ?line Case6Mac_1 = crypto:md5_mac(Case6Key, Case6Data),
+ ?line Case6Mac_2 = crypto:hmac(md5, Case6Key, Case6Data),
+ ?line m(Case6Exp, Case6Mac_1),
+ ?line m(Case6Exp, Case6Mac_2),
+
+ %% Test case 7
+ Case7Key = binary:copy(<<16#aa>>, 80),
+ Case7Data = <<"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data">>,
+ Case7Exp = hexstr2bin("6f630fad67cda0ee1fb1f562db3aa53e"),
+
+ ?line Case7Mac_1 = crypto:md5_mac(Case7Key, Case7Data),
+ ?line Case7Mac_2 = crypto:hmac(md5, Case7Key, Case7Data),
+ ?line m(Case7Exp, Case7Mac_1),
+ ?line m(Case7Exp, Case7Mac_2).
+
+hmac_rfc2202_sha() ->
+ %% Test case 1
+ Case1Key = binary:copy(<<16#0b>>, 20),
+ Case1Data = <<"Hi There">>,
+ Case1Exp = hexstr2bin("b617318655057264e28bc0b6fb378c8ef146be00"),
+
+ ?line Case1Mac_1 = crypto:sha_mac(Case1Key, Case1Data),
+ ?line Case1Mac_2 = crypto:hmac(sha, Case1Key, Case1Data),
+ ?line m(Case1Exp, Case1Mac_1),
+ ?line m(Case1Exp, Case1Mac_2),
+
+ %% Test case 2
+ Case2Key = <<"Jefe">>,
+ Case2Data = <<"what do ya want for nothing?">>,
+ Case2Exp = hexstr2bin("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79"),
+
+ ?line Case2Mac_1 = crypto:sha_mac(Case2Key, Case2Data),
+ ?line Case2Mac_2 = crypto:hmac(sha, Case2Key, Case2Data),
+ ?line m(Case2Exp, Case2Mac_1),
+ ?line m(Case2Exp, Case2Mac_2),
+
+ %% Test case 3
+ Case3Key = binary:copy(<<16#aa>>, 20),
+ Case3Data = binary:copy(<<16#dd>>, 50),
+ Case3Exp = hexstr2bin("125d7342b9ac11cd91a39af48aa17b4f63f175d3"),
+
+ ?line Case3Mac_1 = crypto:sha_mac(Case3Key, Case3Data),
+ ?line Case3Mac_2 = crypto:hmac(sha, Case3Key, Case3Data),
+ ?line m(Case3Exp, Case3Mac_1),
+ ?line m(Case3Exp, Case3Mac_2),
+
+ %% Test case 4
+ Case4Key = list_to_binary(lists:seq(1, 16#19)),
+ Case4Data = binary:copy(<<16#cd>>, 50),
+ Case4Exp = hexstr2bin("4c9007f4026250c6bc8414f9bf50c86c2d7235da"),
+
+ ?line Case4Mac_1 = crypto:sha_mac(Case4Key, Case4Data),
+ ?line Case4Mac_2 = crypto:hmac(sha, Case4Key, Case4Data),
+ ?line m(Case4Exp, Case4Mac_1),
+ ?line m(Case4Exp, Case4Mac_2),
+
+ %% Test case 5
+ Case5Key = binary:copy(<<16#0c>>, 20),
+ Case5Data = "Test With Truncation",
+ Case5Exp = hexstr2bin("4c1a03424b55e07fe7f27be1d58bb9324a9a5a04"),
+ Case5Exp96 = hexstr2bin("4c1a03424b55e07fe7f27be1"),
+
+ ?line Case5Mac_1 = crypto:sha_mac(Case5Key, Case5Data),
+ ?line Case5Mac_2 = crypto:hmac(sha, Case5Key, Case5Data),
+ ?line Case5Mac96_1 = crypto:sha_mac_96(Case5Key, Case5Data),
+ ?line Case5Mac96_2 = crypto:hmac(sha, Case5Key, Case5Data, 12),
+ ?line m(Case5Exp, Case5Mac_1),
+ ?line m(Case5Exp, Case5Mac_2),
+ ?line m(Case5Exp96, Case5Mac96_1),
+ ?line m(Case5Exp96, Case5Mac96_2),
+
+ %% Test case 6
+ Case6Key = binary:copy(<<16#aa>>, 80),
+ Case6Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
+ Case6Exp = hexstr2bin("aa4ae5e15272d00e95705637ce8a3b55ed402112"),
+
+ ?line Case6Mac_1 = crypto:sha_mac(Case6Key, Case6Data),
+ ?line Case6Mac_2 = crypto:hmac(sha, Case6Key, Case6Data),
+ ?line m(Case6Exp, Case6Mac_1),
+ ?line m(Case6Exp, Case6Mac_2),
+
+ %% Test case 7
+ Case7Key = binary:copy(<<16#aa>>, 80),
+ Case7Data = <<"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data">>,
+ Case7Exp = hexstr2bin("e8e99d0f45237d786d6bbaa7965c7808bbff1a91"),
+
+ ?line Case7Mac_1 = crypto:sha_mac(Case7Key, Case7Data),
+ ?line Case7Mac_2 = crypto:hmac(sha, Case7Key, Case7Data),
+ ?line m(Case7Exp, Case7Mac_1),
+ ?line m(Case7Exp, Case7Mac_2).
+
+hmac_rfc4231_sha224(doc) ->
+ ["Generate an HMAC using crypto:sha224_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
+ "Testvectors are take from RFC4231." ];
+hmac_rfc4231_sha224(suite) ->
+ [];
+hmac_rfc4231_sha224(Config) when is_list(Config) ->
+ if_supported(sha224, fun() -> hmac_rfc4231_sha224_do() end).
+
+hmac_rfc4231_sha256(doc) ->
+ ["Generate an HMAC using crypto:sha256_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
+ "Testvectors are take from RFC4231." ];
+hmac_rfc4231_sha256(suite) ->
+ [];
+hmac_rfc4231_sha256(Config) when is_list(Config) ->
+ if_supported(sha256, fun() -> hmac_rfc4231_sha256_do() end).
+
+hmac_rfc4231_sha384(doc) ->
+ ["Generate an HMAC using crypto:sha384_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
+ "Testvectors are take from RFC4231." ];
+hmac_rfc4231_sha384(suite) ->
+ [];
+hmac_rfc4231_sha384(Config) when is_list(Config) ->
+ if_supported(sha384, fun() -> hmac_rfc4231_sha384_do() end).
+
+hmac_rfc4231_sha512(doc) ->
+ ["Generate an HMAC using crypto:sha512_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
+ "Testvectors are take from RFC4231." ];
+hmac_rfc4231_sha512(suite) ->
+ [];
+hmac_rfc4231_sha512(Config) when is_list(Config) ->
+ if_supported(sha512, fun() -> hmac_rfc4231_sha512_do() end).
+
+hmac_rfc4231_case(Hash, case1, Exp) ->
+ %% Test 1
+ Key = binary:copy(<<16#0b>>, 20),
+ Data = <<"Hi There">>,
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
+
+hmac_rfc4231_case(Hash, case2, Exp) ->
+ %% Test 2
+ Key = <<"Jefe">>,
+ Data = <<"what do ya want for nothing?">>,
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
+
+hmac_rfc4231_case(Hash, case3, Exp) ->
+ %% Test 3
+ Key = binary:copy(<<16#aa>>, 20),
+ Data = binary:copy(<<16#dd>>, 50),
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
+
+hmac_rfc4231_case(Hash, case4, Exp) ->
+ %% Test 4
+ Key = list_to_binary(lists:seq(1, 16#19)),
+ Data = binary:copy(<<16#cd>>, 50),
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
+
+hmac_rfc4231_case(Hash, case5, Exp) ->
+ %% Test 5
+ Key = binary:copy(<<16#0c>>, 20),
+ Data = <<"Test With Truncation">>,
+ hmac_rfc4231_case(Hash, Key, Data, 16, Exp);
+
+hmac_rfc4231_case(Hash, case6, Exp) ->
+ %% Test 6
+ Key = binary:copy(<<16#aa>>, 131),
+ Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
+
+hmac_rfc4231_case(Hash, case7, Exp) ->
+ %% Test Case 7
+ Key = binary:copy(<<16#aa>>, 131),
+ Data = <<"This is a test using a larger than block-size key and a larger t",
+ "han block-size data. The key needs to be hashed before being use",
+ "d by the HMAC algorithm.">>,
+ hmac_rfc4231_case(Hash, Key, Data, Exp).
+
+hmac_rfc4231_case(Hash, Key, Data, Exp) ->
+ ?line Ctx = crypto:hmac_init(Hash, Key),
+ ?line Ctx2 = crypto:hmac_update(Ctx, Data),
+ ?line Mac1 = crypto:hmac_final(Ctx2),
+ ?line Mac3 = crypto:hmac(Hash, Key, Data),
+ ?line m(Exp, Mac1),
+ ?line m(Exp, Mac3).
+
+hmac_rfc4231_case(Hash, Key, Data, Trunc, Exp) ->
+ ?line Ctx = crypto:hmac_init(Hash, Key),
+ ?line Ctx2 = crypto:hmac_update(Ctx, Data),
+ ?line Mac1 = crypto:hmac_final_n(Ctx2, Trunc),
+ ?line Mac3 = crypto:hmac(Hash, Key, Data, Trunc),
+ ?line m(Exp, Mac1),
+ ?line m(Exp, Mac3).
+
+hmac_rfc4231_sha224_do() ->
+ Case1 = hexstr2bin("896fb1128abbdf196832107cd49df33f"
+ "47b4b1169912ba4f53684b22"),
+ Case2 = hexstr2bin("a30e01098bc6dbbf45690f3a7e9e6d0f"
+ "8bbea2a39e6148008fd05e44"),
+ Case3 = hexstr2bin("7fb3cb3588c6c1f6ffa9694d7d6ad264"
+ "9365b0c1f65d69d1ec8333ea"),
+ Case4 = hexstr2bin("6c11506874013cac6a2abc1bb382627c"
+ "ec6a90d86efc012de7afec5a"),
+ Case5 = hexstr2bin("0e2aea68a90c8d37c988bcdb9fca6fa8"),
+ Case6 = hexstr2bin("95e9a0db962095adaebe9b2d6f0dbce2"
+ "d499f112f2d2b7273fa6870e"),
+ Case7 = hexstr2bin("3a854166ac5d9f023f54d517d0b39dbd"
+ "946770db9c2b95c9f6f565d1"),
+ hmac_rfc4231_cases_do(sha224, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+
+hmac_rfc4231_sha256_do() ->
+ Case1 = hexstr2bin("b0344c61d8db38535ca8afceaf0bf12b"
+ "881dc200c9833da726e9376c2e32cff7"),
+ Case2 = hexstr2bin("5bdcc146bf60754e6a042426089575c7"
+ "5a003f089d2739839dec58b964ec3843"),
+ Case3 = hexstr2bin("773ea91e36800e46854db8ebd09181a7"
+ "2959098b3ef8c122d9635514ced565fe"),
+ Case4 = hexstr2bin("82558a389a443c0ea4cc819899f2083a"
+ "85f0faa3e578f8077a2e3ff46729665b"),
+ Case5 = hexstr2bin("a3b6167473100ee06e0c796c2955552b"),
+ Case6 = hexstr2bin("60e431591ee0b67f0d8a26aacbf5b77f"
+ "8e0bc6213728c5140546040f0ee37f54"),
+ Case7 = hexstr2bin("9b09ffa71b942fcb27635fbcd5b0e944"
+ "bfdc63644f0713938a7f51535c3a35e2"),
+ hmac_rfc4231_cases_do(sha256, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+
+hmac_rfc4231_sha384_do() ->
+ Case1 = hexstr2bin("afd03944d84895626b0825f4ab46907f"
+ "15f9dadbe4101ec682aa034c7cebc59c"
+ "faea9ea9076ede7f4af152e8b2fa9cb6"),
+ Case2 = hexstr2bin("af45d2e376484031617f78d2b58a6b1b"
+ "9c7ef464f5a01b47e42ec3736322445e"
+ "8e2240ca5e69e2c78b3239ecfab21649"),
+ Case3 = hexstr2bin("88062608d3e6ad8a0aa2ace014c8a86f"
+ "0aa635d947ac9febe83ef4e55966144b"
+ "2a5ab39dc13814b94e3ab6e101a34f27"),
+ Case4 = hexstr2bin("3e8a69b7783c25851933ab6290af6ca7"
+ "7a9981480850009cc5577c6e1f573b4e"
+ "6801dd23c4a7d679ccf8a386c674cffb"),
+ Case5 = hexstr2bin("3abf34c3503b2a23a46efc619baef897"),
+ Case6 = hexstr2bin("4ece084485813e9088d2c63a041bc5b4"
+ "4f9ef1012a2b588f3cd11f05033ac4c6"
+ "0c2ef6ab4030fe8296248df163f44952"),
+ Case7 = hexstr2bin("6617178e941f020d351e2f254e8fd32c"
+ "602420feb0b8fb9adccebb82461e99c5"
+ "a678cc31e799176d3860e6110c46523e"),
+ hmac_rfc4231_cases_do(sha384, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+
+hmac_rfc4231_sha512_do() ->
+ Case1 = hexstr2bin("87aa7cdea5ef619d4ff0b4241a1d6cb0"
+ "2379f4e2ce4ec2787ad0b30545e17cde"
+ "daa833b7d6b8a702038b274eaea3f4e4"
+ "be9d914eeb61f1702e696c203a126854"),
+ Case2 = hexstr2bin("164b7a7bfcf819e2e395fbe73b56e0a3"
+ "87bd64222e831fd610270cd7ea250554"
+ "9758bf75c05a994a6d034f65f8f0e6fd"
+ "caeab1a34d4a6b4b636e070a38bce737"),
+ Case3 = hexstr2bin("fa73b0089d56a284efb0f0756c890be9"
+ "b1b5dbdd8ee81a3655f83e33b2279d39"
+ "bf3e848279a722c806b485a47e67c807"
+ "b946a337bee8942674278859e13292fb"),
+ Case4 = hexstr2bin("b0ba465637458c6990e5a8c5f61d4af7"
+ "e576d97ff94b872de76f8050361ee3db"
+ "a91ca5c11aa25eb4d679275cc5788063"
+ "a5f19741120c4f2de2adebeb10a298dd"),
+ Case5 = hexstr2bin("415fad6271580a531d4179bc891d87a6"),
+ Case6 = hexstr2bin("80b24263c7c1a3ebb71493c1dd7be8b4"
+ "9b46d1f41b4aeec1121b013783f8f352"
+ "6b56d037e05f2598bd0fd2215d6a1e52"
+ "95e64f73f63f0aec8b915a985d786598"),
+ Case7 = hexstr2bin("e37b6a775dc87dbaa4dfa9f96e5e3ffd"
+ "debd71f8867289865df5a32d20cdc944"
+ "b6022cac3c4982b10d5eeb55c3e4de15"
+ "134676fb6de0446065c97440fa8c6a58"),
+ hmac_rfc4231_cases_do(sha512, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+
+hmac_rfc4231_cases_do(Hash, CasesData) ->
+ hmac_rfc4231_cases_do(Hash, [case1, case2, case3, case4, case5, case6, case7], CasesData).
+
+hmac_rfc4231_cases_do(_Hash, _, []) ->
+ ok;
+hmac_rfc4231_cases_do(Hash, [C|Cases], [D|CasesData]) ->
+ hmac_rfc4231_case(Hash, C, D),
+ hmac_rfc4231_cases_do(Hash, Cases, CasesData).
+
+hmac_update_md5_io(doc) ->
+ ["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. "
+ "Expected values for examples are generated using crypto:md5_mac." ];
+hmac_update_md5_io(suite) ->
+ [];
+hmac_update_md5_io(Config) when is_list(Config) ->
+ ?line Key = ["A fine speach", "by a fine man!"],
+ ?line Data = "Sampl",
+ ?line Data2 = "e #1",
+ ?line Ctx = crypto:hmac_init(md5, Key),
+ ?line Ctx2 = crypto:hmac_update(Ctx, Data),
+ ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
+ ?line Mac = crypto:hmac_final(Ctx3),
+ ?line Exp = crypto:md5_mac(Key, lists:flatten([Data, Data2])),
+ ?line m(Exp, Mac).
+
+
+hmac_update_md5_n(doc) ->
+ ["Generate a shortened MD5 HMAC using hmac_init, hmac_update, and hmac_final. "
+ "Expected values for examples are generated using crypto:md5_mac." ];
+hmac_update_md5_n(suite) ->
+ [];
+hmac_update_md5_n(Config) when is_list(Config) ->
+ ?line Key = ["A fine speach", "by a fine man!"],
+ ?line Data = "Sampl",
+ ?line Data2 = "e #1",
+ ?line Ctx = crypto:hmac_init(md5, Key),
+ ?line Ctx2 = crypto:hmac_update(Ctx, Data),
+ ?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
+ ?line Mac = crypto:hmac_final_n(Ctx3, 12),
+ ?line Exp = crypto:md5_mac_96(Key, lists:flatten([Data, Data2])),
+ ?line m(Exp, Mac).
+%%
+%%
+ripemd160(doc) ->
+ ["Generate RIPEMD160 message digests and check the result."];
+ripemd160(suite) ->
+ [];
+ripemd160(Config) when is_list(Config) ->
+ ?line m(crypto:hash(ripemd160,"abc"),
+ hexstr2bin("8EB208F7E05D987A9B044A8E98C6B087F15A0BFC")),
+ ?line m(crypto:hash(ripemd160,"abcdbcdecdefdefgefghfghighijhijkijkljklmklm"
+ "nlmnomnopnopq"),
+ hexstr2bin("12A053384A9C0C88E405A06C27DCF49ADA62EB2B")).
+
+
+%%
+%%
+ripemd160_update(doc) ->
+ ["Generate RIPEMD160 message digests by using ripemd160_init,"
+ "ripemd160_update, and ripemd160_final and check the result."];
+ripemd160_update(suite) ->
+ [];
+ripemd160_update(Config) when is_list(Config) ->
+ ?line Ctx = crypto:hash_init(ripemd160),
+ ?line Ctx1 = crypto:hash_update(Ctx, "abcdbcdecdefdefgefghfghighi"),
+ ?line Ctx2 = crypto:hash_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"),
+ ?line m(crypto:hash_final(Ctx2),
+ hexstr2bin("12A053384A9C0C88E405A06C27DCF49ADA62EB2B")).
+
+%%
+%%
+sha_update(doc) ->
+ ["Generate SHA message digests by using sha_init, sha_update, and"
+ "sha_final, and check the result. Examples are from FIPS-180-1."];
+sha_update(suite) ->
+ [];
+sha_update(Config) when is_list(Config) ->
+ ?line Ctx = crypto:sha_init(),
+ ?line Ctx1 = crypto:sha_update(Ctx, "abcdbcdecdefdefgefghfghighi"),
+ ?line Ctx2 = crypto:sha_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"),
+ ?line m(crypto:sha_final(Ctx2),
+ hexstr2bin("84983E441C3BD26EBAAE4AA1F95129E5E54670F1")).
+
+%%
+%%
+sha256(doc) ->
+ ["Generate SHA-256 message digests and check the result. Examples are "
+ "from rfc-4634."];
+sha256(suite) ->
+ [];
+sha256(Config) when is_list(Config) ->
+ if_supported(sha256, fun() -> sha256_do() end).
+
+sha256_do() ->
+ ?line m(crypto:hash(sha256, "abc"),
+ hexstr2bin("BA7816BF8F01CFEA4141"
+ "40DE5DAE2223B00361A396177A9CB410FF61F20015AD")),
+ ?line m(crypto:hash(sha256, "abcdbcdecdefdefgefghfghighijhijkijkljklmklm"
+ "nlmnomnopnopq"),
+ hexstr2bin("248D6A61D20638B8"
+ "E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")).
+
+%%
+%%
+sha256_update(doc) ->
+ ["Generate SHA256 message digests by using sha256_init, sha256_update, and"
+ "sha256_final, and check the result. Examples are from rfc-4634."];
+sha256_update(suite) ->
+ [];
+sha256_update(Config) when is_list(Config) ->
+ if_supported(sha256, fun() -> sha256_update_do() end).
+
+sha256_update_do() ->
+ ?line Ctx = crypto:hash_init(sha256),
+ ?line Ctx1 = crypto:hash_update(Ctx, "abcdbcdecdefdefgefghfghighi"),
+ ?line Ctx2 = crypto:hash_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"),
+ ?line m(crypto:hash_final(Ctx2),
+ hexstr2bin("248D6A61D20638B8"
+ "E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")).
+
+
+%%
+%%
+sha512(doc) ->
+ ["Generate SHA-512 message digests and check the result. Examples are "
+ "from rfc-4634."];
+sha512(suite) ->
+ [];
+sha512(Config) when is_list(Config) ->
+ if_supported(sha512, fun() -> sha512_do() end).
+
+sha512_do() ->
+ ?line m(crypto:hash(sha512, "abc"),
+ hexstr2bin("DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA2"
+ "0A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD"
+ "454D4423643CE80E2A9AC94FA54CA49F")),
+ ?line m(crypto:hash(sha512, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+ "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"),
+ hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1"
+ "7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A"
+ "C7D329EEB6DD26545E96E55B874BE909")).
+
+%%
+%%
+sha512_update(doc) ->
+ ["Generate SHA512 message digests by using sha512_init, sha512_update, and"
+ "sha512_final, and check the result. Examples are from rfc=4634."];
+sha512_update(suite) ->
+ [];
+sha512_update(Config) when is_list(Config) ->
+ if_supported(sha512, fun() -> sha512_update_do() end).
+
+sha512_update_do() ->
+ ?line Ctx = crypto:hash_init(sha512),
+ ?line Ctx1 = crypto:hash_update(Ctx, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"),
+ ?line Ctx2 = crypto:hash_update(Ctx1, "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"),
+ ?line m(crypto:hash_final(Ctx2),
+ hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1"
+ "7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A"
+ "C7D329EEB6DD26545E96E55B874BE909")).
+
+%%
+%%
+md5_mac(doc) ->
+ ["Generate some HMACs, using MD5, and check the result. Examples are "
+ "from RFC-2104."];
+md5_mac(suite) ->
+ [];
+md5_mac(Config) when is_list(Config) ->
+ ?line m(crypto:md5_mac(hexstr2bin("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+ "Hi There"),
+ hexstr2bin("9294727a3638bb1c13f48ef8158bfc9d")),
+ ?line m(crypto:md5_mac(list_to_binary("Jefe"),
+ "what do ya want for nothing?"),
+ hexstr2bin("750c783e6ab0b503eaa86e310a5db738")),
+ ?line m(crypto:md5_mac(hexstr2bin("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"),
+ hexstr2bin("DDDDDDDDDDDDDDDDDDDD"
+ "DDDDDDDDDDDDDDDDDDDD"
+ "DDDDDDDDDDDDDDDDDDDD"
+ "DDDDDDDDDDDDDDDDDDDD"
+ "DDDDDDDDDDDDDDDDDDDD")),
+ hexstr2bin("56be34521d144c88dbb8c733f0e8b3f6")).
+
+%%
+%%
+md5_mac_io(doc) ->
+ ["Generate some HMACs, using MD5, with Key an IO-list, and check the "
+ "result. Examples are from RFC-2104."];
+md5_mac_io(suite) ->
+ [];
+md5_mac_io(Config) when is_list(Config) ->
+ ?line Key1 = hexstr2bin("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+ ?line {B11, B12} = split_binary(Key1, 4),
+ ?line Key11 = [B11,binary_to_list(B12)],
+ ?line m(crypto:md5_mac(Key11, "Hi There"),
+ hexstr2bin("9294727a3638bb1c13f48ef8158bfc9d")).
+
+%%
+%%
+des_cbc(doc) ->
+ "Encrypt and decrypt according to CBC DES. and check the result. "
+ "Example are from FIPS-81.";
+des_cbc(suite) ->
+ [];
+des_cbc(Config) when is_list(Config) ->
+ ?line Key = hexstr2bin("0123456789abcdef"),
+ ?line IVec = hexstr2bin("1234567890abcdef"),
+ ?line Plain = "Now is the time for all ",
+ ?line Cipher = crypto:des_cbc_encrypt(Key, IVec, Plain),
+ ?line m(Cipher, hexstr2bin("e5c7cdde872bf27c43e934008c389c"
+ "0f683788499a7c05f6")),
+ ?line m(list_to_binary(Plain),
+ crypto:des_cbc_decrypt(Key, IVec, Cipher)),
+ ?line Plain2 = "7654321 Now is the time for " ++ [0, 0, 0, 0],
+ ?line Cipher2 = crypto:des_cbc_encrypt(Key, IVec, Plain2),
+ ?line m(Cipher2, hexstr2bin("b9916b8ee4c3da64b4f44e3cbefb9"
+ "9484521388fa59ae67d58d2e77e86062733")),
+ ?line m(list_to_binary(Plain2),
+ crypto:des_cbc_decrypt(Key, IVec, Cipher2)).
+
+%%
+%%
+des_cbc_iter(doc) ->
+ "Encrypt and decrypt according to CBC DES in two steps, and "
+ "check the result. Example are from FIPS-81.";
+des_cbc_iter(suite) ->
+ [];
+des_cbc_iter(Config) when is_list(Config) ->
+ ?line Key = hexstr2bin("0123456789abcdef"),
+ ?line IVec = hexstr2bin("1234567890abcdef"),
+ ?line Plain1 = "Now is the time ",
+ ?line Plain2 = "for all ",
+ ?line Cipher1 = crypto:des_cbc_encrypt(Key, IVec, Plain1),
+ ?line IVec2 = crypto:des_cbc_ivec(Cipher1),
+ ?line Cipher2 = crypto:des_cbc_encrypt(Key, IVec2, Plain2),
+ ?line Cipher = list_to_binary([Cipher1, Cipher2]),
+ ?line m(Cipher, hexstr2bin("e5c7cdde872bf27c43e934008c389c"
+ "0f683788499a7c05f6")).
+
+%%
+%%
+des_cfb(doc) ->
+ "Encrypt and decrypt according to CFB DES. and check the result. "
+ "Example is from FIPS-81.";
+des_cfb(suite) ->
+ [];
+des_cfb(Config) when is_list(Config) ->
+ ?line Key = hexstr2bin("0123456789abcdef"),
+ ?line IVec = hexstr2bin("1234567890abcdef"),
+ ?line Plain = "Now is the",
+ ?line Cipher = crypto:des_cfb_encrypt(Key, IVec, Plain),
+ ?line m(Cipher, hexstr2bin("f31fda07011462ee187f")),
+ ?line m(list_to_binary(Plain),
+ crypto:des_cfb_decrypt(Key, IVec, Cipher)).
+
+%%
+%%
+des_cfb_iter(doc) ->
+ "Encrypt and decrypt according to CFB DES in two steps, and "
+ "check the result. Example is from FIPS-81.";
+des_cfb_iter(suite) ->
+ [];
+des_cfb_iter(Config) when is_list(Config) ->
+ ?line Key = hexstr2bin("0123456789abcdef"),
+ ?line IVec = hexstr2bin("1234567890abcdef"),
+ ?line Plain1 = "Now i",
+ ?line Plain2 = "s the",
+ ?line Cipher1 = crypto:des_cfb_encrypt(Key, IVec, Plain1),
+ ?line IVec2 = crypto:des_cfb_ivec(IVec, Cipher1),
+ ?line Cipher2 = crypto:des_cfb_encrypt(Key, IVec2, Plain2),
+ ?line Cipher = list_to_binary([Cipher1, Cipher2]),
+ ?line m(Cipher, hexstr2bin("f31fda07011462ee187f")).
+
+%%
+%%
+des_ecb(doc) ->
+ "Encrypt and decrypt according to ECB DES and check the result. "
+ "Example are from FIPS-81.";
+des_ecb(suite) ->
+ [];
+des_ecb(Config) when is_list(Config) ->
+ ?line Key = hexstr2bin("0123456789abcdef"),
+ ?line Cipher1 = crypto:des_ecb_encrypt(Key, "Now is t"),
+ ?line m(Cipher1, hexstr2bin("3fa40e8a984d4815")),
+ ?line Cipher2 = crypto:des_ecb_encrypt(Key, "he time "),
+ ?line m(Cipher2, hexstr2bin("6a271787ab8883f9")),
+ ?line Cipher3 = crypto:des_ecb_encrypt(Key, "for all "),
+ ?line m(Cipher3, hexstr2bin("893d51ec4b563b53")),
+ ?line Cipher4 = crypto:des_ecb_decrypt(Key, hexstr2bin("3fa40e8a984d4815")),
+ ?line m(Cipher4, <<"Now is t">>),
+ ?line Cipher5 = crypto:des_ecb_decrypt(Key, hexstr2bin("6a271787ab8883f9")),
+ ?line m(Cipher5, <<"he time ">>),
+ ?line Cipher6 = crypto:des_ecb_decrypt(Key, hexstr2bin("893d51ec4b563b53")),
+ ?line m(Cipher6, <<"for all ">>).
+%%
+%%
+rc2_cbc(doc) ->
+ "Encrypt and decrypt according to RC2 CBC and check the result. "
+ "Example stripped out from public_key application test";
+rc2_cbc(Config) when is_list(Config) ->
+
+ Key = <<146,210,160,124,215,227,153,239,227,17,222,140,3,93,27,191>>,
+ IV = <<72,91,135,182,25,42,35,210>>,
+
+ Cipher = <<36,245,206,158,168,230,58,69,148,137,32,192,250,41,237,181,181,251, 192,2,175,135,177,171,57,30,111,117,159,149,15,28,88,158,28,81,28,115, 85,219,241,82,117,222,91,85,73,117,164,25,182,52,191,64,123,57,26,19, 211,27,253,31,194,219,231,104,247,240,172,130,119,21,225,154,101,247, 32,216,42,216,133,169,78,22,97,27,227,26,196,224,172,168,17,9,148,55, 203,91,252,40,61,226,236,221,215,160,78,63,13,181,68,57,196,241,185, 207, 116,129,152,237,60,139,247,153,27,146,161,246,222,98,185,222,152, 187,135, 236,86,34,7,110,91,230,173,34,160,242,202,222,121,127,181,140, 101,203,195, 190,88,250,86,147,127,87,72,126,171,16,71,47,110,248,88, 14,29,143,161,152, 129,236,148,22,152,186,208,119,70,8,174,193,203,100, 193,203,200,117,102,242, 134,142,96,125,135,200,217,190,76,117,50,70, 209,186,101,241,200,91,40,193,54, 90,195,38,47,59,197,38,234,86,223,16, 51,253,204,129,20,171,66,21,241,26,135,216, 196,114,110,91,15,53,40, 164,201,136,113,95,247,51,181,208,241,68,168,98,151,36, 155,72,24,57, 42,191,14,125,204,10,167,214,233,138,115,125,234,121,134,227,26,247, 77,200,117,110,117,111,168,156,206,67,159,149,189,173,150,193,91,199, 216,153,22, 189,137,185,89,160,13,131,132,58,109,28,110,246,252,251,14, 232,91,38,52,29,101,188,69,123,50,0,130,178,93,73,239,118,7,77,35,59, 253,10,159,45,86,142,37,78,232,48>>,
+ Text = <<48,130,1,85,2,1,0,48,13,6,9,42,134,72,134,247,13,1,1,1,5,0,4,130,1,63,48,130, 1,59,2,1,0,2,65,0,222,187,252,44,9,214,27,173,162,169,70,47,36,34,78,84,204, 107,60,192,117,95,21,206,49,142,245,126,121,223,23,2,107,106,133,204,161,36, 40,2,114,69,4,93,242,5,42,50,154,47,154,211,209,123,120,161,5,114,173,155,34, 191,52,59,2,3,1,0,1,2,64,45,144,169,106,220,236,71,39,67,82,123,192,35,21,61, 143,13,110,150,180,12,142,210,40,39,109,70,125,132,51,6,66,159,134,112,85, 155,243,118,221,65,133,127,99,151,194,252,141,149,224,229,62,214,45,228,32, 184,85,67,14,228,161,184,161,2,33,0,255,202,240,131,130,57,49,224,115,255,83, 79,6,165,212,21,179,212,20,188,97,74,69,68,163,223,247,237,39,24,23,235,2,33, 0,222,234,48,36,33,23,219,45,59,136,55,245,143,29,165,48,255,131,207,146,131, 104,13,163,54,131,236,78,88,54,16,241,2,33,0,230,2,99,129,173,176,166,131, 241,106,143,76,9,107,70,41,121,185,228,39,124,200,159,62,216,169,5,180,111, 169,255,159,2,33,0,151,193,70,212,209,210,179,219,175,83,165,4,255,81,103,76, 92,39,24,0,222,132,208,3,244,241,10,198,171,54,227,129,2,32,43,250,20,31,16, 189,168,116,225,1,125,132,94,130,118,124,28,56,232,39,69,218,244,33,240,200, 205,9,215,101,35,135,7,7,7,7,7,7,7>>,
+
+ Text = crypto:rc2_cbc_decrypt(Key, IV, Cipher),
+ Cipher = crypto:rc2_cbc_encrypt(Key, IV, Text).
+
+%%
+%%
+des3_cbc(doc) ->
+ "Encrypt and decrypt according to CBC 3DES, and check the result.";
+des3_cbc(suite) ->
+ [];
+des3_cbc(Config) when is_list(Config) ->
+ ?line Key1 = hexstr2bin("0123456789abcdef"),
+ ?line Key2 = hexstr2bin("fedcba9876543210"),
+ ?line Key3 = hexstr2bin("0f2d4b6987a5c3e1"),
+ ?line IVec = hexstr2bin("1234567890abcdef"),
+ ?line Plain = "Now is the time for all ",
+ ?line Cipher = crypto:des3_cbc_encrypt(Key1, Key2, Key3, IVec, Plain),
+ ?line m(Cipher, hexstr2bin("8a2667ee5577267cd9b1af2c5a0480"
+ "0bac1ae66970fb2b89")),
+ ?line m(list_to_binary(Plain),
+ crypto:des3_cbc_decrypt(Key1, Key2, Key3, IVec, Cipher)),
+ ?line Plain2 = "7654321 Now is the time for " ++ [0, 0, 0, 0],
+ ?line Cipher2 = crypto:des3_cbc_encrypt(Key1, Key2, Key3, IVec, Plain2),
+ ?line m(Cipher2, hexstr2bin("eb33ec6ede2c8e90f6877e77b95d5"
+ "4c83cee22907f7f0041ca1b7abe202bfafe")),
+ ?line m(list_to_binary(Plain2),
+ crypto:des3_cbc_decrypt(Key1, Key2, Key3, IVec, Cipher2)),
+
+ ?line Key = hexstr2bin("0123456789abcdef"),
+ ?line DESCipher = crypto:des3_cbc_encrypt(Key, Key, Key, IVec, Plain),
+ ?line m(DESCipher, hexstr2bin("e5c7cdde872bf27c43e934008c389c"
+ "0f683788499a7c05f6")),
+ ?line m(list_to_binary(Plain),
+ crypto:des3_cbc_decrypt(Key, Key, Key, IVec, DESCipher)),
+ ?line DESCipher2 = crypto:des3_cbc_encrypt(Key, Key, Key, IVec, Plain2),
+ ?line m(DESCipher2, hexstr2bin("b9916b8ee4c3da64b4f44e3cbefb9"
+ "9484521388fa59ae67d58d2e77e86062733")),
+ ?line m(list_to_binary(Plain2),
+ crypto:des3_cbc_decrypt(Key, Key, Key, IVec, DESCipher2)).
+
+%%
+%%
+des3_cfb(doc) ->
+ "Encrypt and decrypt according to CFB 3DES, and check the result.";
+des3_cfb(suite) ->
+ [];
+des3_cfb(Config) when is_list(Config) ->
+ case openssl_version() of
+ V when V < 16#90705F -> {skipped,"OpenSSL version too old"};
+ _ -> des3_cfb_do()
+ end.
+
+des3_cfb_do() ->
+ ?line Key1 = hexstr2bin("0123456789abcdef"),
+ ?line Key2 = hexstr2bin("fedcba9876543210"),
+ ?line Key3 = hexstr2bin("0f2d4b6987a5c3e1"),
+ ?line IVec = hexstr2bin("1234567890abcdef"),
+ ?line Plain = "Now is the time for all ",
+ ?line Cipher = crypto:des3_cfb_encrypt(Key1, Key2, Key3, IVec, Plain),
+ ?line m(Cipher, hexstr2bin("fc0ba7a20646ba53cc8bff263f0937"
+ "1deab42a00666db02c")),
+ ?line m(list_to_binary(Plain),
+ crypto:des3_cfb_decrypt(Key1, Key2, Key3, IVec, Cipher)),
+ ?line Plain2 = "7654321 Now is the time for " ++ [0, 0, 0, 0],
+ ?line Cipher2 = crypto:des3_cfb_encrypt(Key1, Key2, Key3, IVec, Plain2),
+ ?line m(Cipher2, hexstr2bin("8582c59ac01897422632c0accb66c"
+ "e413f5efab838fce7e41e2ba67705bad5bc")),
+ ?line m(list_to_binary(Plain2),
+ crypto:des3_cfb_decrypt(Key1, Key2, Key3, IVec, Cipher2)).
+
+%%
+%%
+aes_cfb(doc) ->
+ "Encrypt and decrypt according to AES CFB 128 bit and check "
+ "the result. Example are from NIST SP 800-38A.";
+
+aes_cfb(suite) ->
+ [];
+aes_cfb(Config) when is_list(Config) ->
+
+%% Sample data from NIST Spec.Publ. 800-38A
+%% F.3.13 CFB128-AES128.Encrypt
+%% Key 2b7e151628aed2a6abf7158809cf4f3c
+%% IV 000102030405060708090a0b0c0d0e0f
+%% Segment #1
+%% Input Block 000102030405060708090a0b0c0d0e0f
+%% Output Block 50fe67cc996d32b6da0937e99bafec60
+%% Plaintext 6bc1bee22e409f96e93d7e117393172a
+%% Ciphertext 3b3fd92eb72dad20333449f8e83cfb4a
+%% Segment #2
+%% Input Block 3b3fd92eb72dad20333449f8e83cfb4a
+%% Output Block 668bcf60beb005a35354a201dab36bda
+%% Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
+%% Ciphertext c8a64537a0b3a93fcde3cdad9f1ce58b
+%% Segment #3
+%% Input Block c8a64537a0b3a93fcde3cdad9f1ce58b
+%% Output Block 16bd032100975551547b4de89daea630
+%% Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
+%% Ciphertext 26751f67a3cbb140b1808cf187a4f4df
+%% Segment #4
+%% Input Block 26751f67a3cbb140b1808cf187a4f4df
+%% Output Block 36d42170a312871947ef8714799bc5f6
+%% Plaintext f69f2445df4f9b17ad2b417be66c3710
+%% Ciphertext c04b05357c5d1c0eeac4c66f9ff7f2e6
+
+ ?line Key = hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ ?line IVec = hexstr2bin("000102030405060708090a0b0c0d0e0f"),
+ ?line Plain = hexstr2bin("6bc1bee22e409f96e93d7e117393172a"),
+ ?line Cipher = hexstr2bin("3b3fd92eb72dad20333449f8e83cfb4a"),
+
+ %% Try all prefixes of plain and cipher.
+ aes_cfb_do(byte_size(Plain), Plain, Cipher, Key, IVec).
+
+aes_cfb_do(N, Plain, Cipher, Key, IVec) when N >= 0 ->
+ <<P:N/binary, _/binary>> = Plain,
+ <<C:N/binary, _/binary>> = Cipher,
+ ?line C = crypto:aes_cfb_128_encrypt(Key, IVec, P),
+ ?line P = crypto:aes_cfb_128_decrypt(Key, IVec, C),
+ aes_cfb_do(N-1, Plain, Cipher, Key, IVec);
+aes_cfb_do(_, _, _, _, _) -> ok.
+
+
+%%
+%%
+aes_cbc(doc) ->
+ "Encrypt and decrypt according to AES CBC 128 bit. and check the result. "
+ "Example are from NIST SP 800-38A.";
+
+aes_cbc(suite) ->
+ [];
+aes_cbc(Config) when is_list(Config) ->
+
+%% Sample data from NIST Spec.Publ. 800-38A
+%% F.2.1 CBC-AES128.Encrypt
+%% Key 2b7e151628aed2a6abf7158809cf4f3c
+%% IV 000102030405060708090a0b0c0d0e0f
+%% Block #1
+%% Plaintext 6bc1bee22e409f96e93d7e117393172a
+%% Input Block 6bc0bce12a459991e134741a7f9e1925
+%% Output Block 7649abac8119b246cee98e9b12e9197d
+%% Ciphertext 7649abac8119b246cee98e9b12e9197d
+%% Block #2
+%% Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
+%% Input Block d86421fb9f1a1eda505ee1375746972c
+%% Output Block 5086cb9b507219ee95db113a917678b2
+%% Ciphertext 5086cb9b507219ee95db113a917678b2
+%% Block #3
+%% Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
+%% Input Block 604ed7ddf32efdff7020d0238b7c2a5d
+%% Output Block 73bed6b8e3c1743b7116e69e22229516
+%% Ciphertext 73bed6b8e3c1743b7116e69e22229516
+%% Block #4
+%% Plaintext f69f2445df4f9b17ad2b417be66c3710
+%% Input Block 8521f2fd3c8eef2cdc3da7e5c44ea206
+%% Output Block 3ff1caa1681fac09120eca307586e1a7
+%% Ciphertext 3ff1caa1681fac09120eca307586e1a7
+%%
+%% F.2.2 CBC-AES128.Decrypt
+%% Key 2b7e151628aed2a6abf7158809cf4f3c
+%% IV 000102030405060708090a0b0c0d0e0f
+ %% Block #1
+%% Ciphertext 7649abac8119b246cee98e9b12e9197d
+%% Input Block 7649abac8119b246cee98e9b12e9197d
+%% Output Block 6bc0bce12a459991e134741a7f9e1925
+%% Plaintext 6bc1bee22e409f96e93d7e117393172a
+%% Block #2
+%% Ciphertext 5086cb9b507219ee95db113a917678b2
+%% Input Block 5086cb9b507219ee95db113a917678b2
+%% Output Block d86421fb9f1a1eda505ee1375746972c
+%% Plaintext ae2d8a571e03ac9c9eb76fac45af8e51
+%% Block #3
+%% Ciphertext 73bed6b8e3c1743b7116e69e22229516
+%% Input Block 73bed6b8e3c1743b7116e69e22229516
+%% Output Block 604ed7ddf32efdff7020d0238b7c2a5d
+%% Plaintext 30c81c46a35ce411e5fbc1191a0a52ef
+%% Block #4
+%% Ciphertext 3ff1caa1681fac09120eca307586e1a7
+%% Input Block 3ff1caa1681fac09120eca307586e1a7
+%% Output Block 8521f2fd3c8eef2cdc3da7e5c44ea206
+%% Plaintext f69f2445df4f9b17ad2b417be66c3710
+
+ ?line Key = hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ ?line IVec = hexstr2bin("000102030405060708090a0b0c0d0e0f"),
+ ?line Plain = hexstr2bin("6bc1bee22e409f96e93d7e117393172a"),
+ ?line Cipher = crypto:aes_cbc_128_encrypt(Key, IVec, Plain),
+ ?line m(Cipher, hexstr2bin("7649abac8119b246cee98e9b12e9197d")),
+ ?line m(Plain,
+ crypto:aes_cbc_128_decrypt(Key, IVec, Cipher)).
+
+aes_cbc_iter(doc) ->
+ "Encrypt and decrypt according to CBC AES in steps";
+aes_cbc_iter(suite) -> [];
+aes_cbc_iter(Config) when is_list(Config) ->
+ Key = list_to_binary(lists:seq(255,256-16*17,-17)),
+ IVec = list_to_binary(lists:seq(1,16*7,7)),
+ Plain = <<"One, two, three o'clock, four o'clock, rock"
+ "Five, six, seven o'clock, eight o'clock, rock"
+ "Nine, ten, eleven o'clock, twelve o'clock, rock"
+ "We're gonna rock around the clock tonight">>,
+ ?line 0 = size(Plain) rem 16,
+
+ ?line Cipher = crypto:aes_cbc_128_encrypt(Key, IVec, Plain),
+ ?line Plain = crypto:aes_cbc_128_decrypt(Key, IVec, Cipher),
+
+ ?line Cipher = aes_cbc_encrypt_iter(Key,IVec,Plain,<<>>),
+ ?line Plain = aes_cbc_decrypt_iter(Key,IVec,Cipher,<<>>),
+ ok.
+
+aes_cbc_encrypt_iter(_,_,<<>>, Acc) ->
+ Acc;
+aes_cbc_encrypt_iter(Key,IVec,Data, Acc) ->
+ Bytes = 16 * (1 + size(Data) div (16*3)),
+ <<Chunk:Bytes/binary, Rest/binary>> = Data,
+ %%io:format("encrypt iter Chunk=~p Rest=~p\n",[Chunk,Rest]),
+ ?line Cipher = crypto:aes_cbc_128_encrypt(Key, IVec, Chunk),
+ ?line IVec2 = crypto:aes_cbc_ivec(Cipher),
+ aes_cbc_encrypt_iter(Key,IVec2,Rest, <<Acc/binary, Cipher/binary>>).
+
+aes_cbc_decrypt_iter(_,_,<<>>, Acc) ->
+ Acc;
+aes_cbc_decrypt_iter(Key,IVec,Data, Acc) ->
+ Bytes = 16 * (1 + size(Data) div (16*5)),
+ <<Chunk:Bytes/binary, Rest/binary>> = Data,
+ %%io:format("decrypt iter Chunk=~p Rest=~p\n",[Chunk,Rest]),
+ ?line Plain = crypto:aes_cbc_128_decrypt(Key, IVec, Chunk),
+ ?line IVec2 = crypto:aes_cbc_ivec(Chunk),
+ aes_cbc_decrypt_iter(Key,IVec2,Rest, <<Acc/binary, Plain/binary>>).
+
+
+aes_ctr(doc) -> "CTR";
+aes_ctr(Config) when is_list(Config) ->
+ %% Sample data from NIST Spec.Publ. 800-38A
+ %% F.5.1 CTR-AES128.Encrypt
+ Key128 = hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ Samples128 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
+ "6bc1bee22e409f96e93d7e117393172a", % Plaintext
+ "874d6191b620e3261bef6864990db6ce"},% Ciphertext
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
+ "ae2d8a571e03ac9c9eb76fac45af8e51",
+ "9806f66b7970fdff8617187bb9fffdff"},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
+ "30c81c46a35ce411e5fbc1191a0a52ef",
+ "5ae4df3edbd5d35e5b4f09020db03eab"},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
+ "f69f2445df4f9b17ad2b417be66c3710",
+ "1e031dda2fbe03d1792170a0f3009cee"}],
+ lists:foreach(fun(S) -> aes_ctr_do(Key128,S) end, Samples128),
+
+ %% F.5.3 CTR-AES192.Encrypt
+ Key192 = hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
+ Samples192 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
+ "6bc1bee22e409f96e93d7e117393172a", % Plaintext
+ "1abc932417521ca24f2b0459fe7e6e0b"},% Ciphertext
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
+ "ae2d8a571e03ac9c9eb76fac45af8e51",
+ "090339ec0aa6faefd5ccc2c6f4ce8e94"},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
+ "30c81c46a35ce411e5fbc1191a0a52ef",
+ "1e36b26bd1ebc670d1bd1d665620abf7"},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
+ "f69f2445df4f9b17ad2b417be66c3710",
+ "4f78a7f6d29809585a97daec58c6b050"}],
+ lists:foreach(fun(S) -> aes_ctr_do(Key192,S) end, Samples192),
+
+ %% F.5.5 CTR-AES256.Encrypt
+ Key256 = hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ Samples256 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
+ "6bc1bee22e409f96e93d7e117393172a", % Plaintext
+ "601ec313775789a5b7a7f504bbf3d228"},% Ciphertext
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
+ "ae2d8a571e03ac9c9eb76fac45af8e51",
+ "f443e3ca4d62b59aca84e990cacaf5c5"},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
+ "30c81c46a35ce411e5fbc1191a0a52ef",
+ "2b0930daa23de94ce87017ba2d84988d"},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
+ "f69f2445df4f9b17ad2b417be66c3710",
+ "dfc9c58db67aada613c2dd08457941a6"}],
+ lists:foreach(fun(S) -> aes_ctr_do(Key256,S) end, Samples256).
+
+
+aes_ctr_do(Key,{IVec, Plain, Cipher}) ->
+ ?line I = hexstr2bin(IVec),
+ ?line P = hexstr2bin(Plain),
+ ?line C = crypto:aes_ctr_encrypt(Key, I, P),
+ ?line m(C, hexstr2bin(Cipher)),
+ ?line m(P, crypto:aes_ctr_decrypt(Key, I, C)).
+
+aes_ctr_stream(doc) -> "CTR Streaming";
+aes_ctr_stream(Config) when is_list(Config) ->
+ %% Sample data from NIST Spec.Publ. 800-38A
+ %% F.5.1 CTR-AES128.Encrypt
+ Key128 = hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ Samples128 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
+ ["6bc1bee22e409f", "96e93d7e117393172a"], % Plaintext
+ ["874d6191b620e3261bef6864990db6ce"]}, % Ciphertext
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
+ ["ae2d8a57", "1e03ac9c", "9eb76fac", "45af8e51"],
+ ["9806f66b7970fdff","8617187bb9fffdff"]},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
+ ["30c81c46a35c", "e411e5fbc119", "1a0a52ef"],
+ ["5ae4df3e","dbd5d3","5e5b4f0902","0db03eab"]},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
+ ["f69f2445df4f9b17ad2b417be66c3710"],
+ ["1e031dda2fbe","03d1792170a0","f3009cee"]}],
+ lists:foreach(fun(S) -> aes_ctr_stream_do(Key128,S) end, Samples128),
+
+ %% F.5.3 CTR-AES192.Encrypt
+ Key192 = hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
+ Samples192 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
+ ["6bc1bee22e409f96e93d7e117393172a"], % Plaintext
+ ["1abc9324","17521c","a24f2b04","59fe7e6e0b"]}, % Ciphertext
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
+ ["ae2d8a57", "1e03ac9c9eb76fac", "45af8e51"],
+ ["090339ec0aa6faefd5ccc2c6f4ce8e94"]},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
+ ["30c81c46a35ce411", "e5fbc1191a0a52ef"],
+ ["1e36b26bd1","ebc670d1bd1d","665620abf7"]},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
+ ["f69f2445", "df4f9b17ad", "2b417be6", "6c3710"],
+ ["4f78a7f6d2980958","5a97daec58c6b050"]}],
+ lists:foreach(fun(S) -> aes_ctr_stream_do(Key192,S) end, Samples192),
+
+ %% F.5.5 CTR-AES256.Encrypt
+ Key256 = hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ Samples256 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block
+ ["6bc1bee22e409f96", "e93d7e117393172a"], % Plaintext
+ ["601ec313775789", "a5b7a7f504bbf3d228"]}, % Ciphertext
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00",
+ ["ae2d8a571e03ac9c9eb76fac45af8e51"],
+ ["f443e3ca","4d62b59aca84","e990cacaf5c5"]},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01",
+ ["30c81c46","a35ce411","e5fbc119","1a0a52ef"],
+ ["2b0930daa23de94ce87017ba2d84988d"]},
+ {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02",
+ ["f69f2445df4f","9b17ad2b41","7be66c3710"],
+ ["dfc9c5","8db67aada6","13c2dd08","457941a6"]}],
+ lists:foreach(fun(S) -> aes_ctr_stream_do(Key256,S) end, Samples256).
+
+
+aes_ctr_stream_do(Key,{IVec, PlainList, CipherList}) ->
+ ?line I = hexstr2bin(IVec),
+ ?line S = crypto:aes_ctr_stream_init(Key, I),
+ ?line C = aes_ctr_stream_do_iter(
+ S, PlainList, [],
+ fun(S2,P) -> crypto:aes_ctr_stream_encrypt(S2, P) end),
+ ?line m(C, hexstr2bin(lists:flatten(CipherList))),
+ ?line P = aes_ctr_stream_do_iter(
+ S, CipherList, [],
+ fun(S2,C2) -> crypto:aes_ctr_stream_decrypt(S2, C2) end),
+ ?line m(P, hexstr2bin(lists:flatten(PlainList))).
+
+aes_ctr_stream_do_iter(_State, [], Acc, _CipherFun) ->
+ iolist_to_binary(lists:reverse(Acc));
+aes_ctr_stream_do_iter(State, [Plain|Rest], Acc, CipherFun) ->
+ ?line P = hexstr2bin(Plain),
+ ?line {S2, C} = CipherFun(State, P),
+ aes_ctr_stream_do_iter(S2, Rest, [C | Acc], CipherFun).
+
+%%
+%%
+mod_exp_test(doc) ->
+ "mod_exp testing (A ^ M % P with bignums)";
+mod_exp_test(suite) ->
+ [];
+mod_exp_test(Config) when is_list(Config) ->
+ mod_exp_aux_test(2, 5, 10, 8).
+
+mod_exp_aux_test(_, _, _, 0) ->
+ ok;
+mod_exp_aux_test(B, E, M, N) ->
+ ?line R1 = crypto:mod_exp(B, E, M),
+ ?line R2 = ipow(B, E, M),
+ ?line m(R1, R2),
+ ?line mod_exp_aux_test(B, E*E+1, M*M+1, N-1).
+
+%%
+%%
+rand_uniform_test(doc) ->
+ "rand_uniform and random_bytes testing";
+rand_uniform_test(suite) ->
+ [];
+rand_uniform_test(Config) when is_list(Config) ->
+ rand_uniform_aux_test(10),
+ ?line 10 = size(crypto:rand_bytes(10)).
+
+rand_uniform_aux_test(0) ->
+ ok;
+rand_uniform_aux_test(N) ->
+ ?line L = N*1000,
+ ?line H = N*100000+1,
+ ?line crypto_rand_uniform(L, H),
+ ?line crypto_rand_uniform(-L, L),
+ ?line crypto_rand_uniform(-H, -L),
+ ?line crypto_rand_uniform(-H, L),
+ ?line rand_uniform_aux_test(N-1).
+
+crypto_rand_uniform(L,H) ->
+ ?line R1 = crypto:rand_uniform(L, H),
+ ?line t(R1 >= L),
+ ?line t(R1 < H).
+
+
+%%
+%%
+strong_rand_test(doc) ->
+ "strong_rand_mpint and strong_random_bytes testing";
+strong_rand_test(suite) ->
+ [];
+strong_rand_test(Config) when is_list(Config) ->
+ strong_rand_aux_test(180),
+ ?line 10 = byte_size(crypto:strong_rand_bytes(10)).
+
+strong_rand_aux_test(0) ->
+ ?line t(crypto:strong_rand_mpint(0,0,0) =:= <<0,0,0,0>>),
+ ok;
+strong_rand_aux_test(1) ->
+ ?line t(crypto:erlint(crypto:strong_rand_mpint(1,0,1)) =:= 1),
+ ?line strong_rand_aux_test(0);
+strong_rand_aux_test(N) ->
+ ?line t(sru_length(crypto:strong_rand_mpint(N,-1,0)) =< N),
+ ?line t(sru_length(crypto:strong_rand_mpint(N,0,0)) =:= N),
+ ?line t(crypto:erlint(crypto:strong_rand_mpint(N,0,1)) band 1 =:= 1),
+ ?line t(crypto:erlint(crypto:strong_rand_mpint(N,1,0)) bsr (N - 2) =:= 2#11),
+ ?line strong_rand_aux_test(N-1).
+
+sru_length(Mpint) ->
+ I = crypto:erlint(Mpint),
+ length(erlang:integer_to_list(I, 2)).
+
+%%
+%%
+%%
+%%
+rsa_verify_test(doc) ->
+ "rsa_verify testing (A ^ M % P with bignums)";
+rsa_verify_test(suite) ->
+ [];
+rsa_verify_test(Config) when is_list(Config) ->
+ ?line H = <<178,28,54,104,36,80,144,66,140,201,135,17,36,97,114,124,
+ 194,164,172,147>>,
+ ?line SigBlob = <<153,44,121,71,132,1,192,159,78,33,29,62,153,64,191,70,
+ 208,239,166,208,220,167,49,111,128,67,91,253,24,63,194,241,
+ 97,157,135,226,121,162,150,156,60,49,236,90,151,67,239,23,
+ 92,103,89,254,17,165,78,181,64,128,13,210,86,111,209,76,
+ 115,34,107,227,151,47,80,185,143,85,202,55,245,163,226,26,
+ 139,104,196,6,96,82,108,197,13,0,12,70,153,109,107,180,
+ 130,246,156,182,56,96,31,220,227,218,136,211,252,43,8,14,
+ 145,155,191,206,72,194,80,52,54,206,53,27,6,188,195,29>>,
+ ?line BadSigBlob = <<153,44,121,71,132,1,192,159,78,33,29,62,153,64,191,70,
+ 208,239,166,208,220,167,49,111,128,67,91,253,24,63,194,241,
+ 97,157,135,226,121,162,150,156,60,49,236,90,151,67,239,23,
+ 92,103,89,254,17,165,78,181,64,128,13,210,86,111,209,76,
+ 115,107,34,227,151,47,80,185,143,85,202,55,245,163,226,26,
+ 139,104,196,6,96,82,108,197,13,0,12,70,153,109,107,180,
+ 130,246,156,182,56,96,31,220,227,218,136,211,252,43,8,14,
+ 145,155,191,206,72,194,80,52,54,206,53,27,6,188,195,29>>,
+ ?line E = <<35>>,
+ ?line N = <<0,199,209,142,191,86,92,148,103,37,250,217,175,169,109,10,
+ 130,139,34,237,174,90,97,118,7,185,57,137,252,236,177,193,
+ 228,16,62,29,153,144,64,207,152,240,152,206,136,89,64,6,
+ 3,187,89,57,241,219,88,215,75,70,120,20,145,229,37,1,
+ 67,138,204,17,39,231,249,239,116,142,169,99,149,41,65,123,
+ 26,225,133,0,41,85,77,181,35,100,162,223,92,220,207,50,
+ 63,168,193,171,174,199,23,214,201,63,157,76,125,6,54,73,
+ 76,89,40,33,147,208,189,76,98,24,61,8,10,110,165,119,165>>,
+ ?line Nbad = <<0,199,209,142,191,86,92,148,103,37,250,217,175,169,109,10,
+ 130,139,34,237,174,90,97,118,7,185,57,137,252,236,177,193,
+ 228,16,62,29,153,144,64,207,152,240,152,206,136,89,64,6,
+ 3,187,89,57,241,219,88,215,75,70,120,20,145,229,37,1,
+ 67,138,204,17,39,231,249,239,116,142,169,99,149,41,65,123,
+ 26,225,133,0,41,85,77,181,35,100,162,223,92,220,207,50,
+ 63,168,193,171,174,199,23,214,201,63,157,76,125,6,54,73,
+ 76,89,40,33,147,189,208,76,98,24,61,8,10,110,165,119,165>>,
+ ?line Ebad = <<77>>,
+ ?line m(crypto:rsa_verify(sized_binary(H), sized_binary(SigBlob),
+ [sized_binary(E), sized_binary(N)]), true),
+ ?line m(crypto:rsa_verify(sized_binary(H), sized_binary(SigBlob),
+ [sized_binary(Ebad), sized_binary(N)]), false),
+ ?line m(crypto:rsa_verify(sized_binary(H), sized_binary(SigBlob),
+ [sized_binary(E), sized_binary(Nbad)]), false),
+ ?line m(crypto:rsa_verify(sized_binary(H), sized_binary(BadSigBlob),
+ [sized_binary(E), sized_binary(N)]), false).
+
+%%
+%%
+dsa_verify_test(doc) ->
+ "dsa_verify testing (A ^ M % P with bignums)";
+dsa_verify_test(suite) ->
+ [];
+dsa_verify_test(Config) when is_list(Config) ->
+ ?line Msg = <<48,130,2,245,160,3,2,1,2,2,1,1,48,9,6,7,42,134,72,206,56,4,3,48,
+ 58,49,11,48,9,6,3,85,4,6,19,2,85,83,49,26,48,24,6,3,85,4,10,19,17,
+ 84,101,115,116,32,67,101,114,116,105,102,105,99,97,116,101,115,49,
+ 15,48,13,6,3,85,4,3,19,6,68,83,65,32,67,65,48,30,23,13,48,49,48,
+ 52,49,57,49,52,53,55,50,48,90,23,13,49,49,48,52,49,57,49,52,53,55,
+ 50,48,90,48,93,49,11,48,9,6,3,85,4,6,19,2,85,83,49,26,48,24,6,3,
+ 85,4,10,19,17,84,101,115,116,32,67,101,114,116,105,102,105,99,97,
+ 116,101,115,49,50,48,48,6,3,85,4,3,19,41,86,97,108,105,100,32,68,
+ 83,65,32,83,105,103,110,97,116,117,114,101,115,32,69,69,32,67,101,
+ 114,116,105,102,105,99,97,116,101,32,84,101,115,116,52,48,130,1,
+ 182,48,130,1,43,6,7,42,134,72,206,56,4,1,48,130,1,30,2,129,129,0,
+ 228,139,175,64,140,21,215,61,124,238,3,150,18,104,193,32,5,232,23,
+ 202,158,116,101,75,154,84,151,42,120,51,218,165,197,114,234,52,
+ 179,148,104,66,213,27,253,119,240,168,66,158,100,147,144,182,194,
+ 2,49,70,19,122,3,105,204,152,45,86,157,94,35,95,40,191,173,127,15,
+ 208,105,149,98,92,26,7,42,94,140,115,73,126,253,18,34,142,85,229,
+ 86,233,174,114,41,150,135,8,39,215,119,67,240,134,184,9,10,27,20,
+ 165,230,3,230,69,121,77,233,250,83,95,193,9,189,126,197,195,2,21,
+ 0,128,63,228,252,243,76,229,62,203,15,23,10,42,84,108,208,103,108,
+ 13,59,2,129,128,102,212,22,138,32,173,254,209,50,159,165,127,167,
+ 179,208,234,119,63,235,108,162,228,41,216,216,188,33,221,154,247,
+ 204,229,180,119,77,223,236,218,162,140,156,117,18,90,31,254,102,
+ 211,17,194,239,132,67,236,169,136,110,76,186,76,63,53,150,199,103,
+ 252,153,189,15,153,41,19,145,78,216,2,174,254,107,175,80,86,170,
+ 47,30,181,42,200,238,34,71,37,120,107,33,221,20,63,206,240,16,129,
+ 247,150,29,156,65,187,94,68,146,93,46,198,30,184,205,105,200,143,
+ 63,59,62,208,79,162,206,217,3,129,132,0,2,129,128,15,83,40,172,56,
+ 47,61,243,17,97,65,195,61,167,214,122,247,246,1,50,211,33,113,16,
+ 20,213,195,62,77,235,25,162,140,175,158,8,61,65,10,255,204,162,71,
+ 130,122,86,161,163,253,236,178,139,183,57,181,202,160,25,133,130,
+ 155,150,104,168,187,107,186,144,164,225,173,101,182,68,49,210,30,
+ 34,47,83,65,79,250,156,248,47,232,44,67,36,22,126,43,216,100,247,
+ 100,250,240,121,72,29,185,2,109,144,54,204,235,54,15,242,57,171,
+ 125,39,236,247,71,111,221,51,196,126,77,238,36,87,163,107,48,105,
+ 48,29,6,3,85,29,14,4,22,4,20,179,51,215,81,162,4,13,68,251,157,64,
+ 241,18,98,113,176,83,246,105,13,48,31,6,3,85,29,35,4,24,48,22,128,
+ 20,116,21,213,36,28,189,94,101,136,31,225,139,9,126,127,234,25,72,
+ 78,97,48,23,6,3,85,29,32,4,16,48,14,48,12,6,10,96,134,72,1,101,3,
+ 2,1,48,1,48,14,6,3,85,29,15,1,1,255,4,4,3,2,6,192>>,
+
+ ?line SigBlob = <<48,45,2,21,0,140,167,200,210,153,212,64,155,249,33,146,104,243,
+ 39,38,9,115,162,89,24,2,20,76,254,31,128,187,48,128,215,216,
+ 112,198,78,118,160,217,157,180,246,64,234>>,
+ ?line P_p = 157224271412839155721795253728878055347359513988016145491388196653004661857517720927482198111104095793441029858267073789634147217022008635826863307553453131345099940951090826856271796188522037524757740796268675508118348391218066949174594918958269259937813776150149068811425194955973128428675945283593831134219,
+ ?line Q_p = 1181895316321540581845959276009400765315408342791,
+ ?line G_p = 143872196713149000950547166575757355261637863805587906227228163275557375159769599033632918292482002186641475268486598023281100659643528846513898847919251032731261718358900479488287933293278745715922865499005559197328388506945134386346185262919258658109015074718441639029135304654725637911172671711310801418648,
+
+ ?line Key = 12603618348903387232593303690286336220738319446775939686476278478034365380027994899970214309288018488811754534229198764622077544117034174589418477472887827980332636062691833965078594576024299807057520016043084384987871640003684704483975314128362610573625803532737054022545217931847268776098203204571431581966,
+
+ ValidKey = [crypto:mpint(P_p),
+ crypto:mpint(Q_p),
+ crypto:mpint(G_p),
+ crypto:mpint(Key)
+ ],
+
+ ?line m(my_dss_verify(sized_binary(Msg), sized_binary(SigBlob),
+ ValidKey), true),
+
+ BadMsg = one_bit_wrong(Msg),
+ ?line m(my_dss_verify(sized_binary(BadMsg), sized_binary(SigBlob),
+ ValidKey), false),
+ BadSig = one_bit_wrong(SigBlob),
+ ?line m(my_dss_verify(sized_binary(Msg), sized_binary(BadSig),
+ ValidKey), false),
+ SizeErr = size(SigBlob) - 13,
+
+ BadArg = (catch my_dss_verify(sized_binary(Msg), <<SizeErr:32, SigBlob/binary>>,
+ ValidKey)),
+ badarg = case element(1,element(2,BadArg)) of
+ badarg -> badarg;
+ function_clause -> badarg;
+ X -> X
+ end,
+ InValidKey = [crypto:mpint(P_p),
+ crypto:mpint(Q_p),
+ crypto:mpint(G_p),
+ crypto:mpint(Key+17)
+ ],
+
+ ?line m(my_dss_verify(sized_binary(Msg), sized_binary(SigBlob),
+ InValidKey), false).
+
+
+one_bit_wrong(List) when is_list(List) ->
+ lists:map(fun(Bin) -> one_bit_wrong(Bin) end, List);
+one_bit_wrong(Bin) ->
+ Half = size(Bin) div 2,
+ <<First:Half/binary, Byte:8, Last/binary>> = Bin,
+ <<First/binary, (Byte+1):8, Last/binary>>.
+
+
+%%
+%% Sign tests
+
+rsa_sign_test(doc) ->
+ "rsa_sign testing";
+rsa_sign_test(suite) ->
+ [];
+rsa_sign_test(Config) when is_list(Config) ->
+ PubEx = 65537,
+ PrivEx = 7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945,
+ Mod = 7919488123861148172698919999061127847747888703039837999377650217570191053151807772962118671509138346758471459464133273114654252861270845708312601272799123,
+ Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
+ "09812312908312378623487263487623412039812 huagasd">>,
+
+ PrivKey = [PubEx, Mod, PrivEx],
+ PubKey = [PubEx, Mod],
+ PubKeyMpint = map_int_to_mpint(PubKey),
+ Sig1 = crypto:rsa_sign(sized_binary(Msg), map_int_to_mpint(PrivKey)),
+ Sig1 = crypto:sign(rsa, sha, Msg, PrivKey),
+ true = crypto:rsa_verify(sized_binary(Msg), sized_binary(Sig1), PubKeyMpint),
+ true = crypto:verify(rsa, sha, Msg, Sig1, PubKey),
+
+ Sig2 = crypto:rsa_sign(md5, sized_binary(Msg), map_int_to_mpint(PrivKey)),
+ Sig2 = crypto:sign(rsa, md5, Msg, PrivKey),
+ true = crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig2), PubKeyMpint),
+ true = crypto:verify(rsa, md5, Msg, Sig2, PubKey),
+
+ false = (Sig1 =:= Sig2),
+ false = crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig1), PubKeyMpint),
+ false = crypto:verify(rsa, md5, Msg, Sig1, PubKey),
+ true = crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig1), PubKeyMpint),
+ true = crypto:verify(rsa, sha, Msg, Sig1, PubKey),
+
+ ok.
+map_int_to_mpint(List) ->
+ lists:map(fun(E) -> crypto:mpint(E) end, List).
+
+rsa_sign_hash_test(doc) ->
+ "rsa_sign_hash testing";
+rsa_sign_hash_test(suite) ->
+ [];
+rsa_sign_hash_test(Config) when is_list(Config) ->
+ PubEx = 65537,
+ PrivEx = 7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945,
+ Mod = 7919488123861148172698919999061127847747888703039837999377650217570191053151807772962118671509138346758471459464133273114654252861270845708312601272799123,
+ Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
+ "09812312908312378623487263487623412039812 huagasd">>,
+
+ PrivKey = [crypto:mpint(PubEx), crypto:mpint(Mod), crypto:mpint(PrivEx)],
+ PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)],
+ MD5 = crypto:md5(sized_binary(Msg)),
+ SHA = crypto:sha(sized_binary(Msg)),
+ ?line Sig1 = crypto:rsa_sign(sha, {digest,SHA}, PrivKey),
+ ?line m(crypto:rsa_verify(sha, {digest,SHA}, sized_binary(Sig1),PubKey), true),
+
+ ?line Sig2 = crypto:rsa_sign(md5, {digest,MD5}, PrivKey),
+ ?line m(crypto:rsa_verify(md5, {digest,MD5}, sized_binary(Sig2),PubKey), true),
+
+ ?line m(Sig1 =:= Sig2, false),
+ ?line m(crypto:rsa_verify(md5, {digest,MD5}, sized_binary(Sig1),PubKey), false),
+ ?line m(crypto:rsa_verify(sha, {digest,SHA}, sized_binary(Sig2),PubKey), false),
+
+ ok.
+
+dsa_sign_test(doc) ->
+ "dsa_sign testing";
+dsa_sign_test(suite) ->
+ [];
+dsa_sign_test(Config) when is_list(Config) ->
+ Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
+ "09812312908312378623487263487623412039812 huagasd">>,
+
+ PubKey = _Y = 25854665488880835237281628794585130313500176551981812527054397586638455298000483144002221850980183404910190346416063318160497344811383498859129095184158800144312512447497510551471331451396405348497845813002058423110442376886564659959543650802132345311573634832461635601376738282831340827591903548964194832978,
+ PrivKey = _X = 441502407453038284293378221372000880210588566361,
+ ParamP = 109799869232806890760655301608454668257695818999841877165019612946154359052535682480084145133201304812979481136659521529774182959764860329095546511521488413513097576425638476458000255392402120367876345280670101492199681798674053929238558140260669578407351853803102625390950534052428162468100618240968893110797,
+ ParamQ = 1349199015905534965792122312016505075413456283393,
+ ParamG = 18320614775012672475365915366944922415598782131828709277168615511695849821411624805195787607930033958243224786899641459701930253094446221381818858674389863050420226114787005820357372837321561754462061849169568607689530279303056075793886577588606958623645901271866346406773590024901668622321064384483571751669,
+
+ Params = [crypto:mpint(ParamP), crypto:mpint(ParamQ), crypto:mpint(ParamG)],
+ ?line Sig1 = my_dss_sign(sized_binary(Msg), Params ++ [crypto:mpint(PrivKey)]),
+
+ ?line m(my_dss_verify(sized_binary(Msg), Sig1,
+ Params ++ [crypto:mpint(PubKey)]), true),
+
+ ?line m(my_dss_verify(sized_binary(one_bit_wrong(Msg)), Sig1,
+ Params ++ [crypto:mpint(PubKey)]), false),
+
+ ?line m(my_dss_verify(sized_binary(Msg), one_bit_wrong(Sig1),
+ Params ++ [crypto:mpint(PubKey)]), false),
+
+ %%?line Bad = crypto:dss_sign(sized_binary(Msg), [Params, crypto:mpint(PubKey)]),
+
+ ok.
+
+dsa_sign_hash_test(doc) ->
+ "dsa_sign_hash testing";
+dsa_sign_hash_test(suite) ->
+ [];
+dsa_sign_hash_test(Config) when is_list(Config) ->
+ Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
+ "09812312908312378623487263487623412039812 huagasd">>,
+ SHA = crypto:sha(sized_binary(Msg)),
+
+ PubKey = _Y = 25854665488880835237281628794585130313500176551981812527054397586638455298000483144002221850980183404910190346416063318160497344811383498859129095184158800144312512447497510551471331451396405348497845813002058423110442376886564659959543650802132345311573634832461635601376738282831340827591903548964194832978,
+ PrivKey = _X = 441502407453038284293378221372000880210588566361,
+ ParamP = 109799869232806890760655301608454668257695818999841877165019612946154359052535682480084145133201304812979481136659521529774182959764860329095546511521488413513097576425638476458000255392402120367876345280670101492199681798674053929238558140260669578407351853803102625390950534052428162468100618240968893110797,
+ ParamQ = 1349199015905534965792122312016505075413456283393,
+ ParamG = 18320614775012672475365915366944922415598782131828709277168615511695849821411624805195787607930033958243224786899641459701930253094446221381818858674389863050420226114787005820357372837321561754462061849169568607689530279303056075793886577588606958623645901271866346406773590024901668622321064384483571751669,
+
+ Params = [crypto:mpint(ParamP), crypto:mpint(ParamQ), crypto:mpint(ParamG)],
+ ?line Sig1 = crypto:dss_sign(sha, {digest,SHA}, Params ++ [crypto:mpint(PrivKey)]),
+
+ ?line m(crypto:dss_verify(none, SHA, sized_binary(Sig1),
+ Params ++ [crypto:mpint(PubKey)]), true),
+
+ ?line m(crypto:dss_verify(sized_binary(one_bit_wrong(Msg)), sized_binary(Sig1),
+ Params ++ [crypto:mpint(PubKey)]), false),
+
+ ?line m(crypto:dss_verify(sized_binary(Msg), sized_binary(one_bit_wrong(Sig1)),
+ Params ++ [crypto:mpint(PubKey)]), false),
+
+ %%?line Bad = crypto:dss_sign(sized_binary(Msg), [Params, crypto:mpint(PubKey)]),
+
+ ok.
+
+
+rsa_encrypt_decrypt(doc) ->
+ ["Test rsa_public_encrypt and rsa_private_decrypt functions."];
+rsa_encrypt_decrypt(suite) -> [];
+rsa_encrypt_decrypt(Config) when is_list(Config) ->
+ PubEx = 65537,
+ PrivEx = 7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945,
+ Mod = 7919488123861148172698919999061127847747888703039837999377650217570191053151807772962118671509138346758471459464133273114654252861270845708312601272799123,
+
+ PrivKey = [PubEx, Mod, PrivEx],
+ PubKey = [PubEx, Mod],
+
+ Msg = <<"7896345786348 Asldi">>,
+
+ ?line PKCS1 = rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_padding),
+ ?line PKCS1Dec = rsa_private_decrypt(PKCS1, PrivKey, rsa_pkcs1_padding),
+ io:format("PKCS1Dec ~p~n",[PKCS1Dec]),
+ ?line Msg = PKCS1Dec,
+
+ ?line OAEP = rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_oaep_padding),
+ ?line Msg = rsa_private_decrypt(OAEP, PrivKey, rsa_pkcs1_oaep_padding),
+
+ <<Msg2Len:32,_/binary>> = crypto:mpint(Mod),
+ Msg2 = list_to_binary(lists:duplicate(Msg2Len-1, $X)),
+ ?line NoPad = rsa_public_encrypt(Msg2, PubKey, rsa_no_padding),
+ ?line NoPadDec = rsa_private_decrypt(NoPad, PrivKey, rsa_no_padding),
+ ?line NoPadDec = Msg2,
+
+ ShouldBeError = (catch rsa_public_encrypt(Msg, PubKey, rsa_no_padding)),
+ ?line {'EXIT', {encrypt_failed,_}} = ShouldBeError,
+
+%% ?line SSL = rsa_public_encrypt(Msg, PubKey, rsa_sslv23_padding),
+%% ?line Msg = rsa_private_decrypt(SSL, PrivKey, rsa_sslv23_padding),
+
+ ?line PKCS1_2 = rsa_private_encrypt(Msg, PrivKey, rsa_pkcs1_padding),
+ ?line PKCS1_2Dec = rsa_public_decrypt(PKCS1_2, PubKey, rsa_pkcs1_padding),
+ io:format("PKCS2Dec ~p~n",[PKCS1_2Dec]),
+ ?line Msg = PKCS1_2Dec,
+
+ ?line PKCS1_3 = rsa_private_encrypt(Msg2, PrivKey, rsa_no_padding),
+ ?line PKCS1_3Dec = rsa_public_decrypt(PKCS1_3, PubKey, rsa_no_padding),
+ io:format("PKCS2Dec ~p~n",[PKCS1_3Dec]),
+ ?line Msg2 = PKCS1_3Dec,
+
+ ?line {'EXIT', {encrypt_failed,_}} =
+ (catch rsa_private_encrypt(Msg, PrivKey, rsa_no_padding)),
+
+ ok.
+
+rsa_public_encrypt(Msg, Key, Pad) ->
+ C1 = crypto:rsa_public_encrypt(Msg, Key, Pad),
+ C2 = crypto:rsa_public_encrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad),
+ {C1,C2}.
+
+rsa_public_decrypt(Msg, Key, Pad) ->
+ R = crypto:rsa_public_decrypt(Msg, Key, Pad),
+ R = crypto:rsa_public_decrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad).
+
+rsa_private_encrypt(Msg, Key, Pad) ->
+ R = crypto:rsa_private_encrypt(Msg, Key, Pad),
+ R = crypto:rsa_private_encrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad).
+
+rsa_private_decrypt({C1,C2}, Key, Pad) ->
+ R = crypto:rsa_private_decrypt(C1, Key, Pad),
+ R = crypto:rsa_private_decrypt(C2, Key, Pad),
+ R = crypto:rsa_private_decrypt(C1, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad),
+ R = crypto:rsa_private_decrypt(C2, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad).
+
+
+dh(doc) ->
+ ["Test dh (Diffie-Hellman) functions."];
+dh(suite) -> [];
+dh(Config) when is_list(Config) ->
+ Self = self(),
+ GenP = fun() ->
+ %% Gen Param may take arbitrary long time to finish
+ %% That's not a bug in erlang crypto application.
+ ?line DHPs = crypto:dh_generate_parameters(512,2),
+ ?line ok = crypto:dh_check(DHPs),
+ Self ! {param, DHPs}
+ end,
+ Pid = spawn(GenP),
+ receive
+ {param, DHPs} ->
+ timer:sleep(100),
+ io:format("DHP ~p~n", [DHPs]),
+ DHPs_mpint = lists:map(fun(E) -> sized_binary(E) end, DHPs),
+ ?line {Pub1,Priv1} = crypto:generate_key(dh, DHPs),
+ io:format("Key1:~n~p~n~p~n~n", [Pub1,Priv1]),
+ ?line {Pub2,Priv2} = crypto:dh_generate_key(DHPs_mpint),
+ io:format("Key2:~n~p~n~p~n~n", [Pub2,Priv2]),
+ ?line A = crypto:compute_key(dh, Pub1, unsized_binary(Priv2), DHPs),
+ ?line A = crypto:dh_compute_key(sized_binary(Pub1), Priv2, DHPs_mpint),
+ timer:sleep(100), %% Get another thread see if that triggers problem
+ ?line B = crypto:compute_key(dh, unsized_binary(Pub2), Priv1, DHPs),
+ ?line B = crypto:dh_compute_key(Pub2, sized_binary(Priv1), DHPs_mpint),
+ io:format("A ~p~n",[A]),
+ io:format("B ~p~n",[B]),
+ ?line A = B
+ after 50000 ->
+ io:format("Killing Param generation which took to long ~p~n",[Pid]),
+ exit(Pid, kill)
+ end.
+
+
+ec(doc) ->
+ ["Test ec (Ecliptic Curve) functions."];
+ec(suite) -> [];
+ec(Config) when is_list(Config) ->
+ if_supported(ecdh, fun() -> ec_do() end).
+
+ec_do() ->
+ %% test for a name curve
+ {D2_pub, D2_priv} = crypto:generate_key(ecdh, sect113r2),
+ PrivECDH = [D2_priv, sect113r2],
+ PubECDH = [D2_pub, sect113r2],
+ %%TODO: find a published test case for a EC key
+
+ %% test for a full specified curve and public key,
+ %% taken from csca-germany_013_self_signed_cer.pem
+ PubKey = <<16#04, 16#4a, 16#94, 16#49, 16#81, 16#77, 16#9d, 16#df,
+ 16#1d, 16#a5, 16#e7, 16#c5, 16#27, 16#e2, 16#7d, 16#24,
+ 16#71, 16#a9, 16#28, 16#eb, 16#4d, 16#7b, 16#67, 16#75,
+ 16#ae, 16#09, 16#0a, 16#51, 16#45, 16#19, 16#9b, 16#d4,
+ 16#7e, 16#a0, 16#81, 16#e5, 16#5e, 16#d4, 16#a4, 16#3f,
+ 16#60, 16#7c, 16#6a, 16#50, 16#ee, 16#36, 16#41, 16#8a,
+ 16#87, 16#ff, 16#cd, 16#a6, 16#10, 16#39, 16#ca, 16#95,
+ 16#76, 16#7d, 16#ae, 16#ca, 16#c3, 16#44, 16#3f, 16#e3, 16#2c>>,
+ <<P:264/integer>> = <<16#00, 16#a9, 16#fb, 16#57, 16#db, 16#a1, 16#ee, 16#a9,
+ 16#bc, 16#3e, 16#66, 16#0a, 16#90, 16#9d, 16#83, 16#8d,
+ 16#72, 16#6e, 16#3b, 16#f6, 16#23, 16#d5, 16#26, 16#20,
+ 16#28, 16#20, 16#13, 16#48, 16#1d, 16#1f, 16#6e, 16#53, 16#77>>,
+ <<A:256/integer>> = <<16#7d, 16#5a, 16#09, 16#75, 16#fc, 16#2c, 16#30, 16#57,
+ 16#ee, 16#f6, 16#75, 16#30, 16#41, 16#7a, 16#ff, 16#e7,
+ 16#fb, 16#80, 16#55, 16#c1, 16#26, 16#dc, 16#5c, 16#6c,
+ 16#e9, 16#4a, 16#4b, 16#44, 16#f3, 16#30, 16#b5, 16#d9>>,
+ <<B:256/integer>> = <<16#26, 16#dc, 16#5c, 16#6c, 16#e9, 16#4a, 16#4b, 16#44,
+ 16#f3, 16#30, 16#b5, 16#d9, 16#bb, 16#d7, 16#7c, 16#bf,
+ 16#95, 16#84, 16#16, 16#29, 16#5c, 16#f7, 16#e1, 16#ce,
+ 16#6b, 16#cc, 16#dc, 16#18, 16#ff, 16#8c, 16#07, 16#b6>>,
+ BasePoint = <<16#04, 16#8b, 16#d2, 16#ae, 16#b9, 16#cb, 16#7e, 16#57,
+ 16#cb, 16#2c, 16#4b, 16#48, 16#2f, 16#fc, 16#81, 16#b7,
+ 16#af, 16#b9, 16#de, 16#27, 16#e1, 16#e3, 16#bd, 16#23,
+ 16#c2, 16#3a, 16#44, 16#53, 16#bd, 16#9a, 16#ce, 16#32,
+ 16#62, 16#54, 16#7e, 16#f8, 16#35, 16#c3, 16#da, 16#c4,
+ 16#fd, 16#97, 16#f8, 16#46, 16#1a, 16#14, 16#61, 16#1d,
+ 16#c9, 16#c2, 16#77, 16#45, 16#13, 16#2d, 16#ed, 16#8e,
+ 16#54, 16#5c, 16#1d, 16#54, 16#c7, 16#2f, 16#04, 16#69, 16#97>>,
+ <<Order:264/integer>> = <<16#00, 16#a9, 16#fb, 16#57, 16#db, 16#a1, 16#ee, 16#a9,
+ 16#bc, 16#3e, 16#66, 16#0a, 16#90, 16#9d, 16#83, 16#8d,
+ 16#71, 16#8c, 16#39, 16#7a, 16#a3, 16#b5, 16#61, 16#a6,
+ 16#f7, 16#90, 16#1e, 16#0e, 16#82, 16#97, 16#48, 16#56, 16#a7>>,
+ CoFactor = 1,
+ Curve = {{prime_field,P},{A,B,none},BasePoint, Order,CoFactor},
+
+ Msg = <<99,234,6,64,190,237,201,99,80,248,58,40,70,45,149,218,5,246,242,63>>,
+ Sign = crypto:sign(ecdsa, sha, Msg, PrivECDH),
+ ?line true = crypto:verify(ecdsa, sha, Msg, Sign, PubECDH),
+ ?line false = crypto:verify(ecdsa, sha, Msg, <<10,20>>, PubECDH),
+
+ ok.
+
+srp3(doc) ->
+ ["SRP-3 test vectors generated by http://srp.stanford.edu/demo/demo.html"];
+srp3(suite) -> [];
+srp3(Config) when is_list(Config) ->
+ Username = <<"alice">>,
+ Password = <<"password123">>,
+ Salt = hexstr2bin("2857827A19266A1F2BC6"),
+ Prime = hexstr2bin("EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C"
+ "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4"
+ "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29"
+ "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A"
+ "FD5138FE8376435B9FC61D2FC0EB06E3"),
+ Generator = <<2>>,
+ Version = '3',
+ Scrambler = hexstr2bin("02E2476A"),
+
+ %% X = hexstr2bin("96E54AB0CD4C5123EDCFA4A1502918AAD3C9E2A8"),
+ Verifier = hexstr2bin("96EB5F13621D911AA1CA405DE9C64217D4108EEEECAFFE500034FE0E"
+ "C031E42C8714667C161BCE0E7996F7DDE1B63824C130D2D7286C08C0"
+ "49758420735961347112AE102A3F23B3F687F8FEE0DF2BFAF933C608"
+ "D6FE5B5EEE3116FE54016E065BF8E8C9FDBBC08719231AC215149140"
+ "519E8FDD9AA4F410C28A58AF42974D2D"),
+ ClientPrivate = hexstr2bin("6411DE75538BED8170677D577D0608F39112BC95B503C447EB6AC945"
+ "49C75C7B"),
+ ServerPrivate = hexstr2bin("85E44A6F694DBE676145DB245A045CD37C99F05C562C7840A31F270D"
+ "9AADCF8B"),
+ ClientPublic = hexstr2bin("B22B1FFA2244B8CB94F3A9080F419CAEAB0DBA93EA1965B5E84587EE"
+ "55C79E7A118865DC59B9D0353362C2A8261E7C1B0D221A0E233C2AD1"
+ "640DACBB8664CBC9733EAC392DA7800142860380C3FC573C3C064329"
+ "CF54063FD114C7210E9CB3A611EA8002B1844B698F930D95D143899B"
+ "948A090E0C25938E5F84067D1883DC63"),
+ ServerPublic = hexstr2bin("93A8C4D8B7F7395ADCFD4ABA37B015124513D3F37B3E85EB23064BE5"
+ "F53C0AE32FFB9D8C0AA0DCFFA74D632DD67DEBB5C35AAE9812286CC8"
+ "C43CC176ECBC6D3F447594D9554E995B2509127BF88FADDDA4982D03"
+ "8EC3001320712D3B1269308CE70F319B2295FA57674F03A2D993CFB1"
+ "F84C35B7D0C012FA73CD4C8F7D5A71C7"),
+
+ SessionKey = hexstr2bin("C29A986C4D521BBC66428ED11D994CD7431574A6184B83CDCC345092"
+ "791E75748A1D38CAC4BD14760F0D2694B711236419240FF2F172454C"
+ "46ABF4FF39498DAFDD2C82924F7D7BD76CDFCE688C77D93F18A65409"
+ "9176A9192615DC0277AE7C12F1F6A7F6563FCA11675D809AF578BDE5"
+ "2B51E05D440B63099A017A0B45044801"),
+ UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
+ Verifier = crypto:mod_pow(Generator, UserPassHash, Prime),
+ ClientPublic = crypto:mod_pow(Generator, ClientPrivate, Prime),
+
+ {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate),
+ {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate),
+ SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate},
+ {user, [UserPassHash, Prime, Generator, Version, Scrambler]}),
+ SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate},
+ {host, [Verifier, Prime, Version, Scrambler]}).
+
+srp6(doc) ->
+ ["SRP-6 test vectors generated by http://srp.stanford.edu/demo/demo.html"];
+srp6(suite) -> [];
+srp6(Config) when is_list(Config) ->
+ Username = <<"alice">>,
+ Password = <<"password123">>,
+ Salt = hexstr2bin("2857827A19266A1F2BC6"),
+ Prime = hexstr2bin("EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C"
+ "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4"
+ "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29"
+ "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A"
+ "FD5138FE8376435B9FC61D2FC0EB06E3"),
+ Generator = <<2>>,
+ Version = '6',
+ Scrambler = hexstr2bin("0A2534C0BF52A0DA9001EEC62CF2A546AB0908A7"),
+ Verifier = hexstr2bin("96EB5F13621D911AA1CA405DE9C64217D4108EEEECAFFE500034FE0E"
+ "C031E42C8714667C161BCE0E7996F7DDE1B63824C130D2D7286C08C0"
+ "49758420735961347112AE102A3F23B3F687F8FEE0DF2BFAF933C608"
+ "D6FE5B5EEE3116FE54016E065BF8E8C9FDBBC08719231AC215149140"
+ "519E8FDD9AA4F410C28A58AF42974D2D"),
+ ClientPrivate = hexstr2bin("6411DE75538BED8170677D577D0608F39112BC95B503C447EB6AC945"
+ "49C75C7B"),
+ ServerPrivate = hexstr2bin("85E44A6F694DBE676145DB245A045CD37C99F05C562C7840A31F270D"
+ "9AADCF8B"),
+ ClientPublic = hexstr2bin("B22B1FFA2244B8CB94F3A9080F419CAEAB0DBA93EA1965B5E84587EE"
+ "55C79E7A118865DC59B9D0353362C2A8261E7C1B0D221A0E233C2AD1"
+ "640DACBB8664CBC9733EAC392DA7800142860380C3FC573C3C064329"
+ "CF54063FD114C7210E9CB3A611EA8002B1844B698F930D95D143899B"
+ "948A090E0C25938E5F84067D1883DC63"),
+ ServerPublic = hexstr2bin("D2D07845CE7ECDB9845DD36B10ACD3598CC29049DE9F467F84CE16B6"
+ "D97A6DC567AF8B0F9FEDF74962400AD5C357951E64E67B641246F264"
+ "C8DE6D9A72E554D6C8D3194548780A0C438A0FCC509CA88A14AA1DEB"
+ "C0F09E4B37A965D1545DB4AD361346F3189B0EA569C06D326C4E4797"
+ "9E381C748293B7C0591BE0BE419E053E"),
+
+ SessionKey = hexstr2bin("19D22C19612874EBF1F2581F8EFCFDC44C6FDA3B87B0A73823D7E962"
+ "554295D4E48D3A336523ADBDDD0EC8FB0F02687109E97E01C17C93CC"
+ "7216F9CD8A4AC39F0429857D8D1023066614BDFCBCB89F59A0FEB81C"
+ "72E992AAD89095A84B6A5FADA152369AB1E350A03693BEF044DF3EDF"
+ "0C34741F4696C30E9F675D09F58ACBEB"),
+ UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
+ Verifier = crypto:mod_pow(Generator, UserPassHash, Prime),
+ ClientPublic = crypto:mod_pow(Generator, ClientPrivate, Prime),
+
+ {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate),
+ {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate),
+ SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate},
+ {user, [UserPassHash, Prime, Generator, Version, Scrambler]}),
+ SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate},
+ {host, [Verifier, Prime, Version, Scrambler]}).
+
+srp6a(doc) ->
+ ["SRP-6a test vectors from RFC5054."];
+srp6a(suite) -> [];
+srp6a(Config) when is_list(Config) ->
+ Username = <<"alice">>,
+ Password = <<"password123">>,
+ Salt = hexstr2bin("BEB25379D1A8581EB5A727673A2441EE"),
+ Prime = hexstr2bin("EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C"
+ "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4"
+ "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29"
+ "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A"
+ "FD5138FE8376435B9FC61D2FC0EB06E3"),
+ Generator = <<2>>,
+ Version = '6a',
+ Scrambler = hexstr2bin("CE38B9593487DA98554ED47D70A7AE5F462EF019"),
+ Verifier = hexstr2bin("7E273DE8696FFC4F4E337D05B4B375BEB0DDE1569E8FA00A9886D812"
+ "9BADA1F1822223CA1A605B530E379BA4729FDC59F105B4787E5186F5"
+ "C671085A1447B52A48CF1970B4FB6F8400BBF4CEBFBB168152E08AB5"
+ "EA53D15C1AFF87B2B9DA6E04E058AD51CC72BFC9033B564E26480D78"
+ "E955A5E29E7AB245DB2BE315E2099AFB"),
+ ClientPrivate = hexstr2bin("60975527035CF2AD1989806F0407210BC81EDC04E2762A56AFD529DD"
+ "DA2D4393"),
+ ServerPrivate = hexstr2bin("E487CB59D31AC550471E81F00F6928E01DDA08E974A004F49E61F5D1"
+ "05284D20"),
+ ClientPublic = hexstr2bin("61D5E490F6F1B79547B0704C436F523DD0E560F0C64115BB72557EC4"
+ "4352E8903211C04692272D8B2D1A5358A2CF1B6E0BFCF99F921530EC"
+ "8E39356179EAE45E42BA92AEACED825171E1E8B9AF6D9C03E1327F44"
+ "BE087EF06530E69F66615261EEF54073CA11CF5858F0EDFDFE15EFEA"
+ "B349EF5D76988A3672FAC47B0769447B"),
+ ServerPublic = hexstr2bin("BD0C61512C692C0CB6D041FA01BB152D4916A1E77AF46AE105393011"
+ "BAF38964DC46A0670DD125B95A981652236F99D9B681CBF87837EC99"
+ "6C6DA04453728610D0C6DDB58B318885D7D82C7F8DEB75CE7BD4FBAA"
+ "37089E6F9C6059F388838E7A00030B331EB76840910440B1B27AAEAE"
+ "EB4012B7D7665238A8E3FB004B117B58"),
+
+ SessionKey = hexstr2bin("B0DC82BABCF30674AE450C0287745E7990A3381F63B387AAF271A10D"
+ "233861E359B48220F7C4693C9AE12B0A6F67809F0876E2D013800D6C"
+ "41BB59B6D5979B5C00A172B4A2A5903A0BDCAF8A709585EB2AFAFA8F"
+ "3499B200210DCC1F10EB33943CD67FC88A2F39A4BE5BEC4EC0A3212D"
+ "C346D7E474B29EDE8A469FFECA686E5A"),
+ UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
+ Verifier = crypto:mod_pow(Generator, UserPassHash, Prime),
+
+ {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate),
+ {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate),
+
+ SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate},
+ {user, [UserPassHash, Prime, Generator, Version, Scrambler]}),
+ SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate},
+ {host, [Verifier, Prime, Version, Scrambler]}).
+
+%%
+%%
+exor_test(doc) ->
+ ["Test the exor function."];
+exor_test(suite) ->
+ [];
+exor_test(Config) when is_list(Config) ->
+ B = <<1, 2, 3, 4, 5, 6, 7, 8, 9, 10>>,
+ Z1 = zero_bin(B),
+ Z1 = crypto:exor(B, B),
+ B1 = crypto:rand_bytes(100),
+ B2 = crypto:rand_bytes(100),
+ Z2 = zero_bin(B1),
+ Z2 = crypto:exor(B1, B1),
+ Z2 = crypto:exor(B2, B2),
+ R = xor_bytes(B1, B2),
+ R = crypto:exor(B1, B2),
+ ok.
+
+%%
+%%
+rc4_test(doc) ->
+ ["Test rc4 encryption ."];
+rc4_test(suite) ->
+ [];
+rc4_test(Config) when is_list(Config) ->
+ CT1 = <<"Yo baby yo">>,
+ R1 = <<118,122,68,110,157,166,141,212,139,39>>,
+ K = "apaapa",
+ R1 = crypto:rc4_encrypt(K, CT1),
+ CT1 = crypto:rc4_encrypt(K, R1),
+ CT2 = lists:seq(0, 255),
+ R2 = crypto:rc4_encrypt(K, CT2),
+ CT2 = binary_to_list(crypto:rc4_encrypt(K, R2)),
+ ok.
+
+rc4_stream_test(doc) ->
+ ["Test rc4 stream encryption ."];
+rc4_stream_test(suite) ->
+ [];
+rc4_stream_test(Config) when is_list(Config) ->
+ CT1 = <<"Yo ">>,
+ CT2 = <<"baby yo">>,
+ K = "apaapa",
+ State0 = crypto:rc4_set_key(K),
+ {State1, R1} = crypto:rc4_encrypt_with_state(State0, CT1),
+ {_State2, R2} = crypto:rc4_encrypt_with_state(State1, CT2),
+ R = list_to_binary([R1, R2]),
+ <<118,122,68,110,157,166,141,212,139,39>> = R,
+ ok.
+
+blowfish_cfb64(doc) -> ["Test Blowfish encrypt/decrypt."];
+blowfish_cfb64(suite) -> [];
+blowfish_cfb64(Config) when is_list(Config) ->
+ Key = <<1,35,69,103,137,171,205,239,240,225,210,195,180,165,150,135>>,
+
+ IVec = <<254,220,186,152,118,84,50,16>>,
+ Plain = <<"7654321 Now is the time for ">>,
+ Enc = <<231,50,20,162,130,33,57,202,242,110,207,109,46,185,231,110,61,163,222,4,209,81,114,0,81,157,87,166>>,
+
+ Enc = crypto:blowfish_cfb64_encrypt(Key, IVec, Plain),
+ Plain = crypto:blowfish_cfb64_decrypt(Key, IVec, Enc),
+
+ Key2 = <<"A2B4C">>,
+ IVec2 = <<"12345678">>,
+ Plain2 = <<"badger at my table....!">>,
+ Enc2 = <<173,76,128,155,70,81,79,228,4,162,188,92,119,53,144,89,93,236,28,164,176,16,138>>,
+
+ Enc2 = crypto:blowfish_cfb64_encrypt(Key2, IVec2, Plain2),
+ Plain2 = crypto:blowfish_cfb64_decrypt(Key2, IVec2, Enc2).
+
+
+smp(doc) -> "Check concurrent access to crypto driver";
+smp(suite) -> [];
+smp(Config) ->
+ case erlang:system_info(smp_support) of
+ true ->
+ NumOfProcs = erlang:system_info(schedulers),
+ io:format("smp starting ~p workers\n",[NumOfProcs]),
+ Seeds = [random:uniform(9999) || _ <- lists:seq(1,NumOfProcs)],
+ Parent = self(),
+ Pids = [spawn_link(fun()-> worker(Seed,Config,Parent) end)
+ || Seed <- Seeds],
+ wait_pids(Pids);
+
+ false ->
+ {skipped,"No smp support"}
+ end.
+
+worker(Seed, Config, Parent) ->
+ io:format("smp worker ~p, seed=~p~n",[self(),Seed]),
+ random:seed(Seed,Seed,Seed),
+ worker_loop(100, Config),
+ %%io:format("worker ~p done\n",[self()]),
+ Parent ! self().
+
+worker_loop(0, _) ->
+ ok;
+worker_loop(N, Config) ->
+ Funcs = { md5, md5_update, md5_mac, md5_mac_io, sha, sha_update, des_cbc,
+ aes_cfb, aes_cbc, des_cbc_iter, rand_uniform_test, strong_rand_test,
+ rsa_verify_test, exor_test, rc4_test, rc4_stream_test, mod_exp_test,
+ hmac_update_md5, hmac_update_sha, hmac_update_sha256, hmac_update_sha512,
+ hmac_rfc2202, hmac_rfc4231_sha224, hmac_rfc4231_sha256, hmac_rfc4231_sha384,
+ hmac_rfc4231_sha512, aes_ctr_stream },
+
+ F = element(random:uniform(size(Funcs)),Funcs),
+ %%io:format("worker ~p calling ~p\n",[self(),F]),
+ ?MODULE:F(Config),
+ worker_loop(N-1,Config).
+
+wait_pids([]) ->
+ ok;
+wait_pids(Pids) ->
+ receive
+ Pid ->
+ ?line true = lists:member(Pid,Pids),
+ Others = lists:delete(Pid,Pids),
+ io:format("wait_pid got ~p, still waiting for ~p\n",[Pid,Others]),
+ wait_pids(Others)
+ end.
+
+%%
+%% Help functions
+%%
+
+% match
+m(X, X) ->
+ ?line true.
+t(true) ->
+ true.
+
+% hexstr2bin
+hexstr2bin(S) ->
+ list_to_binary(hexstr2list(S)).
+
+hexstr2list([X,Y|T]) ->
+ [mkint(X)*16 + mkint(Y) | hexstr2list(T)];
+hexstr2list([]) ->
+ [].
+
+mkint(C) when $0 =< C, C =< $9 ->
+ C - $0;
+mkint(C) when $A =< C, C =< $F ->
+ C - $A + 10;
+mkint(C) when $a =< C, C =< $f ->
+ C - $a + 10.
+
+%% mod_exp in erlang (copied from jungerl's ssh_math.erl)
+ipow(A, B, M) when M > 0, B >= 0 ->
+ if A == 1 ->
+ 1;
+ true ->
+ ipow(A, B, M, 1)
+ end.
+
+ipow(A, 1, M, Prod) ->
+ (A*Prod) rem M;
+ipow(_A, 0, _M, Prod) ->
+ Prod;
+ipow(A, B, M, Prod) ->
+ B1 = B bsr 1,
+ A1 = (A*A) rem M,
+ if B - B1 == B1 ->
+ ipow(A1, B1, M, Prod);
+ true ->
+ ipow(A1, B1, M, (A*Prod) rem M)
+ end.
+
+%%
+%% Invert an element X mod P
+%% Calculated as {1, {A,B}} = egcd(X,P),
+%% 1 == P*A + X*B == X*B (mod P) i.e B is the inverse element
+%%
+%% X > 0, P > 0, X < P (P should be prime)
+%%
+%% invert(X,P) when X > 0, P > 0, X < P ->
+%% I = inv(X,P,1,0),
+%% if
+%% I < 0 -> P + I;
+%% true -> I
+%% end.
+
+%% inv(0,_,_,Q) -> Q;
+%% inv(X,P,R1,Q1) ->
+%% D = P div X,
+%% inv(P rem X, X, Q1 - D*R1, R1).
+
+sized_binary(Binary) when is_binary(Binary) ->
+ <<(size(Binary)):32/integer, Binary/binary>>;
+sized_binary(List) ->
+ sized_binary(list_to_binary(List)).
+
+unsized_binary(<<Sz:32/integer, Binary:Sz/binary>>) ->
+ Binary.
+
+xor_bytes(Bin1, Bin2) when is_binary(Bin1), is_binary(Bin2) ->
+ L1 = binary_to_list(Bin1),
+ L2 = binary_to_list(Bin2),
+ list_to_binary(xor_bytes(L1, L2));
+xor_bytes(L1, L2) ->
+ xor_bytes(L1, L2, []).
+
+xor_bytes([], [], Acc) ->
+ lists:reverse(Acc);
+xor_bytes([N1 | Tl1], [N2 | Tl2], Acc) ->
+ xor_bytes(Tl1, Tl2, [N1 bxor N2 | Acc]).
+
+zero_bin(N) when is_integer(N) ->
+ N8 = N * 8,
+ <<0:N8/integer>>;
+zero_bin(B) when is_binary(B) ->
+ zero_bin(size(B)).
+
+my_dss_verify(Data,[Sign|Tail],Key) ->
+ Res = my_dss_verify(Data,sized_binary(Sign),Key),
+ case Tail of
+ [] -> Res;
+ _ -> ?line Res = my_dss_verify(Data,Tail,Key)
+ end;
+my_dss_verify(Data,Sign,Key) ->
+ ?line Res = crypto:dss_verify(Data, Sign, Key),
+ ?line Res = crypto:dss_verify(sha, Data, Sign, Key),
+ ?line <<_:32,Raw/binary>> = Data,
+ ?line Res = crypto:dss_verify(none, crypto:sha(Raw), Sign, Key),
+ Res.
+
+my_dss_sign(Data,Key) ->
+ ?line S1 = crypto:dss_sign(Data, Key),
+ ?line S2 = crypto:dss_sign(sha, Data, Key),
+ ?line <<_:32,Raw/binary>> = Data,
+ ?line S3 = crypto:dss_sign(none, crypto:sha(Raw), Key),
+ [S1,S2,S3].
+
+openssl_version() ->
+ case crypto:info_lib() of
+ [{<<"OpenSSL">>,LibVer,_}] when is_integer(LibVer) ->
+ LibVer;
+ _ ->
+ undefined
+ end.
+
+if_supported(Algorithm, Fun) ->
+ case lists:member(Algorithm, lists:append([Algo || {_, Algo} <- crypto:supports()])) of
+ true ->
+ Fun();
+ _ ->
+ {skipped, io:format("~s not spupported", [Algorithm])}
+ end.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/tuple_set_crash.erl b/lib/dialyzer/test/small_SUITE_data/src/tuple_set_crash.erl
index 5503f39412..e6256e5a53 100644
--- a/lib/dialyzer/test/small_SUITE_data/src/tuple_set_crash.erl
+++ b/lib/dialyzer/test/small_SUITE_data/src/tuple_set_crash.erl
@@ -69,8 +69,8 @@ test(TargetId, [Date | DateTail], Key, IVT, IVF) ->
{ok, message_from_server(), binary(), binary()}.
culprit(Message, Key, IVecToServer, IVecFromServer) ->
{Packet, NewIVecToServer} = message_to_packet(Message, Key, IVecToServer),
- Message = crypto:aes_cbc_128_decrypt(Key, IVecFromServer, Packet),
- NewIVecFromServer = crypto:aes_cbc_ivec(Packet),
+ Message = crypto:block_decrypt(aes_cbc128, Key, IVecFromServer, Packet),
+ NewIVecFromServer = crypto:next_iv(aes_cbc, Packet),
ParsedMessage = parse_message(Message),
{ok, ParsedMessage, NewIVecToServer, NewIVecFromServer}.
@@ -185,9 +185,9 @@ parse_audio_output_info(<<Output:?DWORD, BitMap:?BITMAP1, Rest/binary>>) ->
-spec message_to_packet(binary(), binary(), binary()) -> {binary(), binary()}.
message_to_packet(Message, Key, IVec) ->
PaddedMessage = pad_pkcs5(Message),
- Packet = crypto:aes_cbc_128_encrypt(Key, IVec, PaddedMessage),
+ Packet = crypto:block_encrypt(aes_cbc128, Key, IVec, PaddedMessage),
TotalSize = byte_size(Packet),
- NewIVec = crypto:aes_cbc_ivec(Packet),
+ NewIVec = crypto:next_iv(aes_cbc, Packet),
{<<TotalSize:?WORD, Packet/binary>>, NewIVec}.
-spec pad_pkcs5(binary()) -> binary().
diff --git a/lib/diameter/doc/src/diameter_app.xml b/lib/diameter/doc/src/diameter_app.xml
index d4fb792787..e6c9cc9a90 100644
--- a/lib/diameter/doc/src/diameter_app.xml
+++ b/lib/diameter/doc/src/diameter_app.xml
@@ -565,7 +565,8 @@ Equivalent to</p>
</pre>
<p>
where <c>Avps</c> sets the Origin-Host, Origin-Realm, the specified
-Result-Code and (if the request contained one) Session-Id AVP's.</p>
+Result-Code and (if the request contained one) Session-Id AVP's, and
+possibly Failed-AVP as described below.</p>
<p>
Returning a value other than 3xxx or 5xxx will cause the request
@@ -573,6 +574,14 @@ process in question to fail, as will returning a 5xxx value if the
peer connection in question has been configured with the RFC 3588
common dictionary <c>diameter_gen_base_rfc3588</c>.
(Since RFC 3588 only allows 3xxx values in an answer-message.)</p>
+
+<p>
+When returning 5xxx, Failed-AVP will be populated with the AVP of the
+first matching Result-Code/AVP pair in the <c>errors</c> field of the
+argument &packet;, if found.
+If this is not appropriate then an answer-message should be
+constructed explicitly and returned in a <c>reply</c> tuple
+instead.</p>
</item>
<tag><c>{relay, Opts}</c></tag>
@@ -592,8 +601,7 @@ header of the relayed request.</p>
The returned <c>Opts</c> should not specify <c>detach</c>.
A subsequent &handle_answer;
callback for the relayed request must return its first
-argument, the <c>#diameter_packet{}</c> record containing the answer
-message.
+argument, the &packet; containing the answer message.
Note that the <c>extra</c> option can be specified to supply arguments
that can distinguish the relay case from others if so desired.
Any other return value (for example, from a
diff --git a/lib/diameter/doc/src/diameter_transport.xml b/lib/diameter/doc/src/diameter_transport.xml
index 8bccf6521e..9161bd1f48 100644
--- a/lib/diameter/doc/src/diameter_transport.xml
+++ b/lib/diameter/doc/src/diameter_transport.xml
@@ -137,15 +137,14 @@ passed to the former.</p>
<p>
The start function should use the <c>Host-IP-Address</c> list in
-<c>Svc</c> and/or <c>Config</c> to select an appropriate list of local
-IP addresses, and should return this list if different from the
-<c>Svc</c> addresses.
+<c>Svc</c> and/or <c>Config</c> to select and return an appropriate
+list of local IP addresses.
In the connecting case, the local address list can instead be
communicated in a <c>connected</c> message (see &MESSAGES; below)
following connection establishment.
In either case, the local address list is used to populate
<c>Host-IP-Address</c> AVPs in outgoing capabilities exchange
-messages.</p>
+messages if <c>Host-IP-Address</c> is unspecified.</p>
<p>
A transport process must implement the message interface documented below.
diff --git a/lib/diameter/include/diameter_gen.hrl b/lib/diameter/include/diameter_gen.hrl
index 03aa557c2e..55aae3a243 100644
--- a/lib/diameter/include/diameter_gen.hrl
+++ b/lib/diameter/include/diameter_gen.hrl
@@ -25,11 +25,23 @@
-define(THROW(T), throw({?MODULE, T})).
-%%% ---------------------------------------------------------------------------
-%%% # encode_avps/3
-%%%
-%%% Returns: binary()
-%%% ---------------------------------------------------------------------------
+-type parent_name() :: atom(). %% parent = Message or AVP
+-type parent_record() :: tuple(). %%
+-type avp_name() :: atom().
+-type avp_record() :: tuple().
+-type avp_values() :: [{avp_name(), term()}].
+
+-type non_grouped_avp() :: #diameter_avp{}.
+-type grouped_avp() :: nonempty_improper_list(#diameter_avp{}, [avp()]).
+-type avp() :: non_grouped_avp() | grouped_avp().
+
+%% ---------------------------------------------------------------------------
+%% # encode_avps/2
+%% ---------------------------------------------------------------------------
+
+-spec encode_avps(parent_name(), parent_record() | avp_values())
+ -> binary()
+ | no_return().
encode_avps(Name, Vals)
when is_list(Vals) ->
@@ -129,42 +141,26 @@ pack_AVP(Name, #diameter_avp{name = AvpName,
orelse ?THROW([known_avp_as_AVP, Name, AvpName, Data]),
e(AvpName, [Data]).
-%%% ---------------------------------------------------------------------------
-%%% # decode_avps/2
-%%%
-%%% Returns: {Rec, Avps, Failed}
-%%%
-%%% Rec = decoded message record
-%%% Avps = list of Avp
-%%% Failed = list of {ResultCode, #diameter_avp{}}
-%%%
-%%% Avp = #diameter_avp{} if type is not Grouped
-%%% | list of Avp where first element has type Grouped
-%%% and following elements are its component
-%%% AVP's.
-%%% ---------------------------------------------------------------------------
+%% ---------------------------------------------------------------------------
+%% # decode_avps/2
+%% ---------------------------------------------------------------------------
+
+-spec decode_avps(parent_name(), [#diameter_avp{}])
+ -> {parent_record(), [avp()], Failed}
+ when Failed :: [{5000..5999, #diameter_avp{}}].
decode_avps(Name, Recs) ->
- d_rc(Name, lists:foldl(fun(T,A) -> decode(Name, T, A) end,
- {[], {newrec(Name), []}},
- Recs)).
+ {Avps, {Rec, Failed}}
+ = lists:foldl(fun(T,A) -> decode(Name, T, A) end,
+ {[], {newrec(Name), []}},
+ Recs),
+ {Rec, Avps, Failed ++ missing(Rec, Name)}.
+%% Append 5005 errors so that a 5014 for the same AVP will take
+%% precedence in a Result-Code/Failed-AVP setting.
newrec(Name) ->
'#new-'(name2rec(Name)).
-%% No errors so far: keep looking.
-d_rc(Name, {Avps, {Rec, [] = Failed}}) ->
- try
- true = have_required_avps(Rec, Name),
- {Rec, Avps, Failed}
- catch
- throw: {?MODULE, {AvpName, Reason}} ->
- diameter_lib:log({decode, error},
- ?MODULE,
- ?LINE,
- {AvpName, Reason, Rec}),
- {Rec, Avps, [{5005, empty_avp(AvpName)}]}
- end;
%% 3588:
%%
%% DIAMETER_MISSING_AVP 5005
@@ -175,9 +171,17 @@ d_rc(Name, {Avps, {Rec, [] = Failed}}) ->
%% Vendor-Id if applicable. The value field of the missing AVP
%% should be of correct minimum length and contain zeroes.
-%% Or not. Only need to report the first error so look no further.
-d_rc(_, {Avps, {Rec, Failed}}) ->
- {Rec, Avps, lists:reverse(Failed)}.
+missing(Rec, Name) ->
+ [{5005, empty_avp(F)} || F <- '#info-'(element(1, Rec), fields),
+ A <- [avp_arity(Name, F)],
+ false <- [have_arity(A, '#get-'(F, Rec))]].
+
+%% Maximum arities have already been checked in building the record.
+
+have_arity({Min, _}, L) ->
+ Min =< length(L);
+have_arity(N, V) ->
+ N /= 1 orelse V /= undefined.
%% empty_avp/1
@@ -192,25 +196,6 @@ empty_avp(Name) ->
data = empty_value(Name),
type = Type}.
-%% have_required_avps/2
-
-have_required_avps(Rec, Name) ->
- lists:foreach(fun(F) -> hra(Name, F, Rec) end,
- '#info-'(element(1, Rec), fields)),
- true.
-
-hra(Name, AvpName, Rec) ->
- Arity = avp_arity(Name, AvpName),
- hra(Arity, '#get-'(AvpName, Rec))
- orelse ?THROW({AvpName, {insufficient_arity, Arity}}).
-
-%% Maximum arities have already been checked in building the record.
-
-hra({Min, _}, L) ->
- Min =< length(L);
-hra(N, V) ->
- N /= 1 orelse V /= undefined.
-
%% 3588, ch 7:
%%
%% The Result-Code AVP describes the error that the Diameter node
@@ -227,23 +212,22 @@ decode(Name, #diameter_avp{code = Code, vendor_id = Vid} = Avp, Acc) ->
%% decode/4
-%% Don't know this AVP: see if it can be packed in an 'AVP' field
-%% undecoded, unless it's mandatory. Need to give Failed-AVP special
-%% treatment since it'll contain any unrecognized mandatory AVP's.
-decode(Name, 'AVP', #diameter_avp{is_mandatory = M} = Avp, {Avps, Acc}) ->
- {[Avp | Avps], if M, Name /= 'Failed-AVP' ->
- unknown(Avp, Acc);
- true ->
- pack_AVP(Name, Avp, Acc)
- end};
-%% Note that the type field is 'undefined' in this case.
-
-%% Or try to decode.
decode(Name, {AvpName, Type}, Avp, Acc) ->
- d(Name, Avp#diameter_avp{name = AvpName, type = Type}, Acc).
+ d(Name, Avp#diameter_avp{name = AvpName, type = Type}, Acc);
+
+decode(Name, 'AVP', Avp, Acc) ->
+ decode_AVP(Name, Avp, Acc).
%% d/3
+%% Don't try to decode the value of a Failed-AVP component since it
+%% probably won't. Note that matching on 'Failed-AVP' assumes that
+%% this is the RFC AVP, with code 279. Strictly, this doesn't need to
+%% be the case, so we're assuming no one defines another Failed-AVP.
+d('Failed-AVP' = Name, Avp, Acc) ->
+ decode_AVP(Name, Avp, Acc);
+
+%% Or try to decode.
d(Name, Avp, {Avps, Acc}) ->
#diameter_avp{name = AvpName,
data = Data}
@@ -265,17 +249,25 @@ d(Name, Avp, {Avps, Acc}) ->
?LINE,
{Reason, Avp, erlang:get_stacktrace()}),
{Rec, Failed} = Acc,
- {[Avp|Avps], {Rec, [{rc(Reason), Avp} | Failed]}}
+ {[Avp|Avps], {Rec, [rc(Reason, Avp) | Failed]}}
end.
+%% decode_AVP/3
+%%
+%% Don't know this AVP: see if it can be packed in an 'AVP' field
+%% undecoded. Note that the type field is 'undefined' in this case.
+
+decode_AVP(Name, Avp, {Avps, Acc}) ->
+ {[Avp | Avps], pack_AVP(Name, Avp, Acc)}.
+
%% rc/1
%% diameter_types will raise an error of this form to communicate
%% DIAMETER_INVALID_AVP_LENGTH (5014). A module specified to a
%% @custom_types tag in a spec file can also raise an error of this
%% form.
-rc({'DIAMETER', RC, _}) ->
- RC;
+rc({'DIAMETER', 5014 = RC, _}, #diameter_avp{name = AvpName} = Avp) ->
+ {RC, Avp#diameter_avp{data = empty_value(AvpName)}};
%% 3588:
%%
@@ -283,20 +275,13 @@ rc({'DIAMETER', RC, _}) ->
%% The request contained an AVP with an invalid value in its data
%% portion. A Diameter message indicating this error MUST include
%% the offending AVPs within a Failed-AVP AVP.
-rc(_) ->
- 5004.
+rc(_, Avp) ->
+ {5004, Avp}.
%% ungroup/2
-%%
-%% Returns: {Avp, Dec}
-%%
-%% Avp = #diameter_avp{} if type is not Grouped
-%% | list of Avp where first element has type Grouped
-%% and following elements are its component
-%% AVP's.
-%% = as for decode_avps/2
-%%
-%% Dec = #diameter_avp{}, either Avp or its head in the list case.
+
+-spec ungroup(term(), #diameter_avp{})
+ -> {avp(), #diameter_avp{}}.
%% The decoded value in the Grouped case is as returned by grouped_avp/3:
%% a record and a list of component AVP's.
@@ -325,10 +310,18 @@ pack_avp(_, Arity, Avp, Acc) ->
%% pack_AVP/3
-pack_AVP(Name, Avp, Acc) ->
+%% Give Failed-AVP special treatment since it'll contain any
+%% unrecognized mandatory AVP's.
+pack_AVP(Name, #diameter_avp{is_mandatory = true} = Avp, Acc)
+ when Name /= 'Failed-AVP' ->
+ {Rec, Failed} = Acc,
+ {Rec, [{5001, Avp} | Failed]};
+
+pack_AVP(Name, #diameter_avp{is_mandatory = M} = Avp, Acc) ->
case avp_arity(Name, 'AVP') of
0 ->
- unknown(Avp, Acc);
+ {Rec, Failed} = Acc,
+ {Rec, [{if M -> 5001; true -> 5008 end, Avp} | Failed]};
Arity ->
pack(Arity, 'AVP', Avp, Acc)
end.
@@ -345,9 +338,6 @@ pack_AVP(Name, Avp, Acc) ->
%% A message was received with an AVP that MUST NOT be present. The
%% Failed-AVP AVP MUST be included and contain a copy of the
%% offending AVP.
-%%
-unknown(#diameter_avp{is_mandatory = B} = Avp, {Rec, Failed}) ->
- {Rec, [{if B -> 5001; true -> 5008 end, Avp} | Failed]}.
%% pack/4
@@ -386,23 +376,29 @@ value('AVP', Avp) ->
value(_, Avp) ->
Avp#diameter_avp.value.
-%%% ---------------------------------------------------------------------------
-%%% # grouped_avp/3
-%%% ---------------------------------------------------------------------------
+%% ---------------------------------------------------------------------------
+%% # grouped_avp/3
+%% ---------------------------------------------------------------------------
+
+-spec grouped_avp(decode, avp_name(), binary())
+ -> {avp_record(), [avp()]};
+ (encode, avp_name(), avp_record() | avp_values())
+ -> binary()
+ | no_return().
grouped_avp(decode, Name, Data) ->
{Rec, Avps, []} = decode_avps(Name, diameter_codec:collect_avps(Data)),
{Rec, Avps};
-%% Note that a failed match here will result in 5004. Note that this is
-%% the only AVP type that doesn't just return the decoded value, also
-%% returning the list of component #diameter_avp{}'s.
+%% A failed match here will result in 5004. Note that this is the only
+%% AVP type that doesn't just return the decoded record, also
+%% returning the list of component AVP's.
grouped_avp(encode, Name, Data) ->
encode_avps(Name, Data).
-%%% ---------------------------------------------------------------------------
-%%% # empty_group/1
-%%% ---------------------------------------------------------------------------
+%% ---------------------------------------------------------------------------
+%% # empty_group/1
+%% ---------------------------------------------------------------------------
empty_group(Name) ->
list_to_binary(empty_body(Name)).
@@ -423,9 +419,9 @@ z(Name) ->
Bin = diameter_codec:pack_avp(avp_header(Name), empty_value(Name)),
<< <<0>> || <<_>> <= Bin >>.
-%%% ---------------------------------------------------------------------------
-%%% # empty/1
-%%% ---------------------------------------------------------------------------
+%% ---------------------------------------------------------------------------
+%% # empty/1
+%% ---------------------------------------------------------------------------
empty(AvpName) ->
avp(encode, zero, AvpName).
diff --git a/lib/diameter/src/base/diameter_capx.erl b/lib/diameter/src/base/diameter_capx.erl
index 9a443fead0..4b821f5139 100644
--- a/lib/diameter/src/base/diameter_capx.erl
+++ b/lib/diameter/src/base/diameter_capx.erl
@@ -282,9 +282,26 @@ build_CEA(_, LCaps, RCaps, Dict, CEA) ->
[] ->
Dict:'#set-'({'Result-Code', ?NOSECURITY}, CEA);
[_] = IS ->
- Dict:'#set-'({'Inband-Security-Id', IS}, CEA)
+ Dict:'#set-'({'Inband-Security-Id', inband_security(IS)}, CEA)
end.
+%% Only set Inband-Security-Id if different from the default, since
+%% RFC 6733 recommends against the AVP:
+%%
+%% 6.10. Inband-Security-Id AVP
+%%
+%% The Inband-Security-Id AVP (AVP Code 299) is of type Unsigned32 and
+%% is used in order to advertise support of the security portion of the
+%% application. The use of this AVP in CER and CEA messages is NOT
+%% RECOMMENDED. Instead, discovery of a Diameter entity's security
+%% capabilities can be done either through static configuration or via
+%% Diameter Peer Discovery as described in Section 5.2.
+
+inband_security([?NO_INBAND_SECURITY]) ->
+ [];
+inband_security([_] = IS) ->
+ IS.
+
%% common_security/2
common_security(#diameter_caps{inband_security_id = LS},
diff --git a/lib/diameter/src/base/diameter_codec.erl b/lib/diameter/src/base/diameter_codec.erl
index e446a0209c..6c0e73de36 100644
--- a/lib/diameter/src/base/diameter_codec.erl
+++ b/lib/diameter/src/base/diameter_codec.erl
@@ -38,6 +38,10 @@
-define(MASK(N,I), ((I) band (1 bsl (N)))).
+-type u32() :: 0..16#FFFFFFFF.
+-type u24() :: 0..16#FFFFFF.
+-type u1() :: 0..1.
+
%% 0 1 2 3
%% 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
%% +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -55,9 +59,13 @@
%% +-+-+-+-+-+-+-+-+-+-+-+-+-
%%% ---------------------------------------------------------------------------
-%%% # encode/[2-4]
+%%% # encode/2
%%% ---------------------------------------------------------------------------
+-spec encode(module(), Msg :: term())
+ -> #diameter_packet{}
+ | no_return().
+
encode(Mod, #diameter_packet{} = Pkt) ->
try
e(Mod, Pkt)
@@ -217,6 +225,9 @@ rec2msg(Mod, Rec) ->
%% Unsuccessfully decoded AVPs will be placed in #diameter_packet.errors.
+-spec decode(module(), #diameter_packet{} | bitstring())
+ -> #diameter_packet{}.
+
decode(Mod, Pkt) ->
decode(Mod:id(), Mod, Pkt).
@@ -225,9 +236,9 @@ decode(Mod, Pkt) ->
%% question.
decode(?APP_ID_RELAY, _, #diameter_packet{} = Pkt) ->
case collect_avps(Pkt) of
- {Bs, As} ->
+ {E, As} ->
Pkt#diameter_packet{avps = As,
- errors = [Bs]};
+ errors = [E]};
As ->
Pkt#diameter_packet{avps = As}
end;
@@ -251,12 +262,12 @@ decode(Id, Mod, Bin)
when is_bitstring(Bin) ->
decode(Id, Mod, #diameter_packet{header = decode_header(Bin), bin = Bin}).
-decode_avps(MsgName, Mod, Pkt, {Bs, Avps}) -> %% invalid avp bits ...
+decode_avps(MsgName, Mod, Pkt, {E, Avps}) ->
?LOG(invalid, Pkt#diameter_packet.bin),
#diameter_packet{errors = Failed}
= P
= decode_avps(MsgName, Mod, Pkt, Avps),
- P#diameter_packet{errors = [Bs | Failed]};
+ P#diameter_packet{errors = [E | Failed]};
decode_avps('', Mod, Pkt, Avps) -> %% unknown message ...
?LOG(unknown, {Mod, Pkt#diameter_packet.header}),
@@ -275,6 +286,10 @@ decode_avps(MsgName, Mod, Pkt, Avps) -> %% ... or not
%%% # decode_header/1
%%% ---------------------------------------------------------------------------
+-spec decode_header(bitstring())
+ -> #diameter_header{}
+ | false.
+
decode_header(<<Version:8,
MsgLength:24,
CmdFlags:1/binary,
@@ -324,6 +339,13 @@ decode_header(_) ->
%% wraparound counter. The 8-bit counter is incremented each time the
%% system is restarted.
+-spec sequence_numbers(#diameter_packet{}
+ | #diameter_header{}
+ | binary()
+ | Seq)
+ -> Seq
+ when Seq :: {HopByHopId :: u32(), EndToEndId :: u32()}.
+
sequence_numbers({_,_} = T) ->
T;
@@ -345,6 +367,9 @@ sequence_numbers(<<_:12/binary, H:32, E:32, _/binary>>) ->
%%% # hop_by_hop_id/2
%%% ---------------------------------------------------------------------------
+-spec hop_by_hop_id(u32(), binary())
+ -> binary().
+
hop_by_hop_id(Id, <<H:12/binary, _:32, T/binary>>) ->
<<H/binary, Id:32, T/binary>>.
@@ -352,6 +377,10 @@ hop_by_hop_id(Id, <<H:12/binary, _:32, T/binary>>) ->
%%% # msg_name/2
%%% ---------------------------------------------------------------------------
+-spec msg_name(module(), #diameter_header{})
+ -> atom()
+ | {ApplicationId :: u32(), CommandCode :: u24(), Rbit :: u1()}.
+
msg_name(Dict0, #diameter_header{application_id = ?APP_ID_COMMON,
cmd_code = C,
is_request = R}) ->
@@ -367,6 +396,9 @@ msg_name(_, Hdr) ->
%%% # msg_id/1
%%% ---------------------------------------------------------------------------
+-spec msg_id(#diameter_packet{} | #diameter_header{})
+ -> {ApplicationId :: u32(), CommandCode :: u24(), Rbit :: u1()}.
+
msg_id(#diameter_packet{msg = [#diameter_header{} = Hdr | _]}) ->
msg_id(Hdr);
@@ -389,6 +421,12 @@ msg_id(<<_:32, Rbit:1, _:7, CmdCode:24, ApplId:32, _/bitstring>>) ->
%% order in the binary. Note also that grouped avp's aren't unraveled,
%% only those at the top level.
+-spec collect_avps(#diameter_packet{} | bitstring())
+ -> [Avp]
+ | {Error, [Avp]}
+ when Avp :: #diameter_avp{},
+ Error :: {5014, #diameter_avp{}}.
+
collect_avps(#diameter_packet{bin = Bin}) ->
<<_:20/binary, Avps/bitstring>> = Bin,
collect_avps(Avps);
@@ -403,8 +441,8 @@ collect_avps(Bin, N, Acc) ->
{Rest, AVP} ->
collect_avps(Rest, N+1, [AVP#diameter_avp{index = N} | Acc])
catch
- ?FAILURE(_) ->
- {Bin, Acc}
+ ?FAILURE(Error) ->
+ {Error, Acc}
end.
%% 0 1 2 3
@@ -422,42 +460,87 @@ collect_avps(Bin, N, Acc) ->
%% split_avp/1
split_avp(Bin) ->
- 8 =< size(Bin) orelse ?THROW(truncated_header),
+ {Code, V, M, P, Len, HdrLen} = split_head(Bin),
+ {Data, B} = split_data(Bin, HdrLen, Len - HdrLen),
- <<Code:32, Flags:1/binary, Length:24, Rest/bitstring>>
- = Bin,
+ {B, #diameter_avp{code = Code,
+ vendor_id = V,
+ is_mandatory = 1 == M,
+ need_encryption = 1 == P,
+ data = Data}}.
- DataSize = Length - 8, % size(Code+Flags+Length) = 8 octets
- PadSize = (4 - (DataSize rem 4)) rem 4,
+%% split_head/1
- DataSize + PadSize =< size(Rest)
- orelse ?THROW(truncated_data),
+split_head(<<Code:32, 1:1, M:1, P:1, _:5, Len:24, V:32, _/bitstring>>) ->
+ {Code, V, M, P, Len, 12};
- <<Data:DataSize/binary, _:PadSize/binary, R/bitstring>>
- = Rest,
- <<Vbit:1, Mbit:1, Pbit:1, _Reserved:5>>
- = Flags,
+split_head(<<Code:32, 0:1, M:1, P:1, _:5, Len:24, _/bitstring>>) ->
+ {Code, undefined, M, P, Len, 8};
- 0 == Vbit orelse 4 =< size(Data)
- orelse ?THROW(truncated_vendor_id),
+split_head(Bin) ->
+ ?THROW({5014, #diameter_avp{data = Bin}}).
+
+%% 3588:
+%%
+%% DIAMETER_INVALID_AVP_LENGTH 5014
+%% The request contained an AVP with an invalid length. A Diameter
+%% message indicating this error MUST include the offending AVPs
+%% within a Failed-AVP AVP.
- {Vid, D} = vid(Vbit, Data),
- {R, #diameter_avp{code = Code,
- vendor_id = Vid,
- is_mandatory = 1 == Mbit,
- need_encryption = 1 == Pbit,
- data = D}}.
+%% 6733:
+%%
+%% DIAMETER_INVALID_AVP_LENGTH 5014
+%%
+%% The request contained an AVP with an invalid length. A Diameter
+%% message indicating this error MUST include the offending AVPs
+%% within a Failed-AVP AVP. In cases where the erroneous AVP length
+%% value exceeds the message length or is less than the minimum AVP
+%% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+%% header length, it is sufficient to include the offending AVP
+%% ^^^^^^^^^^^^^
+%% header and a zero filled payload of the minimum required length
+%% for the payloads data type. If the AVP is a Grouped AVP, the
+%% Grouped AVP header with an empty payload would be sufficient to
+%% indicate the offending AVP. In the case where the offending AVP
+%% header cannot be fully decoded when the AVP length is less than
+%% the minimum AVP header length, it is sufficient to include an
+%% offending AVP header that is formulated by padding the incomplete
+%% AVP header with zero up to the minimum AVP header length.
+%%
+%% The underlined clause must be in error since (1) a header less than
+%% the minimum value mean we don't know the identity of the AVP and
+%% (2) the last sentence covers this case.
-%% The RFC is a little misleading when stating that OctetString is
-%% padded to a 32-bit boundary while other types align naturally. All
-%% other types are already multiples of 32 bits so there's no need to
-%% distinguish between types here. Any invalid lengths will result in
-%% decode error in diameter_types.
+%% split_data/3
-vid(1, <<Vid:32, Data/bitstring>>) ->
- {Vid, Data};
-vid(0, Data) ->
- {undefined, Data}.
+split_data(Bin, HdrLen, Len)
+ when 0 =< Len ->
+ split_data(Bin, HdrLen, Len, (4 - (Len rem 4)) rem 4);
+
+split_data(_, _, _) ->
+ invalid_avp_length().
+
+%% split_data/4
+
+split_data(Bin, HdrLen, Len, Pad) ->
+ <<_:HdrLen/binary, T/bitstring>> = Bin,
+ case T of
+ <<Data:Len/binary, _:Pad/binary, Rest/bitstring>> ->
+ {Data, Rest};
+ _ ->
+ invalid_avp_length()
+ end.
+
+%% invalid_avp_length/0
+%%
+%% AVP Length doesn't mesh with payload. Induce a decode error by
+%% returning a payload that no valid Diameter type can have. This is
+%% so that a known AVP will result in 5014 error with a zero'd
+%% payload. Here we simply don't know how to construct this payload.
+%% (Yes, this solution is an afterthought.)
+
+invalid_avp_length() ->
+ {<<0:1>>, <<>>}.
%%% ---------------------------------------------------------------------------
%%% # pack_avp/1
@@ -472,20 +555,35 @@ vid(0, Data) ->
pack_avp(#diameter_avp{data = [#diameter_avp{} | _] = Avps} = A) ->
pack_avp(A#diameter_avp{data = encode_avps(Avps)});
-%% ... data as a type/value tuple, possibly with header data, ...
+%% ... data as a type/value tuple ...
pack_avp(#diameter_avp{data = {Type, Value}} = A)
when is_atom(Type) ->
pack_avp(A#diameter_avp{data = diameter_types:Type(encode, Value)});
+
+%% ... with a header in various forms ...
pack_avp(#diameter_avp{data = {{_,_,_} = T, {Type, Value}}}) ->
pack_avp(T, iolist_to_binary(diameter_types:Type(encode, Value)));
+
pack_avp(#diameter_avp{data = {{_,_,_} = T, Bin}})
when is_binary(Bin) ->
pack_avp(T, Bin);
+
pack_avp(#diameter_avp{data = {Dict, Name, Value}} = A) ->
{Code, _Flags, Vid} = Hdr = Dict:avp_header(Name),
{Name, Type} = Dict:avp_name(Code, Vid),
pack_avp(A#diameter_avp{data = {Hdr, {Type, Value}}});
+pack_avp(#diameter_avp{code = undefined, data = Bin})
+ when is_binary(Bin) ->
+ %% Reset the AVP Length of an AVP Header resulting from a 5014
+ %% error. The RFC doesn't explicitly say to do this but the
+ %% receiver can't correctly extract this and following AVP's
+ %% without a correct length. On the downside, the header doesn't
+ %% reveal if the received header has been padded.
+ Pad = 8*header_length(Bin) - bit_size(Bin),
+ Len = size(<<H:5/binary, _:24, T/binary>> = <<Bin/bitstring, 0:Pad>>),
+ <<H/binary, Len:24, T/binary>>;
+
%% ... or as an iolist.
pack_avp(#diameter_avp{code = Code,
vendor_id = V,
@@ -497,6 +595,11 @@ pack_avp(#diameter_avp{code = Code,
{P, 2#00100000}]),
pack_avp({Code, Flags, V}, iolist_to_binary(Data)).
+header_length(<<_:32, 1:1, _/bitstring>>) ->
+ 12;
+header_length(_) ->
+ 8.
+
flag_avp({true, B}, F) ->
F bor B;
flag_avp({false, _}, F) ->
diff --git a/lib/diameter/src/base/diameter_peer_fsm.erl b/lib/diameter/src/base/diameter_peer_fsm.erl
index 6be4259510..4e55864168 100644
--- a/lib/diameter/src/base/diameter_peer_fsm.erl
+++ b/lib/diameter/src/base/diameter_peer_fsm.erl
@@ -233,20 +233,21 @@ start_transport(Addrs0, T) ->
{TPid, Addrs, Tmo, Data} ->
erlang:monitor(process, TPid),
q_next(TPid, Addrs0, Tmo, Data),
- {TPid, addrs(Addrs, Addrs0)};
+ {TPid, Addrs};
No ->
exit({shutdown, No})
end.
-addrs([], Addrs0) ->
- Addrs0;
-addrs(Addrs, _) ->
- Addrs.
-
-svc(Svc, []) ->
- Svc;
-svc(Svc, Addrs) ->
- readdr(Svc, Addrs).
+svc(#diameter_service{capabilities = LCaps0} = Svc, Addrs) ->
+ #diameter_caps{host_ip_address = Addrs0}
+ = LCaps0,
+ case Addrs0 of
+ [] ->
+ LCaps = LCaps0#diameter_caps{host_ip_address = Addrs},
+ Svc#diameter_service{capabilities = LCaps};
+ [_|_] ->
+ Svc
+ end.
readdr(#diameter_service{capabilities = LCaps0} = Svc, Addrs) ->
LCaps = LCaps0#diameter_caps{host_ip_address = Addrs},
@@ -360,7 +361,7 @@ transition({diameter, {TPid, connected, Remote, LAddrs}},
service = Svc}
= S) ->
transition({diameter, {TPid, connected, Remote}},
- S#state{service = readdr(Svc, LAddrs)});
+ S#state{service = svc(Svc, LAddrs)});
%% Connection from peer.
transition({diameter, {TPid, connected}},
@@ -702,13 +703,13 @@ build_answer('CER',
N -> {cea(CEA, N, Dict0), [fun open/5, Pkt,
SupportedApps,
Caps,
- {accept, hd([_] = IS)}]}
+ {accept, inband_security(IS)}]}
catch
?FAILURE(Reason) ->
rejected(Reason, {'CER', Reason, Caps, Pkt}, S)
end;
-%% The error checks below are similar to those in diameter_service for
+%% The error checks below are similar to those in diameter_traffic for
%% other messages. Should factor out the commonality.
build_answer(Type,
@@ -719,6 +720,11 @@ build_answer(Type,
RC = rc(H, Es),
{answer(Type, RC, Es, S), post(Type, RC, Pkt, S)}.
+inband_security([]) ->
+ ?NO_INBAND_SECURITY;
+inband_security([IS]) ->
+ IS.
+
cea(CEA, ok, _) ->
CEA;
cea(CEA, 2001, _) ->
@@ -742,7 +748,14 @@ rejected(N, T, S) ->
rejected({N, []}, T, S).
answer(Type, RC, Es, S) ->
- set(answer(Type, RC, S), failed_avp([A || {_,A} <- Es])).
+ set(answer(Type, RC, S), failed_avp(RC, Es)).
+
+failed_avp(RC, [{RC, Avp} | _]) ->
+ [{'Failed-AVP', [{'AVP', [Avp]}]}];
+failed_avp(RC, [_ | Es]) ->
+ failed_avp(RC, Es);
+failed_avp(_, [] = No) ->
+ No.
answer(Type, RC, S) ->
answer_message(answer(Type, S), RC).
@@ -762,13 +775,6 @@ is_origin({N, _}) ->
orelse N == 'Origin-Realm'
orelse N == 'Origin-State-Id'.
-%% failed_avp/1
-
-failed_avp([] = No) ->
- No;
-failed_avp(Avps) ->
- [{'Failed-AVP', [[{'AVP', Avps}]]}].
-
%% set/2
set(Ans, []) ->
@@ -784,7 +790,7 @@ rc(#diameter_header{is_error = true}, _) ->
3008; %% DIAMETER_INVALID_HDR_BITS
rc(_, [Bs|_])
- when is_bitstring(Bs) ->
+ when is_bitstring(Bs) -> %% from old code
3009; %% DIAMETER_INVALID_HDR_BITS
rc(#diameter_header{version = ?DIAMETER_VERSION}, Es) ->
diff --git a/lib/diameter/src/base/diameter_traffic.erl b/lib/diameter/src/base/diameter_traffic.erl
index 25b902e3f2..0b15e68ec7 100644
--- a/lib/diameter/src/base/diameter_traffic.erl
+++ b/lib/diameter/src/base/diameter_traffic.erl
@@ -226,10 +226,10 @@ recv_R(false = No, _, _, _, _) -> %% transport has gone down
collect_avps(Pkt) ->
case diameter_codec:collect_avps(Pkt) of
- {_Bs, As} ->
- As;
- As ->
- As
+ {_Error, Avps} ->
+ Avps;
+ Avps ->
+ Avps
end.
%% recv_R/6
@@ -300,7 +300,7 @@ errors(_, #diameter_packet{header = #diameter_header{version = V},
%% AVP's definition.
errors(_, #diameter_packet{errors = [Bs | Es]} = Pkt)
- when is_bitstring(Bs) ->
+ when is_bitstring(Bs) -> %% from old code
Pkt#diameter_packet{errors = [3009 | Es]};
%% DIAMETER_COMMAND_UNSUPPORTED 3001
@@ -479,10 +479,9 @@ answer_message(RC,
#diameter_caps{origin_host = {OH,_},
origin_realm = {OR,_}},
Dict0,
- #diameter_packet{avps = Avps}
- = Pkt) ->
+ Pkt) ->
?LOG({error, RC}, Pkt),
- {Dict0, answer_message(OH, OR, RC, Dict0, Avps)}.
+ {Dict0, answer_message(OH, OR, RC, Dict0, Pkt)}.
%% resend/7
@@ -595,71 +594,87 @@ reply([Msg], Dict, TPid, Dict0, Fs, ReqPkt)
is_tuple(Msg) ->
reply(Msg, Dict, TPid, Dict0, Fs, ReqPkt#diameter_packet{errors = []});
-%% No errors or a diameter_header/avp list.
reply(Msg, Dict, TPid, Dict0, Fs, ReqPkt) ->
- Pkt = encode(Dict, reset(make_answer_packet(Msg, ReqPkt), Dict), Fs),
+ Pkt = encode(Dict,
+ reset(make_answer_packet(Msg, ReqPkt), Dict, Dict0),
+ Fs),
incr(send, Pkt, Dict, TPid, Dict0), %% count outgoing result codes
send(TPid, Pkt).
-%% reset/2
+%% reset/3
%% Header/avps list: send as is.
-reset(#diameter_packet{msg = [#diameter_header{} | _]} = Pkt, _) ->
+reset(#diameter_packet{msg = [#diameter_header{} | _]} = Pkt, _, _) ->
Pkt;
%% No errors to set or errors explicitly ignored.
-reset(#diameter_packet{errors = Es} = Pkt, _)
+reset(#diameter_packet{errors = Es} = Pkt, _, _)
when Es == [];
Es == false ->
Pkt;
%% Otherwise possibly set Result-Code and/or Failed-AVP.
-reset(#diameter_packet{msg = Msg, errors = Es} = Pkt, Dict) ->
- Pkt#diameter_packet{msg = reset(Msg, Dict, Es)}.
-
-%% reset/3
-
-reset(Msg, Dict, Es)
- when is_list(Es) ->
- {E3, E5, Fs} = partition(Es),
- FailedAVP = failed_avp(Msg, lists:reverse(Fs), Dict),
- reset(set(Msg, FailedAVP, Dict),
- Dict,
- choose(is_answer_message(Msg, Dict), E3, E5));
-
-reset(Msg, Dict, N)
- when is_integer(N) ->
- ResultCode = rc(Msg, {'Result-Code', N}, Dict),
- set(Msg, ResultCode, Dict);
-
-reset(Msg, _, _) ->
- Msg.
+reset(#diameter_packet{msg = Msg, errors = Es} = Pkt, Dict, Dict0) ->
+ {RC, Failed} = select_error(Msg, Es, Dict0),
+ Pkt#diameter_packet{msg = reset(Msg, Dict, RC, Failed)}.
-partition(Es) ->
- lists:foldl(fun pacc/2, {false, false, []}, Es).
-
-%% Note that the errors list can contain not only integer() and
-%% {integer(), #diameter_avp{}} but also #diameter_avp{}. The latter
-%% isn't something that's returned by decode but can be set in a reply
-%% for encode.
+%% select_error/3
+%%
+%% Extract the first appropriate RC or {RC, #diameter_avp{}}
+%% pair from an errors list, and accumulate all #diameter_avp{}.
+%%
+%% RFC 6733:
+%%
+%% 7.5. Failed-AVP AVP
+%%
+%% The Failed-AVP AVP (AVP Code 279) is of type Grouped and provides
+%% debugging information in cases where a request is rejected or not
+%% fully processed due to erroneous information in a specific AVP. The
+%% value of the Result-Code AVP will provide information on the reason
+%% for the Failed-AVP AVP. A Diameter answer message SHOULD contain an
+%% instance of the Failed-AVP AVP that corresponds to the error
+%% indicated by the Result-Code AVP. For practical purposes, this
+%% Failed-AVP would typically refer to the first AVP processing error
+%% that a Diameter node encounters.
+
+select_error(Msg, Es, Dict0) ->
+ {RC, Avps} = lists:foldl(fun(T,A) -> select(T, A, Dict0) end,
+ {is_answer_message(Msg, Dict0), []},
+ Es),
+ {RC, lists:reverse(Avps)}.
+
+%% Only integer() and {integer(), #diameter_avp{}} are the result of
+%% decode. #diameter_avp{} can only be set in a reply for encode.
+
+select(#diameter_avp{} = A, {RC, As}, _) ->
+ {RC, [A|As]};
+
+select(_, {RC, _} = Acc, _)
+ when is_integer(RC) ->
+ Acc;
-pacc({RC, #diameter_avp{} = A}, {E3, E5, Acc})
+select({RC, #diameter_avp{} = A}, {IsAns, As} = Acc, Dict0)
when is_integer(RC) ->
- pacc(RC, {E3, E5, [A|Acc]});
+ case is_result(RC, IsAns, Dict0) of
+ true -> {RC, [A|As]};
+ false -> Acc
+ end;
-pacc(#diameter_avp{} = A, {E3, E5, Acc}) ->
- {E3, E5, [A|Acc]};
+select(RC, {IsAns, As} = Acc, Dict0)
+ when is_boolean(IsAns), is_integer(RC) ->
+ case is_result(RC, IsAns, Dict0) of
+ true -> {RC, As};
+ false -> Acc
+ end.
-pacc(RC, {false, E5, Acc})
- when 3 == RC div 1000 ->
- {RC, E5, Acc};
+%% reset/4
-pacc(RC, {E3, false, Acc})
- when 5 == RC div 1000 ->
- {E3, RC, Acc};
+reset(Msg, Dict, RC, Avps) ->
+ FailedAVP = failed_avp(Msg, Avps, Dict),
+ ResultCode = rc(Msg, RC, Dict),
+ set(set(Msg, FailedAVP, Dict), ResultCode, Dict).
-pacc(_, Acc) ->
- Acc.
+%% eval_packet/2
eval_packet(Pkt, Fs) ->
lists:foreach(fun(F) -> diameter_lib:eval([F,Pkt]) end, Fs).
@@ -725,29 +740,34 @@ set(Rec, Avps, Dict) ->
%% the arity is 1 or {0,1}. In other cases (which probably shouldn't
%% exist in practise) we can't know what's appropriate.
-rc([MsgName | _], {'Result-Code' = K, RC} = T, Dict) ->
- case Dict:avp_arity(MsgName, 'Result-Code') of
- 1 -> [T];
+rc(_, B, _)
+ when is_boolean(B) ->
+ [];
+
+rc([MsgName | _], RC, Dict) ->
+ K = 'Result-Code',
+ case Dict:avp_arity(MsgName, K) of
+ 1 -> [{K, RC}];
{0,1} -> [{K, [RC]}];
_ -> []
end;
-rc(Rec, T, Dict) ->
- rc([Dict:rec2msg(element(1, Rec))], T, Dict).
+rc(Rec, RC, Dict) ->
+ rc([Dict:rec2msg(element(1, Rec))], RC, Dict).
%% failed_avp/3
failed_avp(_, [] = No, _) ->
No;
-failed_avp(Rec, Failed, Dict) ->
- [fa(Rec, [{'AVP', Failed}], Dict)].
+failed_avp(Rec, Avps, Dict) ->
+ [failed(Rec, [{'AVP', Avps}], Dict)].
%% Reply as name and tuple list ...
-fa([MsgName | Values], FailedAvp, Dict) ->
- R = Dict:msg2rec(MsgName),
+failed([MsgName | Values], FailedAvp, Dict) ->
+ RecName = Dict:msg2rec(MsgName),
try
- Dict:'#info-'(R, {index, 'Failed-AVP'}),
+ Dict:'#info-'(RecName, {index, 'Failed-AVP'}),
{'Failed-AVP', [FailedAvp]}
catch
error: _ ->
@@ -758,8 +778,10 @@ fa([MsgName | Values], FailedAvp, Dict) ->
end;
%% ... or record.
-fa(Rec, FailedAvp, Dict) ->
+failed(Rec, FailedAvp, Dict) ->
try
+ RecName = element(1, Rec),
+ Dict:'#info-'(RecName, {index, 'Failed-AVP'}),
{'Failed-AVP', [FailedAvp]}
catch
error: _ ->
@@ -838,12 +860,14 @@ fa(Rec, FailedAvp, Dict) ->
%% answer_message/5
-answer_message(OH, OR, RC, Dict0, Avps) ->
+answer_message(OH, OR, RC, Dict0, #diameter_packet{avps = Avps,
+ errors = Es}) ->
{Code, _, Vid} = Dict0:avp_header('Session-Id'),
['answer-message', {'Origin-Host', OH},
{'Origin-Realm', OR},
- {'Result-Code', RC}
- | session_id(Code, Vid, Dict0, Avps)].
+ {'Result-Code', RC}]
+ ++ session_id(Code, Vid, Dict0, Avps)
+ ++ failed_avp(RC, Es).
session_id(Code, Vid, Dict0, Avps)
when is_list(Avps) ->
@@ -855,6 +879,15 @@ session_id(Code, Vid, Dict0, Avps)
[]
end.
+%% Note that this should only match 5xxx result codes currently but
+%% don't bother distinguishing this case.
+failed_avp(RC, [{RC, Avp} | _]) ->
+ [{'Failed-AVP', [{'AVP', [Avp]}]}];
+failed_avp(RC, [_ | Es]) ->
+ failed_avp(RC, Es);
+failed_avp(_, [] = No) ->
+ No.
+
%% find_avp/3
find_avp(Code, Vid, Avps)
diff --git a/lib/diameter/src/base/diameter_watchdog.erl b/lib/diameter/src/base/diameter_watchdog.erl
index 41c493ff20..88ccf630e2 100644
--- a/lib/diameter/src/base/diameter_watchdog.erl
+++ b/lib/diameter/src/base/diameter_watchdog.erl
@@ -505,7 +505,9 @@ set_watchdog(#watchdog{tw = TwInit,
tref = TRef}
= S) ->
cancel(TRef),
- S#watchdog{tref = erlang:start_timer(tw(TwInit), self(), tw)}.
+ S#watchdog{tref = erlang:start_timer(tw(TwInit), self(), tw)};
+set_watchdog(stop = No) ->
+ No.
cancel(undefined) ->
ok;
diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl
index 80036879ea..e687145263 100644
--- a/lib/diameter/src/compiler/diameter_codegen.erl
+++ b/lib/diameter/src/compiler/diameter_codegen.erl
@@ -574,12 +574,12 @@ cs_enumerated_avp({AvpName, Values}) ->
lists:flatmap(fun(V) -> c_enumerated_avp(AvpName, V) end, Values).
c_enumerated_avp(AvpName, {_,I}) ->
- [{?clause, [?ATOM(decode), ?Atom(AvpName), ?TERM(<<I:32/integer>>)],
+ [{?clause, [?ATOM(decode), ?Atom(AvpName), ?TERM(<<I:32>>)],
[],
[?TERM(I)]},
{?clause, [?ATOM(encode), ?Atom(AvpName), ?INTEGER(I)],
[],
- [?TERM(<<I:32/integer>>)]}].
+ [?TERM(<<I:32>>)]}].
%%% ------------------------------------------------------------------------
%%% msg_header/1
@@ -700,7 +700,7 @@ c_empty_value({Name, _, _, _}) ->
c_empty_value({Name, _}) ->
{?clause, [?Atom(Name)],
[],
- [?TERM(<<0:32/integer>>)]}.
+ [?TERM(<<0:32>>)]}.
%%% ------------------------------------------------------------------------
%%% # dict/0
diff --git a/lib/diameter/test/diameter_3xxx_SUITE.erl b/lib/diameter/test/diameter_3xxx_SUITE.erl
index 89c78d8b57..071b1a1177 100644
--- a/lib/diameter/test/diameter_3xxx_SUITE.erl
+++ b/lib/diameter/test/diameter_3xxx_SUITE.erl
@@ -40,9 +40,10 @@
send_unknown_application/1,
send_unknown_command/1,
send_ok/1,
- send_invalid_avp_bits/1,
+ send_invalid_hdr_bits/1,
send_missing_avp/1,
send_ignore_missing_avp/1,
+ send_5xxx_missing_avp/1,
send_double_error/1,
send_3xxx/1,
send_5xxx/1,
@@ -136,9 +137,10 @@ tc() ->
[send_unknown_application,
send_unknown_command,
send_ok,
- send_invalid_avp_bits,
+ send_invalid_hdr_bits,
send_missing_avp,
send_ignore_missing_avp,
+ send_5xxx_missing_avp,
send_double_error,
send_3xxx,
send_5xxx].
@@ -216,27 +218,26 @@ send_ok([_,_]) ->
send_ok(Config) ->
send_ok(?group(Config)).
-%% send_invalid_avp_bits/1
+%% send_invalid_hdr_bits/1
%%
-%% Send a request with an incorrect length on the optional
-%% Origin-State-Id that a callback ignores.
+%% Send a request with an incorrect E-bit that a callback ignores.
%% Callback answers.
-send_invalid_avp_bits([callback, _]) ->
+send_invalid_hdr_bits([callback, _]) ->
#diameter_base_STA{'Result-Code' = 2001, %% SUCCESS
'Failed-AVP' = [],
'AVP' = []}
= call();
%% diameter answers.
-send_invalid_avp_bits([_,_]) ->
- #'diameter_base_answer-message'{'Result-Code' = 3009, %% INVALID_AVP_BITS
+send_invalid_hdr_bits([_,_]) ->
+ #'diameter_base_answer-message'{'Result-Code' = 3008, %% INVALID_HDR_BITS
'Failed-AVP' = [],
'AVP' = []}
= call();
-send_invalid_avp_bits(Config) ->
- send_invalid_avp_bits(?group(Config)).
+send_invalid_hdr_bits(Config) ->
+ send_invalid_hdr_bits(?group(Config)).
%% send_missing_avp/1
%%
@@ -280,10 +281,35 @@ send_ignore_missing_avp([_,_]) ->
send_ignore_missing_avp(Config) ->
send_ignore_missing_avp(?group(Config)).
+%% send_5xxx_missing_avp/1
+%%
+%% Send a request with a missing AVP that a callback answers
+%% with {answer_message, 5005}.
+
+%% RFC 6733 allows 5xxx in an answer-message.
+send_5xxx_missing_avp([_, rfc6733]) ->
+ #'diameter_base_answer-message'{'Result-Code' = 5005, %% MISSING_AVP
+ 'Failed-AVP' = [_],
+ 'AVP' = []}
+ = call();
+
+%% RFC 3588 doesn't: sending answer fails.
+send_5xxx_missing_avp([_, rfc3588]) ->
+ {error, timeout} = call();
+
+%% Callback answers, ignores the error
+send_5xxx_missing_avp([_,_]) ->
+ #diameter_base_STA{'Result-Code' = 2001, %% SUCCESS
+ 'Failed-AVP' = [],
+ 'AVP' = []}
+ = call();
+
+send_5xxx_missing_avp(Config) ->
+ send_5xxx_missing_avp(?group(Config)).
+
%% send_double_error/1
%%
-%% Send a request with both an incorrect length on the optional
-%% Origin-State-Id and a missing AVP.
+%% Send a request with both an invalid E-bit and a missing AVP.
%% Callback answers with STA.
send_double_error([callback, _]) ->
@@ -294,8 +320,8 @@ send_double_error([callback, _]) ->
%% diameter answers with answer-message.
send_double_error([_,_]) ->
- #'diameter_base_answer-message'{'Result-Code' = 3009, %% INVALID_AVP_BITS
- 'Failed-AVP' = [_],
+ #'diameter_base_answer-message'{'Result-Code' = 3008, %% INVALID_HDR_BITS
+ 'Failed-AVP' = [],
'AVP' = []}
= call();
@@ -392,24 +418,21 @@ prepare(Pkt, Caps, T)
T == send_5xxx ->
sta(Pkt, Caps);
-prepare(Pkt0, Caps, send_invalid_avp_bits) ->
- Req0 = sta(Pkt0, Caps),
- %% Append an Origin-State-Id with an incorrect AVP Length in order
- %% to force 3009.
- Req = Req0#diameter_base_STR{'Origin-State-Id' = [7]},
- #diameter_packet{bin = Bin}
+prepare(Pkt0, Caps, send_invalid_hdr_bits) ->
+ Req = sta(Pkt0, Caps),
+ %% Set the E-bit to force 3008.
+ #diameter_packet{bin = <<H:34, 0:1, T/bitstring>>}
= Pkt
= diameter_codec:encode(?DICT, Pkt0#diameter_packet{msg = Req}),
- Offset = size(Bin) - 12 + 5,
- <<H:Offset/binary, Len:24, T/binary>> = Bin,
- Pkt#diameter_packet{bin = <<H/binary, (Len + 2):24, T/binary>>};
+ Pkt#diameter_packet{bin = <<H:34, 1:1, T/bitstring>>};
prepare(Pkt0, Caps, send_double_error) ->
- dehost(prepare(Pkt0, Caps, send_invalid_avp_bits));
+ dehost(prepare(Pkt0, Caps, send_invalid_hdr_bits));
prepare(Pkt, Caps, T)
when T == send_missing_avp;
- T == send_ignore_missing_avp ->
+ T == send_ignore_missing_avp;
+ T == send_5xxx_missing_avp ->
Req = sta(Pkt, Caps),
dehost(diameter_codec:encode(?DICT, Pkt#diameter_packet{msg = Req})).
@@ -480,9 +503,7 @@ request(send_3xxx, _Req, _Caps) ->
request(send_5xxx, _Req, _Caps) ->
{answer_message, 5999};
-request(send_invalid_avp_bits, Req, Caps) ->
- #diameter_base_STR{'Origin-State-Id' = []}
- = Req,
+request(send_invalid_hdr_bits, Req, Caps) ->
%% Default errors field but a non-answer-message and only 3xxx
%% errors detected means diameter sets neither Result-Code nor
%% Failed-AVP.
@@ -495,7 +516,10 @@ request(T, Req, Caps)
request(send_ignore_missing_avp, Req, Caps) ->
{reply, #diameter_packet{msg = answer(Req, Caps),
- errors = false}}. %% ignore errors
+ errors = false}}; %% ignore errors
+
+request(send_5xxx_missing_avp, _Req, _Caps) ->
+ {answer_message, 5005}. %% MISSING_AVP
answer(Req, Caps) ->
#diameter_base_STR{'Session-Id' = SId}
diff --git a/lib/diameter/test/diameter_app_SUITE.erl b/lib/diameter/test/diameter_app_SUITE.erl
index 209f72adf1..1e262895a6 100644
--- a/lib/diameter/test/diameter_app_SUITE.erl
+++ b/lib/diameter/test/diameter_app_SUITE.erl
@@ -56,7 +56,7 @@
%% ===========================================================================
suite() ->
- [{timetrap, {seconds, 10}}].
+ [{timetrap, {seconds, 60}}].
all() ->
[keys,
diff --git a/lib/diameter/test/diameter_codec_SUITE_data/diameter_test_unknown.erl b/lib/diameter/test/diameter_codec_SUITE_data/diameter_test_unknown.erl
index bce3d78a37..49f2158b1a 100644
--- a/lib/diameter/test/diameter_codec_SUITE_data/diameter_test_unknown.erl
+++ b/lib/diameter/test/diameter_codec_SUITE_data/diameter_test_unknown.erl
@@ -71,6 +71,6 @@ dec('AR', #diameter_packet
dec('BR', #diameter_packet
{msg = #recv_BR{'Origin-Host' = ?HOST,
'Origin-Realm' = ?REALM},
- errors = [{5008, ?NOT_MANDATORY_YYY},
- {5001, ?MANDATORY_XXX}]}) ->
+ errors = [{5001, ?MANDATORY_XXX},
+ {5008, ?NOT_MANDATORY_YYY}]}) ->
ok.
diff --git a/lib/diameter/test/diameter_codec_test.erl b/lib/diameter/test/diameter_codec_test.erl
index 0baac59c1a..24d4c7665e 100644
--- a/lib/diameter/test/diameter_codec_test.erl
+++ b/lib/diameter/test/diameter_codec_test.erl
@@ -265,7 +265,7 @@ arity(M, Name, AvpName, Rec) ->
%% enum/3
enum(M, Name, {_,E}) ->
- B = <<E:32/integer>>,
+ B = <<E:32>>,
B = M:avp(encode, E, Name),
E = M:avp(decode, B, Name).
@@ -322,15 +322,15 @@ values('Unsigned64') ->
values('Float32') ->
E = (1 bsl 8) - 2,
F = (1 bsl 23) - 1,
- <<Mx:32/float>> = <<0:1/integer, E:8/integer, F:23/integer>>,
- <<Mn:32/float>> = <<1:1/integer, E:8/integer, F:23/integer>>,
+ <<Mx:32/float>> = <<0:1, E:8, F:23>>,
+ <<Mn:32/float>> = <<1:1, E:8, F:23>>,
{[0.0, infinity, '-infinity', Mx, Mn], [0]};
values('Float64') ->
E = (1 bsl 11) - 2,
F = (1 bsl 52) - 1,
- <<Mx:64/float>> = <<0:1/integer, E:11/integer, F:52/integer>>,
- <<Mn:64/float>> = <<1:1/integer, E:11/integer, F:52/integer>>,
+ <<Mx:64/float>> = <<0:1, E:11, F:52>>,
+ <<Mn:64/float>> = <<1:1, E:11, F:52>>,
{[0.0, infinity, '-infinity', Mx, Mn], [0]};
values('Address') ->
diff --git a/lib/diameter/test/diameter_distribution_SUITE.erl b/lib/diameter/test/diameter_distribution_SUITE.erl
index 01d3507b27..f069abbe2f 100644
--- a/lib/diameter/test/diameter_distribution_SUITE.erl
+++ b/lib/diameter/test/diameter_distribution_SUITE.erl
@@ -28,7 +28,7 @@
all/0]).
%% testcases
--export([enslave/1,
+-export([enslave/1, enslave/0,
ping/1,
start/1,
connect/1,
@@ -36,7 +36,7 @@
send_remote/1,
send_timeout/1,
send_failover/1,
- stop/1]).
+ stop/1, stop/0]).
%% diameter callbacks
-export([peer_up/3,
@@ -126,6 +126,9 @@ all() ->
%% Start four slave nodes, one to implement a Diameter server,
%% two three to implement a client.
+enslave() ->
+ [{timetrap, {seconds, 30*length(?NODES)}}].
+
enslave(Config) ->
Here = filename:dirname(code:which(?MODULE)),
Ebin = filename:join([Here, "..", "ebin"]),
@@ -225,6 +228,9 @@ connect(Config) ->
%%
%% Stop the slave nodes.
+stop() ->
+ [{timetrap, {seconds, 30*length(?NODES)}}].
+
stop(_Config) ->
[] = [{N,E} || {N,_} <- ?NODES,
{error, _, _} = E <- [ct_slave:stop(N)]].
diff --git a/lib/diameter/test/diameter_examples_SUITE.erl b/lib/diameter/test/diameter_examples_SUITE.erl
index 585fc9d3b8..1954bc319b 100644
--- a/lib/diameter/test/diameter_examples_SUITE.erl
+++ b/lib/diameter/test/diameter_examples_SUITE.erl
@@ -29,6 +29,7 @@
%% testcases
-export([dict/1, dict/0,
code/1,
+ slave/1, slave/0,
enslave/1,
start/1,
traffic/1,
@@ -65,11 +66,12 @@
%% ===========================================================================
suite() ->
- [{timetrap, {seconds, 45}}].
+ [{timetrap, {minutes, 2}}].
all() ->
[dict,
code,
+ slave,
enslave,
start,
traffic,
@@ -250,6 +252,29 @@ store(Path, Dict) ->
%% ===========================================================================
+%% slave/1
+%%
+%% Return how long slave start/stop is taking since it seems to be
+%% ridiculously long on some hosts.
+
+slave() ->
+ [{timetrap, {minutes, 10}}].
+
+slave(_) ->
+ T0 = now(),
+ {ok, Node} = ct_slave:start(?MODULE, ?TIMEOUTS),
+ T1 = now(),
+ T2 = rpc:call(Node, erlang, now, []),
+ {ok, Node} = ct_slave:stop(?MODULE),
+ now_diff([T0, T1, T2, now()]).
+
+now_diff([T1,T2|_] = Ts) ->
+ [timer:now_diff(T2,T1) | now_diff(tl(Ts))];
+now_diff(_) ->
+ [].
+
+%% ===========================================================================
+
%% enslave/1
%%
%% Start two nodes: one for the server, one for the client.
diff --git a/lib/diameter/test/diameter_gen_tcp_SUITE.erl b/lib/diameter/test/diameter_gen_tcp_SUITE.erl
new file mode 100644
index 0000000000..7e232edb44
--- /dev/null
+++ b/lib/diameter/test/diameter_gen_tcp_SUITE.erl
@@ -0,0 +1,106 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%% Some gen_sctp-specific tests demonstrating problems that were
+%% encountered during diameter development but have nothing
+%% specifically to do with diameter. At least one of them can cause
+%% diameter_traffic_SUITE testcases to fail.
+%%
+
+-module(diameter_gen_tcp_SUITE).
+
+-export([suite/0,
+ all/0]).
+
+%% testcases
+-export([send_long/1]).
+
+-define(LOOPBACK, {127,0,0,1}).
+-define(GEN_OPTS, [binary, {active, true}, {ip, ?LOOPBACK}]).
+
+%% ===========================================================================
+
+suite() ->
+ [{timetrap, {minutes, 2}}].
+
+all() ->
+ [send_long].
+
+%% ===========================================================================
+
+%% send_long/1
+%%
+%% Test that a long message is received.
+
+send_long(_) ->
+ {Sock, SendF} = connection(),
+ B = list_to_binary(lists:duplicate(1 bsl 20, $X)),
+ ok = SendF(B),
+ B = recv(Sock, size(B), []).
+
+recv(_, 0, Acc) ->
+ list_to_binary(lists:reverse(Acc));
+recv(Sock, N, Acc) ->
+ receive
+ {tcp, Sock, Bin} ->
+ recv(Sock, N - size(Bin), [Bin | Acc]);
+ T ->
+ {T, Acc}
+ end.
+
+%% connection/0
+
+connection() ->
+ {ok, LSock} = gen_tcp:listen(0, ?GEN_OPTS),
+ {ok, PortNr} = inet:port(LSock),
+ LPid = self(),
+ {Pid, MRef} = spawn_monitor(fun() -> connect(PortNr, LPid) end),
+ {ok, Sock} = gen_tcp:accept(LSock),
+ receive
+ {Pid, F} ->
+ {Sock, F};
+ {'DOWN', MRef, process, _, _} = T ->
+ T
+ end.
+
+%% connect/2
+
+connect(PortNr, LPid) ->
+ {ok, Sock} = gen_tcp:connect(?LOOPBACK, PortNr, ?GEN_OPTS),
+ LPid ! {self(), fun(B) -> send(Sock, B) end},
+ down(LPid).
+
+%% down/1
+
+down(Pid)
+ when is_pid(Pid) ->
+ down(erlang:monitor(process, Pid));
+
+down(MRef) ->
+ receive {'DOWN', MRef, process, _, Reason} -> Reason end.
+
+%% send/2
+%%
+%% Send from a spawned process just to avoid sending from the
+%% receiving process, in case it's significant.
+
+send(Sock, Bin) ->
+ {_, MRef} = spawn_monitor(fun() -> exit(gen_tcp:send(Sock, Bin)) end),
+ down(MRef).
diff --git a/lib/diameter/test/diameter_tls_SUITE.erl b/lib/diameter/test/diameter_tls_SUITE.erl
index 5a79c63d36..55565692ec 100644
--- a/lib/diameter/test/diameter_tls_SUITE.erl
+++ b/lib/diameter/test/diameter_tls_SUITE.erl
@@ -181,7 +181,7 @@ start_diameter(_Config) ->
ok = diameter:start().
make_certs() ->
- [{timetrap, {seconds, 30}}].
+ [{timetrap, {minutes, 2}}].
make_certs(Config) ->
Dir = proplists:get_value(priv_dir, Config),
@@ -302,9 +302,7 @@ set([H|T], Vs) ->
disconnect({{LRef, _PortNr}, CRef}) ->
ok = diameter:remove_transport(?CLIENT, CRef),
- ok = receive #diameter_event{info = {down, LRef, _, _}} -> ok
- after 2000 -> false
- end.
+ receive #diameter_event{info = {down, LRef, _, _}} -> ok end.
realm(Host) ->
tl(lists:dropwhile(fun(C) -> C /= $. end, Host)).
@@ -365,13 +363,11 @@ ssl([{ssl_options = T, Opts}]) ->
connect(Host, {_LRef, PortNr}, {Caps, Opts}) ->
{ok, Ref} = diameter:add_transport(Host, ?CONNECT(PortNr, Caps, Opts)),
- ok = receive
- #diameter_event{service = Host,
- info = {up, Ref, _, _, #diameter_packet{}}} ->
- ok
- after 2000 ->
- false
- end,
+ receive
+ #diameter_event{service = Host,
+ info = {up, Ref, _, _, #diameter_packet{}}} ->
+ ok
+ end,
Ref.
copts(S, Opts)
diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl
index 781ed234cc..38bdf55af8 100644
--- a/lib/diameter/test/diameter_traffic_SUITE.erl
+++ b/lib/diameter/test/diameter_traffic_SUITE.erl
@@ -49,9 +49,12 @@
send_unsupported_app/1,
send_error_bit/1,
send_unsupported_version/1,
- send_invalid_avp_bits/1,
+ send_long_avp_length/1,
+ send_short_avp_length/1,
+ send_zero_avp_length/1,
send_invalid_avp_length/1,
send_invalid_reject/1,
+ send_unrecognized_mandatory/1,
send_long/1,
send_nopeer/1,
send_noapp/1,
@@ -268,9 +271,12 @@ tc() ->
send_unsupported_app,
send_error_bit,
send_unsupported_version,
- send_invalid_avp_bits,
+ send_long_avp_length,
+ send_short_avp_length,
+ send_zero_avp_length,
send_invalid_avp_length,
send_invalid_reject,
+ send_unrecognized_mandatory,
send_long,
send_nopeer,
send_noapp,
@@ -405,7 +411,7 @@ send_eval(Config) ->
send_bad_answer(Config) ->
Req = ['ACR', {'Accounting-Record-Type', ?EVENT_RECORD},
{'Accounting-Record-Number', 2}],
- {error, timeout} = call(Config, Req).
+ {timeout, _} = call(Config, Req).
%% Send an ACR that the server callback answers explicitly with a
%% protocol error.
@@ -416,13 +422,14 @@ send_protocol_error(Config) ->
?answer_message(?TOO_BUSY)
= call(Config, Req).
-%% Send an ASR with an arbitrary AVP and expect success and the same
-%% AVP in the reply.
+%% Send an ASR with an arbitrary non-mandatory AVP and expect success
+%% and the same AVP in the reply.
send_arbitrary(Config) ->
- Req = ['ASR', {'AVP', [#diameter_avp{name = 'Class', value = "XXX"}]}],
+ Req = ['ASR', {'AVP', [#diameter_avp{name = 'Product-Name',
+ value = "XXX"}]}],
['ASA', _SessionId, {'Result-Code', ?SUCCESS} | Avps]
= call(Config, Req),
- {'AVP', [#diameter_avp{name = 'Class',
+ {'AVP', [#diameter_avp{name = 'Product-Name',
value = "XXX"}]}
= lists:last(Avps).
@@ -455,7 +462,7 @@ send_unknown_mandatory(Config) ->
%% Send an STR that the server ignores.
send_noreply(Config) ->
Req = ['STR', {'Termination-Cause', ?BAD_ANSWER}],
- {error, timeout} = call(Config, Req).
+ {timeout, _} = call(Config, Req).
%% Send an unsupported command and expect 3001.
send_unsupported(Config) ->
@@ -481,19 +488,33 @@ send_unsupported_version(Config) ->
['STA', _SessionId, {'Result-Code', ?UNSUPPORTED_VERSION} | _]
= call(Config, Req).
-%% Send a request containing an incorrect AVP length.
-send_invalid_avp_bits(Config) ->
- Req = ['STR', {'Termination-Cause', ?LOGOUT}],
+%% Send a request containing an AVP length > data size.
+send_long_avp_length(Config) ->
+ send_invalid_avp_length(Config).
- ?answer_message(?INVALID_AVP_BITS)
- = call(Config, Req).
+%% Send a request containing an AVP length < data size.
+send_short_avp_length(Config) ->
+ send_invalid_avp_length(Config).
+
+%% Send a request containing an AVP whose advertised length is < 8.
+send_zero_avp_length(Config) ->
+ send_invalid_avp_length(Config).
%% Send a request containing an AVP length that doesn't match the
%% AVP's type.
send_invalid_avp_length(Config) ->
Req = ['STR', {'Termination-Cause', ?LOGOUT}],
- ['STA', _SessionId, {'Result-Code', ?INVALID_AVP_LENGTH} | _]
+ ['STA', _SessionId,
+ {'Result-Code', ?INVALID_AVP_LENGTH},
+ _OriginHost,
+ _OriginRealm,
+ _UserName,
+ _Class,
+ _ErrorMessage,
+ _ErrorReportingHost,
+ {'Failed-AVP', [#'diameter_base_Failed-AVP'{'AVP' = [_]}]}
+ | _]
= call(Config, Req).
%% Send a request containing 5xxx errors that the server rejects with
@@ -504,6 +525,14 @@ send_invalid_reject(Config) ->
?answer_message(?TOO_BUSY)
= call(Config, Req).
+%% Send an STR containing a known AVP, but one that's not allowed and
+%% sets the M-bit.
+send_unrecognized_mandatory(Config) ->
+ Req = ['STR', {'Termination-Cause', ?LOGOUT}],
+
+ ['STA', _SessionId, {'Result-Code', ?AVP_UNSUPPORTED} | _]
+ = call(Config, Req).
+
%% Send something long that will be fragmented by TCP.
send_long(Config) ->
Req = ['STR', {'Termination-Cause', ?LOGOUT},
@@ -552,7 +581,7 @@ send_all_2(Config) ->
%% Timeout before the server manages an answer.
send_timeout(Config) ->
Req = ['RAR', {'Re-Auth-Request-Type', ?AUTHORIZE_ONLY}],
- {error, timeout} = call(Config, Req, [{timeout, 1000}]).
+ {timeout, _} = call(Config, Req, [{timeout, 1000}]).
%% Explicitly answer with an answer-message and ensure that we
%% received the Session-Id.
@@ -560,7 +589,7 @@ send_error(Config) ->
Req = ['RAR', {'Re-Auth-Request-Type', ?AUTHORIZE_AUTHENTICATE}],
?answer_message(SId, ?TOO_BUSY)
= call(Config, Req),
- undefined /= SId.
+ true = undefined /= SId.
%% Send a request with the detached option and receive it as a message
%% from handle_answer instead.
@@ -568,7 +597,7 @@ send_detach(Config) ->
Req = ['STR', {'Termination-Cause', ?LOGOUT}],
Ref = make_ref(),
ok = call(Config, Req, [{extra, [{self(), Ref}]}, detach]),
- Ans = receive {Ref, T} -> T after 2000 -> false end,
+ Ans = receive {Ref, T} -> T end,
['STA', _SessionId, {'Result-Code', ?SUCCESS} | _]
= Ans.
@@ -683,7 +712,7 @@ call(Config, Req, Opts) ->
diameter:call(?CLIENT,
dict(Req, Dict0),
msg(Req, ReqEncoding, Dict0),
- [{extra, [Name, Group]} | Opts]).
+ [{extra, [{Name, Group}, now()]} | Opts]).
origin({A,C}) ->
2*codec(A) + container(C);
@@ -767,14 +796,14 @@ peer_down(_SvcName, _Peer, State) ->
%% pick_peer/6-7
-pick_peer(Peers, _, ?CLIENT, _State, Name, Group)
+pick_peer(Peers, _, ?CLIENT, _State, {Name, Group}, _)
when Name /= send_detach ->
find(Group, Peers).
-pick_peer(_Peers, _, ?CLIENT, _State, send_nopeer, _, ?EXTRA) ->
+pick_peer(_Peers, _, ?CLIENT, _State, {send_nopeer, _}, _, ?EXTRA) ->
false;
-pick_peer(Peers, _, ?CLIENT, _State, send_detach, Group, {_,_}) ->
+pick_peer(Peers, _, ?CLIENT, _State, {send_detach, Group}, _, {_,_}) ->
find(Group, Peers).
find(#group{server_encoding = A, server_container = C}, Peers) ->
@@ -789,13 +818,13 @@ id(Id, {Pid, _Caps}) ->
%% prepare_request/5-6
-prepare_request(_Pkt, ?CLIENT, {_Ref, _Caps}, send_discard, _) ->
+prepare_request(_Pkt, ?CLIENT, {_Ref, _Caps}, {send_discard, _}, _) ->
{discard, unprepared};
-prepare_request(Pkt, ?CLIENT, {_Ref, Caps}, Name, Group) ->
+prepare_request(Pkt, ?CLIENT, {_Ref, Caps}, {Name, Group}, _) ->
{send, prepare(Pkt, Caps, Name, Group)}.
-prepare_request(Pkt, ?CLIENT, {_Ref, Caps}, send_detach, Group, _) ->
+prepare_request(Pkt, ?CLIENT, {_Ref, Caps}, {send_detach, Group}, _, _) ->
{eval_packet, {send, prepare(Pkt, Caps, Group)}, [fun log/2, detach]}.
log(#diameter_packet{bin = Bin} = P, T)
@@ -804,45 +833,63 @@ log(#diameter_packet{bin = Bin} = P, T)
%% prepare/4
-prepare(Pkt, Caps, send_invalid_avp_bits, #group{client_dict0 = Dict0}
- = Group) ->
+prepare(Pkt, Caps, N, #group{client_dict0 = Dict0} = Group)
+ when N == send_long_avp_length;
+ N == send_short_avp_length;
+ N == send_zero_avp_length ->
Req = prepare(Pkt, Caps, Group),
- %% Last AVP in our STR is Termination-Cause of type Unsigned32:
- %% set its length improperly.
+ %% Second last AVP in our STR is Auth-Application-Id of type
+ %% Unsigned32: set AVP Length to a value other than 12 and place
+ %% it last in the message (so as not to mess with Termination-Cause).
#diameter_packet{header = #diameter_header{length = L},
bin = B}
= E
= diameter_codec:encode(Dict0, Pkt#diameter_packet{msg = Req}),
- Offset = L - 7, %% to AVP Length
- <<H:Offset/binary, 12:24/integer, T:4/binary>> = B,
- E#diameter_packet{bin = <<H/binary, 13:24/integer, T/binary>>};
+ Offset = L - 24, %% to Auth-Application-Id
+ <<H:Offset/binary,
+ Hdr:5/binary, 12:24, Data:4/binary,
+ T:12/binary>>
+ = B,
+ AL = case N of
+ send_long_avp_length -> 13;
+ send_short_avp_length -> 11;
+ send_zero_avp_length -> 0
+ end,
+ E#diameter_packet{bin = <<H/binary,
+ T/binary,
+ Hdr/binary, AL:24, Data/binary>>};
prepare(Pkt, Caps, N, #group{client_dict0 = Dict0} = Group)
when N == send_invalid_avp_length;
N == send_invalid_reject ->
Req = prepare(Pkt, Caps, Group),
%% Second last AVP in our STR is Auth-Application-Id of type
- %% Unsigned32: Send a value of length 8.
+ %% Unsigned32: send data of length 8.
#diameter_packet{header = #diameter_header{length = L},
bin = B0}
= E
= diameter_codec:encode(Dict0, Pkt#diameter_packet{msg = Req}),
Offset = L - 7 - 12, %% to AVP Length
- <<H0:Offset/binary, 12:24/integer, T:16/binary>> = B0,
- <<V, L:24/integer, H/binary>> = H0, %% assert
- E#diameter_packet{bin = <<V,
- (L+4):24/integer,
- H/binary,
- 16:24/integer,
- 0:32/integer,
- T/binary>>};
+ <<H0:Offset/binary, 12:24, T:16/binary>> = B0,
+ <<V, L:24, H/binary>> = H0, %% assert
+ E#diameter_packet{bin = <<V, (L+4):24, H/binary, 16:24, 0:32, T/binary>>};
+
+prepare(Pkt, Caps, send_unrecognized_mandatory, #group{client_dict0 = Dict0}
+ = Group) ->
+ Req = prepare(Pkt, Caps, Group),
+ #diameter_packet{bin = <<V, Len:24, T/binary>>}
+ = E
+ = diameter_codec:encode(Dict0, Pkt#diameter_packet{msg = Req}),
+ {Code, Flags, undefined} = Dict0:avp_header('Proxy-State'),
+ Avp = <<Code:32, Flags, 8:24>>,
+ E#diameter_packet{bin = <<V, (Len+8):24, T/binary, Avp/binary>>};
prepare(Pkt, Caps, send_unsupported, #group{client_dict0 = Dict0} = Group) ->
Req = prepare(Pkt, Caps, Group),
#diameter_packet{bin = <<H:5/binary, _CmdCode:3/binary, T/binary>>}
= E
= diameter_codec:encode(Dict0, Pkt#diameter_packet{msg = Req}),
- E#diameter_packet{bin = <<H/binary, 42:24/integer, T/binary>>};
+ E#diameter_packet{bin = <<H/binary, 42:24, T/binary>>};
prepare(Pkt, Caps, send_unsupported_app, #group{client_dict0 = Dict0}
= Group) ->
@@ -850,7 +897,7 @@ prepare(Pkt, Caps, send_unsupported_app, #group{client_dict0 = Dict0}
#diameter_packet{bin = <<H:8/binary, _ApplId:4/binary, T/binary>>}
= E
= diameter_codec:encode(Dict0, Pkt#diameter_packet{msg = Req}),
- E#diameter_packet{bin = <<H/binary, ?BAD_APP:32/integer, T/binary>>};
+ E#diameter_packet{bin = <<H/binary, ?BAD_APP:32, T/binary>>};
prepare(Pkt, Caps, send_error_bit, Group) ->
#diameter_packet{header = Hdr} = Pkt,
@@ -928,10 +975,10 @@ prepare_retransmit(_Pkt, false, _Peer, _Name, _Group) ->
%% handle_answer/6-7
-handle_answer(Pkt, Req, ?CLIENT, Peer, Name, Group) ->
+handle_answer(Pkt, Req, ?CLIENT, Peer, {Name, Group}, _) ->
answer(Pkt, Req, Peer, Name, Group).
-handle_answer(Pkt, Req, ?CLIENT, Peer, send_detach = Name, Group, X) ->
+handle_answer(Pkt, Req, ?CLIENT, Peer, {send_detach = Name, Group}, _, X) ->
{Pid, Ref} = X,
Pid ! {Ref, answer(Pkt, Req, Peer, Name, Group)}.
@@ -944,7 +991,9 @@ answer(Pkt, Req, _Peer, Name, #group{client_dict0 = Dict0}) ->
[Dict:rec2msg(R) | Vs].
answer(Rec, [_|_], N)
- when N == send_invalid_avp_bits;
+ when N == send_long_avp_length;
+ N == send_short_avp_length;
+ N == send_zero_avp_length;
N == send_invalid_avp_length;
N == send_invalid_reject ->
Rec;
@@ -959,7 +1008,11 @@ app(Req, _, Dict0) ->
%% handle_error/6
-handle_error(Reason, _Req, ?CLIENT, _Peer, _Name, _Group) ->
+handle_error(timeout = Reason, _Req, ?CLIENT, _Peer, _, Time) ->
+ Now = now(),
+ {Reason, {Time, Now, timer:now_diff(Now, Time)}};
+
+handle_error(Reason, _Req, ?CLIENT, _Peer, _, _Time) ->
{error, Reason}.
%% handle_request/3
@@ -1085,7 +1138,6 @@ request(#diameter_base_STR{'Session-Id' = SId},
{'Origin-Host', OH},
{'Origin-Realm', OR}]};
-%% send_error
+%% send_error/send_timeout
request(#diameter_base_RAR{}, _Caps) ->
- receive after 2000 -> ok end,
- {protocol_error, ?TOO_BUSY}.
+ receive after 2000 -> {protocol_error, ?TOO_BUSY} end.
diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk
index 1a829f8031..4fea62461c 100644
--- a/lib/diameter/test/modules.mk
+++ b/lib/diameter/test/modules.mk
@@ -38,6 +38,7 @@ MODULES = \
diameter_examples_SUITE \
diameter_failover_SUITE \
diameter_gen_sctp_SUITE \
+ diameter_gen_tcp_SUITE \
diameter_length_SUITE \
diameter_reg_SUITE \
diameter_relay_SUITE \
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index f6b13c2998..55794f57dc 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -33,7 +33,6 @@
%% connect_and_send/2,
send/2,
cancel/3,
- stream/3,
stream_next/1,
info/1
]).
@@ -65,7 +64,7 @@
options, % #options{}
timers = #timers{}, % #timers{}
profile_name, % atom() - id of httpc_manager process.
- once % send | undefined
+ once = inactive % inactive | once
}).
@@ -231,6 +230,8 @@ init([Parent, Request, Options, ProfileName]) ->
ProxyOptions = handle_proxy_options(Request#request.scheme, Options),
Address = handle_proxy(Request#request.address, ProxyOptions),
{ok, State} =
+ %% #state.once should initially be 'inactive' because we
+ %% activate the socket at first regardless of the state.
case {Address /= Request#request.address, Request#request.scheme} of
{true, https} ->
connect_and_send_upgrade_request(Address, Request,
@@ -425,7 +426,9 @@ handle_cast({cancel, RequestId, From},
handle_cast(stream_next, #state{session = Session} = State) ->
activate_once(Session),
- {noreply, State#state{once = once}}.
+ %% Inactivate the #state.once here because we don't want
+ %% next_body_chunk/1 to activate the socket twice.
+ {noreply, State#state{once = inactive}}.
%%--------------------------------------------------------------------
@@ -478,6 +481,41 @@ handle_info({Proto, _Socket, Data},
NewMFA = {Module, whole_body, [NewBody, NewLength]},
{noreply, NewState#state{mfa = NewMFA,
request = NewRequest}};
+ {Module, decode_size,
+ [TotalChunk, HexList,
+ {MaxBodySize, BodySoFar, AccLength, MaxHeaderSize}]}
+ when BodySoFar =/= <<>> ->
+ ?hcrd("data processed - decode_size", []),
+ %% The response body is chunk-encoded. Steal decoded
+ %% chunks as much as possible to stream.
+ {_, Code, _} = StatusLine,
+ {NewBody, NewRequest} = stream(BodySoFar, Request, Code),
+ NewState = next_body_chunk(State),
+ NewMFA = {Module, decode_size,
+ [TotalChunk, HexList,
+ {MaxBodySize, NewBody, AccLength, MaxHeaderSize}]},
+ {noreply, NewState#state{mfa = NewMFA,
+ request = NewRequest}};
+ {Module, decode_data,
+ [ChunkSize, TotalChunk,
+ {MaxBodySize, BodySoFar, AccLength, MaxHeaderSize}]}
+ when TotalChunk =/= <<>> orelse BodySoFar =/= <<>> ->
+ ?hcrd("data processed - decode_data", []),
+ %% The response body is chunk-encoded. Steal decoded
+ %% chunks as much as possible to stream.
+ ChunkSizeToSteal = min(ChunkSize, byte_size(TotalChunk)),
+ <<StolenChunk:ChunkSizeToSteal/binary, NewTotalChunk/binary>> = TotalChunk,
+ StolenBody = <<BodySoFar/binary, StolenChunk/binary>>,
+ NewChunkSize = ChunkSize - ChunkSizeToSteal,
+ {_, Code, _} = StatusLine,
+
+ {NewBody, NewRequest} = stream(StolenBody, Request, Code),
+ NewState = next_body_chunk(State),
+ NewMFA = {Module, decode_data,
+ [NewChunkSize, NewTotalChunk,
+ {MaxBodySize, NewBody, AccLength, MaxHeaderSize}]},
+ {noreply, NewState#state{mfa = NewMFA,
+ request = NewRequest}};
NewMFA ->
?hcrd("data processed - new mfa", []),
activate_once(Session),
@@ -1027,11 +1065,15 @@ handle_http_msg({Version, StatusCode, ReasonPharse, Headers, Body},
status_line = StatusLine,
headers = Headers})
end;
-handle_http_msg({ChunkedHeaders, Body}, #state{headers = Headers} = State) ->
+handle_http_msg({ChunkedHeaders, Body},
+ #state{status_line = {_, Code, _}, headers = Headers} = State) ->
?hcrt("handle_http_msg",
[{chunked_headers, ChunkedHeaders}, {headers, Headers}]),
NewHeaders = http_chunk:handle_headers(Headers, ChunkedHeaders),
- handle_response(State#state{headers = NewHeaders, body = Body});
+ {NewBody, NewRequest} = stream(Body, State#state.request, Code),
+ handle_response(State#state{headers = NewHeaders,
+ body = NewBody,
+ request = NewRequest});
handle_http_msg(Body, #state{status_line = {_,Code, _}} = State) ->
?hcrt("handle_http_msg", [{code, Code}]),
{NewBody, NewRequest} = stream(Body, State#state.request, Code),
@@ -1070,8 +1112,7 @@ handle_http_body(Body, #state{headers = Headers,
"chunked" ->
?hcrt("handle_http_body - chunked", []),
case http_chunk:decode(Body, State#state.max_body_size,
- State#state.max_header_size,
- {Code, Request}) of
+ State#state.max_header_size) of
{Module, Function, Args} ->
?hcrt("handle_http_body - new mfa",
[{module, Module},
diff --git a/lib/inets/src/http_lib/http_chunk.erl b/lib/inets/src/http_lib/http_chunk.erl
index 57647438e9..24c939e80c 100644
--- a/lib/inets/src/http_lib/http_chunk.erl
+++ b/lib/inets/src/http_lib/http_chunk.erl
@@ -24,7 +24,7 @@
-include("http_internal.hrl").
%% API
--export([decode/3, decode/4, encode/1, encode_last/0, handle_headers/2]).
+-export([decode/3, encode/1, encode_last/0, handle_headers/2]).
%% Callback API - used for example if the chunkedbody is received a
%% little at a time on a socket.
-export([decode_size/1, ignore_extensions/1, decode_data/1, decode_trailer/1]).
@@ -34,20 +34,14 @@
%%% API
%%%=========================================================================
%%-------------------------------------------------------------------------
-%% decode(ChunkedBody, MaxBodySize, MaxHeaderSize, <Stream>) ->
+%% decode(ChunkedBody, MaxBodySize, MaxHeaderSize) ->
%% {ok, {Headers, Body}} | {Module, Function, Args}
%%
%% Headers = ["Header:Value"]
%% ChunkedBody = binary()
%% MaxBodySize = integer()
%% MaxHeaderSize = integer()
-%% Stream = {Code, Request} - if Request#request.stream =/= none
-%% and Code == 200 the side effect of sending each decode chunk to the
-%% client/file before the whole body is received will take place.
%%
-%% Note: decode/4 should only be used from httpc_handler module.
-%% Otherwhise use the side effect free decode/3.
-%%
%% Description: Decodes a body encoded by the chunked transfer
%% encoding. If the ChunkedBody is not compleate it returns {Module,
%% Function, Args} so that decoding can be continued when more of the
@@ -61,12 +55,9 @@
%% the next pass in the loop.
%%-------------------------------------------------------------------------
decode(ChunkedBody, MaxBodySize, MaxHeaderSize) ->
- decode(ChunkedBody, MaxBodySize, MaxHeaderSize, false).
-
-decode(ChunkedBody, MaxBodySize, MaxHeaderSize, Stream) ->
%% Note decode_size will call decode_data.
- decode_size([ChunkedBody, <<>>, [],
- {MaxBodySize, <<>>, 0, MaxHeaderSize, Stream}]).
+ decode_size([ChunkedBody, <<>>, [],
+ {MaxBodySize, <<>>, 0, MaxHeaderSize}]).
%%-------------------------------------------------------------------------
%% encode(Chunk) -> EncodedChunk
@@ -150,7 +141,7 @@ decode_size(<<>>, HexList, Info) ->
decode_size(Data = <<?CR, ?LF, ChunkRest/binary>>, HexList,
{MaxBodySize, Body,
AccLength,
- MaxHeaderSize, Stream}) ->
+ MaxHeaderSize}) ->
ChunkSize = http_util:hexlist_to_integer(lists:reverse(HexList)),
case ChunkSize of
0 -> % Last chunk, there was no data
@@ -164,7 +155,7 @@ decode_size(Data = <<?CR, ?LF, ChunkRest/binary>>, HexList,
%% to this function comes in.
decode_data(ChunkSize, ChunkRest, {MaxBodySize, Body,
ChunkSize + AccLength ,
- MaxHeaderSize, Stream})
+ MaxHeaderSize})
end;
decode_size(<<";", Rest/binary>>, HexList, Info) ->
%% Note ignore_extensions will call decode_size/1 again when
@@ -189,50 +180,42 @@ ignore_extensions(<<_Octet, Rest/binary>>, NextFunction) ->
ignore_extensions(Rest, NextFunction).
decode_data(ChunkSize, TotalChunk,
- Info = {MaxBodySize, BodySoFar, AccLength, MaxHeaderSize, Stream})
+ Info = {MaxBodySize, BodySoFar, AccLength, MaxHeaderSize})
when ChunkSize =< size(TotalChunk) ->
case TotalChunk of
%% Last chunk
<<Data:ChunkSize/binary, ?CR, ?LF, "0", ";">> ->
%% Note ignore_extensions will call decode_trailer/1
%% once it ignored all extensions.
- {NewBody, _} =
- stream(<<BodySoFar/binary, Data/binary>>, Stream),
{?MODULE, ignore_extensions,
[<<>>,
{?MODULE, decode_trailer, [<<>>, [],[], MaxHeaderSize,
- NewBody,
+ <<BodySoFar/binary, Data/binary>>,
integer_to_list(AccLength)]}]};
<<Data:ChunkSize/binary, ?CR, ?LF, "0", ";", Rest/binary>> ->
%% Note ignore_extensions will call decode_trailer/1
%% once it ignored all extensions.
- {NewBody, _} = stream(<<BodySoFar/binary, Data/binary>>, Stream),
ignore_extensions(Rest, {?MODULE, decode_trailer,
[<<>>, [],[], MaxHeaderSize,
- NewBody,
+ <<BodySoFar/binary, Data/binary>>,
integer_to_list(AccLength)]});
<<Data:ChunkSize/binary, ?CR, ?LF, "0", ?CR, ?LF>> ->
- {NewBody, _} = stream(<<BodySoFar/binary, Data/binary>>, Stream),
{?MODULE, decode_trailer, [<<?CR, ?LF>>, [],[], MaxHeaderSize,
- NewBody,
+ <<BodySoFar/binary, Data/binary>>,
integer_to_list(AccLength)]};
<<Data:ChunkSize/binary, ?CR, ?LF, "0", ?CR, ?LF, Rest/binary>> ->
- {NewBody,_}= stream(<<BodySoFar/binary, Data/binary>>, Stream),
decode_trailer(<<?CR, ?LF, Rest/binary>>, [],[], MaxHeaderSize,
- NewBody,
+ <<BodySoFar/binary, Data/binary>>,
integer_to_list(AccLength));
%% There are more chunks, so here we go agin...
<<Data:ChunkSize/binary, ?CR, ?LF>> ->
- {NewBody, NewStream} =
- stream(<<BodySoFar/binary, Data/binary>>, Stream),
- {?MODULE, decode_size, [<<>>, [], {MaxBodySize, NewBody, AccLength, MaxHeaderSize, NewStream}]};
+ NewBody = <<BodySoFar/binary, Data/binary>>,
+ {?MODULE, decode_size, [<<>>, [], {MaxBodySize, NewBody, AccLength, MaxHeaderSize}]};
<<Data:ChunkSize/binary, ?CR, ?LF, Rest/binary>>
when (AccLength < MaxBodySize) or (MaxBodySize == nolimit) ->
- {NewBody, NewStream} =
- stream(<<BodySoFar/binary, Data/binary>>, Stream),
decode_size(Rest, [],
- {MaxBodySize, NewBody,
- AccLength, MaxHeaderSize, NewStream});
+ {MaxBodySize, <<BodySoFar/binary, Data/binary>>,
+ AccLength, MaxHeaderSize});
<<_:ChunkSize/binary, ?CR, ?LF, _/binary>> ->
throw({error, body_too_big});
_ ->
@@ -286,9 +269,3 @@ decode_trailer(<<Octet, Rest/binary>>, Header, Headers, MaxHeaderSize, Body,
BodyLength) ->
decode_trailer(Rest, [Octet | Header], Headers, MaxHeaderSize,
Body, BodyLength).
-
-stream(BodyPart, false) ->
- {BodyPart, false};
-stream(BodyPart, {Code, Request}) ->
- {NewBody, NewRequest} = httpc_handler:stream(BodyPart, Request, Code),
- {NewBody, {Code, NewRequest}}.
diff --git a/lib/inets/test/erl_make_certs.erl b/lib/inets/test/erl_make_certs.erl
index 5b92e551a5..22dc951ac1 100644
--- a/lib/inets/test/erl_make_certs.erl
+++ b/lib/inets/test/erl_make_certs.erl
@@ -45,7 +45,7 @@
%% {dnQualifer, DnQ}
%% issuer = {Issuer, IssuerKey} true (i.e. a ca cert is created)
%% (obs IssuerKey migth be {Key, Password}
-%% key = KeyFile|KeyBin|rsa|dsa Subject PublicKey rsa or dsa generates key
+%% key = KeyFile|KeyBin|rsa|dsa|ec Subject PublicKey rsa, dsa or ec generates key
%%
%%
%% (OBS: The generated keys are for testing only)
@@ -91,6 +91,16 @@ gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) ->
{Key, encode_key(Key)}.
%%--------------------------------------------------------------------
+%% @doc Creates a ec key (OBS: for testing only)
+%% the sizes are in bytes
+%% @spec (::integer()) -> {::atom(), ::binary(), ::opaque()}
+%% @end
+%%--------------------------------------------------------------------
+gen_ec(Curve) when is_atom(Curve) ->
+ Key = gen_ec2(Curve),
+ {Key, encode_key(Key)}.
+
+%%--------------------------------------------------------------------
%% @doc Verifies cert signatures
%% @spec (::binary(), ::tuple()) -> ::boolean()
%% @end
@@ -102,7 +112,10 @@ verify_signature(DerEncodedCert, DerKey, _KeyParams) ->
public_key:pkix_verify(DerEncodedCert,
#'RSAPublicKey'{modulus=Mod, publicExponent=Exp});
#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} ->
- public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}})
+ public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}});
+ #'ECPrivateKey'{version = _Version, privateKey = _PrivKey,
+ parameters = Params, publicKey = {0, PubKey}} ->
+ public_key:pkix_verify(DerEncodedCert, {#'ECPoint'{point = PubKey}, Params})
end.
%%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -112,6 +125,7 @@ get_key(Opts) ->
undefined -> make_key(rsa, Opts);
rsa -> make_key(rsa, Opts);
dsa -> make_key(dsa, Opts);
+ ec -> make_key(ec, Opts);
Key ->
Password = proplists:get_value(password, Opts, no_passwd),
decode_key(Key, Password)
@@ -129,6 +143,8 @@ decode_key(#'RSAPrivateKey'{} = Key,_) ->
Key;
decode_key(#'DSAPrivateKey'{} = Key,_) ->
Key;
+decode_key(#'ECPrivateKey'{} = Key,_) ->
+ Key;
decode_key(PemEntry = {_,_,_}, Pw) ->
public_key:pem_entry_decode(PemEntry, Pw);
decode_key(PemBin, Pw) ->
@@ -140,7 +156,10 @@ encode_key(Key = #'RSAPrivateKey'{}) ->
{'RSAPrivateKey', Der, not_encrypted};
encode_key(Key = #'DSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key),
- {'DSAPrivateKey', Der, not_encrypted}.
+ {'DSAPrivateKey', Der, not_encrypted};
+encode_key(Key = #'ECPrivateKey'{}) ->
+ {ok, Der} = 'OTP-PUB-KEY':encode('ECPrivateKey', Key),
+ {'ECPrivateKey', Der, not_encrypted}.
make_tbs(SubjectKey, Opts) ->
Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))),
@@ -277,7 +296,14 @@ publickey(#'RSAPrivateKey'{modulus=N, publicExponent=E}) ->
publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) ->
Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-dsa',
parameters={params, #'Dss-Parms'{p=P, q=Q, g=G}}},
- #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}.
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y};
+publickey(#'ECPrivateKey'{version = _Version,
+ privateKey = _PrivKey,
+ parameters = Params,
+ publicKey = {0, PubKey}}) ->
+ Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-ecPublicKey', parameters=Params},
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo,
+ subjectPublicKey = #'ECPoint'{point = PubKey}}.
validity(Opts) ->
DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1),
@@ -298,13 +324,24 @@ sign_algorithm(#'RSAPrivateKey'{}, Opts) ->
end,
{Type, 'NULL'};
sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) ->
- {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}}.
+ {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}};
+sign_algorithm(#'ECPrivateKey'{}, Opts) ->
+ Type = case proplists:get_value(digest, Opts, sha1) of
+ sha1 -> ?'ecdsa-with-SHA1';
+ sha512 -> ?'ecdsa-with-SHA512';
+ sha384 -> ?'ecdsa-with-SHA384';
+ sha256 -> ?'ecdsa-with-SHA256'
+ end,
+ {Type, 'NULL'}.
make_key(rsa, _Opts) ->
%% (OBS: for testing only)
gen_rsa2(64);
make_key(dsa, _Opts) ->
- gen_dsa2(128, 20). %% Bytes i.e. {1024, 160}
+ gen_dsa2(128, 20); %% Bytes i.e. {1024, 160}
+make_key(ec, _Opts) ->
+ %% (OBS: for testing only)
+ gen_ec2(secp256k1).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% RSA key generation (OBS: for testing only)
@@ -349,24 +386,37 @@ gen_dsa2(LSize, NSize) ->
X0 = prime(LSize),
P0 = prime((LSize div 2) +1),
- %% Choose L-bit prime modulus P such that p–1 is a multiple of q.
+ %% Choose L-bit prime modulus P such that p-1 is a multiple of q.
case dsa_search(X0 div (2*Q*P0), P0, Q, 1000) of
error ->
gen_dsa2(LSize, NSize);
P ->
- G = crypto:mod_exp(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q.
- %% such that This may be done by setting g = h^(p–1)/q mod p, commonly h=2 is used.
+ G = crypto:mod_pow(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q.
+ %% such that This may be done by setting g = h^(p-1)/q mod p, commonly h=2 is used.
X = prime(20), %% Choose x by some random method, where 0 < x < q.
- Y = crypto:mod_exp(G, X, P), %% Calculate y = g^x mod p.
+ Y = crypto:mod_pow(G, X, P), %% Calculate y = g^x mod p.
- #'DSAPrivateKey'{version=0, p=P, q=Q, g=G, y=Y, x=X}
+ #'DSAPrivateKey'{version=0, p = P, q = Q,
+ g = crypto:bytes_to_integer(G), y = crypto:bytes_to_integer(Y), x = X}
end.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EC key generation (OBS: for testing only)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+gen_ec2(CurveId) ->
+ {PubKey, PrivKey} = crypto:generate_key(ecdh, CurveId),
+
+ #'ECPrivateKey'{version = 1,
+ privateKey = binary_to_list(PrivKey),
+ parameters = {namedCurve, pubkey_cert_records:namedCurves(CurveId)},
+ publicKey = {0, PubKey}}.
+
%% See fips_186-3.pdf
dsa_search(T, P0, Q, Iter) when Iter > 0 ->
P = 2*T*Q*P0 + 1,
- case is_prime(crypto:mpint(P), 50) of
+ case is_prime(P, 50) of
true -> P;
false -> dsa_search(T+1, P0, Q, Iter-1)
end;
@@ -377,38 +427,40 @@ dsa_search(_,_,_,_) ->
%%%%%%% Crypto Math %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
prime(ByteSize) ->
Rand = odd_rand(ByteSize),
- crypto:erlint(prime_odd(Rand, 0)).
+ prime_odd(Rand, 0).
prime_odd(Rand, N) ->
case is_prime(Rand, 50) of
true ->
Rand;
false ->
- NotPrime = crypto:erlint(Rand),
- prime_odd(crypto:mpint(NotPrime+2), N+1)
+ prime_odd(Rand+2, N+1)
end.
%% see http://en.wikipedia.org/wiki/Fermat_primality_test
is_prime(_, 0) -> true;
is_prime(Candidate, Test) ->
- CoPrime = odd_rand(<<0,0,0,4, 10000:32>>, Candidate),
- case crypto:mod_exp(CoPrime, Candidate, Candidate) of
- CoPrime -> is_prime(Candidate, Test-1);
- _ -> false
- end.
+ CoPrime = odd_rand(10000, Candidate),
+ Result = crypto:mod_pow(CoPrime, Candidate, Candidate) ,
+ is_prime(CoPrime, crypto:bytes_to_integer(Result), Candidate, Test).
+
+is_prime(CoPrime, CoPrime, Candidate, Test) ->
+ is_prime(Candidate, Test-1);
+is_prime(_,_,_,_) ->
+ false.
odd_rand(Size) ->
Min = 1 bsl (Size*8-1),
Max = (1 bsl (Size*8))-1,
- odd_rand(crypto:mpint(Min), crypto:mpint(Max)).
+ odd_rand(Min, Max).
odd_rand(Min,Max) ->
- Rand = <<Sz:32, _/binary>> = crypto:rand_uniform(Min,Max),
- BitSkip = (Sz+4)*8-1,
- case Rand of
- Odd = <<_:BitSkip, 1:1>> -> Odd;
- Even = <<_:BitSkip, 0:1>> ->
- crypto:mpint(crypto:erlint(Even)+1)
+ Rand = crypto:rand_uniform(Min,Max),
+ case Rand rem 2 of
+ 0 ->
+ Rand + 1;
+ _ ->
+ Rand
end.
extended_gcd(A, B) ->
@@ -427,3 +479,4 @@ pem_to_der(File) ->
der_to_pem(File, Entries) ->
PemBin = public_key:pem_encode(Entries),
file:write_file(File, PemBin).
+
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index 350192464e..0c35f284f7 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -1693,6 +1693,15 @@ receive_streamed_body(RequestId, Body, Pid) ->
ct:print("~p:receive_streamed_body -> requested next stream ~n", [?MODULE]),
receive
{http, {RequestId, stream, BinBodyPart}} ->
+ %% Make sure the httpc hasn't sent us the next 'stream'
+ %% without our request.
+ receive
+ {http, {RequestId, stream, _}} = Msg ->
+ ct:fail({unexpected_flood_of_stream, Msg})
+ after
+ 1000 ->
+ ok
+ end,
receive_streamed_body(RequestId,
<<Body/binary, BinBodyPart/binary>>,
Pid);
diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl
index 742c000cc1..ded03361ee 100644
--- a/lib/kernel/src/os.erl
+++ b/lib/kernel/src/os.erl
@@ -126,7 +126,7 @@ verify_executable(Name0, [Ext|Rest], OrigExtensions) ->
end;
verify_executable(Name, [], OrigExtensions) when OrigExtensions =/= [""] -> %% Windows
%% Will only happen on windows, hence case insensitivity
- case can_be_full_name(string:to_lower(Name),OrigExtensions) of
+ case can_be_full_name(string:to_lower(Name),OrigExtensions) of
true ->
verify_executable(Name,[""],[""]);
_ ->
@@ -150,7 +150,7 @@ split_path(Path) ->
{win32, _} ->
{ok,Curr} = file:get_cwd(),
split_path(Path, $;, [], [Curr]);
- _ ->
+ _ ->
split_path(Path, $:, [], [])
end.
@@ -187,11 +187,14 @@ cmd(Cmd) ->
{unix, _} ->
unix_cmd(Cmd);
{win32, Wtype} ->
- Command = case {os:getenv("COMSPEC"),Wtype} of
+ Command0 = case {os:getenv("COMSPEC"),Wtype} of
{false,windows} -> lists:concat(["command.com /c", Cmd]);
{false,_} -> lists:concat(["cmd /c", Cmd]);
{Cspec,_} -> lists:concat([Cspec," /c",Cmd])
end,
+ %% open_port/2 awaits string() in Command, but io_lib:chars() can be
+ %% deep lists according to io_lib module description.
+ Command = lists:flatten(Command0),
Port = open_port({spawn, Command}, [stream, in, eof, hide]),
get_data(Port, [])
end.
@@ -213,7 +216,7 @@ unix_cmd(Cmd) ->
end.
%% The -s flag implies that only the positional parameters are set,
-%% and the commands are read from standard input. We set the
+%% and the commands are read from standard input. We set the
%% $1 parameter for easy identification of the resident shell.
%%
-define(SHELL, "/bin/sh -s unix:cmd 2>&1").
@@ -226,7 +229,7 @@ unix_cmd(Cmd) ->
-spec start_port() -> port().
start_port() ->
Ref = make_ref(),
- Request = {Ref,self()},
+ Request = {Ref,self()},
{Pid, Mon} = case whereis(?PORT_CREATOR_NAME) of
undefined ->
spawn_monitor(fun() ->
@@ -273,7 +276,7 @@ start_port_srv_handle({Ref,Client}) ->
Port
catch
error:Reason ->
- {Reason,erlang:get_stacktrace()}
+ {Reason,erlang:get_stacktrace()}
end,
Client ! {Ref,Reply}.
@@ -355,16 +358,16 @@ get_data(Port, Sofar) ->
{Port, {data, Bytes}} ->
get_data(Port, [Sofar|Bytes]);
{Port, eof} ->
- Port ! {self(), close},
+ Port ! {self(), close},
receive
{Port, closed} ->
true
- end,
+ end,
receive
- {'EXIT', Port, _} ->
+ {'EXIT', Port, _} ->
ok
after 1 -> % force context switch
ok
- end,
+ end,
lists:flatten(Sofar)
end.
diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl
index 6b672004ec..2d5827282f 100644
--- a/lib/kernel/test/gen_tcp_misc_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl
@@ -602,7 +602,7 @@ iter_max_socks(Config) when is_list(Config) ->
%% Run on a different node in order to limit the effect if this test fails.
Dir = filename:dirname(code:which(?MODULE)),
{ok,Node} = test_server:start_node(test_iter_max_socks,slave,
- [{args,"-pa " ++ Dir}]),
+ [{args,"+Q 2048 -pa " ++ Dir}]),
L = rpc:call(Node,?MODULE,do_iter_max_socks,[N, initalize]),
test_server:stop_node(Node),
diff --git a/lib/kernel/test/os_SUITE.erl b/lib/kernel/test/os_SUITE.erl
index 382fd6f6a9..73ed704ae3 100644
--- a/lib/kernel/test/os_SUITE.erl
+++ b/lib/kernel/test/os_SUITE.erl
@@ -18,20 +18,21 @@
%%
-module(os_SUITE).
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
+-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
-export([space_in_cwd/1, quoting/1, space_in_name/1, bad_command/1,
- find_executable/1, unix_comment_in_command/1, evil/1]).
+ find_executable/1, unix_comment_in_command/1, deep_list_command/1, evil/1]).
-include_lib("test_server/include/test_server.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
-all() ->
+all() ->
[space_in_cwd, quoting, space_in_name, bad_command,
- find_executable, unix_comment_in_command, evil].
+ find_executable, unix_comment_in_command, deep_list_command,
+ evil].
-groups() ->
+groups() ->
[].
init_per_suite(Config) ->
@@ -117,9 +118,9 @@ space_in_name(Config) when is_list(Config) ->
?line ok = file:change_mode(Echo, 8#777), % Make it executable on Unix.
%% Run the echo program.
- %% Quoting on windows depends on if the full path of the executable
+ %% Quoting on windows depends on if the full path of the executable
%% contains special characters. Paths when running common_tests always
- %% include @, why Windows would always fail if we do not double the
+ %% include @, why Windows would always fail if we do not double the
%% quotes (this is the behaviour of cmd.exe, not Erlang's idea).
Quote = case os:type() of
{win32,_} ->
@@ -135,7 +136,7 @@ space_in_name(Config) when is_list(Config) ->
?t:sleep(5),
?line [] = receive_all(),
ok.
-
+
bad_command(doc) ->
"Check that a bad command doesn't crasch the server or the emulator (it used to).";
bad_command(suite) -> [];
@@ -153,17 +154,17 @@ find_executable(suite) -> [];
find_executable(doc) -> [];
find_executable(Config) when is_list(Config) ->
case os:type() of
- {win32, _} ->
+ {win32, _} ->
?line DataDir = filename:join(?config(data_dir, Config), "win32"),
?line ok = file:set_cwd(filename:join([DataDir, "current"])),
?line Bin = filename:join(DataDir, "bin"),
?line Abin = filename:join(DataDir, "abin"),
?line UsrBin = filename:join([DataDir, "usr", "bin"]),
?line {ok, Current} = file:get_cwd(),
-
+
?line Path = lists:concat([Bin, ";", Abin, ";", UsrBin]),
?line io:format("Path = ~s", [Path]),
-
+
%% Search for programs in Bin (second element in PATH).
?line find_exe(Abin, "my_ar", ".exe", Path),
?line find_exe(Abin, "my_ascii", ".com", Path),
@@ -175,18 +176,18 @@ find_executable(Config) when is_list(Config) ->
?line find_exe(Abin, "my_ar.EXE", "", Path),
?line find_exe(Abin, "my_ascii.COM", "", Path),
?line find_exe(Abin, "MY_ADB.BAT", "", Path),
-
+
%% Search for programs in Abin (second element in PATH).
?line find_exe(Abin, "my_ar", ".exe", Path),
?line find_exe(Abin, "my_ascii", ".com", Path),
?line find_exe(Abin, "my_adb", ".bat", Path),
-
+
%% Search for programs in the current working directory.
?line find_exe(Current, "my_program", ".exe", Path),
?line find_exe(Current, "my_command", ".com", Path),
?line find_exe(Current, "my_batch", ".bat", Path),
ok;
- {unix, _} ->
+ {unix, _} ->
DataDir = ?config(data_dir, Config),
%% Smoke test.
@@ -237,6 +238,21 @@ unix_comment_in_command(Config) when is_list(Config) ->
?line test_server:timetrap_cancel(Dog),
ok.
+deep_list_command(doc) ->
+ "Check that a deep list in command works equally on unix and on windows.";
+deep_list_command(suite) -> [];
+deep_list_command(Config) when is_list(Config) ->
+ %% As a 'io_lib' module description says: "There is no guarantee that the
+ %% character lists returned from some of the functions are flat, they can
+ %% be deep lists."
+ %% That's why os:cmd/1 can have arguments that are deep lists.
+ %% It is not a problem for unix, but for windows it is (in R15B02 for ex.).
+ Echo = os:cmd([$e, $c, "ho"]),
+ true = erlang:is_list(Echo),
+ %% FYI: [$e, $c, "ho"] =:= io_lib:format("ec~s", ["ho"])
+ ok.
+
+
-define(EVIL_PROCS, 100).
-define(EVIL_LOOPS, 100).
-define(PORT_CREATOR, os_cmd_port_creator).
@@ -303,4 +319,3 @@ receive_all() ->
X -> [X|receive_all()]
after 0 -> []
end.
-
diff --git a/lib/observer/src/crashdump_viewer.erl b/lib/observer/src/crashdump_viewer.erl
index 64a8457d16..e7d71c581e 100644
--- a/lib/observer/src/crashdump_viewer.erl
+++ b/lib/observer/src/crashdump_viewer.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -41,6 +41,7 @@
%% Process state
%% -------------
%% file: The name of the crashdump currently viewed.
+%% dump_vsn: The version number of the crashdump
%% procs_summary: Process summary represented by a list of
%% #proc records. This is used for efficiency reasons when sorting the
%% process summary table instead of reading all processes from the
@@ -127,6 +128,8 @@
% timers, funs...
% Must be equal to
% ?max_sort_process_num!
+-define(not_available,"N/A").
+
%% All possible tags - use macros in order to avoid misspelling in the code
-define(allocated_areas,allocated_areas).
@@ -161,7 +164,7 @@
-define(visible_node,visible_node).
--record(state,{file,procs_summary,sorted,shared_heap=false,
+-record(state,{file,dump_vsn,procs_summary,sorted,shared_heap=false,
wordsize=4,num_atoms="unknown",binaries,bg_status}).
%%%-----------------------------------------------------------------
@@ -499,6 +502,7 @@ handle_call(filename_frame,_From,State=#state{file=File}) ->
{reply,Reply,State};
handle_call(initial_info_frame,_From,State=#state{file=File}) ->
GenInfo = general_info(File),
+ [{DumpVsn,_}] = lookup_index(?erl_crash_dump),
NumAtoms = GenInfo#general_info.num_atoms,
{WS,SH} = parse_vsn_str(GenInfo#general_info.system_vsn,4,false),
NumProcs = list_to_integer(GenInfo#general_info.num_procs),
@@ -506,7 +510,9 @@ handle_call(initial_info_frame,_From,State=#state{file=File}) ->
if NumProcs > ?max_sort_process_num -> too_many;
true -> State#state.procs_summary
end,
- NewState = State#state{shared_heap=SH,
+ NewState = State#state{dump_vsn=[list_to_integer(L) ||
+ L<-string:tokens(DumpVsn,".")],
+ shared_heap=SH,
wordsize=WS,
num_atoms=NumAtoms,
procs_summary=ProcsSummary},
@@ -577,7 +583,7 @@ handle_call({sort_procs,SessionId,Input}, _From, State) ->
handle_call({proc_details,Input},_From,State=#state{file=File,shared_heap=SH}) ->
{ok,Pid} = get_value("pid",httpd:parse_query(Input)),
Reply =
- case get_proc_details(File,Pid) of
+ case get_proc_details(File,Pid,State#state.dump_vsn) of
{ok,Proc} ->
TW = truncated_warning([{?proc,Pid}]),
crashdump_viewer_html:proc_details(Pid,Proc,TW,SH);
@@ -1298,7 +1304,6 @@ find_truncated_proc({Tag,Pid}) ->
is_proc_tag(Tag) when Tag==?proc;
Tag==?proc_dictionary;
Tag==?proc_messages;
- Tag==?proc_dictionary;
Tag==?debug_proc_dictionary;
Tag==?proc_stack;
Tag==?proc_heap ->
@@ -1451,7 +1456,8 @@ count() ->
%% avoid really big data in the server state.
procs_summary(SessionId,TW,_,State=#state{procs_summary=too_many}) ->
chunk_page(SessionId,State#state.file,TW,?proc,processes,
- {no_sort,State#state.shared_heap},procs_summary_parsefun()),
+ {no_sort,State#state.shared_heap,State#state.dump_vsn},
+ procs_summary_parsefun()),
State;
procs_summary(SessionId,TW,SortOn,State) ->
ProcsSummary =
@@ -1465,10 +1471,12 @@ procs_summary(SessionId,TW,SortOn,State) ->
PS ->
PS
end,
- {SortedPS,NewSorted} = do_sort_procs(SortOn,ProcsSummary,State#state.sorted),
+ {SortedPS,NewSorted} = do_sort_procs(SortOn,ProcsSummary,State),
HtmlInfo =
crashdump_viewer_html:chunk_page(processes,SessionId,TW,
- {SortOn,State#state.shared_heap},
+ {SortOn,
+ State#state.shared_heap,
+ State#state.dump_vsn},
SortedPS),
crashdump_viewer_html:chunk(SessionId,done,HtmlInfo),
State#state{procs_summary=ProcsSummary,sorted=NewSorted}.
@@ -1480,15 +1488,14 @@ procs_summary_parsefun() ->
%%-----------------------------------------------------------------
%% Page with one process
-get_proc_details(File,Pid) ->
- [{DumpVsn,_}] = lookup_index(?erl_crash_dump),
+get_proc_details(File,Pid,DumpVsn) ->
case lookup_index(?proc,Pid) of
[{_,Start}] ->
Fd = open(File),
pos_bof(Fd,Start),
Proc0 =
case DumpVsn of
- "0.0" ->
+ [0,0] ->
%% Old version (translated)
#proc{pid=Pid};
_ ->
@@ -1597,6 +1604,9 @@ get_procinfo(Fd,Fun,Proc) ->
get_procinfo(Fd,Fun,Proc#proc{old_heap_top=val(Fd)});
"Old heap end" ->
get_procinfo(Fd,Fun,Proc#proc{old_heap_end=val(Fd)});
+ "Memory" ->
+ %% stored as integer so we can sort on it
+ get_procinfo(Fd,Fun,Proc#proc{memory=list_to_integer(val(Fd))});
{eof,_} ->
Proc; % truncated file
Other ->
@@ -1865,35 +1875,41 @@ parse(Line0, Dict0) ->
Dict.
-do_sort_procs("state",Procs,"state") ->
+do_sort_procs("state",Procs,#state{sorted="state"}) ->
{lists:reverse(lists:keysort(#proc.state,Procs)),"rstate"};
do_sort_procs("state",Procs,_) ->
{lists:keysort(#proc.state,Procs),"state"};
-do_sort_procs("pid",Procs,"pid") ->
+do_sort_procs("pid",Procs,#state{sorted="pid"}) ->
{lists:reverse(Procs),"rpid"};
do_sort_procs("pid",Procs,_) ->
{Procs,"pid"};
-do_sort_procs("msg_q_len",Procs,"msg_q_len") ->
+do_sort_procs("msg_q_len",Procs,#state{sorted="msg_q_len"}) ->
{lists:keysort(#proc.msg_q_len,Procs),"rmsg_q_len"};
do_sort_procs("msg_q_len",Procs,_) ->
{lists:reverse(lists:keysort(#proc.msg_q_len,Procs)),"msg_q_len"};
-do_sort_procs("reds",Procs,"reds") ->
+do_sort_procs("reds",Procs,#state{sorted="reds"}) ->
{lists:keysort(#proc.reds,Procs),"rreds"};
do_sort_procs("reds",Procs,_) ->
{lists:reverse(lists:keysort(#proc.reds,Procs)),"reds"};
-do_sort_procs("mem",Procs,"mem") ->
- {lists:keysort(#proc.stack_heap,Procs),"rmem"};
-do_sort_procs("mem",Procs,_) ->
- {lists:reverse(lists:keysort(#proc.stack_heap,Procs)),"mem"};
-do_sort_procs("init_func",Procs,"init_func") ->
+do_sort_procs("mem",Procs,#state{sorted="mem",dump_vsn=DumpVsn}) ->
+ KeyPos = if DumpVsn>=?r16b01_dump_vsn -> #proc.memory;
+ true -> #proc.stack_heap
+ end,
+ {lists:keysort(KeyPos,Procs),"rmem"};
+do_sort_procs("mem",Procs,#state{dump_vsn=DumpVsn}) ->
+ KeyPos = if DumpVsn>=?r16b01_dump_vsn -> #proc.memory;
+ true -> #proc.stack_heap
+ end,
+ {lists:reverse(lists:keysort(KeyPos,Procs)),"mem"};
+do_sort_procs("init_func",Procs,#state{sorted="init_func"}) ->
{lists:reverse(lists:keysort(#proc.init_func,Procs)),"rinit_func"};
do_sort_procs("init_func",Procs,_) ->
{lists:keysort(#proc.init_func,Procs),"init_func"};
-do_sort_procs("name_func",Procs,"name_func") ->
+do_sort_procs("name_func",Procs,#state{sorted="name_func"}) ->
{lists:reverse(lists:keysort(#proc.name,Procs)),"rname_func"};
do_sort_procs("name_func",Procs,_) ->
{lists:keysort(#proc.name,Procs),"name_func"};
-do_sort_procs("name",Procs,Sorted) ->
+do_sort_procs("name",Procs,#state{sorted=Sorted}) ->
{No,Yes} =
lists:foldl(fun(P,{N,Y}) ->
case P#proc.name of
@@ -2349,7 +2365,7 @@ allocator_info(File) ->
end,
AllAllocators),
close(Fd),
- R
+ [allocator_summary(R) | R]
end.
get_allocatorinfo(Fd,Start) ->
@@ -2374,6 +2390,213 @@ get_all_vals([],Acc) ->
get_all_vals([Char|Rest],Acc) ->
get_all_vals(Rest,[Char|Acc]).
+%% Calculate allocator summary:
+%%
+%% System totals:
+%% blocks size = sum of mbcs, mbcs_pool and sbcs blocks size over
+%% all allocator instances of all types
+%% carriers size = sum of mbcs, mbcs_pool and sbcs carriers size over
+%% all allocator instances of all types
+%%
+%% I any allocator except sbmbc_alloc has "option e: false" then don't
+%% present system totals.
+%%
+%% For each allocator type:
+%% blocks size = sum of sbmbcs, mbcs, mbcs_pool and sbcs blocks
+%% size over all allocator instances of this type
+%% carriers size = sum of sbmbcs, mbcs, mbcs_pool and sbcs carriers
+%% size over all allocator instances of this type
+%% mseg carriers size = sum of mbcs and sbcs mseg carriers size over all
+%% allocator instances of this type
+%%
+
+-define(sbmbcs_blocks_size,"sbmbcs blocks size").
+-define(mbcs_blocks_size,"mbcs blocks size").
+-define(sbcs_blocks_size,"sbcs blocks size").
+-define(sbmbcs_carriers_size,"sbmbcs carriers size").
+-define(mbcs_carriers_size,"mbcs carriers size").
+-define(sbcs_carriers_size,"sbcs carriers size").
+-define(mbcs_mseg_carriers_size,"mbcs mseg carriers size").
+-define(sbcs_mseg_carriers_size,"sbcs mseg carriers size").
+-define(segments_size,"segments_size").
+-define(mbcs_pool_blocks_size,"mbcs_pool blocks size").
+-define(mbcs_pool_carriers_size,"mbcs_pool carriers size").
+
+-define(type_blocks_size,[?sbmbcs_blocks_size,
+ ?mbcs_blocks_size,
+ ?mbcs_pool_blocks_size,
+ ?sbcs_blocks_size]).
+-define(type_carriers_size,[?sbmbcs_carriers_size,
+ ?mbcs_carriers_size,
+ ?mbcs_pool_carriers_size,
+ ?sbcs_carriers_size]).
+-define(type_mseg_carriers_size,[?mbcs_mseg_carriers_size,
+ ?sbcs_mseg_carriers_size]).
+-define(total_blocks_size,[?mbcs_blocks_size,
+ ?mbcs_pool_blocks_size,
+ ?sbcs_blocks_size]).
+-define(total_carriers_size,[?mbcs_carriers_size,
+ ?mbcs_pool_carriers_size,
+ ?sbcs_carriers_size]).
+-define(total_mseg_carriers_size,[?mbcs_mseg_carriers_size,
+ ?sbcs_mseg_carriers_size]).
+-define(interesting_allocator_info, [?sbmbcs_blocks_size,
+ ?mbcs_blocks_size,
+ ?mbcs_pool_blocks_size,
+ ?sbcs_blocks_size,
+ ?sbmbcs_carriers_size,
+ ?mbcs_carriers_size,
+ ?sbcs_carriers_size,
+ ?mbcs_mseg_carriers_size,
+ ?mbcs_pool_carriers_size,
+ ?sbcs_mseg_carriers_size,
+ ?segments_size]).
+-define(mseg_alloc,"mseg_alloc").
+-define(seg_size,"segments_size").
+-define(sbmbc_alloc,"sbmbc_alloc").
+-define(opt_e_false,{"option e","false"}).
+
+allocator_summary(Allocators) ->
+ {Sorted,DoTotal} = sort_allocator_types(Allocators,[],true),
+ {TypeTotals0,Totals} = sum_allocator_data(Sorted,DoTotal),
+ {TotalMCS,TypeTotals} =
+ case lists:keytake(?mseg_alloc,1,TypeTotals0) of
+ {value,{_,[{?seg_size,SegSize}]},Rest} ->
+ {integer_to_list(SegSize),Rest};
+ false ->
+ {?not_available,TypeTotals0}
+ end,
+ {TotalBS,TotalCS} =
+ case Totals of
+ false ->
+ {?not_available,?not_available};
+ {TBS,TCS} ->
+ {integer_to_list(TBS),integer_to_list(TCS)}
+ end,
+ {{"Summary",["blocks size","carriers size","mseg carriers size"]},
+ [{"total",[TotalBS,TotalCS,TotalMCS]} |
+ format_allocator_summary(lists:reverse(TypeTotals))]}.
+
+format_allocator_summary([{Type,Data}|Rest]) ->
+ [format_allocator_summary(Type,Data) | format_allocator_summary(Rest)];
+format_allocator_summary([]) ->
+ [].
+
+format_allocator_summary(Type,Data) ->
+ BS = get_size_value(blocks_size,Data),
+ CS = get_size_value(carriers_size,Data),
+ MCS = get_size_value(mseg_carriers_size,Data),
+ {Type,[BS,CS,MCS]}.
+
+get_size_value(Key,Data) ->
+ case proplists:get_value(Key,Data) of
+ undefined ->
+ ?not_available;
+ Int ->
+ integer_to_list(Int)
+ end.
+
+%% Sort allocator data per type
+%% Input = [{Instance,[{Key,Data}]}]
+%% Output = [{Type,[{Key,Value}]}]
+%% where Key in Output is one of ?interesting_allocator_info
+%% and Value is the sum over all allocator instances of each type.
+sort_allocator_types([{Name,Data}|Allocators],Acc,DoTotal) ->
+ Type =
+ case string:tokens(Name,"[]") of
+ [T,_Id] -> T;
+ [Name] -> Name
+ end,
+ TypeData = proplists:get_value(Type,Acc,[]),
+ {NewTypeData,NewDoTotal} = sort_type_data(Type,Data,TypeData,DoTotal),
+ NewAcc = lists:keystore(Type,1,Acc,{Type,NewTypeData}),
+ sort_allocator_types(Allocators,NewAcc,NewDoTotal);
+sort_allocator_types([],Acc,DoTotal) ->
+ {Acc,DoTotal}.
+
+sort_type_data(Type,[?opt_e_false|Data],Acc,_) when Type=/=?sbmbc_alloc->
+ sort_type_data(Type,Data,Acc,false);
+sort_type_data(Type,[{Key,Val0}|Data],Acc,DoTotal) ->
+ case lists:member(Key,?interesting_allocator_info) of
+ true ->
+ Val = list_to_integer(hd(Val0)),
+ sort_type_data(Type,Data,update_value(Key,Val,Acc),DoTotal);
+ false ->
+ sort_type_data(Type,Data,Acc,DoTotal)
+ end;
+sort_type_data(_Type,[],Acc,DoTotal) ->
+ {Acc,DoTotal}.
+
+%% Sum up allocator data in total blocks- and carriers size for all
+%% allocators and per type of allocator.
+%% Input = Output from sort_allocator_types/3
+%% Output = {[{"mseg_alloc",[{"segments_size",Value}]},
+%% {Type,[{blocks_size,Value},
+%% {carriers_size,Value},
+%% {mseg_carriers_size,Value}]},
+%% ...],
+%% {TotalBlocksSize,TotalCarriersSize}}
+sum_allocator_data(AllocData,false) ->
+ sum_allocator_data(AllocData,[],false);
+sum_allocator_data(AllocData,true) ->
+ sum_allocator_data(AllocData,[],{0,0}).
+
+sum_allocator_data([{_Type,[]}|AllocData],TypeAcc,Total) ->
+ sum_allocator_data(AllocData,TypeAcc,Total);
+sum_allocator_data([{Type,Data}|AllocData],TypeAcc,Total) ->
+ {TypeSum,NewTotal} = sum_type_data(Data,[],Total),
+ sum_allocator_data(AllocData,[{Type,TypeSum}|TypeAcc],NewTotal);
+sum_allocator_data([],TypeAcc,Total) ->
+ {TypeAcc,Total}.
+
+sum_type_data([{Key,Value}|Data],TypeAcc,Total) ->
+ NewTotal =
+ case Total of
+ false ->
+ false;
+ {TotalBS,TotalCS} ->
+ case lists:member(Key,?total_blocks_size) of
+ true ->
+ {TotalBS+Value,TotalCS};
+ false ->
+ case lists:member(Key,?total_carriers_size) of
+ true ->
+ {TotalBS,TotalCS+Value};
+ false ->
+ {TotalBS,TotalCS}
+ end
+ end
+ end,
+ NewTypeAcc =
+ case lists:member(Key,?type_blocks_size) of
+ true ->
+ update_value(blocks_size,Value,TypeAcc);
+ false ->
+ case lists:member(Key,?type_carriers_size) of
+ true ->
+ update_value(carriers_size,Value,TypeAcc);
+ false ->
+ case lists:member(Key,?type_mseg_carriers_size) of
+ true ->
+ update_value(mseg_carriers_size,Value,TypeAcc);
+ false ->
+ %% "segments_size" for "mseg_alloc"
+ update_value(Key,Value,TypeAcc)
+ end
+ end
+ end,
+ sum_type_data(Data,NewTypeAcc,NewTotal);
+sum_type_data([],TypeAcc,Total) ->
+ {TypeAcc,Total}.
+
+update_value(Key,Value,Acc) ->
+ case lists:keytake(Key,1,Acc) of
+ false ->
+ [{Key,Value}|Acc];
+ {value,{Key,Old},Acc1} ->
+ [{Key,Old+Value}|Acc1]
+ end.
+
%%-----------------------------------------------------------------
%% Page with hash table information
hash_tables(File) ->
diff --git a/lib/observer/src/crashdump_viewer.hrl b/lib/observer/src/crashdump_viewer.hrl
index 466f33b63b..2e0ea5cf96 100644
--- a/lib/observer/src/crashdump_viewer.hrl
+++ b/lib/observer/src/crashdump_viewer.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -18,7 +18,7 @@
%%
-define(space, "&nbsp;").
-define(unknown, "unknown").
-
+-define(r16b01_dump_vsn, [0,2]). % =erl_crash_dump:0.2
-record(menu_item,{index,picture,text,depth,children,state,target}).
@@ -83,6 +83,7 @@
old_heap_start=?space,
old_heap_top=?space,
old_heap_end=?space,
+ memory,
stack_dump=?space}).
-record(port,
diff --git a/lib/observer/src/crashdump_viewer_html.erl b/lib/observer/src/crashdump_viewer_html.erl
index 3151b83bfb..93c1a842b5 100644
--- a/lib/observer/src/crashdump_viewer_html.erl
+++ b/lib/observer/src/crashdump_viewer_html.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -333,7 +333,13 @@ proc_details_body(Heading,Proc,TW,SharedHeap) ->
td("COLSPAN=1",href_proc_port(Proc#proc.parent))]),
tr(
[td("NOWRAP=true",b("Reductions")),
- td("COLSPAN=3",integer_to_list(Proc#proc.reds))]),
+ td("COLSPAN=1",integer_to_list(Proc#proc.reds))] ++
+ case Proc#proc.memory of
+ undefined -> []; % before R16B01
+ Mem ->
+ [td("NOWRAP=true",b("Memory (bytes)")),
+ td("COLSPAN=1",integer_to_list(Mem))]
+ end),
if SharedHeap ->
Stack = case Proc#proc.stack_heap of
-1 -> "unknown";
@@ -815,12 +821,26 @@ allocator_info_body(Heading,Allocators,TW) ->
[heading(Heading,"memory"),
warn(TW),
p(b("Sizes are in bytes")),
- lists:map(fun({SubTitle,Allocator}) ->
+ lists:map(fun({Head,Allocator}) ->
+ TableHead =
+ case Head of
+ {SubTitle,Columns} ->
+ tr("BGCOLOR=\"#8899AA\"",
+ [th("ALIGN=left",
+ font("SIZE=+1",SubTitle)) |
+ lists:map(
+ fun(CH) ->
+ th("ALIGN=right",CH)
+ end,
+ Columns)]);
+ SubTitle ->
+ tr("BGCOLOR=\"#8899AA\"",
+ th("COLSPAN=10 ALIGN=left",
+ font("SIZE=+1",SubTitle)))
+ end,
[table(
"BORDER=4 CELLPADDING=4",
- [tr("BGCOLOR=\"#8899AA\"",
- th("COLSPAN=10 ALIGN=left",
- font("SIZE=+1",SubTitle))) |
+ [TableHead |
lists:map(
fun({Key,Values}) ->
tr([th("ALIGN=left",Key) |
@@ -1243,8 +1263,8 @@ replace_insrt([],[],Acc) ->
%%% Create a page with one table by delivering chunk by chunk to
%%% inets. crashdump_viewer first calls chunk_page/5 once, then
%%% chunk/3 multiple times until all data is delivered.
-chunk_page(processes,SessionId,TW,{Sorted,SharedHeap},FirstChunk) ->
- Columns = procs_summary_table_head(Sorted,SharedHeap),
+chunk_page(processes,SessionId,TW,{Sorted,SharedHeap,DumpVsn},FirstChunk) ->
+ Columns = procs_summary_table_head(Sorted,SharedHeap,DumpVsn),
chunk_page(SessionId, "Process Information", TW, FirstChunk,
"processes", Columns, fun procs_summary_table/1);
chunk_page(ports,SessionId,TW,_,FirstChunk) ->
@@ -1321,35 +1341,45 @@ deliver(SessionId,IoList) ->
%%%-----------------------------------------------------------------
%%% Page specific stuff for chunk pages
-procs_summary_table_head(Sorted,SharedHeap) ->
+procs_summary_table_head(Sorted,SharedHeap,DumpVsn) ->
MemHeading =
- if SharedHeap ->
- "Stack";
+ if DumpVsn>=?r16b01_dump_vsn ->
+ "Memory (bytes)";
true ->
- "Stack+heap"
+ if SharedHeap ->
+ "Stack";
+ true ->
+ "Stack+heap"
+ end
end,
- [procs_summary_table_head("pid","Pid",Sorted),
- procs_summary_table_head("name_func","Name/Spawned as",Sorted),
- procs_summary_table_head("state","State",Sorted),
- procs_summary_table_head("reds","Reductions",Sorted),
- procs_summary_table_head("mem",MemHeading,Sorted),
- procs_summary_table_head("msg_q_len","MsgQ Length",Sorted)].
-
-procs_summary_table_head(_,Text,no_sort) ->
+ [procs_summary_table_head1("pid","Pid",Sorted),
+ procs_summary_table_head1("name_func","Name/Spawned as",Sorted),
+ procs_summary_table_head1("state","State",Sorted),
+ procs_summary_table_head1("reds","Reductions",Sorted),
+ procs_summary_table_head1("mem",MemHeading,Sorted),
+ procs_summary_table_head1("msg_q_len","MsgQ Length",Sorted)].
+
+procs_summary_table_head1(_,Text,no_sort) ->
Text;
-procs_summary_table_head(Sorted,Text,Sorted) ->
+procs_summary_table_head1(Sorted,Text,Sorted) ->
%% Mark the sorted column (bigger and italic)
font("SIZE=\"+1\"",em(href("./sort_procs?sort="++Sorted,Text)));
-procs_summary_table_head(SortOn,Text,_Sorted) ->
+procs_summary_table_head1(SortOn,Text,_Sorted) ->
href("./sort_procs?sort="++SortOn,Text).
procs_summary_table(Proc) ->
#proc{pid=Pid,name=Name,state=State,
- reds=Reds,stack_heap=Mem0,msg_q_len=MsgQLen}=Proc,
- Mem = case Mem0 of
- -1 -> "unknown";
- _ -> integer_to_list(Mem0)
- end,
+ reds=Reds,stack_heap=Stack,memory=Memory,msg_q_len=MsgQLen}=Proc,
+ Mem =
+ case Memory of
+ undefined -> % assuming pre-R16B01
+ case Stack of
+ -1 -> "unknown";
+ _ -> integer_to_list(Stack)
+ end;
+ _ ->
+ integer_to_list(Memory)
+ end,
tr(
[td(href(["./proc_details?pid=",Pid],Pid)),
td(Name),
diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl
index 4077f8371a..f7712cf3da 100644
--- a/lib/observer/src/observer_lib.erl
+++ b/lib/observer/src/observer_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -122,7 +122,10 @@ fill_info([{Str, Key}|Rest], Data) when is_atom(Key); is_function(Key) ->
[{Str, get_value(Key, Data)} | fill_info(Rest, Data)];
fill_info([{Str, {Format, Key}}|Rest], Data)
when is_atom(Key); is_function(Key), is_atom(Format) ->
- [{Str, {Format, get_value(Key,Data)}} | fill_info(Rest, Data)];
+ case get_value(Key, Data) of
+ undefined -> [{Str, undefined} | fill_info(Rest, Data)];
+ Value -> [{Str, {Format, Value}} | fill_info(Rest, Data)]
+ end;
fill_info([{Str,SubStructure}|Rest], Data) when is_list(SubStructure) ->
[{Str, fill_info(SubStructure, Data)}|fill_info(Rest,Data)];
fill_info([{Str,Attrib,SubStructure}|Rest], Data) ->
diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl
index 45218c177b..f234218017 100644
--- a/lib/observer/src/observer_procinfo.erl
+++ b/lib/observer/src/observer_procinfo.erl
@@ -64,6 +64,7 @@ init([Pid, ParentFrame, Parent]) ->
MessagePage = init_panel(Notebook, "Messages", Pid, fun init_message_page/2),
DictPage = init_panel(Notebook, "Dictionary", Pid, fun init_dict_page/2),
StackPage = init_panel(Notebook, "Stack Trace", Pid, fun init_stack_page/2),
+ StatePage = init_panel(Notebook, "State", Pid, fun init_state_page/2),
wxFrame:connect(Frame, close_window),
wxMenu:connect(Frame, command_menu_selected),
@@ -72,7 +73,7 @@ init([Pid, ParentFrame, Parent]) ->
{Frame, #state{parent=Parent,
pid=Pid,
frame=Frame,
- pages=[ProcessPage,MessagePage,DictPage,StackPage]
+ pages=[ProcessPage,MessagePage,DictPage,StackPage,StatePage]
}}
catch error:{badrpc, _} ->
observer_wx:return_to_localnode(ParentFrame, node(Pid)),
@@ -235,6 +236,59 @@ init_stack_page(Parent, Pid) ->
Update(),
{LCtrl, Update}.
+
+init_state_page(Parent, Pid) ->
+ Text = init_text_page(Parent),
+ Update = fun() ->
+ %% First, test if sys:get_status/2 have any chance to return an answer
+ case rpc:call(node(Pid), proc_lib, translate_initial_call, [Pid])
+ of
+ %% Not a gen process
+ {proc_lib,init_p,5} -> Misc = [{"Information", "Not available"}];
+ %% May be a gen process
+ {M, _F, _A} ->
+ %% Get the behavio(u)r
+ I = rpc:call(node(Pid), M, module_info, [attributes]),
+ case lists:keyfind(behaviour, 1, I) of
+ false -> case lists:keyfind(behavior, 1, I) of
+ false -> B = undefined;
+ {behavior, [B]} -> B
+ end;
+ {behaviour, [B]} -> B
+ end,
+ %% but not sure that system messages are treated by this process
+ %% so using a rpc with a small timeout in order not to lag the display
+ case rpc:call(node(Pid), sys, get_status, [Pid, 200])
+ of
+ {status, _, {module, _}, [_PDict, _SysState, _Parent, _Dbg,
+ [Header,{data, First},{data, Second}]]} ->
+ Misc = [{"Behaviour", B}] ++ [Header] ++ First ++ Second;
+ {status, _, {module, _}, [_PDict, _SysState, _Parent, _Dbg,
+ [Header,{data, First}, OtherFormat]]} ->
+ Misc = [{"Behaviour", B}] ++ [Header] ++ First ++ [{"State",OtherFormat}];
+ {status, _, {module, _}, [_PDict, _SysState, _Parent, _Dbg,
+ OtherFormat]} ->
+ %% Formatted status ?
+ case lists:keyfind(format_status, 1, rpc:call(node(Pid), M, module_info, [exports])) of
+ false -> Opt = {"Format", unknown};
+ _ -> Opt = {"Format", overriden}
+ end,
+ Misc = [{"Behaviour", B}] ++ [Opt, {"State",OtherFormat}];
+ {badrpc,{'EXIT',{timeout, _}}} ->
+ Misc = [{"Information","Timed out"},
+ {"Tip","system messages are probably not treated by this process"}]
+ end;
+ _ -> Misc=[], throw(process_undefined)
+ end,
+ Dict = [io_lib:format("~-20.s ~tp~n", [K, V]) || {K, V} <- Misc],
+ Last = wxTextCtrl:getLastPosition(Text),
+ wxTextCtrl:remove(Text, 0, Last),
+ wxTextCtrl:writeText(Text, Dict)
+ end,
+ Update(),
+ {Text, Update}.
+
+
create_menus(MenuBar) ->
Menus = [{"File", [#create_menu{id=?wxID_CLOSE, text="Close"}]},
{"View", [#create_menu{id=?REFRESH, text="Refresh\tCtrl-R"}]}],
diff --git a/lib/observer/src/observer_sys_wx.erl b/lib/observer/src/observer_sys_wx.erl
index f00a666a35..31800cf12a 100644
--- a/lib/observer/src/observer_sys_wx.erl
+++ b/lib/observer/src/observer_sys_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -37,6 +37,7 @@
parent_notebook,
panel, sizer,
menubar,
+ alloc,
fields,
timer}).
@@ -47,22 +48,28 @@ start_link(Notebook, Parent) ->
init([Notebook, Parent]) ->
SysInfo = observer_backend:sys_info(),
+ AllocInfo = proplists:get_value(alloc_info, SysInfo, []),
{Info, Stat} = info_fields(),
Panel = wxPanel:new(Notebook),
- Sizer = wxBoxSizer:new(?wxHORIZONTAL),
+ Sizer = wxBoxSizer:new(?wxVERTICAL),
+ TopSizer = wxBoxSizer:new(?wxHORIZONTAL),
{FPanel0, _FSizer0, Fields0} =
observer_lib:display_info(Panel, observer_lib:fill_info(Info, SysInfo)),
{FPanel1, _FSizer1, Fields1} =
observer_lib:display_info(Panel, observer_lib:fill_info(Stat, SysInfo)),
- wxSizer:add(Sizer, FPanel0, [{flag, ?wxEXPAND bor ?wxTOP bor ?wxBOTTOM bor ?wxLEFT},
- {proportion, 1}, {border, 5}]),
- wxSizer:add(Sizer, FPanel1, [{flag, ?wxEXPAND bor ?wxTOP bor ?wxBOTTOM bor ?wxRIGHT},
- {proportion, 1}, {border, 5}]),
+ wxSizer:add(TopSizer, FPanel0, [{flag, ?wxEXPAND}, {proportion, 1}]),
+ wxSizer:add(TopSizer, FPanel1, [{flag, ?wxEXPAND}, {proportion, 1}]),
+ BorderFlags = ?wxLEFT bor ?wxRIGHT,
+ MemoryInfo = create_mem_info(Panel, AllocInfo),
+ wxSizer:add(Sizer, TopSizer, [{flag, ?wxEXPAND bor BorderFlags bor ?wxTOP},
+ {proportion, 0}, {border, 5}]),
+ wxSizer:add(Sizer, MemoryInfo, [{flag, ?wxEXPAND bor BorderFlags bor ?wxBOTTOM},
+ {proportion, 1}, {border, 5}]),
wxPanel:setSizer(Panel, Sizer),
Timer = observer_lib:start_timer(10),
{Panel, #sys_wx_state{parent=Parent,
parent_notebook=Notebook,
- panel=Panel, sizer=Sizer,
+ panel=Panel, sizer=Sizer, alloc=MemoryInfo,
timer=Timer, fields=Fields0 ++ Fields1}}.
create_sys_menu(Parent) ->
@@ -70,13 +77,84 @@ create_sys_menu(Parent) ->
#create_menu{id = ?ID_REFRESH_INTERVAL, text = "Refresh interval"}]},
observer_wx:create_menus(Parent, [View]).
-update_syspage(#sys_wx_state{node = Node, fields=Fields, sizer=Sizer}) ->
+update_syspage(#sys_wx_state{node = Node, fields=Fields, sizer=Sizer, alloc=AllocCtrl}) ->
SysInfo = observer_wx:try_rpc(Node, observer_backend, sys_info, []),
+ AllocInfo = proplists:get_value(alloc_info, SysInfo, []),
{Info, Stat} = info_fields(),
observer_lib:update_info(Fields, observer_lib:fill_info(Info, SysInfo) ++
observer_lib:fill_info(Stat, SysInfo)),
+ update_alloc(AllocCtrl, AllocInfo),
wxSizer:layout(Sizer).
+create_mem_info(Panel, Fields) ->
+ Style = ?wxLC_REPORT bor ?wxLC_SINGLE_SEL bor ?wxLC_HRULES bor ?wxLC_VRULES,
+ Grid = wxListCtrl:new(Panel, [{style, Style}]),
+ Li = wxListItem:new(),
+ AddListEntry = fun({Name, Align, DefSize}, Col) ->
+ wxListItem:setText(Li, Name),
+ wxListItem:setAlign(Li, Align),
+ wxListCtrl:insertColumn(Grid, Col, Li),
+ wxListCtrl:setColumnWidth(Grid, Col, DefSize),
+ Col + 1
+ end,
+ ListItems = [{"Allocator Type", ?wxLIST_FORMAT_LEFT, 200},
+ {"Block size (kB)", ?wxLIST_FORMAT_RIGHT, 150},
+ {"Carrier size (kB)",?wxLIST_FORMAT_RIGHT, 150}],
+ lists:foldl(AddListEntry, 0, ListItems),
+ wxListItem:destroy(Li),
+ update_alloc(Grid, Fields),
+ Grid.
+
+update_alloc(Grid, AllocInfo) ->
+ Fields = alloc_info(AllocInfo, [], 0, 0, true),
+ wxListCtrl:deleteAllItems(Grid),
+ Update = fun({Name, BS, CS}, Row) ->
+ wxListCtrl:insertItem(Grid, Row, ""),
+ wxListCtrl:setItem(Grid, Row, 0, observer_lib:to_str(Name)),
+ wxListCtrl:setItem(Grid, Row, 1, observer_lib:to_str(BS div 1024)),
+ wxListCtrl:setItem(Grid, Row, 2, observer_lib:to_str(CS div 1024)),
+ Row + 1
+ end,
+ lists:foldl(Update, 0, Fields),
+ Fields.
+
+alloc_info([{Type,Instances}|Allocators],TypeAcc,TotalBS,TotalCS,IncludeTotal) ->
+ {BS,CS,NewTotalBS,NewTotalCS,NewIncludeTotal} =
+ sum_alloc_instances(Instances,0,0,TotalBS,TotalCS),
+ alloc_info(Allocators,[{Type,BS,CS}|TypeAcc],NewTotalBS,NewTotalCS,
+ IncludeTotal andalso NewIncludeTotal);
+alloc_info([],TypeAcc,TotalBS,TotalCS,IncludeTotal) ->
+ Types = [X || X={_,BS,CS} <- TypeAcc, (BS>0 orelse CS>0)],
+ case IncludeTotal of
+ true ->
+ [{total,TotalBS,TotalCS} | lists:reverse(Types)];
+ false ->
+ lists:reverse(Types)
+ end.
+
+sum_alloc_instances(false,BS,CS,TotalBS,TotalCS) ->
+ {BS,CS,TotalBS,TotalCS,false};
+sum_alloc_instances([{_,_,Data}|Instances],BS,CS,TotalBS,TotalCS) ->
+ {NewBS,NewCS,NewTotalBS,NewTotalCS} =
+ sum_alloc_one_instance(Data,BS,CS,TotalBS,TotalCS),
+ sum_alloc_instances(Instances,NewBS,NewCS,NewTotalBS,NewTotalCS);
+sum_alloc_instances([],BS,CS,TotalBS,TotalCS) ->
+ {BS,CS,TotalBS,TotalCS,true}.
+
+sum_alloc_one_instance([{sbmbcs,[{blocks_size,BS,_,_},{carriers_size,CS,_,_}]}|
+ Rest],OldBS,OldCS,TotalBS,TotalCS) ->
+ sum_alloc_one_instance(Rest,OldBS+BS,OldCS+CS,TotalBS,TotalCS);
+sum_alloc_one_instance([{_,[{blocks_size,BS,_,_},{carriers_size,CS,_,_}]}|
+ Rest],OldBS,OldCS,TotalBS,TotalCS) ->
+ sum_alloc_one_instance(Rest,OldBS+BS,OldCS+CS,TotalBS+BS,TotalCS+CS);
+sum_alloc_one_instance([{_,[{blocks_size,BS},{carriers_size,CS}]}|
+ Rest],OldBS,OldCS,TotalBS,TotalCS) ->
+ sum_alloc_one_instance(Rest,OldBS+BS,OldCS+CS,TotalBS+BS,TotalCS+CS);
+sum_alloc_one_instance([_|Rest],BS,CS,TotalBS,TotalCS) ->
+ sum_alloc_one_instance(Rest,BS,CS,TotalBS,TotalCS);
+sum_alloc_one_instance([],BS,CS,TotalBS,TotalCS) ->
+ {BS,CS,TotalBS,TotalCS}.
+
info_fields() ->
Info = [{"System and Architecture",
[{"System Version", otp_release},
diff --git a/lib/odbc/configure.in b/lib/odbc/configure.in
index fd28830c0c..83f7a47434 100644
--- a/lib/odbc/configure.in
+++ b/lib/odbc/configure.in
@@ -167,7 +167,8 @@ AC_SUBST(TARGET_FLAGS)
AC_CHECK_SIZEOF(void *)
AC_MSG_CHECKING([for odbc in standard locations])
for rdir in /usr/local/odbc /usr/local /usr/odbc \
- /usr /opt/local/pgm/odbc /usr/local/pgm/odbc; do
+ /usr /opt/local/pgm/odbc /usr/local/pgm/odbc \
+ "$with_odbc"; do
test -f "$erl_xcomp_isysroot$rdir/include/sql.h" || continue
is_odbc_std_location=yes
libdir="$erl_xcomp_sysroot$rdir/lib"
diff --git a/lib/public_key/src/pubkey_pbe.erl b/lib/public_key/src/pubkey_pbe.erl
index 43f6c42f10..6f0be53db9 100644
--- a/lib/public_key/src/pubkey_pbe.erl
+++ b/lib/public_key/src/pubkey_pbe.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -23,7 +23,7 @@
-include("public_key.hrl").
-export([encode/4, decode/4, decrypt_parameters/1]).
--export([pbdkdf1/4, pbdkdf2/6]).
+-export([pbdkdf1/4, pbdkdf2/7]).
-define(DEFAULT_SHA_MAC_KEYLEN, 20).
-define(ASN1_OCTET_STR_TAG, 4).
@@ -40,16 +40,16 @@
%%--------------------------------------------------------------------
encode(Data, Password, "DES-CBC" = Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
- crypto:des_cbc_encrypt(Key, IV, Data);
+ crypto:block_encrypt(des_cbc, Key, IV, Data);
encode(Data, Password, "DES-EDE3-CBC" = Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
<<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key,
- crypto:des_ede3_cbc_encrypt(Key1, Key2, Key3, IV, Data);
+ crypto:block_encrypt(des3_cbc, [Key1, Key2, Key3], IV, Data);
encode(Data, Password, "RC2-CBC" = Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
- crypto:rc2_cbc_encrypt(Key, IV, Data).
+ crypto:block_encrypt(rc2_cbc, Key, IV, Data).
%%--------------------------------------------------------------------
-spec decode(binary(), string(), string(), term()) -> binary().
%%
@@ -57,16 +57,16 @@ encode(Data, Password, "RC2-CBC" = Cipher, KeyDevParams) ->
%%--------------------------------------------------------------------
decode(Data, Password,"DES-CBC"= Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
- crypto:des_cbc_decrypt(Key, IV, Data);
+ crypto:block_decrypt(des_cbc, Key, IV, Data);
decode(Data, Password,"DES-EDE3-CBC" = Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
<<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key,
- crypto:des_ede3_cbc_decrypt(Key1, Key2, Key3, IV, Data);
+ crypto:block_decrypt(des3_cbc, [Key1, Key2, Key3], IV, Data);
decode(Data, Password,"RC2-CBC"= Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
- crypto:rc2_cbc_decrypt(Key, IV, Data).
+ crypto:block_decrypt(rc2_cbc, Key, IV, Data).
%%--------------------------------------------------------------------
-spec pbdkdf1(string(), iodata(), integer(), atom()) -> binary().
@@ -77,21 +77,21 @@ decode(Data, Password,"RC2-CBC"= Cipher, KeyDevParams) ->
pbdkdf1(_, _, 0, Acc) ->
Acc;
pbdkdf1(Password, Salt, Count, Hash) ->
- Result = crypto:Hash([Password, Salt]),
+ Result = crypto:hash(Hash, [Password, Salt]),
do_pbdkdf1(Result, Count-1, Result, Hash).
%%--------------------------------------------------------------------
--spec pbdkdf2(string(), iodata(), integer(), integer(), fun(), integer())
+-spec pbdkdf2(string(), iodata(), integer(), integer(), fun(), atom(), integer())
-> binary().
%%
%% Description: Implements password based decryption key derive function 2.
%% Exported mainly for testing purposes.
%%--------------------------------------------------------------------
-pbdkdf2(Password, Salt, Count, DerivedKeyLen, Prf, PrfOutputLen)->
+pbdkdf2(Password, Salt, Count, DerivedKeyLen, Prf, PrfHash, PrfOutputLen)->
NumBlocks = ceiling(DerivedKeyLen / PrfOutputLen),
NumLastBlockOctets = DerivedKeyLen - (NumBlocks - 1) * PrfOutputLen ,
blocks(NumBlocks, NumLastBlockOctets, 1, Password, Salt,
- Count, Prf, PrfOutputLen, <<>>).
+ Count, Prf, PrfHash, PrfOutputLen, <<>>).
%%--------------------------------------------------------------------
-spec decrypt_parameters(#'EncryptedPrivateKeyInfo_encryptionAlgorithm'{}) ->
{Cipher::string(), #'PBES2-params'{}}.
@@ -106,10 +106,10 @@ decrypt_parameters(#'EncryptedPrivateKeyInfo_encryptionAlgorithm'{
%%% Internal functions
%%--------------------------------------------------------------------
password_to_key_and_iv(Password, _, #'PBES2-params'{} = Params) ->
- {Salt, ItrCount, KeyLen, PseudoRandomFunction, PseudoOtputLen, IV} =
+ {Salt, ItrCount, KeyLen, PseudoRandomFunction, PseudoHash, PseudoOtputLen, IV} =
key_derivation_params(Params),
<<Key:KeyLen/binary, _/binary>> =
- pbdkdf2(Password, Salt, ItrCount, KeyLen, PseudoRandomFunction, PseudoOtputLen),
+ pbdkdf2(Password, Salt, ItrCount, KeyLen, PseudoRandomFunction, PseudoHash, PseudoOtputLen),
{Key, IV};
password_to_key_and_iv(Password, Cipher, Salt) ->
KeyLen = derived_key_length(Cipher, undefined),
@@ -122,13 +122,13 @@ password_to_key_and_iv(Password, Cipher, Salt) ->
pem_encrypt(_, _, _, 0, Acc, _) ->
Acc;
pem_encrypt(Prev, Password, Salt, Count, Acc, Hash) ->
- Result = crypto:Hash([Prev, Password, Salt]),
+ Result = crypto:hash(Hash, [Prev, Password, Salt]),
pem_encrypt(Result, Password, Salt, Count-1 , <<Acc/binary, Result/binary>>, Hash).
do_pbdkdf1(_, 0, Acc, _) ->
Acc;
do_pbdkdf1(Prev, Count, Acc, Hash) ->
- Result = crypto:Hash(Prev),
+ Result = crypto:hash(Hash, Prev),
do_pbdkdf1(Result, Count-1 , <<Result/binary, Acc/binary>>, Hash).
iv(#'PBES2-params_encryptionScheme'{algorithm = Algo,
@@ -143,23 +143,23 @@ iv(#'PBES2-params_encryptionScheme'{algorithm = ?'rc2CBC',
{ok, #'RC2-CBC-Parameter'{iv = IV}} = 'PKCS-FRAME':decode('RC2-CBC-Parameter', ASN1IV),
iolist_to_binary(IV).
-blocks(1, N, Index, Password, Salt, Count, Prf, PrfLen, Acc) ->
- <<XorSum:N/binary, _/binary>> = xor_sum(Password, Salt, Count, Index, Prf, PrfLen),
+blocks(1, N, Index, Password, Salt, Count, Prf, PrfHash, PrfLen, Acc) ->
+ <<XorSum:N/binary, _/binary>> = xor_sum(Password, Salt, Count, Index, Prf, PrfHash, PrfLen),
<<Acc/binary, XorSum/binary>>;
-blocks(NumBlocks, N, Index, Password, Salt, Count, Prf, PrfLen, Acc) ->
- XorSum = xor_sum(Password, Salt, Count, Index, Prf, PrfLen),
- blocks(NumBlocks -1, N, Index +1, Password, Salt, Count, Prf,
+blocks(NumBlocks, N, Index, Password, Salt, Count, Prf, PrfHash, PrfLen, Acc) ->
+ XorSum = xor_sum(Password, Salt, Count, Index, Prf, PrfHash, PrfLen),
+ blocks(NumBlocks -1, N, Index +1, Password, Salt, Count, Prf, PrfHash,
PrfLen, <<Acc/binary, XorSum/binary>>).
-xor_sum(Password, Salt, Count, Index, Prf, PrfLen) ->
- Result = Prf(Password, [Salt,<<Index:32/unsigned-big-integer>>], PrfLen),
- do_xor_sum(Prf, PrfLen, Result, Password, Count-1, Result).
+xor_sum(Password, Salt, Count, Index, Prf, PrfHash, PrfLen) ->
+ Result = Prf(PrfHash, Password, [Salt,<<Index:32/unsigned-big-integer>>], PrfLen),
+ do_xor_sum(Prf, PrfHash, PrfLen, Result, Password, Count-1, Result).
-do_xor_sum(_, _, _, _, 0, Acc) ->
+do_xor_sum(_, _, _, _, _, 0, Acc) ->
Acc;
-do_xor_sum(Prf, PrfLen, Prev, Password, Count, Acc)->
- Result = Prf(Password, Prev, PrfLen),
- do_xor_sum(Prf, PrfLen, Result, Password, Count-1, crypto:exor(Acc, Result)).
+do_xor_sum(Prf, PrfHash, PrfLen, Prev, Password, Count, Acc)->
+ Result = Prf(PrfHash, Password, Prev, PrfLen),
+ do_xor_sum(Prf, PrfHash, PrfLen, Result, Password, Count-1, crypto:exor(Acc, Result)).
decrypt_parameters(?'id-PBES2', DekParams) ->
{ok, Params} = 'PKCS-FRAME':decode('PBES2-params', DekParams),
@@ -174,18 +174,18 @@ key_derivation_params(#'PBES2-params'{keyDerivationFunc = KeyDerivationFunc,
keyLength = Length,
prf = Prf}} = KeyDerivationFunc,
#'PBES2-params_encryptionScheme'{algorithm = Algo} = EncScheme,
- {PseudoRandomFunction, PseudoOtputLen} = pseudo_random_function(Prf),
+ {PseudoRandomFunction, PseudoHash, PseudoOtputLen} = pseudo_random_function(Prf),
KeyLen = derived_key_length(Algo, Length),
{OctetSalt, Count, KeyLen,
- PseudoRandomFunction, PseudoOtputLen, iv(EncScheme)}.
+ PseudoRandomFunction, PseudoHash, PseudoOtputLen, iv(EncScheme)}.
%% This function currently matches a tuple that ougth to be the value
%% ?'id-hmacWithSHA1, but we need some kind of ASN1-fix for this.
pseudo_random_function(#'PBKDF2-params_prf'{algorithm =
{_,_, _,'id-hmacWithSHA1'}}) ->
- {fun crypto:sha_mac/3, pseudo_output_length(?'id-hmacWithSHA1')};
+ {fun crypto:hmac/4, sha, pseudo_output_length(?'id-hmacWithSHA1')};
pseudo_random_function(#'PBKDF2-params_prf'{algorithm = ?'id-hmacWithSHA1'}) ->
- {fun crypto:sha_mac/3, pseudo_output_length(?'id-hmacWithSHA1')}.
+ {fun crypto:hmac/4, sha, pseudo_output_length(?'id-hmacWithSHA1')}.
pseudo_output_length(?'id-hmacWithSHA1') ->
?DEFAULT_SHA_MAC_KEYLEN.
diff --git a/lib/public_key/src/pubkey_ssh.erl b/lib/public_key/src/pubkey_ssh.erl
index 008ea96dd3..aed1f57bbc 100644
--- a/lib/public_key/src/pubkey_ssh.erl
+++ b/lib/public_key/src/pubkey_ssh.erl
@@ -362,18 +362,18 @@ comma_list_encode([Option | Rest], Acc) ->
ssh2_pubkey_encode(#'RSAPublicKey'{modulus = N, publicExponent = E}) ->
TypeStr = <<"ssh-rsa">>,
StrLen = size(TypeStr),
- EBin = crypto:mpint(E),
- NBin = crypto:mpint(N),
+ EBin = mpint(E),
+ NBin = mpint(N),
<<?UINT32(StrLen), TypeStr:StrLen/binary,
EBin/binary,
NBin/binary>>;
ssh2_pubkey_encode({Y, #'Dss-Parms'{p = P, q = Q, g = G}}) ->
TypeStr = <<"ssh-dss">>,
StrLen = size(TypeStr),
- PBin = crypto:mpint(P),
- QBin = crypto:mpint(Q),
- GBin = crypto:mpint(G),
- YBin = crypto:mpint(Y),
+ PBin = mpint(P),
+ QBin = mpint(Q),
+ GBin = mpint(G),
+ YBin = mpint(Y),
<<?UINT32(StrLen), TypeStr:StrLen/binary,
PBin/binary,
QBin/binary,
@@ -476,3 +476,32 @@ split_n(N, Bin, Acc) ->
[Last] ->
split_n(0, <<>>, [Last | Acc])
end.
+%% large integer in a binary with 32bit length
+%% MP representaion (SSH2)
+mpint(X) when X < 0 -> mpint_neg(X);
+mpint(X) -> mpint_pos(X).
+
+mpint_neg(X) ->
+ Bin = int_to_bin_neg(X, []),
+ Sz = byte_size(Bin),
+ <<?UINT32(Sz), Bin/binary>>.
+
+mpint_pos(X) ->
+ Bin = int_to_bin_pos(X, []),
+ <<MSB,_/binary>> = Bin,
+ Sz = byte_size(Bin),
+ if MSB band 16#80 == 16#80 ->
+ <<?UINT32((Sz+1)), 0, Bin/binary>>;
+ true ->
+ <<?UINT32(Sz), Bin/binary>>
+ end.
+
+int_to_bin_pos(0,Ds=[_|_]) ->
+ list_to_binary(Ds);
+int_to_bin_pos(X,Ds) ->
+ int_to_bin_pos(X bsr 8, [(X band 255)|Ds]).
+
+int_to_bin_neg(-1, Ds=[MSB|_]) when MSB >= 16#80 ->
+ list_to_binary(Ds);
+int_to_bin_neg(X,Ds) ->
+ int_to_bin_neg(X bsr 8, [(X band 255)|Ds]).
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 648dba3d5a..3eea6f6ec4 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -347,7 +347,7 @@ generate_key(#'ECParameters'{} = Params) ->
compute_key(#'ECPoint'{point = Point}, #'ECPrivateKey'{privateKey = PrivKey,
parameters = Param}) ->
ECCurve = ec_curve_spec(Param),
- crypto:compute_key(ecdh, Point, list2int(PrivKey), ECCurve).
+ crypto:compute_key(ecdh, Point, list_to_binary(PrivKey), ECCurve).
compute_key(PubKey, PrivKey, #'DHParameter'{prime = P, base = G}) ->
crypto:compute_key(dh, PubKey, PrivKey, [P, G]).
@@ -402,7 +402,7 @@ sign(DigestOrPlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) ->
sign(DigestOrPlainText, DigestType, #'ECPrivateKey'{privateKey = PrivKey,
parameters = Param}) ->
ECCurve = ec_curve_spec(Param),
- crypto:sign(ecdsa, DigestType, DigestOrPlainText, [list2int(PrivKey), ECCurve]);
+ crypto:sign(ecdsa, DigestType, DigestOrPlainText, [list_to_binary(PrivKey), ECCurve]);
%% Backwards compatible
sign(Digest, none, #'DSAPrivateKey'{} = Key) ->
@@ -878,16 +878,8 @@ ec_curve_spec( #'ECParameters'{fieldID = FieldId, curve = PCurve, base = Base, o
ec_curve_spec({namedCurve, OID}) ->
pubkey_cert_records:namedCurves(OID).
-ec_key({PrivateKey, PubKey}, Params) ->
+ec_key({PubKey, PrivateKey}, Params) ->
#'ECPrivateKey'{version = 1,
- privateKey = int2list(PrivateKey),
+ privateKey = binary_to_list(PrivateKey),
parameters = Params,
publicKey = {0, PubKey}}.
-
-list2int(L) ->
- S = length(L) * 8,
- <<R:S/integer>> = erlang:iolist_to_binary(L),
- R.
-int2list(I) ->
- L = (length(integer_to_list(I, 16)) + 1) div 2,
- binary_to_list(<<I:(L*8)>>).
diff --git a/lib/public_key/test/erl_make_certs.erl b/lib/public_key/test/erl_make_certs.erl
index 14efbcc7e0..5926794ca8 100644
--- a/lib/public_key/test/erl_make_certs.erl
+++ b/lib/public_key/test/erl_make_certs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -114,8 +114,8 @@ verify_signature(DerEncodedCert, DerKey, _KeyParams) ->
#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} ->
public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}});
#'ECPrivateKey'{version = _Version, privateKey = _PrivKey,
- parameters = _Params, publicKey = _PubKey} ->
- public_key:pkix_verify(DerEncodedCert, Key)
+ parameters = Params, publicKey = {0, PubKey}} ->
+ public_key:pkix_verify(DerEncodedCert, {#'ECPoint'{point = PubKey}, Params})
end.
%%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -253,7 +253,7 @@ extensions(Opts) ->
end.
default_extensions(Exts) ->
- Def = [{key_usage, default},
+ Def = [{key_usage, default},
{subject_altname, undefined},
{issuer_altname, undefined},
{basic_constraints, default},
@@ -267,6 +267,8 @@ default_extensions(Exts) ->
Filter = fun({Key, _}, D) -> lists:keydelete(Key, 1, D) end,
Exts ++ lists:foldl(Filter, Def, Exts).
+
+
extension({_, undefined}) -> [];
extension({basic_constraints, Data}) ->
case Data of
@@ -284,11 +286,9 @@ extension({basic_constraints, Data}) ->
#'Extension'{extnID = ?'id-ce-basicConstraints',
extnValue = Data}
end;
-
extension({key_usage, default}) ->
#'Extension'{extnID = ?'id-ce-keyUsage',
extnValue = [keyCertSign], critical = true};
-
extension({Id, Data, Critical}) ->
#'Extension'{extnID = Id, extnValue = Data, critical = Critical}.
@@ -396,37 +396,32 @@ gen_dsa2(LSize, NSize) ->
error ->
gen_dsa2(LSize, NSize);
P ->
- G = crypto:mod_exp(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q.
+ G = crypto:mod_pow(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q.
%% such that This may be done by setting g = h^(p-1)/q mod p, commonly h=2 is used.
X = prime(20), %% Choose x by some random method, where 0 < x < q.
- Y = crypto:mod_exp(G, X, P), %% Calculate y = g^x mod p.
+ Y = crypto:mod_pow(G, X, P), %% Calculate y = g^x mod p.
- #'DSAPrivateKey'{version=0, p=P, q=Q, g=G, y=Y, x=X}
+ #'DSAPrivateKey'{version=0, p = P, q = Q,
+ g = crypto:bytes_to_integer(G), y = crypto:bytes_to_integer(Y), x = X}
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% EC key generation (OBS: for testing only)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-int2list(I) ->
- L = (length(integer_to_list(I, 16)) + 1) div 2,
- binary_to_list(<<I:(L*8)>>).
-
gen_ec2(CurveId) ->
- Key = crypto:ec_key_new(CurveId),
- crypto:ec_key_generate(Key),
- {_Curve, PrivKey, PubKey} = crypto:ec_key_to_term(Key),
+ {PubKey, PrivKey} = crypto:generate_key(ecdh, CurveId),
#'ECPrivateKey'{version = 1,
- privateKey = int2list(PrivKey),
+ privateKey = binary_to_list(PrivKey),
parameters = {namedCurve, pubkey_cert_records:namedCurves(CurveId)},
publicKey = {0, PubKey}}.
%% See fips_186-3.pdf
dsa_search(T, P0, Q, Iter) when Iter > 0 ->
P = 2*T*Q*P0 + 1,
- case is_prime(crypto:mpint(P), 50) of
+ case is_prime(P, 50) of
true -> P;
false -> dsa_search(T+1, P0, Q, Iter-1)
end;
@@ -437,38 +432,40 @@ dsa_search(_,_,_,_) ->
%%%%%%% Crypto Math %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
prime(ByteSize) ->
Rand = odd_rand(ByteSize),
- crypto:erlint(prime_odd(Rand, 0)).
+ prime_odd(Rand, 0).
prime_odd(Rand, N) ->
case is_prime(Rand, 50) of
true ->
Rand;
false ->
- NotPrime = crypto:erlint(Rand),
- prime_odd(crypto:mpint(NotPrime+2), N+1)
+ prime_odd(Rand+2, N+1)
end.
%% see http://en.wikipedia.org/wiki/Fermat_primality_test
is_prime(_, 0) -> true;
is_prime(Candidate, Test) ->
- CoPrime = odd_rand(<<0,0,0,4, 10000:32>>, Candidate),
- case crypto:mod_exp(CoPrime, Candidate, Candidate) of
- CoPrime -> is_prime(Candidate, Test-1);
- _ -> false
- end.
+ CoPrime = odd_rand(10000, Candidate),
+ Result = crypto:mod_pow(CoPrime, Candidate, Candidate) ,
+ is_prime(CoPrime, crypto:bytes_to_integer(Result), Candidate, Test).
+
+is_prime(CoPrime, CoPrime, Candidate, Test) ->
+ is_prime(Candidate, Test-1);
+is_prime(_,_,_,_) ->
+ false.
odd_rand(Size) ->
Min = 1 bsl (Size*8-1),
Max = (1 bsl (Size*8))-1,
- odd_rand(crypto:mpint(Min), crypto:mpint(Max)).
+ odd_rand(Min, Max).
odd_rand(Min,Max) ->
- Rand = <<Sz:32, _/binary>> = crypto:rand_uniform(Min,Max),
- BitSkip = (Sz+4)*8-1,
- case Rand of
- Odd = <<_:BitSkip, 1:1>> -> Odd;
- Even = <<_:BitSkip, 0:1>> ->
- crypto:mpint(crypto:erlint(Even)+1)
+ Rand = crypto:rand_uniform(Min,Max),
+ case Rand rem 2 of
+ 0 ->
+ Rand + 1;
+ _ ->
+ Rand
end.
extended_gcd(A, B) ->
@@ -487,3 +484,6 @@ pem_to_der(File) ->
der_to_pem(File, Entries) ->
PemBin = public_key:pem_encode(Entries),
file:write_file(File, PemBin).
+
+
+
diff --git a/lib/public_key/test/pbe_SUITE.erl b/lib/public_key/test/pbe_SUITE.erl
index 8fba1e8cd3..254601b107 100644
--- a/lib/public_key/test/pbe_SUITE.erl
+++ b/lib/public_key/test/pbe_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -109,7 +109,7 @@ pbdkdf2(Config) when is_list(Config) ->
<<16#0c, 16#60, 16#c8, 16#0f, 16#96, 16#1f, 16#0e, 16#71,
16#f3, 16#a9, 16#b5, 16#24, 16#af, 16#60, 16#12, 16#06,
- 16#2f, 16#e0, 16#37, 16#a6>> = pubkey_pbe:pbdkdf2("password", "salt", 1, 20, fun crypto:sha_mac/3, 20),
+ 16#2f, 16#e0, 16#37, 16#a6>> = pubkey_pbe:pbdkdf2("password", "salt", 1, 20, fun crypto:hmac/4, sha, 20),
%% Input:
%% P = "password" (8 octets)
@@ -125,7 +125,7 @@ pbdkdf2(Config) when is_list(Config) ->
<<16#ea, 16#6c, 16#01, 16#4d, 16#c7, 16#2d, 16#6f, 16#8c,
16#cd, 16#1e, 16#d9, 16#2a, 16#ce, 16#1d, 16#41, 16#f0,
16#d8, 16#de, 16#89, 16#57>> =
- pubkey_pbe:pbdkdf2("password", "salt", 2, 20, fun crypto:sha_mac/3, 20),
+ pubkey_pbe:pbdkdf2("password", "salt", 2, 20, fun crypto:hmac/4, sha, 20),
%% Input:
%% P = "password" (8 octets)
@@ -140,7 +140,7 @@ pbdkdf2(Config) when is_list(Config) ->
<<16#4b, 16#00, 16#79, 16#01, 16#b7, 16#65, 16#48, 16#9a,
16#be, 16#ad, 16#49, 16#d9, 16#26, 16#f7, 16#21, 16#d0,
- 16#65, 16#a4, 16#29, 16#c1>> = pubkey_pbe:pbdkdf2("password", "salt", 4096, 20, fun crypto:sha_mac/3, 20),
+ 16#65, 16#a4, 16#29, 16#c1>> = pubkey_pbe:pbdkdf2("password", "salt", 4096, 20, fun crypto:hmac/4, sha, 20),
%% Input:
%% P = "password" (8 octets)
@@ -156,7 +156,7 @@ pbdkdf2(Config) when is_list(Config) ->
<<16#ee, 16#fe, 16#3d, 16#61, 16#cd, 16#4d, 16#a4, 16#e4,
16#e9, 16#94, 16#5b, 16#3d, 16#6b, 16#a2, 16#15, 16#8c,
- 16#26, 16#34, 16#e9, 16#84>> = pubkey_pbe:pbdkdf2("password", "salt", 16777216, 20, fun crypto:sha_mac/3, 20),
+ 16#26, 16#34, 16#e9, 16#84>> = pubkey_pbe:pbdkdf2("password", "salt", 16777216, 20, fun crypto:hmac/4, sha, 20),
%% Input:
%% P = "passwordPASSWORDpassword" (24 octets)
@@ -175,7 +175,7 @@ pbdkdf2(Config) when is_list(Config) ->
16#8b, 16#29, 16#1a, 16#96, 16#4c, 16#f2, 16#f0, 16#70,
16#38>>
= pubkey_pbe:pbdkdf2("passwordPASSWORDpassword",
- "saltSALTsaltSALTsaltSALTsaltSALTsalt", 4096, 25, fun crypto:sha_mac/3, 20),
+ "saltSALTsaltSALTsaltSALTsaltSALTsalt", 4096, 25, fun crypto:hmac/4, sha, 20),
%% Input:
%% P = "pass\0word" (9 octets)
@@ -190,7 +190,7 @@ pbdkdf2(Config) when is_list(Config) ->
<<16#56, 16#fa, 16#6a, 16#a7, 16#55, 16#48, 16#09, 16#9d,
16#cc, 16#37, 16#d7, 16#f0, 16#34, 16#25, 16#e0, 16#c3>>
= pubkey_pbe:pbdkdf2("pass\0word",
- "sa\0lt", 4096, 16, fun crypto:sha_mac/3, 20).
+ "sa\0lt", 4096, 16, fun crypto:hmac/4, sha, 20).
encrypted_private_key_info() ->
[{doc,"Tests reading a EncryptedPrivateKeyInfo file encrypted with different ciphers"}].
diff --git a/lib/public_key/test/pkits_SUITE.erl b/lib/public_key/test/pkits_SUITE.erl
index 8cdf0aaae3..c490493e13 100644
--- a/lib/public_key/test/pkits_SUITE.erl
+++ b/lib/public_key/test/pkits_SUITE.erl
@@ -758,7 +758,9 @@ warning(Format, Args, File0, Line) ->
io:format("~s(~p): Warning "++Format, [File,Line|Args]).
crypto_support_check(Config) ->
- case proplists:get_bool(sha256, crypto:algorithms()) of
+ CryptoSupport = crypto:supports(),
+ Hashs = proplists:get_value(hashs, CryptoSupport),
+ case proplists:get_bool(sha256, Hashs) of
true ->
Config;
false ->
diff --git a/lib/reltool/doc/src/reltool_examples.xml b/lib/reltool/doc/src/reltool_examples.xml
index 19a3f37819..de243343ff 100644
--- a/lib/reltool/doc/src/reltool_examples.xml
+++ b/lib/reltool/doc/src/reltool_examples.xml
@@ -261,7 +261,8 @@ Eshell V5.7.3 (abort with ^G)
8&gt; reltool:get_script(Server, "NAME").
{ok,{script,{"NAME","VSN"},
[{preLoaded,[erl_prim_loader,erlang,init,otp_ring0,
- prim_file,prim_inet,prim_zip,zlib]},
+ prim_eval,prim_file,prim_inet,prim_zip,
+ zlib]},
{progress,preloaded},
{path,["$ROOT/lib/kernel-2.13/ebin",
"$ROOT/lib/stdlib-1.16/ebin"]},
diff --git a/lib/runtime_tools/src/observer_backend.erl b/lib/runtime_tools/src/observer_backend.erl
index d1d291d5cb..670e216d97 100644
--- a/lib/runtime_tools/src/observer_backend.erl
+++ b/lib/runtime_tools/src/observer_backend.erl
@@ -49,6 +49,10 @@ vsn() ->
%% observer backend
%%
sys_info() ->
+ MemInfo = try erlang:memory() of
+ Mem -> Mem
+ catch _:_ -> []
+ end,
{{_,Input},{_,Output}} = erlang:statistics(io),
[{process_count, erlang:system_info(process_count)},
{process_limit, erlang:system_info(process_limit)},
@@ -68,9 +72,16 @@ sys_info() ->
{threads, erlang:system_info(threads)},
{thread_pool_size, erlang:system_info(thread_pool_size)},
{wordsize_internal, erlang:system_info({wordsize, internal})},
- {wordsize_external, erlang:system_info({wordsize, external})} |
- erlang:memory()
- ].
+ {wordsize_external, erlang:system_info({wordsize, external})},
+ {alloc_info, alloc_info()}
+ | MemInfo].
+
+alloc_info() ->
+ {_,_,AllocTypes,_} = erlang:system_info(allocator),
+ try erlang:system_info({allocator_sizes,AllocTypes}) of
+ Allocators -> Allocators
+ catch _:_ -> []
+ end.
get_table(Parent, Table, Module) ->
spawn(fun() ->
@@ -274,7 +285,7 @@ etop_collect([P|Ps], Acc) ->
[{registered_name,Reg},{initial_call,Initial},{memory,Mem},
{reductions,Reds},{current_function,Current},{message_queue_len,Qlen}] ->
Name = case Reg of
- [] -> Initial;
+ [] -> initial_call(Initial, P);
_ -> Reg
end,
Info = #etop_proc_info{pid=P,mem=Mem,reds=Reds,name=Name,
@@ -283,6 +294,11 @@ etop_collect([P|Ps], Acc) ->
end;
etop_collect([], Acc) -> Acc.
+initial_call({proc_lib, init_p, _}, Pid) ->
+ proc_lib:translate_initial_call(Pid);
+initial_call(Initial, _Pid) ->
+ Initial.
+
%%
%% ttb backend
%%
diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl
index 193dbb64bf..b2e95fdbee 100644
--- a/lib/sasl/src/systools_make.erl
+++ b/lib/sasl/src/systools_make.erl
@@ -1461,8 +1461,8 @@ mandatory_modules() ->
preloaded() ->
%% Sorted
- [erl_prim_loader,erlang,erts_internal,init,otp_ring0,prim_file,prim_inet,
- prim_zip,zlib].
+ [erl_prim_loader,erlang,erts_internal,init,otp_ring0,prim_eval,prim_file,
+ prim_inet,prim_zip,zlib].
%%______________________________________________________________________
%% Kernel processes; processes that are specially treated by the init
diff --git a/lib/snmp/.gitignore b/lib/snmp/.gitignore
index b82d23e7bd..650c1d6865 100644
--- a/lib/snmp/.gitignore
+++ b/lib/snmp/.gitignore
@@ -1,4 +1,9 @@
# Match at any level.
*.BKP
+*.orig
+*.rej
+
+doc/index.html
+
diff --git a/lib/snmp/doc/src/files.mk b/lib/snmp/doc/src/files.mk
index 61c91c9729..494c550fff 100644
--- a/lib/snmp/doc/src/files.mk
+++ b/lib/snmp/doc/src/files.mk
@@ -41,6 +41,8 @@ XML_AGENT_REF3_FILES = \
snmpa_error_io.xml \
snmpa_error_logger.xml \
snmpa_local_db.xml \
+ snmpa_mib_data.xml \
+ snmpa_mib_storage.xml \
snmpa_mpd.xml \
snmpa_network_interface.xml \
snmpa_network_interface_filter.xml \
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml
index 5222922848..80de9738f1 100644
--- a/lib/snmp/doc/src/notes.xml
+++ b/lib/snmp/doc/src/notes.xml
@@ -34,6 +34,88 @@
<section>
+ <title>SNMP Development Toolkit 4.24</title>
+ <p>Version 4.24 supports code replacement in runtime from/to
+ version 4.23.1 and 4.23. </p>
+
+ <section>
+ <title>Improvements and new features</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>[agent,manager] Updated to support the new crypto interface. </p>
+ <p>Own Id: OTP-11009</p>
+ </item>
+
+ <item>
+ <p>[agent] Introduced a documented behaviour for the mib-server
+ <seealso marker="snmpa_mib_data">mib-data backend</seealso>.
+ At present only the default module (<c>snmpa_mib_data_tttn</c>) is
+ provided. </p>
+ <p>A config option for the (agent)
+ <seealso marker="snmp_config#agent_mib_server">mib-servers</seealso>
+ mib-data backend module has been added to the agent config options,
+ <seealso marker="snmp_config#agent_ms_data_module">data_module</seealso>. </p>
+ <p>Own Id: OTP-11101</p>
+ </item>
+
+ <item>
+ <p>[agent] Introduced a documented behaviour for the
+ <seealso marker="snmpa_mib_storage">mib storage</seealso>.
+ At present there are three simple modules
+ (<c>snmpa_mib_storage_ets</c>, <c>snmpa_mib_storage_dets</c> and
+ <c>snmpa_mib_storage_mnesia</c>) implement�ng this behaviour,
+ provided with the app. </p>
+ <p>A config option for the (agent)
+ <seealso marker="snmp_config#agent_mib_storage">mib storage</seealso>
+ has been added to the agent config options. </p>
+ <p>Own Id: OTP-11107</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Fixed Bugs and Malfunctions</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>[agent,manager] Updated to support the new crypto interface. </p>
+ <p>Own Id: OTP-11009</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>[manager] The old Addr-and-Port based API functions, previously
+ long deprecated and marked for deletion in R16B, has now been
+ removed. </p>
+ <p>Own Id: OTP-10027</p>
+ </item>
+
+ </list>
+-->
+ </section>
+
+ </section> <!-- 4.24 -->
+
+
+ <section>
<title>SNMP Development Toolkit 4.23.1</title>
<p>Version 4.23.1 supports code replacement in runtime from/to
version 4.23. </p>
@@ -1017,135 +1099,6 @@
</section> <!-- 4.20 -->
- <section>
- <title>SNMP Development Toolkit 4.19</title>
- <p>Version 4.19 supports code replacement in runtime from/to
- version 4.18.</p>
-
- <section>
- <title>Improvements and new features</title>
-<!--
- <p>-</p>
--->
- <list type="bulleted">
- <item>
- <p>[compiler] Added support for textual convention
- <c>AGENT-CAPABILITIES</c> and "full" support for textual
- convention MODULE-COMPLIANCE, both defined by the SNMPv2-CONF
- mib.</p>
- <p>The <c>reference</c> and <c>modules</c> part(s) are
- stored in the <c>assocList</c> of the mib-entry (<c>me</c>)
- record.
- Only handled <em>if</em> the option(s) <c>agent_capabilities</c>
- and <c>module_compliance</c> (respectively) are provided to the
- compiler. </p>
- <p>See <seealso marker="snmpc#compile">compile/2</seealso>
- for more info. </p>
- <p>For backward compatibillity, the MIBs provided with
- this application are <em>not</em> compiled with these
- options. </p>
- <p>Own Id: OTP-8966</p>
- </item>
-
- <item>
- <p>[agent] Added a "complete" set of (snmp) table and variable
- print functions, for each mib handled by the SNMP (agent)
- application. This will be usefull when debugging a running agent.</p>
- <p>See
- <seealso marker="snmpa#print_mib_info">print_mib_info/0</seealso>,
- <seealso marker="snmpa#print_mib_tables">print_mib_tables/0</seealso>
- and
- <seealso marker="snmpa#print_mib_variables">print_mib_variables/0</seealso>
- for more info. </p>
- <p>Own Id: OTP-8977</p>
- </item>
-
- <item>
- <p>[compiler] Added a MIB compiler (frontend) escript,
- <c>snmpc</c>. </p>
- <p>Own Id: OTP-9004</p>
- </item>
-
- </list>
- </section>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
-<!--
- <p>-</p>
--->
- <list type="bulleted">
- <item>
- <p>[agent] For the table vacmAccessTable,
- when performing the is_set_ok and set operation(s),
- all values of the vacmAccessSecurityModel column was
- incorrectly translated to <c>any</c>. </p>
-<!--
-that is when calling:
-snmp_view_basec_acm_mib:vacmAccessTable(set, RowIndex, Cols).
--->
- <p>Own Id: OTP-8980</p>
- </item>
-
- <item>
- <p>[agent] When calling
- <seealso marker="snmp_view_based_acm_mib#reconfigure">snmp_view_based_acm_mib:reconfigure/1</seealso>
- on a running node, the table <c>vacmAccessTable</c> was not properly
- cleaned.
- This meant that if some entries in the vacm.conf file was removed
- (compared to the <c>current</c> config),
- while others where modified and/or added, the removed entrie(s)
- would still exist in the <c>vacmAccessTable</c> table. </p>
- <p>Own Id: OTP-8981</p>
- <p>Aux Id: Seq 11750</p>
- </item>
-
- </list>
- </section>
-
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
-
- </section> <!-- 4.19 -->
-
-
- <section>
- <title>SNMP Development Toolkit 4.18</title>
- <p>Version 4.18 supports code replacement in runtime from/to
- version 4.17.1 and 4.17.</p>
-
- <section>
- <title>Improvements and new features</title>
- <list type="bulleted">
- <item>
- <p>Prepared for R14B release.</p>
- </item>
- </list>
- </section>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <p>-</p>
-<!--
- <list type="bulleted">
- <item>
- <p>[agent] When the function FilterMod:accept_recv/2 returned false
- the SNMP agent stopped collecting messages from UDP.</p>
- <p>Own Id: OTP-8761</p>
- </item>
- </list>
--->
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.18 -->
-
-
<!-- section>
<title>Release notes history</title>
<p>For information about older versions see
diff --git a/lib/snmp/doc/src/ref_man.xml b/lib/snmp/doc/src/ref_man.xml
index 92e8927f6d..628b30b11a 100644
--- a/lib/snmp/doc/src/ref_man.xml
+++ b/lib/snmp/doc/src/ref_man.xml
@@ -44,6 +44,8 @@
<xi:include href="snmpa_error_io.xml"/>
<xi:include href="snmpa_error_logger.xml"/>
<xi:include href="snmpa_local_db.xml"/>
+ <xi:include href="snmpa_mib_data.xml"/>
+ <xi:include href="snmpa_mib_storage.xml"/>
<xi:include href="snmpa_mpd.xml"/>
<xi:include href="snmpa_network_interface.xml"/>
<xi:include href="snmpa_network_interface_filter.xml"/>
diff --git a/lib/snmp/doc/src/snmp_app.xml b/lib/snmp/doc/src/snmp_app.xml
index 62dfa515d1..e5a05342c1 100644
--- a/lib/snmp/doc/src/snmp_app.xml
+++ b/lib/snmp/doc/src/snmp_app.xml
@@ -4,7 +4,7 @@
<appref>
<header>
<copyright>
- <year>1997</year><year>2012</year>
+ <year>1997</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -311,36 +311,125 @@
<p>Default is <c>[]</c>.</p>
</item>
- <marker id="agent_mib_storage"></marker>
- <tag><c><![CDATA[mib_storage() = ets | {ets, Dir} | {ets, Dir, Action} | dets | {dets, Dir} | {dets, Dir, Action} | mnesia | {mnesia, Nodes} | {mnesia, Nodes, Action} <optional>]]></c></tag>
- <item>
- <p>Specifies how info retrieved from the mibs will be stored.</p>
- <p>If <c>mib_storage</c> is <c>{ets, Dir}</c>, the table will also be
- stored on file. If <c>Dir</c> is <c>default</c>, then <c>db_dir</c>
- will be used.</p>
- <p>If <c>mib_storage</c> is <c>dets</c> or if <c>Dir</c> is
- <c>default</c>, then <c>db_dir</c> will be used for <c>Dir</c>.</p>
- <p>If <c>mib_storage</c> is <c>mnesia</c> then <c>erlang:nodes()</c>
- will be used for <c>Nodes</c>.</p>
- <p>Default is <c>ets</c>. </p>
- <p><c>Dir = default | string()</c>. Dir is the directory where the
- files will be stored. If <c>default</c>, then <c>db_dir</c> will be
- used.</p>
- <p><c>Nodes = visible | connected | [node()]</c>.
- <c>Nodes = visible</c> is translated to
- <c>erlang:nodes(visible)</c>.
- <c>Nodes = connected</c> is translated to
- <c>erlang:nodes(connected)</c>.
- If <c>Nodes = []</c> then the own node is assumed.</p>
- <p><c>Action = clear | keep</c>. Default is <c>keep</c>.
- <c>Action</c> is used to specify what shall be done if the
- mnesia/dets table already exist.</p>
+ <marker id="agent_mib_storage"></marker>
+ <tag><c><![CDATA[mib_storage() = [mib_storage_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>mib_storage_opt() = {module, mib_storage_module()} | {options, mib_storage_options()}</c></p>
+ <p>This option specifies how basic mib data is stored.
+ This option is used by two parts of the snmp agent:
+ The mib-server and the symbolic-store. </p>
+ <p>Default is <c>[{module, snmpa_mib_storage_ets}]</c>. </p>
+ </item>
+
+ <marker id="agent_mst_module"></marker>
+ <tag><c><![CDATA[mib_storage_module() = snmpa_mib_data_ets | snmpa_mib_data_dets | snmpa_mib_data_mnesia | module()]]></c></tag>
+ <item>
+ <p>Defines the mib storage module of the SNMP agent as defined by the
+ <seealso marker="snmpa_mib_storage">snmpa_mib_storage</seealso>
+ behaviour. </p>
+ <p>Several entities (<c>mib-server</c> via the its data module and
+ the <c>symbolic-store</c>) of the snmp agent uses this for storage
+ of miscelaneous mib related data retrieved while loading a mib. </p>
+ <p>There are several implementations provided with the agent:
+ <c>snmpa_mib_storage_ets</c>, <c>snmpa_mib_storage_dets</c> and
+ <c>snmpa_mib_storage_mnesia</c>. </p>
+ <p>Default module is <c>snmpa_mib_storage_ets</c>. </p>
+ </item>
+
+ <marker id="agent_mst_options"></marker>
+ <tag><c><![CDATA[mib_storage_options() = list() <optional>]]></c></tag>
+ <item>
+ <p>This is implementattion depended. That is, it depends on the
+ module. For each module a specific set of options are valid.
+ For the module provided with the app, these options are supported: </p>
+ <list type="bulleted">
+ <item>
+ <p><c>snmpa_mib_storage_ets</c>: <c>{dir, filename()} | {action, keep | clear}, {checksum, boolean()}</c></p>
+ <list>
+ <item>
+ <p><c>dir</c> - If present, points to a directory where a file
+ to which all data in the ets table is "synced". </p>
+ <p>Also, when a table is opened this file is read,
+ if it exists. </p>
+ <p>By default, this will <em>not</em> be used. </p>
+ </item>
+ <item>
+ <p><c>action</c> - Specifies the behaviour when a non-empty
+ file is found: Keep its content or clear it out. </p>
+ <p>Default is <c>keep</c>. </p>
+ </item>
+ <item>
+ <p><c>checksum</c> - Defines if the file is checksummed
+ or not. </p>
+ <p>Default is <c>false</c>. </p>
+ </item>
+ </list>
+ </item>
+ <item>
+ <p><c>snmpa_mib_storage_dets</c>: <c>{dir, filename()} | {action, keep | clear}, {auto_save, default | pos_integer()} | {repair, force | boolean()}</c></p>
+ <list>
+ <item>
+ <p><c>dir</c> - This <em>mandatory</em> option points to a
+ directory where to place the file of a dets table. </p>
+ </item>
+ <item>
+ <p><c>action</c> - Specifies the behaviour when a non-empty
+ file is found: Keep its content or clear it out. </p>
+ <p>Default is <c>keep</c>. </p>
+ </item>
+ <item>
+ <p><c>auto_save</c> - Defines the dets auto-save frequency. </p>
+ <p>Default is <c>default</c>. </p>
+ </item>
+ <item>
+ <p><c>repair</c> - Defines the dets repair behaviour. </p>
+ <p>Default is <c>false</c>. </p>
+ </item>
+ </list>
+ </item>
+ <item>
+ <p><c>snmpa_mib_storage_mnesia</c>: <c>{action, keep | clear}, {nodes, [node()]}</c></p>
+ <list>
+ <item>
+ <p><c>action</c> - Specifies the behaviour when a non-empty,
+ already existing, table: Keep its content or clear it out. </p>
+ <p>Default is <c>keep</c>. </p>
+ </item>
+ <item>
+ <p><c>nodes</c> - A list of node names (or an atom
+ describing a list of nodes) defining where to open the table.
+ Its up to the user to ensure that mnesia is actually running
+ on the specified nodes. </p>
+ <p>The following distinct values are recognised: </p>
+ <list>
+ <item>
+ <p><c>[]</c> - Translated into a list of the own node: <c>[node()]</c></p>
+ </item>
+ <item>
+ <p><c>all</c> - <c>erlang:nodes()</c></p>
+ </item>
+ <item>
+ <p><c>visible</c> - <c>erlang:nodes(visible)</c></p>
+ </item>
+ <item>
+ <p><c>connected</c> - <c>erlang:nodes(connected)</c></p>
+ </item>
+ <item>
+ <p><c>db_nodes</c> - <c>mnesia:system_info(db_nodes)</c></p>
+ </item>
+ </list>
+
+ <p>Default is the result of the call: <c>erlang:nodes()</c>. </p>
+ </item>
+ </list>
+ </item>
+ </list>
</item>
<marker id="agent_mib_server"></marker>
<tag><c><![CDATA[mib_server() = [mib_server_opt()] <optional>]]></c></tag>
<item>
- <p><c>mib_server_opt() = {mibentry_override, mibentry_override()} | {trapentry_override, trapentry_override()} | {verbosity, verbosity()} | {cache, mibs_cache()}</c></p>
+ <p><c>mib_server_opt() = {mibentry_override, mibentry_override()} | {trapentry_override, trapentry_override()} | {verbosity, verbosity()} | {cache, mibs_cache()} | {data_module, mib_server_data_module()}</c></p>
<p>Defines options specific for the SNMP agent mib server. </p>
<p>For defaults see the options in <c>mib_server_opt()</c>.</p>
</item>
@@ -365,7 +454,28 @@
<p>Default is <c>false</c>.</p>
</item>
- <marker id="agent_ms_cache"></marker>
+ <marker id="agent_ms_data_module"></marker>
+<!--
+ <tag><c><![CDATA[mib_server_data_module() = snmpa_mib_data_tttn | snmpa_mib_data_ttln | module() <optional>]]></c></tag>
+-->
+ <tag><c><![CDATA[mib_server_data_module() = snmpa_mib_data_tttn | module() <optional>]]></c></tag>
+ <item>
+ <p>Defines the backend data module of the SNMP agent mib-server as
+ defined by the
+ <seealso marker="snmpa_mib_data">snmpa_mib_data</seealso>
+ behaviour. </p>
+ <p>At present only the default module is provided with the agent,
+ <c>snmpa_mib_data_tttn</c>. </p>
+<!--
+ <p>Two modules is provided with the agent
+ <c>snmpa_mib_data_tttn</c> (this is the old implementation) and
+ <c>snmpa_mib_data_ttln</c> (for a mib tree with many holes,
+ this algorithm can be more price efficient). </p>
+-->
+ <p>Default module is <c>snmpa_mib_data_tttn</c>. </p>
+ </item>
+
+ <marker id="agent_ms_cache"></marker>
<tag><c><![CDATA[mibs_cache() = bool() | mibs_cache_opts() <optional>]]></c></tag>
<item>
<p>Shall the agent utilize the mib server lookup cache or not.</p>
@@ -385,30 +495,30 @@
<tag><c><![CDATA[mibs_cache_autogc() = bool() <optional>]]></c></tag>
<item>
<p>Defines if the mib server shall perform cache gc automatically or
- leave it to the user (see
- <seealso marker="snmpa#gc_mibs_cache">gc_mibs_cache/0,1,2,3</seealso>). </p>
+ leave it to the user (see
+ <seealso marker="snmpa#gc_mibs_cache">gc_mibs_cache/0,1,2,3</seealso>). </p>
<p>Default is <c>true</c>.</p>
</item>
<marker id="agent_ms_cache_age"></marker>
<tag><c><![CDATA[mibs_cache_age() = integer() > 0 <optional>]]></c></tag>
<item>
- <p>Defines how old the entries in the cache will be allowed before
- they are GC'ed (assuming GC is performed). Each entry in the
- cache is "touched" whenever it is accessed. </p>
- <p>The age is defined in milliseconds. </p>
- <p>Default is <c>10 timutes</c>.</p>
+ <p>Defines how old the entries in the cache will be allowed
+ to become before they are GC'ed (assuming GC is performed).
+ Each entry in the cache is "touched" whenever it is accessed. </p>
+ <p>The age is defined in milliseconds. </p>
+ <p>Default is <c>10 timutes</c>.</p>
</item>
<marker id="agent_ms_cache_gclimit"></marker>
<tag><c><![CDATA[mibs_cache_gclimit() = integer() > 0 | infinity <optional>]]></c></tag>
<item>
<p>When performing a GC, this is the max number of cache entries
- that will be deleted from the cache. </p>
+ that will be deleted from the cache. </p>
<p>The reason for having this limit is that if the cache is
- large, the GC can potentially take a long time, during which
- the agent is locked. </p>
- <p>Default is <c>100</c>.</p>
+ large, the GC can potentially take a long time, during which
+ the agent is locked. </p>
+ <p>Default is <c>100</c>.</p>
</item>
<marker id="agent_error_report_mod"></marker>
diff --git a/lib/snmp/doc/src/snmp_config.xml b/lib/snmp/doc/src/snmp_config.xml
index eec53162a1..61ee7f00ee 100644
--- a/lib/snmp/doc/src/snmp_config.xml
+++ b/lib/snmp/doc/src/snmp_config.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2012</year>
+ <year>1997</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -308,6 +308,126 @@
<p>Default is <c>[]</c>.</p>
</item>
+ <marker id="agent_mib_storage"></marker>
+ <tag><c><![CDATA[mib_storage() = [mib_storage_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>mib_storage_opt() = {module, mib_storage_module()} | {options, mib_storage_options()}</c></p>
+ <p>This option specifies how basic mib data is stored.
+ This option is used by two parts of the snmp agent:
+ The mib-server and the symbolic-store. </p>
+ <p>Default is <c>[{module, snmpa_mib_storage_ets}]</c>. </p>
+ </item>
+
+ <marker id="agent_mst_module"></marker>
+ <tag><c><![CDATA[mib_storage_module() = snmpa_mib_data_ets | snmpa_mib_data_dets | snmpa_mib_data_mnesia | module()]]></c></tag>
+ <item>
+ <p>Defines the mib storage module of the SNMP agent as defined by the
+ <seealso marker="snmpa_mib_storage">snmpa_mib_storage</seealso>
+ behaviour. </p>
+ <p>Several entities (<c>mib-server</c> via the its data module and
+ the <c>symbolic-store</c>) of the snmp agent uses this for storage
+ of miscelaneous mib related data dataretrieved while loading a mib. </p>
+ <p>There are several implementations provided with the agent:
+ <c>snmpa_mib_storage_ets</c>, <c>snmpa_mib_storage_dets</c> and
+ <c>snmpa_mib_storage_mnesia</c>. </p>
+ <p>Default module is <c>snmpa_mib_storage_ets</c>. </p>
+ </item>
+
+ <marker id="agent_mst_options"></marker>
+ <tag><c><![CDATA[mib_storage_options() = list() <optional>]]></c></tag>
+ <item>
+ <p>This is implementattion depended. That is, it depends on the
+ module. For each module a specific set of options are valid.
+ For the module provided with the app, these options are supported: </p>
+ <list type="bulleted">
+ <item>
+ <p><c>snmpa_mib_storage_ets</c>: <c>{dir, filename()} | {action, keep | clear}, {checksum, boolean()}</c></p>
+ <list>
+ <item>
+ <p><c>dir</c> - If present, points to a directory where a file
+ to which all data in the ets table is "synced". </p>
+ <p>Also, when a table is opened this file is read,
+ if it exists. </p>
+ <p>By default, this will <em>not</em> be used. </p>
+ </item>
+ <item>
+ <p><c>action</c> - Specifies the behaviour when a non-empty
+ file is found: Keep its content or clear it out. </p>
+ <p>Default is <c>keep</c>. </p>
+ </item>
+ <item>
+ <p><c>checksum</c> - Defines if the file is checksummed
+ or not. </p>
+ <p>Default is <c>false</c>. </p>
+ </item>
+ </list>
+ </item>
+ <item>
+ <p><c>snmpa_mib_storage_dets</c>: <c>{dir, filename()} | {action, keep | clear}, {auto_save, default | pos_integer()} | {repair, force | boolean()}</c></p>
+ <list>
+ <item>
+ <p><c>dir</c> - This <em>mandatory</em> option points to a
+ directory where to place the file of a dets table. </p>
+ </item>
+ <item>
+ <p><c>action</c> - Specifies the behaviour when a non-empty
+ file is found: Keep its content or clear it out. </p>
+ <p>Default is <c>keep</c>. </p>
+ </item>
+ <item>
+ <p><c>auto_save</c> - Defines the dets auto-save frequency. </p>
+ <p>Default is <c>default</c>. </p>
+ </item>
+ <item>
+ <p><c>repair</c> - Defines the dets repair behaviour. </p>
+ <p>Default is <c>false</c>. </p>
+ </item>
+ </list>
+ </item>
+ <item>
+ <p><c>snmpa_mib_storage_mnesia</c>: <c>{action, keep | clear}, {nodes, [node()]}</c></p>
+ <list>
+ <item>
+ <p><c>action</c> - Specifies the behaviour when a non-empty,
+ already existing, table: Keep its content or clear it out. </p>
+ <p>Default is <c>keep</c>. </p>
+ </item>
+ <item>
+ <p><c>nodes</c> - A list of node names (or an atom
+ describing a list of nodes) defining where to open the table.
+ Its up to the user to ensure that mnesia is actually running
+ on the specified nodes. </p>
+ <p>The following distinct values are recognised: </p>
+ <list>
+ <item>
+ <p><c>[]</c> - Translated into a list of the own node: <c>[node()]</c></p>
+ </item>
+ <item>
+ <p><c>all</c> - <c>erlang:nodes()</c></p>
+ </item>
+ <item>
+ <p><c>visible</c> - <c>erlang:nodes(visible)</c></p>
+ </item>
+ <item>
+ <p><c>connected</c> - <c>erlang:nodes(connected)</c></p>
+ </item>
+ <item>
+ <p><c>db_nodes</c> - <c>mnesia:system_info(db_nodes)</c></p>
+ </item>
+ </list>
+
+ <p>Default is the result of the call: <c>erlang:nodes()</c>. </p>
+ </item>
+ </list>
+ </item>
+ </list>
+ </item>
+
+<!--
+
+This is the old format which is "supported", but not documented,
+in so far as it will be converted to the new format if found.
+
<marker id="agent_mib_storage"></marker>
<tag><c><![CDATA[mib_storage() = ets | {ets, Dir} | {ets, Dir, Action} | dets | {dets, Dir} | {dets, Dir, Action} | mnesia | {mnesia, Nodes} | {mnesia, Nodes, Action} <optional>]]></c></tag>
<item>
@@ -333,11 +453,12 @@
<c>Action</c> is used to specify what shall be done if the
mnesia/dets table already exist.</p>
</item>
+-->
<marker id="agent_mib_server"></marker>
<tag><c><![CDATA[mib_server() = [mib_server_opt()] <optional>]]></c></tag>
<item>
- <p><c>mib_server_opt() = {mibentry_override, mibentry_override()} | {trapentry_override, trapentry_override()} | {verbosity, verbosity()} | {cache, mibs_cache()}</c></p>
+ <p><c>mib_server_opt() = {mibentry_override, mibentry_override()} | {trapentry_override, trapentry_override()} | {verbosity, verbosity()} | {cache, mibs_cache()} | {data_module, mib_server_data_module()}</c></p>
<p>Defines options specific for the SNMP agent mib server. </p>
<p>For defaults see the options in <c>mib_server_opt()</c>.</p>
</item>
@@ -362,6 +483,27 @@
<p>Default is <c>false</c>.</p>
</item>
+ <marker id="agent_ms_data_module"></marker>
+<!--
+ <tag><c><![CDATA[mib_server_data_module() = snmpa_mib_data_tttn | snmpa_mib_data_ttln | module() <optional>]]></c></tag>
+-->
+ <tag><c><![CDATA[mib_server_data_module() = snmpa_mib_data_tttn | module() <optional>]]></c></tag>
+ <item>
+ <p>Defines the backend data module of the SNMP agent mib-server as
+ defined by the
+ <seealso marker="snmpa_mib_data">snmpa_mib_data</seealso>
+ behaviour. </p>
+ <p>At present only the default module is provided with the agent,
+ <c>snmpa_mib_data_tttn</c>. </p>
+<!--
+ <p>Two modules is provided with the agent
+ <c>snmpa_mib_data_tttn</c> (this is the old implementation) and
+ <c>snmpa_mib_data_ttln</c> (for a mib tree with many holes,
+ this algorithm can be more price efficient). </p>
+-->
+ <p>Default module is <c>snmpa_mib_data_tttn</c>. </p>
+ </item>
+
<marker id="agent_ms_cache"></marker>
<tag><c><![CDATA[mibs_cache() = bool() | mibs_cache_opts() <optional>]]></c></tag>
<item>
@@ -382,18 +524,18 @@
<tag><c><![CDATA[mibs_cache_autogc() = bool() <optional>]]></c></tag>
<item>
<p>Defines if the mib server shall perform cache gc automatically or
- leave it to the user (see
- <seealso marker="snmpa#gc_mibs_cache">gc_mibs_cache/0,1,2,3</seealso>). </p>
- <p>Default is <c>true</c>.</p>
+ leave it to the user (see
+ <seealso marker="snmpa#gc_mibs_cache">gc_mibs_cache/0,1,2,3</seealso>). </p>
+ <p>Default is <c>true</c>.</p>
</item>
<marker id="agent_ms_cache_age"></marker>
<tag><c><![CDATA[mibs_cache_age() = integer() > 0 <optional>]]></c></tag>
<item>
- <p>Defines how old the entries in the cache will be allowed before
- they are GC'ed (assuming GC is performed). Each entry in the
- cache is "touched" whenever it is accessed. </p>
- <p>The age is defined in milliseconds. </p>
+ <p>Defines how old the entries in the cache will be allowed
+ to become before they are GC'ed (assuming GC is performed).
+ Each entry in the cache is "touched" whenever it is accessed. </p>
+ <p>The age is defined in milliseconds. </p>
<p>Default is <c>10 timutes</c>.</p>
</item>
@@ -401,11 +543,11 @@
<tag><c><![CDATA[mibs_cache_gclimit() = integer() > 0 | infinity <optional>]]></c></tag>
<item>
<p>When performing a GC, this is the max number of cache entries
- that will be deleted from the cache. </p>
- <p>The reason for having this limit is that if the cache is
- large, the GC can potentially take a long time, during which
- the agent is locked. </p>
- <p>Default is <c>100</c>.</p>
+ that will be deleted from the cache. </p>
+ <p>The reason for having this limit is that if the cache is
+ large, the GC can potentially take a long time, during which
+ the agent is locked. </p>
+ <p>Default is <c>100</c>.</p>
</item>
<marker id="agent_error_report_mod"></marker>
diff --git a/lib/snmp/doc/src/snmpa_mib_data.xml b/lib/snmp/doc/src/snmpa_mib_data.xml
new file mode 100644
index 0000000000..ff07a03b98
--- /dev/null
+++ b/lib/snmp/doc/src/snmpa_mib_data.xml
@@ -0,0 +1,392 @@
+<?xml version="1.0" encoding="iso-8859-1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2013</year><year>2013</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>snmpa_mib_data</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>snmpa_mib_data.xml</file>
+ </header>
+
+ <module>snmpa_mib_data</module>
+ <modulesummary>Behaviour module for the SNMP agent mib-server
+ data module.</modulesummary>
+ <description>
+ <p>This module defines the behaviour of the SNMP agent mib-server
+ data module. A <c>snmpa_mib_data</c> compliant module
+ must export the following functions: </p>
+ <list type="bulleted">
+ <item>
+ <seealso marker="#new">new/1</seealso>
+ </item>
+ <item>
+ <seealso marker="#close">close/1</seealso>
+ </item>
+ <item>
+ <seealso marker="#sync">sync/1</seealso>
+ </item>
+ <item>
+ <seealso marker="#load_mib">load_mib/4</seealso>
+ </item>
+ <item>
+ <seealso marker="#unload_mib">unload_mib/4</seealso>
+ </item>
+ <item>
+ <seealso marker="#lookup">lookup/2</seealso>
+ </item>
+ <item>
+ <seealso marker="#next">next/3</seealso>
+ </item>
+ <item>
+ <seealso marker="#register_subagent">register_subagent/3</seealso>
+ </item>
+ <item>
+ <seealso marker="#unregister_subagent">unregister_subagent/2</seealso>
+ </item>
+ <item>
+ <seealso marker="#which_mib">which_mib/2</seealso>
+ </item>
+ <item>
+ <seealso marker="#which_mibs">which_mibs/1</seealso>
+ </item>
+ <item>
+ <seealso marker="#whereis_mib">whereis_mib/2</seealso>
+ </item>
+ <item>
+ <seealso marker="#dump">dump/2</seealso>
+ </item>
+ <item>
+ <seealso marker="#info">info/1</seealso>
+ </item>
+ <item>
+ <seealso marker="#backup">backup/2</seealso>
+ </item>
+ <item>
+ <seealso marker="#code_change">code_change/4</seealso>
+ </item>
+ </list>
+
+ <p>The semantics of them and their exact signatures are
+ explained below. </p>
+
+ <p>Note that the data extracted from the imported (loaded)
+ mibs are stored partly by the mib-server and partly by the
+ symbolic-store server. See the default mib-server data
+ module, <c>snmpa_mib_data_tttn</c> for details. </p>
+
+ </description>
+
+ <section>
+ <title>CALLBACK FUNCTIONS</title>
+ <p>The following functions must be exported from a
+ <c>mib-server</c> data callback module: </p>
+
+ <marker id="new"></marker>
+ </section>
+
+ <funcs>
+ <func>
+ <name>Module:new(Storage) -> State</name>
+ <fsummary>Create new (mib-server) data instance</fsummary>
+ <type>
+ <v>Storage = mib_storage()</v>
+ <v>State = term()</v>
+ </type>
+ <desc>
+ <p>Create a new mib-server data instance. </p>
+
+ <marker id="close"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:close(State) -> void()</name>
+ <fsummary>Close the mib-server data instance</fsummary>
+ <type>
+ <v>State = term()</v>
+ </type>
+ <desc>
+ <p>Close the mib-storage.</p>
+
+ <marker id="sync"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:sync(State) -> void()</name>
+ <fsummary>Synchronize to disc</fsummary>
+ <type>
+ <v>State = term()</v>
+ </type>
+ <desc>
+ <p>Synchronize (write to disc, if possible) the mib-server data.
+ This depends on the <c>mib_storage</c> option, and will only have
+ an effect if the mib-storage option has an actual disc component
+ (such as dets, or ets with a file). </p>
+
+ <marker id="load_mib"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:load_mib(State, Filename, MeOverride, TeOverride) -> {ok, NewState} | {error, Reason}</name>
+ <fsummary>Load a mib into the mib-server</fsummary>
+ <type>
+ <v>State = NewState = term()</v>
+ <v>Filename = filename()</v>
+ <v>MeOverride = boolean()</v>
+ <v>TeOverride = boolean()</v>
+ <v>Reason = already_loaded | term()</v>
+ </type>
+ <desc>
+ <p>Load the mib specified by the <c>Filename</c> argument
+ into the mib-server.
+ The <c>MeOverride</c> and <c>TeOverride</c> arguments
+ specifies how the mib-server shall handle duplicate mib- and trap-
+ entries. </p>
+
+ <marker id="unload_mib"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:unload_mib(State, Filename) -> {ok, NewState} | {error, Reason}</name>
+ <fsummary>Unload mib from the mib-server</fsummary>
+ <type>
+ <v>State = NewState = term()</v>
+ <v>Filename = filename()</v>
+ <v>Reason = not_loaded | term()</v>
+ </type>
+ <desc>
+ <p>Unload the mib specified by the <c>Filename</c> argument
+ from the mib-server. </p>
+
+ <marker id="lookup"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:lookup(State, Oid) -> Reply</name>
+ <fsummary>Find the mib-entry corresponding to the Oid</fsummary>
+ <type>
+ <v>State = term()</v>
+ <v>Reply = {variable, ME} | {table_column, ME, TEOid} | {subagent, SAPid, SAOid} | {false, Reason}</v>
+ <v>Oid = TEOid = SAOid = oid()</v>
+ <v>SAPid = pid()</v>
+ <v>ME = me()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Find the mib-entry corresponding to the <c>Oid</c>.
+ If it is a variable, the <c>Oid</c> must be
+ &lt;Oid for var&gt;.0
+ and if it is a table, <c>Oid</c> must be
+ &lt;table&gt;.&lt;entry&gt;.&lt;col&gt;.&lt;any&gt;.</p>
+
+ <marker id="next"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:next(State, Oid, MibView) -> Reply</name>
+ <fsummary>Finds the lexicographically next oid</fsummary>
+ <type>
+ <v>State = term()</v>
+ <v>Reply = false | endOfTable | {subagent, SAPid, SAOid} | {variable, ME, VarOid} | {table, TableOid, TableRestOid, ME}</v>
+ <v>Oid = SAOid = VarOid = TableOid = TableRestOid = oid()</v>
+ <v>SAPid = pid()</v>
+ <v>ME = me()</v>
+ </type>
+ <desc>
+ <p>Finds the lexicographically next oid. </p>
+
+ <marker id="register_subagent"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:register_subagent(State, Oid, Pid) -> Reply</name>
+ <fsummary>Register the subagent</fsummary>
+ <type>
+ <v>State = NewState = term()</v>
+ <v>Reply = {ok, NewState} | {error, Reason}</v>
+ <v>Oid = oid()</v>
+ <v>Pid = pid()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Register the subagent, process,
+ handling part of the mib-tree. </p>
+
+ <marker id="unregister_subagent"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:unregister_subagent(State, PidOrOid) -> Reply</name>
+ <fsummary>Unregister the subagent</fsummary>
+ <type>
+ <v>State = NewState = term()</v>
+ <v>Reply = {ok, NewState} | {ok, NewState, Pid} | {error, Reason}</v>
+ <v>PidOrOid = pid() | oid()</v>
+ <v>Pid = pid()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Unregister the subagent, handling part of the mib-tree,
+ as specified by the <c>oid()</c> or <c>pid()</c>
+ (<c>PidOrOid</c>). </p>
+ <p>When unregister the subagent using an <c>oid()</c>, the <c>pid()</c>
+ of the process handling the sub-tree is also returned. </p>
+
+ <marker id="dump"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:dump(State, Destination) -> Reply</name>
+ <fsummary>Unregister the subagent</fsummary>
+ <type>
+ <v>State = term()</v>
+ <v>Reply = ok | {error, Reason}</v>
+ <v>Destination = io | filename()</v>
+ <v>Pid = pid()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Dump the mib-server data to <c>stdio</c> (Destination = <c>io</c>) or
+ the specified file. </p>
+
+ <marker id="which_mib"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:which_mib(State, Oid) -> Reply</name>
+ <fsummary>Retrieve the mib file for an oid()</fsummary>
+ <type>
+ <v>State = term()</v>
+ <v>Reply = {ok, MibFile} | {error, Reason}</v>
+ <v>Oid = oid()</v>
+ <v>MibFile = string()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Retrieve the mib-file to which an given <c>oid()</c> belongs. </p>
+
+ <marker id="which_mibs"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:which_mibs(State) -> Reply</name>
+ <fsummary>Retrieve all loaded mib files</fsummary>
+ <type>
+ <v>State = term()</v>
+ <v>Reply = [{MibName, Filename}]</v>
+ <v>MibName = atom()</v>
+ <v>Filename = string()</v>
+ </type>
+ <desc>
+ <p>Retrieve all loaded mib-files. </p>
+
+ <marker id="whereis_mib"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:whereis_mib(State, MibName) -> Reply</name>
+ <fsummary>Retrieve the mib file for the mib</fsummary>
+ <type>
+ <v>State = term()</v>
+ <v>MibName = atom()</v>
+ <v>Reply = {ok, Filename} | {error, Reason}</v>
+ <v>Filename = string()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Retrieve the mib file for the mib. </p>
+
+ <marker id="info"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:info(State) -> Reply</name>
+ <fsummary>Retrieve misc info for the mib data</fsummary>
+ <type>
+ <v>State = term()</v>
+ <v>Reply = {ok, Filename} | {error, Reason}</v>
+ <v>Filename = string()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Retrieve misc info for the mib data. </p>
+ <p>This is a utility function used to inspect, for instance,
+ memory usage, in a simple way. </p>
+
+ <marker id="backup"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:backup(State, BackupDir) -> Reply</name>
+ <fsummary>Perform a backup of the mib-server data</fsummary>
+ <type>
+ <v>State = term()</v>
+ <v>Reply = ok | {error, Reason}</v>
+ <v>BackupDir = string()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Perform a backup of the mib-server data. </p>
+ <p>Note that its implementation dependant (and also
+ dependent on mib-storage is used) if a backup is possible. </p>
+
+ <marker id="code_change"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:code_change(Destination, Vsn, Extra, State) -> NewState</name>
+ <fsummary>Perform a code-change</fsummary>
+ <type>
+ <v>Destination = up | down</v>
+ <v>Vsn = term()</v>
+ <v>Extra = term()</v>
+ <v>State = NewState = term()</v>
+ </type>
+ <desc>
+ <p>Perform a code-change (upgrade or downgrade). </p>
+ <p>See
+ <seealso marker="gen_server">gen_server</seealso>
+ for more info regarding the <c>Vsn</c> and <c>Extra</c> arguments. </p>
+
+ </desc>
+ </func>
+
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmpa_mib_storage.xml b/lib/snmp/doc/src/snmpa_mib_storage.xml
new file mode 100644
index 0000000000..a857ce79e8
--- /dev/null
+++ b/lib/snmp/doc/src/snmpa_mib_storage.xml
@@ -0,0 +1,292 @@
+<?xml version="1.0" encoding="iso-8859-1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2013</year><year>2013</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>snmpa_mib_storage</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>snmpa_mib_storage.xml</file>
+ </header>
+
+ <module>snmpa_mib_storage</module>
+ <modulesummary>
+ Behaviour module for the SNMP agent mib storage.
+ </modulesummary>
+ <description>
+ <p>This module defines the behaviour of the SNMP agent mib storage. </p>
+ <p>The mib storage is used by the agent to store internal mib-
+ related information. The mib storage module is used by several entities,
+ not just the mib-server. </p>
+
+ <p>A <c>snmpa_mib_storage</c> compliant module
+ must export the following functions: </p>
+ <list type="bulleted">
+ <item>
+ <seealso marker="#open">open/5</seealso>
+ </item>
+ <item>
+ <seealso marker="#close">close/1</seealso>
+ </item>
+ <item>
+ <seealso marker="#read">read/2</seealso>
+ </item>
+ <item>
+ <seealso marker="#write">write/2</seealso>
+ </item>
+ <item>
+ <seealso marker="#delete1">delete/1</seealso>
+ </item>
+ <item>
+ <seealso marker="#delete2">delete/2</seealso>
+ </item>
+ <item>
+ <seealso marker="#match_object">match_object/2</seealso>
+ </item>
+ <item>
+ <seealso marker="#match_delete">match_delete/2</seealso>
+ </item>
+ <item>
+ <seealso marker="#tab2list">tab2list/1</seealso>
+ </item>
+ <item>
+ <seealso marker="#info">info/1</seealso>
+ </item>
+ <item>
+ <seealso marker="#sync">sync/1</seealso>
+ </item>
+ <item>
+ <seealso marker="#backup">backup/2</seealso>
+ </item>
+ </list>
+
+ <p>The semantics of them and their exact signatures are
+ explained below. </p>
+
+ </description>
+
+ <section>
+ <title>CALLBACK FUNCTIONS</title>
+ <p>The following functions must be exported from a
+ <c>mib-server</c> data callback module: </p>
+
+ <marker id="open"></marker>
+ </section>
+
+ <funcs>
+ <func>
+ <name>Module:open(Name, RecordName, Fields, Type, Options) -> {ok, TabId} | {error, Reason}</name>
+ <fsummary>Create new (mib-server) data instance</fsummary>
+ <type>
+ <v>Name = atom()</v>
+ <v>RecordName = atom()</v>
+ <v>Fields = [atom()]</v>
+ <v>Type = set | bag()</v>
+ <v>Options = list()</v>
+ <v>TabId = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Create or open a mib storage table. </p>
+ <p>Note that the <c>RecordName</c> and <c>Fields</c> arguments
+ my not be used in all implementations (they are actually only
+ needed for mnesia-based implementations). </p>
+
+ <p>Note also that the <c>Options</c> argument comes from
+ the <c>options</c> config option of the mib-storage config option,
+ and is passed on as is. </p>
+
+ <marker id="close"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:close(TabId) -> void()</name>
+ <fsummary>Close the mib-storage table</fsummary>
+ <type>
+ <v>State = term()</v>
+ </type>
+ <desc>
+ <p>Close the mib-storage table.</p>
+
+ <marker id="read"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:read(TabId, Key) -> false | {value, Record}</name>
+ <fsummary>Read a record from the mib-storage table</fsummary>
+ <type>
+ <v>TabId = term()</v>
+ <v>Key = term()</v>
+ <v>Record = tuple()</v>
+ </type>
+ <desc>
+ <p>Read a record from the mib-storage table. </p>
+
+ <marker id="write"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:write(TabId, Record) -> ok | {error, Reason}</name>
+ <fsummary>Write a record to the mib-storage table</fsummary>
+ <type>
+ <v>TabId = term()</v>
+ <v>Record = tuple()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Write a record to the mib-storage table. </p>
+
+ <marker id="delete1"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:delete(TabId) -> void()</name>
+ <fsummary>Delete an entire mib-storage table</fsummary>
+ <type>
+ <v>TabId = term()</v>
+ </type>
+ <desc>
+ <p>Delete an entire mib-storage table. </p>
+
+ <marker id="delete2"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:delete(TabId, Key) -> ok | {error, Reason}</name>
+ <fsummary>Delete a record from the mib-storage table</fsummary>
+ <type>
+ <v>TabId = term()</v>
+ <v>Key = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Delete a record from the mib-storage table. </p>
+
+ <marker id="match_object"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:match_object(TabId, Pattern) -> {ok, Recs} | {error, Reason}</name>
+ <fsummary>Search the mib-storage table for record matching pattern</fsummary>
+ <type>
+ <v>TabId = term()</v>
+ <v>Pattern = match_pattern()</v>
+ <v>Recs = [tuple()]</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Search the mib-storage table for record that match the
+ specified pattern. </p>
+
+ <marker id="match_delete"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:match_delete(TabId, Pattern) -> {ok, Recs} | {error, Reason}</name>
+ <fsummary>Delete records in the mib-storage table matching pattern</fsummary>
+ <type>
+ <v>TabId = term()</v>
+ <v>Pattern = match_pattern()</v>
+ <v>Recs = [tuple()]</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Search the mib-storage table for record that match the
+ specified pattern and then delete them. The records deleted are
+ also returned. </p>
+
+ <marker id="tab2list"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:tab2list(TabId) -> Recs</name>
+ <fsummary>Return all records of the mib-storage table</fsummary>
+ <type>
+ <v>TabId = term()</v>
+ <v>Recs = [tuple()]</v>
+ </type>
+ <desc>
+ <p>Return all records in the mib-storage table in the form
+ of a list. </p>
+
+ <marker id="info"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:info(TabId) -> {ok, Info} | {error, Reason}</name>
+ <fsummary>Returns information about the mib-storage table. </fsummary>
+ <type>
+ <v>TabId = term()</v>
+ <v>Info = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Retrieve implementation dependent mib-storage table
+ information. </p>
+
+ <marker id="sync"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:sync(TabId) -> void()</name>
+ <fsummary>Synchronize mib-storage table</fsummary>
+ <type>
+ <v>TabId = term()</v>
+ </type>
+ <desc>
+ <p>Synchronize the mib-storage table. </p>
+ <p>What this means, if anything, is implementation dependent. </p>
+
+ <marker id="backup"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>Module:backup(TabId, BackupDir) -> ok | {error, Reason}</name>
+ <fsummary>Perform a backup of the mib-storage table</fsummary>
+ <type>
+ <v>TabId = term()</v>
+ <v>BackupDir = string()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Perform a backup of the mib-storage table. </p>
+ <p>What this means, if anything, is implementation dependent. </p>
+
+ </desc>
+ </func>
+
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/src/agent/depend.mk b/lib/snmp/src/agent/depend.mk
index ea9261e266..4b12b66e3b 100644
--- a/lib/snmp/src/agent/depend.mk
+++ b/lib/snmp/src/agent/depend.mk
@@ -77,10 +77,6 @@ $(EBIN)/snmpa_error_logger.$(EMULATOR): \
snmpa_error_report.erl \
snmpa_error_logger.erl
-$(EBIN)/snmpa_general_db.$(EMULATOR): \
- snmpa_general_db.erl \
- ../misc/snmp_verbosity.hrl
-
$(EBIN)/snmpa_local_db.$(EMULATOR): \
snmpa_local_db.erl \
../misc/snmp_debug.hrl \
@@ -88,6 +84,18 @@ $(EBIN)/snmpa_local_db.$(EMULATOR): \
../../include/snmp_types.hrl \
../../include/STANDARD-MIB.hrl
+$(EBIN)/snmpa_mib_storage.$(EMULATOR): \
+ snmpa_mib_storage.erl
+
+$(EBIN)/snmpa_mib_storage_ets.$(EMULATOR): \
+ snmpa_mib_storage_ets.erl
+
+$(EBIN)/snmpa_mib_storage_dets.$(EMULATOR): \
+ snmpa_mib_storage_dets.erl
+
+$(EBIN)/snmpa_mib_storage_mnesia.$(EMULATOR): \
+ snmpa_mib_storage_mnesia.erl
+
$(EBIN)/snmpa_mib.$(EMULATOR): \
snmpa_mib.erl \
../misc/snmp_debug.hrl \
@@ -96,6 +104,10 @@ $(EBIN)/snmpa_mib.$(EMULATOR): \
$(EBIN)/snmpa_mib_data.$(EMULATOR): \
snmpa_mib_data.erl \
+ ../../include/snmp_types.hrl
+
+$(EBIN)/snmpa_mib_data_tttn.$(EMULATOR): \
+ snmpa_mib_data_tttn.erl \
../misc/snmp_debug.hrl \
../misc/snmp_verbosity.hrl \
../../include/snmp_types.hrl
diff --git a/lib/snmp/src/agent/modules.mk b/lib/snmp/src/agent/modules.mk
index 33ab41b434..34765475b9 100644
--- a/lib/snmp/src/agent/modules.mk
+++ b/lib/snmp/src/agent/modules.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2009. All Rights Reserved.
+# Copyright Ericsson AB 2004-2013. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -21,15 +21,21 @@ BEHAVIOUR_MODULES = \
snmpa_authentication_service \
snmpa_discovery_handler \
snmpa_error_report \
+ snmpa_mib_storage \
+ snmpa_mib_data \
snmpa_network_interface \
snmpa_network_interface_filter \
snmpa_notification_delivery_info_receiver \
snmpa_notification_filter \
snmpa_set_mechanism
+# snmpa is "plain" interface module but also defines some agent specific types
+# and therefor must be compiled before the modules that use them, including
+# the behaviour modules...
+# snmpa_mib_data_ttln
MODULES = \
- $(BEHAVIOUR_MODULES) \
snmpa \
+ $(BEHAVIOUR_MODULES) \
snmpa_acm \
snmpa_agent \
snmpa_agent_sup \
@@ -39,10 +45,12 @@ MODULES = \
snmpa_error \
snmpa_error_io \
snmpa_error_logger \
- snmpa_general_db \
snmpa_local_db \
+ snmpa_mib_storage_ets \
+ snmpa_mib_storage_dets \
+ snmpa_mib_storage_mnesia \
snmpa_mib \
- snmpa_mib_data \
+ snmpa_mib_data_tttn \
snmpa_mib_lib \
snmpa_misc_sup \
snmpa_mpd \
diff --git a/lib/snmp/src/agent/snmp_user_based_sm_mib.erl b/lib/snmp/src/agent/snmp_user_based_sm_mib.erl
index 3c4ba1af66..223d3f7218 100644
--- a/lib/snmp/src/agent/snmp_user_based_sm_mib.erl
+++ b/lib/snmp/src/agent/snmp_user_based_sm_mib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -214,12 +214,12 @@ check_user(User) ->
case element(?usmUserAuthProtocol, User) of
?usmNoAuthProtocol -> ok;
?usmHMACMD5AuthProtocol ->
- case is_crypto_supported(md5_mac_96) of
+ case is_crypto_supported(md5) of
true -> ok;
false -> exit({unsupported_crypto, md5_mac_96})
end;
?usmHMACSHAAuthProtocol ->
- case is_crypto_supported(sha_mac_96) of
+ case is_crypto_supported(sha) of
true -> ok;
false -> exit({unsupported_crypto, sha_mac_96})
end
@@ -227,14 +227,14 @@ check_user(User) ->
case element(?usmUserPrivProtocol, User) of
?usmNoPrivProtocol -> ok;
?usmDESPrivProtocol ->
- case is_crypto_supported(des_cbc_decrypt) of
+ case is_crypto_supported(des_cbc) of
true -> ok;
- false -> exit({unsupported_crypto, des_cbc_decrypt})
+ false -> exit({unsupported_crypto, des_cbc})
end;
?usmAesCfb128Protocol ->
- case is_crypto_supported(aes_cfb_128_decrypt) of
+ case is_crypto_supported(aes_cfb128) of
true -> ok;
- false -> exit({unsupported_crypto, aes_cfb_128_decrypt})
+ false -> exit({unsupported_crypto, aes_cfb128})
end
end.
@@ -874,13 +874,13 @@ validate_auth_protocol(RowIndex, Cols) ->
_ -> inconsistentValue(?usmUserAuthProtocol)
end;
?usmHMACMD5AuthProtocol ->
- case is_crypto_supported(md5_mac_96) of
+ case is_crypto_supported(md5) of
true -> ok;
false ->
wrongValue(?usmUserAuthProtocol)
end;
?usmHMACSHAAuthProtocol ->
- case is_crypto_supported(sha_mac_96) of
+ case is_crypto_supported(sha) of
true -> ok;
false ->
wrongValue(?usmUserAuthProtocol)
@@ -1008,7 +1008,7 @@ validate_priv_protocol(RowIndex, Cols) ->
?usmDESPrivProtocol ->
%% The 'catch' handles the case when 'crypto' is
%% not present in the system.
- case is_crypto_supported(des_cbc_decrypt) of
+ case is_crypto_supported(des_cbc) of
true ->
case get_auth_proto(RowIndex, Cols) of
?usmNoAuthProtocol ->
@@ -1022,7 +1022,7 @@ validate_priv_protocol(RowIndex, Cols) ->
?usmAesCfb128Protocol ->
%% The 'catch' handles the case when 'crypto' is
%% not present in the system.
- case is_crypto_supported(aes_cfb_128_decrypt) of
+ case is_crypto_supported(aes_cfb128) of
true ->
case get_auth_proto(RowIndex, Cols) of
?usmNoAuthProtocol ->
@@ -1164,7 +1164,7 @@ mk_key_change(Hash, OldKey, NewKey) ->
%% case in the standard where Random is pre-defined.
mk_key_change(Alg, OldKey, NewKey, KeyLen, Random) ->
%% OldKey and Random is of length KeyLen...
- Digest = lists:sublist(binary_to_list(crypto:Alg(OldKey++Random)), KeyLen),
+ Digest = lists:sublist(binary_to_list(crypto:hash(Alg, OldKey++Random)), KeyLen),
%% ... and so is Digest
Delta = snmp_misc:str_xor(Digest, NewKey),
Random ++ Delta.
@@ -1181,7 +1181,7 @@ extract_new_key(Hash, OldKey, KeyChange) ->
sha -> sha
end,
{Random, Delta} = split(KeyLen, KeyChange, []),
- Digest = lists:sublist(binary_to_list(crypto:Alg(OldKey++Random)), KeyLen),
+ Digest = lists:sublist(binary_to_list(crypto:hash(Alg, OldKey++Random)), KeyLen),
NewKey = snmp_misc:str_xor(Digest, Delta),
NewKey.
@@ -1219,13 +1219,10 @@ split(N, [H | T], FirstRev) when N > 0 ->
split(N-1, T, [H | FirstRev]).
+-compile({inline, [{is_crypto_supported,1}]}).
is_crypto_supported(Func) ->
- %% The 'catch' handles the case when 'crypto' is
- %% not present in the system (or not started).
- case catch lists:member(Func, crypto:info()) of
- true -> true;
- _ -> false
- end.
+ snmp_misc:is_crypto_supported(Func).
+
inconsistentValue(V) -> throw({inconsistentValue, V}).
inconsistentName(N) -> throw({inconsistentName, N}).
diff --git a/lib/snmp/src/agent/snmpa.erl b/lib/snmp/src/agent/snmpa.erl
index b45a47ec6b..14b93439df 100644
--- a/lib/snmp/src/agent/snmpa.erl
+++ b/lib/snmp/src/agent/snmpa.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -111,13 +111,44 @@
-export([print_mib_info/0, print_mib_tables/0, print_mib_variables/0]).
+-export_type([
+ me/0,
+
+ %% Agent config types
+ mib_storage/0,
+ mib_storage_opt/0,
+ mib_storage_module/0,
+ mib_storage_options/0
+ ]).
+
+-deprecated([{old_info_format, 1, next_major_release}]).
+
+
-include("snmpa_atl.hrl").
-include("snmpa_internal.hrl").
+-include_lib("snmp/include/snmp_types.hrl"). % type of me needed.
-define(DISCO_EXTRA_INFO, undefined).
%%-----------------------------------------------------------------
+%% Types
+%%-----------------------------------------------------------------
+
+-type me() :: #me{}.
+
+%% Agent config types
+-type mib_storage() :: [mib_storage_opt()].
+-type mib_storage_opt() :: {module, mib_storage_module()} |
+ {options, mib_storage_options()}.
+
+%% Module implementing the snmpa_mib_storage behaviour
+-type mib_storage_module() :: atom().
+%% Options specific to the above module
+-type mib_storage_options() :: list().
+
+
+%%-----------------------------------------------------------------
%% This utility function is used to convert an old SNMP application
%% config (prior to snmp-4.0) to a SNMP agent config (as of
%% snmp-4.0).
diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl
index 57846db13b..c267ce5a70 100644
--- a/lib/snmp/src/agent/snmpa_agent.erl
+++ b/lib/snmp/src/agent/snmpa_agent.erl
@@ -159,12 +159,15 @@
%% it is sent to the worker, and the worker is marked as busy.
%% If a request is received when the worker is busy, a new temporary
%% worker is spawned.
+%%
%% Code change
%% ===========
%% Note that the worker(s) execute the same module as the master
%% agent. For code change we have two options - ignore the workers,
%% or send them a code change message.
+%%
%%-----------------------------------------------------------------
+
-record(state, {type,
parent,
worker,
@@ -219,22 +222,19 @@
%%-----------------------------------------------------------------
start_link(Prio, Parent, Ref, Options) ->
?d("start_link -> entry with"
- "~n Prio: ~p"
- "~n Parent: ~p"
- "~n Ref: ~p"
- "~n Options: ~p", [Prio, Parent, Ref, Options]),
- %% gen_server:start_link(?MODULE, [Prio, Parent, Ref, Options], []).
+ "~n Prio: ~p"
+ "~n Parent: ~p"
+ "~n Ref: ~p"
+ "~n Options: ~p", [Prio, Parent, Ref, Options]),
?GS_START_LINK3(Prio, Parent, Ref, Options).
start_link(Prio, Name, Parent, Ref, Options) ->
?d("start_link -> entry with"
- "~n Prio: ~p"
- "~n Name: ~p"
- "~n Parent: ~p"
- "~n Ref: ~p"
- "~n Options: ~p", [Prio, Name, Parent, Ref, Options]),
-% gen_server:start_link({local, Name}, ?MODULE,
-% [Prio, Parent, Ref, Options], []).
+ "~n Prio: ~p"
+ "~n Name: ~p"
+ "~n Parent: ~p"
+ "~n Ref: ~p"
+ "~n Options: ~p", [Prio, Name, Parent, Ref, Options]),
?GS_START_LINK4(Prio, Name, Parent, Ref, Options).
stop(Agent) -> call(Agent, stop).
@@ -335,10 +335,10 @@ increment_counter(Counter, Initial, Max) ->
init([Prio, Parent, Ref, Options]) ->
?d("init -> entry with"
- "~n Prio: ~p"
- "~n Parent: ~p"
- "~n Ref: ~p"
- "~n Options: ~p", [Prio, Parent, Ref, Options]),
+ "~n Prio: ~p"
+ "~n Parent: ~p"
+ "~n Ref: ~p"
+ "~n Options: ~p", [Prio, Parent, Ref, Options]),
case (catch do_init(Prio, Parent, Ref, Options)) of
{ok, State} ->
?vdebug("started",[]),
@@ -1457,80 +1457,80 @@ handle_mibs_cache_request(MibServer, Req) ->
%% Downgrade
%%
-code_change({down, _Vsn}, S1, downgrade_to_pre_4_17_3) ->
- #state{type = Type,
- parent = Parent,
- worker = Worker,
- worker_state = WorkerState,
- set_worker = SetWorker,
- multi_threaded = MT,
- ref = Ref,
- vsns = Vsns,
- nfilters = NF,
- note_store = NoteStore,
- mib_server = MS,
- net_if = NetIf,
- net_if_mod = NetIfMod,
- backup = Backup,
- disco = Disco,
- mibs_cache_request = MCR} = S1,
- S2 = {state,
- type = Type,
- parent = Parent,
- worker = Worker,
- worker_state = WorkerState,
- set_worker = SetWorker,
- multi_threaded = MT,
- ref = Ref,
- vsns = Vsns,
- nfilters = NF,
- note_store = NoteStore,
- mib_server = MS,
- net_if = NetIf,
- net_if_mod = NetIfMod,
- backup = Backup,
- disco = Disco,
- mibs_cache_request = MCR},
- {ok, S2};
-
-%% Upgrade
-%%
-code_change(_Vsn, S1, upgrade_from_pre_4_17_3) ->
- {state,
- type = Type,
- parent = Parent,
- worker = Worker,
- worker_state = WorkerState,
- set_worker = SetWorker,
- multi_threaded = MT,
- ref = Ref,
- vsns = Vsns,
- nfilters = NF,
- note_store = NoteStore,
- mib_server = MS,
- net_if = NetIf,
- net_if_mod = NetIfMod,
- backup = Backup,
- disco = Disco,
- mibs_cache_request = MCR} = S1,
- S2 = #state{type = Type,
- parent = Parent,
- worker = Worker,
- worker_state = WorkerState,
- set_worker = SetWorker,
- multi_threaded = MT,
- ref = Ref,
- vsns = Vsns,
- nfilters = NF,
- note_store = NoteStore,
- mib_server = MS,
- net_if = NetIf,
- net_if_mod = NetIfMod,
- backup = Backup,
- disco = Disco,
- mibs_cache_request = MCR,
- gb_max_vbs = ?DEFAULT_GB_MAX_VBS},
- {ok, S2};
+%% code_change({down, _Vsn}, S1, downgrade_to_pre_4_17_3) ->
+%% #state{type = Type,
+%% parent = Parent,
+%% worker = Worker,
+%% worker_state = WorkerState,
+%% set_worker = SetWorker,
+%% multi_threaded = MT,
+%% ref = Ref,
+%% vsns = Vsns,
+%% nfilters = NF,
+%% note_store = NoteStore,
+%% mib_server = MS,
+%% net_if = NetIf,
+%% net_if_mod = NetIfMod,
+%% backup = Backup,
+%% disco = Disco,
+%% mibs_cache_request = MCR} = S1,
+%% S2 = {state,
+%% type = Type,
+%% parent = Parent,
+%% worker = Worker,
+%% worker_state = WorkerState,
+%% set_worker = SetWorker,
+%% multi_threaded = MT,
+%% ref = Ref,
+%% vsns = Vsns,
+%% nfilters = NF,
+%% note_store = NoteStore,
+%% mib_server = MS,
+%% net_if = NetIf,
+%% net_if_mod = NetIfMod,
+%% backup = Backup,
+%% disco = Disco,
+%% mibs_cache_request = MCR},
+%% {ok, S2};
+
+%% %% Upgrade
+%% %%
+%% code_change(_Vsn, S1, upgrade_from_pre_4_17_3) ->
+%% {state,
+%% type = Type,
+%% parent = Parent,
+%% worker = Worker,
+%% worker_state = WorkerState,
+%% set_worker = SetWorker,
+%% multi_threaded = MT,
+%% ref = Ref,
+%% vsns = Vsns,
+%% nfilters = NF,
+%% note_store = NoteStore,
+%% mib_server = MS,
+%% net_if = NetIf,
+%% net_if_mod = NetIfMod,
+%% backup = Backup,
+%% disco = Disco,
+%% mibs_cache_request = MCR} = S1,
+%% S2 = #state{type = Type,
+%% parent = Parent,
+%% worker = Worker,
+%% worker_state = WorkerState,
+%% set_worker = SetWorker,
+%% multi_threaded = MT,
+%% ref = Ref,
+%% vsns = Vsns,
+%% nfilters = NF,
+%% note_store = NoteStore,
+%% mib_server = MS,
+%% net_if = NetIf,
+%% net_if_mod = NetIfMod,
+%% backup = Backup,
+%% disco = Disco,
+%% mibs_cache_request = MCR,
+%% gb_max_vbs = ?DEFAULT_GB_MAX_VBS},
+%% {ok, S2};
code_change(_Vsn, S, _Extra) ->
{ok, S}.
@@ -4411,7 +4411,7 @@ get_mibs(Opts) ->
get_option(mibs, Opts, []).
get_mib_storage(Opts) ->
- get_option(mib_storage, Opts, ets).
+ get_option(mib_storage, Opts).
get_set_mechanism(Opts) ->
get_option(set_mechanism, Opts, snmpa_set).
@@ -4450,6 +4450,9 @@ net_if_verbosity(_Pid,_Verbosity) ->
ok.
+get_option(Key, Opts) ->
+ snmp_misc:get_option(Key, Opts).
+
get_option(Key, Opts, Default) ->
snmp_misc:get_option(Key, Opts, Default).
diff --git a/lib/snmp/src/agent/snmpa_agent_sup.erl b/lib/snmp/src/agent/snmpa_agent_sup.erl
index 9b8c4d12a6..2805e2dc0d 100644
--- a/lib/snmp/src/agent/snmpa_agent_sup.erl
+++ b/lib/snmp/src/agent/snmpa_agent_sup.erl
@@ -29,10 +29,12 @@
-export([init/1]).
-define(SERVER, ?MODULE).
+%% Always use plain ets for sub-agents
-ifdef(snmp_debug).
--define(DEFAULT_OPTS, [{verbosity, trace}]).
+-define(DEFAULT_SA_OPTS, [{mib_storage, [{module, snmpa_mib_storage_ets}]},
+ {verbosity, trace}]).
-else.
--define(DEFAULT_OPTS, []).
+-define(DEFAULT_SA_OPTS, [{mib_storage, [{module, snmpa_mib_storage_ets}]}]).
-endif.
@@ -63,8 +65,8 @@ start_subagent(ParentAgent, Subtree, Mibs) ->
Ref = make_ref(),
?d("start_subagent -> Ref: ~p", [Ref]),
Options = [{priority, Prio},
- {mibs, Mibs},
- {misc_sup, snmpa_misc_sup} | ?DEFAULT_OPTS],
+ {mibs, Mibs},
+ {misc_sup, snmpa_misc_sup} | ?DEFAULT_SA_OPTS],
Agent = {{sub_agent, Max},
{snmpa_agent, start_link,
[Prio, ParentAgent, Ref, Options]},
diff --git a/lib/snmp/src/agent/snmpa_mib.erl b/lib/snmp/src/agent/snmpa_mib.erl
index 575a018c0c..031309b990 100644
--- a/lib/snmp/src/agent/snmpa_mib.erl
+++ b/lib/snmp/src/agent/snmpa_mib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -18,7 +18,6 @@
%%
-module(snmpa_mib).
-%% c(snmpa_mib).
%%%-----------------------------------------------------------------
%%% This module implements a MIB server.
@@ -75,12 +74,14 @@
%% Internal Data structures
%%
%% State
-%% data - is the MIB data (defined in snmpa_mib_data)
+%% data - is the MIB data (defined in mib_data module)
%% meo - mib entry override
%% teo - trap (notification) entry override
%%-----------------------------------------------------------------
--record(state, {data, meo, teo, backup,
- cache, cache_tmr, cache_autogc, cache_gclimit, cache_age}).
+-record(state,
+ {data, meo, teo, backup,
+ cache, cache_tmr, cache_autogc, cache_gclimit, cache_age,
+ data_mod}).
@@ -224,9 +225,9 @@ info(MibServer, Type) ->
call(MibServer, {info, Type}).
dump(MibServer) ->
- call(MibServer, dump).
+ dump(MibServer, io).
-dump(MibServer, File) when is_list(File) ->
+dump(MibServer, File) when (File =:= io) orelse is_list(File) ->
call(MibServer, {dump, File}).
backup(MibServer, BackupDir) when is_list(BackupDir) ->
@@ -256,7 +257,7 @@ init([Prio, Mibs, Opts]) ->
do_init(Prio, Mibs, Opts) ->
process_flag(priority, Prio),
process_flag(trap_exit, true),
- put(sname,ms),
+ put(sname, ms),
put(verbosity, ?vvalidate(get_verbosity(Opts))),
?vlog("starting",[]),
@@ -289,13 +290,19 @@ do_init(Prio, Mibs, Opts) ->
MeOverride = get_me_override(Opts),
TeOverride = get_te_override(Opts),
MibStorage = get_mib_storage(Opts),
- Data = snmpa_mib_data:new(MibStorage),
- ?vtrace("init -> mib data created",[]),
- case (catch mib_operations(load_mib, Mibs, Data,
+ MibDataMod = get_data_mod(Opts),
+ ?vtrace("init -> try create mib data with"
+ "~n MeOverride: ~p"
+ "~n TeOverride: ~p"
+ "~n MibStorage: ~p", [MeOverride, TeOverride, MibStorage]),
+ Data = MibDataMod:new(MibStorage),
+ ?vdebug("init -> mib data created", []),
+ case (catch mib_operations(MibDataMod,
+ load_mib, Mibs, Data,
MeOverride, TeOverride, true)) of
{ok, Data2} ->
?vdebug("started",[]),
- snmpa_mib_data:sync(Data2),
+ MibDataMod:sync(Data2),
?vdebug("mib data synced",[]),
{ok, #state{data = Data2,
teo = TeOverride,
@@ -304,7 +311,8 @@ do_init(Prio, Mibs, Opts) ->
cache_tmr = CacheGcTimer,
cache_autogc = CacheAutoGC,
cache_gclimit = CacheGcLimit,
- cache_age = CacheAge}};
+ cache_age = CacheAge,
+ data_mod = MibDataMod}};
{'aborted at', Mib, _NewData, Reason} ->
?vinfo("failed loading mib ~p: ~p",[Mib,Reason]),
{error, {Mib, Reason}}
@@ -315,32 +323,34 @@ do_init(Prio, Mibs, Opts) ->
%% Returns: {ok, NewMibData} | {'aborted at', Mib, NewData, Reason}
%% Args: Operation is load_mib | unload_mib.
%%----------------------------------------------------------------------
-mib_operations(Operation, Mibs, Data, MeOverride, TeOverride) ->
- mib_operations(Operation, Mibs, Data, MeOverride, TeOverride, false).
+mib_operations(Mod, Operation, Mibs, Data, MeOverride, TeOverride) ->
+ mib_operations(Mod, Operation, Mibs, Data, MeOverride, TeOverride, false).
-mib_operations(_Operation, [], Data, _MeOverride, _TeOverride, _Force) ->
+mib_operations(_Mod, _Operation, [], Data, _MeOverride, _TeOverride, _Force) ->
{ok, Data};
-mib_operations(Operation, [Mib|Mibs], Data0, MeOverride, TeOverride, Force) ->
+mib_operations(Mod, Operation, [Mib|Mibs], Data0, MeOverride, TeOverride, Force) ->
?vtrace("mib operations ~p on"
- "~n Mibs: ~p"
- "~n with "
- "~n MeOverride: ~p"
- "~n TeOverride: ~p"
- "~n Force: ~p", [Operation,Mibs,MeOverride,TeOverride,Force]),
- Data = mib_operation(Operation, Mib, Data0, MeOverride, TeOverride, Force),
- mib_operations(Operation, Mibs, Data, MeOverride, TeOverride, Force).
-
-mib_operation(Operation, Mib, Data0, MeOverride, TeOverride, Force)
+ "~n Mibs: ~p"
+ "~n with "
+ "~n MeOverride: ~p"
+ "~n TeOverride: ~p"
+ "~n Force: ~p",
+ [Operation, Mibs, MeOverride, TeOverride, Force]),
+ Data = mib_operation(Mod,
+ Operation, Mib, Data0, MeOverride, TeOverride, Force),
+ mib_operations(Mod, Operation, Mibs, Data, MeOverride, TeOverride, Force).
+
+mib_operation(Mod, Operation, Mib, Data0, MeOverride, TeOverride, Force)
when is_list(Mib) ->
?vtrace("mib operation on mib ~p", [Mib]),
- case apply(snmpa_mib_data, Operation, [Data0,Mib,MeOverride,TeOverride]) of
- {error, 'already loaded'} when (Operation =:= load_mib) andalso
+ case apply(Mod, Operation, [Data0, Mib, MeOverride, TeOverride]) of
+ {error, already_loaded} when (Operation =:= load_mib) andalso
(Force =:= true) ->
?vlog("ignore mib ~p -> already loaded", [Mib]),
Data0;
- {error, 'not loaded'} when (Operation =:= unload_mib) andalso
- (Force =:= true) ->
+ {error, not_loaded} when (Operation =:= unload_mib) andalso
+ (Force =:= true) ->
?vlog("ignore mib ~p -> not loaded", [Mib]),
Data0;
{error, Reason} ->
@@ -350,7 +360,7 @@ mib_operation(Operation, Mib, Data0, MeOverride, TeOverride, Force)
{ok, Data} ->
Data
end;
-mib_operation(_Op, Mib, Data, _MeOverride, _TeOverride, _Force) ->
+mib_operation(_Mod, _Op, Mib, Data, _MeOverride, _TeOverride, _Force) ->
throw({'aborted at', Mib, Data, bad_mibname}).
@@ -395,15 +405,15 @@ handle_call({update_cache_opts, Key, Value}, _From, State) ->
{reply, Result, NewState};
handle_call({lookup, Oid}, _From,
- #state{data = Data, cache = Cache} = State) ->
+ #state{data = Data, cache = Cache, data_mod = Mod} = State) ->
?vlog("lookup ~p", [Oid]),
Key = {lookup, Oid},
{Reply, NewState} =
case maybe_cache_lookup(Cache, Key) of
?NO_CACHE ->
- {snmpa_mib_data:lookup(Data, Oid), State};
+ {Mod:lookup(Data, Oid), State};
[] ->
- Rep = snmpa_mib_data:lookup(Data, Oid),
+ Rep = Mod:lookup(Data, Oid),
ets:insert(Cache, {Key, Rep, timestamp()}),
{Rep, maybe_start_cache_gc_timer(State)};
[{Key, Rep, _}] ->
@@ -414,22 +424,23 @@ handle_call({lookup, Oid}, _From,
?vdebug("lookup -> Reply: ~p", [Reply]),
{reply, Reply, NewState};
-handle_call({which_mib, Oid}, _From, #state{data = Data} = State) ->
+handle_call({which_mib, Oid}, _From,
+ #state{data = Data, data_mod = Mod} = State) ->
?vlog("which_mib ~p",[Oid]),
- Reply = snmpa_mib_data:which_mib(Data, Oid),
+ Reply = Mod:which_mib(Data, Oid),
?vdebug("which_mib: ~p",[Reply]),
{reply, Reply, State};
handle_call({next, Oid, MibView}, _From,
- #state{data = Data, cache = Cache} = State) ->
+ #state{data = Data, cache = Cache, data_mod = Mod} = State) ->
?vlog("next ~p [~p]", [Oid, MibView]),
Key = {next, Oid, MibView},
{Reply, NewState} =
case maybe_cache_lookup(Cache, Key) of
?NO_CACHE ->
- {snmpa_mib_data:next(Data, Oid, MibView), State};
+ {Mod:next(Data, Oid, MibView), State};
[] ->
- Rep = snmpa_mib_data:next(Data, Oid, MibView),
+ Rep = Mod:next(Data, Oid, MibView),
ets:insert(Cache, {Key, Rep, timestamp()}),
{Rep, maybe_start_cache_gc_timer(State)};
[{Key, Rep, _}] ->
@@ -441,89 +452,99 @@ handle_call({next, Oid, MibView}, _From,
{reply, Reply, NewState};
handle_call({load_mibs, Mibs}, _From,
- #state{data = Data,
- teo = TeOverride,
- meo = MeOverride,
- cache = Cache} = State) ->
+ #state{data = Data,
+ teo = TeOverride,
+ meo = MeOverride,
+ cache = Cache,
+ data_mod = Mod} = State) ->
?vlog("load mibs ~p",[Mibs]),
%% Invalidate cache
NewCache = maybe_invalidate_cache(Cache),
- {NData,Reply} =
- case (catch mib_operations(load_mib, Mibs, Data,
+ {NData, Reply} =
+ case (catch mib_operations(Mod, load_mib, Mibs, Data,
MeOverride, TeOverride)) of
{'aborted at', Mib, NewData, Reason} ->
?vlog("aborted at ~p for reason ~p",[Mib,Reason]),
- {NewData,{error, {'load aborted at', Mib, Reason}}};
+ {NewData, {error, {'load aborted at', Mib, Reason}}};
{ok, NewData} ->
- {NewData,ok}
+ {NewData, ok}
end,
- snmpa_mib_data:sync(NData),
+ Mod:sync(NData),
{reply, Reply, State#state{data = NData, cache = NewCache}};
handle_call({unload_mibs, Mibs}, _From,
- #state{data = Data,
- teo = TeOverride,
- meo = MeOverride,
- cache = Cache} = State) ->
+ #state{data = Data,
+ teo = TeOverride,
+ meo = MeOverride,
+ cache = Cache,
+ data_mod = Mod} = State) ->
?vlog("unload mibs ~p",[Mibs]),
%% Invalidate cache
NewCache = maybe_invalidate_cache(Cache),
%% Unload mib(s)
- {NData,Reply} =
- case (catch mib_operations(unload_mib, Mibs, Data,
+ {NData, Reply} =
+ case (catch mib_operations(Mod, unload_mib, Mibs, Data,
MeOverride, TeOverride)) of
{'aborted at', Mib, NewData, Reason} ->
- ?vlog("aborted at ~p for reason ~p",[Mib,Reason]),
+ ?vlog("aborted at ~p for reason ~p", [Mib,Reason]),
{NewData, {error, {'unload aborted at', Mib, Reason}}};
{ok, NewData} ->
- {NewData,ok}
+ {NewData, ok}
end,
- snmpa_mib_data:sync(NData),
+ Mod:sync(NData),
{reply, Reply, State#state{data = NData, cache = NewCache}};
-handle_call(which_mibs, _From, #state{data = Data} = State) ->
+handle_call(which_mibs, _From, #state{data = Data, data_mod = Mod} = State) ->
?vlog("which mibs",[]),
- Reply = snmpa_mib_data:which_mibs(Data),
+ Reply = Mod:which_mibs(Data),
{reply, Reply, State};
-handle_call({whereis_mib, Mib}, _From, #state{data = Data} = State) ->
+handle_call({whereis_mib, Mib}, _From,
+ #state{data = Data,
+ data_mod = Mod} = State) ->
?vlog("whereis mib: ~p",[Mib]),
- Reply = snmpa_mib_data:whereis_mib(Data, Mib),
+ Reply = Mod:whereis_mib(Data, Mib),
{reply, Reply, State};
handle_call({register_subagent, Oid, Pid}, _From,
- #state{data = Data, cache = Cache} = State) ->
+ #state{data = Data,
+ cache = Cache,
+ data_mod = Mod} = State) ->
?vlog("register subagent ~p, ~p",[Oid,Pid]),
%% Invalidate cache
NewCache = maybe_invalidate_cache(Cache),
- case snmpa_mib_data:register_subagent(Data, Oid, Pid) of
+ case Mod:register_subagent(Data, Oid, Pid) of
{error, Reason} ->
?vlog("registration failed: ~p",[Reason]),
{reply, {error, Reason}, State#state{cache = NewCache}};
- NewData ->
+ {ok, NewData} ->
{reply, ok, State#state{data = NewData, cache = NewCache}}
end;
handle_call({unregister_subagent, OidOrPid}, _From,
- #state{data = Data, cache = Cache} = State) ->
+ #state{data = Data,
+ cache = Cache,
+ data_mod = Mod} = State) ->
?vlog("unregister subagent ~p",[OidOrPid]),
%% Invalidate cache
NewCache = maybe_invalidate_cache(Cache),
- case snmpa_mib_data:unregister_subagent(Data, OidOrPid) of
+ case Mod:unregister_subagent(Data, OidOrPid) of
+ {ok, NewData} ->
+ {reply, ok, State#state{data = NewData, cache = NewCache}};
{ok, NewData, DeletedSubagentPid} ->
{reply, {ok, DeletedSubagentPid}, State#state{data = NewData,
cache = NewCache}};
{error, Reason} ->
?vlog("unregistration failed: ~p",[Reason]),
- {reply, {error, Reason}, State#state{cache = NewCache}};
- NewData ->
- {reply, ok, State#state{data = NewData, cache = NewCache}}
+ {reply, {error, Reason}, State#state{cache = NewCache}}
end;
-handle_call(info, _From, #state{data = Data, cache = Cache} = State) ->
+handle_call(info, _From, #state{data = Data,
+ cache = Cache,
+ data_mod = Mod} = State) ->
?vlog("info",[]),
Reply =
- case (catch snmpa_mib_data:info(Data)) of
+ case (catch Mod:info(Data)) of
Info when is_list(Info) ->
[{cache, size_cache(Cache)} | Info];
E ->
@@ -531,10 +552,12 @@ handle_call(info, _From, #state{data = Data, cache = Cache} = State) ->
end,
{reply, Reply, State};
-handle_call({info, Type}, _From, #state{data = Data} = State) ->
+handle_call({info, Type}, _From,
+ #state{data = Data,
+ data_mod = Mod} = State) ->
?vlog("info ~p",[Type]),
Reply =
- case (catch snmpa_mib_data:info(Data, Type)) of
+ case (catch Mod:info(Data, Type)) of
Info when is_list(Info) ->
Info;
E ->
@@ -542,21 +565,19 @@ handle_call({info, Type}, _From, #state{data = Data} = State) ->
end,
{reply, Reply, State};
-handle_call(dump, _From, State) ->
- ?vlog("dump",[]),
- Reply = snmpa_mib_data:dump(State#state.data),
- {reply, Reply, State};
-
-handle_call({dump, File}, _From, #state{data = Data} = State) ->
+handle_call({dump, File}, _From,
+ #state{data = Data, data_mod = Mod} = State) ->
?vlog("dump on ~s",[File]),
- Reply = snmpa_mib_data:dump(Data, File),
+ Reply = Mod:dump(Data, File),
{reply, Reply, State};
%% This check (that there is no backup already in progress) is also
%% done in the master agent process, but just in case a user issues
%% a backup call to this process directly, we add a similar check here.
handle_call({backup, BackupDir}, From,
- #state{backup = undefined, data = Data} = State) ->
+ #state{backup = undefined,
+ data = Data,
+ data_mod = Mod} = State) ->
?vlog("backup to ~s", [BackupDir]),
Pid = self(),
V = get(verbosity),
@@ -568,7 +589,7 @@ handle_call({backup, BackupDir}, From,
put(sname, ambs),
put(verbosity, V),
Dir = filename:join([BackupDir]),
- Reply = snmpa_mib_data:backup(Data, Dir),
+ Reply = Mod:backup(Data, Dir),
Pid ! {backup_done, Reply},
unlink(Pid)
end),
@@ -637,8 +658,8 @@ handle_info(Info, State) ->
warning_msg("received unknown info: ~n~p", [Info]),
{noreply, State}.
-terminate(_Reason, #state{data = Data}) ->
- catch snmpa_mib_data:close(Data),
+terminate(_Reason, #state{data = Data, data_mod = Mod}) ->
+ catch Mod:close(Data),
ok.
@@ -655,6 +676,11 @@ terminate(_Reason, #state{data = Data}) ->
%% S2 = {state, Data, MEO, TEO, B},
%% {ok, S2};
+code_change({down, Vsn}, #state{data = Data0, data_mod = Mod} = State, Extra) ->
+ Data = Mod:code_change(down, Vsn, Extra, Data0),
+ {ok, State#state{data = Data}};
+
+
%% %% upgrade
%% %%
%% code_change(_Vsn, S1, upgrade_from_pre_4_12) ->
@@ -663,8 +689,9 @@ terminate(_Reason, #state{data = Data}) ->
%% S2 = #state{data = Data, meo = MEO, teo = TEO, backup = B, cache = Cache},
%% {ok, S2};
-code_change(_Vsn, State, _Extra) ->
- {ok, State}.
+code_change(Vsn, #state{data = Data0, data_mod = Mod} = State, Extra) ->
+ Data = Mod:code_change(up, Vsn, Extra, Data0),
+ {ok, State#state{data = Data}}.
%%-----------------------------------------------------------------
@@ -681,7 +708,10 @@ get_te_override(Options) ->
get_opt(trapentry_override, Options, false).
get_mib_storage(Options) ->
- get_opt(mib_storage, Options, ets).
+ get_opt(mib_storage, Options).
+
+get_data_mod(Options) ->
+ get_opt(data_module, Options, snmpa_mib_data_tttn).
get_cacheopt_autogc(Cache, CacheOpts) ->
IsValid = fun(AutoGC) when ((AutoGC =:= true) orelse
@@ -868,6 +898,9 @@ timestamp() ->
%% ----------------------------------------------------------------
+get_opt(Key, Options) ->
+ snmp_misc:get_option(Key, Options).
+
get_opt(Key, Options, Default) ->
snmp_misc:get_option(Key, Options, Default).
diff --git a/lib/snmp/src/agent/snmpa_mib_data.erl b/lib/snmp/src/agent/snmpa_mib_data.erl
index b80d85d2ee..4d8a12b6c6 100644
--- a/lib/snmp/src/agent/snmpa_mib_data.erl
+++ b/lib/snmp/src/agent/snmpa_mib_data.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -18,1338 +18,92 @@
%%
-module(snmpa_mib_data).
-%%%-----------------------------------------------------------------
-%%% This module implements the MIB internal data structures.
-%%% An MIB Data Structure consists of three items; an ets-table,
-%%% a tree and a list of registered subagents.
-%%% The subagent information is consequently duplicated. It resides
-%%% both in the tree and in the list.
-%%% The ets-table contains all data associated with each variable,
-%%% table, tableentry and tablecolumn in the MIB.
-%%% The tree contains information of the Oids in the MIB.
-%%%
-%%% When a mib is loaded, the tree is built from the plain list
-%%% in the binary file.
-%%%-----------------------------------------------------------------
--include("snmp_types.hrl").
--include("snmp_debug.hrl").
-
--define(VMODULE,"MDATA").
--include("snmp_verbosity.hrl").
-
--define(MIB_DATA,snmpa_mib_data).
--define(MIB_NODE,snmpa_mib_node).
--define(MIB_TREE,snmpa_mib_tree).
--define(DUMMY_TREE_GENERATION,1).
--define(DEFAULT_TREE,{tree,{undefined_node},internal}).
-%%-define(DUMMY_TREE_DB,dummy_tree_db).
-%%-define(DUMMY_TREE_DB_INIT,{?DUMMY_TREE_DB,?DEFAULT_TREE}).
-
+-include_lib("snmp/include/snmp_types.hrl").
%%%-----------------------------------------------------------------
-%%% Table of contents
-%%% =================
-%%% 1. Interface
-%%% 2. Implementation of tree access
-%%% 3. Tree building functions
-%%% 4. Tree merging
-%%% 5. Tree deletion routines
-%%% 6. Functions for subagent handling
-%%% 7. Misc functions
+%%% This is the behaviour for the MIB server backend internal
+%%% data storage.
%%%-----------------------------------------------------------------
+%% These types should really be defined elsewhere...
+-export_type([
+ mib_view/0,
+ mib_view_elem/0,
+ mib_view_mask/0,
+ mib_view_inclusion/0
+ ]).
-%%----------------------------------------------------------------------
-%% data_db is an database containing loaded mibs as:
-%% {MibName = atom(), Symbolic = ?, FullFileName = string()}
-%% it is either ets or mnesia
-%% tree_db is a database containing _one_ record with the tree!
-%% (the reason for this is part to get replication and part out of convenience)
-%% ref_tree is the root node, without any subagent.
-%% tree is the root node (same as ref_tree but with the subagents added).
-%% subagents is a list of {SAPid, Oid}
-%%----------------------------------------------------------------------
--record(mib_data, {mib_db, % table of #mib_info
- node_db, % table of #node_info
- tree_db, % table of #tree
- tree, % The actual tree
- subagents = []}).
-
--record(mib_info, {name, symbolic, file_name}).
--record(node_info, {oid, mib_name, me}).
-
-
-%% API
--export([new/0, new/1, sync/1, close/1,
- load_mib/4, unload_mib/4, which_mibs/1, whereis_mib/2,
- info/1, info/2,
- dump/1, dump/2,
- backup/2,
- lookup/2, next/3, which_mib/2,
- register_subagent/3, unregister_subagent/2]).
-
-%% Internal exports
--export([code_change/2]).
-
-
-%%-----------------------------------------------------------------
-%% A tree is represented as a N-tuple, where each element is a
-%% node. A node is:
-%% 1) {tree, Tree, Info} where Info can be {table, Id}, {table_entry, Id}
-%% or perhaps 'internal'
-%% 2) undefined_node (memory optimization (instead of {node, undefined}))
-%% 3) {node, Info} where Info can be {subagent, Pid}, {variable, Id},
-%% {table_column, Id}
-%% Id is {MibName, MibEntry}
-%% The over all root is represented as {tree, Tree, internal}.
-%%
-%% tree() = {tree, nodes(), tree_info()}
-%% nodes() = {tree() | node() | undefined_node, ...}
-%% node() = {node, node_info()}
-%% tree_info() = {table, Id} | {table_entry, Id} | internal
-%% node_info() = {subagent, Pid} | {variable, Id} | {table_colum, Id}
-%%-----------------------------------------------------------------
-
-%% This record is what is stored in the database. The 'tree' part
-%% is described above...
--record(tree,{generation = ?DUMMY_TREE_GENERATION, root = ?DEFAULT_TREE}).
-
-
-%%%======================================================================
-%%% 1. Interface
-%%%======================================================================
-
-%%-----------------------------------------------------------------
-%% Func: new/0, new/1
-%% Returns: A representation of mib data.
-%%-----------------------------------------------------------------
-new() ->
- new(ets).
-
-%% Where -> A list of nodes where the tables will be created
-new(Storage) ->
- %% First we must check if there is already something to read
- %% If a database already exists, then the tree structure has to be read
- ?vtrace("open (mib) database",[]),
- MibDb = snmpa_general_db:open(Storage, ?MIB_DATA,
- mib_info,
- record_info(fields,mib_info), set),
- ?vtrace("open (mib) node database",[]),
- NodeDb = snmpa_general_db:open(Storage, ?MIB_NODE,
- node_info,
- record_info(fields,node_info), set),
- ?vtrace("open (mib) tree database",[]),
- TreeDb = snmpa_general_db:open(Storage, ?MIB_TREE,
- tree,
- record_info(fields,tree), set),
- Tree =
- case snmpa_general_db:read(TreeDb, ?DUMMY_TREE_GENERATION) of
- false ->
- T = #tree{},
- snmpa_general_db:write(TreeDb, T),
- T;
- {value, T} ->
- T
- end,
- install_mibs(MibDb, NodeDb),
- #mib_data{mib_db = MibDb,
- node_db = NodeDb,
- tree_db = TreeDb,
- tree = Tree}.
-
-
-%%----------------------------------------------------------------------
-%% Returns: new mib data | {error, Reason}
-%%----------------------------------------------------------------------
-load_mib(MibData,FileName,MeOverride,TeOverride)
- when is_record(MibData,mib_data) andalso is_list(FileName) ->
- ?vlog("load mib file: ~p",[FileName]),
- ActualFileName = filename:rootname(FileName, ".bin") ++ ".bin",
- MibName = list_to_atom(filename:basename(FileName, ".bin")),
- (catch do_load_mib(MibData, ActualFileName, MibName,
- MeOverride, TeOverride)).
-
-do_load_mib(MibData, ActualFileName, MibName, MeOverride, TeOverride) ->
- ?vtrace("do_load_mib -> entry with"
- "~n ActualFileName: ~s"
- "~n MibName: ~p",[ActualFileName, MibName]),
- #mib_data{mib_db = MibDb,
- node_db = NodeDb,
- %% tree_db = TreeDb,
- tree = Tree} = MibData,
- verify_not_loaded(MibDb, MibName),
- ?vtrace("do_load_mib -> already loaded mibs:"
- "~n ~p",[loaded(MibDb)]),
- Mib = do_read_mib(ActualFileName),
- ?vtrace("do_load_mib -> read mib ~s",[Mib#mib.name]),
- NonInternalMes =
- lists:filter(fun(ME) -> maybe_drop_me(ME) end, Mib#mib.mes),
- OldRoot = Tree#tree.root,
- T = build_tree(NonInternalMes, MibName),
- ?d("load_mib -> "
- "~n OldRoot: ~p"
- "~n T: ~p", [OldRoot, T]),
- case (catch merge_nodes(T, OldRoot)) of
- {error_merge_nodes, Node1, Node2} ->
- ?vlog("error merging nodes:"
- "~n~p~nand~n~p", [Node1,Node2]),
- {error, oid_conflict};
- NewRoot when is_tuple(NewRoot) andalso (element(1,NewRoot) =:= tree) ->
- ?d("load_mib -> "
- "~n NewRoot: ~p", [NewRoot]),
- Symbolic = not lists:member(no_symbolic_info, Mib#mib.misc),
- case (catch check_notif_and_mes(TeOverride, MeOverride, Symbolic,
- Mib#mib.traps, NonInternalMes)) of
- true ->
- install_mes(NodeDb, MibName, NonInternalMes),
- install_mib(MibDb, Symbolic, Mib,
- MibName, ActualFileName, NonInternalMes),
- ?vtrace("installed mib ~s", [Mib#mib.name]),
- Tree2 = Tree#tree{root = NewRoot},
- %% snmpa_general_db:write(TreeDb, Tree2), %% Store later?
- {ok, MibData#mib_data{tree = Tree2}};
- Else ->
- Else
- end
- end.
-
-
-verify_not_loaded(Db, Name) ->
- case snmpa_general_db:read(Db, Name) of
- {value, #mib_info{name = Name}} ->
- throw({error, 'already loaded'});
- false ->
- ok
- end.
-
-do_read_mib(ActualFileName) ->
- case snmp_misc:read_mib(ActualFileName) of
- {error, Reason} ->
- ?vlog("Failed reading mib file ~p with reason: ~p",
- [ActualFileName,Reason]),
- throw({error, Reason});
- {ok, Mib} ->
- Mib
- end.
-
-%% The Tree DB is handled in a special way since it can be very large.
-sync(#mib_data{mib_db = M,
- node_db = N,
- tree_db = T, tree = Tree, subagents = []}) ->
- snmpa_general_db:sync(M),
- snmpa_general_db:sync(N),
- snmpa_general_db:write(T, Tree),
- snmpa_general_db:sync(T);
-sync(#mib_data{mib_db = M,
- node_db = N,
- tree_db = T, tree = Tree, subagents = SAs}) ->
-
- snmpa_general_db:sync(M),
- snmpa_general_db:sync(N),
-
- %% Ouch. Since the subagent info is dynamic we do not
- %% want to store the tree containing subagent info. So, we
- %% have to create a tmp tree without those and store it.
-
- case delete_subagents(Tree, SAs) of
- {ok, TreeWithoutSAs} ->
- snmpa_general_db:write(T, TreeWithoutSAs),
- snmpa_general_db:sync(T);
- Error ->
- Error
- end.
-
-delete_subagents(Tree, []) ->
- {ok, Tree};
-delete_subagents(Tree0, [{_, Oid}|SAs]) ->
- case (catch delete_subagent(Tree0, Oid)) of
- {tree, _Tree, _Info} = Tree1 ->
- delete_subagents(Tree1, SAs);
- _Error ->
- {error, {'invalid oid', Oid}}
- end.
-
-%%----------------------------------------------------------------------
-%% (OTP-3601)
-%%----------------------------------------------------------------------
-check_notif_and_mes(TeOverride,MeOverride,Symbolic,Traps,MEs) ->
- ?vtrace("check notifications and mib entries",[]),
- check_notifications(TeOverride,Symbolic,Traps),
- check_mes(MeOverride,MEs).
-
-check_notifications(true, _Symbolic, _Traps) ->
- ?vtrace("trapentry override = true => skip check",[]),
- true;
-check_notifications(_, Symbolic, Traps) ->
- check_notifications(Symbolic, Traps).
-
-check_notifications(true, Traps) ->
- check_notifications(Traps);
-check_notifications(_, _) -> true.
-
-check_notifications([]) -> true;
-check_notifications([#trap{trapname = Key} = Trap | Traps]) ->
- ?vtrace("check notification [trap] with Key: ~p",[Key]),
- case snmpa_symbolic_store:get_notification(Key) of
- {value, Trap} -> check_notifications(Traps);
- {value, _} -> throw({error, {'trap already defined', Key}});
- undefined -> check_notifications(Traps)
- end;
-check_notifications([#notification{trapname = Key} = Notif | Traps]) ->
- ?vtrace("check notification [notification] with Key: ~p",[Key]),
- case snmpa_symbolic_store:get_notification(Key) of
- {value, Notif} ->
- check_notifications(Traps);
- {value, _} ->
- throw({error, {'notification already defined', Key}});
- undefined ->
- check_notifications(Traps)
- end;
-check_notifications([Crap | Traps]) ->
- ?vlog("skipped check of: ~n~p",[Crap]),
- check_notifications(Traps).
-
-check_mes(true,_) ->
- ?vtrace("mibentry override = true => skip check",[]),
- true;
-check_mes(_,MEs) ->
- check_mes(MEs).
-
-check_mes([]) -> true;
-check_mes([#me{aliasname = Name, oid = Oid1} | MEs]) ->
- ?vtrace("check mib entries with aliasname: ~p",[Name]),
- case snmpa_symbolic_store:aliasname_to_oid(Name) of
- {value, Oid1} ->
- check_mes(MEs);
- {value, Oid2} ->
- ?vinfo("~n expecting '~p'~n but found '~p'",[Oid1, Oid2]),
- throw({error, {'mibentry already defined', Name}});
- false ->
- check_mes(MEs)
- end;
-check_mes([Crap | MEs]) ->
- ?vlog("skipped check of: ~n~p",[Crap]),
- check_mes(MEs).
-
-
-
-%%----------------------------------------------------------------------
-%% Returns: new mib data | {error, Reason}
-%%----------------------------------------------------------------------
-unload_mib(MibData, FileName, _, _) when is_list(FileName) ->
- MibName = list_to_atom(filename:basename(FileName, ".bin")),
- (catch do_unload_mib(MibData, MibName)).
-
-do_unload_mib(MibData, MibName) ->
- ?vtrace("do_unload_mib -> entry with"
- "~n MibName: ~p", [MibName]),
- #mib_data{mib_db = MibDb,
- node_db = NodeDb,
- %% tree_db = TreeDb,
- tree = Tree} = MibData,
- #mib_info{symbolic = Symbolic} = verify_loaded(MibDb, MibName),
- NewRoot = delete_mib_from_tree(MibName, Tree#tree.root),
- MEs = uninstall_mes(NodeDb, MibName),
- uninstall_mib(MibDb, Symbolic, MibName, MEs),
- NewMibData = MibData#mib_data{tree = Tree#tree{root = NewRoot}},
- {ok, NewMibData}.
-
-verify_loaded(Db, Name) ->
- case snmpa_general_db:read(Db, Name) of
- {value, MibInfo} ->
- MibInfo;
- false ->
- throw({error, 'not loaded'})
- end.
-
-
-close(#mib_data{mib_db = MibDb, node_db = NodeDb, tree_db = TreeDb}) ->
- snmpa_general_db:close(MibDb),
- snmpa_general_db:close(NodeDb),
- snmpa_general_db:close(TreeDb),
- ok.
-
-register_subagent(#mib_data{tree = T} = MibData, Oid, Pid) ->
- case insert_subagent(Oid, T#tree.root) of
- {error, Reason} ->
- {error, Reason};
- NewRootTree ->
- SAs = [{Pid, Oid} | MibData#mib_data.subagents],
- T2 = T#tree{root = NewRootTree},
- MibData#mib_data{tree = T2, subagents = SAs}
- end.
-
-
-%%----------------------------------------------------------------------
-%% Purpose: Get a list of all loaded mibs
-%% Returns: [{Name, File}]
-%%----------------------------------------------------------------------
-
-which_mibs(#mib_data{mib_db = Db}) ->
- Mibs = snmpa_general_db:tab2list(Db),
- [{Name, File} || #mib_info{name = Name, file_name = File} <- Mibs].
-
-
-%%----------------------------------------------------------------------
-%% Purpose: Get a list of all loaded mibs
-%% Returns: [{Name, File}]
-%%----------------------------------------------------------------------
-
-whereis_mib(#mib_data{mib_db = Db}, Name) ->
- case snmpa_general_db:read(Db, Name) of
- {value, #mib_info{file_name = File}} ->
- {ok, File};
- false ->
- {error, not_found}
- end.
-
-
-%%----------------------------------------------------------------------
-%% Purpose: Deletes SA with Pid from all subtrees it handles.
-%% Returns: NewMibData.
-%%----------------------------------------------------------------------
-unregister_subagent(MibData, Pid) when is_pid(Pid) ->
- SAs = MibData#mib_data.subagents,
- case lists:keysearch(Pid, 1, SAs) of
- false -> MibData;
- {value, {Pid, Oid}} ->
- % we should never get an error since Oid is found in MibData.
- {ok, NewMibData, _DeletedSA} = unregister_subagent(MibData, Oid),
- % continue if the same Pid handles other mib subtrees.
- unregister_subagent(NewMibData, Pid)
- end;
-
-%%----------------------------------------------------------------------
-%% Purpose: Deletes one unique subagent.
-%% Returns: {error, Reason} | {ok, NewMibData, DeletedSubagentPid}
-%%----------------------------------------------------------------------
-unregister_subagent(#mib_data{tree = T} = MibData, Oid) when is_list(Oid) ->
- case catch delete_subagent(T#tree.root, Oid) of
- {tree, Tree, Info} ->
- OldSAs = MibData#mib_data.subagents,
- {value, {Pid, _Oid}} = lists:keysearch(Oid, 2, OldSAs),
- SAs = lists:keydelete(Oid, 2, OldSAs),
- T2 = T#tree{root = {tree, Tree, Info}},
- {ok,
- MibData#mib_data{tree = T2, subagents = SAs},
- Pid};
- _ ->
- {error, {'invalid oid', Oid}}
- end.
-
-%%----------------------------------------------------------------------
-%% Purpose: To inpect memory usage, loaded mibs, registered subagents
-%%----------------------------------------------------------------------
-info(MibData) ->
- ?vtrace("retrieve info",[]),
- #mib_data{mib_db = MibDb, node_db = NodeDb, tree_db = TreeDb,
- tree = Tree, subagents = SAs} = MibData,
- LoadedMibs = old_format(snmpa_general_db:tab2list(MibDb)),
- TreeSize = snmp_misc:mem_size(Tree),
- {memory, ProcSize} = erlang:process_info(self(),memory),
- MibDbSize = snmpa_general_db:info(MibDb, memory),
- NodeDbSize = snmpa_general_db:info(NodeDb, memory),
- TreeDbSize = snmpa_general_db:info(TreeDb, memory),
- [{loaded_mibs, LoadedMibs}, {subagents, SAs}, {tree_size_bytes, TreeSize},
- {process_memory, ProcSize},
- {db_memory, [{mib,MibDbSize},{node,NodeDbSize},{tree,TreeDbSize}]}].
-
-info(#mib_data{mib_db = MibDb}, loaded_mibs) ->
- Mibs = snmpa_general_db:tab2list(MibDb),
- [filename:rootname(FN, ".bin") || #mib_info{file_name = FN} <- Mibs];
-info(#mib_data{tree = Tree}, tree_size_bytes) ->
- snmp_misc:mem_size(Tree);
-info(_, process_memory) ->
- {memory, ProcSize} = erlang:process_info(self(),memory),
- ProcSize;
-info(#mib_data{mib_db = MibDb, node_db = NodeDb, tree_db = TreeDb},
- db_memory) ->
- MibDbSize = snmpa_general_db:info(MibDb, memory),
- NodeDbSize = snmpa_general_db:info(NodeDb, memory),
- TreeDbSize = snmpa_general_db:info(TreeDb, memory),
- [{mib,MibDbSize},{node,NodeDbSize},{tree,TreeDbSize}];
-info(#mib_data{subagents = SAs}, subagents) ->
- SAs.
-
-old_format(LoadedMibs) ->
- ?vtrace("convert mib info to old format",[]),
- [{N,S,F} || #mib_info{name=N,symbolic=S,file_name=F} <- LoadedMibs].
-
-
-%%----------------------------------------------------------------------
-%% A total dump for debugging.
-%%----------------------------------------------------------------------
-dump(#mib_data{mib_db = MibDb, node_db = NodeDb, tree = Tree}) ->
- (catch io:format("MIB-tables:~n~p~n~n",
- [snmpa_general_db:tab2list(MibDb)])),
- (catch io:format("MIB-entries:~n~p~n~n",
- [snmpa_general_db:tab2list(NodeDb)])),
- (catch io:format("Tree:~n~p~n", [Tree])), % good luck reading it!
- ok.
-
-dump(#mib_data{mib_db = MibDb, node_db = NodeDb, tree = Tree}, File) ->
- case file:open(File,[write]) of
- {ok, Fd} ->
- io:format(Fd,"~s~n",
- [snmp:date_and_time_to_string(snmp:date_and_time())]),
- (catch io:format(Fd,"MIB-tables:~n~p~n~n",
- [snmpa_general_db:tab2list(MibDb)])),
- (catch io:format(Fd, "MIB-entries:~n~p~n~n",
- [snmpa_general_db:tab2list(NodeDb)])),
- io:format(Fd,"Tree:~n~p~n", [Tree]), % good luck reading it!
- file:close(Fd),
- ok;
- {error,Reason} ->
- ?vinfo("~n Failed opening file '~s' for reason ~p",
- [File,Reason]),
- {error,Reason}
- end.
-
-
-backup(#mib_data{mib_db = M, node_db = N, tree_db = T}, BackupDir) ->
- MRes = snmpa_general_db:backup(M, BackupDir),
- NRes = snmpa_general_db:backup(N, BackupDir),
- TRes = snmpa_general_db:backup(T, BackupDir),
- handle_backup_res([{mib_db, MRes}, {node_db, NRes}, {tree_db, TRes}]).
-
-handle_backup_res(Res) ->
- handle_backup_res(Res, []).
-
-handle_backup_res([], []) ->
- ok;
-handle_backup_res([], Err) ->
- {error, lists:reverse(Err)};
-handle_backup_res([{_, ok}|Res], Err) ->
- handle_backup_res(Res, Err);
-handle_backup_res([{Tag, {error, Reason}}|Res], Err) ->
- handle_backup_res(Res, [{Tag, Reason}|Err]);
-handle_backup_res([{Tag, Error}|Res], Err) ->
- handle_backup_res(Res, [{Tag, Error}|Err]).
-
-
-%%%======================================================================
-%%% 2. Implementation of tree access
-%%% lookup and next.
-%%%======================================================================
-
-
-which_mib(#mib_data{tree = T} = D, Oid) ->
- ?vtrace("which_mib -> entry with"
- "~n Oid: ~p",[Oid]),
- case (catch find_node(D, T#tree.root, Oid, [])) of
- {variable, _ME, Mib} ->
- ?vtrace("which_mib -> variable:"
- "~n Mib: ~p", [Mib]),
- {ok, Mib};
- {table, _EntryME, _, Mib} ->
- ?vtrace("which_mib -> table:"
- "~n Mib: ~p", [Mib]),
- {ok, Mib};
- {subagent, SubAgentPid, _SANextOid} ->
- ?vtrace("which_mib -> subagent:"
- "~n SubAgentPid: ~p", [SubAgentPid]),
- {error, {subagent, SubAgentPid}};
- {false, ErrorCode} ->
- ?vtrace("which_mib -> false:"
- "~n ErrorCode: ~p",[ErrorCode]),
- {error, ErrorCode};
- false ->
- ?vtrace("which_mib -> false",[]),
- {error, noSuchObject};
- {'EXIT', R} ->
- ?vtrace("which_mib -> exit:"
- "~n R: ~p",[R]),
- {error, noSuchObject}
- end.
-
-
-%%-----------------------------------------------------------------
-%% Func: lookup/2
-%% Purpose: Finds the mib entry corresponding to the Oid. If it is a
-%% variable, the Oid must be <Oid for var>.0 and if it is
-%% a table, Oid must be <table>.<entry>.<col>.<any>
-%% Returns: {variable, MibEntry} |
-%% {table_column, MibEntry, TableEntryOid} |
-%% {subagent, SubAgentPid, SAOid} |
-%% {false, Reason}
-%%-----------------------------------------------------------------
-lookup(#mib_data{tree = T} = D, Oid) ->
- ?vtrace("lookup -> entry with"
- "~n Oid: ~p",[Oid]),
- case (catch find_node(D, T#tree.root, Oid, [])) of
- {variable, ME, _Mib} when is_record(ME, me) ->
- ?vtrace("lookup -> variable:"
- "~n ME: ~p",[ME]),
- {variable, ME};
- {table, EntryME, {ColME, TableEntryOid}, _Mib} ->
- ?vtrace("lookup -> table:"
- "~n EntryME: ~p"
- "~n ColME: ~p"
- "~n RevTableEntryOid: ~p",
- [EntryME, ColME, TableEntryOid]),
- MFA = EntryME#me.mfa,
- RetME = ColME#me{mfa = MFA},
- {table_column, RetME, TableEntryOid};
- {subagent, SubAgentPid, SANextOid} ->
- ?vtrace("lookup -> subagent:"
- "~n SubAgentPid: ~p"
- "~n SANextOid: ~p", [SubAgentPid, SANextOid]),
- {subagent, SubAgentPid, SANextOid};
- {false, ErrorCode} ->
- ?vtrace("lookup -> false:"
- "~n ErrorCode: ~p",[ErrorCode]),
- {false, ErrorCode};
- false ->
- ?vtrace("lookup -> false",[]),
- {false, noSuchObject};
- {'EXIT', R} ->
- ?vtrace("lookup -> exit:"
- "~n R: ~p",[R]),
- {false, noSuchObject}
- end.
-
-
-find_node(D, {tree, Tree, {table, _}}, RestOfOid, RevOid) ->
- ?vtrace("find_node(tree,table) -> entry with"
- "~n RestOfOid: ~p"
- "~n RevOid: ~p",[RestOfOid, RevOid]),
- find_node(D, {tree, Tree, internal}, RestOfOid, RevOid);
-find_node(D, {tree, Tree, {table_entry, _}}, RestOfOid, RevOid) ->
- ?vtrace("find_node(tree,table_entry) -> entry with"
- "~n RestOfOid: ~p"
- "~n RevOid: ~p",[RestOfOid, RevOid]),
- #mib_data{node_db = Db} = D,
- Oid = lists:reverse(RevOid),
- case snmpa_general_db:read(Db, Oid) of
- {value, #node_info{me = ME, mib_name = Mib}} ->
- case find_node(D, {tree, Tree, internal}, RestOfOid, RevOid) of
- {false, ErrorCode} -> {false, ErrorCode};
- Val -> {table, ME, Val, Mib}
- end;
- false ->
- ?vinfo("find_node -> could not find table_entry ME with"
- "~n RevOid: ~p"
- "~n when"
- "~n RestOfOid: ~p",
- [RevOid, RestOfOid]),
- false
- end;
-find_node(D, {tree, Tree, _Internal}, [Int | RestOfOid], RevOid) ->
- ?vtrace("find_node(tree) -> entry with"
- "~n Int: ~p"
- "~n RestOfOid: ~p"
- "~n RevOid: ~p",[Int, RestOfOid, RevOid]),
- find_node(D, element(Int+1, Tree), RestOfOid, [Int | RevOid]);
-find_node(D, {node, {table_column, _}}, RestOfOid, [ColInt | RevOid]) ->
- ?vtrace("find_node(tree,table_column) -> entry with"
- "~n RestOfOid: ~p"
- "~n ColInt: ~p"
- "~n RevOid: ~p",[RestOfOid, ColInt, RevOid]),
- #mib_data{node_db = Db} = D,
- Oid = lists:reverse([ColInt | RevOid]),
- case snmpa_general_db:read(Db, Oid) of
- {value, #node_info{me = ME}} ->
- {ME, lists:reverse(RevOid)};
- false ->
- X = snmpa_general_db:read(Db, lists:reverse([ColInt | RevOid])),
- ?vinfo("find_node -> could not find table_column ME with"
- "~n RevOid: ~p"
- "~n trying [~p|~p]"
- "~n X: ~p",
- [RevOid, [ColInt | RevOid], X]),
- false
- end;
-find_node(D, {node, {variable, _MibName}}, [0], RevOid) ->
- ?vtrace("find_node(tree,variable,[0]) -> entry with"
- "~n RevOid: ~p",[RevOid]),
- #mib_data{node_db = Db} = D,
- Oid = lists:reverse(RevOid),
- %% {value, #node_info{me = ME}} = snmpa_general_db:read(Db, Oid),
- case snmpa_general_db:read(Db, Oid) of
- {value, #node_info{me = ME, mib_name = Mib}} ->
- {variable, ME, Mib};
- false ->
- ?vinfo("find_node -> could not find variable ME with"
- "~n RevOid: ~p", [RevOid]),
- false
- end;
-find_node(_D, {node, {variable, _MibName}}, [], _RevOid) ->
- ?vtrace("find_node(tree,variable,[]) -> entry",[]),
- {false, noSuchObject};
-find_node(_D, {node, {variable, _MibName}}, _, _RevOid) ->
- ?vtrace("find_node(tree,variable) -> entry",[]),
- {false, noSuchInstance};
-find_node(D, {node, subagent}, _RestOfOid, SARevOid) ->
- ?vtrace("find_node(tree,subagent) -> entry with"
- "~n SARevOid: ~p",[SARevOid]),
- #mib_data{subagents = SAs} = D,
- SAOid = lists:reverse(SARevOid),
- case lists:keysearch(SAOid, 2, SAs) of
- {value, {SubAgentPid, SAOid}} ->
- {subagent, SubAgentPid, SAOid};
- false ->
- ?vinfo("find_node -> could not find subagent with"
- "~n SAOid: ~p"
- "~n SAs: ~p", [SAOid, SAs]),
- false
- end;
-find_node(_D, Node, _RestOfOid, _RevOid) ->
- ?vtrace("find_node -> failed:~n~p",[Node]),
- {false, noSuchObject}.
-
-
-%%-----------------------------------------------------------------
-%% Func: next/3
-%% Purpose: Finds the lexicographically next oid.
-%% Returns: endOfMibView |
-%% {subagent, SubAgentPid, SAOid} |
-%% {variable, MibEntry, VarOid} |
-%% {table, TableOid, TableRestOid, MibEntry}
-%% If a variable is returnes, it is in the MibView.
-%% If a table or subagent is returned, it *may* be in the MibView.
-%%-----------------------------------------------------------------
-next(#mib_data{tree = T} = D, Oid, MibView) ->
- case catch next_node(D, T#tree.root, Oid, [], MibView) of
- false -> endOfMibView;
- Else -> Else
- end.
-
-%%-----------------------------------------------------------------
-%% This function is used as long as we have any Oid left. Take
-%% one integer at a time from the Oid, and traverse the tree
-%% accordingly. When the Oid is empty, call find_next.
-%% Returns: {subagent, SubAgentPid, SAOid} |
-%% false |
-%% {variable, MibEntry, VarOid} |
-%% {table, TableOid, TableRestOid, MibEntry}
-%%-----------------------------------------------------------------
-next_node(_D, undefined_node, _Oid, _RevOidSoFar, _MibView) ->
- ?vtrace("next_node(undefined_node) -> entry", []),
- false;
-
-next_node(_D, {tree, Tree, {table_entry, _Id}}, [Int | _Oid],
- _RevOidSoFar, _MibView)
- when Int+1 > size(Tree) ->
- ?vtrace("next_node(tree,table_entry) -> entry when not found whith"
- "~n Int: ~p"
- "~n size(Tree): ~p", [Int, size(Tree)]),
- false;
-next_node(D, {tree, Tree, {table_entry, _MibName}},
- Oid, RevOidSoFar, MibView) ->
- ?vtrace("next_node(tree,table_entry) -> entry when"
- "~n size(Tree): ~p"
- "~n Oid: ~p"
- "~n RevOidSoFar: ~p"
- "~n MibView: ~p", [size(Tree), Oid, RevOidSoFar, MibView]),
- OidSoFar = lists:reverse(RevOidSoFar),
- case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
- true ->
- ?vdebug("next_node(tree,table_entry) -> not in mib view",[]),
- false;
- _ ->
- #mib_data{node_db = Db} = D,
- case snmpa_general_db:read(Db, OidSoFar) of
- false ->
- ?vinfo("next_node -> could not find table_entry with"
- "~n OidSoFar: ~p", [OidSoFar]),
- false;
- {value, #node_info{me = ME}} ->
- ?vtrace("next_node(tree,table_entry) -> found: ~n ~p",
- [ME]),
- {table, OidSoFar, Oid, ME}
- end
- end;
-
-next_node(D, {tree, Tree, _Info}, [Int | RestOfOid], RevOidSoFar, MibView)
- when (Int < size(Tree)) andalso (Int >= 0) ->
- ?vtrace("next_node(tree) -> entry when"
- "~n size(Tree): ~p"
- "~n Int: ~p"
- "~n RestOfOid: ~p"
- "~n RevOidSoFar: ~p"
- "~n MibView: ~p",
- [size(Tree), Int, RestOfOid, RevOidSoFar, MibView]),
- case next_node(D, element(Int+1,Tree),
- RestOfOid, [Int|RevOidSoFar], MibView) of
- false ->
- find_next(D, {tree, Tree, _Info}, Int+1, RevOidSoFar, MibView);
- Else ->
- Else
- end;
-%% no solution
-next_node(D, {tree, Tree, _Info}, [], RevOidSoFar, MibView) ->
- ?vtrace("next_node(tree,[]) -> entry when"
- "~n size(Tree): ~p"
- "~n RevOidSoFar: ~p"
- "~n MibView: ~p",
- [size(Tree), RevOidSoFar, MibView]),
- find_next(D, {tree, Tree, _Info}, 0, RevOidSoFar, MibView);
-next_node(_D, {tree, Tree, _Info}, _RestOfOid, _RevOidSoFar, _MibView) ->
- ?vtrace("next_node(tree) -> entry when"
- "~n size(Tree): ~p", [size(Tree)]),
- false;
-
-next_node(D, {node, subagent}, Oid, RevOidSoFar, MibView) ->
- ?vtrace("next_node(node,subagent) -> entry when"
- "~n Oid: ~p"
- "~n RevOidSoFar: ~p"
- "~n MibView: ~p",
- [Oid, RevOidSoFar, MibView]),
- OidSoFar = lists:reverse(RevOidSoFar),
- case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
- true ->
- false;
- _ ->
- #mib_data{subagents = SAs} = D,
- case lists:keysearch(OidSoFar, 2, SAs) of
- {value, {SubAgentPid, OidSoFar}} ->
- {subagent, SubAgentPid, OidSoFar};
- _ ->
- ?vinfo("next_node -> could not find subagent with"
- "~n OidSoFar: ~p"
- "~n SAs: ~p", [OidSoFar, SAs]),
- false
- end
- end;
-
-next_node(D, {node, {variable, _MibName}}, [], RevOidSoFar, MibView) ->
- ?vtrace("next_node(node,variable,[]) -> entry when"
- "~n RevOidSoFar: ~p"
- "~n MibView: ~p",
- [RevOidSoFar, MibView]),
- OidSoFar = lists:reverse([0 | RevOidSoFar]),
- case snmpa_acm:validate_mib_view(OidSoFar, MibView) of
- true ->
- #mib_data{node_db = Db} = D,
- case snmpa_general_db:read(Db, lists:reverse(RevOidSoFar)) of
- false ->
- ?vinfo("next_node -> could not find variable with"
- "~n RevOidSoFar: ~p", [RevOidSoFar]),
- false;
- {value, #node_info{me = ME}} ->
- {variable, ME, OidSoFar}
- end;
- _ ->
- false
- end;
-
-next_node(_D, {node, {variable, _MibName}}, _Oid, _RevOidSoFar, _MibView) ->
- ?vtrace("next_node(node,variable) -> entry", []),
- false.
-
-%%-----------------------------------------------------------------
-%% This function is used to find the first leaf from where we
-%% are.
-%% Returns: {subagent, SubAgentPid, SAOid} |
-%% false |
-%% {variable, MibEntry, VarOid} |
-%% {table, TableOid, TableRestOid, MibEntry}
-%% PRE: This function must always be called with a {internal, Tree}
-%% node.
-%%-----------------------------------------------------------------
-find_next(D, {tree, Tree, internal}, Idx, RevOidSoFar, MibView)
- when Idx < size(Tree) ->
- case find_next(D, element(Idx+1, Tree), 0, [Idx| RevOidSoFar], MibView) of
- false ->
- find_next(D, {tree, Tree, internal}, Idx+1, RevOidSoFar, MibView);
- Other ->
- Other
- end;
-find_next(_D, {tree, _Tree, internal}, _Idx, _RevOidSoFar, _MibView) ->
- false;
-find_next(_D, undefined_node, _Idx, _RevOidSoFar, _MibView) ->
- false;
-find_next(D, {tree, Tree, {table, _MibName}}, Idx, RevOidSoFar, MibView) ->
- find_next(D, {tree, Tree, internal}, Idx, RevOidSoFar, MibView);
-find_next(D, {tree, _Tree, {table_entry, _MibName}}, _Index,
- RevOidSoFar, MibView) ->
- OidSoFar = lists:reverse(RevOidSoFar),
- case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
- true ->
- false;
- _ ->
- #mib_data{node_db = Db} = D,
- case snmpa_general_db:read(Db, OidSoFar) of
- false ->
- ?vinfo("find_next -> could not find table_entry ME with"
- "~n OidSoFar: ~p", [OidSoFar]),
- false;
- {value, #node_info{me = ME}} ->
- {table, OidSoFar, [], ME}
- end
- end;
-find_next(D, {node, {variable, _MibName}}, _Idx, RevOidSoFar, MibView) ->
- OidSoFar = lists:reverse([0 | RevOidSoFar]),
- case snmpa_acm:validate_mib_view(OidSoFar, MibView) of
- true ->
- #mib_data{node_db = Db} = D,
- case snmpa_general_db:read(Db, lists:reverse(RevOidSoFar)) of
- false ->
- ?vinfo("find_next -> could not find variable with"
- "~n RevOidSoFar: ~p", [RevOidSoFar]),
- false;
- {value, #node_info{me = ME}} ->
- {variable, ME, OidSoFar}
- end;
- _ ->
- false
- end;
-find_next(D, {node, subagent}, _Idx, RevOidSoFar, MibView) ->
- OidSoFar = lists:reverse(RevOidSoFar),
- case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
- true ->
- false;
- _ ->
- #mib_data{subagents = SAs} = D,
- case lists:keysearch(OidSoFar, 2, SAs) of
- {value, {SubAgentPid, OidSoFar}} ->
- {subagent, SubAgentPid, OidSoFar};
- false ->
- ?vinfo("find_node -> could not find subagent with"
- "~n OidSoFar: ~p"
- "~n SAs: ~p", [OidSoFar, SAs]),
- false
- end
- end.
-
-%%%======================================================================
-%%% 3. Tree building functions
-%%% Used when loading mibs.
-%%%======================================================================
-
-build_tree(Mes, MibName) ->
- ?d("build_tree -> "
- "~n Mes: ~p", [Mes]),
- {ListTree, []} = build_subtree([], Mes, MibName),
- {tree, convert_tree(ListTree), internal}.
-
-%%----------------------------------------------------------------------
-%% Purpose: Builds the tree where all oids have prefix equal to LevelPrefix.
-%% Returns: {Tree, RestMes}
-%% RestMes are Mes that should not be in this subtree.
-%% The Tree is a temporary and simplified data structure that is easy to
-%% convert to the final tuple tree used by the MIB process.
-%% A Node is represented as in the final tree.
-%% The tree is not represented as a N-tuple, but as an Index-list.
-%% Example: Temporary: [{1, Node1}, {3, Node3}]
-%% Final: {Node1, undefined_node, Node3}
-%% Pre: Mes are sorted on oid.
-%%----------------------------------------------------------------------
-build_subtree(LevelPrefix, [Me | Mes], MibName) ->
- ?vtrace("build subtree -> ~n"
- " oid: ~p~n"
- " LevelPrefix: ~p~n"
- " MibName: ~p", [Me#me.oid, LevelPrefix, MibName]),
- EType = Me#me.entrytype,
- ?vtrace("build subtree -> EType = ~p",[EType]),
- case in_subtree(LevelPrefix, Me) of
- above ->
- ?vtrace("build subtree -> above",[]),
- {[], [Me|Mes]};
- {node, Index} ->
- ?vtrace("build subtree -> node at ~p",[Index]),
- {Tree, RestMes} = build_subtree(LevelPrefix, Mes, MibName),
- {[{Index, {node, {EType, MibName}}} | Tree], RestMes};
- {subtree, Index, NewLevelPrefix} ->
- ?vtrace("build subtree -> subtree at"
- "~n ~w with ~w",
- [Index, NewLevelPrefix]),
- {BelowTree, RestMes} =
- build_subtree(NewLevelPrefix, Mes, MibName),
- {CurTree, RestMes2} =
- build_subtree(LevelPrefix, RestMes, MibName),
- {[{Index, {tree, BelowTree, {EType,MibName}}}| CurTree], RestMes2};
- {internal_subtree, Index, NewLevelPrefix} ->
- ?vtrace("build subtree -> internal_subtree at"
- "~n ~w with ~w",
- [Index,NewLevelPrefix]),
- {BelowTree, RestMes} =
- build_subtree(NewLevelPrefix, [Me | Mes], MibName),
- {CurTree, RestMes2} =
- build_subtree(LevelPrefix, RestMes, MibName),
- {[{Index, {tree, BelowTree, internal}} | CurTree], RestMes2}
- end;
-
-build_subtree(_LevelPrefix, [], _MibName) ->
- ?vtrace("build subtree -> done", []),
- {[], []}.
-
-%%--------------------------------------------------
-%% Purpose: Determine how/if/where Me should be inserted in subtree
-%% with LevelPrefix. This function does not build any tree, only
-%% determinses what should be done (by build subtree).
-%% Returns:
-%% above - Indicating that this ME should _not_ be in this subtree.
-%% {node, Index} - yes, construct a node with index Index on this level
-%% {internal_subtree, Index, NewLevelPrefix} - yes, there should be an
-%% internal subtree at this index.
-%% {subtree, Index, NewLevelPrefix} - yes, construct a subtree with
-%% NewLevelPrefix and insert this on current level in position Index.
-%%--------------------------------------------------
-in_subtree(LevelPrefix, Me) ->
- case lists:prefix(LevelPrefix, Me#me.oid) of
- true when length(Me#me.oid) > length(LevelPrefix) ->
- classify_how_in_subtree(LevelPrefix, Me);
- _ ->
- above
- end.
-
-%%--------------------------------------------------
-%% See comment about in_subtree/2. This function takes care of all cases
-%% where the ME really should be in _this_ subtree (not above).
-%%--------------------------------------------------
-classify_how_in_subtree(LevelPrefix, Me)
- when (length(Me#me.oid) =:= (length(LevelPrefix) + 1)) ->
- Oid = Me#me.oid,
- case node_or_subtree(Me#me.entrytype) of
- subtree ->
- {subtree, lists:last(Oid), Oid};
- node ->
- {node, lists:last(Oid)}
- end;
-
-classify_how_in_subtree(LevelPrefix, Me)
- when (length(Me#me.oid) > (length(LevelPrefix) + 1)) ->
- L1 = length(LevelPrefix) + 1,
- Oid = Me#me.oid,
- {internal_subtree, lists:nth(L1, Oid), lists:sublist(Oid, 1, L1)}.
-
-%%--------------------------------------------------
-%% Determines how to treat different kinds om MEs in the tree building process.
-%% Pre: all internal nodes have been removed.
-%%--------------------------------------------------
-node_or_subtree(table) -> subtree;
-node_or_subtree(table_entry) -> subtree;
-node_or_subtree(variable) -> node;
-node_or_subtree(table_column) -> node.
-
-%%--------------------------------------------------
-%% Purpose: (Recursively) Converts a temporary tree (see above) to a final tree.
-%% If input is a ListTree, output is a TupleTree.
-%% If input is a Node, output is the same Node.
-%% Pre: All Indexes are >= 0.
-%%--------------------------------------------------
-convert_tree({Index, {tree, Tree, Info}}) when Index >= 0 ->
- L = lists:map(fun convert_tree/1, Tree),
- {Index, {tree, dict_list_to_tuple(L), Info}};
-convert_tree({Index, {node, Info}}) when Index >= 0 ->
- {Index, {node, Info}};
-convert_tree(Tree) when is_list(Tree) ->
- L = lists:map(fun convert_tree/1, Tree),
- dict_list_to_tuple(L).
-
-%%----------------------------------------------------------------------
-%% Purpose: Converts a single level (that is non-recursively) from
-%% the temporary indexlist to the N-tuple.
-%% Input: A list of {Index, Data}.
-%% Output: A tuple where element Index is Data.
-%%----------------------------------------------------------------------
-dict_list_to_tuple(L) ->
- L2 = lists:keysort(1, L),
- list_to_tuple(integrate_indexes(0, L2)).
-
-%%----------------------------------------------------------------------
-%% Purpose: Helper function for dict_list_to_tuple/1.
-%% Converts an indexlist to a N-list.
-%% Input: A list of {Index, Data}.
-%% Output: A (usually longer, never shorter) list where element Index is Data.
-%% Example: [{1,hej}, {3, sven}] will give output
-%% [undefined_node, hej, undefined_node, sven].
-%% Initially CurIndex should be 0.
-%%----------------------------------------------------------------------
-integrate_indexes(CurIndex, [{CurIndex, Data} | T]) ->
- [Data | integrate_indexes(CurIndex + 1, T)];
-integrate_indexes(_Index, []) ->
- [];
-integrate_indexes(CurIndex, L) ->
- [undefined_node | integrate_indexes(CurIndex + 1, L)].
-
-%%%======================================================================
-%%% 4. Tree merging
-%%% Used by: load mib, insert subagent.
-%%%======================================================================
-
-%%----------------------------------------------------------------------
-%% Arg: Two root nodes (that is to be merged).
-%% Returns: A new root node where the nodes have been merger to one.
-%%----------------------------------------------------------------------
-merge_nodes(Same, Same) ->
- Same;
-merge_nodes(Node, undefined_node) ->
- Node;
-merge_nodes(undefined_node, Node) ->
- Node;
-merge_nodes({tree, Tree1, internal}, {tree, Tree2, internal}) ->
- {tree, merge_levels(tuple_to_list(Tree1),tuple_to_list(Tree2)), internal};
-merge_nodes(Node1, Node2) ->
- throw({error_merge_nodes, Node1, Node2}).
-
-%%----------------------------------------------------------------------
-%% Arg: Two levels to be merged.
-%% Here, a level is represented as a list of nodes. A list is easier
-%% to extend than a tuple.
-%% Returns: The resulting, merged level tuple.
-%%----------------------------------------------------------------------
-merge_levels(Level1, Level2) when length(Level1) =:= length(Level2) ->
- MergeNodes = fun(N1, N2) -> merge_nodes(N1, N2) end,
- list_to_tuple(snmp_misc:multi_map(MergeNodes, [Level1, Level2]));
-merge_levels(Level1, Level2) when length(Level1) > length(Level2) ->
- merge_levels(Level1, Level2 ++
- undefined_nodes_list(length(Level1) - length(Level2)));
-merge_levels(Level1, Level2) when length(Level1) < length(Level2) ->
- merge_levels(Level2, Level1).
-
-undefined_nodes_list(N) -> lists:duplicate(N, undefined_node).
-
-
-%%%======================================================================
-%%% 5. Tree deletion routines
-%%% (for unload mib)
-%%%======================================================================
-
-%%----------------------------------------------------------------------
-%% Purpose: Actually kicks of the tree reconstruction.
-%% Returns: {list of removed MEs, NewTree}
-%%----------------------------------------------------------------------
-delete_mib_from_tree(MibName, {tree, Tree, internal}) ->
- case delete_tree(Tree, MibName) of
- [] ->
- {tree, {undefined_node}, internal}; % reduce
- LevelList ->
- {tree, list_to_tuple(LevelList), internal}
- end.
-
-%%----------------------------------------------------------------------
-%% Purpose: Deletes all nodes associated to MibName from this level and
-%% all levels below.
-%% If the new level does not contain information (that is, no
-%% other mibs use it) anymore the empty list is returned.
-%% Returns: {MEs, The new level represented as a list}
-%%----------------------------------------------------------------------
-delete_tree(Tree, MibName) when is_tuple(Tree) ->
- NewLevel = delete_nodes(tuple_to_list(Tree), MibName, []),
- case lists:filter(fun drop_undefined_nodes/1,NewLevel) of
- [] -> [];
- _A_perhaps_shorted_list ->
- NewLevel % some other mib needs this level
- end.
-
-%%----------------------------------------------------------------------
-%% Purpose: Nodes belonging to MibName are removed from the tree.
-%% Recursively deletes sub trees to this node.
-%% Returns: {MEs, NewNodesList}
-%%----------------------------------------------------------------------
-delete_nodes([], _MibName, AccNodes) ->
- lists:reverse(AccNodes);
-
-delete_nodes([{node, {variable, MibName}}|T], MibName, AccNodes) ->
- delete_nodes(T, MibName, [undefined_node | AccNodes]);
-
-delete_nodes([{node, {table_column, MibName}}|T], MibName, AccNodes) ->
- delete_nodes(T, MibName, [undefined_node | AccNodes]);
-
-delete_nodes([{tree, _Tree, {table, MibName}}|T], MibName, AccNodes) ->
- delete_nodes(T, MibName, [undefined_node | AccNodes]);
-
-delete_nodes([{tree, _Tree, {table_entry, MibName}}|T], MibName, AccNodes) ->
- delete_nodes(T, MibName, [undefined_node | AccNodes]);
-
-delete_nodes([{tree, Tree, Info}|T], MibName, AccNodes) ->
- case delete_tree(Tree, MibName) of
- [] -> % tree completely deleted
- delete_nodes(T, MibName, [undefined_node | AccNodes]);
- LevelList ->
- delete_nodes(T, MibName,
- [{tree, list_to_tuple(LevelList), Info} | AccNodes])
- end;
-
-delete_nodes([NodeToKeep|T], MibName, AccNodes) ->
- delete_nodes(T, MibName, [NodeToKeep | AccNodes]).
-
-drop_undefined_nodes(undefined_node) -> false;
-drop_undefined_nodes(_) -> true.
-
-
-%%%======================================================================
-%%% 6. Functions for subagent handling
-%%%======================================================================
-
-%%----------------------------------------------------------------------
-%% Returns: A new Root|{error, reason}
-%%----------------------------------------------------------------------
-insert_subagent(Oid, OldRoot) ->
- ListTree = build_tree_for_subagent(Oid),
- case catch convert_tree(ListTree) of
- {'EXIT', _Reason} ->
- {error, 'cannot construct tree from oid'};
- Level when is_tuple(Level) ->
- T = {tree, Level, internal},
- case catch merge_nodes(T, OldRoot) of
- {error_merge_nodes, _Node1, _Node2} ->
- {error, oid_conflict};
- NewRoot when is_tuple(NewRoot) andalso
- (element(1, NewRoot) =:= tree) ->
- NewRoot
- end
- end.
-
-build_tree_for_subagent([Index]) ->
- [{Index, {node, subagent}}];
-
-build_tree_for_subagent([Index | T]) ->
- [{Index, {tree, build_tree_for_subagent(T), internal}}].
+-type mib_view() :: [mib_view_elem()].
+-type mib_view_elem() :: {SubTree :: snmp:oid(),
+ Mask :: [non_neg_integer()],
+ Inclusion :: mib_view_inclusion()}.
+-type mib_view_mask() :: [non_neg_integer()].
+-type mib_view_inclusion() :: 1 | 2. % 1 = included, 2 = excluded
-%%----------------------------------------------------------------------
-%% Returns: A new tree where the subagent at Oid (2nd arg) has been deleted.
-%%----------------------------------------------------------------------
-delete_subagent({tree, Tree, Info}, [Index]) ->
- {node, subagent} = element(Index+1, Tree),
- {tree, setelement(Index+1, Tree, undefined_node), Info};
-delete_subagent({tree, Tree, Info}, [Index | TI]) ->
- {tree, setelement(Index+1, Tree,
- delete_subagent(element(Index+1, Tree), TI)), Info}.
+-type filename() :: file:filename().
-%%%======================================================================
-%%% 7. Misc functions
-%%%======================================================================
-%%----------------------------------------------------------------------
-%% Installs the mibs found in the database when starting the agent.
-%% Basically calls the instrumentation functions for all non-internal
-%% mib-entries
-%%----------------------------------------------------------------------
-install_mibs(MibDb, NodeDb) ->
- MibNames = loaded(MibDb),
- ?vtrace("install_mibs -> found following mibs in database: ~n"
- "~p", [MibNames]),
- install_mibs2(NodeDb, MibNames).
+-callback new(MibStorage :: snmpa:mib_storage()) -> State :: term().
-install_mibs2(_, []) ->
- ok;
-install_mibs2(NodeDb, [MibName|MibNames]) ->
- Pattern = #node_info{oid = '_', mib_name = MibName, me = '_'},
- Nodes = snmpa_general_db:match_object(NodeDb, Pattern),
- MEs = [ME || #node_info{me = ME} <- Nodes],
- ?vtrace("install_mibs2 -> installing ~p MEs for mib ~p",
- [length(MEs),MibName]),
- NewF = fun(ME) -> call_instrumentation(ME, new) end,
- lists:foreach(NewF, MEs),
- install_mibs2(NodeDb, MibNames).
-
-
-%%----------------------------------------------------------------------
-%% Does all side effect stuff during load_mib.
-%%----------------------------------------------------------------------
-install_mib(Db, Symbolic, Mib, MibName, FileName, NonInternalMes) ->
- ?vdebug("install_mib -> entry with"
- "~n Symbolic: ~p"
- "~n MibName: ~p"
- "~n FileName: ~p", [Symbolic, MibName, FileName]),
- Rec = #mib_info{name = MibName, symbolic = Symbolic, file_name = FileName},
- snmpa_general_db:write(Db, Rec),
- install_mib2(Symbolic, MibName, Mib),
- NewF = fun(ME) -> call_instrumentation(ME, new) end,
- lists:foreach(NewF, NonInternalMes).
+-callback close(State :: term()) -> ok.
-install_mib2(true, MibName, Mib) ->
- #mib{table_infos = TabInfos,
- variable_infos = VarInfos,
- mes = MEs,
- asn1_types = ASN1Types,
- traps = Traps} = Mib,
- snmpa_symbolic_store:add_table_infos(MibName, TabInfos),
- snmpa_symbolic_store:add_variable_infos(MibName, VarInfos),
- snmpa_symbolic_store:add_aliasnames(MibName, MEs),
- snmpa_symbolic_store:add_types(MibName, ASN1Types),
- SetF = fun(Trap) ->
- snmpa_symbolic_store:set_notification(Trap, MibName)
- end,
- lists:foreach(SetF, Traps);
-install_mib2(_, _, _) ->
- ok.
+-callback sync(State :: term()) -> ok.
-install_mes(_Db, _MibName, []) ->
- ok;
-install_mes(Db, MibName, [ME|MEs]) ->
- Node = #node_info{oid = ME#me.oid, mib_name = MibName, me = ME},
- snmpa_general_db:write(Db, Node),
- install_mes(Db, MibName, MEs).
+-callback load_mib(State :: term(), FileName :: string(),
+ MeOverride :: boolean(),
+ TeOverride :: boolean()) ->
+ {ok, NewState :: term()} | {error, Reason :: already_loaded | term()}.
+-callback unload_mib(State :: term(), FileName :: string(),
+ MeOverride :: boolean(),
+ TeOverride :: boolean()) ->
+ {ok, NewState :: term()} | {error, Reason :: not_loaded | term()}.
-%%----------------------------------------------------------------------
-%% Does all side effect stuff during unload_mib.
-%%----------------------------------------------------------------------
-uninstall_mib(Db, Symbolic, MibName, MEs) ->
- ?vtrace("uninstall_mib -> entry with"
- "~n Db: ~p"
- "~n Symbolic: ~p"
- "~n MibName: ~p", [Db, Symbolic, MibName]),
- Res = snmpa_general_db:delete(Db, MibName),
- ?vtrace("uninstall_mib -> (mib) db delete result: ~p", [Res]),
- uninstall_mib2(Symbolic, MibName),
- DelF = fun(ME) -> call_instrumentation(ME, delete) end,
- lists:foreach(DelF, MEs).
+-callback lookup(State :: term(), Oid :: snmp:oid()) ->
+ {false, Reason :: term()} |
+ {variable, MibEntry :: snmpa:me()} |
+ {table_column, MibEntry :: snmpa:me(), TableEntryOid :: snmp:oid()} |
+ {subagent, SubAgentPid :: pid(), SAOid :: snmp:oid()}.
-uninstall_mib2(true, MibName) ->
- snmpa_symbolic_store:delete_table_infos(MibName),
- snmpa_symbolic_store:delete_variable_infos(MibName),
- snmpa_symbolic_store:delete_aliasnames(MibName),
- snmpa_symbolic_store:delete_types(MibName),
- snmpa_symbolic_store:delete_notifications(MibName);
-uninstall_mib2(_, _) ->
- ok.
+-callback next(State :: term(), Oid :: snmp:oid(), MibView :: mib_view()) ->
+ endOfView | false |
+ {subagent, SubAgentPid :: pid(), SAOid :: snmp:oid()} |
+ {variable, MibEntry :: snmpa:me(), VarOid :: snmp:oid()} |
+ {table, TableOid :: snmp:oid(), TableRestOid :: snmp:oid(), MibEntry :: snmpa:me()}.
-uninstall_mes(Db, MibName) ->
- Pattern = #node_info{oid = '_', mib_name = MibName, me = '_'},
- snmpa_general_db:match_delete(Db, Pattern).
+-callback register_subagent(State :: term(),
+ Oid :: snmp:oid(),
+ Pid :: pid()) ->
+ {ok, NewState :: term()} | {error, Reason :: term()}.
+-callback unregister_subagent(State :: term(),
+ PidOrOid :: pid() | snmp:oid()) ->
+ {ok, NewState :: term()} | % When second arg was a pid()
+ {ok, NewState :: term(), Pid :: pid()} | % When second arg was a oid()
+ {error, Reason :: term()}.
-%%----------------------------------------------------------------------
-%% Create a list of the names of all the loaded mibs
-%%----------------------------------------------------------------------
-loaded(Db) ->
- [N || #mib_info{name = N} <- snmpa_general_db:tab2list(Db)].
-
+-callback dump(State :: term(), Destination :: io | filename()) ->
+ ok | {error, Reason :: term()}.
-%%----------------------------------------------------------------------
-%% Calls MFA-instrumentation with 'new' or 'delete' operation.
-%%----------------------------------------------------------------------
-call_instrumentation(#me{entrytype = variable, mfa={M,F,A}}, Operation) ->
- ?vtrace("call instrumentation with"
- "~n entrytype: variable"
- "~n MFA: {~p,~p,~p}"
- "~n Operation: ~p",
- [M,F,A,Operation]),
- catch apply(M, F, [Operation | A]);
-call_instrumentation(#me{entrytype = table_entry, mfa={M,F,A}}, Operation) ->
- ?vtrace("call instrumentation with"
- "~n entrytype: table_entry"
- "~n MFA: {~p,~p,~p}"
- "~n Operation: ~p",
- [M,F,A,Operation]),
- catch apply(M, F, [Operation | A]);
-call_instrumentation(_ShitME, _Operation) ->
- done.
+-callback which_mib(State :: term(), Oid :: snmp:oid()) ->
+ {ok, Mib :: string()} | {error, Reason :: term()}.
+-callback which_mibs(State :: term()) ->
+ [{MibName :: atom(), Filename :: string()}].
-maybe_drop_me(#me{entrytype = internal}) -> false;
-maybe_drop_me(#me{entrytype = group}) -> false;
-maybe_drop_me(#me{imported = true}) -> false;
-maybe_drop_me(_) -> true.
+-callback whereis_mib(State :: term(), MibName :: atom()) ->
+ {ok, Filename :: string()} | {error, Reason :: term()}.
+-callback info(State :: term()) -> list().
-%%----------------------------------------------------------------------
-%% Code change functions
-%%----------------------------------------------------------------------
+-callback backup(State :: term(), BackupDir :: string()) ->
+ ok | {error, Reason :: term()}.
-code_change(down, State) ->
- ?d("code_change(down) -> entry",[]),
- State;
+-callback code_change(Direction :: up | down,
+ Vsn :: term(),
+ Extra :: term(),
+ State :: term()) ->
+ NewState :: term().
-code_change(up, State) ->
- ?d("code_change(up)",[]),
- State;
-code_change(_Vsn, State) ->
- State.
diff --git a/lib/snmp/src/agent/snmpa_mib_data_ttln.erl b/lib/snmp/src/agent/snmpa_mib_data_ttln.erl
new file mode 100644
index 0000000000..d367e8f13f
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_mib_data_ttln.erl
@@ -0,0 +1,1402 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(snmpa_mib_data_ttln).
+
+%%%-----------------------------------------------------------------
+%%%
+%%% THIS FILE IS JUST A PLACE HOLDER - IGNORE
+%%%
+%%%-----------------------------------------------------------------
+
+
+%%%-----------------------------------------------------------------
+%%%
+%%% TTLN - TupleTreeListNodes
+%%%
+%%% This module implements the MIB internal data structures.
+%%% An MIB Data Structure consists of three items; an ets-table,
+%%% a tree and a list of registered subagents.
+%%% The subagent information is consequently duplicated. It resides
+%%% both in the tree and in the list.
+%%% The ets-table contains all data associated with each variable,
+%%% table, tableentry and tablecolumn in the MIB.
+%%% The tree contains information of the Oids in the MIB.
+%%%
+%%% When a mib is loaded, the tree is built from the plain list
+%%% in the binary file.
+%%%
+%%%-----------------------------------------------------------------
+
+-include("snmp_types.hrl").
+-include("snmp_debug.hrl").
+
+-define(VMODULE,"MDATA_TTLN").
+-include("snmp_verbosity.hrl").
+
+-behaviour(snmpa_mib_data).
+
+-define(MIB_DATA, snmpa_mib_data).
+-define(MIB_NODE, snmpa_mib_node).
+-define(MIB_TREE, snmpa_mib_tree).
+-define(DUMMY_TREE_GENERATION, 1).
+-define(DEFAULT_TREE, {tree,{undefined_node},internal}).
+
+
+%%%-----------------------------------------------------------------
+%%% Table of contents
+%%% =================
+%%% 1. Interface
+%%% 2. Implementation of tree access
+%%% 3. Tree building functions
+%%% 4. Tree merging
+%%% 5. Tree deletion routines
+%%% 6. Functions for subagent handling
+%%% 7. Misc functions
+%%%-----------------------------------------------------------------
+
+
+%%----------------------------------------------------------------------
+%% data_db is an database containing loaded mibs as:
+%% {MibName = atom(), Symbolic = ?, FullFileName = string()}
+%% it is either ets or mnesia
+%% tree_db is a database containing _one_ record with the tree!
+%% (the reason for this is part to get replication and part out of convenience)
+%% ref_tree is the root node, without any subagent.
+%% tree is the root node (same as ref_tree but with the subagents added).
+%% subagents is a list of {SAPid, Oid}
+%%----------------------------------------------------------------------
+-record(mib_data, {mib_db, % table of #mib_info
+ node_db, % table of #node_info
+ tree_db, % table of #tree
+ tree, % The actual tree
+ subagents = []}).
+
+-record(mib_info, {name, symbolic, file_name}).
+-record(node_info, {oid, mib_name, me}).
+
+
+%% API
+-export([new/0, new/1, sync/1, close/1,
+ load_mib/4, unload_mib/4, which_mibs/1, whereis_mib/2,
+ info/1, info/2,
+ dump/1, dump/2,
+ backup/2,
+ lookup/2, next/3, which_mib/2,
+ register_subagent/3, unregister_subagent/2]).
+
+%% Internal exports
+-export([code_change/2]).
+
+
+%%-----------------------------------------------------------------
+%% A tree is represented as a N-tuple, where each element is a
+%% node. A node is:
+%% 1) {tree, Tree, Info} where Info can be {table, Id}, {table_entry, Id}
+%% or perhaps 'internal'
+%% 2) undefined_node (memory optimization (instead of {node, undefined}))
+%% 3) {node, Info} where Info can be {subagent, Pid}, {variable, Id},
+%% {table_column, Id}
+%% Id is {MibName, MibEntry}
+%% The over all root is represented as {tree, Tree, internal}.
+%%
+%% tree() = {tree, nodes(), tree_info()}
+%% nodes() = [tree() | node() | undefined_node]
+%% node() = {node, node_info()}
+%% tree_info() = {table, Id} | {table_entry, Id} | internal
+%% node_info() = {subagent, Pid} | {variable, Id} | {table_colum, Id}
+%%-----------------------------------------------------------------
+
+-type tree_generation() :: non_neg_integer().
+-type tree() :: #tree{}.
+-type tree_nodes() :: [tree_node()].
+-type tree_node() :: tree() |
+ tree_node_elem() |
+ tree_node_empty().
+-type tree_node_elem() :: {node, tree_node_info()}.
+-type tree_node_info() :: {subagent, Pid :: pid()} |
+ {variable, Id :: non_neg_integer()} |
+ {table_column, Id :: non_neg_integer()}.
+-type tree_node_empty() :: {undefined_node, N :: pos_integer()}.
+-type tree_info() :: {table, Id :: non_neg_integer()} |
+ {table_entry, Id :: non_neg_integer()} |
+ internal.
+
+
+%% This record is what is stored in the database. The 'tree' part
+%% is described above...
+-record(mtree,
+ {
+ generation = ?DUMMY_TREE_GENERATION :: tree_generation(),
+ root = ?DEFAULT_TREE :: tree()
+ }).
+
+-record(tree,
+ {
+ %% The number of nodes is *not* actually the length of the
+ %% nodes list. Since the undefined-node(s) can be collapsed
+ %% into {undefined_node, N} we need to keep track of the
+ %% actual size some other way (so that we dont have the
+ %% traverse the nodes every time we want to check an index).
+ num_nodes :: non_neg_integer(),
+ nodes :: tree_nodes(),
+ tree_info :: tree_info()
+ }).
+
+
+
+
+%%%======================================================================
+%%% 1. Interface
+%%%======================================================================
+
+%%-----------------------------------------------------------------
+%% Func: new/0, new/1
+%% Returns: A representation of mib data.
+%%-----------------------------------------------------------------
+new() ->
+ new(ets).
+
+%% Where -> A list of nodes where the tables will be created
+new(Storage) ->
+ %% First we must check if there is already something to read
+ %% If a database already exists, then the tree structure has to be read
+ ?vtrace("open (mib) database",[]),
+ MibDb = snmpa_general_db:open(Storage, ?MIB_DATA,
+ mib_info,
+ record_info(fields, mib_info), set),
+ ?vtrace("open (mib) node database",[]),
+ NodeDb = snmpa_general_db:open(Storage, ?MIB_NODE,
+ node_info,
+ record_info(fields, node_info), set),
+ ?vtrace("open (mib) tree database",[]),
+ TreeDb = snmpa_general_db:open(Storage, ?MIB_TREE,
+ tree,
+ record_info(fields, mtree), set),
+ MTree =
+ case snmpa_general_db:read(TreeDb, ?DUMMY_TREE_GENERATION) of
+ false ->
+ T = #mtree{},
+ snmpa_general_db:write(TreeDb, T),
+ T;
+ {value, T} ->
+ T
+ end,
+ install_mibs(MibDb, NodeDb),
+ #mib_data{mib_db = MibDb,
+ node_db = NodeDb,
+ tree_db = TreeDb,
+ mtree = MTree}.
+
+
+%%----------------------------------------------------------------------
+%% Returns: new mib data | {error, Reason}
+%%----------------------------------------------------------------------
+load_mib(MibData,FileName,MeOverride,TeOverride)
+ when is_record(MibData,mib_data) andalso is_list(FileName) ->
+ ?vlog("load mib file: ~p",[FileName]),
+ ActualFileName = filename:rootname(FileName, ".bin") ++ ".bin",
+ MibName = list_to_atom(filename:basename(FileName, ".bin")),
+ (catch do_load_mib(MibData, ActualFileName, MibName,
+ MeOverride, TeOverride)).
+
+do_load_mib(MibData, ActualFileName, MibName, MeOverride, TeOverride) ->
+ ?vtrace("do_load_mib -> entry with"
+ "~n ActualFileName: ~s"
+ "~n MibName: ~p",[ActualFileName, MibName]),
+ #mib_data{mib_db = MibDb,
+ node_db = NodeDb,
+ %% tree_db = TreeDb,
+ tree = Tree} = MibData,
+ verify_not_loaded(MibDb, MibName),
+ ?vtrace("do_load_mib -> already loaded mibs:"
+ "~n ~p",[loaded(MibDb)]),
+ Mib = do_read_mib(ActualFileName),
+ ?vtrace("do_load_mib -> read mib ~s",[Mib#mib.name]),
+ NonInternalMes =
+ lists:filter(fun(ME) -> maybe_drop_me(ME) end, Mib#mib.mes),
+ OldRoot = Tree#tree.root,
+ T = build_tree(NonInternalMes, MibName),
+ ?d("load_mib -> "
+ "~n OldRoot: ~p"
+ "~n T: ~p", [OldRoot, T]),
+ case (catch merge_nodes(T, OldRoot)) of
+ {error_merge_nodes, Node1, Node2} ->
+ ?vlog("error merging nodes:"
+ "~n~p~nand~n~p", [Node1,Node2]),
+ {error, oid_conflict};
+ NewRoot when is_tuple(NewRoot) andalso (element(1,NewRoot) =:= tree) ->
+ ?d("load_mib -> "
+ "~n NewRoot: ~p", [NewRoot]),
+ Symbolic = not lists:member(no_symbolic_info, Mib#mib.misc),
+ case (catch check_notif_and_mes(TeOverride, MeOverride, Symbolic,
+ Mib#mib.traps, NonInternalMes)) of
+ true ->
+ install_mes(NodeDb, MibName, NonInternalMes),
+ install_mib(MibDb, Symbolic, Mib,
+ MibName, ActualFileName, NonInternalMes),
+ ?vtrace("installed mib ~s", [Mib#mib.name]),
+ Tree2 = Tree#tree{root = NewRoot},
+ %% snmpa_general_db:write(TreeDb, Tree2), %% Store later?
+ {ok, MibData#mib_data{tree = Tree2}};
+ Else ->
+ Else
+ end
+ end.
+
+
+verify_not_loaded(Db, Name) ->
+ case snmpa_general_db:read(Db, Name) of
+ {value, #mib_info{name = Name}} ->
+ throw({error, 'already loaded'});
+ false ->
+ ok
+ end.
+
+do_read_mib(ActualFileName) ->
+ case snmp_misc:read_mib(ActualFileName) of
+ {error, Reason} ->
+ ?vlog("Failed reading mib file ~p with reason: ~p",
+ [ActualFileName,Reason]),
+ throw({error, Reason});
+ {ok, Mib} ->
+ Mib
+ end.
+
+%% The Tree DB is handled in a special way since it can be very large.
+sync(#mib_data{mib_db = M,
+ node_db = N,
+ tree_db = T, tree = Tree, subagents = []}) ->
+ snmpa_general_db:sync(M),
+ snmpa_general_db:sync(N),
+ snmpa_general_db:write(T, Tree),
+ snmpa_general_db:sync(T);
+sync(#mib_data{mib_db = M,
+ node_db = N,
+ tree_db = T, tree = Tree, subagents = SAs}) ->
+
+ snmpa_general_db:sync(M),
+ snmpa_general_db:sync(N),
+
+ %% Ouch. Since the subagent info is dynamic we do not
+ %% want to store the tree containing subagent info. So, we
+ %% have to create a tmp tree without those and store it.
+
+ case delete_subagents(Tree, SAs) of
+ {ok, TreeWithoutSAs} ->
+ snmpa_general_db:write(T, TreeWithoutSAs),
+ snmpa_general_db:sync(T);
+ Error ->
+ Error
+ end.
+
+delete_subagents(Tree, []) ->
+ {ok, Tree};
+delete_subagents(Tree0, [{_, Oid}|SAs]) ->
+ case (catch delete_subagent(Tree0, Oid)) of
+ {tree, _Tree, _Info} = Tree1 ->
+ delete_subagents(Tree1, SAs);
+ _Error ->
+ {error, {'invalid oid', Oid}}
+ end.
+
+%%----------------------------------------------------------------------
+%% (OTP-3601)
+%%----------------------------------------------------------------------
+check_notif_and_mes(TeOverride,MeOverride,Symbolic,Traps,MEs) ->
+ ?vtrace("check notifications and mib entries",[]),
+ check_notifications(TeOverride,Symbolic,Traps),
+ check_mes(MeOverride,MEs).
+
+check_notifications(true, _Symbolic, _Traps) ->
+ ?vtrace("trapentry override = true => skip check",[]),
+ true;
+check_notifications(_, Symbolic, Traps) ->
+ check_notifications(Symbolic, Traps).
+
+check_notifications(true, Traps) ->
+ check_notifications(Traps);
+check_notifications(_, _) -> true.
+
+check_notifications([]) -> true;
+check_notifications([#trap{trapname = Key} = Trap | Traps]) ->
+ ?vtrace("check notification [trap] with Key: ~p",[Key]),
+ case snmpa_symbolic_store:get_notification(Key) of
+ {value, Trap} -> check_notifications(Traps);
+ {value, _} -> throw({error, {'trap already defined', Key}});
+ undefined -> check_notifications(Traps)
+ end;
+check_notifications([#notification{trapname = Key} = Notif | Traps]) ->
+ ?vtrace("check notification [notification] with Key: ~p",[Key]),
+ case snmpa_symbolic_store:get_notification(Key) of
+ {value, Notif} ->
+ check_notifications(Traps);
+ {value, _} ->
+ throw({error, {'notification already defined', Key}});
+ undefined ->
+ check_notifications(Traps)
+ end;
+check_notifications([Crap | Traps]) ->
+ ?vlog("skipped check of: ~n~p",[Crap]),
+ check_notifications(Traps).
+
+check_mes(true,_) ->
+ ?vtrace("mibentry override = true => skip check",[]),
+ true;
+check_mes(_,MEs) ->
+ check_mes(MEs).
+
+check_mes([]) -> true;
+check_mes([#me{aliasname = Name, oid = Oid1} | MEs]) ->
+ ?vtrace("check mib entries with aliasname: ~p",[Name]),
+ case snmpa_symbolic_store:aliasname_to_oid(Name) of
+ {value, Oid1} ->
+ check_mes(MEs);
+ {value, Oid2} ->
+ ?vinfo("~n expecting '~p'~n but found '~p'",[Oid1, Oid2]),
+ throw({error, {'mibentry already defined', Name}});
+ false ->
+ check_mes(MEs)
+ end;
+check_mes([Crap | MEs]) ->
+ ?vlog("skipped check of: ~n~p",[Crap]),
+ check_mes(MEs).
+
+
+
+%%----------------------------------------------------------------------
+%% Returns: new mib data | {error, Reason}
+%%----------------------------------------------------------------------
+unload_mib(MibData, FileName, _, _) when is_list(FileName) ->
+ MibName = list_to_atom(filename:basename(FileName, ".bin")),
+ (catch do_unload_mib(MibData, MibName)).
+
+do_unload_mib(MibData, MibName) ->
+ ?vtrace("do_unload_mib -> entry with"
+ "~n MibName: ~p", [MibName]),
+ #mib_data{mib_db = MibDb,
+ node_db = NodeDb,
+ %% tree_db = TreeDb,
+ tree = Tree} = MibData,
+ #mib_info{symbolic = Symbolic} = verify_loaded(MibDb, MibName),
+ NewRoot = delete_mib_from_tree(MibName, Tree#tree.root),
+ MEs = uninstall_mes(NodeDb, MibName),
+ uninstall_mib(MibDb, Symbolic, MibName, MEs),
+ NewMibData = MibData#mib_data{tree = Tree#tree{root = NewRoot}},
+ {ok, NewMibData}.
+
+verify_loaded(Db, Name) ->
+ case snmpa_general_db:read(Db, Name) of
+ {value, MibInfo} ->
+ MibInfo;
+ false ->
+ throw({error, 'not loaded'})
+ end.
+
+
+close(#mib_data{mib_db = MibDb, node_db = NodeDb, tree_db = TreeDb}) ->
+ snmpa_general_db:close(MibDb),
+ snmpa_general_db:close(NodeDb),
+ snmpa_general_db:close(TreeDb),
+ ok.
+
+register_subagent(#mib_data{tree = T} = MibData, Oid, Pid) ->
+ case insert_subagent(Oid, T#tree.root) of
+ {error, Reason} ->
+ {error, Reason};
+ NewRootTree ->
+ SAs = [{Pid, Oid} | MibData#mib_data.subagents],
+ T2 = T#tree{root = NewRootTree},
+ MibData#mib_data{tree = T2, subagents = SAs}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Purpose: Get a list of all loaded mibs
+%% Returns: [{Name, File}]
+%%----------------------------------------------------------------------
+
+which_mibs(#mib_data{mib_db = Db}) ->
+ Mibs = snmpa_general_db:tab2list(Db),
+ [{Name, File} || #mib_info{name = Name, file_name = File} <- Mibs].
+
+
+%%----------------------------------------------------------------------
+%% Purpose: Get a list of all loaded mibs
+%% Returns: [{Name, File}]
+%%----------------------------------------------------------------------
+
+whereis_mib(#mib_data{mib_db = Db}, Name) ->
+ case snmpa_general_db:read(Db, Name) of
+ {value, #mib_info{file_name = File}} ->
+ {ok, File};
+ false ->
+ {error, not_found}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Purpose: Deletes SA with Pid from all subtrees it handles.
+%% Returns: NewMibData.
+%%----------------------------------------------------------------------
+unregister_subagent(MibData, Pid) when is_pid(Pid) ->
+ SAs = MibData#mib_data.subagents,
+ case lists:keysearch(Pid, 1, SAs) of
+ false -> MibData;
+ {value, {Pid, Oid}} ->
+ % we should never get an error since Oid is found in MibData.
+ {ok, NewMibData, _DeletedSA} = unregister_subagent(MibData, Oid),
+ % continue if the same Pid handles other mib subtrees.
+ unregister_subagent(NewMibData, Pid)
+ end;
+
+%%----------------------------------------------------------------------
+%% Purpose: Deletes one unique subagent.
+%% Returns: {error, Reason} | {ok, NewMibData, DeletedSubagentPid}
+%%----------------------------------------------------------------------
+unregister_subagent(#mib_data{tree = T} = MibData, Oid) when is_list(Oid) ->
+ case catch delete_subagent(T#tree.root, Oid) of
+ {tree, Tree, Info} ->
+ OldSAs = MibData#mib_data.subagents,
+ {value, {Pid, _Oid}} = lists:keysearch(Oid, 2, OldSAs),
+ SAs = lists:keydelete(Oid, 2, OldSAs),
+ T2 = T#tree{root = {tree, Tree, Info}},
+ {ok,
+ MibData#mib_data{tree = T2, subagents = SAs},
+ Pid};
+ _ ->
+ {error, {'invalid oid', Oid}}
+ end.
+
+%%----------------------------------------------------------------------
+%% Purpose: To inpect memory usage, loaded mibs, registered subagents
+%%----------------------------------------------------------------------
+info(MibData) ->
+ ?vtrace("retrieve info",[]),
+ #mib_data{mib_db = MibDb, node_db = NodeDb, tree_db = TreeDb,
+ tree = Tree, subagents = SAs} = MibData,
+ LoadedMibs = old_format(snmpa_general_db:tab2list(MibDb)),
+ TreeSize = snmp_misc:mem_size(Tree),
+ {memory, ProcSize} = erlang:process_info(self(),memory),
+ MibDbSize = snmpa_general_db:info(MibDb, memory),
+ NodeDbSize = snmpa_general_db:info(NodeDb, memory),
+ TreeDbSize = snmpa_general_db:info(TreeDb, memory),
+ [{loaded_mibs, LoadedMibs}, {subagents, SAs}, {tree_size_bytes, TreeSize},
+ {process_memory, ProcSize},
+ {db_memory, [{mib,MibDbSize},{node,NodeDbSize},{tree,TreeDbSize}]}].
+
+info(#mib_data{mib_db = MibDb}, loaded_mibs) ->
+ Mibs = snmpa_general_db:tab2list(MibDb),
+ [filename:rootname(FN, ".bin") || #mib_info{file_name = FN} <- Mibs];
+info(#mib_data{tree = Tree}, tree_size_bytes) ->
+ snmp_misc:mem_size(Tree);
+info(_, process_memory) ->
+ {memory, ProcSize} = erlang:process_info(self(),memory),
+ ProcSize;
+info(#mib_data{mib_db = MibDb, node_db = NodeDb, tree_db = TreeDb},
+ db_memory) ->
+ MibDbSize = snmpa_general_db:info(MibDb, memory),
+ NodeDbSize = snmpa_general_db:info(NodeDb, memory),
+ TreeDbSize = snmpa_general_db:info(TreeDb, memory),
+ [{mib,MibDbSize},{node,NodeDbSize},{tree,TreeDbSize}];
+info(#mib_data{subagents = SAs}, subagents) ->
+ SAs.
+
+old_format(LoadedMibs) ->
+ ?vtrace("convert mib info to old format",[]),
+ [{N,S,F} || #mib_info{name=N,symbolic=S,file_name=F} <- LoadedMibs].
+
+
+%%----------------------------------------------------------------------
+%% A total dump for debugging.
+%%----------------------------------------------------------------------
+dump(#mib_data{mib_db = MibDb, node_db = NodeDb, tree = Tree}) ->
+ (catch io:format("MIB-tables:~n~p~n~n",
+ [snmpa_general_db:tab2list(MibDb)])),
+ (catch io:format("MIB-entries:~n~p~n~n",
+ [snmpa_general_db:tab2list(NodeDb)])),
+ (catch io:format("Tree:~n~p~n", [Tree])), % good luck reading it!
+ ok.
+
+dump(#mib_data{mib_db = MibDb, node_db = NodeDb, tree = Tree}, File) ->
+ case file:open(File,[write]) of
+ {ok, Fd} ->
+ io:format(Fd,"~s~n",
+ [snmp:date_and_time_to_string(snmp:date_and_time())]),
+ (catch io:format(Fd,"MIB-tables:~n~p~n~n",
+ [snmpa_general_db:tab2list(MibDb)])),
+ (catch io:format(Fd, "MIB-entries:~n~p~n~n",
+ [snmpa_general_db:tab2list(NodeDb)])),
+ io:format(Fd,"Tree:~n~p~n", [Tree]), % good luck reading it!
+ file:close(Fd),
+ ok;
+ {error,Reason} ->
+ ?vinfo("~n Failed opening file '~s' for reason ~p",
+ [File,Reason]),
+ {error,Reason}
+ end.
+
+
+backup(#mib_data{mib_db = M, node_db = N, tree_db = T}, BackupDir) ->
+ MRes = snmpa_general_db:backup(M, BackupDir),
+ NRes = snmpa_general_db:backup(N, BackupDir),
+ TRes = snmpa_general_db:backup(T, BackupDir),
+ handle_backup_res([{mib_db, MRes}, {node_db, NRes}, {tree_db, TRes}]).
+
+handle_backup_res(Res) ->
+ handle_backup_res(Res, []).
+
+handle_backup_res([], []) ->
+ ok;
+handle_backup_res([], Err) ->
+ {error, lists:reverse(Err)};
+handle_backup_res([{_, ok}|Res], Err) ->
+ handle_backup_res(Res, Err);
+handle_backup_res([{Tag, {error, Reason}}|Res], Err) ->
+ handle_backup_res(Res, [{Tag, Reason}|Err]);
+handle_backup_res([{Tag, Error}|Res], Err) ->
+ handle_backup_res(Res, [{Tag, Error}|Err]).
+
+
+%%%======================================================================
+%%% 2. Implementation of tree access
+%%% lookup and next.
+%%%======================================================================
+
+
+which_mib(#mib_data{tree = T} = D, Oid) ->
+ ?vtrace("which_mib -> entry with"
+ "~n Oid: ~p",[Oid]),
+ case (catch find_node(D, T#tree.root, Oid, [])) of
+ {variable, _ME, Mib} ->
+ ?vtrace("which_mib -> variable:"
+ "~n Mib: ~p", [Mib]),
+ {ok, Mib};
+ {table, _EntryME, _, Mib} ->
+ ?vtrace("which_mib -> table:"
+ "~n Mib: ~p", [Mib]),
+ {ok, Mib};
+ {subagent, SubAgentPid, _SANextOid} ->
+ ?vtrace("which_mib -> subagent:"
+ "~n SubAgentPid: ~p", [SubAgentPid]),
+ {error, {subagent, SubAgentPid}};
+ {false, ErrorCode} ->
+ ?vtrace("which_mib -> false:"
+ "~n ErrorCode: ~p",[ErrorCode]),
+ {error, ErrorCode};
+ false ->
+ ?vtrace("which_mib -> false",[]),
+ {error, noSuchObject};
+ {'EXIT', R} ->
+ ?vtrace("which_mib -> exit:"
+ "~n R: ~p",[R]),
+ {error, noSuchObject}
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: lookup/2
+%% Purpose: Finds the mib entry corresponding to the Oid. If it is a
+%% variable, the Oid must be <Oid for var>.0 and if it is
+%% a table, Oid must be <table>.<entry>.<col>.<any>
+%% Returns: {variable, MibEntry} |
+%% {table_column, MibEntry, TableEntryOid} |
+%% {subagent, SubAgentPid, SAOid} |
+%% {false, Reason}
+%%-----------------------------------------------------------------
+lookup(#mib_data{tree = T} = D, Oid) ->
+ ?vtrace("lookup -> entry with"
+ "~n Oid: ~p",[Oid]),
+ case (catch find_node(D, T#tree.root, Oid, [])) of
+ {variable, ME, _Mib} when is_record(ME, me) ->
+ ?vtrace("lookup -> variable:"
+ "~n ME: ~p",[ME]),
+ {variable, ME};
+ {table, EntryME, {ColME, TableEntryOid}, _Mib} ->
+ ?vtrace("lookup -> table:"
+ "~n EntryME: ~p"
+ "~n ColME: ~p"
+ "~n RevTableEntryOid: ~p",
+ [EntryME, ColME, TableEntryOid]),
+ MFA = EntryME#me.mfa,
+ RetME = ColME#me{mfa = MFA},
+ {table_column, RetME, TableEntryOid};
+ {subagent, SubAgentPid, SANextOid} ->
+ ?vtrace("lookup -> subagent:"
+ "~n SubAgentPid: ~p"
+ "~n SANextOid: ~p", [SubAgentPid, SANextOid]),
+ {subagent, SubAgentPid, SANextOid};
+ {false, ErrorCode} ->
+ ?vtrace("lookup -> false:"
+ "~n ErrorCode: ~p",[ErrorCode]),
+ {false, ErrorCode};
+ false ->
+ ?vtrace("lookup -> false",[]),
+ {false, noSuchObject};
+ {'EXIT', R} ->
+ ?vtrace("lookup -> exit:"
+ "~n R: ~p",[R]),
+ {false, noSuchObject}
+ end.
+
+
+find_node(D, {tree, Tree, {table, _}}, RestOfOid, RevOid) ->
+ ?vtrace("find_node(tree,table) -> entry with"
+ "~n RestOfOid: ~p"
+ "~n RevOid: ~p",[RestOfOid, RevOid]),
+ find_node(D, {tree, Tree, internal}, RestOfOid, RevOid);
+find_node(D, {tree, Tree, {table_entry, _}}, RestOfOid, RevOid) ->
+ ?vtrace("find_node(tree,table_entry) -> entry with"
+ "~n RestOfOid: ~p"
+ "~n RevOid: ~p",[RestOfOid, RevOid]),
+ #mib_data{node_db = Db} = D,
+ Oid = lists:reverse(RevOid),
+ case snmpa_general_db:read(Db, Oid) of
+ {value, #node_info{me = ME, mib_name = Mib}} ->
+ case find_node(D, {tree, Tree, internal}, RestOfOid, RevOid) of
+ {false, ErrorCode} -> {false, ErrorCode};
+ Val -> {table, ME, Val, Mib}
+ end;
+ false ->
+ ?vinfo("find_node -> could not find table_entry ME with"
+ "~n RevOid: ~p"
+ "~n when"
+ "~n RestOfOid: ~p",
+ [RevOid, RestOfOid]),
+ false
+ end;
+find_node(D, {tree, Tree, _Internal}, [Int | RestOfOid], RevOid) ->
+ ?vtrace("find_node(tree) -> entry with"
+ "~n Int: ~p"
+ "~n RestOfOid: ~p"
+ "~n RevOid: ~p",[Int, RestOfOid, RevOid]),
+ find_node(D, element(Int+1, Tree), RestOfOid, [Int | RevOid]);
+find_node(D, {node, {table_column, _}}, RestOfOid, [ColInt | RevOid]) ->
+ ?vtrace("find_node(tree,table_column) -> entry with"
+ "~n RestOfOid: ~p"
+ "~n ColInt: ~p"
+ "~n RevOid: ~p",[RestOfOid, ColInt, RevOid]),
+ #mib_data{node_db = Db} = D,
+ Oid = lists:reverse([ColInt | RevOid]),
+ case snmpa_general_db:read(Db, Oid) of
+ {value, #node_info{me = ME}} ->
+ {ME, lists:reverse(RevOid)};
+ false ->
+ X = snmpa_general_db:read(Db, lists:reverse([ColInt | RevOid])),
+ ?vinfo("find_node -> could not find table_column ME with"
+ "~n RevOid: ~p"
+ "~n trying [~p|~p]"
+ "~n X: ~p",
+ [RevOid, [ColInt | RevOid], X]),
+ false
+ end;
+find_node(D, {node, {variable, _MibName}}, [0], RevOid) ->
+ ?vtrace("find_node(tree,variable,[0]) -> entry with"
+ "~n RevOid: ~p",[RevOid]),
+ #mib_data{node_db = Db} = D,
+ Oid = lists:reverse(RevOid),
+ %% {value, #node_info{me = ME}} = snmpa_general_db:read(Db, Oid),
+ case snmpa_general_db:read(Db, Oid) of
+ {value, #node_info{me = ME, mib_name = Mib}} ->
+ {variable, ME, Mib};
+ false ->
+ ?vinfo("find_node -> could not find variable ME with"
+ "~n RevOid: ~p", [RevOid]),
+ false
+ end;
+find_node(_D, {node, {variable, _MibName}}, [], _RevOid) ->
+ ?vtrace("find_node(tree,variable,[]) -> entry",[]),
+ {false, noSuchObject};
+find_node(_D, {node, {variable, _MibName}}, _, _RevOid) ->
+ ?vtrace("find_node(tree,variable) -> entry",[]),
+ {false, noSuchInstance};
+find_node(D, {node, subagent}, _RestOfOid, SARevOid) ->
+ ?vtrace("find_node(tree,subagent) -> entry with"
+ "~n SARevOid: ~p",[SARevOid]),
+ #mib_data{subagents = SAs} = D,
+ SAOid = lists:reverse(SARevOid),
+ case lists:keysearch(SAOid, 2, SAs) of
+ {value, {SubAgentPid, SAOid}} ->
+ {subagent, SubAgentPid, SAOid};
+ false ->
+ ?vinfo("find_node -> could not find subagent with"
+ "~n SAOid: ~p"
+ "~n SAs: ~p", [SAOid, SAs]),
+ false
+ end;
+find_node(_D, Node, _RestOfOid, _RevOid) ->
+ ?vtrace("find_node -> failed:~n~p",[Node]),
+ {false, noSuchObject}.
+
+
+%%-----------------------------------------------------------------
+%% Func: next/3
+%% Purpose: Finds the lexicographically next oid.
+%% Returns: endOfMibView |
+%% {subagent, SubAgentPid, SAOid} |
+%% {variable, MibEntry, VarOid} |
+%% {table, TableOid, TableRestOid, MibEntry}
+%% If a variable is returnes, it is in the MibView.
+%% If a table or subagent is returned, it *may* be in the MibView.
+%%-----------------------------------------------------------------
+next(#mib_data{tree = T} = D, Oid, MibView) ->
+ case catch next_node(D, T#tree.root, Oid, [], MibView) of
+ false -> endOfMibView;
+ Else -> Else
+ end.
+
+%%-----------------------------------------------------------------
+%% This function is used as long as we have any Oid left. Take
+%% one integer at a time from the Oid, and traverse the tree
+%% accordingly. When the Oid is empty, call find_next.
+%% Returns: {subagent, SubAgentPid, SAOid} |
+%% false |
+%% {variable, MibEntry, VarOid} |
+%% {table, TableOid, TableRestOid, MibEntry}
+%%-----------------------------------------------------------------
+next_node(_D, undefined_node, _Oid, _RevOidSoFar, _MibView) ->
+ ?vtrace("next_node(undefined_node) -> entry", []),
+ false;
+
+next_node(_D, {tree, Tree, {table_entry, _Id}}, [Int | _Oid],
+ _RevOidSoFar, _MibView)
+ when Int+1 > size(Tree) ->
+ ?vtrace("next_node(tree,table_entry) -> entry when not found whith"
+ "~n Int: ~p"
+ "~n size(Tree): ~p", [Int, size(Tree)]),
+ false;
+next_node(D, {tree, Tree, {table_entry, _MibName}},
+ Oid, RevOidSoFar, MibView) ->
+ ?vtrace("next_node(tree,table_entry) -> entry when"
+ "~n size(Tree): ~p"
+ "~n Oid: ~p"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p", [size(Tree), Oid, RevOidSoFar, MibView]),
+ OidSoFar = lists:reverse(RevOidSoFar),
+ case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
+ true ->
+ ?vdebug("next_node(tree,table_entry) -> not in mib view",[]),
+ false;
+ _ ->
+ #mib_data{node_db = Db} = D,
+ case snmpa_general_db:read(Db, OidSoFar) of
+ false ->
+ ?vinfo("next_node -> could not find table_entry with"
+ "~n OidSoFar: ~p", [OidSoFar]),
+ false;
+ {value, #node_info{me = ME}} ->
+ ?vtrace("next_node(tree,table_entry) -> found: ~n ~p",
+ [ME]),
+ {table, OidSoFar, Oid, ME}
+ end
+ end;
+
+next_node(D, {tree, Tree, _Info}, [Int | RestOfOid], RevOidSoFar, MibView)
+ when (Int < size(Tree)) andalso (Int >= 0) ->
+ ?vtrace("next_node(tree) -> entry when"
+ "~n size(Tree): ~p"
+ "~n Int: ~p"
+ "~n RestOfOid: ~p"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p",
+ [size(Tree), Int, RestOfOid, RevOidSoFar, MibView]),
+ case next_node(D, element(Int+1,Tree),
+ RestOfOid, [Int|RevOidSoFar], MibView) of
+ false ->
+ find_next(D, {tree, Tree, _Info}, Int+1, RevOidSoFar, MibView);
+ Else ->
+ Else
+ end;
+%% no solution
+next_node(D, {tree, Tree, _Info}, [], RevOidSoFar, MibView) ->
+ ?vtrace("next_node(tree,[]) -> entry when"
+ "~n size(Tree): ~p"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p",
+ [size(Tree), RevOidSoFar, MibView]),
+ find_next(D, {tree, Tree, _Info}, 0, RevOidSoFar, MibView);
+next_node(_D, {tree, Tree, _Info}, _RestOfOid, _RevOidSoFar, _MibView) ->
+ ?vtrace("next_node(tree) -> entry when"
+ "~n size(Tree): ~p", [size(Tree)]),
+ false;
+
+next_node(D, {node, subagent}, Oid, RevOidSoFar, MibView) ->
+ ?vtrace("next_node(node,subagent) -> entry when"
+ "~n Oid: ~p"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p",
+ [Oid, RevOidSoFar, MibView]),
+ OidSoFar = lists:reverse(RevOidSoFar),
+ case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
+ true ->
+ false;
+ _ ->
+ #mib_data{subagents = SAs} = D,
+ case lists:keysearch(OidSoFar, 2, SAs) of
+ {value, {SubAgentPid, OidSoFar}} ->
+ {subagent, SubAgentPid, OidSoFar};
+ _ ->
+ ?vinfo("next_node -> could not find subagent with"
+ "~n OidSoFar: ~p"
+ "~n SAs: ~p", [OidSoFar, SAs]),
+ false
+ end
+ end;
+
+next_node(D, {node, {variable, _MibName}}, [], RevOidSoFar, MibView) ->
+ ?vtrace("next_node(node,variable,[]) -> entry when"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p",
+ [RevOidSoFar, MibView]),
+ OidSoFar = lists:reverse([0 | RevOidSoFar]),
+ case snmpa_acm:validate_mib_view(OidSoFar, MibView) of
+ true ->
+ #mib_data{node_db = Db} = D,
+ case snmpa_general_db:read(Db, lists:reverse(RevOidSoFar)) of
+ false ->
+ ?vinfo("next_node -> could not find variable with"
+ "~n RevOidSoFar: ~p", [RevOidSoFar]),
+ false;
+ {value, #node_info{me = ME}} ->
+ {variable, ME, OidSoFar}
+ end;
+ _ ->
+ false
+ end;
+
+next_node(_D, {node, {variable, _MibName}}, _Oid, _RevOidSoFar, _MibView) ->
+ ?vtrace("next_node(node,variable) -> entry", []),
+ false.
+
+%%-----------------------------------------------------------------
+%% This function is used to find the first leaf from where we
+%% are.
+%% Returns: {subagent, SubAgentPid, SAOid} |
+%% false |
+%% {variable, MibEntry, VarOid} |
+%% {table, TableOid, TableRestOid, MibEntry}
+%% PRE: This function must always be called with a {internal, Tree}
+%% node.
+%%-----------------------------------------------------------------
+find_next(D, {tree, Tree, internal}, Idx, RevOidSoFar, MibView)
+ when Idx < size(Tree) ->
+ case find_next(D, element(Idx+1, Tree), 0, [Idx| RevOidSoFar], MibView) of
+ false ->
+ find_next(D, {tree, Tree, internal}, Idx+1, RevOidSoFar, MibView);
+ Other ->
+ Other
+ end;
+find_next(_D, {tree, _Tree, internal}, _Idx, _RevOidSoFar, _MibView) ->
+ false;
+find_next(_D, undefined_node, _Idx, _RevOidSoFar, _MibView) ->
+ false;
+find_next(D, {tree, Tree, {table, _MibName}}, Idx, RevOidSoFar, MibView) ->
+ find_next(D, {tree, Tree, internal}, Idx, RevOidSoFar, MibView);
+find_next(D, {tree, _Tree, {table_entry, _MibName}}, _Index,
+ RevOidSoFar, MibView) ->
+ OidSoFar = lists:reverse(RevOidSoFar),
+ case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
+ true ->
+ false;
+ _ ->
+ #mib_data{node_db = Db} = D,
+ case snmpa_general_db:read(Db, OidSoFar) of
+ false ->
+ ?vinfo("find_next -> could not find table_entry ME with"
+ "~n OidSoFar: ~p", [OidSoFar]),
+ false;
+ {value, #node_info{me = ME}} ->
+ {table, OidSoFar, [], ME}
+ end
+ end;
+find_next(D, {node, {variable, _MibName}}, _Idx, RevOidSoFar, MibView) ->
+ OidSoFar = lists:reverse([0 | RevOidSoFar]),
+ case snmpa_acm:validate_mib_view(OidSoFar, MibView) of
+ true ->
+ #mib_data{node_db = Db} = D,
+ case snmpa_general_db:read(Db, lists:reverse(RevOidSoFar)) of
+ false ->
+ ?vinfo("find_next -> could not find variable with"
+ "~n RevOidSoFar: ~p", [RevOidSoFar]),
+ false;
+ {value, #node_info{me = ME}} ->
+ {variable, ME, OidSoFar}
+ end;
+ _ ->
+ false
+ end;
+find_next(D, {node, subagent}, _Idx, RevOidSoFar, MibView) ->
+ OidSoFar = lists:reverse(RevOidSoFar),
+ case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
+ true ->
+ false;
+ _ ->
+ #mib_data{subagents = SAs} = D,
+ case lists:keysearch(OidSoFar, 2, SAs) of
+ {value, {SubAgentPid, OidSoFar}} ->
+ {subagent, SubAgentPid, OidSoFar};
+ false ->
+ ?vinfo("find_node -> could not find subagent with"
+ "~n OidSoFar: ~p"
+ "~n SAs: ~p", [OidSoFar, SAs]),
+ false
+ end
+ end.
+
+%%%======================================================================
+%%% 3. Tree building functions
+%%% Used when loading mibs.
+%%%======================================================================
+
+build_tree(Mes, MibName) ->
+ ?d("build_tree -> "
+ "~n Mes: ~p", [Mes]),
+ {ListTree, []} = build_subtree([], Mes, MibName),
+ {tree, convert_tree(ListTree), internal}.
+
+%%----------------------------------------------------------------------
+%% Purpose: Builds the tree where all oids have prefix equal to LevelPrefix.
+%% Returns: {Tree, RestMes}
+%% RestMes are Mes that should not be in this subtree.
+%% The Tree is a temporary and simplified data structure that is easy to
+%% convert to the final tuple tree used by the MIB process.
+%% A Node is represented as in the final tree.
+%% The tree is not represented as a N-tuple, but as an Index-list.
+%% Example: Temporary: [{1, Node1}, {3, Node3}]
+%% Final: {Node1, undefined_node, Node3}
+%% Pre: Mes are sorted on oid.
+%%----------------------------------------------------------------------
+build_subtree(LevelPrefix, [Me | Mes], MibName) ->
+ ?vtrace("build subtree -> ~n"
+ " oid: ~p~n"
+ " LevelPrefix: ~p~n"
+ " MibName: ~p", [Me#me.oid, LevelPrefix, MibName]),
+ EType = Me#me.entrytype,
+ ?vtrace("build subtree -> EType = ~p",[EType]),
+ case in_subtree(LevelPrefix, Me) of
+ above ->
+ ?vtrace("build subtree -> above",[]),
+ {[], [Me|Mes]};
+ {node, Index} ->
+ ?vtrace("build subtree -> node at ~p",[Index]),
+ {Tree, RestMes} = build_subtree(LevelPrefix, Mes, MibName),
+ {[{Index, {node, {EType, MibName}}} | Tree], RestMes};
+ {subtree, Index, NewLevelPrefix} ->
+ ?vtrace("build subtree -> subtree at"
+ "~n ~w with ~w",
+ [Index, NewLevelPrefix]),
+ {BelowTree, RestMes} =
+ build_subtree(NewLevelPrefix, Mes, MibName),
+ {CurTree, RestMes2} =
+ build_subtree(LevelPrefix, RestMes, MibName),
+ {[{Index, {tree, BelowTree, {EType,MibName}}}| CurTree], RestMes2};
+ {internal_subtree, Index, NewLevelPrefix} ->
+ ?vtrace("build subtree -> internal_subtree at"
+ "~n ~w with ~w",
+ [Index,NewLevelPrefix]),
+ {BelowTree, RestMes} =
+ build_subtree(NewLevelPrefix, [Me | Mes], MibName),
+ {CurTree, RestMes2} =
+ build_subtree(LevelPrefix, RestMes, MibName),
+ {[{Index, {tree, BelowTree, internal}} | CurTree], RestMes2}
+ end;
+
+build_subtree(_LevelPrefix, [], _MibName) ->
+ ?vtrace("build subtree -> done", []),
+ {[], []}.
+
+%%--------------------------------------------------
+%% Purpose: Determine how/if/where Me should be inserted in subtree
+%% with LevelPrefix. This function does not build any tree, only
+%% determinses what should be done (by build subtree).
+%% Returns:
+%% above - Indicating that this ME should _not_ be in this subtree.
+%% {node, Index} - yes, construct a node with index Index on this level
+%% {internal_subtree, Index, NewLevelPrefix} - yes, there should be an
+%% internal subtree at this index.
+%% {subtree, Index, NewLevelPrefix} - yes, construct a subtree with
+%% NewLevelPrefix and insert this on current level in position Index.
+%%--------------------------------------------------
+in_subtree(LevelPrefix, Me) ->
+ case lists:prefix(LevelPrefix, Me#me.oid) of
+ true when length(Me#me.oid) > length(LevelPrefix) ->
+ classify_how_in_subtree(LevelPrefix, Me);
+ _ ->
+ above
+ end.
+
+%%--------------------------------------------------
+%% See comment about in_subtree/2. This function takes care of all cases
+%% where the ME really should be in _this_ subtree (not above).
+%%--------------------------------------------------
+classify_how_in_subtree(LevelPrefix, Me)
+ when (length(Me#me.oid) =:= (length(LevelPrefix) + 1)) ->
+ Oid = Me#me.oid,
+ case node_or_subtree(Me#me.entrytype) of
+ subtree ->
+ {subtree, lists:last(Oid), Oid};
+ node ->
+ {node, lists:last(Oid)}
+ end;
+
+classify_how_in_subtree(LevelPrefix, Me)
+ when (length(Me#me.oid) > (length(LevelPrefix) + 1)) ->
+ L1 = length(LevelPrefix) + 1,
+ Oid = Me#me.oid,
+ {internal_subtree, lists:nth(L1, Oid), lists:sublist(Oid, 1, L1)}.
+
+%%--------------------------------------------------
+%% Determines how to treat different kinds om MEs in the tree building process.
+%% Pre: all internal nodes have been removed.
+%%--------------------------------------------------
+node_or_subtree(table) -> subtree;
+node_or_subtree(table_entry) -> subtree;
+node_or_subtree(variable) -> node;
+node_or_subtree(table_column) -> node.
+
+%%--------------------------------------------------
+%% Purpose: (Recursively) Converts a temporary tree (see above) to a final tree.
+%% If input is a ListTree, output is a TupleTree.
+%% If input is a Node, output is the same Node.
+%% Pre: All Indexes are >= 0.
+%%--------------------------------------------------
+convert_tree({Index, {tree, Tree, Info}}) when Index >= 0 ->
+ L = lists:map(fun convert_tree/1, Tree),
+ {Index, {tree, dict_list_to_tuple(L), Info}};
+convert_tree({Index, {node, Info}}) when Index >= 0 ->
+ {Index, {node, Info}};
+convert_tree(Tree) when is_list(Tree) ->
+ L = lists:map(fun convert_tree/1, Tree),
+ dict_list_to_tuple(L).
+
+%%----------------------------------------------------------------------
+%% Purpose: Converts a single level (that is non-recursively) from
+%% the temporary indexlist to the N-tuple.
+%% Input: A list of {Index, Data}.
+%% Output: A tuple where element Index is Data.
+%%----------------------------------------------------------------------
+dict_list_to_tuple(L) ->
+ L2 = lists:keysort(1, L),
+ list_to_tuple(integrate_indexes(0, L2)).
+
+%%----------------------------------------------------------------------
+%% Purpose: Helper function for dict_list_to_tuple/1.
+%% Converts an indexlist to a N-list.
+%% Input: A list of {Index, Data}.
+%% Output: A (usually longer, never shorter) list where element Index is Data.
+%% Example: [{1,hej}, {3, sven}] will give output
+%% [undefined_node, hej, undefined_node, sven].
+%% Initially CurIndex should be 0.
+%%----------------------------------------------------------------------
+integrate_indexes(CurIndex, [{CurIndex, Data} | T]) ->
+ [Data | integrate_indexes(CurIndex + 1, T)];
+integrate_indexes(_Index, []) ->
+ [];
+integrate_indexes(CurIndex, L) ->
+ [undefined_node | integrate_indexes(CurIndex + 1, L)].
+
+%%%======================================================================
+%%% 4. Tree merging
+%%% Used by: load mib, insert subagent.
+%%%======================================================================
+
+%%----------------------------------------------------------------------
+%% Arg: Two root nodes (that is to be merged).
+%% Returns: A new root node where the nodes have been merger to one.
+%%----------------------------------------------------------------------
+merge_nodes(Same, Same) ->
+ Same;
+merge_nodes(Node, undefined_node) ->
+ Node;
+merge_nodes(undefined_node, Node) ->
+ Node;
+merge_nodes({tree, Tree1, internal}, {tree, Tree2, internal}) ->
+ {tree, merge_levels(tuple_to_list(Tree1),tuple_to_list(Tree2)), internal};
+merge_nodes(Node1, Node2) ->
+ throw({error_merge_nodes, Node1, Node2}).
+
+%%----------------------------------------------------------------------
+%% Arg: Two levels to be merged.
+%% Here, a level is represented as a list of nodes. A list is easier
+%% to extend than a tuple.
+%% Returns: The resulting, merged level tuple.
+%%----------------------------------------------------------------------
+merge_levels(Level1, Level2) when length(Level1) =:= length(Level2) ->
+ MergeNodes = fun(N1, N2) -> merge_nodes(N1, N2) end,
+ list_to_tuple(snmp_misc:multi_map(MergeNodes, [Level1, Level2]));
+merge_levels(Level1, Level2) when length(Level1) > length(Level2) ->
+ merge_levels(Level1, Level2 ++
+ undefined_nodes_list(length(Level1) - length(Level2)));
+merge_levels(Level1, Level2) when length(Level1) < length(Level2) ->
+ merge_levels(Level2, Level1).
+
+undefined_nodes_list(N) -> lists:duplicate(N, undefined_node).
+
+
+%%%======================================================================
+%%% 5. Tree deletion routines
+%%% (for unload mib)
+%%%======================================================================
+
+%%----------------------------------------------------------------------
+%% Purpose: Actually kicks of the tree reconstruction.
+%% Returns: {list of removed MEs, NewTree}
+%%----------------------------------------------------------------------
+delete_mib_from_tree(MibName, {tree, Tree, internal}) ->
+ case delete_tree(Tree, MibName) of
+ [] ->
+ {tree, {undefined_node}, internal}; % reduce
+ LevelList ->
+ {tree, list_to_tuple(LevelList), internal}
+ end.
+
+%%----------------------------------------------------------------------
+%% Purpose: Deletes all nodes associated to MibName from this level and
+%% all levels below.
+%% If the new level does not contain information (that is, no
+%% other mibs use it) anymore the empty list is returned.
+%% Returns: {MEs, The new level represented as a list}
+%%----------------------------------------------------------------------
+delete_tree(Tree, MibName) when is_tuple(Tree) ->
+ NewLevel = delete_nodes(tuple_to_list(Tree), MibName, []),
+ case lists:filter(fun drop_undefined_nodes/1,NewLevel) of
+ [] -> [];
+ _A_perhaps_shorted_list ->
+ NewLevel % some other mib needs this level
+ end.
+
+%%----------------------------------------------------------------------
+%% Purpose: Nodes belonging to MibName are removed from the tree.
+%% Recursively deletes sub trees to this node.
+%% Returns: {MEs, NewNodesList}
+%%----------------------------------------------------------------------
+delete_nodes([], _MibName, AccNodes) ->
+ lists:reverse(AccNodes);
+
+delete_nodes([{node, {variable, MibName}}|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+
+delete_nodes([{node, {table_column, MibName}}|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+
+delete_nodes([{tree, _Tree, {table, MibName}}|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+
+delete_nodes([{tree, _Tree, {table_entry, MibName}}|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+
+delete_nodes([{tree, Tree, Info}|T], MibName, AccNodes) ->
+ case delete_tree(Tree, MibName) of
+ [] -> % tree completely deleted
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+ LevelList ->
+ delete_nodes(T, MibName,
+ [{tree, list_to_tuple(LevelList), Info} | AccNodes])
+ end;
+
+delete_nodes([NodeToKeep|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [NodeToKeep | AccNodes]).
+
+drop_undefined_nodes(undefined_node) -> false;
+drop_undefined_nodes(_) -> true.
+
+
+%%%======================================================================
+%%% 6. Functions for subagent handling
+%%%======================================================================
+
+%%----------------------------------------------------------------------
+%% Returns: A new Root|{error, reason}
+%%----------------------------------------------------------------------
+insert_subagent(Oid, OldRoot) ->
+ ListTree = build_tree_for_subagent(Oid),
+ case catch convert_tree(ListTree) of
+ {'EXIT', _Reason} ->
+ {error, 'cannot construct tree from oid'};
+ Level when is_tuple(Level) ->
+ T = {tree, Level, internal},
+ case catch merge_nodes(T, OldRoot) of
+ {error_merge_nodes, _Node1, _Node2} ->
+ {error, oid_conflict};
+ NewRoot when is_tuple(NewRoot) andalso
+ (element(1, NewRoot) =:= tree) ->
+ NewRoot
+ end
+ end.
+
+build_tree_for_subagent([Index]) ->
+ [{Index, {node, subagent}}];
+
+build_tree_for_subagent([Index | T]) ->
+ [{Index, {tree, build_tree_for_subagent(T), internal}}].
+
+%%----------------------------------------------------------------------
+%% Returns: A new tree where the subagent at Oid (2nd arg) has been deleted.
+%%----------------------------------------------------------------------
+delete_subagent({tree, Tree, Info}, [Index]) ->
+ {node, subagent} = element(Index+1, Tree),
+ {tree, setelement(Index+1, Tree, undefined_node), Info};
+delete_subagent({tree, Tree, Info}, [Index | TI]) ->
+ {tree, setelement(Index+1, Tree,
+ delete_subagent(element(Index+1, Tree), TI)), Info}.
+
+%%%======================================================================
+%%% 7. Misc functions
+%%%======================================================================
+
+%%----------------------------------------------------------------------
+%% Installs the mibs found in the database when starting the agent.
+%% Basically calls the instrumentation functions for all non-internal
+%% mib-entries
+%%----------------------------------------------------------------------
+install_mibs(MibDb, NodeDb) ->
+ MibNames = loaded(MibDb),
+ ?vtrace("install_mibs -> found following mibs in database: ~n"
+ "~p", [MibNames]),
+ install_mibs2(NodeDb, MibNames).
+
+install_mibs2(_, []) ->
+ ok;
+install_mibs2(NodeDb, [MibName|MibNames]) ->
+ Pattern = #node_info{oid = '_', mib_name = MibName, me = '_'},
+ Nodes = snmpa_general_db:match_object(NodeDb, Pattern),
+ MEs = [ME || #node_info{me = ME} <- Nodes],
+ ?vtrace("install_mibs2 -> installing ~p MEs for mib ~p",
+ [length(MEs),MibName]),
+ NewF = fun(ME) -> call_instrumentation(ME, new) end,
+ lists:foreach(NewF, MEs),
+ install_mibs2(NodeDb, MibNames).
+
+
+%%----------------------------------------------------------------------
+%% Does all side effect stuff during load_mib.
+%%----------------------------------------------------------------------
+install_mib(Db, Symbolic, Mib, MibName, FileName, NonInternalMes) ->
+ ?vdebug("install_mib -> entry with"
+ "~n Symbolic: ~p"
+ "~n MibName: ~p"
+ "~n FileName: ~p", [Symbolic, MibName, FileName]),
+ Rec = #mib_info{name = MibName, symbolic = Symbolic, file_name = FileName},
+ snmpa_general_db:write(Db, Rec),
+ install_mib2(Symbolic, MibName, Mib),
+ NewF = fun(ME) -> call_instrumentation(ME, new) end,
+ lists:foreach(NewF, NonInternalMes).
+
+install_mib2(true, MibName, Mib) ->
+ #mib{table_infos = TabInfos,
+ variable_infos = VarInfos,
+ mes = MEs,
+ asn1_types = ASN1Types,
+ traps = Traps} = Mib,
+ snmpa_symbolic_store:add_table_infos(MibName, TabInfos),
+ snmpa_symbolic_store:add_variable_infos(MibName, VarInfos),
+ snmpa_symbolic_store:add_aliasnames(MibName, MEs),
+ snmpa_symbolic_store:add_types(MibName, ASN1Types),
+ SetF = fun(Trap) ->
+ snmpa_symbolic_store:set_notification(Trap, MibName)
+ end,
+ lists:foreach(SetF, Traps);
+install_mib2(_, _, _) ->
+ ok.
+
+install_mes(_Db, _MibName, []) ->
+ ok;
+install_mes(Db, MibName, [ME|MEs]) ->
+ Node = #node_info{oid = ME#me.oid, mib_name = MibName, me = ME},
+ snmpa_general_db:write(Db, Node),
+ install_mes(Db, MibName, MEs).
+
+
+%%----------------------------------------------------------------------
+%% Does all side effect stuff during unload_mib.
+%%----------------------------------------------------------------------
+uninstall_mib(Db, Symbolic, MibName, MEs) ->
+ ?vtrace("uninstall_mib -> entry with"
+ "~n Db: ~p"
+ "~n Symbolic: ~p"
+ "~n MibName: ~p", [Db, Symbolic, MibName]),
+ Res = snmpa_general_db:delete(Db, MibName),
+ ?vtrace("uninstall_mib -> (mib) db delete result: ~p", [Res]),
+ uninstall_mib2(Symbolic, MibName),
+ DelF = fun(ME) -> call_instrumentation(ME, delete) end,
+ lists:foreach(DelF, MEs).
+
+uninstall_mib2(true, MibName) ->
+ snmpa_symbolic_store:delete_table_infos(MibName),
+ snmpa_symbolic_store:delete_variable_infos(MibName),
+ snmpa_symbolic_store:delete_aliasnames(MibName),
+ snmpa_symbolic_store:delete_types(MibName),
+ snmpa_symbolic_store:delete_notifications(MibName);
+uninstall_mib2(_, _) ->
+ ok.
+
+uninstall_mes(Db, MibName) ->
+ Pattern = #node_info{oid = '_', mib_name = MibName, me = '_'},
+ snmpa_general_db:match_delete(Db, Pattern).
+
+
+%%----------------------------------------------------------------------
+%% Create a list of the names of all the loaded mibs
+%%----------------------------------------------------------------------
+loaded(Db) ->
+ [N || #mib_info{name = N} <- snmpa_general_db:tab2list(Db)].
+
+
+%%----------------------------------------------------------------------
+%% Calls MFA-instrumentation with 'new' or 'delete' operation.
+%%----------------------------------------------------------------------
+call_instrumentation(#me{entrytype = variable, mfa={M,F,A}}, Operation) ->
+ ?vtrace("call instrumentation with"
+ "~n entrytype: variable"
+ "~n MFA: {~p,~p,~p}"
+ "~n Operation: ~p",
+ [M,F,A,Operation]),
+ catch apply(M, F, [Operation | A]);
+call_instrumentation(#me{entrytype = table_entry, mfa={M,F,A}}, Operation) ->
+ ?vtrace("call instrumentation with"
+ "~n entrytype: table_entry"
+ "~n MFA: {~p,~p,~p}"
+ "~n Operation: ~p",
+ [M,F,A,Operation]),
+ catch apply(M, F, [Operation | A]);
+call_instrumentation(_ShitME, _Operation) ->
+ done.
+
+
+maybe_drop_me(#me{entrytype = internal}) -> false;
+maybe_drop_me(#me{entrytype = group}) -> false;
+maybe_drop_me(#me{imported = true}) -> false;
+maybe_drop_me(_) -> true.
+
+
+%%----------------------------------------------------------------------
+%% Code change functions
+%%----------------------------------------------------------------------
+
+code_change(down, State) ->
+ ?d("code_change(down) -> entry",[]),
+ State;
+
+code_change(up, State) ->
+ ?d("code_change(up)",[]),
+ State;
+
+code_change(_Vsn, State) ->
+ State.
+
diff --git a/lib/snmp/src/agent/snmpa_mib_data_tttn.erl b/lib/snmp/src/agent/snmpa_mib_data_tttn.erl
new file mode 100644
index 0000000000..90ddf4869f
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_mib_data_tttn.erl
@@ -0,0 +1,1443 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(snmpa_mib_data_tttn).
+
+
+%%%-----------------------------------------------------------------
+%%%
+%%% TTTN - TupleTreeTupleNodes
+%%%
+%%% This module implements the MIB (internal) data structures.
+%%% The TTTN MIB Data structure consists of three items:
+%%%
+%%% 1) A mib-storage (as specified when new is called) for
+%%% the data associated with each variable, table,
+%%% table-entry and table-column in the MIB.
+%%% 2) A tree contains information of the Oids in the MIB.
+%%% 3) A list of registered subagents.
+%%%
+%%% The subagent information is consequently duplicated. It resides
+%%% both in the tree and in the list.
+%%%
+%%% When a mib is loaded, the tree is built from the plain list
+%%% in the binary file.
+%%%
+%%%-----------------------------------------------------------------
+
+-include_lib("snmp/include/snmp_types.hrl").
+-include_lib("snmp/src/misc/snmp_debug.hrl").
+
+-define(VMODULE,"MDATA_TTTN").
+-include_lib("snmp/src/misc/snmp_verbosity.hrl").
+
+-behaviour(snmpa_mib_data).
+
+-define(MIB_DATA, snmpa_mib_data).
+-define(MIB_NODE, snmpa_mib_node).
+-define(MIB_TREE, snmpa_mib_tree).
+-define(DUMMY_TREE_GENERATION, 1).
+-define(DEFAULT_TREE, {tree,{undefined_node},internal}).
+
+
+%%%-----------------------------------------------------------------
+%%% Table of contents
+%%% =================
+%%% 1. Interface
+%%% 2. Implementation of tree access
+%%% 3. Tree building functions
+%%% 4. Tree merging
+%%% 5. Tree deletion routines
+%%% 6. Functions for subagent handling
+%%% 7. Misc functions
+%%%-----------------------------------------------------------------
+
+-record(mib_data,
+ {
+ %% Mib storage module
+ module :: snmpa:mib_storage_module(),
+
+ %% A database of loaded mibs
+ %% #mib_info{}
+ mib_db,
+
+ %% A database with information about each node in the tree
+ %% #node_info{}
+ node_db,
+
+ %% A database containing _one_ record with the tree
+ %% without the subagent(s).
+ %% (the reason for this is part to get replication
+ %% and part out of convenience)
+ %% #tree{}
+ tree_db,
+
+ %% The root node (same as the tree part of the tree_db
+ %% but with the subagents added).
+ tree,
+
+ %% A list of {SAPid, Oid}
+ subagents = []
+ }).
+
+-record(mib_info, {name, symbolic, file_name}).
+-record(node_info, {oid, mib_name, me}).
+
+
+%% (behaviour) API
+-export([new/1,
+ close/1,
+ sync/1,
+ load_mib/4,
+ unload_mib/4,
+ lookup/2,
+ next/3,
+ register_subagent/3,
+ unregister_subagent/2,
+ dump/2,
+ which_mib/2, which_mibs/1,
+ whereis_mib/2,
+ info/1, info/2,
+ backup/2,
+ code_change/4]).
+
+
+%%-----------------------------------------------------------------
+%% A tree is represented as a N-tuple, where each element is a
+%% node. A node is:
+%% 1) {tree, Tree, Info} where Info can be {table, Id}, {table_entry, Id}
+%% or perhaps 'internal'
+%% 2) undefined_node (memory optimization (instead of {node, undefined}))
+%% 3) {node, Info} where Info can be {subagent, Pid}, {variable, Id},
+%% {table_column, Id}
+%% Id is {MibName, MibEntry}
+%% The over all root is represented as {tree, Tree, internal}.
+%%
+%% tree() = {tree, nodes(), tree_info()}
+%% nodes() = {tree() | node() | undefined_node, ...}
+%% node() = {node, node_info()}
+%% tree_info() = {table, Id} | {table_entry, Id} | internal
+%% node_info() = {subagent, Pid} | {variable, Id} | {table_colum, Id}
+%%-----------------------------------------------------------------
+
+%% This record is what is stored in the database. The 'tree' part
+%% is described above...
+-record(tree, {generation = ?DUMMY_TREE_GENERATION, root = ?DEFAULT_TREE}).
+
+
+%%%======================================================================
+%%% 1. Interface
+%%%======================================================================
+
+%%-----------------------------------------------------------------
+%% Func: new/1
+%% Returns: A representation of mib data.
+%%-----------------------------------------------------------------
+
+%% Where -> A list of nodes where the tables will be created
+new(MibStorage) ->
+ Mod = snmp_misc:get_option(module, MibStorage),
+ Opts = snmp_misc:get_option(options, MibStorage, []),
+
+ %% First we must check if there is already something to read
+ %% If a database already exists, then the tree structure has to be read
+ ?vdebug("open (mib) database",[]),
+ MibDb =
+ case Mod:open(?MIB_DATA, mib_info, record_info(fields, mib_info),
+ set, Opts) of
+ {ok, T1} ->
+ T1;
+ {error, Reason1} ->
+ throw({error, {open, mib_data, Reason1}})
+ end,
+
+ ?vdebug("open (mib) node database",[]),
+ NodeDb =
+ case Mod:open(?MIB_NODE, node_info, record_info(fields, node_info),
+ set, Opts) of
+ {ok, T2} ->
+ T2;
+ {error, Reason2} ->
+ throw({error, {open, mib_node, Reason2}})
+ end,
+
+ ?vdebug("open (mib) tree database",[]),
+ TreeDb =
+ case Mod:open(?MIB_TREE, tree, record_info(fields, tree),
+ set, Opts) of
+ {ok, T3} ->
+ T3;
+ {error, Reason3} ->
+ throw({error, {open, mib_tree, Reason3}})
+ end,
+
+ ?vdebug("write the default (mib) tree",[]),
+ Tree =
+ case Mod:read(TreeDb, ?DUMMY_TREE_GENERATION) of
+ false ->
+ T = #tree{},
+ Mod:write(TreeDb, T),
+ T;
+ {value, T} ->
+ T
+ end,
+ ?vdebug("install (existing) mibs",[]),
+ install_mibs(Mod, MibDb, NodeDb),
+ ?vdebug("done",[]),
+ #mib_data{module = Mod,
+ mib_db = MibDb,
+ node_db = NodeDb,
+ tree_db = TreeDb,
+ tree = Tree}.
+
+
+%%----------------------------------------------------------------------
+%% Returns: new mib data | {error, Reason}
+%%----------------------------------------------------------------------
+load_mib(MibData, FileName, MeOverride, TeOverride)
+ when is_record(MibData,mib_data) andalso is_list(FileName) ->
+ ?vlog("load mib file: ~p",[FileName]),
+ ActualFileName = filename:rootname(FileName, ".bin") ++ ".bin",
+ MibName = list_to_atom(filename:basename(FileName, ".bin")),
+ (catch do_load_mib(MibData, ActualFileName, MibName,
+ MeOverride, TeOverride)).
+
+do_load_mib(MibData, ActualFileName, MibName, MeOverride, TeOverride) ->
+ ?vtrace("do_load_mib -> entry with"
+ "~n ActualFileName: ~s"
+ "~n MibName: ~p",[ActualFileName, MibName]),
+ #mib_data{module = Mod,
+ mib_db = MibDb,
+ node_db = NodeDb,
+ %% tree_db = TreeDb,
+ tree = Tree} = MibData,
+ verify_not_loaded(Mod, MibDb, MibName),
+ ?vtrace("do_load_mib -> already loaded mibs:"
+ "~n ~p", [loaded(Mod, MibDb)]),
+ Mib = do_read_mib(ActualFileName),
+ ?vtrace("do_load_mib -> read mib ~s",[Mib#mib.name]),
+ NonInternalMes =
+ lists:filter(fun(ME) -> maybe_drop_me(ME) end, Mib#mib.mes),
+ OldRoot = Tree#tree.root,
+ T = build_tree(NonInternalMes, MibName),
+ ?d("load_mib -> "
+ "~n OldRoot: ~p"
+ "~n T: ~p", [OldRoot, T]),
+ case (catch merge_nodes(T, OldRoot)) of
+ {error_merge_nodes, Node1, Node2} ->
+ ?vlog("error merging nodes:"
+ "~n~p~nand~n~p", [Node1,Node2]),
+ {error, oid_conflict};
+ NewRoot when is_tuple(NewRoot) andalso (element(1,NewRoot) =:= tree) ->
+ ?d("load_mib -> "
+ "~n NewRoot: ~p", [NewRoot]),
+ Symbolic = not lists:member(no_symbolic_info, Mib#mib.misc),
+ case (catch check_notif_and_mes(TeOverride, MeOverride, Symbolic,
+ Mib#mib.traps, NonInternalMes)) of
+ true ->
+ install_mes(Mod, NodeDb, MibName, NonInternalMes),
+ install_mib(Mod,
+ MibDb, Symbolic, Mib,
+ MibName, ActualFileName, NonInternalMes),
+ ?vtrace("installed mib ~s", [Mib#mib.name]),
+ Tree2 = Tree#tree{root = NewRoot},
+ {ok, MibData#mib_data{tree = Tree2}};
+ Else ->
+ Else
+ end
+ end.
+
+
+verify_not_loaded(Mod, Tab, Name) ->
+ case Mod:read(Tab, Name) of
+ {value, #mib_info{name = Name}} ->
+ throw({error, already_loaded});
+ false ->
+ ok
+ end.
+
+do_read_mib(ActualFileName) ->
+ case snmp_misc:read_mib(ActualFileName) of
+ {error, Reason} ->
+ ?vlog("Failed reading mib file ~p with reason: ~p",
+ [ActualFileName, Reason]),
+ throw({error, Reason});
+ {ok, Mib} ->
+ Mib
+ end.
+
+%% The Tree DB is handled in a special way since it can be very large.
+sync(#mib_data{module = Mod,
+ mib_db = M,
+ node_db = N,
+ tree_db = T, tree = Tree, subagents = []}) ->
+ Mod:sync(M),
+ Mod:sync(N),
+ Mod:write(T, Tree),
+ Mod:sync(T);
+sync(#mib_data{module = Mod,
+ mib_db = M,
+ node_db = N,
+ tree_db = T, tree = Tree, subagents = SAs}) ->
+
+ Mod:sync(M),
+ Mod:sync(N),
+
+ %% Ouch. Since the subagent info is dynamic we do not
+ %% want to store the tree containing subagent info. So, we
+ %% have to create a tmp tree without those and store it.
+
+ case delete_subagents(Tree, SAs) of
+ {ok, TreeWithoutSAs} ->
+ Mod:write(T, TreeWithoutSAs),
+ Mod:sync(T);
+ Error ->
+ Error
+ end.
+
+delete_subagents(Tree, []) ->
+ {ok, Tree};
+delete_subagents(Tree0, [{_, Oid}|SAs]) ->
+ case (catch delete_subagent(Tree0, Oid)) of
+ {tree, _Tree, _Info} = Tree1 ->
+ delete_subagents(Tree1, SAs);
+ _Error ->
+ {error, {'invalid oid', Oid}}
+ end.
+
+%%----------------------------------------------------------------------
+%% (OTP-3601)
+%%----------------------------------------------------------------------
+check_notif_and_mes(TeOverride,MeOverride,Symbolic,Traps,MEs) ->
+ ?vtrace("check notifications and mib entries",[]),
+ check_notifications(TeOverride,Symbolic,Traps),
+ check_mes(MeOverride,MEs).
+
+check_notifications(true, _Symbolic, _Traps) ->
+ ?vtrace("trapentry override = true => skip check",[]),
+ true;
+check_notifications(_, Symbolic, Traps) ->
+ check_notifications(Symbolic, Traps).
+
+check_notifications(true, Traps) ->
+ check_notifications(Traps);
+check_notifications(_, _) -> true.
+
+check_notifications([]) -> true;
+check_notifications([#trap{trapname = Key} = Trap | Traps]) ->
+ ?vtrace("check notification [trap] with Key: ~p",[Key]),
+ case snmpa_symbolic_store:get_notification(Key) of
+ {value, Trap} -> check_notifications(Traps);
+ {value, _} -> throw({error, {'trap already defined', Key}});
+ undefined -> check_notifications(Traps)
+ end;
+check_notifications([#notification{trapname = Key} = Notif | Traps]) ->
+ ?vtrace("check notification [notification] with Key: ~p",[Key]),
+ case snmpa_symbolic_store:get_notification(Key) of
+ {value, Notif} ->
+ check_notifications(Traps);
+ {value, _} ->
+ throw({error, {'notification already defined', Key}});
+ undefined ->
+ check_notifications(Traps)
+ end;
+check_notifications([Crap | Traps]) ->
+ ?vlog("skipped check of: ~n~p",[Crap]),
+ check_notifications(Traps).
+
+check_mes(true,_) ->
+ ?vtrace("mibentry override = true => skip check",[]),
+ true;
+check_mes(_,MEs) ->
+ check_mes(MEs).
+
+check_mes([]) -> true;
+check_mes([#me{aliasname = Name, oid = Oid1} | MEs]) ->
+ ?vtrace("check mib entries with aliasname: ~p",[Name]),
+ case snmpa_symbolic_store:aliasname_to_oid(Name) of
+ {value, Oid1} ->
+ check_mes(MEs);
+ {value, Oid2} ->
+ ?vinfo("~n expecting '~p'~n but found '~p'",[Oid1, Oid2]),
+ throw({error, {'mibentry already defined', Name}});
+ false ->
+ check_mes(MEs)
+ end;
+check_mes([Crap | MEs]) ->
+ ?vlog("skipped check of: ~n~p",[Crap]),
+ check_mes(MEs).
+
+
+
+%%----------------------------------------------------------------------
+%% Returns: new mib data | {error, Reason}
+%%----------------------------------------------------------------------
+unload_mib(MibData, FileName, _, _) when is_list(FileName) ->
+ MibName = list_to_atom(filename:basename(FileName, ".bin")),
+ (catch do_unload_mib(MibData, MibName)).
+
+do_unload_mib(MibData, MibName) ->
+ ?vtrace("do_unload_mib -> entry with"
+ "~n MibName: ~p", [MibName]),
+ #mib_data{module = Mod,
+ mib_db = MibDb,
+ node_db = NodeDb,
+ %% tree_db = TreeDb,
+ tree = Tree} = MibData,
+ #mib_info{symbolic = Symbolic} = verify_loaded(Mod, MibDb, MibName),
+ NewRoot = delete_mib_from_tree(MibName, Tree#tree.root),
+ MEs = uninstall_mes(Mod, NodeDb, MibName),
+ uninstall_mib(Mod, MibDb, Symbolic, MibName, MEs),
+ NewMibData = MibData#mib_data{tree = Tree#tree{root = NewRoot}},
+ {ok, NewMibData}.
+
+verify_loaded(Mod, Tab, Name) ->
+ case Mod:read(Tab, Name) of
+ {value, MibInfo} ->
+ MibInfo;
+ false ->
+ throw({error, not_loaded})
+ end.
+
+
+close(#mib_data{module = Mod,
+ mib_db = MibDb,
+ node_db = NodeDb,
+ tree_db = TreeDb}) ->
+ Mod:close(MibDb),
+ Mod:close(NodeDb),
+ Mod:close(TreeDb),
+ ok.
+
+register_subagent(#mib_data{tree = T} = MibData, Oid, Pid) ->
+ case insert_subagent(Oid, T#tree.root) of
+ {error, Reason} ->
+ {error, Reason};
+ NewRootTree ->
+ SAs = [{Pid, Oid} | MibData#mib_data.subagents],
+ T2 = T#tree{root = NewRootTree},
+ {ok, MibData#mib_data{tree = T2, subagents = SAs}}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Purpose: Get a list of all loaded mibs
+%% Returns: [{Name, File}]
+%%----------------------------------------------------------------------
+
+which_mibs(#mib_data{module = Mod, mib_db = Db}) ->
+ Mibs = Mod:tab2list(Db),
+ [{Name, File} || #mib_info{name = Name, file_name = File} <- Mibs].
+
+
+%%----------------------------------------------------------------------
+%% Purpose: Get a list of all loaded mibs
+%% Returns: [{Name, File}]
+%%----------------------------------------------------------------------
+
+whereis_mib(#mib_data{module = Mod, mib_db = Db}, Name) ->
+ case Mod:read(Db, Name) of
+ {value, #mib_info{file_name = File}} ->
+ {ok, File};
+ false ->
+ {error, not_found}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Purpose: Deletes SA with Pid from all subtrees it handles.
+%% Returns: NewMibData.
+%%----------------------------------------------------------------------
+unregister_subagent(#mib_data{subagents = SAs} = MibData, Pid)
+ when is_pid(Pid) ->
+ SAs = MibData#mib_data.subagents,
+ case lists:keysearch(Pid, 1, SAs) of
+ false ->
+ {ok, MibData};
+ {value, {Pid, Oid}} ->
+ % we should never get an error since Oid is found in MibData.
+ {ok, NewMibData, _DeletedSA} = unregister_subagent(MibData, Oid),
+ % continue if the same Pid handles other mib subtrees.
+ unregister_subagent(NewMibData, Pid)
+ end;
+
+%%----------------------------------------------------------------------
+%% Purpose: Deletes one unique subagent.
+%% Returns: {error, Reason} | {ok, NewMibData, DeletedSubagentPid}
+%%----------------------------------------------------------------------
+unregister_subagent(#mib_data{tree = T} = MibData, Oid) when is_list(Oid) ->
+ case (catch delete_subagent(T#tree.root, Oid)) of
+ {tree, Tree, Info} ->
+ OldSAs = MibData#mib_data.subagents,
+ {value, {Pid, _Oid}} = lists:keysearch(Oid, 2, OldSAs),
+ SAs = lists:keydelete(Oid, 2, OldSAs),
+ T2 = T#tree{root = {tree, Tree, Info}},
+ {ok,
+ MibData#mib_data{tree = T2, subagents = SAs},
+ Pid};
+ _ ->
+ {error, {invalid_oid, Oid}}
+ end.
+
+%%----------------------------------------------------------------------
+%% Purpose: To inpect memory usage, loaded mibs, registered subagents
+%%----------------------------------------------------------------------
+info(MibData) ->
+ ?vtrace("retrieve info",[]),
+ #mib_data{module = Mod,
+ mib_db = MibDb,
+ node_db = NodeDb,
+ tree_db = TreeDb,
+ tree = Tree,
+ subagents = SAs} = MibData,
+ LoadedMibs = old_format(Mod:tab2list(MibDb)),
+ TreeSize = snmp_misc:mem_size(Tree),
+ {memory, ProcSize} = erlang:process_info(self(), memory),
+ MibDbSize = Mod:info(MibDb, memory),
+ NodeDbSize = Mod:info(NodeDb, memory),
+ TreeDbSize = Mod:info(TreeDb, memory),
+ [{loaded_mibs, LoadedMibs}, {subagents, SAs}, {tree_size_bytes, TreeSize},
+ {process_memory, ProcSize},
+ {db_memory, [{mib,MibDbSize},{node,NodeDbSize},{tree,TreeDbSize}]}].
+
+info(#mib_data{module = Mod, mib_db = MibDb}, loaded_mibs) ->
+ Mibs = Mod:tab2list(MibDb),
+ [filename:rootname(FN, ".bin") || #mib_info{file_name = FN} <- Mibs];
+info(#mib_data{tree = Tree}, tree_size_bytes) ->
+ snmp_misc:mem_size(Tree);
+info(_, process_memory) ->
+ {memory, ProcSize} = erlang:process_info(self(),memory),
+ ProcSize;
+info(#mib_data{module = Mod,
+ mib_db = MibDb,
+ node_db = NodeDb,
+ tree_db = TreeDb},
+ db_memory) ->
+ MibDbSize = Mod:info(MibDb, memory),
+ NodeDbSize = Mod:info(NodeDb, memory),
+ TreeDbSize = Mod:info(TreeDb, memory),
+ [{mib, MibDbSize}, {node, NodeDbSize}, {tree, TreeDbSize}];
+info(#mib_data{subagents = SAs}, subagents) ->
+ SAs.
+
+old_format(LoadedMibs) ->
+ ?vtrace("convert mib info to old format",[]),
+ [{N,S,F} || #mib_info{name=N,symbolic=S,file_name=F} <- LoadedMibs].
+
+
+%%----------------------------------------------------------------------
+%% A total dump for debugging.
+%%----------------------------------------------------------------------
+
+dump(#mib_data{module = Mod,
+ mib_db = MibDb,
+ node_db = NodeDb,
+ tree = Tree}, io) ->
+ (catch io:format("MIB-tables:~n~p~n~n",
+ [Mod:tab2list(MibDb)])),
+ (catch io:format("MIB-entries:~n~p~n~n",
+ [Mod:tab2list(NodeDb)])),
+ (catch io:format("Tree:~n~p~n", [Tree])), % good luck reading it!
+ ok;
+
+dump(#mib_data{module = Mod,
+ mib_db = MibDb,
+ node_db = NodeDb,
+ tree = Tree}, File) ->
+ case file:open(File, [write]) of
+ {ok, Fd} ->
+ io:format(Fd,"~s~n",
+ [snmp:date_and_time_to_string(snmp:date_and_time())]),
+ (catch io:format(Fd,"MIB-tables:~n~p~n~n",
+ [Mod:tab2list(MibDb)])),
+ (catch io:format(Fd, "MIB-entries:~n~p~n~n",
+ [Mod:tab2list(NodeDb)])),
+ io:format(Fd,"Tree:~n~p~n", [Tree]), % good luck reading it!
+ file:close(Fd),
+ ok;
+ {error, Reason} ->
+ ?vinfo("~n Failed opening file '~s' for reason ~p",
+ [File, Reason]),
+ {error, Reason}
+ end.
+
+
+backup(#mib_data{module = Mod,
+ mib_db = M,
+ node_db = N,
+ tree_db = T}, BackupDir) ->
+ MRes = Mod:backup(M, BackupDir),
+ NRes = Mod:backup(N, BackupDir),
+ TRes = Mod:backup(T, BackupDir),
+ handle_backup_res([{mib_db, MRes}, {node_db, NRes}, {tree_db, TRes}]).
+
+handle_backup_res(Res) ->
+ handle_backup_res(Res, []).
+
+handle_backup_res([], []) ->
+ ok;
+handle_backup_res([], Err) ->
+ {error, lists:reverse(Err)};
+handle_backup_res([{_, ok}|Res], Err) ->
+ handle_backup_res(Res, Err);
+handle_backup_res([{Tag, {error, Reason}}|Res], Err) ->
+ handle_backup_res(Res, [{Tag, Reason}|Err]);
+handle_backup_res([{Tag, Error}|Res], Err) ->
+ handle_backup_res(Res, [{Tag, Error}|Err]).
+
+
+%%%======================================================================
+%%% 2. Implementation of tree access
+%%% lookup and next.
+%%%======================================================================
+
+
+which_mib(#mib_data{tree = T} = D, Oid) ->
+ ?vtrace("which_mib -> entry with"
+ "~n Oid: ~p",[Oid]),
+ case (catch find_node(D, T#tree.root, Oid, [])) of
+ {variable, _ME, Mib} ->
+ ?vtrace("which_mib -> variable:"
+ "~n Mib: ~p", [Mib]),
+ {ok, Mib};
+ {table, _EntryME, _, Mib} ->
+ ?vtrace("which_mib -> table:"
+ "~n Mib: ~p", [Mib]),
+ {ok, Mib};
+ {subagent, SubAgentPid, _SANextOid} ->
+ ?vtrace("which_mib -> subagent:"
+ "~n SubAgentPid: ~p", [SubAgentPid]),
+ {error, {subagent, SubAgentPid}};
+ {false, ErrorCode} ->
+ ?vtrace("which_mib -> false:"
+ "~n ErrorCode: ~p",[ErrorCode]),
+ {error, ErrorCode};
+ false ->
+ ?vtrace("which_mib -> false",[]),
+ {error, noSuchObject};
+ {'EXIT', R} ->
+ ?vtrace("which_mib -> exit:"
+ "~n R: ~p",[R]),
+ {error, noSuchObject}
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: lookup/2
+%% Purpose: Finds the mib entry corresponding to the Oid. If it is a
+%% variable, the Oid must be <Oid for var>.0 and if it is
+%% a table, Oid must be <table>.<entry>.<col>.<any>
+%% Returns: {variable, MibEntry} |
+%% {table_column, MibEntry, TableEntryOid} |
+%% {subagent, SubAgentPid, SAOid} |
+%% {false, Reason}
+%%-----------------------------------------------------------------
+lookup(#mib_data{tree = T} = D, Oid) ->
+ ?vtrace("lookup -> entry with"
+ "~n Oid: ~p",[Oid]),
+ case (catch find_node(D, T#tree.root, Oid, [])) of
+ {variable, ME, _Mib} when is_record(ME, me) ->
+ ?vtrace("lookup -> variable:"
+ "~n ME: ~p",[ME]),
+ {variable, ME};
+ {table, EntryME, {ColME, TableEntryOid}, _Mib} ->
+ ?vtrace("lookup -> table:"
+ "~n EntryME: ~p"
+ "~n ColME: ~p"
+ "~n RevTableEntryOid: ~p",
+ [EntryME, ColME, TableEntryOid]),
+ MFA = EntryME#me.mfa,
+ RetME = ColME#me{mfa = MFA},
+ {table_column, RetME, TableEntryOid};
+ {subagent, SubAgentPid, SANextOid} ->
+ ?vtrace("lookup -> subagent:"
+ "~n SubAgentPid: ~p"
+ "~n SANextOid: ~p", [SubAgentPid, SANextOid]),
+ {subagent, SubAgentPid, SANextOid};
+ {false, ErrorCode} ->
+ ?vtrace("lookup -> false:"
+ "~n ErrorCode: ~p",[ErrorCode]),
+ {false, ErrorCode};
+ false ->
+ ?vtrace("lookup -> false",[]),
+ {false, noSuchObject};
+ {'EXIT', R} ->
+ ?vtrace("lookup -> exit:"
+ "~n R: ~p",[R]),
+ {false, noSuchObject}
+ end.
+
+
+find_node(D, {tree, Tree, {table, _}}, RestOfOid, RevOid) ->
+ ?vtrace("find_node(tree,table) -> entry with"
+ "~n RestOfOid: ~p"
+ "~n RevOid: ~p",[RestOfOid, RevOid]),
+ find_node(D, {tree, Tree, internal}, RestOfOid, RevOid);
+find_node(D, {tree, Tree, {table_entry, _}}, RestOfOid, RevOid) ->
+ ?vtrace("find_node(tree,table_entry) -> entry with"
+ "~n RestOfOid: ~p"
+ "~n RevOid: ~p",[RestOfOid, RevOid]),
+ #mib_data{module = Mod, node_db = Db} = D,
+ Oid = lists:reverse(RevOid),
+ case Mod:read(Db, Oid) of
+ {value, #node_info{me = ME, mib_name = Mib}} ->
+ case find_node(D, {tree, Tree, internal}, RestOfOid, RevOid) of
+ {false, ErrorCode} -> {false, ErrorCode};
+ Val -> {table, ME, Val, Mib}
+ end;
+ false ->
+ ?vinfo("find_node -> could not find table_entry ME with"
+ "~n RevOid: ~p"
+ "~n when"
+ "~n RestOfOid: ~p",
+ [RevOid, RestOfOid]),
+ false
+ end;
+find_node(D, {tree, Tree, _Internal}, [Int | RestOfOid], RevOid) ->
+ ?vtrace("find_node(tree) -> entry with"
+ "~n Int: ~p"
+ "~n RestOfOid: ~p"
+ "~n RevOid: ~p",[Int, RestOfOid, RevOid]),
+ find_node(D, element(Int+1, Tree), RestOfOid, [Int | RevOid]);
+find_node(D, {node, {table_column, _}}, RestOfOid, [ColInt | RevOid]) ->
+ ?vtrace("find_node(tree,table_column) -> entry with"
+ "~n RestOfOid: ~p"
+ "~n ColInt: ~p"
+ "~n RevOid: ~p",[RestOfOid, ColInt, RevOid]),
+ #mib_data{module = Mod, node_db = Db} = D,
+ Oid = lists:reverse([ColInt | RevOid]),
+ case Mod:read(Db, Oid) of
+ {value, #node_info{me = ME}} ->
+ {ME, lists:reverse(RevOid)};
+ false ->
+ X = Mod:read(Db, lists:reverse([ColInt | RevOid])),
+ ?vinfo("find_node -> could not find table_column ME with"
+ "~n RevOid: ~p"
+ "~n trying [~p|~p]"
+ "~n X: ~p",
+ [RevOid, [ColInt | RevOid], X]),
+ false
+ end;
+find_node(D, {node, {variable, _MibName}}, [0], RevOid) ->
+ ?vtrace("find_node(tree,variable,[0]) -> entry with"
+ "~n RevOid: ~p",[RevOid]),
+ #mib_data{module = Mod, node_db = Db} = D,
+ Oid = lists:reverse(RevOid),
+ case Mod:read(Db, Oid) of
+ {value, #node_info{me = ME, mib_name = Mib}} ->
+ {variable, ME, Mib};
+ false ->
+ ?vinfo("find_node -> could not find variable ME with"
+ "~n RevOid: ~p", [RevOid]),
+ false
+ end;
+find_node(_D, {node, {variable, _MibName}}, [], _RevOid) ->
+ ?vtrace("find_node(tree,variable,[]) -> entry",[]),
+ {false, noSuchObject};
+find_node(_D, {node, {variable, _MibName}}, _, _RevOid) ->
+ ?vtrace("find_node(tree,variable) -> entry",[]),
+ {false, noSuchInstance};
+find_node(D, {node, subagent}, _RestOfOid, SARevOid) ->
+ ?vtrace("find_node(tree,subagent) -> entry with"
+ "~n SARevOid: ~p",[SARevOid]),
+ #mib_data{subagents = SAs} = D,
+ SAOid = lists:reverse(SARevOid),
+ case lists:keysearch(SAOid, 2, SAs) of
+ {value, {SubAgentPid, SAOid}} ->
+ {subagent, SubAgentPid, SAOid};
+ false ->
+ ?vinfo("find_node -> could not find subagent with"
+ "~n SAOid: ~p"
+ "~n SAs: ~p", [SAOid, SAs]),
+ false
+ end;
+find_node(_D, Node, _RestOfOid, _RevOid) ->
+ ?vtrace("find_node -> failed:~n~p",[Node]),
+ {false, noSuchObject}.
+
+
+%%-----------------------------------------------------------------
+%% Func: next/3
+%% Purpose: Finds the lexicographically next oid.
+%% Returns: endOfMibView |
+%% {subagent, SubAgentPid, SAOid} |
+%% {variable, MibEntry, VarOid} |
+%% {table, TableOid, TableRestOid, MibEntry}
+%% If a variable is returnes, it is in the MibView.
+%% If a table or subagent is returned, it *may* be in the MibView.
+%%-----------------------------------------------------------------
+next(#mib_data{tree = T} = D, Oid, MibView) ->
+ case catch next_node(D, T#tree.root, Oid, [], MibView) of
+ false -> endOfMibView;
+ Else -> Else
+ end.
+
+%%-----------------------------------------------------------------
+%% This function is used as long as we have any Oid left. Take
+%% one integer at a time from the Oid, and traverse the tree
+%% accordingly. When the Oid is empty, call find_next.
+%% Returns: {subagent, SubAgentPid, SAOid} |
+%% false |
+%% {variable, MibEntry, VarOid} |
+%% {table, TableOid, TableRestOid, MibEntry}
+%%-----------------------------------------------------------------
+next_node(_D, undefined_node, _Oid, _RevOidSoFar, _MibView) ->
+ ?vtrace("next_node(undefined_node) -> entry", []),
+ false;
+
+next_node(_D, {tree, Tree, {table_entry, _Id}}, [Int | _Oid],
+ _RevOidSoFar, _MibView)
+ when Int+1 > size(Tree) ->
+ ?vtrace("next_node(tree,table_entry) -> entry when not found whith"
+ "~n Int: ~p"
+ "~n size(Tree): ~p", [Int, size(Tree)]),
+ false;
+next_node(D, {tree, Tree, {table_entry, _MibName}},
+ Oid, RevOidSoFar, MibView) ->
+ ?vtrace("next_node(tree,table_entry) -> entry when"
+ "~n size(Tree): ~p"
+ "~n Oid: ~p"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p", [size(Tree), Oid, RevOidSoFar, MibView]),
+ OidSoFar = lists:reverse(RevOidSoFar),
+ case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
+ true ->
+ ?vdebug("next_node(tree,table_entry) -> not in mib view",[]),
+ false;
+ _ ->
+ #mib_data{module = Mod, node_db = Db} = D,
+ case Mod:read(Db, OidSoFar) of
+ false ->
+ ?vinfo("next_node -> could not find table_entry with"
+ "~n OidSoFar: ~p", [OidSoFar]),
+ false;
+ {value, #node_info{me = ME}} ->
+ ?vtrace("next_node(tree,table_entry) -> found: ~n ~p",
+ [ME]),
+ {table, OidSoFar, Oid, ME}
+ end
+ end;
+
+next_node(D, {tree, Tree, _Info}, [Int | RestOfOid], RevOidSoFar, MibView)
+ when (Int < size(Tree)) andalso (Int >= 0) ->
+ ?vtrace("next_node(tree) -> entry when"
+ "~n size(Tree): ~p"
+ "~n Int: ~p"
+ "~n RestOfOid: ~p"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p",
+ [size(Tree), Int, RestOfOid, RevOidSoFar, MibView]),
+ case next_node(D, element(Int+1,Tree),
+ RestOfOid, [Int|RevOidSoFar], MibView) of
+ false ->
+ find_next(D, {tree, Tree, _Info}, Int+1, RevOidSoFar, MibView);
+ Else ->
+ Else
+ end;
+%% no solution
+next_node(D, {tree, Tree, _Info}, [], RevOidSoFar, MibView) ->
+ ?vtrace("next_node(tree,[]) -> entry when"
+ "~n size(Tree): ~p"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p",
+ [size(Tree), RevOidSoFar, MibView]),
+ find_next(D, {tree, Tree, _Info}, 0, RevOidSoFar, MibView);
+next_node(_D, {tree, Tree, _Info}, _RestOfOid, _RevOidSoFar, _MibView) ->
+ ?vtrace("next_node(tree) -> entry when"
+ "~n size(Tree): ~p", [size(Tree)]),
+ false;
+
+next_node(D, {node, subagent}, Oid, RevOidSoFar, MibView) ->
+ ?vtrace("next_node(node,subagent) -> entry when"
+ "~n Oid: ~p"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p",
+ [Oid, RevOidSoFar, MibView]),
+ OidSoFar = lists:reverse(RevOidSoFar),
+ case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
+ true ->
+ false;
+ _ ->
+ #mib_data{subagents = SAs} = D,
+ case lists:keysearch(OidSoFar, 2, SAs) of
+ {value, {SubAgentPid, OidSoFar}} ->
+ {subagent, SubAgentPid, OidSoFar};
+ _ ->
+ ?vinfo("next_node -> could not find subagent with"
+ "~n OidSoFar: ~p"
+ "~n SAs: ~p", [OidSoFar, SAs]),
+ false
+ end
+ end;
+
+next_node(D, {node, {variable, _MibName}}, [], RevOidSoFar, MibView) ->
+ ?vtrace("next_node(node,variable,[]) -> entry when"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p",
+ [RevOidSoFar, MibView]),
+ OidSoFar = lists:reverse([0 | RevOidSoFar]),
+ case snmpa_acm:validate_mib_view(OidSoFar, MibView) of
+ true ->
+ #mib_data{module = Mod, node_db = Db} = D,
+ case Mod:read(Db, lists:reverse(RevOidSoFar)) of
+ false ->
+ ?vinfo("next_node -> could not find variable with"
+ "~n RevOidSoFar: ~p", [RevOidSoFar]),
+ false;
+ {value, #node_info{me = ME}} ->
+ {variable, ME, OidSoFar}
+ end;
+ _ ->
+ false
+ end;
+
+next_node(_D, {node, {variable, _MibName}}, _Oid, _RevOidSoFar, _MibView) ->
+ ?vtrace("next_node(node,variable) -> entry", []),
+ false.
+
+
+%%-----------------------------------------------------------------
+%% This function is used to find the first leaf from where we
+%% are.
+%% Returns: {subagent, SubAgentPid, SAOid} |
+%% false |
+%% {variable, MibEntry, VarOid} |
+%% {table, TableOid, TableRestOid, MibEntry}
+%% PRE: This function must always be called with a {internal, Tree}
+%% node.
+%%-----------------------------------------------------------------
+find_next(D, {tree, Tree, internal}, Idx, RevOidSoFar, MibView)
+ when Idx < size(Tree) ->
+ case find_next(D, element(Idx+1, Tree), 0, [Idx| RevOidSoFar], MibView) of
+ false ->
+ find_next(D, {tree, Tree, internal}, Idx+1, RevOidSoFar, MibView);
+ Other ->
+ Other
+ end;
+find_next(_D, {tree, _Tree, internal}, _Idx, _RevOidSoFar, _MibView) ->
+ false;
+find_next(_D, undefined_node, _Idx, _RevOidSoFar, _MibView) ->
+ false;
+find_next(D, {tree, Tree, {table, _MibName}}, Idx, RevOidSoFar, MibView) ->
+ find_next(D, {tree, Tree, internal}, Idx, RevOidSoFar, MibView);
+find_next(D, {tree, _Tree, {table_entry, _MibName}}, _Index,
+ RevOidSoFar, MibView) ->
+ OidSoFar = lists:reverse(RevOidSoFar),
+ case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
+ true ->
+ false;
+ _ ->
+ #mib_data{module = Mod, node_db = Db} = D,
+ case Mod:read(Db, OidSoFar) of
+ false ->
+ ?vinfo("find_next -> could not find table_entry ME with"
+ "~n OidSoFar: ~p", [OidSoFar]),
+ false;
+ {value, #node_info{me = ME}} ->
+ {table, OidSoFar, [], ME}
+ end
+ end;
+find_next(D, {node, {variable, _MibName}}, _Idx, RevOidSoFar, MibView) ->
+ OidSoFar = lists:reverse([0 | RevOidSoFar]),
+ case snmpa_acm:validate_mib_view(OidSoFar, MibView) of
+ true ->
+ #mib_data{module = Mod, node_db = Db} = D,
+ case Mod:read(Db, lists:reverse(RevOidSoFar)) of
+ false ->
+ ?vinfo("find_next -> could not find variable with"
+ "~n RevOidSoFar: ~p", [RevOidSoFar]),
+ false;
+ {value, #node_info{me = ME}} ->
+ {variable, ME, OidSoFar}
+ end;
+ _ ->
+ false
+ end;
+find_next(D, {node, subagent}, _Idx, RevOidSoFar, MibView) ->
+ OidSoFar = lists:reverse(RevOidSoFar),
+ case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
+ true ->
+ false;
+ _ ->
+ #mib_data{subagents = SAs} = D,
+ case lists:keysearch(OidSoFar, 2, SAs) of
+ {value, {SubAgentPid, OidSoFar}} ->
+ {subagent, SubAgentPid, OidSoFar};
+ false ->
+ ?vinfo("find_node -> could not find subagent with"
+ "~n OidSoFar: ~p"
+ "~n SAs: ~p", [OidSoFar, SAs]),
+ false
+ end
+ end.
+
+%%%======================================================================
+%%% 3. Tree building functions
+%%% Used when loading mibs.
+%%%======================================================================
+
+build_tree(Mes, MibName) ->
+ ?d("build_tree -> "
+ "~n Mes: ~p", [Mes]),
+ {ListTree, []} = build_subtree([], Mes, MibName),
+ {tree, convert_tree(ListTree), internal}.
+
+%%----------------------------------------------------------------------
+%% Purpose: Builds the tree where all oids have prefix equal to LevelPrefix.
+%% Returns: {Tree, RestMes}
+%% RestMes are Mes that should not be in this subtree.
+%% The Tree is a temporary and simplified data structure that is easy to
+%% convert to the final tuple tree used by the MIB process.
+%% A Node is represented as in the final tree.
+%% The tree is not represented as a N-tuple, but as an Index-list.
+%% Example: Temporary: [{1, Node1}, {3, Node3}]
+%% Final: {Node1, undefined_node, Node3}
+%% Pre: Mes are sorted on oid.
+%%----------------------------------------------------------------------
+build_subtree(LevelPrefix, [Me | Mes], MibName) ->
+ ?vtrace("build subtree -> ~n"
+ " oid: ~p~n"
+ " LevelPrefix: ~p~n"
+ " MibName: ~p", [Me#me.oid, LevelPrefix, MibName]),
+ EType = Me#me.entrytype,
+ ?vtrace("build subtree -> EType = ~p",[EType]),
+ case in_subtree(LevelPrefix, Me) of
+ above ->
+ ?vtrace("build subtree -> above",[]),
+ {[], [Me|Mes]};
+ {node, Index} ->
+ ?vtrace("build subtree -> node at ~p",[Index]),
+ {Tree, RestMes} = build_subtree(LevelPrefix, Mes, MibName),
+ {[{Index, {node, {EType, MibName}}} | Tree], RestMes};
+ {subtree, Index, NewLevelPrefix} ->
+ ?vtrace("build subtree -> subtree at"
+ "~n ~w with ~w",
+ [Index, NewLevelPrefix]),
+ {BelowTree, RestMes} =
+ build_subtree(NewLevelPrefix, Mes, MibName),
+ {CurTree, RestMes2} =
+ build_subtree(LevelPrefix, RestMes, MibName),
+ {[{Index, {tree, BelowTree, {EType,MibName}}}| CurTree], RestMes2};
+ {internal_subtree, Index, NewLevelPrefix} ->
+ ?vtrace("build subtree -> internal_subtree at"
+ "~n ~w with ~w",
+ [Index,NewLevelPrefix]),
+ {BelowTree, RestMes} =
+ build_subtree(NewLevelPrefix, [Me | Mes], MibName),
+ {CurTree, RestMes2} =
+ build_subtree(LevelPrefix, RestMes, MibName),
+ {[{Index, {tree, BelowTree, internal}} | CurTree], RestMes2}
+ end;
+
+build_subtree(_LevelPrefix, [], _MibName) ->
+ ?vtrace("build subtree -> done", []),
+ {[], []}.
+
+%%--------------------------------------------------
+%% Purpose: Determine how/if/where Me should be inserted in subtree
+%% with LevelPrefix. This function does not build any tree, only
+%% determinses what should be done (by build subtree).
+%% Returns:
+%% above - Indicating that this ME should _not_ be in this subtree.
+%% {node, Index} - yes, construct a node with index Index on this level
+%% {internal_subtree, Index, NewLevelPrefix} - yes, there should be an
+%% internal subtree at this index.
+%% {subtree, Index, NewLevelPrefix} - yes, construct a subtree with
+%% NewLevelPrefix and insert this on current level in position Index.
+%%--------------------------------------------------
+in_subtree(LevelPrefix, Me) ->
+ case lists:prefix(LevelPrefix, Me#me.oid) of
+ true when length(Me#me.oid) > length(LevelPrefix) ->
+ classify_how_in_subtree(LevelPrefix, Me);
+ _ ->
+ above
+ end.
+
+%%--------------------------------------------------
+%% See comment about in_subtree/2. This function takes care of all cases
+%% where the ME really should be in _this_ subtree (not above).
+%%--------------------------------------------------
+classify_how_in_subtree(LevelPrefix, Me)
+ when (length(Me#me.oid) =:= (length(LevelPrefix) + 1)) ->
+ Oid = Me#me.oid,
+ case node_or_subtree(Me#me.entrytype) of
+ subtree ->
+ {subtree, lists:last(Oid), Oid};
+ node ->
+ {node, lists:last(Oid)}
+ end;
+
+classify_how_in_subtree(LevelPrefix, Me)
+ when (length(Me#me.oid) > (length(LevelPrefix) + 1)) ->
+ L1 = length(LevelPrefix) + 1,
+ Oid = Me#me.oid,
+ {internal_subtree, lists:nth(L1, Oid), lists:sublist(Oid, 1, L1)}.
+
+%%--------------------------------------------------
+%% Determines how to treat different kinds om MEs in the tree building process.
+%% Pre: all internal nodes have been removed.
+%%--------------------------------------------------
+node_or_subtree(table) -> subtree;
+node_or_subtree(table_entry) -> subtree;
+node_or_subtree(variable) -> node;
+node_or_subtree(table_column) -> node.
+
+%%--------------------------------------------------
+%% Purpose: (Recursively) Converts a temporary tree (see above) to a final tree.
+%% If input is a ListTree, output is a TupleTree.
+%% If input is a Node, output is the same Node.
+%% Pre: All Indexes are >= 0.
+%%--------------------------------------------------
+convert_tree({Index, {tree, Tree, Info}}) when Index >= 0 ->
+ L = lists:map(fun convert_tree/1, Tree),
+ {Index, {tree, dict_list_to_tuple(L), Info}};
+convert_tree({Index, {node, Info}}) when Index >= 0 ->
+ {Index, {node, Info}};
+convert_tree(Tree) when is_list(Tree) ->
+ L = lists:map(fun convert_tree/1, Tree),
+ dict_list_to_tuple(L).
+
+%%----------------------------------------------------------------------
+%% Purpose: Converts a single level (that is non-recursively) from
+%% the temporary indexlist to the N-tuple.
+%% Input: A list of {Index, Data}.
+%% Output: A tuple where element Index is Data.
+%%----------------------------------------------------------------------
+dict_list_to_tuple(L) ->
+ L2 = lists:keysort(1, L),
+ list_to_tuple(integrate_indexes(0, L2)).
+
+%%----------------------------------------------------------------------
+%% Purpose: Helper function for dict_list_to_tuple/1.
+%% Converts an indexlist to a N-list.
+%% Input: A list of {Index, Data}.
+%% Output: A (usually longer, never shorter) list where element Index is Data.
+%% Example: [{1,hej}, {3, sven}] will give output
+%% [undefined_node, hej, undefined_node, sven].
+%% Initially CurIndex should be 0.
+%%----------------------------------------------------------------------
+integrate_indexes(CurIndex, [{CurIndex, Data} | T]) ->
+ [Data | integrate_indexes(CurIndex + 1, T)];
+integrate_indexes(_Index, []) ->
+ [];
+integrate_indexes(CurIndex, L) ->
+ [undefined_node | integrate_indexes(CurIndex + 1, L)].
+
+%%%======================================================================
+%%% 4. Tree merging
+%%% Used by: load mib, insert subagent.
+%%%======================================================================
+
+%%----------------------------------------------------------------------
+%% Arg: Two root nodes (that is to be merged).
+%% Returns: A new root node where the nodes have been merger to one.
+%%----------------------------------------------------------------------
+merge_nodes(Same, Same) ->
+ Same;
+merge_nodes(Node, undefined_node) ->
+ Node;
+merge_nodes(undefined_node, Node) ->
+ Node;
+merge_nodes({tree, Tree1, internal}, {tree, Tree2, internal}) ->
+ {tree, merge_levels(tuple_to_list(Tree1),tuple_to_list(Tree2)), internal};
+merge_nodes(Node1, Node2) ->
+ throw({error_merge_nodes, Node1, Node2}).
+
+%%----------------------------------------------------------------------
+%% Arg: Two levels to be merged.
+%% Here, a level is represented as a list of nodes. A list is easier
+%% to extend than a tuple.
+%% Returns: The resulting, merged level tuple.
+%%----------------------------------------------------------------------
+merge_levels(Level1, Level2) when length(Level1) =:= length(Level2) ->
+ MergeNodes = fun(N1, N2) -> merge_nodes(N1, N2) end,
+ list_to_tuple(snmp_misc:multi_map(MergeNodes, [Level1, Level2]));
+merge_levels(Level1, Level2) when length(Level1) > length(Level2) ->
+ merge_levels(Level1, Level2 ++
+ undefined_nodes_list(length(Level1) - length(Level2)));
+merge_levels(Level1, Level2) when length(Level1) < length(Level2) ->
+ merge_levels(Level2, Level1).
+
+undefined_nodes_list(N) -> lists:duplicate(N, undefined_node).
+
+
+%%%======================================================================
+%%% 5. Tree deletion routines
+%%% (for unload mib)
+%%%======================================================================
+
+%%----------------------------------------------------------------------
+%% Purpose: Actually kicks of the tree reconstruction.
+%% Returns: {list of removed MEs, NewTree}
+%%----------------------------------------------------------------------
+delete_mib_from_tree(MibName, {tree, Tree, internal}) ->
+ case delete_tree(Tree, MibName) of
+ [] ->
+ {tree, {undefined_node}, internal}; % reduce
+ LevelList ->
+ {tree, list_to_tuple(LevelList), internal}
+ end.
+
+%%----------------------------------------------------------------------
+%% Purpose: Deletes all nodes associated to MibName from this level and
+%% all levels below.
+%% If the new level does not contain information (that is, no
+%% other mibs use it) anymore the empty list is returned.
+%% Returns: {MEs, The new level represented as a list}
+%%----------------------------------------------------------------------
+delete_tree(Tree, MibName) when is_tuple(Tree) ->
+ NewLevel = delete_nodes(tuple_to_list(Tree), MibName, []),
+ case lists:filter(fun drop_undefined_nodes/1,NewLevel) of
+ [] -> [];
+ _A_perhaps_shorted_list ->
+ NewLevel % some other mib needs this level
+ end.
+
+%%----------------------------------------------------------------------
+%% Purpose: Nodes belonging to MibName are removed from the tree.
+%% Recursively deletes sub trees to this node.
+%% Returns: {MEs, NewNodesList}
+%%----------------------------------------------------------------------
+delete_nodes([], _MibName, AccNodes) ->
+ lists:reverse(AccNodes);
+
+delete_nodes([{node, {variable, MibName}}|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+
+delete_nodes([{node, {table_column, MibName}}|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+
+delete_nodes([{tree, _Tree, {table, MibName}}|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+
+delete_nodes([{tree, _Tree, {table_entry, MibName}}|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+
+delete_nodes([{tree, Tree, Info}|T], MibName, AccNodes) ->
+ case delete_tree(Tree, MibName) of
+ [] -> % tree completely deleted
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+ LevelList ->
+ delete_nodes(T, MibName,
+ [{tree, list_to_tuple(LevelList), Info} | AccNodes])
+ end;
+
+delete_nodes([NodeToKeep|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [NodeToKeep | AccNodes]).
+
+drop_undefined_nodes(undefined_node) -> false;
+drop_undefined_nodes(_) -> true.
+
+
+%%%======================================================================
+%%% 6. Functions for subagent handling
+%%%======================================================================
+
+%%----------------------------------------------------------------------
+%% Returns: A new Root|{error, reason}
+%%----------------------------------------------------------------------
+insert_subagent(Oid, OldRoot) ->
+ ListTree = build_tree_for_subagent(Oid),
+ case catch convert_tree(ListTree) of
+ {'EXIT', _Reason} ->
+ {error, 'cannot construct tree from oid'};
+ Level when is_tuple(Level) ->
+ T = {tree, Level, internal},
+ case catch merge_nodes(T, OldRoot) of
+ {error_merge_nodes, _Node1, _Node2} ->
+ {error, oid_conflict};
+ NewRoot when is_tuple(NewRoot) andalso
+ (element(1, NewRoot) =:= tree) ->
+ NewRoot
+ end
+ end.
+
+build_tree_for_subagent([Index]) ->
+ [{Index, {node, subagent}}];
+
+build_tree_for_subagent([Index | T]) ->
+ [{Index, {tree, build_tree_for_subagent(T), internal}}].
+
+
+%%----------------------------------------------------------------------
+%% Returns: A new tree where the subagent at Oid (2nd arg) has been deleted.
+%%----------------------------------------------------------------------
+
+delete_subagent({tree, Tree, Info}, [Index]) ->
+ {node, subagent} = element(Index+1, Tree),
+ {tree, setelement(Index+1, Tree, undefined_node), Info};
+delete_subagent({tree, Tree, Info}, [Index | TI]) ->
+ {tree, setelement(Index+1, Tree,
+ delete_subagent(element(Index+1, Tree), TI)), Info}.
+
+
+%%%======================================================================
+%%% 7. Misc functions
+%%%======================================================================
+
+%%----------------------------------------------------------------------
+%% Installs the mibs found in the database when starting the agent.
+%% Basically calls the instrumentation functions for all non-internal
+%% mib-entries
+%%----------------------------------------------------------------------
+install_mibs(Mod, MibDb, NodeDb) ->
+ MibNames = loaded(Mod, MibDb),
+ ?vtrace("install_mibs -> found following mibs in database: ~n"
+ "~p", [MibNames]),
+ install_mibs2(Mod, NodeDb, MibNames).
+
+install_mibs2(_, _, []) ->
+ ok;
+install_mibs2(Mod, NodeDb, [MibName|MibNames]) ->
+ Pattern = #node_info{oid = '_', mib_name = MibName, me = '_'},
+ Nodes = Mod:match_object(NodeDb, Pattern),
+ MEs = [ME || #node_info{me = ME} <- Nodes],
+ ?vtrace("install_mibs2 -> installing ~p MEs for mib ~p",
+ [length(MEs), MibName]),
+ NewF = fun(ME) -> call_instrumentation(ME, new) end,
+ lists:foreach(NewF, MEs),
+ install_mibs2(Mod, NodeDb, MibNames).
+
+
+%%----------------------------------------------------------------------
+%% Does all side effect stuff during load_mib.
+%%----------------------------------------------------------------------
+install_mib(Mod, Db, Symbolic, Mib, MibName, FileName, NonInternalMes) ->
+ ?vdebug("install_mib -> entry with"
+ "~n Symbolic: ~p"
+ "~n MibName: ~p"
+ "~n FileName: ~p", [Symbolic, MibName, FileName]),
+ Rec = #mib_info{name = MibName, symbolic = Symbolic, file_name = FileName},
+ Mod:write(Db, Rec),
+ install_mib2(Symbolic, MibName, Mib),
+ NewF = fun(ME) -> call_instrumentation(ME, new) end,
+ lists:foreach(NewF, NonInternalMes).
+
+install_mib2(true, MibName, Mib) ->
+ #mib{table_infos = TabInfos,
+ variable_infos = VarInfos,
+ mes = MEs,
+ asn1_types = ASN1Types,
+ traps = Traps} = Mib,
+ snmpa_symbolic_store:add_table_infos(MibName, TabInfos),
+ snmpa_symbolic_store:add_variable_infos(MibName, VarInfos),
+ snmpa_symbolic_store:add_aliasnames(MibName, MEs),
+ snmpa_symbolic_store:add_types(MibName, ASN1Types),
+ SetF = fun(Trap) ->
+ snmpa_symbolic_store:set_notification(Trap, MibName)
+ end,
+ lists:foreach(SetF, Traps);
+install_mib2(_, _, _) ->
+ ok.
+
+install_mes(Mod, Db, MibName, MEs) ->
+ Write = fun(#me{oid = Oid} = ME) ->
+ Node = #node_info{oid = Oid,
+ mib_name = MibName,
+ me = ME},
+ Mod:write(Db, Node)
+ end,
+ install_mes(Write, MEs).
+
+install_mes(_Write, []) ->
+ ok;
+install_mes(Write, [ME|MEs]) ->
+ Write(ME),
+ install_mes(Write, MEs).
+
+
+%%----------------------------------------------------------------------
+%% Does all side effect stuff during unload_mib.
+%%----------------------------------------------------------------------
+uninstall_mib(Mod, Db, Symbolic, MibName, MEs) ->
+ ?vtrace("uninstall_mib -> entry with"
+ "~n Db: ~p"
+ "~n Symbolic: ~p"
+ "~n MibName: ~p", [Db, Symbolic, MibName]),
+ Res = Mod:delete(Db, MibName),
+ ?vtrace("uninstall_mib -> (mib) db delete result: ~p", [Res]),
+ uninstall_mib2(Symbolic, MibName),
+ DelF = fun(ME) -> call_instrumentation(ME, delete) end,
+ lists:foreach(DelF, MEs).
+
+uninstall_mib2(true, MibName) ->
+ snmpa_symbolic_store:delete_table_infos(MibName),
+ snmpa_symbolic_store:delete_variable_infos(MibName),
+ snmpa_symbolic_store:delete_aliasnames(MibName),
+ snmpa_symbolic_store:delete_types(MibName),
+ snmpa_symbolic_store:delete_notifications(MibName);
+uninstall_mib2(_, _) ->
+ ok.
+
+uninstall_mes(Mod, Db, MibName) ->
+ Pattern = #node_info{oid = '_', mib_name = MibName, me = '_'},
+ Mod:match_delete(Db, Pattern).
+
+
+%%----------------------------------------------------------------------
+%% Create a list of the names of all the loaded mibs
+%%----------------------------------------------------------------------
+loaded(Mod, Db) ->
+ [N || #mib_info{name = N} <- Mod:tab2list(Db)].
+
+
+%%----------------------------------------------------------------------
+%% Calls MFA-instrumentation with 'new' or 'delete' operation.
+%%----------------------------------------------------------------------
+call_instrumentation(#me{entrytype = variable, mfa={M,F,A}}, Operation) ->
+ ?vtrace("call instrumentation with"
+ "~n entrytype: variable"
+ "~n MFA: {~p,~p,~p}"
+ "~n Operation: ~p",
+ [M,F,A,Operation]),
+ catch apply(M, F, [Operation | A]);
+call_instrumentation(#me{entrytype = table_entry, mfa={M,F,A}}, Operation) ->
+ ?vtrace("call instrumentation with"
+ "~n entrytype: table_entry"
+ "~n MFA: {~p,~p,~p}"
+ "~n Operation: ~p",
+ [M,F,A,Operation]),
+ catch apply(M, F, [Operation | A]);
+call_instrumentation(_ShitME, _Operation) ->
+ done.
+
+
+maybe_drop_me(#me{entrytype = internal}) -> false;
+maybe_drop_me(#me{entrytype = group}) -> false;
+maybe_drop_me(#me{imported = true}) -> false;
+maybe_drop_me(_) -> true.
+
+
+%%----------------------------------------------------------------------
+%% Code change functions
+%%----------------------------------------------------------------------
+
+code_change(down, _Vsn, _Extra, State) ->
+ ?d("code_change(down) -> entry when"
+ "~n Vsn: ~p"
+ "~n Extra: ~p", [_Vsn, _Extra]),
+ State;
+
+code_change(up, _Vsn, _Extra, State) ->
+ ?d("code_change(up) -> entry when"
+ "~n Vsn: ~p"
+ "~n Extra: ~p", [_Vsn, _Extra]),
+ State.
+
+
diff --git a/lib/snmp/src/agent/snmpa_mib_storage.erl b/lib/snmp/src/agent/snmpa_mib_storage.erl
new file mode 100644
index 0000000000..5c3f76d89b
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_mib_storage.erl
@@ -0,0 +1,181 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(snmpa_mib_storage).
+
+-export_type([
+ mib_storage_fields/0,
+ mib_storage_table_type/0,
+ mib_storage_table_id/0
+ ]).
+
+
+%%% ----------------------------------------------------------------
+%%% This behaviour module defines the API for the mib-storage.
+%%% This is how the agent stores its internal mib-data
+%%% (symbolic-store and mib-server).
+%%%-----------------------------------------------------------------
+
+-type mib_storage_fields() :: [atom()].
+-type mib_storage_table_type() :: set | bag.
+-type mib_storage_table_id() :: term().
+
+
+%% ---------------------------------------------------------------
+%% open
+%%
+%% Open or create a mib-storage table.
+%% If any extra info needs to be communicated to the implementor
+%% (of the behaviour), this is done using the *Options* argument.
+%% ---------------------------------------------------------------
+
+%% Options is callback module dependant
+
+-callback open(Name :: atom(),
+ RecName :: atom(),
+ Fields :: mib_storage_fields(),
+ Type :: mib_storage_table_type(),
+ Options :: list()) ->
+ {ok, TabId :: mib_storage_table_id()} | {error, Reason :: term()}.
+
+
+%% ---------------------------------------------------------------
+%% close
+%%
+%% Close the mib-storage table. What this does is up to the
+%% implementor (when using mnesia it may be a no-op but for ets
+%% it may actually delete the table).
+%% ---------------------------------------------------------------
+
+-callback close(TabId :: mib_storage_table_id()) ->
+ term().
+
+
+%% ---------------------------------------------------------------
+%% read/2
+%%
+%% Retrieve a record from the mib-storage table.
+%% ---------------------------------------------------------------
+
+-callback read(TabId :: mib_storage_table_id(),
+ Key :: term()) ->
+ false | {value, Record :: tuple()}.
+
+
+%% ---------------------------------------------------------------
+%% write/2
+%%
+%% Write a record to the mib-storage table.
+%% ---------------------------------------------------------------
+
+-callback write(TabId :: mib_storage_table_id(),
+ Record :: tuple()) ->
+ ok | {error, Reason :: term()}.
+
+
+%% ---------------------------------------------------------------
+%% delete/1
+%%
+%% Delete the mib-storage table.
+%% ---------------------------------------------------------------
+
+-callback delete(TabId :: mib_storage_table_id()) ->
+ snmp:void().
+
+
+%% ---------------------------------------------------------------
+%% delete/2
+%%
+%% Delete a record from the mib-storage table.
+%% ---------------------------------------------------------------
+
+-callback delete(TabId :: mib_storage_table_id(),
+ Key :: term()) ->
+ ok | {error, Reason :: term()}.
+
+
+%% ---------------------------------------------------------------
+%% match_object
+%%
+%% Search the mib-storage table for records which matches
+%% the pattern.
+%% ---------------------------------------------------------------
+
+-callback match_object(TabId :: mib_storage_table_id(),
+ Pattern :: ets:match_pattern()) ->
+ {ok, Recs :: [tuple()]} | {error, Reason :: term()}.
+
+
+%% ---------------------------------------------------------------
+%% match_delete
+%%
+%% Search the mib-storage table for records which matches the
+%% pattern and deletes them from the database and return the
+%5 deleted records.
+%% ---------------------------------------------------------------
+
+-callback match_delete(TabId :: mib_storage_table_id(),
+ Pattern :: ets:match_pattern()) ->
+ {ok, Recs :: [tuple()]} | {error, Reason :: term()}.
+
+
+%% ---------------------------------------------------------------
+%% tab2list
+%%
+%% Return all records in the table in the form of a list.
+%% ---------------------------------------------------------------
+
+-callback tab2list(TabId :: mib_storage_table_id()) ->
+ [tuple()].
+
+
+%% ---------------------------------------------------------------
+%% info/1,2
+%%
+%% Retrieve implementation dependent mib-storage table
+%% information.
+%% ---------------------------------------------------------------
+
+-callback info(TabId :: mib_storage_table_id()) ->
+ Info :: term().
+
+-callback info(TabId :: mib_storage_table_id(), Item :: atom()) ->
+ Info :: term().
+
+
+%% ---------------------------------------------------------------
+%% sync
+%%
+%% Dump mib-storage table to disc (if it has a disk component).
+%% ---------------------------------------------------------------
+
+-callback sync(TabId :: mib_storage_table_id()) ->
+ snmp:void().
+
+
+%% ---------------------------------------------------------------
+%% backup
+%%
+%% Make a backup copy of the mib-storage table.
+%% ---------------------------------------------------------------
+
+-callback backup(TabId :: mib_storage_table_id(),
+ Dir :: file:filename()) ->
+ ok | {error, Reason :: term()}.
+
diff --git a/lib/snmp/src/agent/snmpa_mib_storage_dets.erl b/lib/snmp/src/agent/snmpa_mib_storage_dets.erl
new file mode 100644
index 0000000000..e84e18e7ea
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_mib_storage_dets.erl
@@ -0,0 +1,309 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(snmpa_mib_storage_dets).
+
+-behaviour(snmpa_mib_storage).
+
+
+%%%-----------------------------------------------------------------
+%%% This module implements the snmpa_mib_storage behaviour.
+%%% It uses dets for storage.
+%%%-----------------------------------------------------------------
+
+-export([
+ open/5,
+ close/1,
+ read/2,
+ write/2,
+ delete/1,
+ delete/2,
+ match_object/2,
+ match_delete/2,
+ tab2list/1,
+ info/1, info/2,
+ sync/1,
+ backup/2
+ ]).
+
+
+-define(VMODULE, "MS-DETS").
+-include("snmp_verbosity.hrl").
+
+-record(tab, {id, rec_name}).
+
+
+%% ---------------------------------------------------------------
+%% open
+%%
+%% Open or create a mib-storage (dets) table.
+%%
+%% Opts - A list of implementation dependent options
+%% dets_open_options() = [dets_open_option()]
+%% dets_open_option() = {dir, filename()} |
+%% {action, keep | clear} |
+%% {auto_save, default | pos_integer()} |
+%% {repair, force | boolean()}
+%%
+%% ---------------------------------------------------------------
+
+open(Name, RecName, _Fields, Type, Opts) ->
+ Dir = snmp_misc:get_option(dir, Opts),
+ Action = snmp_misc:get_option(action, Opts, keep),
+ AutoSave = snmp_misc:get_option(auto_save, Opts, default),
+ Repair = snmp_misc:get_option(repair, Opts, false),
+ File = dets_filename(Name, Dir),
+ OpenOpts = [{file, File},
+ {type, Type},
+ {keypos, 2},
+ {repair, Repair}] ++
+ case AutoSave of
+ default ->
+ [];
+ _ ->
+ [{auto_save, AutoSave}]
+ end,
+ case dets:open_file(Name, OpenOpts) of
+ {ok, ID} when (Action =:= keep) ->
+ {ok, #tab{id = ID, rec_name = RecName}};
+ {ok, ID} when (Action =:= clear) ->
+ dets:match_delete(ID, '_'),
+ {ok, #tab{id = ID, rec_name = RecName}};
+ {error, Reason} ->
+ {error, {dets_open, Reason}}
+ end.
+
+dets_filename(Name, Dir) ->
+ Dir1 = dets_filename1(Dir),
+ Dir2 = string:strip(Dir1, right, $/),
+ io_lib:format("~s/~p.dat", [Dir2, Name]).
+
+dets_filename1([]) -> ".";
+dets_filename1(Dir) -> Dir.
+
+
+%% ---------------------------------------------------------------
+%% close
+%%
+%% Close the table.
+%% ---------------------------------------------------------------
+
+close(#tab{id = ID}) ->
+ ?vtrace("close database ~p", [ID]),
+ dets:close(ID).
+
+
+%% ---------------------------------------------------------------
+%% read
+%%
+%% Retrieve a record from the database table.
+%% ---------------------------------------------------------------
+
+read(#tab{id = ID}, Key) ->
+ ?vtrace("read from table ~p: ~p", [ID, Key]),
+ case dets:lookup(ID, Key) of
+ [Rec|_] -> {value, Rec};
+ _ -> false
+ end.
+
+
+%% ---------------------------------------------------------------
+%% write
+%%
+%% Write a record to the database table.
+%% ---------------------------------------------------------------
+
+write(#tab{id = ID, rec_name = RecName}, Rec)
+ when (is_tuple(Rec) andalso (element(1, Rec) =:= RecName)) ->
+ ?vtrace("write to table ~p", [ID]),
+ dets:insert(ID, Rec).
+
+
+%% ---------------------------------------------------------------
+%% delete
+%%
+%% Delete the database table.
+%% ---------------------------------------------------------------
+
+delete(#tab{id = ID}) ->
+ ?vtrace("delete database ~p", [ID]),
+ File = dets:info(ID, filename),
+ case dets:close(ID) of
+ ok ->
+ file:delete(File);
+ Error ->
+ Error
+ end.
+
+
+%% ---------------------------------------------------------------
+%% delete
+%%
+%% Delete a record from the database table.
+%% ---------------------------------------------------------------
+
+delete(#tab{id = ID}, Key) ->
+ ?vtrace("delete from table ~p: ~p", [ID, Key]),
+ dets:delete(ID, Key).
+
+
+%% ---------------------------------------------------------------
+%% match_object
+%%
+%% Search the database table for records witch matches the pattern.
+%% ---------------------------------------------------------------
+
+match_object(#tab{id = ID}, Pattern) ->
+ ?vtrace("match_object in ~p of ~p", [ID, Pattern]),
+ dets:match_object(ID, Pattern).
+
+
+%% ---------------------------------------------------------------
+%% match_delete
+%%
+%% Search the database table for records witch matches the
+%% pattern and deletes them from the database table.
+%% ---------------------------------------------------------------
+
+match_delete(#tab{id = ID}, Pattern) ->
+ ?vtrace("match_delete in ~p with pattern ~p", [ID, Pattern]),
+ Recs = dets:match_object(ID, Pattern),
+ dets:match_delete(ID, Pattern),
+ Recs.
+
+
+%% ---------------------------------------------------------------
+%% tab2list
+%%
+%% Return all records in the table in the form of a list.
+%% ---------------------------------------------------------------
+
+tab2list(#tab{id = ID} = Tab) ->
+ ?vtrace("tab2list -> list of ~p", [ID]),
+ match_object(Tab, '_').
+
+
+%% ---------------------------------------------------------------
+%% info
+%%
+%% Retrieve implementation dependent mib-storage table
+%% information.
+%% ---------------------------------------------------------------
+
+info(#tab{id = ID}) ->
+ ?vtrace("info -> info of ~p", [ID]),
+ dets:info(ID).
+
+
+info(TabId, all = _Item) ->
+ info(TabId);
+info(#tab{id = ID}, memory = _Item) ->
+ ?vtrace("info on ~p (~w)", [ID, _Item]),
+ dets:info(ID, file_size);
+info(#tab{id = ID}, Item) ->
+ ?vtrace("info on ~p (~w)", [ID, Item]),
+ dets:info(ID, Item).
+
+
+%% ---------------------------------------------------------------
+%% sync
+%%
+%% Dump mib-storage table to disc (if it has a disk component)
+%% ---------------------------------------------------------------
+
+sync(#tab{id = ID}) ->
+ ?vtrace("sync -> sync ~p", [ID]),
+ dets:sync(ID).
+
+
+%% ---------------------------------------------------------------
+%% backup
+%%
+%% Make a backup copy of the mib-storage table.
+%% ---------------------------------------------------------------
+
+backup(#tab{id = ID}, BackupDir) ->
+ ?vtrace("backup -> backup of ~p to ~p", [ID, BackupDir]),
+ case dets:info(ID, filename) of
+ undefined ->
+ {error, no_file};
+ Filename ->
+ case filename:dirname(Filename) of
+ BackupDir ->
+ {error, db_dir};
+ _ ->
+ Type = dets:info(ID, type),
+ KP = dets:info(ID, keypos),
+ dets_backup(ID,
+ filename:basename(Filename),
+ BackupDir, Type, KP)
+ end
+ end.
+
+
+dets_backup(ID, Filename, BackupDir, Type, KP) ->
+ ?vtrace("dets_backup -> entry with"
+ "~n ID: ~p"
+ "~n Filename: ~p"
+ "~n BackupDir: ~p"
+ "~n Type: ~p"
+ "~n KP: ~p", [ID, Filename, BackupDir, Type, KP]),
+ BackupFile = filename:join(BackupDir, Filename),
+ ?vtrace("dets_backup -> "
+ "~n BackupFile: ~p", [BackupFile]),
+ Backup = list_to_atom(atom_to_list(ID) ++ "_backup"),
+ Opts = [{file, BackupFile}, {type, Type}, {keypos, KP}],
+ case dets:open_file(Backup, Opts) of
+ {ok, B} ->
+ ?vtrace("dets_backup -> create fun", []),
+ F = fun(Arg) ->
+ dets_backup(Arg, start, ID, B)
+ end,
+ dets:safe_fixtable(ID, true),
+ Res = dets:init_table(Backup, F, [{format, bchunk}]),
+ dets:safe_fixtable(ID, false),
+ ?vtrace("dets_backup -> Res: ~p", [Res]),
+ Res;
+ Error ->
+ ?vinfo("dets_backup -> open_file failed: "
+ "~n ~p", [Error]),
+ Error
+ end.
+
+dets_backup(close, _Cont, _ID, B) ->
+ dets:close(B),
+ ok;
+dets_backup(read, Cont1, ID, B) ->
+ case dets:bchunk(ID, Cont1) of
+ {Cont2, Data} ->
+ F = fun(Arg) ->
+ dets_backup(Arg, Cont2, ID, B)
+ end,
+ {Data, F};
+ '$end_of_table' ->
+ dets:close(B),
+ end_of_input;
+ Error ->
+ Error
+ end.
+
+
+%%----------------------------------------------------------------------
+
+%% user_err(F, A) ->
+%% snmpa_error:user_err(F, A).
diff --git a/lib/snmp/src/agent/snmpa_mib_storage_ets.erl b/lib/snmp/src/agent/snmpa_mib_storage_ets.erl
new file mode 100644
index 0000000000..04faf46864
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_mib_storage_ets.erl
@@ -0,0 +1,341 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(snmpa_mib_storage_ets).
+
+-behaviour(snmpa_mib_storage).
+
+%%%-----------------------------------------------------------------
+%%% This module implements the snmpa_mib_storage behaviour.
+%%% It uses ets for storage.
+%%%-----------------------------------------------------------------
+
+-export([
+ open/5,
+ close/1,
+ read/2,
+ write/2,
+ delete/1,
+ delete/2,
+ match_object/2,
+ match_delete/2,
+ tab2list/1,
+ info/1, info/2,
+ sync/1,
+ backup/2
+ ]).
+
+
+-define(VMODULE,"MS-ETS").
+-include("snmp_verbosity.hrl").
+
+-record(tab, {id, rec_name, file, checksum = false}).
+
+
+%% ---------------------------------------------------------------
+%% open
+%%
+%% Open or create an ets table.
+%% Possibly also read data from a (specified) file (mirror) and
+%% populate the table from that (the dir option).
+%%
+%% Opts - A list of implementation dependent options
+%% ets_open_options() = [ets_open_option()]
+%% ets_open_option() = {dir, filename()} |
+%% {action, keep | clear} |
+%% {checksum, boolean()}
+%%
+%% The RecName and Fields arguments are not used in this
+%% implementation.
+%%
+%% ---------------------------------------------------------------
+
+%% This function creates the ets table
+open(Name, RecName, _Fields, Type, Opts) ->
+ ?vtrace("open table ~p", [Name]),
+ case lists:keysearch(dir, 1, Opts) of
+ {value, {dir, Dir}} ->
+ Action = snmp_misc:get_option(action, Opts, keep),
+ Checksum = snmp_misc:get_option(checksum, Opts, false),
+ ?vtrace("open ~p database ~p - check if file exist", [Type, Name]),
+ File = filename:join(Dir, atom_to_list(Name) ++ ".db"),
+ case file:read_file_info(File) of
+ {ok, _} ->
+ ?vdebug("open ~p database ~p - file exist - try reading",
+ [Type, Name]),
+ case ets:file2tab(File, [{verify, Checksum}]) of
+ {ok, ID} ->
+ ?vtrace("open ~p database ~p - "
+ "data read from file", [Type, Name]),
+ {ok, #tab{id = ID,
+ rec_name = RecName,
+ file = File,
+ checksum = Checksum}};
+ {error, Reason} when (Action =:= keep) ->
+ ?vinfo("open ~p database ~p - "
+ "failed reading from file (keep): "
+ "~n ~p",
+ [Type, Name, Reason]),
+ {error, {file2tab, Reason}};
+ {error, Reason} ->
+ ?vlog("open ~p database ~p - "
+ "failed reading from file (clear): "
+ "~n ~p", [Type, Name, Reason]),
+ user_err("Warning: could not read file - "
+ "create new (empty): "
+ "~n File: ~p"
+ "~n Reason: ~p", [File, Reason]),
+ ID = ets:new(Name, [Type, protected, {keypos, 2}]),
+ write_ets_file(ID, File, Checksum),
+ {ok, #tab{id = ID,
+ rec_name = RecName,
+ file = File,
+ checksum = Checksum}}
+ end;
+ {error, enoent} ->
+ %% No such file - create it
+ ?vdebug("open ~p database ~p - "
+ "file does *not* exist - create",
+ [Type, Name]),
+ ID = ets:new(Name, [Type, protected, {keypos, 2}]),
+ write_ets_file(ID, File, Checksum),
+ {ok, #tab{id = ID,
+ rec_name = RecName,
+ file = File,
+ checksum = Checksum}};
+ {error, Reason} when (Action =:= keep) ->
+ ?vinfo("open ~p database ~p - "
+ "failed reading file info (keep): "
+ "~n ~p",
+ [Type, Name, Reason]),
+ {error, {read_file_info, Reason}};
+ {error, Reason} ->
+ ?vlog("open ~p database ~p - "
+ "failed reading file info (clear): "
+ "~n ~p",
+ [Type, Name, Reason]),
+ user_err("Warning: could not read file info - "
+ "create new file: "
+ "~n File: ~p"
+ "~n Reason: ~p", [File, Reason]),
+ ID = ets:new(Name, [Type, protected, {keypos, 2}]),
+ write_ets_file(ID, File, Checksum),
+ {ok, #tab{id = ID,
+ rec_name = RecName,
+ file = File,
+ checksum = Checksum}}
+ end;
+ false ->
+ ?vdebug("open ~p database ~p - ok", [Type, Name]),
+ ID = ets:new(Name, [Type, protected, {keypos, 2}]),
+ {ok, #tab{id = ID, rec_name = RecName}}
+ end.
+
+
+%% ---------------------------------------------------------------
+%% close
+%%
+%% Close the mib-storage table.
+%% We will delete the table and if there is a file component,
+%% will also be written to file.
+%% ---------------------------------------------------------------
+close(#tab{id = ID, file = undefined}) ->
+ ?vtrace("close (delete) table ~p", [ID]),
+ ets:delete(ID);
+close(#tab{id = ID, file = File, checksum = Checksum}) ->
+ ?vtrace("close (delete) table ~p", [ID]),
+ write_ets_file(ID, File, Checksum),
+ ets:delete(ID).
+
+
+%% ---------------------------------------------------------------
+%% read
+%%
+%% Retrieve a record from the mib-storage table.
+%% ---------------------------------------------------------------
+
+read(#tab{id = ID}, Key) ->
+ ?vtrace("read from table ~p: ~p", [ID, Key]),
+ case ets:lookup(ID, Key) of
+ [Rec|_] -> {value, Rec};
+ _ -> false
+ end.
+
+
+%% ---------------------------------------------------------------
+%% write
+%%
+%% Write a record to the mib-storage table.
+%% ---------------------------------------------------------------
+
+%% This is a very crude guard test is used instead of: is_record(Rec, RecName)
+write(#tab{id = ID, rec_name = RecName}, Rec)
+ when (is_tuple(Rec) andalso (element(1, Rec) =:= RecName)) ->
+ ?vtrace("write to table ~p", [ID]),
+ ets:insert(ID, Rec).
+
+
+%% ---------------------------------------------------------------
+%% delete
+%%
+%% Delete the mib-storage table.
+%% ---------------------------------------------------------------
+delete(#tab{id = ID, file = undefined}) ->
+ ?vtrace("delete table ~p", [ID]),
+ ets:delete(ID);
+delete(#tab{id = ID, file = File}) ->
+ ?vtrace("delete table ~p", [ID]),
+ file:delete(File),
+ ets:delete(ID).
+
+
+%% ---------------------------------------------------------------
+%% delete
+%%
+%% Delete a record from the mib-storage table.
+%% ---------------------------------------------------------------
+delete(#tab{id = ID}, Key) ->
+ ?vtrace("delete from table ~p: ~p", [ID, Key]),
+ ets:delete(ID, Key).
+
+
+%% ---------------------------------------------------------------
+%% match_object
+%%
+%% Search the mib-storage table for records witch matches
+%% the pattern.
+%% ---------------------------------------------------------------
+
+match_object(#tab{id = ID}, Pattern) ->
+ ?vtrace("match_object in ~p of ~p", [ID, Pattern]),
+ ets:match_object(ID, Pattern).
+
+
+%% ---------------------------------------------------------------
+%% match_delete
+%%
+%% Search the mib-storage table for records witch matches
+%% the pattern and deletes them from the table.
+%% ---------------------------------------------------------------
+
+match_delete(#tab{id = ID}, Pattern) ->
+ ?vtrace("match_delete in ~p with pattern ~p", [ID, Pattern]),
+ Recs = ets:match_object(ID, Pattern),
+ ets:match_delete(ID, Pattern),
+ Recs.
+
+
+%% ---------------------------------------------------------------
+%% tab2list
+%%
+%% Return all records in the mib-storage table in the form
+%% of a list.
+%% ---------------------------------------------------------------
+
+tab2list(#tab{id = ID}) ->
+ ?vtrace("tab2list -> list of ~p", [ID]),
+ ets:tab2list(ID).
+
+
+
+%% ---------------------------------------------------------------
+%% info/1,2
+%%
+%% Retrieve implementation dependent mib-storage table
+%% information.
+%% ---------------------------------------------------------------
+info(#tab{id = ID}) ->
+ ?vtrace("info on ~p", [ID]),
+ case ets:info(ID) of
+ undefined ->
+ [];
+ L ->
+ L
+ end.
+
+
+info(TabId, all = _Item) ->
+ info(TabId);
+info(#tab{id = ID}, Item) ->
+ ?vtrace("info on ~p", [ID]),
+ ets:info(ID, Item).
+
+
+%% ---------------------------------------------------------------
+%% sync
+%%
+%% Dump mib-storage table to disc (if there is a file compionent)
+%% ---------------------------------------------------------------
+
+sync(#tab{file = undefined}) ->
+ ok;
+sync(#tab{id = ID, file = File, checksum = Checksum}) ->
+ ?vtrace("sync ~p", [ID]),
+ write_ets_file(ID, File, Checksum).
+
+
+%% ---------------------------------------------------------------
+%% backup
+%%
+%% Make a backup copy of the mib-storage table. Only valid id
+%% there is a file component.
+%% ---------------------------------------------------------------
+
+backup(#tab{file = undefined}, _BackupDir) ->
+ ok;
+backup(#tab{id = ID, file = File, checksum = Checksum}, BackupDir) ->
+ ?vtrace("backup ~p to ~p", [ID, BackupDir]),
+ Filename = filename:basename(File),
+ case filename:join(BackupDir, Filename) of
+ File ->
+ %% Oups: backup-dir and db-dir the same
+ {error, db_dir};
+ BackupFile ->
+ write_ets_file(ID, BackupFile, Checksum)
+ end.
+
+
+%%----------------------------------------------------------------------
+
+write_ets_file(ID, File, Checksum) when (Checksum =:= true) ->
+ do_write_ets_file(ID, File, [{extended_info, [md5sum]}]);
+write_ets_file(ID, File, Checksum) when (Checksum =:= false) ->
+ do_write_ets_file(ID, File, []).
+
+do_write_ets_file(ID, File, Options) ->
+ TmpFile = File ++ ".tmp",
+ case ets:tab2file(ID, TmpFile, Options) of
+ ok ->
+ case file:rename(TmpFile, File) of
+ ok ->
+ ok;
+ Else ->
+ user_err("Warning: could not move file ~p"
+ " (~p)", [File, Else])
+ end;
+ {error, Reason} ->
+ user_err("Warning: could not save file ~p (~p)",
+ [File, Reason])
+ end.
+
+
+%%----------------------------------------------------------------------
+
+user_err(F, A) ->
+ snmpa_error:user_err(F, A).
diff --git a/lib/snmp/src/agent/snmpa_mib_storage_mnesia.erl b/lib/snmp/src/agent/snmpa_mib_storage_mnesia.erl
new file mode 100644
index 0000000000..192b5aa26e
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_mib_storage_mnesia.erl
@@ -0,0 +1,302 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(snmpa_mib_storage_mnesia).
+
+
+-behaviour(snmpa_mib_storage).
+
+%%%-----------------------------------------------------------------
+%%% This module implements the snmpa_mib_storage behaviour.
+%%% It uses mnesia for storage.
+%%%-----------------------------------------------------------------
+
+-export([
+ open/5,
+ close/1,
+ read/2,
+ write/2,
+ delete/1,
+ delete/2,
+ match_object/2,
+ match_delete/2,
+ tab2list/1,
+ info/1, info/2,
+ sync/1,
+ backup/2
+ ]).
+
+
+-define(VMODULE,"MS-MNESIA").
+-include("snmp_verbosity.hrl").
+
+-record(tab, {id}).
+
+
+%% ---------------------------------------------------------------
+%% open
+%%
+%% Open or create a mnesia table.
+%%
+%% Opts - A list of implementation dependent options
+%% mnesia_open_options() = [mnesia_open_option()]
+%% mnesia_open_option() = {action, keep | clear} |
+%% {nodes, [node()]}
+%%
+%% ---------------------------------------------------------------
+
+open(Name, RecName, Fields, Type, Opts) ->
+ ?vtrace("open ~p table ~p for record ~p",
+ [Type, Name, RecName]),
+ Action = get_action(Opts),
+ Nodes = get_nodes(Opts),
+ case table_exists(Name) of
+ true when (Action =:= keep) ->
+ ?vtrace("open table ~p - exist (keep)", [Name]),
+ {ok, #tab{id = Name}};
+ true when (Action =:= clear) ->
+ ?vtrace("open table ~p - exist (clear)", [Name]),
+ F = fun() -> mnesia:clear_table(Name) end,
+ case mnesia:transaction(F) of
+ {aborted, Reason} ->
+ {error, {clear, Reason}};
+ {atomic, _} ->
+ {ok, #tab{id = Name}}
+ end;
+ false ->
+ ?vtrace("open table ~p - does not exist", [Name]),
+ Args = [{record_name, RecName},
+ {attributes, Fields},
+ {type, Type},
+ {disc_copies, Nodes}],
+ case mnesia:create_table(Name, Args) of
+ {atomic, ok} ->
+ ?vtrace("open table ~p - ok", [Name]),
+ {ok, #tab{id = Name}};
+ {aborted, Reason} ->
+ ?vinfo("open table ~p - aborted"
+ "~n Reason: ~p", [Name, Reason]),
+ {error, {create, Reason}}
+ end
+ end.
+
+table_exists(Name) ->
+ case (catch mnesia:table_info(Name, type)) of
+ {'EXIT', _Reason} ->
+ false;
+ _ ->
+ true
+ end.
+
+
+%% ---------------------------------------------------------------
+%% close
+%%
+%% Close the mib-storage table.
+%% This does nothing in the mnesia case.
+%% ---------------------------------------------------------------
+
+close(_) ->
+ ?vtrace("close mib-storage - ignore",[]),
+ ok.
+
+
+%% ---------------------------------------------------------------
+%% read
+%%
+%% Retrieve a record from the mib-storage table.
+%% ---------------------------------------------------------------
+
+read(#tab{id = ID}, Key) ->
+ ?vtrace("read (dirty) from database ~p: ~p", [ID, Key]),
+ case (catch mnesia:dirty_read(ID, Key)) of
+ [Rec|_] -> {value,Rec};
+ _ -> false
+ end.
+
+
+%% ---------------------------------------------------------------
+%% write
+%%
+%% Write a record to the mib-storage table.
+%% ---------------------------------------------------------------
+
+write(#tab{id = ID}, Rec) ->
+ ?vtrace("write to database ~p", [ID]),
+ F = fun() -> mnesia:write(ID, Rec, write) end,
+ case mnesia:transaction(F) of
+ {aborted, _Reason} = ABORTED ->
+ {error, ABORTED};
+ {atomic,_} ->
+ ok
+ end.
+
+
+%% ---------------------------------------------------------------
+%% delete
+%%
+%% Delete the mib-storage table.
+%% ---------------------------------------------------------------
+
+delete(#tab{id = ID}) ->
+ ?vtrace("delete database: ~p", [ID]),
+ mnesia:delete_table(ID).
+
+
+%% ---------------------------------------------------------------
+%% delete
+%%
+%% Delete a record from the mib-storage table.
+%% ---------------------------------------------------------------
+
+delete(#tab{id = ID}, Key) ->
+ ?vtrace("delete from database ~p: ~p", [ID, Key]),
+ F = fun() -> mnesia:delete(ID, Key, write) end,
+ case mnesia:transaction(F) of
+ {aborted, _Reason} = ABORTED ->
+ {error, ABORTED};
+ {atomic, _} ->
+ ok
+ end.
+
+
+%% ---------------------------------------------------------------
+%% match_object
+%%
+%% Search the mib-storage table for records witch matches
+%% the pattern.
+%% ---------------------------------------------------------------
+
+match_object(#tab{id = ID}, Pattern) ->
+ ?vtrace("match_object in ~p of ~p", [ID, Pattern]),
+ F = fun() -> mnesia:match_object(ID, Pattern, read) end,
+ case mnesia:transaction(F) of
+ {aborted, _Reason} = ABORTED ->
+ {error, ABORTED};
+ {atomic, Rs} ->
+ Rs
+ end.
+
+
+%% ---------------------------------------------------------------
+%% match_delete
+%%
+%% Search the mib-storage table for records witch matches
+%% the pattern and deletes them from the table.
+%% ---------------------------------------------------------------
+
+match_delete(#tab{id = ID}, Pattern) ->
+ ?vtrace("match_delete in ~p with pattern ~p", [ID, Pattern]),
+ F = fun() ->
+ Recs = mnesia:match_object(ID, Pattern, read),
+ lists:foreach(fun(Rec) ->
+ mnesia:delete_object(ID, Rec, write)
+ end, Recs),
+ Recs
+ end,
+ case mnesia:transaction(F) of
+ {aborted, _Reason} = ABORTED ->
+ {error, ABORTED};
+ {atomic, Rs} ->
+ Rs
+ end.
+
+
+%% ---------------------------------------------------------------
+%% tab2list
+%%
+%% Return all records in the mib-storage table in the form of
+%% a list.
+%% ---------------------------------------------------------------
+
+tab2list(#tab{id = ID} = Tab) ->
+ ?vtrace("tab2list -> list of ~p", [ID]),
+ match_object(Tab, mnesia:table_info(ID, wild_pattern)).
+
+
+%% ---------------------------------------------------------------
+%% info
+%%
+%% Retrieve implementation dependent mib-storage table
+%% information.
+%% ---------------------------------------------------------------
+
+info(#tab{id = ID}) ->
+ case (catch mnesia:table_info(ID, all)) of
+ Info when is_list(Info) ->
+ Info;
+ {'EXIT', {aborted, Reason}} ->
+ {error, Reason}
+ end.
+
+
+info(#tab{id = ID}, Item) ->
+ mnesia:table_info(ID, Item).
+
+
+%% ---------------------------------------------------------------
+%% sync
+%%
+%% Ignore
+%% ---------------------------------------------------------------
+
+sync(_) ->
+ ok.
+
+
+%% ---------------------------------------------------------------
+%% backup
+%%
+%% Ignore. Mnesia handles its own backups.
+%% ---------------------------------------------------------------
+
+backup(_, _) ->
+ ok.
+
+
+%%----------------------------------------------------------------------
+
+get_action(Opts) ->
+ snmp_misc:get_option(action, Opts, keep).
+
+get_nodes(Opts) ->
+ case snmp_misc:get_option(nodes, Opts, erlang:nodes()) of
+ [] ->
+ [node()];
+ Nodes when is_list(Nodes) ->
+ Nodes;
+ all ->
+ erlang:nodes();
+ visible ->
+ erlang:nodes(visible);
+ connected ->
+ erlang:nodes(connected);
+ db_nodes ->
+ try mnesia:system_info(db_nodes) of
+ DbNodes when is_list(DbNodes) ->
+ DbNodes;
+ _ ->
+ erlang:nodes()
+ catch
+ _:_ ->
+ erlang:nodes()
+ end
+ end.
+
+%% user_err(F, A) ->
+%% snmpa_error:user_err(F, A).
diff --git a/lib/snmp/src/agent/snmpa_supervisor.erl b/lib/snmp/src/agent/snmpa_supervisor.erl
index 886fd074bc..aebcdbaa84 100644
--- a/lib/snmp/src/agent/snmpa_supervisor.erl
+++ b/lib/snmp/src/agent/snmpa_supervisor.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -224,26 +224,101 @@ init([AgentType, Opts]) ->
ets:insert(snmp_agent_table, {error_report_mod, ErrorReportMod}),
%% -- mib storage --
+ %% MibStorage has only one mandatory part: module
+ %% Everything else is module dependent and therefor
+ %% put in a special option: options
MibStorage =
- case get_opt(mib_storage, Opts, ets) of
+ case get_opt(mib_storage, Opts, [{module, snmpa_mib_storage_ets}]) of
+
+ %% --- ETS wrappers ---
+
+ ets ->
+ [{module, snmpa_mib_storage_ets}];
+ {ets, default} ->
+ [{module, snmpa_mib_storage_ets},
+ {options, [{dir, filename:join([DbDir])},
+ {action, keep}]}];
+ {ets, Dir} when is_list(Dir) ->
+ [{module, snmpa_mib_storage_ets},
+ {options, [{dir, filename:join([Dir])},
+ {action, keep}]}];
+ {ets, default, Action} when ((Action =:= keep) orelse
+ (Action =:= clear)) ->
+ [{module, snmpa_mib_storage_ets},
+ {options, [{dir, filename:join([DbDir])},
+ {action, Action}]}];
+ {ets, Dir, Action} when is_list(Dir) andalso
+ ((Action =:= keep) orelse
+ (Action =:= clear)) ->
+ [{module, snmpa_mib_storage_ets},
+ {options, [{dir, filename:join([Dir])},
+ {action, Action}]}];
+
+ %% --- DETS wrappers ---
+
dets ->
- {dets, DbDir};
+ [{module, snmpa_mib_storage_dets},
+ {options, [{dir, filename:join([DbDir])},
+ {action, keep}]}];
{dets, default} ->
- {dets, DbDir};
- {dets, default, Act} ->
- {dets, DbDir, Act};
- {ets, default} ->
- {ets, DbDir};
+ [{module, snmpa_mib_storage_dets},
+ {options, [{dir, filename:join([DbDir])},
+ {action, keep}]}];
+ {dets, default, Action} when ((Action =:= keep) orelse
+ (Action =:= clear)) ->
+ [{module, snmpa_mib_storage_dets},
+ {options, [{dir, filename:join([DbDir])},
+ {action, Action}]}];
+ {dets, Dir, Action} when is_list(Dir) andalso
+ ((Action =:= keep) orelse
+ (Action =:= clear)) ->
+ [{module, snmpa_mib_storage_dets},
+ {options, [{dir, filename:join([Dir])},
+ {action, Action}]}];
+
+ %% --- Mnesia wrappers ---
+
mnesia ->
- {mnesia, erlang:nodes()};
- {mnesia, visible} ->
- {mnesia, erlang:nodes(visible)};
- {mnesia, connected} ->
- {mnesia, erlang:nodes(connected)};
- Other ->
+ [{module, snmpa_mib_storage_mnesia},
+ {options, [{nodes, erlang:nodes()},
+ {action, keep}]}];
+ {mnesia, Nodes0} ->
+ Nodes =
+ if
+ Nodes0 =:= visible ->
+ erlang:nodes(visible);
+ Nodes0 =:= connected ->
+ erlang:nodes(connected);
+ Nodes0 =:= [] ->
+ [node()];
+ true ->
+ Nodes0
+ end,
+ [{module, snmpa_mib_storage_mnesia},
+ {options, [{nodes, Nodes},
+ {action, keep}]}];
+ {mnesia, Nodes0, Action} when ((Action =:= keep) orelse
+ (Action =:= clear)) ->
+ Nodes =
+ if
+ Nodes0 =:= visible ->
+ erlang:nodes(visible);
+ Nodes0 =:= connected ->
+ erlang:nodes(connected);
+ Nodes0 =:= [] ->
+ [node()];
+ true ->
+ Nodes0
+ end,
+ [{module, snmpa_mib_storage_mnesia},
+ {options, [{nodes, Nodes},
+ {action, Action}]}];
+
+ Other when is_list(Other) ->
Other
end,
- ?vdebug("[agent table] store mib storage: ~w",[MibStorage]),
+
+ ?vdebug("[agent table] store mib storage: ~w", [MibStorage]),
ets:insert(snmp_agent_table, {mib_storage, MibStorage}),
%% -- Agent mib storage --
@@ -388,7 +463,7 @@ init([AgentType, Opts]) ->
AgentSpec =
worker_spec(snmpa_agent,
- [Prio,snmp_master_agent,none,Ref,AgentOpts],
+ [Prio, snmp_master_agent, none, Ref, AgentOpts],
Restart, 15000),
AgentSupSpec =
sup_spec(snmpa_agent_sup, [AgentSpec],
diff --git a/lib/snmp/src/agent/snmpa_symbolic_store.erl b/lib/snmp/src/agent/snmpa_symbolic_store.erl
index 6c58ffde41..00178f4bcd 100644
--- a/lib/snmp/src/agent/snmpa_symbolic_store.erl
+++ b/lib/snmp/src/agent/snmpa_symbolic_store.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -78,7 +78,7 @@
gen_server:start_link({local, ?SERVER}, ?MODULE, [Prio, Opts], [])).
-endif.
--record(state, {db, backup}).
+-record(state, {module, db, backup}).
-record(symbol, {key, mib_name, info}).
@@ -112,6 +112,9 @@ backup(BackupDir) ->
get_db() ->
call(get_db).
+which_module() ->
+ call(which_module).
+
%%----------------------------------------------------------------------
%% Returns: {value, Oid} | false
@@ -202,49 +205,63 @@ verbosity(Verbosity) ->
%%----------------------------------------------------------------------
%% DB access (read) functions: Returns: {value, Oid} | false
%%----------------------------------------------------------------------
+
aliasname_to_oid(Db, Aliasname) ->
- case snmpa_general_db:read(Db, {alias, Aliasname}) of
+ Mod = which_module(),
+ aliasname_to_oid(Mod, Db, Aliasname).
+
+aliasname_to_oid(Mod, Db, Aliasname) ->
+ case Mod:read(Db, {alias, Aliasname}) of
{value,#symbol{info = {Oid, _Enums}}} -> {value, Oid};
false -> false
end.
-oid_to_aliasname(Db,Oid) ->
- case snmpa_general_db:read(Db, {oid, Oid}) of
+oid_to_aliasname(Db, Oid) ->
+ Mod = which_module(),
+ oid_to_aliasname(Mod, Db, Oid).
+
+oid_to_aliasname(Mod, Db, Oid) ->
+ case Mod:read(Db, {oid, Oid}) of
{value,#symbol{info = Aliasname}} -> {value, Aliasname};
_ -> false
end.
-which_notifications(Db) ->
+which_notifications(Mod, Db) ->
Pattern = #symbol{key = {trap, '_'}, _ = '_'},
- Symbols = snmpa_general_db:match_object(Db, Pattern),
+ Symbols = Mod:match_object(Db, Pattern),
[{Name, Mib, Rec} || #symbol{key = {trap, Name},
mib_name = Mib,
info = Rec} <- Symbols].
-which_aliasnames(Db) ->
+which_aliasnames(Mod, Db) ->
Pattern = #symbol{key = {alias, '_'}, _ = '_'},
- Symbols = snmpa_general_db:match_object(Db, Pattern),
+ Symbols = Mod:match_object(Db, Pattern),
[Alias || #symbol{key = {alias, Alias}} <- Symbols].
-which_tables(Db) ->
+which_tables(Mod, Db) ->
Pattern = #symbol{key = {table_info, '_'}, _ = '_'},
- Symbols = snmpa_general_db:match_object(Db, Pattern),
+ Symbols = Mod:match_object(Db, Pattern),
[Name || #symbol{key = {table_info, Name}} <- Symbols].
-which_variables(Db) ->
+which_variables(Mod, Db) ->
Pattern = #symbol{key = {variable_info, '_'}, _ = '_'},
- Symbols = snmpa_general_db:match_object(Db, Pattern),
+ Symbols = Mod:match_object(Db, Pattern),
[Name || #symbol{key = {variable_info, Name}} <- Symbols].
-int_to_enum(Db,TypeOrObjName,Int) ->
- case snmpa_general_db:read(Db, {alias, TypeOrObjName}) of
+
+int_to_enum(Db, TypeOrObjName, Int) ->
+ Mod = which_module(),
+ int_to_enum(Mod, Db, TypeOrObjName, Int).
+
+int_to_enum(Mod, Db, TypeOrObjName, Int) ->
+ case Mod:read(Db, {alias, TypeOrObjName}) of
{value,#symbol{info = {_Oid, Enums}}} ->
case lists:keysearch(Int, 2, Enums) of
{value, {Enum, _Int}} -> {value, Enum};
false -> false
end;
false -> % Not an Aliasname ->
- case snmpa_general_db:read(Db, {type, TypeOrObjName}) of
+ case Mod:read(Db, {type, TypeOrObjName}) of
{value,#symbol{info = Enums}} ->
case lists:keysearch(Int, 2, Enums) of
{value, {Enum, _Int}} -> {value, Enum};
@@ -256,14 +273,18 @@ int_to_enum(Db,TypeOrObjName,Int) ->
end.
enum_to_int(Db, TypeOrObjName, Enum) ->
- case snmpa_general_db:read(Db, {alias, TypeOrObjName}) of
+ Mod = which_module(),
+ enum_to_int(Mod, Db, TypeOrObjName, Enum).
+
+enum_to_int(Mod, Db, TypeOrObjName, Enum) ->
+ case Mod:read(Db, {alias, TypeOrObjName}) of
{value,#symbol{info = {_Oid, Enums}}} ->
case lists:keysearch(Enum, 1, Enums) of
{value, {_Enum, Int}} -> {value, Int};
false -> false
end;
false -> % Not an Aliasname
- case snmpa_general_db:read(Db, {type, TypeOrObjName}) of
+ case Mod:read(Db, {type, TypeOrObjName}) of
{value,#symbol{info = Enums}} ->
case lists:keysearch(Enum, 1, Enums) of
{value, {_Enum, Int}} -> {value, Int};
@@ -278,8 +299,9 @@ enum_to_int(Db, TypeOrObjName, Enum) ->
%%----------------------------------------------------------------------
%% DB access (read) functions: Returns: false|{value, Info}
%%----------------------------------------------------------------------
-table_info(Db,TableName) ->
- case snmpa_general_db:read(Db, {table_info, TableName}) of
+
+table_info(Mod, Db, TableName) ->
+ case Mod:read(Db, {table_info, TableName}) of
{value,#symbol{info = Info}} -> {value, Info};
false -> false
end.
@@ -288,8 +310,8 @@ table_info(Db,TableName) ->
%%----------------------------------------------------------------------
%% DB access (read) functions: Returns: false|{value, Info}
%%----------------------------------------------------------------------
-variable_info(Db,VariableName) ->
- case snmpa_general_db:read(Db, {variable_info, VariableName}) of
+variable_info(Mod, Db, VariableName) ->
+ case Mod:read(Db, {variable_info, VariableName}) of
{value,#symbol{info = Info}} -> {value, Info};
false -> false
end.
@@ -299,7 +321,7 @@ variable_info(Db,VariableName) ->
%% Implementation
%%----------------------------------------------------------------------
-init([Prio,Opts]) ->
+init([Prio, Opts]) ->
?d("init -> entry with"
"~n Prio: ~p"
"~n Opts: ~p", [Prio,Opts]),
@@ -317,102 +339,125 @@ do_init(Prio, Opts) ->
put(sname,ss),
put(verbosity,get_verbosity(Opts)),
?vlog("starting",[]),
- Storage = get_mib_storage(Opts),
+ MibStorage = get_mib_storage(Opts),
+ Mod = snmp_misc:get_option(module, MibStorage),
+ MsOpts = snmp_misc:get_option(options, MibStorage, []),
+
%% type = bag solves the problem with import and multiple
%% object/type definitions.
- Db = snmpa_general_db:open(Storage, snmpa_symbolic_store,
- symbol, record_info(fields,symbol), bag),
- S = #state{db = Db},
- ?vdebug("started",[]),
- {ok, S}.
+ case Mod:open(?MODULE, symbol, record_info(fields, symbol), bag, MsOpts) of
+ {ok, Db} ->
+ S = #state{module = Mod, db = Db},
+ ?vdebug("started",[]),
+ {ok, S};
+ {error, _} = ERROR ->
+ ERROR
+ end.
handle_call(get_db, _From, #state{db = DB} = S) ->
?vlog("get db",[]),
{reply, DB, S};
-handle_call({table_info, TableName}, _From, #state{db = DB} = S) ->
+handle_call(which_module, _From, #state{module = Mod} = S) ->
+ ?vlog("which module",[]),
+ {reply, Mod, S};
+
+handle_call({table_info, TableName}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("table info: ~p",[TableName]),
- Res = table_info(DB, TableName),
+ Res = table_info(Mod, DB, TableName),
?vdebug("table info result: ~p",[Res]),
{reply, Res, S};
-handle_call({variable_info, VariableName}, _From, #state{db = DB} = S) ->
+handle_call({variable_info, VariableName}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("variable info: ~p",[VariableName]),
- Res = variable_info(DB, VariableName),
+ Res = variable_info(Mod, DB, VariableName),
?vdebug("variable info result: ~p",[Res]),
{reply, Res, S};
-handle_call({aliasname_to_oid, Aliasname}, _From, #state{db = DB} = S) ->
+handle_call({aliasname_to_oid, Aliasname}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("aliasname to oid: ~p",[Aliasname]),
- Res = aliasname_to_oid(DB,Aliasname),
+ Res = aliasname_to_oid(Mod, DB, Aliasname),
?vdebug("aliasname to oid result: ~p",[Res]),
{reply, Res, S};
-handle_call({oid_to_aliasname, Oid}, _From, #state{db = DB} = S) ->
+handle_call({oid_to_aliasname, Oid}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("oid to aliasname: ~p",[Oid]),
- Res = oid_to_aliasname(DB, Oid),
+ Res = oid_to_aliasname(Mod, DB, Oid),
?vdebug("oid to aliasname result: ~p",[Res]),
{reply, Res, S};
-handle_call(which_aliasnames, _From, #state{db = DB} = S) ->
+handle_call(which_aliasnames, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("which aliasnames",[]),
- Res = which_aliasnames(DB),
+ Res = which_aliasnames(Mod, DB),
?vdebug("which aliasnames: ~p",[Res]),
{reply, Res, S};
-handle_call(which_tables, _From, #state{db = DB} = S) ->
+handle_call(which_tables, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("which tables",[]),
- Res = which_tables(DB),
+ Res = which_tables(Mod, DB),
?vdebug("which tables: ~p",[Res]),
{reply, Res, S};
-handle_call(which_variables, _From, #state{db = DB} = S) ->
+handle_call(which_variables, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("which variables",[]),
- Res = which_variables(DB),
+ Res = which_variables(Mod, DB),
?vdebug("which variables: ~p",[Res]),
{reply, Res, S};
-handle_call({enum_to_int, TypeOrObjName, Enum}, _From, #state{db = DB} = S) ->
+handle_call({enum_to_int, TypeOrObjName, Enum}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("enum to int: ~p, ~p",[TypeOrObjName,Enum]),
- Res = enum_to_int(DB, TypeOrObjName, Enum),
+ Res = enum_to_int(Mod, DB, TypeOrObjName, Enum),
?vdebug("enum to int result: ~p",[Res]),
{reply, Res, S};
-handle_call({int_to_enum, TypeOrObjName, Int}, _From, #state{db = DB} = S) ->
+handle_call({int_to_enum, TypeOrObjName, Int}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("int to enum: ~p, ~p",[TypeOrObjName,Int]),
- Res = int_to_enum(DB, TypeOrObjName, Int),
+ Res = int_to_enum(Mod, DB, TypeOrObjName, Int),
?vdebug("int to enum result: ~p",[Res]),
{reply, Res, S};
-handle_call({set_notification, MibName, Trap}, _From, #state{db = DB} = S) ->
+handle_call({set_notification, MibName, Trap}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("set notification:"
"~n ~p~n ~p", [MibName,Trap]),
- set_notif(DB, MibName, Trap),
+ set_notif(Mod, DB, MibName, Trap),
{reply, true, S};
-handle_call({delete_notifications, MibName}, _From, #state{db = DB} = S) ->
+handle_call({delete_notifications, MibName}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("delete notification: ~p",[MibName]),
- delete_notif(DB, MibName),
+ delete_notif(Mod, DB, MibName),
{reply, true, S};
-handle_call(which_notifications, _From, #state{db = DB} = S) ->
+handle_call(which_notifications, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("which notifications", []),
- Reply = which_notifications(DB),
+ Reply = which_notifications(Mod, DB),
{reply, Reply, S};
-handle_call({get_notification, Key}, _From, #state{db = DB} = S) ->
+handle_call({get_notification, Key}, _From,
+ #state{module = Mod, db = DB} = S) ->
?vlog("get notification: ~p",[Key]),
- Res = get_notif(DB, Key),
+ Res = get_notif(Mod, DB, Key),
?vdebug("get notification result: ~p",[Res]),
{reply, Res, S};
-handle_call(info, _From, #state{db = DB} = S) ->
+handle_call(info, _From, #state{module = Mod, db = DB} = S) ->
?vlog("info",[]),
- Info = get_info(DB),
+ Info = get_info(Mod, DB),
{reply, Info, S};
-handle_call({backup, BackupDir}, From, #state{db = DB} = S) ->
+handle_call({backup, BackupDir}, From, #state{module = Mod, db = DB} = S) ->
?vlog("info to ~p",[BackupDir]),
Pid = self(),
V = get(verbosity),
@@ -424,7 +469,7 @@ handle_call({backup, BackupDir}, From, #state{db = DB} = S) ->
put(sname, albs),
put(verbosity, V),
Dir = filename:join([BackupDir]),
- Reply = snmpa_general_db:backup(DB, Dir),
+ Reply = Mod:backup(DB, Dir),
Pid ! {backup_done, Reply},
unlink(Pid)
end),
@@ -446,7 +491,7 @@ handle_call(Req, _From, S) ->
{reply, Reply, S}.
-handle_cast({add_types, MibName, Types}, #state{db = DB} = S) ->
+handle_cast({add_types, MibName, Types}, #state{module = Mod, db = DB} = S) ->
?vlog("add types for ~p:",[MibName]),
F = fun(#asn1_type{assocList = Alist, aliasname = Name}) ->
case snmp_misc:assq(enums, Alist) of
@@ -455,20 +500,21 @@ handle_cast({add_types, MibName, Types}, #state{db = DB} = S) ->
Rec = #symbol{key = {type, Name},
mib_name = MibName,
info = Es},
- snmpa_general_db:write(DB, Rec);
+ Mod:write(DB, Rec);
false -> done
end
end,
lists:foreach(F, Types),
{noreply, S};
-handle_cast({delete_types, MibName}, #state{db = DB} = S) ->
+handle_cast({delete_types, MibName}, #state{module = Mod, db = DB} = S) ->
?vlog("delete types: ~p",[MibName]),
Pattern = #symbol{key = {type, '_'}, mib_name = MibName, info = '_'},
- snmpa_general_db:match_delete(DB, Pattern),
+ Mod:match_delete(DB, Pattern),
{noreply, S};
-handle_cast({add_aliasnames, MibName, MEs}, #state{db = DB} = S) ->
+handle_cast({add_aliasnames, MibName, MEs},
+ #state{module = Mod, db = DB} = S) ->
?vlog("add aliasnames for ~p:",[MibName]),
F = fun(#me{aliasname = AN, oid = Oid, asn1_type = AT}) ->
Enums =
@@ -480,20 +526,21 @@ handle_cast({add_aliasnames, MibName, MEs}, #state{db = DB} = S) ->
end;
_ -> []
end,
- write_alias(AN, DB, Enums, MibName, Oid)
+ write_alias(Mod, AN, DB, Enums, MibName, Oid)
end,
lists:foreach(F, MEs),
{noreply, S};
-handle_cast({delete_aliasname, MibName}, #state{db = DB} = S) ->
+handle_cast({delete_aliasname, MibName}, #state{module = Mod, db = DB} = S) ->
?vlog("delete aliasname: ~p",[MibName]),
Pattern1 = #symbol{key = {alias, '_'}, mib_name = MibName, info = '_'},
- snmpa_general_db:match_delete(DB, Pattern1),
+ Mod:match_delete(DB, Pattern1),
Pattern2 = #symbol{key = {oid, '_'}, mib_name = MibName, info = '_'},
- snmpa_general_db:match_delete(DB, Pattern2),
+ Mod:match_delete(DB, Pattern2),
{noreply, S};
-handle_cast({add_table_infos, MibName, TableInfos}, #state{db = DB} = S) ->
+handle_cast({add_table_infos, MibName, TableInfos},
+ #state{module = Mod, db = DB} = S) ->
?vlog("add table infos for ~p:",[MibName]),
F = fun({Name, TableInfo}) ->
?vlog("add table info~n ~p -> ~p",
@@ -501,19 +548,20 @@ handle_cast({add_table_infos, MibName, TableInfos}, #state{db = DB} = S) ->
Rec = #symbol{key = {table_info, Name},
mib_name = MibName,
info = TableInfo},
- snmpa_general_db:write(DB, Rec)
+ Mod:write(DB, Rec)
end,
lists:foreach(F, TableInfos),
{noreply, S};
-handle_cast({delete_table_infos, MibName}, #state{db = DB} = S) ->
+handle_cast({delete_table_infos, MibName},
+ #state{module = Mod, db = DB} = S) ->
?vlog("delete table infos: ~p",[MibName]),
Pattern = #symbol{key = {table_info, '_'}, mib_name = MibName, info = '_'},
- snmpa_general_db:match_delete(DB, Pattern),
+ Mod:match_delete(DB, Pattern),
{noreply, S};
handle_cast({add_variable_infos, MibName, VariableInfos},
- #state{db = DB} = S) ->
+ #state{module = Mod, db = DB} = S) ->
?vlog("add variable infos for ~p:",[MibName]),
F = fun({Name, VariableInfo}) ->
?vlog("add variable info~n ~p -> ~p",
@@ -521,17 +569,18 @@ handle_cast({add_variable_infos, MibName, VariableInfos},
Rec = #symbol{key = {variable_info, Name},
mib_name = MibName,
info = VariableInfo},
- snmpa_general_db:write(DB, Rec)
+ Mod:write(DB, Rec)
end,
lists:foreach(F, VariableInfos),
{noreply, S};
-handle_cast({delete_variable_infos, MibName}, #state{db = DB} = S) ->
+handle_cast({delete_variable_infos, MibName},
+ #state{module = Mod, db = DB} = S) ->
?vlog("delete variable infos: ~p",[MibName]),
Pattern = #symbol{key = {variable_info,'_'},
mib_name = MibName,
info = '_'},
- snmpa_general_db:match_delete(DB, Pattern),
+ Mod:match_delete(DB, Pattern),
{noreply, S};
handle_cast({verbosity,Verbosity}, State) ->
@@ -565,9 +614,9 @@ handle_info(Info, S) ->
{noreply, S}.
-terminate(Reason, S) ->
- ?vlog("terminate: ~p",[Reason]),
- snmpa_general_db:close(S#state.db).
+terminate(Reason, #state{module = Mod, db = DB}) ->
+ ?vlog("terminate: ~p", [Reason]),
+ Mod:close(DB).
%%----------------------------------------------------------
@@ -575,18 +624,18 @@ terminate(Reason, S) ->
%%----------------------------------------------------------
% downgrade
-code_change({down, _Vsn}, #state{db = DB, backup = B}, downgrade_to_pre_4_7) ->
- ?d("code_change(down) -> entry", []),
- stop_backup_server(B),
- S = {state, DB},
- {ok, S};
-
-% upgrade
-code_change(_Vsn, S, upgrade_from_pre_4_7) ->
- ?d("code_change(up) -> entry", []),
- {state, DB} = S,
- S1 = #state{db = DB},
- {ok, S1};
+%% code_change({down, _Vsn}, #state{db = DB, backup = B}, downgrade_to_pre_4_7) ->
+%% ?d("code_change(down) -> entry", []),
+%% stop_backup_server(B),
+%% S = {state, DB},
+%% {ok, S};
+
+%% % upgrade
+%% code_change(_Vsn, S, upgrade_from_pre_4_7) ->
+%% ?d("code_change(up) -> entry", []),
+%% {state, DB} = S,
+%% S1 = #state{db = DB},
+%% {ok, S1};
code_change(_Vsn, S, _Extra) ->
?d("code_change -> entry [do nothing]", []),
@@ -609,13 +658,13 @@ stop_backup_server({Pid, _}) when is_pid(Pid) ->
%%-----------------------------------------------------------------
%% Returns: {value, Value} | undefined
%%-----------------------------------------------------------------
-get_notif(Db, Key) ->
- case snmpa_general_db:read(Db, {trap, Key}) of
+get_notif(Mod, Db, Key) ->
+ case Mod:read(Db, {trap, Key}) of
{value,#symbol{info = Value}} -> {value, Value};
false -> undefined
end.
-set_notif(Db, MibName, Trap) when is_record(Trap, trap) ->
+set_notif(Mod, Db, MibName, Trap) when is_record(Trap, trap) ->
#trap{trapname = Name} = Trap,
Rec = #symbol{key = {trap, Name}, mib_name = MibName, info = Trap},
%% convert old v1 trap to oid
@@ -625,40 +674,41 @@ set_notif(Db, MibName, Trap) when is_record(Trap, trap) ->
Oid0 ->
Oid0 ++ [0, Trap#trap.specificcode]
end,
- write_alias(Name, Db, MibName, Oid),
- snmpa_general_db:write(Db, Rec);
-set_notif(Db, MibName, Trap) ->
+ write_alias(Mod, Name, Db, MibName, Oid),
+ Mod:write(Db, Rec);
+set_notif(Mod, Db, MibName, Trap) ->
#notification{trapname = Name, oid = Oid} = Trap,
Rec = #symbol{key = {trap, Name}, mib_name = MibName, info = Trap},
- write_alias(Name, Db, MibName, Oid),
- snmpa_general_db:write(Db, Rec).
+ write_alias(Mod, Name, Db, MibName, Oid),
+ Mod:write(Db, Rec).
-delete_notif(Db, MibName) ->
+delete_notif(Mod, Db, MibName) ->
Pattern = #symbol{key = {trap, '_'}, mib_name = MibName, info = '_'},
- snmpa_general_db:match_delete(Db, Pattern).
+ Mod:match_delete(Db, Pattern).
-write_alias(AN, DB, MibName, Oid) ->
- write_alias(AN, DB, [], MibName, Oid).
+write_alias(Mod, AN, DB, MibName, Oid) ->
+ write_alias(Mod, AN, DB, [], MibName, Oid).
-write_alias(AN, DB, Enums, MibName, Oid) ->
+write_alias(Mod, AN, DB, Enums, MibName, Oid) ->
?vlog("add alias~n ~p -> {~p,~p}",[AN, Oid, Enums]),
Rec1 = #symbol{key = {alias, AN},
mib_name = MibName,
info = {Oid,Enums}},
- snmpa_general_db:write(DB, Rec1),
+ Mod:write(DB, Rec1),
?vlog("add oid~n ~p -> ~p",[Oid, AN]),
Rec2 = #symbol{key = {oid, Oid},
mib_name = MibName,
info = AN},
- snmpa_general_db:write(DB, Rec2).
+ Mod:write(DB, Rec2).
+
%% -------------------------------------
-get_info(DB) ->
+get_info(Mod, DB) ->
ProcSize = proc_mem(self()),
- DbSz = tab_size(DB),
- [{process_memory, ProcSize}, {db_memory, DbSz}].
+ DbMemory = Mod:info(DB, memory),
+ [{process_memory, ProcSize}, {db_memory, DbMemory}].
proc_mem(P) when is_pid(P) ->
case (catch erlang:process_info(P, memory)) of
@@ -667,26 +717,15 @@ proc_mem(P) when is_pid(P) ->
_ ->
undefined
end.
-%% proc_mem(_) ->
-%% undefined.
-
-tab_size(DB) ->
- case (catch snmpa_general_db:info(DB, memory)) of
- Sz when is_integer(Sz) ->
- Sz;
- _ ->
- undefined
- end.
-
%% -------------------------------------
get_verbosity(L) ->
- snmp_misc:get_option(verbosity,L,?default_verbosity).
+ snmp_misc:get_option(verbosity, L, ?default_verbosity).
get_mib_storage(L) ->
- snmp_misc:get_option(mib_storage,L,ets).
+ snmp_misc:get_option(mib_storage, L).
%% -------------------------------------
diff --git a/lib/snmp/src/app/snmp.app.src b/lib/snmp/src/app/snmp.app.src
index b11c1ef934..904d17954b 100644
--- a/lib/snmp/src/app/snmp.app.src
+++ b/lib/snmp/src/app/snmp.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -48,11 +48,15 @@
snmpa_error_io,
snmpa_error_logger,
snmpa_error_report,
- snmpa_general_db,
snmpa_local_db,
snmpa_mib,
snmpa_mib_data,
+ snmpa_mib_data_tttn,
snmpa_mib_lib,
+ snmpa_mib_storage,
+ snmpa_mib_storage_ets,
+ snmpa_mib_storage_dets,
+ snmpa_mib_storage_mnesia,
snmpa_misc_sup,
snmpa_mpd,
snmpa_net_if,
diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src
index 4c5f14da90..7ffa4a725d 100644
--- a/lib/snmp/src/app/snmp.appup.src
+++ b/lib/snmp/src/app/snmp.appup.src
@@ -22,19 +22,15 @@
%% ----- U p g r a d e -------------------------------------------------------
[
- {"4.23",
- [
- ]
- }
+ {"4.23.1", [{restart_application, snmp}]},
+ {"4.23", [{restart_application, snmp}]}
],
%% ------D o w n g r a d e ---------------------------------------------------
[
- {"4.23",
- [
- ]
- }
+ {"4.23.1", [{restart_application, snmp}]},
+ {"4.23", [{restart_application, snmp}]}
]
}.
diff --git a/lib/snmp/src/app/snmp.erl b/lib/snmp/src/app/snmp.erl
index cd3e3a0055..1bb562654a 100644
--- a/lib/snmp/src/app/snmp.erl
+++ b/lib/snmp/src/app/snmp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -90,6 +90,13 @@
]).
+-export_type([
+ oid/0,
+
+ void/0
+ ]).
+
+
%% This is for XREF
-deprecated([{c, 1, eventually},
{c, 2, eventually},
@@ -143,6 +150,15 @@
-define(APPLICATION, snmp).
+
+%%-----------------------------------------------------------------
+%% Types
+%%-----------------------------------------------------------------
+
+-type oid() :: [non_neg_integer()].
+-type void() :: term().
+
+
%%-----------------------------------------------------------------
%% Application
%%-----------------------------------------------------------------
diff --git a/lib/snmp/src/app/snmp_app.erl b/lib/snmp/src/app/snmp_app.erl
index deb42cc373..0cfbb22a5a 100644
--- a/lib/snmp/src/app/snmp_app.erl
+++ b/lib/snmp/src/app/snmp_app.erl
@@ -62,17 +62,17 @@ entities([], []) ->
?d("entities -> converted config: ~n~p", [Conf]),
[{agent, Conf}]
end;
-entities([], E) ->
+entities([], Acc) ->
?d("entities -> done", []),
- lists:reverse(E);
-entities([ET|ETs], E) ->
+ lists:reverse(Acc);
+entities([Ent|Ents], Acc) ->
?d("entities -> entry with"
- "~n ET: ~p", [ET]),
- case application:get_env(snmp, ET) of
+ "~n Ent: ~p", [Ent]),
+ case application:get_env(snmp, Ent) of
{ok, Conf} ->
- entities(ETs, [{ET, Conf}|E]);
+ entities(Ents, [{Ent, Conf}|Acc]);
_ ->
- entities(ETs, E)
+ entities(Ents, Acc)
end.
start_entities(_Type, []) ->
diff --git a/lib/snmp/src/manager/snmpm_config.erl b/lib/snmp/src/manager/snmpm_config.erl
index 5bbf9e5542..9d687f1d31 100644
--- a/lib/snmp/src/manager/snmpm_config.erl
+++ b/lib/snmp/src/manager/snmpm_config.erl
@@ -2028,7 +2028,7 @@ verify_usm_user_auth(usmNoAuthProtocol, AuthKey) ->
end;
verify_usm_user_auth(usmHMACMD5AuthProtocol, AuthKey)
when is_list(AuthKey) andalso (length(AuthKey) =:= 16) ->
- case is_crypto_supported(md5_mac_96) of
+ case is_crypto_supported(md5) of
true ->
case snmp_conf:all_integer(AuthKey) of
true ->
@@ -2037,7 +2037,7 @@ verify_usm_user_auth(usmHMACMD5AuthProtocol, AuthKey)
error({invalid_auth_key, usmHMACMD5AuthProtocol})
end;
false ->
- error({unsupported_crypto, md5_mac_96})
+ error({unsupported_crypto, md5})
end;
verify_usm_user_auth(usmHMACMD5AuthProtocol, AuthKey) when is_list(AuthKey) ->
Len = length(AuthKey),
@@ -2046,7 +2046,7 @@ verify_usm_user_auth(usmHMACMD5AuthProtocol, _AuthKey) ->
error({invalid_auth_key, usmHMACMD5AuthProtocol});
verify_usm_user_auth(usmHMACSHAAuthProtocol, AuthKey)
when is_list(AuthKey) andalso (length(AuthKey) =:= 20) ->
- case is_crypto_supported(sha_mac_96) of
+ case is_crypto_supported(sha) of
true ->
case snmp_conf:all_integer(AuthKey) of
true ->
@@ -2055,7 +2055,7 @@ verify_usm_user_auth(usmHMACSHAAuthProtocol, AuthKey)
error({invalid_auth_key, usmHMACSHAAuthProtocol})
end;
false ->
- error({unsupported_crypto, sha_mac_96})
+ error({unsupported_crypto, sha})
end;
verify_usm_user_auth(usmHMACSHAAuthProtocol, AuthKey) when is_list(AuthKey) ->
Len = length(AuthKey),
@@ -2074,7 +2074,7 @@ verify_usm_user_priv(usmNoPrivProtocol, PrivKey) ->
end;
verify_usm_user_priv(usmDESPrivProtocol, PrivKey)
when (length(PrivKey) =:= 16) ->
- case is_crypto_supported(des_cbc_decrypt) of
+ case is_crypto_supported(des_cbc) of
true ->
case snmp_conf:all_integer(PrivKey) of
true ->
@@ -2083,7 +2083,7 @@ verify_usm_user_priv(usmDESPrivProtocol, PrivKey)
error({invalid_priv_key, usmDESPrivProtocol})
end;
false ->
- error({unsupported_crypto, des_cbc_decrypt})
+ error({unsupported_crypto, des_cbc})
end;
verify_usm_user_priv(usmDESPrivProtocol, PrivKey) when is_list(PrivKey) ->
Len = length(PrivKey),
@@ -2092,7 +2092,7 @@ verify_usm_user_priv(usmDESPrivProtocol, _PrivKey) ->
error({invalid_priv_key, usmDESPrivProtocol});
verify_usm_user_priv(usmAesCfb128Protocol, PrivKey)
when (length(PrivKey) =:= 16) ->
- case is_crypto_supported(aes_cfb_128_decrypt) of
+ case is_crypto_supported(aes_cfb128) of
true ->
case snmp_conf:all_integer(PrivKey) of
true ->
@@ -2101,7 +2101,7 @@ verify_usm_user_priv(usmAesCfb128Protocol, PrivKey)
error({invalid_priv_key, usmAesCfb128Protocol})
end;
false ->
- error({unsupported_crypto, aes_cfb_128_decrypt})
+ error({unsupported_crypto, aes_cfb128})
end;
verify_usm_user_priv(usmAesCfb128Protocol, PrivKey) when is_list(PrivKey) ->
Len = length(PrivKey),
@@ -2111,13 +2111,10 @@ verify_usm_user_priv(usmAesCfb128Protocol, _PrivKey) ->
verify_usm_user_priv(PrivP, _PrivKey) ->
error({invalid_priv_protocol, PrivP}).
+
+-compile({inline, [{is_crypto_supported,1}]}).
is_crypto_supported(Func) ->
- %% The 'catch' handles the case when 'crypto' is
- %% not present in the system (or not started).
- case (catch lists:member(Func, crypto:info())) of
- true -> true;
- _ -> false
- end.
+ snmp_misc:is_crypto_supported(Func).
read_manager_config_file(Dir) ->
@@ -2879,11 +2876,11 @@ do_update_usm_user_info(Key,
#usm_user{auth = usmHMACMD5AuthProtocol} = User,
auth_key, Val)
when length(Val) =:= 16 ->
- case is_crypto_supported(md5_mac_96) of
+ case is_crypto_supported(md5) of
true ->
do_update_usm_user_info(Key, User#usm_user{auth_key = Val});
false ->
- {error, {unsupported_crypto, md5_mac_96}}
+ {error, {unsupported_crypto, md5}}
end;
do_update_usm_user_info(_Key,
#usm_user{auth = usmHMACMD5AuthProtocol},
@@ -2898,11 +2895,11 @@ do_update_usm_user_info(Key,
#usm_user{auth = usmHMACSHAAuthProtocol} = User,
auth_key, Val)
when length(Val) =:= 20 ->
- case is_crypto_supported(sha_mac_96) of
+ case is_crypto_supported(sha) of
true ->
do_update_usm_user_info(Key, User#usm_user{auth_key = Val});
false ->
- {error, {unsupported_crypto, sha_mac_96}}
+ {error, {unsupported_crypto, sha}}
end;
do_update_usm_user_info(_Key,
#usm_user{auth = usmHMACSHAAuthProtocol},
@@ -2933,21 +2930,21 @@ do_update_usm_user_info(Key,
#usm_user{priv = usmDESPrivProtocol} = User,
priv_key, Val)
when length(Val) =:= 16 ->
- case is_crypto_supported(des_cbc_decrypt) of
+ case is_crypto_supported(des_cbc) of
true ->
do_update_usm_user_info(Key, User#usm_user{priv_key = Val});
false ->
- {error, {unsupported_crypto, des_cbc_decrypt}}
+ {error, {unsupported_crypto, des_cbc}}
end;
do_update_usm_user_info(Key,
#usm_user{priv = usmAesCfb128Protocoll} = User,
priv_key, Val)
when length(Val) =:= 16 ->
- case is_crypto_supported(aes_cfb_128_decrypt) of
+ case is_crypto_supported(aes_cfb128) of
true ->
do_update_usm_user_info(Key, User#usm_user{priv_key = Val});
false ->
- {error, {unsupported_crypto, aes_cfb_128_decrypt}}
+ {error, {unsupported_crypto, aes_cfb128}}
end;
do_update_usm_user_info(_Key,
#usm_user{auth = usmHMACSHAAuthProtocol},
diff --git a/lib/snmp/src/misc/snmp_config.erl b/lib/snmp/src/misc/snmp_config.erl
index 0bed097b62..22fe25941c 100644
--- a/lib/snmp/src/misc/snmp_config.erl
+++ b/lib/snmp/src/misc/snmp_config.erl
@@ -238,7 +238,7 @@ config_agent_sys() ->
MibStorage =
case MibStorageType of
ets ->
- ets;
+ [{module, snmpa_mib_storage_ets}];
dets ->
DetsDir = ask("6b. Mib storage directory (absolute path)?",
DbDir, fun verify_dir/1),
@@ -248,13 +248,14 @@ config_agent_sys() ->
"default", fun verify_mib_storage_action/1),
case DetsAction of
default ->
- {dets, DetsDir};
+ [{module, snmpa_mib_storage_dets},
+ {options, [{dir, DetsDir}]}];
_ ->
- {dets, DetsDir, DetsAction}
+ [{module, snmpa_mib_storage_dets},
+ {options, [{dir, DetsDir},
+ {action, DetsAction}]}]
end;
mnesia ->
-% Nodes = ask("Mib storage nodes?", "none",
-% fun verify_mib_storage_nodes/1),
Nodes = [],
MnesiaAction = ask("6b. Mib storage [mnesia] database start "
"action "
@@ -262,11 +263,18 @@ config_agent_sys() ->
"default", fun verify_mib_storage_action/1),
case MnesiaAction of
default ->
- {mnesia, Nodes};
+ [{module, snmpa_mib_storage_mnesia},
+ {options, [{nodes, Nodes}]}];
_ ->
- {mnesia, Nodes, MnesiaAction}
+ [{module, snmpa_mib_storage_mnesia},
+ {options, [{nodes, Nodes},
+ {action, MnesiaAction}]}]
end
end,
+
+ %% Here we should ask about mib-server data module,
+ %% but as we only have one at the moment...
+
TargetCacheVerb = ask("7. Target cache verbosity "
"(silence/info/log/debug/trace)?", "silence",
fun verify_verbosity/1),
diff --git a/lib/snmp/src/misc/snmp_misc.erl b/lib/snmp/src/misc/snmp_misc.erl
index a061dcd97c..293b22991b 100644
--- a/lib/snmp/src/misc/snmp_misc.erl
+++ b/lib/snmp/src/misc/snmp_misc.erl
@@ -43,6 +43,7 @@
ip/1, ip/2,
is_auth/1,
is_BitString/1,
+ is_crypto_supported/1,
is_oid/1,
is_priv/1,
is_reportable/1,
@@ -117,13 +118,27 @@ now(sec) ->
(element(3,Now) div 1000000).
+is_crypto_supported(Alg) ->
+ %% The 'try catch' handles the case when 'crypto' is
+ %% not present in the system (or not started).
+ try
+ begin
+ Supported = crypto:supports(),
+ Hashs = proplists:get_value(hashs, Supported),
+ Ciphers = proplists:get_value(ciphers, Supported),
+ lists:member(Alg, Hashs ++ Ciphers)
+ end
+ catch
+ _:_ ->
+ false
+ end.
+
is_string([]) -> true;
is_string([Tkn | Str])
when is_integer(Tkn) andalso (Tkn >= 0) andalso (Tkn =< 255) ->
is_string(Str);
is_string(_) -> false.
-
is_oid([E1, E2| Rest])
when (length(Rest) =< 126) andalso (E1 *40 + E2 =< 255) ->
is_oid2(Rest);
diff --git a/lib/snmp/src/misc/snmp_usm.erl b/lib/snmp/src/misc/snmp_usm.erl
index df2c1f0b18..67e3476816 100644
--- a/lib/snmp/src/misc/snmp_usm.erl
+++ b/lib/snmp/src/misc/snmp_usm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -69,7 +69,7 @@ passwd2localized_key(Alg, Passwd, EngineID) when length(Passwd) > 0 ->
%%-----------------------------------------------------------------
localize_key(Alg, Key, EngineID) ->
Str = [Key, EngineID, Key],
- binary_to_list(crypto:Alg(Str)).
+ binary_to_list(crypto:hash(Alg, Str)).
mk_digest(md5, Passwd) ->
@@ -78,25 +78,25 @@ mk_digest(sha, Passwd) ->
mk_sha_digest(Passwd).
mk_md5_digest(Passwd) ->
- Ctx = crypto:md5_init(),
+ Ctx = crypto:hash_init(md5),
Ctx2 = md5_loop(0, [], Ctx, Passwd, length(Passwd)),
- crypto:md5_final(Ctx2).
+ crypto:hash_final(Ctx2).
md5_loop(Count, Buf, Ctx, Passwd, PasswdLen) when Count < 1048576 ->
{Buf64, NBuf} = mk_buf64(length(Buf), Buf, Passwd, PasswdLen),
- NCtx = crypto:md5_update(Ctx, Buf64),
+ NCtx = crypto:hash_update(Ctx, Buf64),
md5_loop(Count+64, NBuf, NCtx, Passwd, PasswdLen);
md5_loop(_Count, _Buf, Ctx, _Passwd, _PasswdLen) ->
Ctx.
mk_sha_digest(Passwd) ->
- Ctx = crypto:sha_init(),
+ Ctx = crypto:hash_init(sha),
Ctx2 = sha_loop(0, [], Ctx, Passwd, length(Passwd)),
- crypto:sha_final(Ctx2).
+ crypto:hash_final(Ctx2).
sha_loop(Count, Buf, Ctx, Passwd, PasswdLen) when Count < 1048576 ->
{Buf64, NBuf} = mk_buf64(length(Buf), Buf, Passwd, PasswdLen),
- NCtx = crypto:sha_update(Ctx, Buf64),
+ NCtx = crypto:hash_update(Ctx, Buf64),
sha_loop(Count+64, NBuf, NCtx, Passwd, PasswdLen);
sha_loop(_Count, _Buf, Ctx, _Passwd, _PasswdLen) ->
Ctx.
@@ -142,26 +142,33 @@ auth_out(?usmHMACSHAAuthProtocol, AuthKey, Message, UsmSecParams) ->
sha_auth_out(AuthKey, Message, UsmSecParams).
md5_auth_out(AuthKey, Message, UsmSecParams) ->
+ %% ?vtrace("md5_auth_out -> entry with"
+ %% "~n AuthKey: ~w"
+ %% "~n Message: ~w"
+ %% "~n UsmSecParams: ~w", [AuthKey, Message, UsmSecParams]),
%% 6.3.1.1
Message2 = set_msg_auth_params(Message, UsmSecParams, ?twelwe_zeros),
- Packet = snmp_pdus:enc_message_only(Message2),
+ Packet = snmp_pdus:enc_message_only(Message2),
%% 6.3.1.2-4 is done by the crypto function
%% 6.3.1.4
- MAC = binary_to_list(crypto:md5_mac_96(AuthKey, Packet)),
+ MAC = binary_to_list(crypto:hmac(md5, AuthKey, Packet, 12)),
+ %% ?vtrace("md5_auth_out -> crypto (md5) encoded"
+ %% "~n MAC: ~w", [MAC]),
%% 6.3.1.5
set_msg_auth_params(Message, UsmSecParams, MAC).
md5_auth_in(AuthKey, AuthParams, Packet) when length(AuthParams) == 12 ->
+ %% ?vtrace("md5_auth_in -> entry with"
+ %% "~n AuthKey: ~w"
+ %% "~n AuthParams: ~w"
+ %% "~n Packet: ~w", [AuthKey, AuthParams, Packet]),
%% 6.3.2.3
Packet2 = patch_packet(binary_to_list(Packet)),
%% 6.3.2.5
- MAC = binary_to_list(crypto:md5_mac_96(AuthKey, Packet2)),
+ MAC = binary_to_list(crypto:hmac(md5, AuthKey, Packet2, 12)),
%% 6.3.2.6
-%% ?vtrace("md5_auth_in -> entry with"
-%% "~n Packet2: ~w"
-%% "~n AuthKey: ~w"
-%% "~n AuthParams: ~w"
-%% "~n MAC: ~w", [Packet2, AuthKey, AuthParams, MAC]),
+ %% ?vtrace("md5_auth_in -> crypto (md5) encoded"
+ %% "~n MAC: ~w", [MAC]),
MAC == AuthParams;
md5_auth_in(_AuthKey, _AuthParams, _Packet) ->
%% 6.3.2.1
@@ -177,7 +184,7 @@ sha_auth_out(AuthKey, Message, UsmSecParams) ->
Packet = snmp_pdus:enc_message_only(Message2),
%% 7.3.1.2-4 is done by the crypto function
%% 7.3.1.4
- MAC = binary_to_list(crypto:sha_mac_96(AuthKey, Packet)),
+ MAC = binary_to_list(crypto:hmac(sha, AuthKey, Packet, 12)),
%% 7.3.1.5
set_msg_auth_params(Message, UsmSecParams, MAC).
@@ -185,7 +192,7 @@ sha_auth_in(AuthKey, AuthParams, Packet) when length(AuthParams) =:= 12 ->
%% 7.3.2.3
Packet2 = patch_packet(binary_to_list(Packet)),
%% 7.3.2.5
- MAC = binary_to_list(crypto:sha_mac_96(AuthKey, Packet2)),
+ MAC = binary_to_list(crypto:hmac(sha, AuthKey, Packet2, 12)),
%% 7.3.2.6
MAC == AuthParams;
sha_auth_in(_AuthKey, _AuthParams, _Packet) ->
@@ -203,7 +210,7 @@ des_encrypt(PrivKey, Data, SaltFun) ->
IV = list_to_binary(snmp_misc:str_xor(PreIV, Salt)),
TailLen = (8 - (length(Data) rem 8)) rem 8,
Tail = mk_tail(TailLen),
- EncData = crypto:des_cbc_encrypt(DesKey, IV, [Data,Tail]),
+ EncData = crypto:block_encrypt(des_cbc, DesKey, IV, [Data,Tail]),
{ok, binary_to_list(EncData), Salt}.
des_decrypt(PrivKey, MsgPrivParams, EncData)
@@ -217,7 +224,7 @@ des_decrypt(PrivKey, MsgPrivParams, EncData)
Salt = MsgPrivParams,
IV = list_to_binary(snmp_misc:str_xor(PreIV, Salt)),
%% Whatabout errors here??? E.g. not a mulitple of 8!
- Data = binary_to_list(crypto:des_cbc_decrypt(DesKey, IV, EncData)),
+ Data = binary_to_list(crypto:block_decrypt(des_cbc, DesKey, IV, EncData)),
Data2 = snmp_pdus:strip_encrypted_scoped_pdu_data(Data),
{ok, Data2};
des_decrypt(PrivKey, BadMsgPrivParams, EncData) ->
@@ -235,7 +242,7 @@ aes_encrypt(PrivKey, Data, SaltFun) ->
EngineBoots = snmp_framework_mib:get_engine_boots(),
EngineTime = snmp_framework_mib:get_engine_time(),
IV = list_to_binary([?i32(EngineBoots), ?i32(EngineTime) | Salt]),
- EncData = crypto:aes_cfb_128_encrypt(AesKey, IV, Data),
+ EncData = crypto:block_encrypt(aes_cbf128, AesKey, IV, Data),
{ok, binary_to_list(EncData), Salt}.
aes_decrypt(PrivKey, MsgPrivParams, EncData, EngineBoots, EngineTime)
@@ -244,7 +251,7 @@ aes_decrypt(PrivKey, MsgPrivParams, EncData, EngineBoots, EngineTime)
Salt = MsgPrivParams,
IV = list_to_binary([?i32(EngineBoots), ?i32(EngineTime) | Salt]),
%% Whatabout errors here??? E.g. not a mulitple of 8!
- Data = binary_to_list(crypto:aes_cfb_128_decrypt(AesKey, IV, EncData)),
+ Data = binary_to_list(crypto:block_decrypt(aes_cbf128, AesKey, IV, EncData)),
Data2 = snmp_pdus:strip_encrypted_scoped_pdu_data(Data),
{ok, Data2}.
diff --git a/lib/snmp/test/snmp_agent_mibs_test.erl b/lib/snmp/test/snmp_agent_mibs_test.erl
index 3e48130fac..248fe7d83e 100644
--- a/lib/snmp/test/snmp_agent_mibs_test.erl
+++ b/lib/snmp/test/snmp_agent_mibs_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -19,13 +19,17 @@
%%
%%----------------------------------------------------------------------
-%% Purpose:
+%% Purpose: Test suite of the agent mib-server.
+%% Some of these tests should really be in a mib-storage suite.
%%----------------------------------------------------------------------
+
-module(snmp_agent_mibs_test).
+
%%----------------------------------------------------------------------
%% Include files
%%----------------------------------------------------------------------
+
-include_lib("test_server/include/test_server.hrl").
-include("snmp_test_lib.hrl").
-include_lib("snmp/include/snmp_types.hrl").
@@ -39,13 +43,25 @@
%% External exports
%%----------------------------------------------------------------------
-export([
- all/0,groups/0,init_per_group/2,end_per_group/2,
- init_per_testcase/2, end_per_testcase/2,
- init_per_suite/1, end_per_suite/1,
+ all/0,
+ groups/0,
+
+ init_per_suite/1,
+ end_per_suite/1,
+
+ init_per_group/2,
+ end_per_group/2,
+
+ init_per_testcase/2,
+ end_per_testcase/2,
start_and_stop/1,
- size_check_ets/1,
+ size_check_ets1/1,
+ size_check_ets2/1,
+ size_check_ets2_bad_file1/1,
+ size_check_ets3/1,
+ size_check_ets3_bad_file1/1,
size_check_dets/1,
size_check_mnesia/1,
load_unload/1,
@@ -55,6 +71,7 @@
]).
+
%%----------------------------------------------------------------------
%% Internal exports
%%----------------------------------------------------------------------
@@ -71,18 +88,51 @@
%% External functions
%%======================================================================
-init_per_testcase(size_check_dets, Config) when is_list(Config) ->
- Dir = ?config(priv_dir, Config),
- DetsDir = join(Dir, "dets_dir/"),
- ?line ok = file:make_dir(DetsDir),
- [{dets_dir, DetsDir}|Config];
-init_per_testcase(size_check_mnesia, Config) when is_list(Config) ->
- Dir = ?config(priv_dir, Config),
- MnesiaDir = join(Dir, "mnesia_dir/"),
- ?line ok = file:make_dir(MnesiaDir),
- mnesia_start([{dir, MnesiaDir}]),
- [{mnesia_dir, MnesiaDir}|Config];
-init_per_testcase(cache_test, Config) when is_list(Config) ->
+init_per_suite(Config0) when is_list(Config0) ->
+
+ ?DBG("init_per_suite -> entry with"
+ "~n Config0: ~p", [Config0]),
+
+ Config1 = snmp_test_lib:init_suite_top_dir(?MODULE, Config0),
+
+ ?DBG("init_per_suite -> done when"
+ "~n Config1: ~p", [Config1]),
+
+ Config1.
+
+end_per_suite(Config) when is_list(Config) ->
+
+ ?DBG("end_per_suite -> entry with"
+ "~n Config: ~p", [Config]),
+
+ Config.
+
+
+init_per_testcase(Case, Config0) when is_list(Config0) ->
+ Config1 = snmp_test_lib:fix_data_dir(Config0),
+ CaseTopDir = snmp_test_lib:init_testcase_top_dir(Case, Config1),
+ DbDir = join(CaseTopDir, "db_dir/"),
+ ?line ok = file:make_dir(DbDir),
+ init_per_testcase2(Case, [{db_dir, DbDir},
+ {case_top_dir, CaseTopDir} | Config1]).
+
+init_per_testcase2(size_check_ets2_bad_file1, Config) when is_list(Config) ->
+ DbDir = ?config(db_dir, Config),
+ %% Create a ad file
+ ok = file:write_file(join(DbDir, "snmpa_symbolic_store.db"),
+ "calvin and hoppes play chess"),
+ Config;
+init_per_testcase2(size_check_ets3_bad_file1, Config) when is_list(Config) ->
+ DbDir = ?config(db_dir, Config),
+ %% Create a ad file
+ ok = file:write_file(join(DbDir, "snmpa_symbolic_store.db"),
+ "calvin and hoppes play chess"),
+ Config;
+init_per_testcase2(size_check_mnesia, Config) when is_list(Config) ->
+ DbDir = ?config(db_dir, Config),
+ mnesia_start([{dir, DbDir}]),
+ Config;
+init_per_testcase2(cache_test, Config) when is_list(Config) ->
Min = timer:minutes(5),
Timeout =
case lists:keysearch(tc_timeout, 1, Config) of
@@ -95,18 +145,26 @@ init_per_testcase(cache_test, Config) when is_list(Config) ->
end,
Dog = test_server:timetrap(Timeout),
[{watchdog, Dog} | Config];
-init_per_testcase(_Case, Config) when is_list(Config) ->
+init_per_testcase2(_Case, Config) when is_list(Config) ->
Config.
-end_per_testcase(size_check_dets, Config) when is_list(Config) ->
- Dir = ?config(dets_dir, Config),
- ?line ok = ?DEL_DIR(Dir),
- lists:keydelete(dets_dir, 1, Config);
+%% end_per_testcase(EtsCase, Config)
+%% when (is_list(Config) andalso
+%% ((EtsCase =:= size_check_ets2) orelse
+%% (EtsCase =:= size_check_ets3))) ->
+%% Dir = ?config(ets_dir, Config),
+%% ?line ok = ?DEL_DIR(Dir),
+%% lists:keydelete(ets_dir, 1, Config);
+%% end_per_testcase(size_check_dets, Config) when is_list(Config) ->
+%% Dir = ?config(dets_dir, Config),
+%% ?line ok = ?DEL_DIR(Dir),
+%% lists:keydelete(dets_dir, 1, Config);
end_per_testcase(size_check_mnesia, Config) when is_list(Config) ->
mnesia_stop(),
- Dir = ?config(mnesia_dir, Config),
- ?line ok = ?DEL_DIR(Dir),
- lists:keydelete(mnesia_dir, 1, Config);
+ %% Dir = ?config(db_dir, Config),
+ %% ?line ok = ?DEL_DIR(Dir),
+ %% lists:keydelete(mnesia_dir, 1, Config);
+ Config;
end_per_testcase(cache_test, Config) when is_list(Config) ->
Dog = ?config(watchdog, Config),
test_server:timetrap_cancel(Dog),
@@ -120,33 +178,40 @@ end_per_testcase(_Case, Config) when is_list(Config) ->
%%======================================================================
all() ->
-cases().
+ cases().
groups() ->
[{size_check, [],
- [size_check_ets, size_check_dets, size_check_mnesia]}].
+ [
+ size_check_ets1, % Plain ets
+ size_check_ets2, % ets with a file
+ size_check_ets2_bad_file1, % ets with a bad file
+ size_check_ets3, % ets with a checksummed file
+ size_check_ets3_bad_file1, % ets with bad file (checksummed)
+ size_check_dets, % Plain dets
+ size_check_mnesia % Plain mnesia
+ ]
+ }].
+
-init_per_group(_GroupName, Config) ->
- Config.
+init_per_group(GroupName, Config) ->
+ snmp_test_lib:init_group_top_dir(GroupName, Config).
end_per_group(_GroupName, Config) ->
- Config.
+ %% Do we really need to do this?
+ %% lists:keydelete(snmp_group_top_dir, 1, Config).
+ Config.
cases() ->
-[start_and_stop, load_unload, {group, size_check},
- me_lookup, which_mib, cache_test].
-
-init_per_suite(Config) when is_list(Config) ->
- %% Data dir points wrong
- DataDir0 = ?config(data_dir, Config),
- DataDir1 = filename:split(filename:absname(DataDir0)),
- [_|DataDir2] = lists:reverse(DataDir1),
- DataDir = filename:join(lists:reverse(DataDir2) ++ [?snmp_test_data]),
- [{snmp_data_dir, DataDir ++ "/"}|Config].
-
-end_per_suite(Config) when is_list(Config) ->
- lists:keydelete(snmp_data_dir, 1, Config).
+ [
+ start_and_stop,
+ load_unload,
+ {group, size_check},
+ me_lookup,
+ which_mib,
+ cache_test
+ ].
%%======================================================================
@@ -175,8 +240,7 @@ load_unload(suite) -> [];
load_unload(Config) when is_list(Config) ->
Prio = normal,
Verbosity = log,
- %% MibStorage = ets,
- MibDir = ?config(snmp_data_dir, Config),
+ MibDir = ?config(data_dir, Config),
?DBG("load_unload -> start symbolic store", []),
?line sym_start(Prio, Verbosity),
@@ -221,30 +285,74 @@ load_unload(Config) when is_list(Config) ->
%% ---------------------------------------------------------------------
-size_check_ets(suite) ->
+size_check_ets1(suite) ->
+ [];
+size_check_ets1(Config) when is_list(Config) ->
+ MibStorage = [{module, snmpa_mib_storage_ets}],
+ do_size_check([{mib_storage, MibStorage}|Config]).
+
+size_check_ets2(suite) ->
+ [];
+size_check_ets2(Config) when is_list(Config) ->
+ Dir = ?config(db_dir, Config),
+ MibStorage = [{module, snmpa_mib_storage_ets},
+ {options, [{dir, Dir}]}],
+ do_size_check([{mib_storage, MibStorage}|Config]).
+
+size_check_ets2_bad_file1(suite) ->
+ [];
+size_check_ets2_bad_file1(Config) when is_list(Config) ->
+ Dir = ?config(db_dir, Config),
+ %% Ensure that the bad file does not cause any problems (action = clear)
+ MibStorage = [{module, snmpa_mib_storage_ets},
+ {options, [{dir, Dir},
+ {action, clear}]}],
+ do_size_check([{mib_storage, MibStorage}|Config]).
+
+size_check_ets3(suite) ->
[];
-size_check_ets(Config) when is_list(Config) ->
- do_size_check([{mib_storage, ets}|Config]).
+size_check_ets3(Config) when is_list(Config) ->
+ Dir = ?config(db_dir, Config),
+ MibStorage = [{module, snmpa_mib_storage_ets},
+ {options, [{dir, Dir},
+ {checksum, true}]}],
+ do_size_check([{mib_storage, MibStorage}|Config]).
+
+size_check_ets3_bad_file1(suite) ->
+ [];
+size_check_ets3_bad_file1(Config) when is_list(Config) ->
+ Dir = ?config(db_dir, Config),
+ %% Ensure that the bad file does not cause any problems (action = clear)
+ MibStorage = [{module, snmpa_mib_storage_ets},
+ {options, [{dir, Dir},
+ {action, clear},
+ {checksum, true}]}],
+ do_size_check([{mib_storage, MibStorage}|Config]).
size_check_dets(suite) ->
[];
size_check_dets(Config) when is_list(Config) ->
- Dir = ?config(dets_dir, Config),
- do_size_check([{mib_storage, {dets, Dir}}|Config]).
+ Dir = ?config(db_dir, Config),
+ MibStorage = [{module, snmpa_mib_storage_dets},
+ {options, [{dir, Dir}]}],
+ do_size_check([{mib_storage, MibStorage}|Config]).
size_check_mnesia(suite) ->
[];
size_check_mnesia(Config) when is_list(Config) ->
- do_size_check([{mib_storage, {mnesia, [node()]}}|Config]).
+ MibStorage = [{module, snmpa_mib_storage_mnesia},
+ {options, [{nodes, [node()]}]}],
+ do_size_check([{mib_storage, MibStorage}|Config]).
do_size_check(Config) ->
- ?DBG("do_size_check -> start", []),
+ ?DBG("do_size_check -> start with"
+ "~n Config: ~p", [Config]),
Prio = normal,
Verbosity = trace,
MibStorage = ?config(mib_storage, Config),
?DBG("do_size_check -> MibStorage: ~p", [MibStorage]),
- MibDir = ?config(snmp_data_dir, Config),
+ MibDir = ?config(data_dir, Config),
StdMibDir = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
?DBG("do_size_check -> start symbolic store", []),
@@ -294,8 +402,7 @@ me_lookup(suite) -> [];
me_lookup(Config) when is_list(Config) ->
Prio = normal,
Verbosity = trace,
- %% MibStorage = ets,
- MibDir = ?config(snmp_data_dir, Config),
+ MibDir = ?config(data_dir, Config),
StdMibDir = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
Mibs = ["Test2", "TestTrap", "TestTrapv2"],
StdMibs = ["OTP-SNMPEA-MIB",
@@ -348,8 +455,7 @@ which_mib(suite) -> [];
which_mib(Config) when is_list(Config) ->
Prio = normal,
Verbosity = trace,
- %% MibStorage = ets,
- MibDir = ?config(snmp_data_dir, Config),
+ MibDir = ?config(data_dir, Config),
StdMibDir = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
Mibs = ["Test2", "TestTrap", "TestTrapv2"],
StdMibs = ["OTP-SNMPEA-MIB",
@@ -406,28 +512,28 @@ cache_test(Config) when is_list(Config) ->
?DBG("cache_test -> start", []),
Prio = normal,
Verbosity = trace,
- MibStorage = ets,
- MibDir = ?config(snmp_data_dir, Config),
+ MibStorage = [{module, snmpa_mib_storage_ets}],
+ MibDir = ?config(data_dir, Config),
StdMibDir = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
- Mibs = ["Test2", "TestTrap", "TestTrapv2"],
- StdMibs = ["OTP-SNMPEA-MIB",
- "SNMP-COMMUNITY-MIB",
- "SNMP-FRAMEWORK-MIB",
- "SNMP-MPD-MIB",
- "SNMP-NOTIFICATION-MIB",
- "SNMP-TARGET-MIB",
- %% "SNMP-USER-BASED-SM-MIB",
- "SNMP-VIEW-BASED-ACM-MIB",
- "SNMPv2-MIB",
- "SNMPv2-TC",
- "SNMPv2-TM"],
+ Mibs = ["Test2", "TestTrap", "TestTrapv2"],
+ StdMibs = ["OTP-SNMPEA-MIB",
+ "SNMP-COMMUNITY-MIB",
+ "SNMP-FRAMEWORK-MIB",
+ "SNMP-MPD-MIB",
+ "SNMP-NOTIFICATION-MIB",
+ "SNMP-TARGET-MIB",
+ %% "SNMP-USER-BASED-SM-MIB",
+ "SNMP-VIEW-BASED-ACM-MIB",
+ "SNMPv2-MIB",
+ "SNMPv2-TC",
+ "SNMPv2-TM"],
?DBG("cache_test -> start symbolic store", []),
?line sym_start(Prio, MibStorage, Verbosity),
?DBG("cache_test -> start mib server", []),
- GcLimit = 2,
- Age = timer:seconds(10),
+ GcLimit = 2,
+ Age = timer:seconds(10),
CacheOpts = [{autogc, false}, {age, Age}, {gclimit, GcLimit}],
?line MibsPid = mibs_start(Prio, MibStorage, [], Verbosity, CacheOpts),
@@ -537,7 +643,7 @@ mnesia_stop() ->
%% - Symbolic Store mini interface
sym_start(Prio, Verbosity) ->
- sym_start(Prio, ets, Verbosity).
+ sym_start(Prio, mib_storage(), Verbosity).
sym_start(Prio, MibStorage, Verbosity) ->
Opts = [{mib_storage, MibStorage}, {verbosity,Verbosity}],
@@ -554,7 +660,7 @@ sym_info() ->
%% -- MIB server mini interface
mibs_start(Prio, Verbosity) when is_atom(Prio) andalso is_atom(Verbosity) ->
- mibs_start(Prio, ets, [], Verbosity).
+ mibs_start(Prio, mib_storage(), [], Verbosity).
mibs_start(Prio, MibStorage, Verbosity)
when is_atom(Prio) andalso is_atom(Verbosity) ->
@@ -671,6 +777,11 @@ which_mib(M1, M2) ->
{error, {invalid_mib, M1, M2}}.
+%% Default mib-storage
+mib_storage() ->
+ [{module, snmpa_mib_storage_ets}].
+
+
%% --
display_memory_usage(MibsPid) ->
diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl
index 09e1eb25a9..6fe97ccd25 100644
--- a/lib/snmp/test/snmp_agent_test.erl
+++ b/lib/snmp/test/snmp_agent_test.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -24,7 +24,402 @@
%% * Test fault-tolerance (kill master etc)
%%
--compile(export_all).
+-export([
+ all/0,
+ groups/0,
+ init_per_suite/1, end_per_suite/1,
+ init_per_group/2, end_per_group/2,
+ init_per_testcase/2, end_per_testcase/2,
+
+ %% all_tcs - misc
+ app_info/1,
+ info_test/1,
+
+ %% all_tcs - test_v1
+ simple/1,
+ db_notify_client/1,
+ v1_processing/1,
+ big/1,
+ big2/1,
+ loop_mib/1,
+ api/1,
+ subagent/1,
+ mnesia/1,
+ sa_register/1,
+ v1_trap/1,
+ sa_error/1,
+ next_across_sa/1,
+ undo/1,
+ sparse_table/1,
+ cnt_64/1,
+ opaque/1,
+ change_target_addr_config/1,
+
+ %% all_tcs - test_v1 - multiple_reqs
+ mul_get/1,
+ mul_get_err/1,
+ mul_next/1,
+ mul_next_err/1,
+ mul_set/1,
+ mul_set_err/1,
+
+ %% all_tcs - test_v1 - reported_bugs
+ otp_1128/1,
+ otp_1129/1,
+ otp_1131/1,
+ otp_1162/1,
+ otp_1222/1,
+ otp_1298/1,
+ otp_1331/1,
+ otp_1338/1,
+ otp_1342/1,
+ otp_1366/1,
+ otp_2776/1,
+ otp_2979/1,
+ otp_3187/1,
+ otp_3725/1,
+
+ %% all_tcs - test_v1 - standard_mibs
+ snmp_standard_mib/1,
+ snmp_community_mib/1,
+ snmp_framework_mib/1,
+ snmp_target_mib/1,
+ snmp_notification_mib/1,
+ snmp_view_based_acm_mib/1,
+
+ %% all_tcs - test_v2
+ simple_2/1,
+ v2_processing/1,
+ big_2/1,
+ big2_2/1,
+ loop_mib_2/1,
+ api_2/1,
+ subagent_2/1,
+ mnesia_2/1,
+ sa_register_2/1,
+ v2_trap/1,
+ sa_error_2/1,
+ next_across_sa_2/1,
+ undo_2/1,
+ v2_types/1,
+ implied/1,
+ sparse_table_2/1,
+ cnt_64_2/1,
+ opaque_2/1,
+ v2_caps/1,
+
+ %% all_tcs - test_v2 - multiple_reqs_2
+ mul_get_2/1,
+ mul_get_err_2/1,
+ mul_next_2/1,
+ mul_next_err_2/1,
+ mul_set_2/1,
+ mul_set_err_2/1,
+
+ %% all_tcs - test_v2 - v2_inform
+ v2_inform_i/1,
+
+ %% all_tcs - test_v2 - reported_bugs_2
+ otp_1128_2/1,
+ otp_1129_2/1,
+ otp_1131_2/1,
+ otp_1162_2/1,
+ otp_1222_2/1,
+ otp_1298_2/1,
+ otp_1331_2/1,
+ otp_1338_2/1,
+ otp_1342_2/1,
+ otp_1366_2/1,
+ otp_2776_2/1,
+ otp_2979_2/1,
+ otp_3187_2/1,
+
+ %% all_tcs - test_v2 - standard_mibs_2
+ snmpv2_mib_2/1,
+ snmp_community_mib_2/1,
+ snmp_framework_mib_2/1,
+ snmp_target_mib_2/1,
+ snmp_notification_mib_2/1,
+ snmp_view_based_acm_mib_2/1,
+
+ %% all_tcs - test_v1_v2
+ simple_bi/1,
+
+ %% all_tcs - test_v3
+ simple_3/1,
+ v3_processing/1,
+ big_3/1,
+ big2_3/1,
+ api_3/1,
+ subagent_3/1,
+ mnesia_3/1,
+ loop_mib_3/1,
+ sa_register_3/1,
+ v3_trap/1,
+ sa_error_3/1,
+ next_across_sa_3/1,
+ undo_3/1,
+ v2_types_3/1,
+ implied_3/1,
+ sparse_table_3/1,
+ cnt_64_3/1,
+ opaque_3/1,
+ v2_caps_3/1,
+
+ %% all_tcs - test_v3 - multiple_reqs_3
+ mul_get_3/1,
+ mul_get_err_3/1,
+ mul_next_3/1,
+ mul_next_err_3/1,
+ mul_set_3/1,
+ mul_set_err_3/1,
+
+ %% all_tcs - test_v3 - v3_inform
+ v3_inform_i/1,
+
+ %% all_tcs - test_v3 - reported_bugs_3
+ otp_1128_3/1,
+ otp_1129_3/1,
+ otp_1131_3/1,
+ otp_1162_3/1,
+ otp_1222_3/1,
+ otp_1298_3/1,
+ otp_1331_3/1,
+ otp_1338_3/1,
+ otp_1342_3/1,
+ otp_1366_3/1,
+ otp_2776_3/1,
+ otp_2979_3/1,
+ otp_3187_3/1,
+ otp_3542/1,
+
+ %% all_tcs - test_v3 - standard_mibs_3
+ snmpv2_mib_3/1,
+ snmp_framework_mib_3/1,
+ snmp_mpd_mib_3/1,
+ snmp_target_mib_3/1,
+ snmp_notification_mib_3/1,
+ snmp_view_based_acm_mib_3/1,
+ snmp_user_based_sm_mib_3/1,
+
+ %% all_tcs - test_v3 - v3_security
+ v3_crypto_basic/1,
+ v3_md5_auth/1,
+ v3_sha_auth/1,
+ v3_des_priv/1,
+
+ %% all_tcs - test_multi_threaded
+ multi_threaded/1,
+ mt_trap/1,
+
+ %% all_tcs - mib_storage - mib_storage_ets
+ mse_simple/1,
+ mse_v1_processing/1,
+ mse_big/1,
+ mse_big2/1,
+ mse_loop_mib/1,
+ mse_api/1,
+ mse_sa_register/1,
+ mse_v1_trap/1,
+ mse_sa_error/1,
+ mse_next_across_sa/1,
+ mse_undo/1,
+ mse_standard_mib/1,
+ mse_community_mib/1,
+ mse_framework_mib/1,
+ mse_target_mib/1,
+ mse_notification_mib/1,
+ mse_view_based_acm_mib/1,
+ mse_sparse_table/1,
+ mse_me_of/1,
+ mse_mib_of/1,
+
+ %% all_tcs - mib_storage - mib_storage_dets
+ msd_simple/1,
+ msd_v1_processing/1,
+ msd_big/1,
+ msd_big2/1,
+ msd_loop_mib/1,
+ msd_api/1,
+ msd_sa_register/1,
+ msd_v1_trap/1,
+ msd_sa_error/1,
+ msd_next_across_sa/1,
+ msd_undo/1,
+ msd_standard_mib/1,
+ msd_community_mib/1,
+ msd_framework_mib/1,
+ msd_target_mib/1,
+ msd_notification_mib/1,
+ msd_view_based_acm_mib/1,
+ msd_sparse_table/1,
+ msd_me_of/1,
+ msd_mib_of/1,
+
+ %% all_tcs - mib_storage - mib_storage_mnesia
+ msm_simple/1,
+ msm_v1_processing/1,
+ msm_big/1,
+ msm_big2/1,
+ msm_loop_mib/1,
+ msm_api/1,
+ msm_sa_register/1,
+ msm_v1_trap/1,
+ msm_sa_error/1,
+ msm_next_across_sa/1,
+ msm_undo/1,
+ msm_standard_mib/1,
+ msm_community_mib/1,
+ msm_framework_mib/1,
+ msm_target_mib/1,
+ msm_notification_mib/1,
+ msm_view_based_acm_mib/1,
+ msm_sparse_table/1,
+ msm_me_of/1,
+ msm_mib_of/1,
+
+ %% all_tcs - mib_storage - mse_size_check
+ mse_size_check/1,
+
+ %% all_tcs - mib_storage - msd_size_check
+ msd_size_check/1,
+
+ %% all_tcs - mib_storage - msm_size_check
+ msm_size_check/1,
+
+ %% all_tcs - mib_storage - varm_mib_storage_dets
+ msd_varm_mib_start/1,
+
+ %% all_tcs - mib_storage - varm_mib_storage_mnesia
+ msm_varm_mib_start/1,
+
+ %% all_tcs - tickets1 - otp4394
+ otp_4394/1,
+
+ %% all_tcs - tickets1 - otp7157
+ otp_7157/1,
+
+ %% tickets2
+ otp8395/1,
+ otp9884/1
+
+ ]).
+
+%% Internal exports
+-export([dummy_manager_init/2,
+ v3_sync/1,
+ v3_inform_sync/1,
+ v2_caps_i/1,
+ v1_proc/0,
+ v2_proc/0,
+ big_test/0,
+ big_test_2/0,
+ simple_standard_test/0,
+ db_notify_client_test/0,
+ notify/2,
+ multi_threaded_test/0,
+ mt_trap_test/1,
+ types_v2_test/0,
+ implied_test/1,
+ sparse_table_test/0,
+ cnt_64_test/1,
+ opaque_test/0,
+ api_test/1,
+ unreg_test/0,
+ load_test/0,
+ load_test_sa/0,
+ api_test2/0,
+ api_test3/0,
+ do_mul_get/0,
+ do_mul_get_err/0,
+ do_mul_next/0,
+ do_mul_next_err/0,
+ do_mul_set/0,
+ do_mul_set_err/0,
+ sa_mib/0,
+ ma_trap1/1,
+ ma_trap2/1,
+ ma_v2_2_v1_trap/1,
+ ma_v2_2_v1_trap2/1,
+ sa_trap1/1,
+ sa_trap2/1,
+ sa_trap3/1,
+ ma_v2_trap1/1,
+ ma_v2_trap2/1,
+ ma_v2_inform1/1,
+ ma_v2_inform2/1,
+ ma_v2_inform3/1,
+ delivery_targets/3,
+ delivery_info/4,
+ ma_v1_2_v2_trap/1,
+ ma_v1_2_v2_trap2/1,
+ sa_v1_2_v2_trap1/1,
+ sa_v1_2_v2_trap2/1,
+ sa_v1_2_v2_trap3/1,
+ sa_errs_bad_value/0,
+ sa_errs_gen_err/0,
+ sa_too_big/0,
+ next_across_sa_test/0,
+ undo_test/0,
+ bad_return/0,
+ standard_mib_a/0,
+ std_mib_read/0,
+ std_mib_write/0,
+ std_mib_init/0,
+ std_mib_finish/0,
+ standard_mib_test_finish/0,
+ std_mib_asn_err/0,
+ snmpv2_mib_test_finish/0,
+ std_mib_a/0,
+ std_mib_b/1,
+ std_mib_c/1,
+ snmpv2_mib_a/0,
+ snmp_community_mib_test/0,
+ snmp_framework_mib_test/0,
+ snmp_mpd_mib_a/0,
+ snmp_mpd_mib_b/0,
+ snmp_mpd_mib_c/1,
+ snmp_target_mib_test/0,
+ snmp_notification_mib_test/0,
+ do_set/1,
+ add_row/1,
+ del_row/1,
+ use_no_rights/0,
+ use_rights/0,
+ usm_add_user1/0,
+ usm_use_user/0,
+ usm_key_change1/2,
+ usm_key_change2/4,
+ usm_key_change3/4,
+ usm_read/0,
+ usm_del_user/0,
+ usm_bad/0,
+ loop_mib_1/0,
+ loop_mib_2/0,
+ otp_1129_i/1,
+ otp_1162_test/0,
+ otp_1131_test/0,
+ otp_1222_test/0,
+ otp_1298_test/0,
+ otp_1331_test/0,
+ otp_1338_test/0,
+ otp_1342_test/0,
+ otp_1366_test/0,
+ otp_1128_test/0,
+ otp_2776_test/0,
+ otp_2979_test/0,
+ otp_3542_test/0,
+ otp_3725_test/1,
+ otp_4394_test/0,
+ otp_7157_test/1,
+ otp9884_backup/4,
+ agent_log_validation/0,
+ mnesia_init/1,
+ mnesia_start/0,
+ mnesia_stop/0,
+ start_stdalone_agent/1,
+ do_info/1
+ ]).
-define(application, snmp).
@@ -86,6 +481,26 @@
end).
+-define(expect1(What),
+ snmp_agent_test_lib:expect(?MODULE, ?LINE,
+ What)).
+-define(expect2(What, ExpVBs),
+ snmp_agent_test_lib:expect(?MODULE, ?LINE,
+ What, ExpVBs)).
+-define(expect3(Err, Idx, ExpVBs),
+ snmp_agent_test_lib:expect(?MODULE, ?LINE,
+ Err, Idx, ExpVBs)).
+-define(expect4(Err, Idx, ExpVBs, To),
+ snmp_agent_test_lib:expect(?MODULE, ?LINE,
+ Err, Idx, ExpVBs, To)).
+-define(expect5(Type, Ent, Gen, Spec, ExpVBs),
+ snmp_agent_test_lib:expect(?MODULE, ?LINE,
+ Type, Ent, Gen, Spec, ExpVBs)).
+-define(expect6(Type, Ent, Gen, Spec, ExpVBs, To),
+ snmp_agent_test_lib:expect(?MODULE, ?LINE,
+ Type, Ent, Gen, Spec, ExpVBs, To)).
+
+
all() ->
%% Reqs = [mnesia, distribution, {local_slave_nodes, 2}, {time, 360}],
Conf1 = [{group, all_tcs}],
@@ -94,19 +509,8 @@ all() ->
groups() ->
[
- {all_tcs, [], cases()},
- {mib_storage, [],
- [
- {group, mib_storage_ets},
- {group, mib_storage_dets},
- {group, mib_storage_mnesia},
- {group, mib_storage_size_check_ets},
- {group, mib_storage_size_check_dets},
- {group, mib_storage_size_check_mnesia},
- {group, mib_storage_varm_dets},
- {group, mib_storage_varm_mnesia}
- ]
- },
+ {all_tcs, [], cases()},
+ {mib_storage, [], mib_storage_cases()},
{mib_storage_ets, [], mib_storage_ets_cases()},
{mib_storage_dets, [], mib_storage_dets_cases()},
{mib_storage_mnesia, [], mib_storage_mnesia_cases()},
@@ -123,109 +527,20 @@ groups() ->
{test_multi_threaded, [], mt_cases()},
{multiple_reqs, [], mul_cases()},
{multiple_reqs_2, [], mul_cases_2()},
- {v2_inform, [],
- [
- v2_inform_i
- ]
- },
- {v3_security, [],
- [
- v3_crypto_basic,
- v3_md5_auth,
- v3_sha_auth,
- v3_des_priv
- ]
- },
- {standard_mibs, [],
- [
- snmp_standard_mib,
- snmp_community_mib,
- snmp_framework_mib,
- snmp_target_mib,
- snmp_notification_mib,
- snmp_view_based_acm_mib
- ]
- },
- {standard_mibs_2, [],
- [
- snmpv2_mib_2,
- snmp_community_mib_2,
- snmp_framework_mib_2,
- snmp_target_mib_2,
- snmp_notification_mib_2,
- snmp_view_based_acm_mib_2
- ]
- },
- {standard_mibs_3, [],
- [
- snmpv2_mib_3,
- snmp_framework_mib_3,
- snmp_mpd_mib_3,
- snmp_target_mib_3,
- snmp_notification_mib_3,
- snmp_view_based_acm_mib_3,
- snmp_user_based_sm_mib_3
- ]
- },
- {reported_bugs, [],
- [
- otp_1128,
- otp_1129,
- otp_1131,
- otp_1162,
- otp_1222,
- otp_1298,
- otp_1331,
- otp_1338,
- otp_1342,
- otp_2776,
- otp_2979,
- otp_3187,
- otp_3725
- ]
- },
- {reported_bugs_2, [],
- [
- otp_1128_2,
- otp_1129_2,
- otp_1131_2,
- otp_1162_2,
- otp_1222_2,
- otp_1298_2,
- otp_1331_2,
- otp_1338_2,
- otp_1342_2,
- otp_2776_2,
- otp_2979_2,
- otp_3187_2
- ]
- },
- {reported_bugs_3, [],
- [
- otp_1128_3,
- otp_1129_3,
- otp_1131_3,
- otp_1162_3,
- otp_1222_3,
- otp_1298_3,
- otp_1331_3,
- otp_1338_3,
- otp_1342_3,
- otp_2776_3,
- otp_2979_3,
- otp_3187_3,
- otp_3542
- ]
- },
- {tickets1, [],
- [
- {group, otp_4394},
- {group, otp_7157}
- ]
- },
- {tickets2, [], [otp8395, otp9884]},
- {otp_4394, [], [otp_4394_test]},
- {otp_7157, [], [otp_7157_test]}
+ {multiple_reqs_3, [], mul_cases_3()},
+ {v2_inform, [], v2_inform_cases()},
+ {v3_inform, [], v3_inform_cases()},
+ {v3_security, [], v3_security_cases()},
+ {standard_mibs, [], standard_mibs_cases()},
+ {standard_mibs_2, [], standard_mibs2_cases()},
+ {standard_mibs_3, [], standard_mibs3_cases()},
+ {reported_bugs, [], reported_bugs_cases()},
+ {reported_bugs_2, [], reported_bugs2_cases()},
+ {reported_bugs_3, [], reported_bugs3_cases()},
+ {tickets1, [], tickets1_cases()},
+ {tickets2, [], tickets2_cases()},
+ {otp4394, [], [otp_4394]},
+ {otp7157, [], [otp_7157]}
].
@@ -258,15 +573,19 @@ end_per_suite(Config) when is_list(Config) ->
init_per_group(all_tcs = GroupName, Config) ->
init_all(snmp_test_lib:init_group_top_dir(GroupName, Config));
-init_per_group(otp_7157 = GroupName, Config) ->
- init_otp_7157(snmp_test_lib:init_group_top_dir(GroupName, Config));
-init_per_group(otp_4394 = GroupName, Config) ->
- init_otp_4394(snmp_test_lib:init_group_top_dir(GroupName, Config));
+init_per_group(otp7157 = GroupName, Config) ->
+ otp_7157_init(snmp_test_lib:init_group_top_dir(GroupName, Config));
+init_per_group(otp4394 = GroupName, Config) ->
+ otp_4394_init(snmp_test_lib:init_group_top_dir(GroupName, Config));
init_per_group(v2_inform = GroupName, Config) ->
init_v2_inform(snmp_test_lib:init_group_top_dir(GroupName, Config));
+init_per_group(v3_inform = GroupName, Config) ->
+ init_v3_inform(snmp_test_lib:init_group_top_dir(GroupName, Config));
+init_per_group(multiple_reqs = GroupName, Config) ->
+ init_mul(snmp_test_lib:init_group_top_dir(GroupName, Config));
init_per_group(multiple_reqs_2 = GroupName, Config) ->
init_mul(snmp_test_lib:init_group_top_dir(GroupName, Config));
-init_per_group(multiple_reqs = GroupName, Config) ->
+init_per_group(multiple_reqs_3 = GroupName, Config) ->
init_mul(snmp_test_lib:init_group_top_dir(GroupName, Config));
init_per_group(test_multi_threaded = GroupName, Config) ->
init_mt(snmp_test_lib:init_group_top_dir(GroupName, Config));
@@ -284,8 +603,10 @@ init_per_group(mib_storage_varm_mnesia = GroupName, Config) ->
init_varm_mib_storage_mnesia(snmp_test_lib:init_group_top_dir(GroupName,
Config));
init_per_group(mib_storage_varm_dets = GroupName, Config) ->
- init_varm_mib_storage_dets(snmp_test_lib:init_group_top_dir(GroupName,
- Config));
+ ?DBG("init_per_group(mib_storage_varm_dets) -> entry with"
+ "~n Config: ~p", [Config]),
+ init_varm_mib_storage_dets(
+ snmp_test_lib:init_group_top_dir(GroupName, Config));
init_per_group(mib_storage_size_check_mnesia = GroupName, Config) ->
init_size_check_msm(snmp_test_lib:init_group_top_dir(GroupName, Config));
init_per_group(mib_storage_size_check_dets = GroupName, Config) ->
@@ -304,16 +625,20 @@ init_per_group(GroupName, Config) ->
end_per_group(all_tcs, Config) ->
finish_all(Config);
-end_per_group(otp_7157, Config) ->
- finish_otp_7157(Config);
-end_per_group(otp_4394, Config) ->
- finish_otp_4394(Config);
+end_per_group(otp7157, Config) ->
+ otp_7157_finish(Config);
+end_per_group(otp4394, Config) ->
+ otp_4394_finish(Config);
end_per_group(v2_inform, Config) ->
- finish_v2_inform(Config);
-end_per_group(multiple_reqs_2, Config) ->
- finish_mul(Config);
+ finish_v2_inform(Config);
+end_per_group(v3_inform, Config) ->
+ finish_v3_inform(Config);
end_per_group(multiple_reqs, Config) ->
finish_mul(Config);
+end_per_group(multiple_reqs_2, Config) ->
+ finish_mul(Config);
+end_per_group(multiple_reqs_3, Config) ->
+ finish_mul(Config);
end_per_group(test_multi_threaded, Config) ->
finish_mt(Config);
end_per_group(test_v3, Config) ->
@@ -353,9 +678,6 @@ init_per_testcase(Case, Config) when is_list(Config) ->
?DBG("init_per_testcase -> entry with"
"~n Config: ~p", [Config]),
- p("Agent Info: "
- "~n ~p", [snmpa:info()]),
-
init_per_testcase1(Case, Config).
init_per_testcase1(otp8395 = Case, Config) when is_list(Config) ->
@@ -368,7 +690,7 @@ init_per_testcase1(otp9884 = Case, Config) when is_list(Config) ->
"~n Case: ~p"
"~n Config: ~p", [Case, Config]),
otp9884({init, init_per_testcase2(Case, Config)});
-init_per_testcase1(otp_7157_test = _Case, Config) when is_list(Config) ->
+init_per_testcase1(otp_7157 = _Case, Config) when is_list(Config) ->
?DBG("init_per_testcase1 -> entry with"
"~n Case: ~p"
"~n Config: ~p", [_Case, Config]),
@@ -400,9 +722,6 @@ end_per_testcase(Case, Config) when is_list(Config) ->
?DBG("end_per_testcase -> entry with"
"~n Config: ~p", [Config]),
- p("Agent Info: "
- "~n ~p", [snmpa:info()]),
-
display_log(Config),
end_per_testcase1(Case, Config).
@@ -454,20 +773,20 @@ init_per_testcase2(Case, Config) ->
{sub_agent_top_dir, SubAgentTopDir},
{manager_top_dir, ManagerTopDir} | Config].
-end_per_testcase2(_Case, Config) ->
- Config.
+%% end_per_testcase2(_Case, Config) ->
+%% Config.
cases() ->
[
- {group, misc},
- {group, test_v1},
- {group, test_v2},
- {group, test_v1_v2},
- {group, test_v3},
- {group, test_multi_threaded},
- {group, mib_storage},
- {group, tickets1}
+ {group, misc},
+ {group, test_v1},
+ {group, test_v2},
+ {group, test_v1_v2},
+ {group, test_v3},
+ {group, test_multi_threaded},
+ {group, mib_storage},
+ {group, tickets1}
].
@@ -553,7 +872,7 @@ delete_tables() ->
mnesia:delete_table(kompissTable2),
mnesia:delete_table(snmp_variables).
-%% Creation is done in runtime!
+%% Tables are created in runtime!
delete_mib_storage_mnesia_tables() ->
mnesia:delete_table(snmpa_mib_data),
mnesia:delete_table(snmpa_mib_tree),
@@ -576,40 +895,89 @@ delete_mib_storage_mnesia_tables() ->
%% versions as well, <base>_N.
%%-----------------------------------------------------------------
-
-
-
-
-
-
-
-
+mib_storage_cases() ->
+ [
+ {group, mib_storage_ets},
+ {group, mib_storage_dets},
+ {group, mib_storage_mnesia},
+ {group, mib_storage_size_check_ets},
+ {group, mib_storage_size_check_dets},
+ {group, mib_storage_size_check_mnesia},
+ {group, mib_storage_varm_dets},
+ {group, mib_storage_varm_mnesia}
+ ].
+
mib_storage_ets_cases() ->
-[mse_simple, mse_v1_processing, mse_big, mse_big2,
- mse_loop_mib, mse_api, mse_sa_register, mse_v1_trap,
- mse_sa_error, mse_next_across_sa, mse_undo,
- mse_standard_mib, mse_community_mib, mse_framework_mib,
- mse_target_mib, mse_notification_mib,
- mse_view_based_acm_mib, mse_sparse_table, mse_me_of,
- mse_mib_of].
+ [
+ mse_simple,
+ mse_v1_processing,
+ mse_big,
+ mse_big2,
+ mse_loop_mib,
+ mse_api,
+ mse_sa_register,
+ mse_v1_trap,
+ mse_sa_error,
+ mse_next_across_sa,
+ mse_undo,
+ mse_standard_mib,
+ mse_community_mib,
+ mse_framework_mib,
+ mse_target_mib,
+ mse_notification_mib,
+ mse_view_based_acm_mib,
+ mse_sparse_table,
+ mse_me_of,
+ mse_mib_of
+ ].
mib_storage_dets_cases() ->
-[msd_simple, msd_v1_processing, msd_big, msd_big2,
- msd_loop_mib, msd_api, msd_sa_register, msd_v1_trap,
- msd_sa_error, msd_next_across_sa, msd_undo,
- msd_standard_mib, msd_community_mib, msd_framework_mib,
- msd_target_mib, msd_notification_mib,
- msd_view_based_acm_mib, msd_sparse_table, msd_me_of,
- msd_mib_of].
+ [
+ msd_simple,
+ msd_v1_processing,
+ msd_big,
+ msd_big2,
+ msd_loop_mib,
+ msd_api,
+ msd_sa_register,
+ msd_v1_trap,
+ msd_sa_error,
+ msd_next_across_sa,
+ msd_undo,
+ msd_standard_mib,
+ msd_community_mib,
+ msd_framework_mib,
+ msd_target_mib,
+ msd_notification_mib,
+ msd_view_based_acm_mib,
+ msd_sparse_table,
+ msd_me_of,
+ msd_mib_of
+ ].
mib_storage_mnesia_cases() ->
-[msm_simple, msm_v1_processing, msm_big, msm_big2,
- msm_loop_mib, msm_api, msm_sa_register, msm_v1_trap,
- msm_sa_error, msm_next_across_sa, msm_undo,
- msm_standard_mib, msm_community_mib, msm_framework_mib,
- msm_target_mib, msm_notification_mib,
- msm_view_based_acm_mib, msm_sparse_table, msm_me_of,
- msm_mib_of].
+ [
+ msm_simple,
+ msm_v1_processing,
+ msm_big,
+ msm_big2,
+ msm_loop_mib,
+ msm_api,
+ msm_sa_register,
+ msm_v1_trap,
+ msm_sa_error,
+ msm_next_across_sa,
+ msm_undo,
+ msm_standard_mib,
+ msm_community_mib,
+ msm_framework_mib,
+ msm_target_mib,
+ msm_notification_mib,
+ msm_view_based_acm_mib,
+ msm_sparse_table,
+ msm_me_of,
+ msm_mib_of
+ ].
mse_size_check_cases() ->
[mse_size_check].
@@ -628,22 +996,27 @@ varm_mib_storage_mnesia_cases() ->
init_mib_storage_ets(Config) when is_list(Config) ->
?LOG("init_mib_storage_ets -> entry", []),
- MibStorage = {snmp_mib_storage,ets},
+ MibStorage = {mib_storage, [{module, snmpa_mib_storage_ets}]},
init_ms(Config, [MibStorage]).
init_mib_storage_dets(Config) when is_list(Config) ->
- ?LOG("init_mib_storage_ets -> entry", []),
+ ?LOG("init_mib_storage_dets -> entry", []),
?line AgentDbDir = ?GCONF(agent_db_dir, Config),
- MibStorage = {snmp_mib_storage, {dets, AgentDbDir}},
+ MibStorage = {mib_storage, [{module, snmpa_mib_storage_dets},
+ {options, [{dir, AgentDbDir}]}]},
init_ms(Config, [MibStorage]).
init_mib_storage_mnesia(Config) when is_list(Config) ->
- ?LOG("init_mib_storage_ets -> entry", []),
- MibStorage = {snmp_mib_storage, {mnesia,[]}},
+ ?LOG("init_mib_storage_mnesia -> entry", []),
+ ?line AgentNode = ?GCONF(snmp_master, Config),
+ MibStorage = {mib_storage, [{module, snmpa_mib_storage_mnesia},
+ {options, [{nodes, [AgentNode]}]}]},
init_ms(Config, [MibStorage]).
init_ms(Config, Opts) when is_list(Config) ->
- ?LOG("init_mib_storage_ets -> entry", []),
+ ?LOG("init_ms -> entry with"
+ "~n Config: ~p"
+ "~n Opts: ~p", [Config, Opts]),
?line SaNode = ?GCONF(snmp_sa, Config),
?line create_tables(SaNode),
?line AgentConfDir = ?GCONF(agent_conf_dir, Config),
@@ -651,23 +1024,26 @@ init_ms(Config, Opts) when is_list(Config) ->
?line Ip = ?GCONF(ip, Config),
?line config([v1], MgrDir, AgentConfDir,
tuple_to_list(Ip), tuple_to_list(Ip)),
- MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
- MibsVerbosity = {snmp_mibserver_verbosity, trace},
- SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
+ MasterAgentVerbosity = {agent_verbosity, trace},
+ MibsVerbosity = {mib_server, [{verbosity, trace}]},
+ SymStoreVerbosity = {symbolic_store, [{verbosity, trace}]},
Opts1 = [MasterAgentVerbosity, MibsVerbosity, SymStoreVerbosity | Opts],
[{vsn, v1} | start_v1_agent(Config, Opts1)].
init_size_check_mse(Config) when is_list(Config) ->
- MibStorage = {snmp_mib_storage, ets},
+ MibStorage = {mib_storage, [{module, snmpa_mib_storage_ets}]},
init_size_check_ms(Config, [MibStorage]).
init_size_check_msd(Config) when is_list(Config) ->
AgentDbDir = ?GCONF(agent_db_dir, Config),
- MibStorage = {snmp_mib_storage, {dets, AgentDbDir}},
+ MibStorage = {mib_storage, [{module, snmpa_mib_storage_dets},
+ {options, [{dir, AgentDbDir}]}]},
init_size_check_ms(Config, [MibStorage]).
init_size_check_msm(Config) when is_list(Config) ->
- MibStorage = {snmp_mib_storage, {mnesia,[]}},
+ ?line AgentNode = ?GCONF(snmp_master, Config),
+ MibStorage = {mib_storage, [{module, snmpa_mib_storage_mnesia},
+ {options, [{nodes, [AgentNode]}]}]},
init_size_check_ms(Config, [MibStorage]).
init_size_check_ms(Config, Opts) when is_list(Config) ->
@@ -702,12 +1078,16 @@ init_varm_mib_storage_dets(Config) when is_list(Config) ->
?line Ip = ?GCONF(ip, Config),
?line config([v1], MgrDir, AgentConfDir,
tuple_to_list(Ip), tuple_to_list(Ip)),
- MibStorage = {snmp_mib_storage, {dets, AgentDbDir}},
- MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
- MibsVerbosity = {snmp_mibserver_verbosity, trace},
- SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
- Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity],
- [{vsn, v1}, {agent_opts,Opts} | Config].
+ MibStorage = {mib_storage, [{module, snmpa_mib_storage_dets},
+ {options, [{dir, AgentDbDir}]}]},
+ MasterAgentVerbosity = {agent_verbosity, trace},
+ MibsVerbosity = {mib_server, [{verbosity, trace}]},
+ SymStoreVerbosity = {symbolic_store, [{verbosity, trace}]},
+ Opts = [MibStorage,
+ MasterAgentVerbosity,
+ MibsVerbosity,
+ SymStoreVerbosity],
+ [{vsn, v1}, {agent_opts, Opts} | Config].
init_varm_mib_storage_mnesia(Config) when is_list(Config) ->
?LOG("init_varm_mib_storage_mnesia -> entry", []),
@@ -718,12 +1098,17 @@ init_varm_mib_storage_mnesia(Config) when is_list(Config) ->
?line Ip = ?GCONF(ip, Config),
?line config([v1], MgrDir, AgentConfDir,
tuple_to_list(Ip), tuple_to_list(Ip)),
- MibStorage = {snmp_mib_storage,{mnesia,[]}},
- MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
- MibsVerbosity = {snmp_mibserver_verbosity, trace},
- SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
- Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity],
- [{vsn, v1}, {agent_opts,Opts} | Config].
+ ?line AgentNode = ?GCONF(snmp_master, Config),
+ MibStorage = {mib_storage, [{module, snmpa_mib_storage_mnesia},
+ {options, [{nodes, [AgentNode]}]}]},
+ MasterAgentVerbosity = {agent_verbosity, trace},
+ MibsVerbosity = {mib_server, [{verbosity, trace}]},
+ SymStoreVerbosity = {symbolic_store, [{verbosity, trace}]},
+ Opts = [MibStorage,
+ MasterAgentVerbosity,
+ MibsVerbosity,
+ SymStoreVerbosity],
+ [{vsn, v1}, {agent_opts, Opts} | Config].
finish_mib_storage_ets(Config) when is_list(Config) ->
?LOG("finish_mib_storage_ets -> entry", []),
@@ -956,10 +1341,10 @@ varm_mib_start(Config) when is_list(Config) ->
%% Perform the test(s)
?DBG("varm_mib_start -> perform the tests", []),
- try_test(snmp_community_mib),
- try_test(snmp_framework_mib),
- try_test(snmp_target_mib),
- try_test(snmp_notification_mib),
+ try_test(snmp_community_mib_test),
+ try_test(snmp_framework_mib_test),
+ try_test(snmp_target_mib_test),
+ try_test(snmp_notification_mib_test),
%% Stop the agent (without deleting the stored files)
?DBG("varm_mib_start -> stop the agent", []),
@@ -1119,7 +1504,10 @@ finish_misc(Config) ->
finish_v1(Config).
misc_cases() ->
-[app_info, info_test].
+ [
+ app_info,
+ info_test
+ ].
app_info(suite) -> [];
app_info(Config) when is_list(Config) ->
@@ -1270,10 +1658,10 @@ v3_cases() ->
subagent_3,
mnesia_3,
loop_mib_3,
- multiple_reqs_3,
+ {group, multiple_reqs_3},
sa_register_3,
v3_trap,
- v3_inform,
+ {group, v3_inform},
sa_error_3,
next_across_sa_3,
undo_3,
@@ -1626,7 +2014,7 @@ change_target_addr_config(Config) when is_list(Config) ->
dummy_manager_start(MA) ->
?DBG("dummy_manager_start -> entry",[]),
- Pid = spawn(get(mgr_node), ?MODULE,dummy_manager_init,[self(),MA]),
+ Pid = spawn(get(mgr_node), ?MODULE, dummy_manager_init, [self(), MA]),
?DBG("dummy_manager_start -> Pid: ~p",[Pid]),
await_dummy_manager_started(Pid).
@@ -1818,23 +2206,41 @@ mnesia_2(X) -> ?P(mnesia_2), mnesia(X).
mnesia_3(X) -> ?P(mnesia_3), mnesia(X).
-
mul_cases() ->
-[mul_get, mul_get_err, mul_next, mul_next_err,
- mul_set_err].
-
+ [
+ mul_get,
+ mul_get_err,
+ mul_next,
+ mul_next_err,
+ mul_set,
+ mul_set_err
+ ].
+
-multiple_reqs_3(_X) ->
- {req, [], {conf, init_mul, mul_cases_3(), finish_mul}}.
+%% multiple_reqs_3(_X) ->
+%% {req, [], {conf, init_mul, mul_cases_3(), finish_mul}}.
mul_cases_2() ->
-[mul_get_2, mul_get_err_2, mul_next_2, mul_next_err_2,
- mul_set_err_2].
-
+ [
+ mul_get_2,
+ mul_get_err_2,
+ mul_next_2,
+ mul_next_err_2,
+ mul_set_2,
+ mul_set_err_2
+ ].
+
mul_cases_3() ->
- [mul_get_3, mul_get_err_3, mul_next_3, mul_next_err_3, mul_set_err_3].
+ [
+ mul_get_3,
+ mul_get_err_3,
+ mul_next_3,
+ mul_next_err_3,
+ mul_set_3,
+ mul_set_err_3
+ ].
init_mul(Config) when is_list(Config) ->
@@ -2056,27 +2462,32 @@ v3_trap(Config) when is_list(Config) ->
trap2(Config).
-v3_inform(_X) ->
- %% v2_inform(X).
- {req, [], {conf, init_v3_inform, [v3_inform_i], finish_v3_inform}}.
+v3_inform_cases() ->
+ [
+ v3_inform_i
+ ].
+
+init_v3_inform(X) ->
+ init_v2_inform(X).
+
+finish_v3_inform(X) ->
+ finish_v2_inform(X).
+
init_v2_inform(Config) when is_list(Config) ->
_Dir = ?config(agent_conf_dir, Config),
%% snmp_internal_mib:configure(Dir),
Config.
-init_v3_inform(X) ->
- init_v2_inform(X).
-
finish_v2_inform(Config) when is_list(Config) ->
_Dir = ?config(agent_conf_dir, Config),
%% snmp_internal_mib:configure(Dir),
Config.
-finish_v3_inform(X) ->
- finish_v2_inform(X).
-
-
+v2_inform_cases() ->
+ [
+ v2_inform_i
+ ].
v2_inform_i(suite) -> [];
v2_inform_i(Config) when is_list(Config) ->
@@ -2176,7 +2587,7 @@ next_across_sa(Config) when is_list(Config) ->
try_test(load_test_sa),
?P1("Testing next across subagent (endOfMibView from SA)..."),
- try_test(next_across_sa),
+ try_test(next_across_sa_test),
?P1("Unloading mib (Klas1)"),
snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]),
@@ -2186,7 +2597,7 @@ next_across_sa(Config) when is_list(Config) ->
?P1("Starting another subagent (2) "),
?line {ok, SA2} = start_subagent(SaNode, ?klas1, "Klas1"),
?P1("Testing next across subagent (wrong prefix from SA)..."),
- try_test(next_across_sa),
+ try_test(next_across_sa_test),
?P1("stop subagent (1)..."),
stop_subagent(SA),
@@ -2315,6 +2726,15 @@ v3_processing(Config) when is_list(Config) ->
%% report, which makes it in sync. The notification-generating
%% application times out, and send again. This time it'll work.
+v3_security_cases() ->
+ [
+ v3_crypto_basic,
+ v3_md5_auth,
+ v3_sha_auth,
+ v3_des_priv
+ ].
+
+
v3_crypto_basic(suite) -> [];
v3_crypto_basic(_Config) ->
?P(v3_crypto_basic),
@@ -2453,9 +2873,9 @@ v3_des_priv(Config) when is_list(Config) ->
v3_sync(Funcs) ->
?DBG("v3_sync -> entry with Funcs: ~p",[Funcs]),
g([[sysDescr, 0]]),
- expect(432, report, [{?usmStatsNotInTimeWindows_instance, any}]),
+ ?expect2(report, [{?usmStatsNotInTimeWindows_instance, any}]),
g([[sysDescr, 0]]),
- expect(433, [{[sysDescr,0], any}]),
+ ?expect1([{[sysDescr,0], any}]),
lists:foreach(fun({Func, Args}) -> apply(?MODULE, Func, Args) end, Funcs).
v3_inform_sync(MA) ->
@@ -2466,9 +2886,9 @@ v3_inform_sync(MA) ->
?DBG("v3_sync -> wait some time: ",[]),
?SLEEP(20000), % more than 1500*10 in target_addr.conf
?DBG("v3_sync -> await response",[]),
- ?line expect(1, {inform, true},
- [{[sysUpTime, 0], any},
- {[snmpTrapOID, 0], ?system ++ [0,1]}]).
+ ?line ?expect2({inform, true},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]).
v2_caps(suite) -> [];
@@ -2484,11 +2904,11 @@ v2_caps_3(X) -> ?P(v2_caps_3), v2_caps(X).
v2_caps_i(Node) ->
?line Idx = rpc:call(Node, snmp, add_agent_caps, [[1,2,3,4,5], "test cap"]),
g([[sysORID, Idx], [sysORDescr, Idx]]),
- ?line expect(1, [{[sysORID, Idx], [1,2,3,4,5]},
- {[sysORDescr, Idx], "test cap"}]),
+ ?line ?expect1([{[sysORID, Idx], [1,2,3,4,5]},
+ {[sysORDescr, Idx], "test cap"}]),
?line rpc:call(Node, snmp, del_agent_caps, [Idx]),
g([[sysORID, Idx]]),
- ?line expect(2, [{[sysORID, Idx], noSuchInstance}]).
+ ?line ?expect1([{[sysORID, Idx], noSuchInstance}]).
%% Req. Test2
@@ -2504,86 +2924,86 @@ v1_proc() ->
v1_get_p() ->
%% 4.1.2:1
g([[test2]]),
- ?line expect(10, noSuchName, 1, [{[test2], 'NULL'}]),
+ ?line ?expect3(noSuchName, 1, [{[test2], 'NULL'}]),
g([[tDescr]]),
- ?line expect(11, noSuchName, 1, [{[tDescr], 'NULL'}]),
+ ?line ?expect3(noSuchName, 1, [{[tDescr], 'NULL'}]),
g([[tDescr2,0]]),
- ?line expect(12, noSuchName, 1, [{[tDescr2,0], 'NULL'}]),
+ ?line ?expect3(noSuchName, 1, [{[tDescr2,0], 'NULL'}]),
g([[tDescr3,0]]),
- ?line expect(131, noSuchName, 1, [{[tDescr3,0], 'NULL'}]),
+ ?line ?expect3(noSuchName, 1, [{[tDescr3,0], 'NULL'}]),
g([[tDescr4,0]]),
- ?line expect(132, noSuchName, 1, [{[tDescr4,0], 'NULL'}]),
+ ?line ?expect3(noSuchName, 1, [{[tDescr4,0], 'NULL'}]),
g([[sysDescr, 0], [tDescr,0]]), % Outside mibview
- ?line expect(14, noSuchName, 2, [{[sysDescr, 0], 'NULL'},
- {[tDescr,0], 'NULL'}]),
+ ?line ?expect3(noSuchName, 2, [{[sysDescr, 0], 'NULL'},
+ {[tDescr,0], 'NULL'}]),
g([[sysDescr,3]]),
- ?line expect(15, noSuchName, 1, [{[sysDescr, 3], 'NULL'}]),
+ ?line ?expect3(noSuchName, 1, [{[sysDescr, 3], 'NULL'}]),
%% 4.1.2:2
g([[tTable]]),
- ?line expect(20, noSuchName, 1, [{[tTable], 'NULL'}]),
+ ?line ?expect3(noSuchName, 1, [{[tTable], 'NULL'}]),
g([[tEntry]]),
- ?line expect(21, noSuchName, 1, [{[tEntry], 'NULL'}]),
+ ?line ?expect3(noSuchName, 1, [{[tEntry], 'NULL'}]),
%% 4.1.2:3
g([[tTooBig, 0]]),
- ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]),
+ ?line ?expect3(tooBig, 0, [{[tTooBig, 0], 'NULL'}]),
%% 4.1.2:4
g([[tGenErr1, 0]]),
- ?line expect(40, genErr, 1, [{[tGenErr1, 0], 'NULL'}]),
+ ?line ?expect3(genErr, 1, [{[tGenErr1, 0], 'NULL'}]),
g([[tGenErr2, 0]]),
- ?line expect(41, genErr, 1, [{[tGenErr2, 0], 'NULL'}]),
+ ?line ?expect3(genErr, 1, [{[tGenErr2, 0], 'NULL'}]),
g([[sysDescr, 0], [tGenErr3, 0]]),
- ?line expect(42, genErr, 2, [{[sysDescr, 0], 'NULL'},
- {[tGenErr3, 0], 'NULL'}]).
+ ?line ?expect3(genErr, 2, [{[sysDescr, 0], 'NULL'},
+ {[tGenErr3, 0], 'NULL'}]).
v1_get_next_p() ->
%% 4.1.3:1
gn([[1,3,7,1]]),
- ?line expect(10, noSuchName, 1, [{[1,3,7,1], 'NULL'}]),
+ ?line ?expect3(noSuchName, 1, [{[1,3,7,1], 'NULL'}]),
gn([[tDescr2]]),
- ?line expect(11, tooBig, 0, any),
+ ?line ?expect3(tooBig, 0, any),
%% 4.1.3:2
gn([[tTooBig]]),
io:format("We currently don't handle tooBig correct!!!\n"),
-% ?line expect(20, tooBig, 0, [{[tTooBig], 'NULL'}]),
- ?line expect(20, tooBig, 0, any),
+% ?line ?expect3(tooBig, 0, [{[tTooBig], 'NULL'}]),
+ ?line ?expect3(tooBig, 0, any),
%% 4.1.3:3
gn([[tGenErr1]]),
% ?line expect(40, genErr, 1, [{[tGenErr1], 'NULL'}]),
- ?line expect(40, genErr, 1, any),
+ ?line ?expect3(genErr, 1, any),
gn([[tGenErr2]]),
-% ?line expect(41, genErr, 1, [{[tGenErr2], 'NULL'}]),
- ?line expect(41, genErr, 1, any),
+% ?line ?expect3(genErr, 1, [{[tGenErr2], 'NULL'}]),
+ ?line ?expect3(genErr, 1, any),
gn([[sysDescr], [tGenErr3]]),
-% ?line expect(42, genErr, 2, [{[sysDescr], 'NULL'},
+% ?line ?expect3(genErr, 2, [{[sysDescr], 'NULL'},
% {[tGenErr3], 'NULL'}]).
- ?line expect(42, genErr, 2, any).
+ ?line ?expect3(genErr, 2, any).
v1_set_p() ->
%% 4.1.5:1
s([{[1,3,7,0], i, 4}]),
- ?line expect(10, noSuchName, 1, [{[1,3,7,0], 4}]),
+ ?line ?expect3(noSuchName, 1, [{[1,3,7,0], 4}]),
s([{[tDescr,0], s, "outside mibview"}]),
- ?line expect(11, noSuchName, 1, [{[tDescr,0], "outside mibview"}]),
+ ?line ?expect3(noSuchName, 1, [{[tDescr,0], "outside mibview"}]),
s([{[tDescr3,0], s, "read-only"}]),
- ?line expect(12, noSuchName, 1, [{[tDescr3,0], "read-only"}]),
+ ?line ?expect3(noSuchName, 1, [{[tDescr3,0], "read-only"}]),
s([{[tDescr3], s, "noSuchObject"}]),
- ?line expect(13, noSuchName, 1, [{[tDescr3], "noSuchObject"}]),
+ ?line ?expect3(noSuchName, 1, [{[tDescr3], "noSuchObject"}]),
s([{[tDescr3,1], s, "noSuchInstance"}]),
- ?line expect(14, noSuchName, 1, [{[tDescr3,1], "noSuchInstance"}]),
+ ?line ?expect3(noSuchName, 1, [{[tDescr3,1], "noSuchInstance"}]),
s([{[tDescr2,0], s, "inconsistentName"}]),
- ?line expect(15, noSuchName, 1, [{[tDescr2,0], "inconsistentName"}]),
+ ?line ?expect3(noSuchName, 1, [{[tDescr2,0], "inconsistentName"}]),
%% 4.1.5:2
s([{[tDescr2, 0], i, 4}]),
- ?line expect(20, badValue, 1, [{[tDescr2, 0], 4}]),
+ ?line ?expect3(badValue, 1, [{[tDescr2, 0], 4}]),
s([{[tDescr2, 0], s, "badValue"}]),
- ?line expect(21, badValue, 1, [{[tDescr2, 0], "badValue"}]),
+ ?line ?expect3(badValue, 1, [{[tDescr2, 0], "badValue"}]),
%% 4.1.5:3
%% The standard is quite incorrect here. The resp pdu was too big. In
@@ -2593,14 +3013,14 @@ v1_set_p() ->
%% of the std-like original value.
s([{[tTooBig, 0], s, ?tooBigStr}]),
%% according to std:
-% ?line expect(30, tooBig, 0, [{[tTooBig, 0], ?tooBigStr}]),
- ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]),
+% ?line ?expect3(tooBig, 0, [{[tTooBig, 0], ?tooBigStr}]),
+ ?line ?expect3(tooBig, 0, [{[tTooBig, 0], 'NULL'}]),
%% 4.1.5:4
s([{[tDescr2, 0], s, "is_set_ok_fail"}]),
- ?line expect(40, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]),
+ ?line ?expect3(genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]),
s([{[tDescr2, 0], s, "commit_fail"}]),
- ?line expect(41, genErr, 1, [{[tDescr2, 0], "commit_fail"}]).
+ ?line ?expect3(genErr, 1, [{[tDescr2, 0], "commit_fail"}]).
%% Req. Test2
v2_proc() ->
@@ -2616,183 +3036,183 @@ v2_get_p() ->
%% 4.2.1:2
?DBG("v2_get_p -> entry",[]),
g([[test2]]),
- ?line expect(10, [{[test2], noSuchObject}]),
+ ?line ?expect1([{[test2], noSuchObject}]),
g([[tDescr]]),
- ?line expect(11, [{[tDescr], noSuchObject}]),
+ ?line ?expect1([{[tDescr], noSuchObject}]),
g([[tDescr4,0]]),
- ?line expect(12, [{[tDescr4,0], noSuchObject}]),
+ ?line ?expect1([{[tDescr4,0], noSuchObject}]),
g([[sysDescr, 0], [tDescr,0]]), % Outside mibview
- ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"},
- {[tDescr,0], noSuchObject}]),
+ ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"},
+ {[tDescr,0], noSuchObject}]),
g([[tTable]]),
- ?line expect(14, [{[tTable], noSuchObject}]),
+ ?line ?expect1([{[tTable], noSuchObject}]),
g([[tEntry]]),
- ?line expect(15, [{[tEntry], noSuchObject}]),
+ ?line ?expect1([{[tEntry], noSuchObject}]),
%% 4.2.1:3
g([[tDescr2,0]]), %% instrum ret noSuchName!!!
- ?line expect(20, [{[tDescr2,0], noSuchInstance}]),
+ ?line ?expect1([{[tDescr2,0], noSuchInstance}]),
g([[tDescr3,0]]),
- ?line expect(21, [{[tDescr3,0], noSuchInstance}]),
+ ?line ?expect1([{[tDescr3,0], noSuchInstance}]),
g([[sysDescr,3]]),
- ?line expect(22, [{[sysDescr, 3], noSuchInstance}]),
+ ?line ?expect1([{[sysDescr, 3], noSuchInstance}]),
g([[tIndex,1]]),
- ?line expect(23, [{[tIndex, 1], noSuchInstance}]),
+ ?line ?expect1([{[tIndex, 1], noSuchInstance}]),
%% 4.2.1 - any other error: genErr
g([[tGenErr1, 0]]),
- ?line expect(30, genErr, 1, [{[tGenErr1, 0], 'NULL'}]),
+ ?line ?expect3(genErr, 1, [{[tGenErr1, 0], 'NULL'}]),
g([[tGenErr2, 0]]),
- ?line expect(31, genErr, 1, [{[tGenErr2, 0], 'NULL'}]),
+ ?line ?expect3(genErr, 1, [{[tGenErr2, 0], 'NULL'}]),
g([[sysDescr, 0], [tGenErr3, 0]]),
- ?line expect(32, genErr, 2, [{[sysDescr, 0], 'NULL'},
- {[tGenErr3, 0], 'NULL'}]),
+ ?line ?expect3(genErr, 2, [{[sysDescr, 0], 'NULL'},
+ {[tGenErr3, 0], 'NULL'}]),
%% 4.2.1 - tooBig
g([[tTooBig, 0]]),
- ?line expect(40, tooBig, 0, []).
+ ?line ?expect3(tooBig, 0, []).
v2_get_next_p() ->
%% 4.2.2:2
?DBG("v2_get_next_p -> entry",[]),
gn([[1,3,7,1]]),
- ?line expect(10, [{[1,3,7,1], endOfMibView}]),
+ ?line ?expect1([{[1,3,7,1], endOfMibView}]),
gn([[sysDescr], [1,3,7,1]]),
- ?line expect(11, [{[sysDescr, 0], "Erlang SNMP agent"},
- {[1,3,7,1], endOfMibView}]),
+ ?line ?expect1([{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView}]),
gn([[tCnt2, 1]]),
- ?line expect(12, [{[tCnt2,2], 100}]),
+ ?line ?expect1([{[tCnt2,2], 100}]),
gn([[tCnt2, 2]]),
- ?line expect(12, [{[tCnt2,2], endOfMibView}]),
+ ?line ?expect1([{[tCnt2,2], endOfMibView}]),
%% 4.2.2 - any other error: genErr
gn([[tGenErr1]]),
- ?line expect(20, genErr, 1, [{[tGenErr1], 'NULL'}]),
+ ?line ?expect3(genErr, 1, [{[tGenErr1], 'NULL'}]),
gn([[tGenErr2]]),
- ?line expect(21, genErr, 1, [{[tGenErr2], 'NULL'}]),
+ ?line ?expect3(genErr, 1, [{[tGenErr2], 'NULL'}]),
gn([[sysDescr], [tGenErr3]]),
- ?line expect(22, genErr, 2, [{[sysDescr], 'NULL'},
- {[tGenErr3], 'NULL'}]),
+ ?line ?expect3(genErr, 2, [{[sysDescr], 'NULL'},
+ {[tGenErr3], 'NULL'}]),
%% 4.2.2 - tooBig
gn([[tTooBig]]),
- ?line expect(20, tooBig, 0, []).
+ ?line ?expect3(tooBig, 0, []).
v2_get_bulk_p() ->
%% 4.2.3
?DBG("v2_get_bulk_p -> entry",[]),
gb(1, 1, []),
- ?line expect(10, []),
+ ?line ?expect1([]),
gb(-1, 1, []),
- ?line expect(11, []),
+ ?line ?expect1([]),
gb(-1, -1, []),
- ?line expect(12, []),
+ ?line ?expect1([]),
gb(-1, -1, []),
- ?line expect(13, []),
+ ?line ?expect1([]),
gb(2, 0, [[sysDescr], [1,3,7,1]]),
- ?line expect(14, [{[sysDescr, 0], "Erlang SNMP agent"},
- {[1,3,7,1], endOfMibView}]),
+ ?line ?expect1([{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView}]),
gb(1, 2, [[sysDescr], [1,3,7,1]]),
- ?line expect(15, [{[sysDescr, 0], "Erlang SNMP agent"},
- {[1,3,7,1], endOfMibView}]),
+ ?line ?expect1([{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView}]),
gb(0, 2, [[sysDescr], [1,3,7,1]]),
- ?line expect(16, [{[sysDescr, 0], "Erlang SNMP agent"},
- {[1,3,7,1], endOfMibView},
- {[sysObjectID, 0], [1,2,3]},
- {[1,3,7,1], endOfMibView}]),
+ ?line ?expect1([{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView},
+ {[sysObjectID, 0], [1,2,3]},
+ {[1,3,7,1], endOfMibView}]),
gb(2, 2, [[sysDescr], [1,3,7,1], [sysDescr], [1,3,7,1]]),
- ?line expect(17, [{[sysDescr, 0], "Erlang SNMP agent"},
- {[1,3,7,1], endOfMibView},
- {[sysDescr, 0], "Erlang SNMP agent"},
- {[1,3,7,1], endOfMibView},
- {[sysObjectID, 0], [1,2,3]},
- {[1,3,7,1], endOfMibView}]),
+ ?line ?expect1([{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView},
+ {[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView},
+ {[sysObjectID, 0], [1,2,3]},
+ {[1,3,7,1], endOfMibView}]),
gb(1, 2, [[sysDescr], [sysDescr], [tTooBig]]),
- ?line expect(18, [{[sysDescr, 0], "Erlang SNMP agent"},
- {[sysDescr, 0], "Erlang SNMP agent"}]),
+ ?line ?expect1([{[sysDescr, 0], "Erlang SNMP agent"},
+ {[sysDescr, 0], "Erlang SNMP agent"}]),
gb(1,12, [[tDescr2], [sysDescr]]), % next one after tDescr2 is tTooBig.
- ?line expect(19, []),
+ ?line ?expect1([]),
gb(2,2, [[sysDescr], [sysObjectID], [tGenErr1], [sysDescr]]),
- ?line expect(20, genErr, 3, [{[sysDescr], 'NULL'},
- {[sysObjectID], 'NULL'},
- {[tGenErr1], 'NULL'},
- {[sysDescr], 'NULL'}]),
+ ?line ?expect3(genErr, 3, [{[sysDescr], 'NULL'},
+ {[sysObjectID], 'NULL'},
+ {[tGenErr1], 'NULL'},
+ {[sysDescr], 'NULL'}]),
gb(0, 2, [[tCnt2, 1]]),
- ?line expect(21, [{[tCnt2,2], 100},
- {[tCnt2,2], endOfMibView}]).
+ ?line ?expect1([{[tCnt2,2], 100},
+ {[tCnt2,2], endOfMibView}]).
v2_set_p() ->
%% 4.2.5:1
?DBG("v2_set_p -> entry",[]),
s([{[1,3,7,0], i, 4}]),
- ?line expect(10, noAccess, 1, [{[1,3,7,0], 4}]),
+ ?line ?expect3(noAccess, 1, [{[1,3,7,0], 4}]),
s([{[tDescr,0], s, "outside mibview"}]),
- ?line expect(11, noAccess, 1, [{[tDescr,0], "outside mibview"}]),
+ ?line ?expect3(noAccess, 1, [{[tDescr,0], "outside mibview"}]),
%% 4.2.5:2
s([{[1,3,6,1,0], s, "noSuchObject"}]),
- ?line expect(20, notWritable, 1, [{[1,3,6,1,0], "noSuchObject"}]),
+ ?line ?expect3(notWritable, 1, [{[1,3,6,1,0], "noSuchObject"}]),
%% 4.2.5:3
s([{[tDescr2, 0], i, 4}]),
- ?line expect(30, wrongType, 1, [{[tDescr2, 0], 4}]),
+ ?line ?expect3(wrongType, 1, [{[tDescr2, 0], 4}]),
s([{[tDescr2, 0], s, "badValue"}]),
- ?line expect(31, badValue, 1, [{[tDescr2, 0], "badValue"}]),
+ ?line ?expect3(badValue, 1, [{[tDescr2, 0], "badValue"}]),
%% 4.2.5:4
s([{[tStr, 0], s, ""}]),
- ?line expect(40, wrongLength, 1, [{[tStr, 0], ""}]),
+ ?line ?expect3(wrongLength, 1, [{[tStr, 0], ""}]),
s([{[tStr, 0], s, "12345"}]),
- ?line expect(40, wrongLength, 1, [{[tStr, 0], "12345"}]),
+ ?line ?expect3(wrongLength, 1, [{[tStr, 0], "12345"}]),
%% 4.2.5:5 - N/A
%% 4.2.5:6
s([{[tInt1, 0], i, 0}]),
- ?line expect(60, wrongValue, 1, [{[tInt1, 0], 0}]),
+ ?line ?expect3(wrongValue, 1, [{[tInt1, 0], 0}]),
s([{[tInt1, 0], i, 5}]),
- ?line expect(61, wrongValue, 1, [{[tInt1, 0], 5}]),
+ ?line ?expect3(wrongValue, 1, [{[tInt1, 0], 5}]),
s([{[tInt2, 0], i, 0}]),
- ?line expect(62, wrongValue, 1, [{[tInt2, 0], 0}]),
+ ?line ?expect3(wrongValue, 1, [{[tInt2, 0], 0}]),
s([{[tInt2, 0], i, 5}]),
- ?line expect(63, wrongValue, 1, [{[tInt2, 0], 5}]),
+ ?line ?expect3(wrongValue, 1, [{[tInt2, 0], 5}]),
s([{[tInt3, 0], i, 5}]),
- ?line expect(64, wrongValue, 1, [{[tInt3, 0], 5}]),
+ ?line ?expect3(wrongValue, 1, [{[tInt3, 0], 5}]),
%% 4.2.5:7
s([{[tDescrX, 1, 1], s, "noCreation"}]),
- ?line expect(70, noCreation, 1, [{[tDescrX, 1, 1], "noCreation"}]),
+ ?line ?expect3(noCreation, 1, [{[tDescrX, 1, 1], "noCreation"}]),
%% 4.2.5:8
s([{[tDescrX, 1, 2], s, "inconsistentName"}]),
- ?line expect(80, inconsistentName, 1,
- [{[tDescrX, 1, 2], "inconsistentName"}]),
+ ?line ?expect3(inconsistentName, 1,
+ [{[tDescrX, 1, 2], "inconsistentName"}]),
%% 4.2.5:9
s([{[tCnt, 1, 2], i, 5}]),
- ?line expect(90, notWritable, 1, [{[tCnt, 1, 2], 5}]),
+ ?line ?expect3(notWritable, 1, [{[tCnt, 1, 2], 5}]),
s([{[tDescr3,0], s, "read-only"}]),
- ?line expect(90, notWritable, 1, [{[tDescr3,0], "read-only"}]),
+ ?line ?expect3(notWritable, 1, [{[tDescr3,0], "read-only"}]),
%% 4.2.5:10
s([{[tDescr2,0], s, "inconsistentValue"}]),
- ?line expect(100, inconsistentValue, 1,
- [{[tDescr2,0], "inconsistentValue"}]),
+ ?line ?expect3(inconsistentValue, 1,
+ [{[tDescr2,0], "inconsistentValue"}]),
%% 4.2.5:11
s([{[tDescr2,0], s, "resourceUnavailable"}]),
- ?line expect(110, resourceUnavailable, 1,
- [{[tDescr2,0],"resourceUnavailable"}]),
+ ?line ?expect3(resourceUnavailable, 1,
+ [{[tDescr2,0],"resourceUnavailable"}]),
%% 4.2.5:12
s([{[tDescr2, 0], s, "is_set_ok_fail"}]),
- ?line expect(120, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]).
+ ?line ?expect3(genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]).
%% commitFailed and undoFailed is tested by the 'undo' case.
@@ -2807,101 +3227,101 @@ table_test() ->
Key1c4 = [intCommunityAccess,get(mip),is("public")],
EndKey = [intCommunityEntry,[9],get(mip),is("public")],
gn([[intCommunityEntry]]),
- ?line expect(7, [{Key1c3, 2}]),
+ ?line ?expect1([{Key1c3, 2}]),
gn([[intCommunityTable]]),
- ?line expect(71, [{Key1c3, 2}]),
+ ?line ?expect1([{Key1c3, 2}]),
gn([[community]]),
- ?line expect(72, [{Key1c3, 2}]),
+ ?line ?expect1([{Key1c3, 2}]),
gn([[otpSnmpeaMIB]]),
- ?line expect(73, [{Key1c3, 2}]),
+ ?line ?expect1([{Key1c3, 2}]),
gn([[ericsson]]),
- ?line expect(74, [{Key1c3, 2}]),
+ ?line ?expect1([{Key1c3, 2}]),
gn([Key1c3]),
- ?line expect(8, [{Key2c3, 2}]),
+ ?line ?expect1([{Key2c3, 2}]),
gn([Key2c3]),
- ?line expect(9, [{Key1c4, 2}]),
+ ?line ?expect1([{Key1c4, 2}]),
gn([EndKey]),
AgentIp = [intAgentIpAddress,0],
- ?line expect(10, [{AgentIp, any}]),
+ ?line ?expect1([{AgentIp, any}]),
g([Key1c3]),
- ?line expect(11, [{Key1c3, 2}]),
+ ?line ?expect1([{Key1c3, 2}]),
g([EndKey]),
- ?line ?v1_2(expect(12, noSuchName, 1, any),
- expect(12, [{EndKey, noSuchObject}])),
+ ?line ?v1_2(?expect3(noSuchName, 1, any),
+ ?expect1([{EndKey, noSuchObject}])),
io:format("Testing row creation/deletion on communityTable...~n"),
NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")],
NewKeyc4 = [intCommunityAccess,get(mip),is("test")],
NewKeyc5 = [intCommunityStatus,get(mip),is("test")],
s([{NewKeyc5, ?createAndGo}]),
- ?line expect(14, ?v1_2(badValue, inconsistentValue), 1,any),
+ ?line ?expect3(?v1_2(badValue, inconsistentValue), 1, any),
s([{NewKeyc5, ?createAndGo}, {NewKeyc3, 2}, {NewKeyc4, 2}]),
- ?line expect(15, [{NewKeyc5, ?createAndGo},{NewKeyc3, 2}, {NewKeyc4, 2}]),
+ ?line ?expect1([{NewKeyc5, ?createAndGo},{NewKeyc3, 2}, {NewKeyc4, 2}]),
g([NewKeyc4]),
- ?line expect(16, [{NewKeyc4, 2}]),
+ ?line ?expect1([{NewKeyc4, 2}]),
s([{NewKeyc5, ?destroy}]),
- ?line expect(17, [{NewKeyc5, ?destroy}]),
+ ?line ?expect1([{NewKeyc5, ?destroy}]),
s([{NewKeyc4, 2}]),
- ?line expect(18, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc4, 2}]),
+ ?line ?expect3(?v1_2(noSuchName, inconsistentName), 1, [{NewKeyc4, 2}]),
s([{NewKeyc5, ?createAndWait}]),
- ?line expect(19, [{NewKeyc5, ?createAndWait}]),
+ ?line ?expect1([{NewKeyc5, ?createAndWait}]),
g([NewKeyc5]),
- ?line expect(20, [{NewKeyc5, ?notReady}]),
+ ?line ?expect1([{NewKeyc5, ?notReady}]),
s([{NewKeyc4, 2}]),
- ?line expect(21, [{NewKeyc4, 2}]),
+ ?line ?expect1([{NewKeyc4, 2}]),
g([NewKeyc5]),
- ?line expect(22, [{NewKeyc5, ?notReady}]),
+ ?line ?expect1([{NewKeyc5, ?notReady}]),
s([{NewKeyc3, 2}]),
- ?line expect(23, [{NewKeyc3, 2}]),
+ ?line ?expect1([{NewKeyc3, 2}]),
g([NewKeyc5]),
- ?line expect(24, [{NewKeyc5, ?notInService}]),
+ ?line ?expect1([{NewKeyc5, ?notInService}]),
s([{NewKeyc5, ?active}]),
- ?line expect(25, [{NewKeyc5, ?active}]),
+ ?line ?expect1([{NewKeyc5, ?active}]),
s([{NewKeyc5, ?destroy}]),
- ?line expect(26, [{NewKeyc5, ?destroy}]),
+ ?line ?expect1([{NewKeyc5, ?destroy}]),
s([{NewKeyc3, 3}]),
- ?line expect(27, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc3, 3}]),
- otp_1128().
+ ?line ?expect3(?v1_2(noSuchName, inconsistentName), 1, [{NewKeyc3, 3}]),
+ otp_1128_test().
%% Req. system group
simple_standard_test() ->
?DBG("simple_standard_test -> entry",[]),
gn([[1,1]]),
- ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]),
gn([[1,3]]),
- ?line expect(11, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]),
gn([[1,3,6]]),
- ?line expect(12, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]),
gn([[1,3,6,1]]),
- ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]),
gn([[1,3,6,1,2]]),
- ?line expect(14, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]),
gn([[1,3,6,1,2,1]]),
- ?line expect(15, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]),
gn([[1,3,6,1,2,1,1]]),
- ?line expect(16, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]),
gn([[sysDescr]]),
- ?line expect(17, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]),
g([[sysDescr,0]]),
- ?line expect(2, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"}]),
g([[sysDescr]]),
- ?line ?v1_2(expect(3, noSuchName, 1, any),
- expect(3, [{[sysDescr], noSuchObject}])),
+ ?line ?v1_2(?expect3(noSuchName, 1, any),
+ ?expect1([{[sysDescr], noSuchObject}])),
g([[1,6,7,0]]),
- ?line ?v1_2(expect(41, noSuchName, 1, any),
- expect(3, [{[1,6,7,0], noSuchObject}])),
+ ?line ?v1_2(?expect3(noSuchName, 1, any),
+ ?expect1([{[1,6,7,0], noSuchObject}])),
gn([[1,13]]),
- ?line ?v1_2(expect(4, noSuchName,1, any),
- expect(4, [{[1,13], endOfMibView}])),
+ ?line ?v1_2(?expect3(noSuchName,1, any),
+ ?expect1([{[1,13], endOfMibView}])),
s([{[sysLocation, 0], "new_value"}]),
- ?line expect(5, [{[sysLocation, 0], "new_value"}]),
+ ?line ?expect1([{[sysLocation, 0], "new_value"}]),
g([[sysLocation, 0]]),
- ?line expect(6, [{[sysLocation, 0], "new_value"}]),
+ ?line ?expect1([{[sysLocation, 0], "new_value"}]),
io:format("Testing noSuchName and badValue...~n"),
s([{[sysServices,0], 3}]),
- ?line expect(61, ?v1_2(noSuchName, notWritable), 1, any),
+ ?line ?expect3(?v1_2(noSuchName, notWritable), 1, any),
s([{[sysLocation, 0], i, 3}]),
- ?line expect(62, ?v1_2(badValue, wrongType), 1, any),
+ ?line ?expect3(?v1_2(badValue, wrongType), 1, any),
?DBG("simple_standard_test -> done",[]),
ok.
@@ -2918,7 +3338,7 @@ db_notify_client(Config) when is_list(Config) ->
snmpa_local_db:verbosity(trace),
Self = self(),
?DBG("db_notify_client -> register self (~p) notify client", [Self]),
- snmpa_local_db:register_notify_client(self(),?MODULE),
+ snmpa_local_db:register_notify_client(Self, ?MODULE),
%% This call (to the manager) will issue to set operations, so
%% we expect to receive to notify(insert) calls.
@@ -2943,7 +3363,7 @@ db_notify_client(Config) when is_list(Config) ->
end,
?DBG("db_notify_client -> unregister self (~p) notify client", [Self]),
- snmpa_local_db:unregister_notify_client(self()),
+ snmpa_local_db:unregister_notify_client(Self),
?DBG("db_notify_client -> minimize verbosity", []),
snmpa_local_db:verbosity(silence),
@@ -2955,12 +3375,13 @@ db_notify_client(Config) when is_list(Config) ->
db_notify_client_test() ->
?DBG("set first new sysLocation",[]),
s([{[sysLocation, 0], "new_value"}]),
- ?line expect(5, [{[sysLocation, 0], "new_value"}]),
+ ?line ?expect1([{[sysLocation, 0], "new_value"}]),
?DBG("set second new sysLocation",[]),
s([{[sysLocation, 0], "new_value"}]),
- ?line expect(5, [{[sysLocation, 0], "new_value"}]).
+ ?line ?expect1([{[sysLocation, 0], "new_value"}]).
+%% Callback function
notify(Pid, What) ->
?DBG("notify(~p,~p) -> called",[Pid,What]),
Pid ! {db_notify_test_reply, What}.
@@ -2976,24 +3397,23 @@ big_test() ->
?DBG("big_test -> testing simple next/get/set @ subagent...",[]),
gn([[klas1]]),
- ?line expect(1, [{[fname,0], ""}]),
+ ?line ?expect1([{[fname,0], ""}]),
g([[fname,0]]),
- ?line expect(2, [{[fname,0], ""}]),
+ ?line ?expect1([{[fname,0], ""}]),
s([{[fname,0], s, "test set"}]),
- ?line expect(3, [{[fname,0], "test set"}]),
+ ?line ?expect1([{[fname,0], "test set"}]),
g([[fname,0]]),
- ?line expect(4, [{[fname,0], "test set"}]),
+ ?line ?expect1([{[fname,0], "test set"}]),
?DBG("big_test -> "
"testing next from last instance in master to subagent...",[]),
gn([[?v1_2(sysServices, sysORLastChange),0]]),
- ?line expect(5, [{[fname,0], "test set"}]),
- gn([[1,1],
- [?v1_2(sysServices, sysORLastChange),0]]),
- ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"},
- {[fname,0], "test set"}]),
+ ?line ?expect1([{[fname,0], "test set"}]),
+ gn([[1,1], [?v1_2(sysServices, sysORLastChange),0]]),
+ ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"},
+ {[fname,0], "test set"}]),
s([{[fname,0], s, ""}]),
- ?line expect(52, [{[fname,0], ""}]),
+ ?line ?expect1([{[fname,0], ""}]),
table_test(),
@@ -3001,43 +3421,43 @@ big_test() ->
_FTab = [friendsEntry],
s([{[friendsEntry, [2, 3]], s, "kompis3"},
{[friendsEntry, [3, 3]], i, ?createAndGo}]),
- ?line expect(6, [{[friendsEntry, [2, 3]], "kompis3"},
- {[friendsEntry, [3, 3]], ?createAndGo}]),
+ ?line ?expect1([{[friendsEntry, [2, 3]], "kompis3"},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
g([[friendsEntry, [2, 3]],
[friendsEntry, [3, 3]]]),
- ?line expect(7, [{[friendsEntry, [2, 3]], "kompis3"},
- {[friendsEntry, [3, 3]], ?active}]),
+ ?line ?expect1([{[friendsEntry, [2, 3]], "kompis3"},
+ {[friendsEntry, [3, 3]], ?active}]),
s([{[friendsEntry, [3, 3]], i, ?destroy}]),
- ?line expect(8, [{[friendsEntry, [3, 3]], ?destroy}]),
+ ?line ?expect1([{[friendsEntry, [3, 3]], ?destroy}]),
- otp_1131(),
+ otp_1131_test(),
?DBG("big_test -> adding two rows in subagent table with special INDEX",
[]),
s([{[kompissEntry, [1, 3]], s, "kompis3"},
{[kompissEntry, [2, 3]], i, ?createAndGo}]),
- ?line expect(9, [{[kompissEntry, [1, 3]], "kompis3"},
- {[kompissEntry, [2, 3]], ?createAndGo}]),
+ ?line ?expect1([{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?createAndGo}]),
g([[kompissEntry, [1, 3]],
[kompissEntry, [2, 3]]]),
- ?line expect(10, [{[kompissEntry, [1, 3]], "kompis3"},
- {[kompissEntry, [2, 3]], ?active}]),
+ ?line ?expect1([{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?active}]),
gn([[kompissEntry, [1]],
[kompissEntry, [2]]]),
- ?line expect(11, [{[kompissEntry, [1, 3]], "kompis3"},
- {[kompissEntry, [2, 3]], ?active}]),
+ ?line ?expect1([{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?active}]),
s([{[kompissEntry, [1, 2]], s, "kompis3"},
{[kompissEntry, [2, 2]], i, ?createAndGo}]),
- ?line expect(12, [{[kompissEntry, [1, 2]], "kompis3"},
- {[kompissEntry, [2, 2]], ?createAndGo}]),
+ ?line ?expect1([{[kompissEntry, [1, 2]], "kompis3"},
+ {[kompissEntry, [2, 2]], ?createAndGo}]),
gn([[kompissEntry, [1, 1]],
[kompissEntry, [2, 1]]]),
- ?line expect(13, [{[kompissEntry, [1, 2]], "kompis3"},
- {[kompissEntry, [2, 2]], ?active}]),
+ ?line ?expect1([{[kompissEntry, [1, 2]], "kompis3"},
+ {[kompissEntry, [2, 2]], ?active}]),
s([{[kompissEntry, [2, 3]], i, ?destroy}]),
- ?line expect(14, [{[kompissEntry, [2, 3]], ?destroy}]),
+ ?line ?expect1([{[kompissEntry, [2, 3]], ?destroy}]),
s([{[kompissEntry, [2, 2]], i, ?destroy}]),
- ?line expect(15, [{[kompissEntry, [2, 2]], ?destroy}]),
+ ?line ?expect1([{[kompissEntry, [2, 2]], ?destroy}]),
?DBG("big_test -> done",[]),
ok.
@@ -3048,23 +3468,22 @@ big_test_2() ->
?P1("Testing simple next/get/set @ subagent (2)..."),
gn([[klas2]]),
- ?line expect(1, [{[fname2,0], ""}]),
+ ?line ?expect1([{[fname2,0], ""}]),
g([[fname2,0]]),
- ?line expect(2, [{[fname2,0], ""}]),
+ ?line ?expect1([{[fname2,0], ""}]),
s([{[fname2,0], s, "test set"}]),
- ?line expect(3, [{[fname2,0], "test set"}]),
+ ?line ?expect1([{[fname2,0], "test set"}]),
g([[fname2,0]]),
- ?line expect(4, [{[fname2,0], "test set"}]),
+ ?line ?expect1([{[fname2,0], "test set"}]),
- otp_1298(),
+ otp_1298_test(),
?P1("Testing next from last object in master to subagent (2)..."),
gn([[?v1_2(sysServices, sysORLastChange),0]]),
- ?line expect(5, [{[fname2,0], "test set"}]),
- gn([[1,1],
- [?v1_2(sysServices, sysORLastChange),0]]),
- ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"},
- {[fname2,0], "test set"}]),
+ ?line ?expect1([{[fname2,0], "test set"}]),
+ gn([[1,1], [?v1_2(sysServices, sysORLastChange),0]]),
+ ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"},
+ {[fname2,0], "test set"}]),
table_test(),
@@ -3072,40 +3491,40 @@ big_test_2() ->
_FTab = [friendsEntry2],
s([{[friendsEntry2, [2, 3]], s, "kompis3"},
{[friendsEntry2, [3, 3]], i, ?createAndGo}]),
- ?line expect(6, [{[friendsEntry2, [2, 3]], "kompis3"},
- {[friendsEntry2, [3, 3]], ?createAndGo}]),
+ ?line ?expect1([{[friendsEntry2, [2, 3]], "kompis3"},
+ {[friendsEntry2, [3, 3]], ?createAndGo}]),
g([[friendsEntry2, [2, 3]],
[friendsEntry2, [3, 3]]]),
- ?line expect(7, [{[friendsEntry2, [2, 3]], "kompis3"},
- {[friendsEntry2, [3, 3]], ?active}]),
+ ?line ?expect1([{[friendsEntry2, [2, 3]], "kompis3"},
+ {[friendsEntry2, [3, 3]], ?active}]),
s([{[friendsEntry2, [3, 3]], i, ?destroy}]),
- ?line expect(8, [{[friendsEntry2, [3, 3]], ?destroy}]),
+ ?line ?expect1([{[friendsEntry2, [3, 3]], ?destroy}]),
?P1("Adding two rows in subagent table with special INDEX (2)"),
s([{[kompissEntry2, [1, 3]], s, "kompis3"},
{[kompissEntry2, [2, 3]], i, ?createAndGo}]),
- ?line expect(9, [{[kompissEntry2, [1, 3]], "kompis3"},
- {[kompissEntry2, [2, 3]], ?createAndGo}]),
+ ?line ?expect1([{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?createAndGo}]),
g([[kompissEntry2, [1, 3]],
[kompissEntry2, [2, 3]]]),
- ?line expect(10, [{[kompissEntry2, [1, 3]], "kompis3"},
- {[kompissEntry2, [2, 3]], ?active}]),
+ ?line ?expect1([{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?active}]),
gn([[kompissEntry2, [1]],
[kompissEntry2, [2]]]),
- ?line expect(11, [{[kompissEntry2, [1, 3]], "kompis3"},
- {[kompissEntry2, [2, 3]], ?active}]),
+ ?line ?expect1([{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?active}]),
s([{[kompissEntry2, [1, 2]], s, "kompis3"},
{[kompissEntry2, [2, 2]], i, ?createAndGo}]),
- ?line expect(12, [{[kompissEntry2, [1, 2]], "kompis3"},
- {[kompissEntry2, [2, 2]], ?createAndGo}]),
+ ?line ?expect1([{[kompissEntry2, [1, 2]], "kompis3"},
+ {[kompissEntry2, [2, 2]], ?createAndGo}]),
gn([[kompissEntry2, [1, 1]],
[kompissEntry2, [2, 1]]]),
- ?line expect(13, [{[kompissEntry2, [1, 2]], "kompis3"},
- {[kompissEntry2, [2, 2]], ?active}]),
+ ?line ?expect1([{[kompissEntry2, [1, 2]], "kompis3"},
+ {[kompissEntry2, [2, 2]], ?active}]),
s([{[kompissEntry2, [2, 3]], i, ?destroy}]),
- ?line expect(14, [{[kompissEntry2, [2, 3]], ?destroy}]),
+ ?line ?expect1([{[kompissEntry2, [2, 3]], ?destroy}]),
s([{[kompissEntry2, [2, 2]], i, ?destroy}]),
- ?line expect(15, [{[kompissEntry2, [2, 2]], ?destroy}]),
+ ?line ?expect1([{[kompissEntry2, [2, 2]], ?destroy}]),
ok.
%% Req. Test1
@@ -3114,26 +3533,26 @@ multi_threaded_test() ->
g([[multiStr,0]]),
Pid = get_multi_pid(),
g([[sysUpTime,0]]),
- ?line expect(1, [{[sysUpTime,0], any}]),
+ ?line ?expect1([{[sysUpTime,0], any}]),
s([{[sysLocation, 0], s, "pelle"}]),
- ?line expect(2, [{[sysLocation, 0], "pelle"}]),
+ ?line ?expect1([{[sysLocation, 0], "pelle"}]),
Pid ! continue,
- ?line expect(3, [{[multiStr,0], "ok"}]),
+ ?line ?expect1([{[multiStr,0], "ok"}]),
s([{[multiStr, 0], s, "block"}]),
Pid2 = get_multi_pid(),
g([[sysUpTime,0]]),
- ?line expect(4, [{[sysUpTime,0], any}]),
+ ?line ?expect1([{[sysUpTime,0], any}]),
g([[multiStr,0]]),
Pid3 = get_multi_pid(),
g([[sysUpTime,0]]),
- ?line expect(5, [{[sysUpTime,0], any}]),
+ ?line ?expect1([{[sysUpTime,0], any}]),
s([{[sysLocation, 0], s, "kalle"}]),
Pid3 ! continue,
- ?line expect(6, [{[multiStr,0], "ok"}]),
+ ?line ?expect1([{[multiStr,0], "ok"}]),
Pid2 ! continue,
- ?line expect(7, [{[multiStr,0], "block"}]),
- ?line expect(8, [{[sysLocation,0], "kalle"}]).
+ ?line ?expect1([{[multiStr,0], "block"}]),
+ ?line ?expect1([{[sysLocation,0], "kalle"}]).
%% Req. Test1, TestTrapv2
mt_trap_test(MA) ->
@@ -3141,9 +3560,8 @@ mt_trap_test(MA) ->
?DBG("mt_trap_test(01) -> issue testTrapv22 (standard trap)", []),
snmpa:send_trap(MA, testTrapv22, "standard trap"),
?DBG("mt_trap_test(02) -> await v2trap", []),
- ?line expect(mt_trap_test_1, v2trap,
- [{[sysUpTime, 0], any},
- {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ ?line ?expect2(v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
?DBG("mt_trap_test(03) -> issue mtTrap (standard trap)", []),
snmpa:send_trap(MA, mtTrap, "standard trap"),
@@ -3152,21 +3570,21 @@ mt_trap_test(MA) ->
g([[sysUpTime,0]]),
?DBG("mt_trap_test(06) -> await sysUpTime", []),
- ?line expect(mt_trap_test_2, [{[sysUpTime,0], any}]),
+ ?line ?expect1([{[sysUpTime,0], any}]),
?DBG("mt_trap_test(07) -> issue testTrapv22 (standard trap)", []),
snmpa:send_trap(MA, testTrapv22, "standard trap"),
?DBG("mt_trap_test(08) -> await v2trap", []),
- ?line expect(mt_trap_test_3, v2trap,
- [{[sysUpTime, 0], any},
- {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ ?line ?expect2(v2trap,
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
?DBG("mt_trap_test(09) -> send continue to multi-pid", []),
Pid ! continue,
?DBG("mt_trap_test(10) -> await v2trap", []),
- ?line expect(mt_trap_test_4, v2trap, [{[sysUpTime, 0], any},
- {[snmpTrapOID, 0], ?testTrap ++ [2]},
- {[multiStr,0], "ok"}]),
+ ?line ?expect2(v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?testTrap ++ [2]},
+ {[multiStr,0], "ok"}]),
?DBG("mt_trap_test(11) -> done", []),
ok.
@@ -3187,26 +3605,26 @@ types_v2_test() ->
?P1("Testing v2 types..."),
s([{[bits1,0], 2#10}]),
- ?line expect(1, [{[bits1,0], ?str(2#10)}]),
+ ?line ?expect1([{[bits1,0], ?str(2#10)}]),
g([[bits1,0]]),
- ?line expect(2, [{[bits1,0], ?str(2#101)}]),
+ ?line ?expect1([{[bits1,0], ?str(2#101)}]),
s([{[bits2,0], 2#11000000110}]),
- ?line expect(3, [{[bits2,0], ?str(2#11000000110)}]),
+ ?line ?expect1([{[bits2,0], ?str(2#11000000110)}]),
g([[bits2,0]]),
- ?line expect(4, [{[bits2,0], ?str(2#11000000110)}]),
+ ?line ?expect1([{[bits2,0], ?str(2#11000000110)}]),
g([[bits3,0]]),
- ?line expect(50, genErr, 1, any),
+ ?line ?expect3(genErr, 1, any),
g([[bits4,0]]),
- ?line expect(51, genErr, 1, any),
+ ?line ?expect3(genErr, 1, any),
s([{[bits1,0], s, [2#10]}]),
- ?line expect(6, ?v1_2(badValue, wrongValue), 1, any),
+ ?line ?expect3(?v1_2(badValue, wrongValue), 1, any),
s([{[bits2,0], 2#11001001101010011}]),
- ?line expect(7, ?v1_2(badValue, wrongValue), 1, any).
+ ?line ?expect3(?v1_2(badValue, wrongValue), 1, any).
%% Req. Test1
@@ -3214,64 +3632,63 @@ implied_test(MA) ->
?LOG("implied_test -> start",[]),
?P1("Testing IMPLIED..."),
- snmpa:verbosity(MA,trace),
- snmpa:verbosity(MA,trace),
+ snmpa:verbosity(MA, trace),
%% Create two rows, check that they are get-nexted in correct order.
Idx1 = "apa",
Idx2 = "qq",
?DBG("implied_test -> (send) create row 1 '~s' in table 1",[Idx1]),
s([{[testStatus, Idx1], i, ?createAndGo}, {[testDescr, Idx1],s,"row 1"}]),
- ?line expect(1, [{[testStatus, Idx1], ?createAndGo},
- {[testDescr, Idx1], "row 1"}]),
+ ?line ?expect1([{[testStatus, Idx1], ?createAndGo},
+ {[testDescr, Idx1], "row 1"}]),
?DBG("implied_test -> (send) create row 2 '~s' in table 1",[Idx2]),
s([{[testStatus, Idx2], i, ?createAndGo}, {[testDescr, Idx2],s,"row 2"}]),
- ?line expect(2, [{[testStatus, Idx2], ?createAndGo},
- {[testDescr, Idx2], "row 2"}]),
+ ?line ?expect1([{[testStatus, Idx2], ?createAndGo},
+ {[testDescr, Idx2], "row 2"}]),
?DBG("implied_test -> get-next(testDescr)",[]),
gn([[testDescr]]),
- ?line expect(3, [{[testDescr,Idx1], "row 1"}]),
+ ?line ?expect1([{[testDescr,Idx1], "row 1"}]),
?DBG("implied_test -> get-next(testDescr) of row 1",[]),
gn([[testDescr,Idx1]]),
- ?line expect(4, [{[testDescr,Idx2], "row 2"}]),
+ ?line ?expect1([{[testDescr,Idx2], "row 2"}]),
% Delete the rows
?DBG("implied_test -> (send) delete row 1 '~s' from table 1",[Idx1]),
s([{[testStatus, Idx1], i, ?destroy}]),
- ?line expect(5, [{[testStatus, Idx1], ?destroy}]),
+ ?line ?expect1([{[testStatus, Idx1], ?destroy}]),
?DBG("implied_test -> (send) delete row 2 '~s' from table 1",[Idx2]),
s([{[testStatus, Idx2], i, ?destroy}]),
- ?line expect(6, [{[testStatus, Idx2], ?destroy}]),
+ ?line ?expect1([{[testStatus, Idx2], ?destroy}]),
%% Try the same in other table
Idx3 = [1, "apa"],
Idx4 = [1, "qq"],
?DBG("implied_test -> (send) create row 1 '~s' in table 2",[Idx3]),
s([{[testStatus2, Idx3], i, ?createAndGo}, {[testDescr2,Idx3],s,"row 1"}]),
- ?line expect(1, [{[testStatus2, Idx3], ?createAndGo},
- {[testDescr2, Idx3], "row 1"}]),
+ ?line ?expect1([{[testStatus2, Idx3], ?createAndGo},
+ {[testDescr2, Idx3], "row 1"}]),
?DBG("implied_test -> (send) create row 2 '~s' in table 2",[Idx4]),
s([{[testStatus2, Idx4], i, ?createAndGo}, {[testDescr2,Idx4],s,"row 2"}]),
- ?line expect(2, [{[testStatus2, Idx4], ?createAndGo},
- {[testDescr2, Idx4], "row 2"}]),
+ ?line ?expect1([{[testStatus2, Idx4], ?createAndGo},
+ {[testDescr2, Idx4], "row 2"}]),
?DBG("implied_test -> get-next(testDescr2)",[]),
gn([[testDescr2]]),
- ?line expect(3, [{[testDescr2,Idx3], "row 1"}]),
+ ?line ?expect1([{[testDescr2,Idx3], "row 1"}]),
?DBG("implied_test -> get-next(testDescr2) of row 1",[]),
gn([[testDescr2,Idx3]]),
- ?line expect(4, [{[testDescr2,Idx4], "row 2"}]),
+ ?line ?expect1([{[testDescr2,Idx4], "row 2"}]),
% Delete the rows
?DBG("implied_test -> (send) delete row 1 '~s' from table 2",[Idx3]),
s([{[testStatus2, Idx3], i, ?destroy}]),
- ?line expect(5, [{[testStatus2, Idx3], ?destroy}]),
+ ?line ?expect1([{[testStatus2, Idx3], ?destroy}]),
?DBG("implied_test -> (send) delete row 2 '~s' from table 2",[Idx4]),
s([{[testStatus2, Idx4], i, ?destroy}]),
- ?line expect(6, [{[testStatus2, Idx4], ?destroy}]),
+ ?line ?expect1([{[testStatus2, Idx4], ?destroy}]),
- snmpa:verbosity(MA,log),
+ snmpa:verbosity(MA, log),
- ?LOG("implied_test -> done",[]).
+ ?LOG("implied_test -> done", []).
@@ -3284,25 +3701,25 @@ sparse_table_test() ->
Idx2 = 2,
s([{[sparseStatus, Idx1], i, ?createAndGo},
{[sparseDescr, Idx1], s, "row 1"}]),
- ?line expect(1, [{[sparseStatus, Idx1], ?createAndGo},
- {[sparseDescr, Idx1], "row 1"}]),
+ ?line ?expect1([{[sparseStatus, Idx1], ?createAndGo},
+ {[sparseDescr, Idx1], "row 1"}]),
s([{[sparseStatus, Idx2], i, ?createAndGo},
{[sparseDescr, Idx2], s, "row 2"}]),
- ?line expect(2, [{[sparseStatus, Idx2], ?createAndGo},
- {[sparseDescr, Idx2], "row 2"}]),
+ ?line ?expect1([{[sparseStatus, Idx2], ?createAndGo},
+ {[sparseDescr, Idx2], "row 2"}]),
?v1_2(gn([[sparseIndex], [sparseDescr,Idx1], [sparseDescr,Idx2],
[sparseStatus,Idx1], [sparseStatus,Idx2]]),
gb(0,5,[[sparseIndex]])),
- ?line expect(3, [{[sparseDescr,Idx1], "row 1"},
- {[sparseDescr,Idx2], "row 2"},
- {[sparseStatus,Idx1], ?active},
- {[sparseStatus,Idx2], ?active},
- {[sparseStr,0], "slut"}]),
- % Delete the rows
+ ?line ?expect1([{[sparseDescr,Idx1], "row 1"},
+ {[sparseDescr,Idx2], "row 2"},
+ {[sparseStatus,Idx1], ?active},
+ {[sparseStatus,Idx2], ?active},
+ {[sparseStr,0], "slut"}]),
+ %% Delete the rows
s([{[sparseStatus, Idx1], i, ?destroy}]),
- ?line expect(4, [{[sparseStatus, Idx1], ?destroy}]),
+ ?line ?expect1([{[sparseStatus, Idx1], ?destroy}]),
s([{[sparseStatus, Idx2], i, ?destroy}]),
- ?line expect(5, [{[sparseStatus, Idx2], ?destroy}]).
+ ?line ?expect1([{[sparseStatus, Idx2], ?destroy}]).
%% Req. Test1
@@ -3316,13 +3733,13 @@ cnt_64_test(MA) ->
?DBG("get cnt64",[]),
g([[cnt64,0]]),
?DBG("await response",[]),
- ?line ?v1_2(expect(1, noSuchName, 1, any),
- expect(1, [{[cnt64,0],18446744073709551615}])),
+ ?line ?v1_2(?expect3(noSuchName, 1, any),
+ ?expect1([{[cnt64,0],18446744073709551615}])),
?DBG("get-next cnt64",[]),
gn([[cnt64]]),
?DBG("await response",[]),
- ?line ?v1_2(expect(2, [{[cnt64Str,0], "after cnt64"}]),
- expect(2, [{[cnt64,0],18446744073709551615}])),
+ ?line ?v1_2(?expect1([{[cnt64Str,0], "after cnt64"}]),
+ ?expect1([{[cnt64,0],18446744073709551615}])),
?DBG("send cntTrap",[]),
snmpa:send_trap(MA,cntTrap,"standard trap",[
{sysContact, "pelle"},
@@ -3330,13 +3747,13 @@ cnt_64_test(MA) ->
{sysLocation, "here"}
]),
?DBG("await response",[]),
- ?line ?v1_2(expect(3, trap, [test], 6, 1, [{[sysContact,0], "pelle"},
- {[sysLocation,0], "here"}]),
- expect(3, v2trap, [{[sysUpTime, 0], any},
- {[snmpTrapOID, 0], ?testTrap ++ [1]},
- {[sysContact,0], "pelle"},
- {[cnt64,0], 10},
- {[sysLocation,0], "here"}])),
+ ?line ?v1_2(?expect5(trap, [test], 6, 1, [{[sysContact,0], "pelle"},
+ {[sysLocation,0], "here"}]),
+ ?expect2(v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?testTrap ++ [1]},
+ {[sysContact,0], "pelle"},
+ {[cnt64,0], 10},
+ {[sysLocation,0], "here"}])),
%% Create two rows, check that they are get-nexted in correct order.
Idx1 = 1,
@@ -3344,27 +3761,27 @@ cnt_64_test(MA) ->
?DBG("create row (cntStatus): ~p",[Idx1]),
s([{[cntStatus, Idx1], i, ?createAndGo}]),
?DBG("await response",[]),
- ?line expect(1, [{[cntStatus, Idx1], ?createAndGo}]),
+ ?line ?expect1([{[cntStatus, Idx1], ?createAndGo}]),
?DBG("create row (cntStatus): ~p",[Idx2]),
s([{[cntStatus, Idx2], i, ?createAndGo}]),
?DBG("await response",[]),
- ?line expect(2, [{[cntStatus, Idx2], ?createAndGo}]),
+ ?line ?expect1([{[cntStatus, Idx2], ?createAndGo}]),
?DBG("get-next (cntIndex)",[]),
gn([[cntIndex]]),
?DBG("await response",[]),
- ?line ?v1_2(expect(3, [{[cntStatus,Idx1], ?active}]),
- expect(3, [{[cntCnt,Idx1], 0}])),
+ ?line ?v1_2(?expect1([{[cntStatus,Idx1], ?active}]),
+ ?expect1([{[cntCnt,Idx1], 0}])),
% Delete the rows
?DBG("delete row (cntStatus): ~p",[Idx1]),
s([{[cntStatus, Idx1], i, ?destroy}]),
?DBG("await response",[]),
- ?line expect(4, [{[cntStatus, Idx1], ?destroy}]),
+ ?line ?expect1([{[cntStatus, Idx1], ?destroy}]),
?DBG("delete row (cntStatus): ~p",[Idx2]),
s([{[cntStatus, Idx2], i, ?destroy}]),
?DBG("await response",[]),
- ?line expect(5, [{[cntStatus, Idx2], ?destroy}]),
- catch snmpa:verbosity(MA,log),
+ ?line ?expect1([{[cntStatus, Idx2], ?destroy}]),
+ catch snmpa:verbosity(MA, log),
?DBG("done",[]),
ok.
@@ -3372,7 +3789,7 @@ cnt_64_test(MA) ->
opaque_test() ->
?P1("Testing Opaque datatype..."),
g([[opaqueObj,0]]),
- ?line expect(1, [{[opaqueObj,0], "opaque-data"}]).
+ ?line ?expect1([{[opaqueObj,0], "opaque-data"}]).
%% Req. OLD-SNMPEA-MIB
api_test(MaNode) ->
@@ -3413,70 +3830,69 @@ api_test(MaNode) ->
%% Req. Klas3
api_test2() ->
g([[fname3,0]]),
- ?line expect(1, [{[fname3,0], "ok"}]),
+ ?line ?expect1([{[fname3,0], "ok"}]),
g([[fname4,0]]),
- ?line expect(2, [{[fname4,0], 1}]).
+ ?line ?expect1([{[fname4,0], 1}]).
api_test3() ->
g([[fname3,0]]),
- ?line expect(1, [{[fname3,0], "ok"}]).
+ ?line ?expect1([{[fname3,0], "ok"}]).
unreg_test() ->
gn([[?v1_2(sysServices, sysORLastChange),0]]),
- ?line expect(1, [{[snmpInPkts, 0], any}]).
+ ?line ?expect1([{[snmpInPkts, 0], any}]).
load_test() ->
gn([[?v1_2(sysServices, sysORLastChange),0]]),
- ?line expect(1, [{[fname,0], ""}]).
+ ?line ?expect1([{[fname,0], ""}]).
%% Req. Klas1
load_test_sa() ->
gn([[?v1_2(sysServices,sysORLastChange), 0]]),
- ?line expect(1, [{[fname,0], any}]).
+ ?line ?expect1([{[fname,0], any}]).
%% Req. system group, Klas1, OLD-SNMPEA-MIB
do_mul_get() ->
Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
s([{[fname,0], s, "test set"}]),
- ?line expect(3, [{[fname,0], "test set"}]),
- g([[sysDescr,0], Key1c4, [fname,0],Key1c3,
- [sysName,0]]),
- ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
- {Key1c4, 2},
- {[fname,0], "test set"},
- {Key1c3, 2},
- {[sysName,0], "test"}]),
+ ?line ?expect1([{[fname,0], "test set"}]),
+ g([[sysDescr,0], Key1c4, [fname,0],Key1c3,[sysName,0]]),
+ ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname,0], "test set"},
+ {Key1c3, 2},
+ {[sysName,0], "test"}]),
g([[1,3,7,1], Key1c4, [sysDescr,0], [1,3,7,2], Key1c3, [sysDescr,0]]),
- ?line ?v1_2(expect(2, noSuchName, [1,4], any),
- expect(2, [{[1,3,7,1], noSuchObject},
- {Key1c4, 2},
- {[sysDescr,0], "Erlang SNMP agent"},
- {[1,3,7,2], noSuchObject},
- {Key1c3, 2},
- {[sysDescr,0], "Erlang SNMP agent"}])).
+ ?line ?v1_2(?expect3(noSuchName, [1,4], any),
+ ?expect1([{[1,3,7,1], noSuchObject},
+ {Key1c4, 2},
+ {[sysDescr,0], "Erlang SNMP agent"},
+ {[1,3,7,2], noSuchObject},
+ {Key1c3, 2},
+ {[sysDescr,0], "Erlang SNMP agent"}])).
%% Req. v1, system group, Klas1, OLD-SNMPEA-MIB, *ej* Klas3.
do_mul_get_err() ->
Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
s([{[fname,0], s, "test set"}]),
- ?line expect(3, [{[fname,0], "test set"}]),
+ ?line ?expect1([{[fname,0], "test set"}]),
g([[sysDescr,0],Key1c4,[fname,0], Key1c3, [sysName,2]]),
- ?line ?v1_2(expect(1, noSuchName, 5, any),
- expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
- {Key1c4, 2},
- {[fname,0], "test set"},
- {Key1c3, 2},
- {[sysName,2], noSuchInstance}])),
+ ?line ?v1_2(?expect3(noSuchName, 5, any),
+ ?expect1([{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname,0], "test set"},
+ {Key1c3, 2},
+ {[sysName,2], noSuchInstance}])),
g([[sysDescr,0],Key1c4,[fname3,0], Key1c3, [sysName,1]]),
- ?line ?v1_2(expect(1, noSuchName, [3,5], any),
- expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
- {Key1c4, 2},
- {[fname3,0], noSuchObject},
- {Key1c3, 2},
- {[sysName,1], noSuchInstance}])).
+ ?line ?v1_2(?expect3(noSuchName, [3,5], any),
+ ?expect1([{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname3,0], noSuchObject},
+ {Key1c3, 2},
+ {[sysName,1], noSuchInstance}])).
%% Req. system group, Klas1, OLD-SNMPEA-MIB
@@ -3486,11 +3902,11 @@ do_mul_next() ->
Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
s([{[fname,0], s, "test set"}]),
- ?line expect(3, [{[fname,0], "test set"}]),
+ ?line ?expect1([{[fname,0], "test set"}]),
gn([[sysDescr], Key1c4s, [fname],Key1c3s,[sysName]]),
- ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
- {Key1c4, 2}, {[fname,0], "test set"},
- {Key1c3, 2}, {[sysName,0], "test"}]).
+ ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2}, {[fname,0], "test set"},
+ {Key1c3, 2}, {[sysName,0], "test"}]).
%% Req. system group, Klas1, OLD-SNMPEA-MIB
do_mul_next_err() ->
@@ -3499,17 +3915,17 @@ do_mul_next_err() ->
Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
s([{[fname,0], s, "test set"}]),
- ?line expect(3, [{[fname,0], "test set"}]),
+ ?line ?expect1([{[fname,0], "test set"}]),
gn([[sysDescr], Key1c4s, [1,3,6,999], [fname],[1,3,90], Key1c3s,[sysName]]),
- ?line ?v1_2(expect(1, noSuchName, [3,5], any),
- expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
- {Key1c4, 2},
- {[1,3,6,999], endOfMibView},
- {[fname,0], "test set"},
- {[1,3,90], endOfMibView},
- {Key1c3, 2},
- {[sysName,0], "test"}])).
-
+ ?line ?v1_2(?expect3(noSuchName, [3,5], any),
+ ?expect1([{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[1,3,6,999], endOfMibView},
+ {[fname,0], "test set"},
+ {[1,3,90], endOfMibView},
+ {Key1c3, 2},
+ {[sysName,0], "test"}])).
+
%% Req. system group, Klas1, OLD-SNMPEA-MIB
do_mul_set() ->
@@ -3523,24 +3939,24 @@ do_mul_set() ->
{NewKeyc5, ?createAndGo},
{NewKeyc4, 2},
{[friendsEntry, [3, 3]], ?createAndGo}]),
- ?line expect(1, [{[friendsEntry, [2, 3]], "kompis3"},
- {NewKeyc3, 2},
- {[sysLocation,0], "new_value"},
- {NewKeyc5, ?createAndGo},
- {NewKeyc4, 2},
- {[friendsEntry, [3, 3]], ?createAndGo}]),
+ ?line ?expect1([{[friendsEntry, [2, 3]], "kompis3"},
+ {NewKeyc3, 2},
+ {[sysLocation,0], "new_value"},
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
g([[friendsEntry, [2, 3]],
- [sysLocation,0],
- [friendsEntry, [3, 3]]]),
- ?line expect(2, [{[friendsEntry, [2, 3]], "kompis3"},
- {[sysLocation,0], "new_value"},
- {[friendsEntry, [3, 3]], ?active}]),
+ [sysLocation,0],
+ [friendsEntry, [3, 3]]]),
+ ?line ?expect1([{[friendsEntry, [2, 3]], "kompis3"},
+ {[sysLocation,0], "new_value"},
+ {[friendsEntry, [3, 3]], ?active}]),
g([NewKeyc4]),
- ?line expect(3, [{NewKeyc4, 2}]),
+ ?line ?expect1([{NewKeyc4, 2}]),
s([{[friendsEntry, [3, 3]], ?destroy},
{NewKeyc5, ?destroy}]),
- ?line expect(4, [{[friendsEntry, [3, 3]], ?destroy},
- {NewKeyc5, ?destroy}]).
+ ?line ?expect1([{[friendsEntry, [3, 3]], ?destroy},
+ {NewKeyc5, ?destroy}]).
%% Req. system group, Klas1, OLD-SNMPEA-MIB
do_mul_set_err() ->
@@ -3554,53 +3970,48 @@ do_mul_set_err() ->
{NewKeyc5, ?createAndGo},
{NewKeyc4, 2},
{[friendsEntry, [3, 3]], ?createAndGo}]),
- ?line expect(1, ?v1_2(noSuchName, notWritable), 3, any),
+ ?line ?expect3(?v1_2(noSuchName, notWritable), 3, any),
g([[friendsEntry, [2, 3]]]),
- ?line ?v1_2(expect(2, noSuchName, 1, any),
- expect(2, [{[friendsEntry, [2,3]], noSuchInstance}])),
+ ?line ?v1_2(?expect3(noSuchName, 1, any),
+ ?expect1([{[friendsEntry, [2,3]], noSuchInstance}])),
g([NewKeyc4]),
- ?line ?v1_2(expect(3, noSuchName, 1, any),
- expect(3, [{NewKeyc4, noSuchInstance}])).
+ ?line ?v1_2(?expect3(noSuchName, 1, any),
+ ?expect1([{NewKeyc4, noSuchInstance}])).
%% Req. SA-MIB
sa_mib() ->
g([[sa, [2,0]]]),
- ?line expect(sa_mib_1, [{[sa, [2,0]], 3}]),
+ ?line ?expect1([{[sa, [2,0]], 3}]),
s([{[sa, [1,0]], s, "sa_test"}]),
- ?line expect(sa_mib_2, [{[sa, [1,0]], "sa_test"}]),
+ ?line ?expect1([{[sa, [1,0]], "sa_test"}]),
ok.
ma_trap1(MA) ->
ok = snmpa:send_trap(MA, testTrap2, "standard trap"),
- ?line expect(ma_trap1_1,
- trap, [system], 6, 1, [{[system, [4,0]],
- "{mbj,eklas}@erlang.ericsson.se"}]),
+ ?line ?expect5(trap, [system], 6, 1, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"}]),
ok = snmpa:send_trap(MA, testTrap1, "standard trap"),
- ?line expect(ma_trap1_2,
- trap, [1,2,3] , 1, 0, [{[system, [4,0]],
- "{mbj,eklas}@erlang.ericsson.se"}]),
+ ?line ?expect5(trap, [1,2,3] , 1, 0, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"}]),
ok.
ma_trap2(MA) ->
snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]),
- ?line expect(ma_trap2_3,
- trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]),
+ ?line ?expect5(trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]),
ok.
ma_v2_2_v1_trap(MA) ->
snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]),
- ?line expect(ma_v2_2_v1_trap_3,
- trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]),
+ ?line ?expect5(trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]),
ok.
ma_v2_2_v1_trap2(MA) ->
snmpa:send_trap(MA,linkUp,"standard trap",[{ifIndex, [1], 1},
{ifAdminStatus, [1], 1},
{ifOperStatus, [1], 2}]),
- ?line expect(ma_v2_2_v1_trap2_3,
- trap, [1,2,3], 3, 0, [{[ifIndex, 1], 1},
- {[ifAdminStatus, 1], 1},
- {[ifOperStatus, 1], 2}]),
+ ?line ?expect5(trap, [1,2,3], 3, 0, [{[ifIndex, 1], 1},
+ {[ifAdminStatus, 1], 1},
+ {[ifOperStatus, 1], 2}]),
ok.
sa_trap1(SA) ->
@@ -3618,47 +4029,44 @@ sa_trap1(SA) ->
%% io:format("sa_trap1 -> SA trap send: "
%% "~n TSRes: ~p"
%% "~n", [TSRes]),
- ?line expect(sa_trap1_4,
- trap, [ericsson], 6, 1, [{[system, [4,0]],
- "{mbj,eklas}@erlang.ericsson.se"},
- {[sa, [1,0]], "sa_test"}]),
+ ?line ?expect5(trap, [ericsson], 6, 1, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"}]),
snmpa:verbosity(SA, {subagents, silence}),
ok.
sa_trap2(SA) ->
snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]),
- ?line expect(sa_trap2_5,
- trap, [ericsson], 6, 1, [{[system, [4,0]], "pelle"},
- {[sa, [1,0]], "sa_test"}]),
+ ?line ?expect5(trap, [ericsson], 6, 1, [{[system, [4,0]], "pelle"},
+ {[sa, [1,0]], "sa_test"}]),
ok.
sa_trap3(SA) ->
snmpa:send_trap(SA, saTrap2, "standard trap",
[{intViewSubtree, [4], [1,2,3,4]}]),
- ?line expect(sa_trap3_6,
- trap, [ericsson], 6, 2, [{[system, [4,0]],
- "{mbj,eklas}@erlang.ericsson.se"},
- {[sa, [1,0]], "sa_test"},
- {[intViewSubtree,4],[1,2,3,4]}]),
+ ?line ?expect5(trap, [ericsson], 6, 2, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[intViewSubtree,4],[1,2,3,4]}]),
ok.
ma_v2_trap1(MA) ->
?DBG("ma_v2_traps -> entry with MA = ~p => "
"send standard trap: testTrapv22",[MA]),
snmpa:send_trap(MA, testTrapv22, "standard trap"),
- ?line expect(1, v2trap, [{[sysUpTime, 0], any},
- {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ ?line ?expect2(v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
?DBG("ma_v2_traps -> send standard trap: testTrapv21",[]),
snmpa:send_trap(MA, testTrapv21, "standard trap"),
- ?line expect(2, v2trap, [{[sysUpTime, 0], any},
- {[snmpTrapOID, 0], ?snmp ++ [1]}]),
+ ?line ?expect2(v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?snmp ++ [1]}]),
ok.
ma_v2_trap2(MA) ->
snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]),
- ?line expect(3, v2trap, [{[sysUpTime, 0], any},
- {[snmpTrapOID, 0], ?system ++ [0,1]},
- {[system, [4,0]], "pelle"}]).
+ ?line ?expect2(v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]},
+ {[system, [4,0]], "pelle"}]).
%% Note: This test case takes a while... actually a couple of minutes.
ma_v2_inform1(MA) ->
@@ -3667,11 +4075,10 @@ ma_v2_inform1(MA) ->
"~n send notification: testTrapv22", [MA]),
CmdExpectInform =
- fun(No, Response) ->
- expect(No,
- {inform, Response},
- [{[sysUpTime, 0], any},
- {[snmpTrapOID, 0], ?system ++ [0,1]}])
+ fun(_No, Response) ->
+ ?expect2({inform, Response},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}])
end,
CmdExp =
@@ -3817,11 +4224,10 @@ ma_v2_inform2(MA) ->
"~n send notification: testTrapv22", [MA]),
CmdExpectInform =
- fun(No, Response) ->
- expect(No,
- {inform, Response},
- [{[sysUpTime, 0], any},
- {[snmpTrapOID, 0], ?system ++ [0,1]}])
+ fun(_No, Response) ->
+ ?expect2({inform, Response},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}])
end,
CmdExp =
@@ -3909,17 +4315,17 @@ ma_v2_inform3(MA) ->
CmdExpectInform =
fun(No, Response) ->
- expect(No,
- {inform, Response},
- [{[sysUpTime, 0], any},
- {[snmpTrapOID, 0], ?system ++ [0,1]}])
+ ?DBG("CmdExpectInform -> ~p: ~n~p", [No, Response]),
+ ?expect2({inform, Response},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}])
end,
CmdExp =
fun(ok) ->
ok;
({ok, Val}) ->
- ?DBG("ma_v2_inform3 -> [cmd2] Val: ~p", [Val]),
+ ?DBG("CmdExp -> Val: ~p", [Val]),
ok;
({error, Id, Extra}) ->
{error, {unexpected, Id, Extra}};
@@ -3983,15 +4389,16 @@ ma_v2_inform3(MA) ->
Commands =
[
- {15, "Send notification [tag31]", Cmd15},
- {16, "Expect notification message [tag31]", Cmd16},
- {17, "Expect targets message [tag31]", Cmd17},
- {18, "Expect notification (no) response message [tag31]", Cmd18}
+ {15, "Send notification [" ++ atom_to_list(Tag15) ++ "]", Cmd15},
+ {16, "Expect notification message [" ++ atom_to_list(Tag15) ++ "]", Cmd16},
+ {17, "Expect targets message [" ++ atom_to_list(Tag15) ++ "]", Cmd17},
+ {18, "Expect notification (no) response message [" ++ atom_to_list(Tag15) ++ "]", Cmd18}
],
command_handler(Commands).
-
+
+%% snmpa_notification_delivery_info_receiver callback function
delivery_targets(Tag, Addresses, Extra) ->
io:format("~w:delivery_targets -> entry with"
"~n Tag: ~p"
@@ -4008,6 +4415,7 @@ delivery_targets(Tag, Addresses, Extra) ->
end,
ok.
+%% snmpa_notification_delivery_info_receiver callback function
delivery_info(Tag, Address, DeliveryResult, Extra) ->
io:format("~w:delivery_info -> entry with"
"~n Tag: ~p"
@@ -4045,40 +4453,40 @@ command_handler([{No, Desc, Cmd}|Rest]) ->
ma_v1_2_v2_trap(MA) ->
snmpa:send_trap(MA,linkDown,"standard trap",[{ifIndex, [1], 1}]),
- ?line expect(2, v2trap, [{[sysUpTime, 0], any},
- {[snmpTrapOID, 0], ?snmpTraps ++ [3]},
- {[ifIndex, 1], 1},
- {[snmpTrapEnterprise, 0], [1,2,3]}]).
+ ?line ?expect2(v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?snmpTraps ++ [3]},
+ {[ifIndex, 1], 1},
+ {[snmpTrapEnterprise, 0], [1,2,3]}]).
ma_v1_2_v2_trap2(MA) ->
snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]),
- ?line expect(3, v2trap, [{[sysUpTime, 0], any},
- {[snmpTrapOID, 0], ?system ++ [0,1]},
- {[system, [4,0]], "pelle"},
- {[snmpTrapEnterprise, 0], ?system}]).
+ ?line ?expect2(v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]},
+ {[system, [4,0]], "pelle"},
+ {[snmpTrapEnterprise, 0], ?system}]).
sa_v1_2_v2_trap1(SA) ->
snmpa:verbosity(SA, {subagents, trace}),
snmpa:send_trap(SA, saTrap, "standard trap"),
- ?line expect(trap1_4, v2trap, [{[sysUpTime, 0], any},
- {[snmpTrapOID, 0], ?ericsson ++ [0, 1]},
- {[system, [4,0]],
- "{mbj,eklas}@erlang.ericsson.se"},
- {[sa, [1,0]], "sa_test"},
- {[snmpTrapEnterprise, 0], ?ericsson}]),
+ ?line ?expect2(v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 1]},
+ {[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[snmpTrapEnterprise, 0], ?ericsson}]),
snmpa:verbosity(SA, {subagents, silence}),
ok.
sa_v1_2_v2_trap2(SA) ->
snmpa:verbosity(SA, {subagents, trace}),
snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]),
- ?line expect(trap2_4, v2trap, [{[sysUpTime, 0], any},
- {[snmpTrapOID, 0], ?ericsson ++ [0, 1]},
- {[system, [4,0]], "pelle"},
- {[sa, [1,0]], "sa_test"},
- {[snmpTrapEnterprise, 0], ?ericsson}]),
+ ?line ?expect2(v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 1]},
+ {[system, [4,0]], "pelle"},
+ {[sa, [1,0]], "sa_test"},
+ {[snmpTrapEnterprise, 0], ?ericsson}]),
snmpa:verbosity(SA, {subagents, silence}),
ok.
@@ -4087,13 +4495,13 @@ sa_v1_2_v2_trap3(SA) ->
snmpa:verbosity(SA, {subagents, trace}),
snmpa:send_trap(SA, saTrap2, "standard trap",
[{intViewSubtree, [4], [1,2,3,4]}]),
- ?line expect(trap3_4, v2trap, [{[sysUpTime, 0], any},
- {[snmpTrapOID, 0], ?ericsson ++ [0, 2]},
- {[system, [4,0]],
- "{mbj,eklas}@erlang.ericsson.se"},
- {[sa, [1,0]], "sa_test"},
- {[intViewSubtree,4],[1,2,3,4]},
- {[snmpTrapEnterprise, 0], ?ericsson}]),
+ ?line ?expect2(v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 2]},
+ {[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[intViewSubtree,4],[1,2,3,4]},
+ {[snmpTrapEnterprise, 0], ?ericsson}]),
snmpa:verbosity(SA, {subagents, silence}),
ok.
@@ -4107,15 +4515,15 @@ sa_errs_bad_value() ->
{[sa, [2,0]], 5}, % badValue (i is_set_ok)
{NewKeyc5, ?createAndGo},
{NewKeyc4, 2}]),
- ?line expect(1, badValue, 2, any),
+ ?line ?expect3(badValue, 2, any),
s([{NewKeyc3, 2},
{[sa, [2,0]], 6}, % wrongValue (i is_set_ok)
{NewKeyc5, ?createAndGo},
{NewKeyc4, 2}]),
- ?line expect(1, ?v1_2(badValue, wrongValue), 2, any),
+ ?line ?expect3(?v1_2(badValue, wrongValue), 2, any),
g([NewKeyc4]),
- ?line ?v1_2(expect(2, noSuchName, 1, any),
- expect(2, [{NewKeyc4, noSuchInstance}])).
+ ?line ?v1_2(?expect3(noSuchName, 1, any),
+ ?expect1([{NewKeyc4, noSuchInstance}])).
%% Req. SA-MIB, OLD-SNMPEA-MIB
sa_errs_gen_err() ->
@@ -4124,23 +4532,23 @@ sa_errs_gen_err() ->
NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
s([{NewKeyc3, 2},{NewKeyc4, 2},
{NewKeyc5, ?createAndGo}, {[sa, [3,0]], 5}]),
- ?line expect(1, genErr, 4, any),
+ ?line ?expect3(genErr, 4, any),
% The row might have been added; we don't know.
% (as a matter of fact we do - it is added, because the agent
% first sets its own vars, and then th SAs. Lets destroy it.
s([{NewKeyc5, ?destroy}]),
- ?line expect(2, [{NewKeyc5, ?destroy}]).
+ ?line ?expect1([{NewKeyc5, ?destroy}]).
%% Req. SA-MIB, OLD-SNMPEA-MIB
sa_too_big() ->
g([[sa, [4,0]]]),
- ?line expect(1, tooBig).
+ ?line ?expect1(tooBig).
%% Req. Klas1, system group, snmp group (v1/v2)
-next_across_sa() ->
+next_across_sa_test() ->
gn([[sysDescr],[klas1,5]]),
- ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
- {[snmpInPkts, 0], any}]).
+ ?line ?expect1([{[sysDescr,0], "Erlang SNMP agent"},
+ {[snmpInPkts, 0], any}]).
%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]). -> noError
%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]). -> {badValue, 2}
@@ -4151,40 +4559,40 @@ next_across_sa() ->
%% Req. Klas3, Klas4
undo_test() ->
s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]),
- ?line expect(1, [{[fStatus3, 1], 4}, {[fname3,0], "ok"}]),
+ ?line ?expect1([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]),
s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]),
- ?line expect(2, ?v1_2(badValue, inconsistentValue), 2, any),
+ ?line ?expect3(?v1_2(badValue, inconsistentValue), 2, any),
s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]),
- ?line expect(3, ?v1_2(genErr, undoFailed), 1, any),
+ ?line ?expect3(?v1_2(genErr, undoFailed), 1, any),
s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]),
- ?line expect(4, ?v1_2(genErr, commitFailed), 1, any),
+ ?line ?expect3(?v1_2(genErr, commitFailed), 1, any),
% unfortunatly we don't know if we'll get undoFailed or commitFailed.
% it depends on which order the agent traverses the varbind list.
% s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]),
% ?line expect(5, ?v1_2(genErr, undoFailed), 1, any),
s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]),
- ?line expect(6, genErr, 2, any).
+ ?line ?expect3(genErr, 2, any).
%% Req. Klas3, Klas4
bad_return() ->
g([[fStatus4,4],
[fName4,4]]),
- ?line expect(4, genErr, 2, any),
+ ?line ?expect3(genErr, 2, any),
g([[fStatus4,5],
[fName4,5]]),
- ?line expect(5, genErr, 1, any),
+ ?line ?expect3(genErr, 1, any),
g([[fStatus4,6],
[fName4,6]]),
- ?line expect(6, genErr, 2, any),
+ ?line ?expect3(genErr, 2, any),
gn([[fStatus4,7],
[fName4,7]]),
- ?line expect(7, genErr, 2, any),
+ ?line ?expect3(genErr, 2, any),
gn([[fStatus4,8],
[fName4,8]]),
- ?line expect(8, genErr, 1, any),
+ ?line ?expect3(genErr, 1, any),
gn([[fStatus4,9],
[fName4,9]]),
- ?line expect(9, genErr, 2, any).
+ ?line ?expect3(genErr, 2, any).
%%%-----------------------------------------------------------------
@@ -4195,7 +4603,16 @@ bad_return() ->
%%% already tested by the normal tests.
%%%-----------------------------------------------------------------
-
+standard_mibs_cases() ->
+ [
+ snmp_standard_mib,
+ snmp_community_mib,
+ snmp_framework_mib,
+ snmp_target_mib,
+ snmp_notification_mib,
+ snmp_view_based_acm_mib
+ ].
+
%%-----------------------------------------------------------------
%% For this test, the agent is configured for v1.
@@ -4247,27 +4664,27 @@ std_mib_init() ->
%% disable authentication failure traps. (otherwise w'd get many of
%% them - this is also a test to see that it works).
s([{[snmpEnableAuthenTraps,0], 2}]),
- ?line expect(std_mib_init_1, [{[snmpEnableAuthenTraps, 0], 2}]).
+ ?line ?expect1([{[snmpEnableAuthenTraps, 0], 2}]).
%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
std_mib_finish() ->
%% enable again
s([{[snmpEnableAuthenTraps,0], 1}]),
- ?line expect(std_mib_finish_1, [{[snmpEnableAuthenTraps, 0], 1}]).
+ ?line ?expect1([{[snmpEnableAuthenTraps, 0], 1}]).
%% Req. SNMP-STANDARD-MIB
standard_mib_test_finish() ->
%% force a authenticationFailure (should result in a trap)
std_mib_write(),
%% check that we got a trap
- ?line expect(standard_mib_test_finish_2, trap, [1,2,3], 4, 0, []).
+ ?line ?expect5(trap, [1,2,3], 4, 0, []).
%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
std_mib_read() ->
?DBG("std_mib_read -> entry", []),
g([[sysUpTime,0]]), % try a bad <something>; msg dropped, no reply
?DBG("std_mib_read -> await timeout (i.e. no reply)", []),
- ?line expect(std_mib_read_1, timeout). % make sure we don't get a trap!
+ ?line ?expect1(timeout). % make sure we don't get a trap!
%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
@@ -4279,6 +4696,18 @@ std_mib_write() ->
std_mib_asn_err() ->
snmp_test_mgr:send_bytes([48,99,67,12,0,0,0,0,0,0,5]).
+
+standard_mibs2_cases() ->
+ [
+ snmpv2_mib_2,
+ snmp_community_mib_2,
+ snmp_framework_mib_2,
+ snmp_target_mib_2,
+ snmp_notification_mib_2,
+ snmp_view_based_acm_mib_2
+ ].
+
+
%%-----------------------------------------------------------------
%% For this test, the agent is configured for v2 and v3.
%% o Test the counters and control objects in SNMPv2-MIB
@@ -4327,6 +4756,19 @@ snmpv2_mib_2(Config) when is_list(Config) ->
?LOG("snmpv2_mib_2 -> done",[]).
+
+standard_mibs3_cases() ->
+ [
+ snmpv2_mib_3,
+ snmp_framework_mib_3,
+ snmp_mpd_mib_3,
+ snmp_target_mib_3,
+ snmp_notification_mib_3,
+ snmp_view_based_acm_mib_3,
+ snmp_user_based_sm_mib_3
+ ].
+
+
%% Req. SNMPv2-MIB
snmpv2_mib_3(suite) -> [];
snmpv2_mib_3(Config) when is_list(Config) ->
@@ -4358,13 +4800,13 @@ snmpv2_mib_test_finish() ->
%% check that we got a trap
?DBG("ma_v2_inform -> await trap",[]),
- ?line expect(2, v2trap, [{[sysUpTime,0], any},
- {[snmpTrapOID,0], ?authenticationFailure}]),
+ ?line ?expect2(v2trap, [{[sysUpTime,0], any},
+ {[snmpTrapOID,0], ?authenticationFailure}]),
%% and the the inform
?DBG("ma_v2_inform -> await inform",[]),
- ?line expect(2, {inform,true}, [{[sysUpTime,0], any},
- {[snmpTrapOID,0],?authenticationFailure}]).
+ ?line ?expect2({inform,true}, [{[sysUpTime,0], any},
+ {[snmpTrapOID,0],?authenticationFailure}]).
%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
std_mib_a() ->
@@ -4402,12 +4844,12 @@ std_mib_c({InBadCommunityNames, InBadCommunityUses, InASNErrs}) ->
snmpv2_mib_a() ->
?line [SetSerial] = get_req(2, [[snmpSetSerialNo,0]]),
s([{[snmpSetSerialNo,0], SetSerial}, {[sysLocation, 0], "val2"}]),
- ?line expect(snmpv2_mib_a_3, [{[snmpSetSerialNo,0], SetSerial},
- {[sysLocation, 0], "val2"}]),
+ ?line ?expect1([{[snmpSetSerialNo,0], SetSerial},
+ {[sysLocation, 0], "val2"}]),
s([{[sysLocation, 0], "val3"}, {[snmpSetSerialNo,0], SetSerial}]),
- ?line expect(snmpv2_mib_a_4, inconsistentValue, 2,
- [{[sysLocation, 0], "val3"},
- {[snmpSetSerialNo,0], SetSerial}]),
+ ?line ?expect3(inconsistentValue, 2,
+ [{[sysLocation, 0], "val3"},
+ {[snmpSetSerialNo,0], SetSerial}]),
?line ["val2"] = get_req(5, [[sysLocation,0]]).
@@ -4421,13 +4863,13 @@ snmp_community_mib(Config) when is_list(Config) ->
?P(snmp_community_mib),
init_case(Config),
?line load_master_std("SNMP-COMMUNITY-MIB"),
- try_test(snmp_community_mib),
+ try_test(snmp_community_mib_test),
?line unload_master("SNMP-COMMUNITY-MIB").
snmp_community_mib_2(X) -> ?P(snmp_community_mib_2), snmp_community_mib(X).
%% Req. SNMP-COMMUNITY-MIB
-snmp_community_mib() ->
+snmp_community_mib_test() ->
?INF("NOT YET IMPLEMENTED", []),
nyi.
@@ -4439,7 +4881,7 @@ snmp_framework_mib(Config) when is_list(Config) ->
?P(snmp_framework_mib),
init_case(Config),
?line load_master_std("SNMP-FRAMEWORK-MIB"),
- try_test(snmp_framework_mib),
+ try_test(snmp_framework_mib_test),
?line unload_master("SNMP-FRAMEWORK-MIB").
snmp_framework_mib_2(X) -> ?P(snmp_framework_mib_2), snmp_framework_mib(X).
@@ -4448,11 +4890,11 @@ snmp_framework_mib_3(suite) -> [];
snmp_framework_mib_3(Config) when is_list(Config) ->
?P(snmp_framework_mib_3),
init_case(Config),
- try_test(snmp_framework_mib).
+ try_test(snmp_framework_mib_test).
%% Req. SNMP-FRAMEWORK-MIB
-snmp_framework_mib() ->
+snmp_framework_mib_test() ->
?line ["agentEngine"] = get_req(1, [[snmpEngineID,0]]),
?line [EngineTime] = get_req(2, [[snmpEngineTime,0]]),
?SLEEP(5000),
@@ -4538,7 +4980,7 @@ snmp_mpd_mib_a() ->
-define(snmpUnknownPDUHandlers_instance, [1,3,6,1,6,3,11,2,1,3,0]).
snmp_mpd_mib_b() ->
g([[sysUpTime,0]]),
- ?line expect(1, report, [{?snmpUnknownPDUHandlers_instance, any}]).
+ ?line ?expect2(report, [{?snmpUnknownPDUHandlers_instance, any}]).
snmp_mpd_mib_c(UnknownPDUHs) ->
@@ -4551,14 +4993,14 @@ snmp_target_mib(Config) when is_list(Config) ->
?P(snmp_target_mib),
init_case(Config),
?line load_master_std("SNMP-TARGET-MIB"),
- try_test(snmp_target_mib),
+ try_test(snmp_target_mib_test),
?line unload_master("SNMP-TARGET-MIB").
snmp_target_mib_2(X) -> ?P(snmp_target_mib_2), snmp_target_mib(X).
snmp_target_mib_3(X) -> ?P(snmp_target_mib_3), snmp_target_mib(X).
-snmp_target_mib() ->
+snmp_target_mib_test() ->
?INF("NOT YET IMPLEMENTED", []),
nyi.
@@ -4567,7 +5009,7 @@ snmp_notification_mib(Config) when is_list(Config) ->
?P(snmp_notification_mib),
init_case(Config),
?line load_master_std("SNMP-NOTIFICATION-MIB"),
- try_test(snmp_notification_mib),
+ try_test(snmp_notification_mib_test),
?line unload_master("SNMP-NOTIFICATION-MIB").
snmp_notification_mib_2(X) -> ?P(snmp_notification_mib_2),
@@ -4576,7 +5018,7 @@ snmp_notification_mib_2(X) -> ?P(snmp_notification_mib_2),
snmp_notification_mib_3(X) -> ?P(snmp_notification_mib_3),
snmp_notification_mib(X).
-snmp_notification_mib() ->
+snmp_notification_mib_test() ->
?INF("NOT YET IMPLEMENTED", []),
nyi.
@@ -4728,50 +5170,51 @@ snmp_view_based_acm_mib() ->
do_set(Row) ->
s(Row),
- expect(do_set_1, Row).
+ ?expect1(Row).
add_row(RowStatus) ->
s([{RowStatus, ?createAndGo}]),
- expect(add_row_1, [{RowStatus, ?createAndGo}]).
+ ?expect1([{RowStatus, ?createAndGo}]).
del_row(RowStatus) ->
s([{RowStatus, ?destroy}]),
- expect(del_row_1, [{RowStatus, ?destroy}]).
+ ?expect1([{RowStatus, ?destroy}]).
use_no_rights() ->
g([[xDescr,0]]),
- ?v1_2_3(expect(use_no_rights_11, noSuchName, 1, any),
- expect(use_no_rights_12, [{[xDescr,0], noSuchObject}]),
- expect(use_no_rights_13, authorizationError, 1, any)),
+ ?v1_2_3(?expect3(noSuchName, 1, any),
+ ?expect1([{[xDescr,0], noSuchObject}]),
+ ?expect3(authorizationError, 1, any)),
g([[xDescr2,0]]),
- ?v1_2_3(expect(use_no_rights_21, noSuchName, 1, any),
- expect(use_no_rights_22, [{[xDescr2,0], noSuchObject}]),
- expect(use_no_rights_23, authorizationError, 1, any)),
+ ?v1_2_3(?expect3(noSuchName, 1, any),
+ ?expect1([{[xDescr2,0], noSuchObject}]),
+ ?expect3(authorizationError, 1, any)),
gn([[xDescr]]),
- ?v1_2_3(expect(use_no_rights_31, noSuchName, 1, any),
- expect(use_no_rights_32, [{[xDescr], endOfMibView}]),
- expect(use_no_rights_33, authorizationError, 1, any)),
+ ?v1_2_3(?expect3(noSuchName, 1, any),
+ ?expect1([{[xDescr], endOfMibView}]),
+ ?expect3(authorizationError, 1, any)),
s([{[xDescr,0], "tryit"}]),
- ?v1_2_3(expect(use_no_rights_41, noSuchName, 1, any),
- expect(use_no_rights_42, noAccess, 1, any),
- expect(use_no_rights_43, authorizationError, 1, any)).
+ ?v1_2_3(?expect3(noSuchName, 1, any),
+ ?expect3(noAccess, 1, any),
+ ?expect3(authorizationError, 1, any)).
use_rights() ->
g([[xDescr,0]]),
- expect(use_rights_1, [{[xDescr,0], any}]),
+ ?expect1([{[xDescr,0], any}]),
g([[xDescr2,0]]),
- expect(use_rights_2, [{[xDescr2,0], any}]),
+ ?expect1([{[xDescr2,0], any}]),
s([{[xDescr,0], "tryit"}]),
- expect(use_rights_3, noError, 0, any),
+ ?expect3(noError, 0, any),
g([[xDescr,0]]),
- expect(use_rights_4, [{[xDescr,0], "tryit"}]).
+ ?expect1([{[xDescr,0], "tryit"}]).
mk_ln(X) ->
[length(X) | X].
+
%%-----------------------------------------------------------------
%% o add/delete users and try them
%% o test all secLevels
@@ -4851,15 +5294,15 @@ snmp_user_based_sm_mib_3(Config) when is_list(Config) ->
%% Try some read requests
?line try_test(v3_sync, [[{usm_read, []}]],
- [{sec_level, authPriv}, {user, "privDES"}]),
+ [{sec_level, authPriv}, {user, "privDES"}]),
%% Delete the new user
?line try_test(v3_sync, [[{usm_del_user, []}]],
- [{sec_level, authPriv}, {user, "privDES"}]),
+ [{sec_level, authPriv}, {user, "privDES"}]),
%% Try some bad requests
?line try_test(v3_sync, [[{usm_bad, []}]],
- [{sec_level, authPriv}, {user, "privDES"}]),
+ [{sec_level, authPriv}, {user, "privDES"}]),
?line unload_master("SNMP-USER-BASED-SM-MIB").
@@ -4871,7 +5314,7 @@ usm_add_user1() ->
Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer},
{[usmUserStatus, NewRowIndex], ?createAndGo}],
?line s(Vbs1),
- ?line expect(1, Vbs1),
+ ?line ?expect1(Vbs1),
ok.
usm_use_user() ->
@@ -4890,7 +5333,7 @@ usm_key_change1(ShaKey, DesKey) ->
Vbs1 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange},
{[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}],
s(Vbs1),
- ?line expect(1, Vbs1).
+ ?line ?expect1(Vbs1).
%% Change own private keys
usm_key_change2(OldShaKey, OldDesKey, ShaKey, DesKey) ->
@@ -4904,7 +5347,7 @@ usm_key_change2(OldShaKey, OldDesKey, ShaKey, DesKey) ->
Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange},
{[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}],
s(Vbs1),
- ?line expect(1, Vbs1).
+ ?line ?expect1(Vbs1).
%% Change other's public keys
usm_key_change3(OldShaKey, OldDesKey, ShaKey, DesKey) ->
@@ -4917,16 +5360,16 @@ usm_key_change3(OldShaKey, OldDesKey, ShaKey, DesKey) ->
DesKey),
Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange}],
s(Vbs1),
- ?line expect(1, noAccess, 1, any),
+ ?line ?expect3(noAccess, 1, any),
Vbs2 = [{[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}],
s(Vbs2),
- ?line expect(2, noAccess, 1, any),
+ ?line ?expect3(noAccess, 1, any),
Vbs3 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange},
{[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}],
s(Vbs3),
- ?line expect(1, Vbs3).
+ ?line ?expect1(Vbs3).
usm_read() ->
NewRowIndex = [11,"agentEngine", 7, "newUser"],
@@ -4936,13 +5379,12 @@ usm_read() ->
[usmUserOwnAuthKeyChange, NewRowIndex],
[usmUserPrivKeyChange, NewRowIndex],
[usmUserOwnPrivKeyChange, NewRowIndex]]),
- ?line expect(1,
- [{[usmUserSecurityName, NewRowIndex], "newUser"},
- {[usmUserCloneFrom, NewRowIndex], [0,0]},
- {[usmUserAuthKeyChange, NewRowIndex], ""},
- {[usmUserOwnAuthKeyChange, NewRowIndex], ""},
- {[usmUserPrivKeyChange, NewRowIndex], ""},
- {[usmUserOwnPrivKeyChange, NewRowIndex], ""}]),
+ ?line ?expect1([{[usmUserSecurityName, NewRowIndex], "newUser"},
+ {[usmUserCloneFrom, NewRowIndex], [0,0]},
+ {[usmUserAuthKeyChange, NewRowIndex], ""},
+ {[usmUserOwnAuthKeyChange, NewRowIndex], ""},
+ {[usmUserPrivKeyChange, NewRowIndex], ""},
+ {[usmUserOwnPrivKeyChange, NewRowIndex], ""}]),
ok.
@@ -4951,7 +5393,7 @@ usm_del_user() ->
NewRowIndex = [11,"agentEngine", 7, "newUser"],
Vbs1 = [{[usmUserStatus, NewRowIndex], ?destroy}],
?line s(Vbs1),
- ?line expect(1, Vbs1),
+ ?line ?expect1(Vbs1),
ok.
-define(usmUserCloneFrom, [1,3,6,1,6,3,15,1,2,2,1,4]).
@@ -4972,32 +5414,31 @@ usm_bad() ->
Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer1},
{[usmUserStatus, NewRowIndex], ?createAndGo}],
?line s(Vbs1),
- ?line expect(1, inconsistentName, 1, any),
+ ?line ?expect3(inconsistentName, 1, any),
RowPointer2 = ?usmUserCloneFrom ++ [11|"agentEngine"] ++ [7|"privDES"],
Vbs2 = [{[usmUserCloneFrom, NewRowIndex], RowPointer2},
{[usmUserStatus, NewRowIndex], ?createAndGo}],
?line s(Vbs2),
- ?line expect(2, wrongValue, 1, any),
+ ?line ?expect3(wrongValue, 1, any),
RowPointer3 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"],
Vbs3 = [{[usmUserCloneFrom, NewRowIndex], RowPointer3},
{[usmUserStatus, NewRowIndex], ?createAndGo}],
?line s(Vbs3),
- ?line expect(3, Vbs3),
+ ?line ?expect1(Vbs3),
?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmNoAuthProtocol}]),
- ?line expect(4, inconsistentValue, 1, any),
+ ?line ?expect3(inconsistentValue, 1, any),
?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmHMACMD5AuthProtocol}]),
- ?line expect(5, inconsistentValue, 1, any),
+ ?line ?expect3(inconsistentValue, 1, any),
?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmDESPrivProtocol}]),
- ?line expect(6, wrongValue, 1, any),
+ ?line ?expect3(wrongValue, 1, any),
?line s([{[usmUserPrivProtocol, NewRowIndex], ?usmHMACSHAAuthProtocol}]),
- ?line expect(7, wrongValue, 1, any),
+ ?line ?expect3(wrongValue, 1, any),
Vbs4 = [{[usmUserStatus, NewRowIndex], ?destroy}],
?line s(Vbs4),
- ?line expect(1, Vbs4),
-
+ ?line ?expect1(Vbs4),
ok.
@@ -5239,7 +5680,60 @@ loop_it_2(Oid, N) ->
%%% Testing of reported bugs and other tickets.
%%%-----------------------------------------------------------------
+reported_bugs_cases() ->
+ [
+ otp_1128,
+ otp_1129,
+ otp_1131,
+ otp_1162,
+ otp_1222,
+ otp_1298,
+ otp_1331,
+ otp_1338,
+ otp_1342,
+ otp_1366,
+ otp_2776,
+ otp_2979,
+ otp_3187,
+ otp_3725
+ ].
+
+reported_bugs2_cases() ->
+ [
+ otp_1128_2,
+ otp_1129_2,
+ otp_1131_2,
+ otp_1162_2,
+ otp_1222_2,
+ otp_1298_2,
+ otp_1331_2,
+ otp_1338_2,
+ otp_1342_2,
+ otp_1366_2,
+ otp_2776_2,
+ otp_2979_2,
+ otp_3187_2
+ ].
+reported_bugs3_cases() ->
+ [
+ otp_1128_3,
+ otp_1129_3,
+ otp_1131_3,
+ otp_1162_3,
+ otp_1222_3,
+ otp_1298_3,
+ otp_1331_3,
+ otp_1338_3,
+ otp_1342_3,
+ otp_1366_3,
+ otp_2776_3,
+ otp_2979_3,
+ otp_3187_3,
+ otp_3542
+ ].
+
+
%%-----------------------------------------------------------------
%% Ticket: OTP-1128
%% Slogan: Bug in handling of createAndWait set-requests.
@@ -5251,14 +5745,14 @@ otp_1128(Config) when is_list(Config) ->
?line load_master("OLD-SNMPEA-MIB"),
?line init_old(),
- try_test(otp_1128),
+ try_test(otp_1128_test),
?line unload_master("OLD-SNMPEA-MIB").
otp_1128_2(X) -> ?P(otp_1128_2), otp_1128(X).
otp_1128_3(X) -> ?P(otp_1128_3), otp_1128(X).
-otp_1128() ->
+otp_1128_test() ->
io:format("Testing bug reported in ticket OTP-1128...~n"),
NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")],
@@ -5266,15 +5760,16 @@ otp_1128() ->
NewKeyc5 = [intCommunityStatus,get(mip),is("test")],
s([{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]),
- ?line expect(28, [{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]),
+ ?line ?expect1([{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]),
g([NewKeyc5]),
- ?line expect(29, [{NewKeyc5, ?notReady}]),
+ ?line ?expect1([{NewKeyc5, ?notReady}]),
s([{NewKeyc5, ?active}, {NewKeyc3, 2}]),
- ?line expect(30, [{NewKeyc5, ?active}, {NewKeyc3, 2}]),
+ ?line ?expect1([{NewKeyc5, ?active}, {NewKeyc3, 2}]),
g([NewKeyc5]),
- ?line expect(31, [{NewKeyc5, ?active}]),
+ ?line ?expect1([{NewKeyc5, ?active}]),
s([{NewKeyc5, ?destroy}]),
- ?line expect(32, [{NewKeyc5, ?destroy}]).
+ ?line ?expect1([{NewKeyc5, ?destroy}]).
+
%%-----------------------------------------------------------------
%% Ticket: OTP-1129, OTP-1169
@@ -5297,6 +5792,7 @@ otp_1129_i(MaNode) ->
false = rpc:call(MaNode, snmp, int_to_enum, [iso, 1]),
false = rpc:call(MaNode, snmp, int_to_enum, [isox, 1]).
+
%%-----------------------------------------------------------------
%% Ticket: OTP-1131
%% Slogan: Agent crashes / erlang node halts if RowIndex in a
@@ -5309,7 +5805,7 @@ otp_1131(Config) when is_list(Config) ->
init_case(Config),
?line load_master("Klas1"),
- try_test(otp_1131),
+ try_test(otp_1131_test),
?line unload_master("Klas1").
otp_1131_2(X) -> ?P(otp_1131_2), otp_1131(X).
@@ -5352,11 +5848,11 @@ otp_1131_3(X) ->
?P(otp_1131_3),
otp_1131(X).
-otp_1131() ->
+otp_1131_test() ->
io:format("Testing bug reported in ticket OTP-1131...~n"),
s([{[friendsEntry, [2, 3, 1]], s, "kompis3"},
{[friendsEntry, [3, 3, 1]], i, ?createAndGo}]),
- ?line expect(1, ?v1_2(noSuchName, noCreation), 2, any).
+ ?line ?expect3(?v1_2(noSuchName, noCreation), 2, any).
%%-----------------------------------------------------------------
@@ -5368,16 +5864,16 @@ otp_1162(Config) when is_list(Config) ->
?P(otp_1162),
{SaNode, _MgrNode, _MibDir} = init_case(Config),
?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
- try_test(otp_1162),
+ try_test(otp_1162_test),
stop_subagent(SA).
otp_1162_2(X) -> ?P(otp_1162_2), otp_1162(X).
otp_1162_3(X) -> ?P(otp_1162_3), otp_1162(X).
-otp_1162() ->
+otp_1162_test() ->
s([{[sa, [2,0]], 6}]), % wrongValue (i is_set_ok)
- ?line expect(1, ?v1_2(badValue, wrongValue), 1, any).
+ ?line ?expect3(?v1_2(badValue, wrongValue), 1, any).
%%-----------------------------------------------------------------
@@ -5390,7 +5886,7 @@ otp_1222(Config) when is_list(Config) ->
init_case(Config),
?line load_master("Klas3"),
?line load_master("Klas4"),
- try_test(otp_1222),
+ try_test(otp_1222_test),
?line unload_master("Klas3"),
?line unload_master("Klas4").
@@ -5398,12 +5894,13 @@ otp_1222_2(X) -> ?P(otp_1222_2), otp_1222(X).
otp_1222_3(X) -> ?P(otp_1222_3), otp_1222(X).
-otp_1222() ->
+otp_1222_test() ->
io:format("Testing bug reported in ticket OTP-1222...~n"),
s([{[fStatus4,1], 4}, {[fName4,1], 1}]),
- ?line expect(1, genErr, 0, any),
+ ?line ?expect3(genErr, 0, any),
s([{[fStatus4,2], 4}, {[fName4,2], 1}]),
- ?line expect(2, genErr, 0, any).
+ ?line ?expect3(genErr, 0, any).
+
%%-----------------------------------------------------------------
%% Ticket: OTP-1298
@@ -5415,17 +5912,17 @@ otp_1298(Config) when is_list(Config) ->
init_case(Config),
?line load_master("Klas2"),
- try_test(otp_1298),
+ try_test(otp_1298_test),
?line unload_master("Klas2").
otp_1298_2(X) -> ?P(otp_1298_2), otp_1298(X).
otp_1298_3(X) -> ?P(otp_1298_3), otp_1298(X).
-otp_1298() ->
+otp_1298_test() ->
io:format("Testing bug reported in ticket OTP-1298...~n"),
s([{[fint,0], -1}]),
- ?line expect(1298, [{[fint,0], -1}]).
+ ?line ?expect1([{[fint,0], -1}]).
%%-----------------------------------------------------------------
@@ -5438,17 +5935,17 @@ otp_1331(Config) when is_list(Config) ->
init_case(Config),
?line load_master("OLD-SNMPEA-MIB"),
?line init_old(),
- try_test(otp_1331),
+ try_test(otp_1331_test),
?line unload_master("OLD-SNMPEA-MIB").
otp_1331_2(X) -> ?P(otp_1331_2), otp_1331(X).
otp_1331_3(X) -> ?P(otp_1331_3), otp_1331(X).
-otp_1331() ->
+otp_1331_test() ->
NewKeyc5 = [intCommunityStatus,[127,32,0,0],is("test")],
s([{NewKeyc5, ?destroy}]),
- ?line expect(1, [{NewKeyc5, ?destroy}]).
+ ?line ?expect1([{NewKeyc5, ?destroy}]).
%%-----------------------------------------------------------------
@@ -5461,18 +5958,19 @@ otp_1338(Config) when is_list(Config) ->
init_case(Config),
?line load_master("Klas2"),
- try_test(otp_1338),
+ try_test(otp_1338_test),
?line unload_master("Klas2").
otp_1338_2(X) -> ?P(otp_1338_2), otp_1338(X).
otp_1338_3(X) -> ?P(otp_1338_3), otp_1338(X).
-otp_1338() ->
+otp_1338_test() ->
s([{[kStatus2, 7], i, ?createAndGo}]),
- ?line expect(1, [{[kStatus2, 7], ?createAndGo}]),
+ ?line ?expect1([{[kStatus2, 7], ?createAndGo}]),
g([[kName2, 7]]),
- ?line expect(2, [{[kName2, 7], "JJJ"}]).
+ ?line ?expect1([{[kName2, 7], "JJJ"}]).
+
%%-----------------------------------------------------------------
%% Ticket: OTP-1342
@@ -5484,18 +5982,18 @@ otp_1342(Config) when is_list(Config) ->
?P(otp_1342),
init_case(Config),
?line load_master("Klas4"),
- try_test(otp_1342),
+ try_test(otp_1342_test),
?line unload_master("Klas4").
otp_1342_2(X) -> ?P(otp_1342_2), otp_1342(X).
otp_1342_3(X) -> ?P(otp_1342_3), otp_1342(X).
-otp_1342() ->
+otp_1342_test() ->
s([{[fIndex5, 1], i, 1},
{[fName5, 1], i, 3},
{[fStatus5, 1], i, ?createAndGo}]),
- ?line expect(1, ?v1_2(noSuchName, noCreation), 3, any).
+ ?line ?expect3(?v1_2(noSuchName, noCreation), 3, any).
%%-----------------------------------------------------------------
@@ -5510,17 +6008,18 @@ otp_1366(Config) when is_list(Config) ->
init_case(Config),
?line load_master("OLD-SNMPEA-MIB"),
?line init_old(),
- try_test(otp_1366),
+ try_test(otp_1366_test),
?line unload_master("OLD-SNMPEA-MIB").
otp_1366_2(X) -> ?P(otp_1366_2), otp_1366(X).
otp_1366_3(X) -> ?P(otp_1366_3), otp_1366(X).
-otp_1366() ->
+otp_1366_test() ->
?INF("NOT YET IMPLEMENTED", []),
'NYI'.
+
%%-----------------------------------------------------------------
%% Ticket: OTP-2776
%% Slogan: snmp:validate_date_and_time() fails when time is 00:00
@@ -5529,13 +6028,13 @@ otp_2776(suite) -> [];
otp_2776(Config) when is_list(Config) ->
?P(otp_2776),
init_case(Config),
- try_test(otp_2776).
+ try_test(otp_2776_test).
otp_2776_2(X) -> ?P(otp_2776_2), otp_2776(X).
otp_2776_3(X) -> ?P(otp_2776_3), otp_2776(X).
-otp_2776() ->
+otp_2776_test() ->
io:format("Testing bug reported in ticket OTP-2776...~n"),
Dt01_valid = [19,98,9,1,1,0,23,0,43,0,0],
@@ -5598,17 +6097,18 @@ otp_2979(Config) when is_list(Config) ->
init_case(Config),
?line load_master("Test1"),
?line init_old(),
- try_test(otp_2979),
+ try_test(otp_2979_test),
?line unload_master("Test1").
otp_2979_2(X) -> ?P(otp_2979_2), otp_2979(X).
otp_2979_3(X) -> ?P(otp_2979_3), otp_2979(X).
-otp_2979() ->
+otp_2979_test() ->
gn([[sparseDescr], [sparseStatus]]),
- ?line expect(1, [{[sparseStr,0], "slut"},
- {[sparseStr,0], "slut"}]).
+ ?line ?expect1([{[sparseStr,0], "slut"},
+ {[sparseStr,0], "slut"}]).
+
%%-----------------------------------------------------------------
%% Ticket: OTP-3187
@@ -5620,14 +6120,14 @@ otp_3187(Config) when is_list(Config) ->
?P(otp_3187),
init_case(Config),
?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
- otp_3187(),
+ otp_3187_test(),
?line unload_master("SNMP-VIEW-BASED-ACM-MIB").
otp_3187_2(X) -> ?P(otp_3187_2), otp_3187(X).
otp_3187_3(X) -> ?P(otp_3187_3), otp_3187(X).
-otp_3187() ->
+otp_3187_test() ->
?line Elements =
snmp_view_based_acm_mib:vacmAccessTable(get_next,[],[4,5,6]),
lists:foreach(fun(E) ->
@@ -5645,9 +6145,9 @@ otp_3542(suite) -> [];
otp_3542(Config) when is_list(Config) ->
?P(otp_3542),
init_case(Config),
- try_test(otp_3542).
+ try_test(otp_3542_test).
-otp_3542() ->
+otp_3542_test() ->
io:format("SNMP v3 discovery...~n"),
?line Res = snmp_test_mgr:d(),
io:format("SNMP v3 discovery result: ~p~n",[Res]).
@@ -5716,10 +6216,15 @@ otp_3725_test(MaNode) ->
%% Slogan: Target mib tag list check invalid
%%-----------------------------------------------------------------
+tickets1_cases() ->
+ [
+ {group, otp4394},
+ {group, otp7157}
+ ].
+
-
-init_otp_4394(Config) when is_list(Config) ->
- ?DBG("init_otp_4394 -> entry with"
+otp_4394_init(Config) when is_list(Config) ->
+ ?DBG("otp_4394_init -> entry with"
"~n Config: ~p", [Config]),
?line AgentConfDir = ?config(agent_conf_dir, Config),
?line MgrDir = ?config(mgr_dir, Config),
@@ -5772,35 +6277,35 @@ otp_4394_config(AgentConfDir, MgrDir, Ip0) ->
-finish_otp_4394(Config) when is_list(Config) ->
+otp_4394_finish(Config) when is_list(Config) ->
?DBG("finish_otp_4394 -> entry", []),
C1 = stop_agent(Config),
delete_files(C1),
erase(mgr_node),
lists:keydelete(vsn, 1, C1).
-otp_4394_test(suite) -> [];
-otp_4394_test(Config) ->
- ?P(otp_4394_test),
- ?DBG("otp_4394_test -> entry", []),
+otp_4394(suite) -> [];
+otp_4394(Config) ->
+ ?P(otp_4394),
+ ?DBG("otp_4394 -> entry", []),
init_case(Config),
- try_test(otp_4394_test1),
- ?DBG("otp_4394_test -> done", []),
+ try_test(otp_4394_test),
+ ?DBG("otp_4394 -> done", []),
ok.
-otp_4394_test1() ->
- ?DBG("otp_4394_test1 -> entry", []),
+otp_4394_test() ->
+ ?DBG("otp_4394_test -> entry", []),
gn([[1,1]]),
Res =
case snmp_test_mgr:expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]) of
%% {error, 1, {"?",[]}, {"~w",[timeout]}}
{error, 1, _, {_, [timeout]}} ->
- ?DBG("otp_4394_test1 -> expected result: timeout", []),
+ ?DBG("otp_4394_test -> expected result: timeout", []),
ok;
Else ->
Else
end,
- ?DBG("otp_4394_test1 -> done with: ~p", [Res]),
+ ?DBG("otp_4394_test -> done with: ~p", [Res]),
Res.
@@ -5811,7 +6316,7 @@ otp_4394_test1() ->
-init_otp_7157(Config) when is_list(Config) ->
+otp_7157_init(Config) when is_list(Config) ->
%% <CONDITIONAL-SKIP>
Skippable = [win32],
Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
@@ -5831,30 +6336,30 @@ init_otp_7157(Config) when is_list(Config) ->
[{vsn, v2} | start_v2_agent(Config, Opts)].
-finish_otp_7157(Config) when is_list(Config) ->
+otp_7157_finish(Config) when is_list(Config) ->
?DBG("finish_otp_7157 -> entry", []),
C1 = stop_agent(Config),
delete_files(C1),
erase(mgr_node),
lists:keydelete(vsn, 1, C1).
-otp_7157_test(suite) -> [];
-otp_7157_test(Config) ->
- ?P(otp_7157_test),
- ?DBG("otp_7157_test -> entry", []),
+otp_7157(suite) -> [];
+otp_7157(Config) ->
+ ?P(otp_7157),
+ ?DBG("otp_7157 -> entry", []),
init_case(Config),
MA = whereis(snmp_master_agent),
?line load_master("Test1"),
- try_test(otp_7157_test1, [MA]),
+ try_test(otp_7157_test, [MA]),
?line unload_master("Test1"),
- ?DBG("otp_7157_test -> done", []),
+ ?DBG("otp_7157 -> done", []),
ok.
%% ts:run(snmp, snmp_agent_test, [batch]).
-otp_7157_test1(MA) ->
- ?LOG("start otp_7157_test1 test (~p)",[MA]),
+otp_7157_test(MA) ->
+ ?LOG("start otp_7157_test test (~p)",[MA]),
snmpa:verbosity(MA, trace),
- ?LOG("start otp_7157_test1 test",[]),
+ ?LOG("start otp_7157_test test",[]),
?P1("Testing that varbinds in traps/notifications are not reordered"),
?DBG("send cntTrap",[]),
@@ -5862,11 +6367,11 @@ otp_7157_test1(MA) ->
?DBG("await response",[]),
%% We don't really care about the values, just the vb order.
- ?line ok = expect(1, v2trap, [{[sysUpTime, 0], any},
- {[snmpTrapOID, 0], any},
- {[sysContact, 0], any},
- {[cnt64, 0], any},
- {[sysLocation, 0], any}]),
+ ?line ok = ?expect2(v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], any},
+ {[sysContact, 0], any},
+ {[cnt64, 0], any},
+ {[sysLocation, 0], any}]),
?DBG("done", []),
ok.
@@ -5878,6 +6383,13 @@ otp_7157_test1(MA) ->
%% These cases are started in the new way
%%-----------------------------------------------------------------
+tickets2_cases() ->
+ [
+ otp8395,
+ otp9884
+ ].
+
+
otp8395({init, Config}) when is_list(Config) ->
?DBG("otp8395(init) -> entry with"
"~n Config: ~p", [Config]),
@@ -6336,13 +6848,13 @@ process_options(Defaults, _Opts) ->
%% {value, {Key, Value}} when is_list->
-snmp_app_env_init(Node, Entity, Conf) ->
- rpc:call(Node, snmp_app_env_init, [Entity, Conf]).
+%% snmp_app_env_init(Node, Entity, Conf) ->
+%% rpc:call(Node, snmp_app_env_init, [Entity, Conf]).
-snmp_app_env_init(Entity, Conf) ->
- application:unload(snmp),
- application:load(snmp),
- application:set_env(snmp, Entity, Conf).
+%% snmp_app_env_init(Entity, Conf) ->
+%% application:unload(snmp),
+%% application:load(snmp),
+%% application:set_env(snmp, Entity, Conf).
start_stdalone_agent(Node, Config) ->
rpc:call(Node, ?MODULE, start_stdalone_agent, [Config]).
@@ -6403,10 +6915,10 @@ info_test(Config) when is_list(Config) ->
?line load_master("OLD-SNMPEA-MIB"),
?line init_old(),
- try_test(info_test1, [node()]),
+ try_test(do_info, [node()]),
?line unload_master("OLD-SNMPEA-MIB").
-info_test1(MaNode) ->
+do_info(MaNode) ->
?line Info = rpc:call(MaNode, snmpa, info, []),
?DBG("info_test1 -> Info: ~n~p", [Info]),
Keys = [vsns,
@@ -6482,7 +6994,7 @@ verify_old_info([Key|Keys], Info) ->
?FAIL({missing_old_info, Key})
end.
-%% string used in index
+%% Index String - string used in index
is(S) -> [length(S) | S].
try_test(Func) ->
@@ -6500,16 +7012,11 @@ try_test(Func, A, Opts) ->
%% Test manager wrapperfunctions:
g(Oids) -> snmp_test_mgr:g(Oids).
-gn() -> snmp_test_mgr:gn().
+%%gn() -> snmp_test_mgr:gn().
gn(OidsOrN) -> snmp_test_mgr:gn(OidsOrN).
gb(NR, MR, Oids) -> snmp_test_mgr:gb(NR, MR, Oids).
s(VAV) -> snmp_test_mgr:s(VAV).
-expect(A, B) -> snmp_agent_test_lib:expect(A, B).
-expect(A, B, C) -> snmp_agent_test_lib:expect(A, B, C).
-expect(A, B, C, D) -> snmp_agent_test_lib:expect(A, B, C, D).
-expect(A, B, C, D, E, F) -> snmp_agent_test_lib:expect(A, B, C, D, E, F).
-
get_req(Id, Vars) ->
snmp_agent_test_lib:get_req(Id, Vars).
@@ -6545,8 +7052,8 @@ rewrite_usm_mgr(Dir, ShaKey, DesKey) ->
reset_usm_mgr(Dir) ->
snmp_agent_test_lib:reset_usm_mgr(Dir).
-update_community(Vsns, DIr) ->
- snmp_agent_test_lib:update_community(Vsns, DIr).
+%% update_community(Vsns, Dir) ->
+%% snmp_agent_test_lib:update_community(Vsns, Dir).
update_vacm(Vsn, Dir) ->
snmp_agent_test_lib:update_vacm(Vsn, Dir).
@@ -6579,8 +7086,8 @@ reset_target_params_conf(Dir) ->
write_notify_conf(Dir) ->
snmp_agent_test_lib:write_notify_conf(Dir).
-write_view_conf(Dir) ->
- snmp_agent_test_lib:write_view_conf(Dir).
+%% write_view_conf(Dir) ->
+%% snmp_agent_test_lib:write_view_conf(Dir).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -6742,8 +7249,8 @@ lists_key1search(Key, List) when is_atom(Key) ->
end.
-regs() ->
- lists:sort(registered()).
+%% regs() ->
+%% lists:sort(registered()).
%% ------
diff --git a/lib/snmp/test/snmp_agent_test_lib.erl b/lib/snmp/test/snmp_agent_test_lib.erl
index 757aebfa9b..11c05fc1db 100644
--- a/lib/snmp/test/snmp_agent_test_lib.erl
+++ b/lib/snmp/test/snmp_agent_test_lib.erl
@@ -28,7 +28,7 @@
start_mt_agent/1, start_mt_agent/2,
stop_agent/1,
- start_sup/0, stop_sup/2,
+ %% start_sup/0, stop_sup/2,
start_subagent/3, stop_subagent/1,
start_sub_sup/1, start_sub_sup/2,
@@ -58,7 +58,7 @@
init_all/1, finish_all/1,
init_case/1,
try_test/2, try_test/3, try_test/4,
- expect/2, expect/3, expect/4, expect/6,
+ expect/3, expect/4, expect/5, expect/7,
regs/0,
rpc/3
@@ -418,10 +418,10 @@ start_bilingual_agent(Config, Opts)
start_agent(Config, [v1,v2], Opts).
start_mt_agent(Config) when is_list(Config) ->
- start_agent(Config, [v2], [{snmp_multi_threaded, true}]).
+ start_agent(Config, [v2], [{multi_threaded, true}]).
start_mt_agent(Config, Opts) when is_list(Config) andalso is_list(Opts) ->
- start_agent(Config, [v2], [{snmp_multi_threaded, true}|Opts]).
+ start_agent(Config, [v2], [{multi_threaded, true}|Opts]).
start_agent(Config, Vsns) ->
start_agent(Config, Vsns, []).
@@ -437,79 +437,231 @@ start_agent(Config, Vsns, Opts) ->
?line AgentDbDir = ?config(agent_db_dir, Config),
?line SaNode = ?config(snmp_sa, Config),
- app_env_init(vsn_init(Vsns) ++
- [{audit_trail_log, read_write_log},
- {audit_trail_log_dir, AgentLogDir},
- {audit_trail_log_size, {10240, 10}},
- {force_config_reload, false},
- {snmp_agent_type, master},
- {snmp_config_dir, AgentConfDir},
- {snmp_db_dir, AgentDbDir},
- {snmp_local_db_auto_repair, true},
- {snmp_local_db_verbosity, log},
- {snmp_master_agent_verbosity, trace},
- {snmp_supervisor_verbosity, trace},
- {snmp_mibserver_verbosity, log},
- {snmp_symbolic_store_verbosity, log},
- {snmp_note_store_verbosity, log},
- {snmp_net_if_verbosity, trace}],
- Opts),
-
+ Env = app_agent_env_init(
+ [{versions, Vsns},
+ {agent_type, master},
+ {agent_verbosity, trace},
+ {db_dir, AgentDbDir},
+ {audit_trail_log, [{type, read_write},
+ {dir, AgentLogDir},
+ {size, {10240, 10}}]},
+ {config, [{dir, AgentConfDir},
+ {force_load, false},
+ {verbosity, trace}]},
+ {local_db, [{repair, true},
+ {verbosity, log}]},
+ {mib_server, [{verbosity, log}]},
+ {symbolic_store, [{verbosity, log}]},
+ {note_store, [{verbosity, log}]},
+ {net_if, [{verbosity, trace}]}],
+ Opts),
+
process_flag(trap_exit,true),
{ok, AppSup} = snmp_app_sup:start_link(),
unlink(AppSup),
- ?DBG("start_agent -> snmp app supervisor: ~p",[AppSup]),
+ ?DBG("start_agent -> snmp app supervisor: ~p", [AppSup]),
- ?DBG("start_agent -> start master agent (old style)",[]),
- ?line Sup = start_sup(),
+ ?DBG("start_agent -> start master agent",[]),
+ ?line Sup = start_sup(Env),
- ?DBG("start_agent -> unlink from supervisor",[]),
+ ?DBG("start_agent -> unlink from supervisor", []),
?line unlink(Sup),
?line SaDir = ?config(sa_dir, Config),
- ?DBG("start_agent -> (rpc) start sub on ~p",[SaNode]),
+ ?DBG("start_agent -> (rpc) start sub on ~p", [SaNode]),
?line {ok, Sub} = start_sub_sup(SaNode, SaDir),
?DBG("start_agent -> done",[]),
?line [{snmp_sup, {Sup, self()}}, {snmp_sub, Sub} | Config].
-vsn_init(Vsn) ->
- vsn_init([v1,v2,v3], Vsn, []).
+app_agent_env_init(Env0, Opts) ->
+ ?DBG("app_agent_env_init -> unload snmp",[]),
+ ?line application:unload(snmp),
+
+ ?DBG("app_agent_env_init -> load snmp",[]),
+ ?line application:load(snmp),
-vsn_init([], _Vsn, Acc) ->
- Acc;
-vsn_init([V|Vsns], Vsn, Acc) ->
- case lists:member(V, Vsn) of
- true ->
- vsn_init(Vsns, Vsn, [{V, true}|Acc]);
- false ->
- vsn_init(Vsns, Vsn, [{V, false}|Acc])
+ ?DBG("app_agent_env_init -> "
+ "merge or maybe replace (snmp agent) app env",[]),
+ Env = add_or_maybe_merge_agent_env(Opts, Env0),
+ ?DBG("app_agent_env_init -> merged env: "
+ "~n ~p", [Env]),
+
+ %% We put it into the app environment just as
+ %% a precaution, since when starting normally,
+ %% this is where the environment is extracted from.
+ app_agent_set_env(Env),
+ Env.
+
+app_agent_set_env(Value) ->
+ application_controller:set_env(snmp, agent, Value).
+
+add_or_maybe_merge_agent_env([], Env) ->
+ ?DBG("merging agent env -> merged", []),
+ lists:keysort(1, Env);
+add_or_maybe_merge_agent_env([{Key, Value1}|Opts], Env) ->
+ ?DBG("merging agent env -> add, replace or merge ~p", [Key]),
+ case lists:keysearch(Key, 1, Env) of
+ {value, {Key, Value1}} ->
+ %% Identical, move on
+ ?DBG("merging agent env -> "
+ "no need to merge ~p - identical - keep: "
+ "~n ~p", [Key, Value1]),
+ add_or_maybe_merge_agent_env(Opts, Env);
+ {value, {Key, Value2}} ->
+ %% Another value, merge or replace
+ NewValue = merge_or_replace_agent_env(Key, Value1, Value2),
+ Env2 = lists:keyreplace(Key, 1, Env, {Key, NewValue}),
+ add_or_maybe_merge_agent_env(Opts, Env2);
+ false ->
+ ?DBG("merging agent env -> no old ~p to merge with - add: "
+ "~n ~p", [Key, Value1]),
+ add_or_maybe_merge_agent_env(Opts, [{Key, Value1}|Env])
end.
-app_env_init(Env0, Opts) ->
- ?DBG("app_env_init -> unload snmp",[]),
- ?line application:unload(snmp),
- ?DBG("app_env_init -> load snmp",[]),
- ?line application:load(snmp),
- ?DBG("app_env_init -> initiate (snmp) application env",[]),
- F1 = fun({Key, Val} = New, Acc0) ->
- ?DBG("app_env_init -> "
- "updating setting ~p to ~p", [Key, Val]),
- case lists:keyreplace(Key, 1, Acc0, New) of
- Acc0 ->
- [New|Acc0];
- Acc ->
- Acc
- end
- end,
- Env = lists:foldr(F1, Env0, Opts),
- ?DBG("app_env_init -> Env: ~p",[Env]),
- F2 = fun({Key,Val}) ->
- ?DBG("app_env_init -> setting ~p to ~p",[Key, Val]),
- application_controller:set_env(snmp, Key, Val)
- end,
- lists:foreach(F2, Env).
+merge_or_replace_agent_env(versions, NewVersions, _OldVersions) ->
+ ?DBG("merging agent env -> versions replaced: ~p -> ~p",
+ [NewVersions, _OldVersions]),
+ NewVersions;
+merge_or_replace_agent_env(agent_type, NewType, _OldType) ->
+ ?DBG("merging agent env -> agent type replaced: ~p -> ~p",
+ [NewType, _OldType]),
+ NewType;
+merge_or_replace_agent_env(agent_verbosity, NewVerbosity, _OldVerbosity) ->
+ ?DBG("merging agent env -> agent verbosity replaced: ~p -> ~p",
+ [NewVerbosity, _OldVerbosity]),
+ NewVerbosity;
+merge_or_replace_agent_env(db_dir, NewDbDir, _OldDbDir) ->
+ ?DBG("merging agent env -> db-dir replaced: ~p -> ~p",
+ [NewDbDir, _OldDbDir]),
+ NewDbDir;
+merge_or_replace_agent_env(audit_trail_log, NewATL, OldATL) ->
+ merge_or_replace_agent_env_atl(NewATL, OldATL);
+merge_or_replace_agent_env(config, NewConfig, OldConfig) ->
+ merge_or_replace_agent_env_config(NewConfig, OldConfig);
+merge_or_replace_agent_env(local_db, NewLdb, OldLdb) ->
+ merge_or_replace_agent_env_ldb(NewLdb, OldLdb);
+merge_or_replace_agent_env(mib_storage, NewMst, OldMst) ->
+ merge_or_replace_agent_env_mib_storage(NewMst, OldMst);
+merge_or_replace_agent_env(mib_server, NewMibs, OldMibs) ->
+ merge_or_replace_agent_env_mib_server(NewMibs, OldMibs);
+merge_or_replace_agent_env(symbolic_store, NewSymStore, OldSymStore) ->
+ merge_or_replace_agent_env_symbolic_store(NewSymStore, OldSymStore);
+merge_or_replace_agent_env(note_store, NewNoteStore, OldNoteStore) ->
+ merge_or_replace_agent_env_note_store(NewNoteStore, OldNoteStore);
+merge_or_replace_agent_env(net_if, NewNetIf, OldNetIf) ->
+ merge_or_replace_agent_env_net_if(NewNetIf, OldNetIf);
+merge_or_replace_agent_env(Key, NewValue, OldValue) ->
+ ?FAIL({not_implemented_merge_or_replace,
+ Key, NewValue, OldValue}).
+
+merge_or_replace_agent_env_atl(New, Old) ->
+ ATL = merge_agent_options(New, Old),
+ ?DBG("merging agent env -> audit-trail-log merged: "
+ "~n ~p | ~p -> ~p", [New, Old, ATL]),
+ ATL.
+
+merge_or_replace_agent_env_config(New, Old) ->
+ Config = merge_agent_options(New, Old),
+ case lists:keymember(dir, 1, Config) of
+ true ->
+ ?DBG("merging agent env -> config merged: "
+ "~n ~p | ~p -> ~p", [New, Old, Config]),
+ Config;
+ false ->
+ ?FAIL({missing_mandatory_option, {config, dir}})
+ end.
+
+merge_or_replace_agent_env_ldb(New, Old) ->
+ LDB = merge_agent_options(New, Old),
+ ?DBG("merging agent env -> local-db merged: "
+ "~n ~p | ~p -> ~p", [New, Old, LDB]),
+ LDB.
+
+merge_or_replace_agent_env_mib_storage(NewMibStorage, OldMibStorage) ->
+ %% Shall we merge or replace?
+ %% module is mandatory. We will only merge if NewModule is
+ %% equal to OldModule.
+ NewModule =
+ case lists:keysearch(module, 1, NewMibStorage) of
+ {value, {module, M}} ->
+ M;
+ false ->
+ ?FAIL({missing_mandatory_option, {mib_storage, module}})
+ end,
+ case lists:keysearch(module, 1, OldMibStorage) of
+ {value, {module, NewModule}} ->
+ %% Same module => merge
+ %% Non-ex new options => remove
+ %% Ex new options and non-ex old options => replace
+ %% Otherwise merge
+ case lists:keysearch(options, 1, NewMibStorage) of
+ false ->
+ ?DBG("merging agent env -> "
+ "no mib-storage ~p merge needed - "
+ "no new options (= remove old options)", [NewModule]),
+ NewMibStorage;
+ {value, {options, NewOptions}} ->
+ case lists:keysearch(options, 1, OldMibStorage) of
+ false ->
+ ?DBG("merging agent env -> "
+ "no mib-storage ~p merge needed - "
+ "no old options", [NewModule]),
+ NewMibStorage;
+ {value, {options, OldOptions}} ->
+ MergedOptions =
+ merge_agent_options(NewOptions, OldOptions),
+ ?DBG("merging agent env -> mib-storage ~p merged: "
+ "~n Options: ~p | ~p -> ~p",
+ [NewModule,
+ NewOptions, OldOptions, MergedOptions]),
+ [{module, NewModule},
+ {options, MergedOptions}]
+ end
+ end;
+ _ ->
+ %% Diff module => replace
+ ?DBG("merging agent env -> "
+ "no mib-storage ~p merge needed - "
+ "new module", [NewModule]),
+ NewMibStorage
+ end.
+
+merge_or_replace_agent_env_mib_server(New, Old) ->
+ MibServer = merge_agent_options(New, Old),
+ ?DBG("merging agent env -> mib-server merged: "
+ "~n ~p | ~p -> ~p", [New, Old, MibServer]),
+ MibServer.
+
+merge_or_replace_agent_env_symbolic_store(New, Old) ->
+ SymbolicStore = merge_agent_options(New, Old),
+ ?DBG("merging agent env -> symbolic-store merged: "
+ "~n ~p | ~p -> ~p", [New, Old, SymbolicStore]),
+ SymbolicStore.
+
+merge_or_replace_agent_env_note_store(New, Old) ->
+ NoteStore = merge_agent_options(New, Old),
+ ?DBG("merging agent env -> note-store merged: "
+ "~n ~p | ~p -> ~p", [New, Old, NoteStore]),
+ NoteStore.
+
+merge_or_replace_agent_env_net_if(New, Old) ->
+ NetIf = merge_agent_options(New, Old),
+ ?DBG("merging agent env -> net-if merged: "
+ "~n ~p | ~p -> ~p", [New, Old, NetIf]),
+ NetIf.
+
+merge_agent_options([], Options) ->
+ lists:keysort(1, Options);
+merge_agent_options([{Key, _Value} = Opt|Opts], Options) ->
+ case lists:keysearch(Key, 1, Options) of
+ {value, _} ->
+ NewOptions = lists:keyreplace(Key, 1, Options, Opt),
+ merge_agent_options(Opts, NewOptions);
+ false ->
+ merge_agent_options(Opts, [Opt|Options])
+ end.
stop_agent(Config) when is_list(Config) ->
@@ -544,8 +696,8 @@ stop_agent(Config) when is_list(Config) ->
lists:keydelete(snmp_sub, 1, C1).
-start_sup() ->
- case (catch snmpa_app:start(normal)) of
+start_sup(Env) ->
+ case (catch snmp_app_sup:start_agent(normal, Env)) of
{ok, S} ->
?DBG("start_agent -> started, Sup: ~p",[S]),
S;
@@ -553,7 +705,7 @@ start_sup() ->
Else ->
?DBG("start_agent -> unknown result: ~n~p",[Else]),
%% Get info about the apps we depend on
- ?FAIL({start_failed,Else, ?IS_MNESIA_RUNNING()})
+ ?FAIL({start_failed, Else, ?IS_MNESIA_RUNNING()})
end.
stop_sup(Pid, _) when (node(Pid) =:= node()) ->
@@ -594,7 +746,7 @@ start_sub_sup(Node, Dir) ->
start_sub_sup(Dir) ->
?DBG("start_sub -> entry",[]),
- Opts = [{db_dir, Dir},
+ Opts = [{db_dir, Dir},
{supervisor, [{verbosity, trace}]}],
{ok, P} = snmpa_supervisor:start_sub_sup(Opts),
unlink(P),
@@ -690,31 +842,33 @@ agent_info(Sup) ->
%% ---
+%% The first two arguments are simple to be able to find where in the
+%% (test) code this call is made.
-expect(Id, A) ->
- Fun = fun() -> do_expect(A) end,
- expect2(Id, Fun).
+expect(Mod, Line, What) ->
+ Fun = fun() -> do_expect(What) end,
+ expect2(Mod, Line, Fun).
-expect(Id, A, B) ->
- Fun = fun() -> do_expect(A, B) end,
- expect2(Id, Fun).
+expect(Mod, Line, What, ExpVBs) ->
+ Fun = fun() -> do_expect(What, ExpVBs) end,
+ expect2(Mod, Line, Fun).
-expect(Id, A, B, C) ->
- Fun = fun() -> do_expect(A, B, C) end,
- expect2(Id, Fun).
+expect(Mod, Line, Error, Index, ExpVBS) ->
+ Fun = fun() -> do_expect(Error, Index, ExpVBS) end,
+ expect2(Mod, Line, Fun).
-expect(Id, A, B, C, D, E) ->
- Fun = fun() -> do_expect(A, B, C, D, E) end,
- expect2(Id, Fun).
+expect(Mod, Line, Type, Enterp, Generic, Specific, ExpVBs) ->
+ Fun = fun() -> do_expect(Type, Enterp, Generic, Specific, ExpVBs) end,
+ expect2(Mod, Line, Fun).
-expect2(Id, F) ->
- io:format("EXPECT for ~w~n", [Id]),
+expect2(Mod, Line, F) ->
+ io:format("EXPECT for ~w:~w~n", [Mod, Line]),
case F() of
{error, Reason} ->
- io:format("EXPECT failed for ~w: ~n~p~n", [Id, Reason]),
- throw({error, {expect, Id, Reason}});
+ io:format("EXPECT failed at ~w:~w => ~n~p~n", [Mod, Line, Reason]),
+ throw({error, {expect, Mod, Line, Reason}});
Else ->
- io:format("EXPECT result for ~w: ~n~p~n", [Id, Else]),
+ io:format("EXPECT result for ~w:~w => ~n~p~n", [Mod, Line, Else]),
Else
end.
@@ -766,7 +920,8 @@ do_expect({timeout, To}) ->
end;
do_expect({Err, To})
- when is_atom(Err) andalso (is_integer(To) orelse (To =:= infinity)) ->
+ when (is_atom(Err) andalso
+ ((is_integer(To) andalso To > 0) orelse (To =:= infinity))) ->
io:format("EXPECT error ~w within ~w~n", [Err, To]),
do_expect({{error, Err}, To});
diff --git a/lib/snmp/test/snmp_test_lib.erl b/lib/snmp/test/snmp_test_lib.erl
index f0abae73e8..505332b586 100644
--- a/lib/snmp/test/snmp_test_lib.erl
+++ b/lib/snmp/test/snmp_test_lib.erl
@@ -435,7 +435,7 @@ crypto_start() ->
end.
crypto_support() ->
- crypto_support([md5_mac_96, sha_mac_96], []).
+ crypto_support([md5, sha], []).
crypto_support([], []) ->
yes;
@@ -450,12 +450,7 @@ crypto_support([Func|Funcs], Acc) ->
end.
is_crypto_supported(Func) ->
- %% The 'catch' handles the case when 'crypto' is
- %% not present in the system (or not started).
- case (catch lists:member(Func, crypto:info())) of
- true -> true;
- _ -> false
- end.
+ snmp_misc:is_crypto_supported(Func).
%% ----------------------------------------------------------------
diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk
index fb7aa52402..0e48e7ea56 100644
--- a/lib/snmp/vsn.mk
+++ b/lib/snmp/vsn.mk
@@ -18,6 +18,6 @@
# %CopyrightEnd%
APPLICATION = snmp
-SNMP_VSN = 4.23.1
+SNMP_VSN = 4.24
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)"
diff --git a/lib/ssh/src/ssh_bits.erl b/lib/ssh/src/ssh_bits.erl
index 5841f06d70..fc6efc817f 100644
--- a/lib/ssh/src/ssh_bits.erl
+++ b/lib/ssh/src/ssh_bits.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -33,7 +33,6 @@
%% integer utils
-export([isize/1]).
--export([irandom/1, irandom/3]).
-export([random/1]).
-export([xor_bits/2, fill_bits/2]).
-export([i2bin/2, bin2i/1]).
@@ -387,31 +386,7 @@ xor_bits(XBits, YBits) ->
<<Y:Sz, _/binary>> = YBits,
<<(X bxor Y):Sz>>.
-%%
-%% irandom(N)
-%%
-%% Generate a N bits size random number
-%% note that the top most bit is always set
-%% to guarantee that the number is N bits
-%%
-irandom(Bits) ->
- irandom(Bits, 1, 0).
-
-%%
-%% irandom(N, Top, Bottom)
-%%
-%% Generate a N bits size random number
-%% Where Top = 0 - do not set top bit
-%% = 1 - set the most significant bit
-%% = 2 - set two most significant bits
-%% Bot = 0 - do not set the least signifcant bit
-%% Bot = 1 - set the least signifcant bit (i.e always odd)
-%%
-irandom(Bits, Top, Bottom) when is_integer(Top),
- 0 =< Top, Top =< 2 ->
- crypto:erlint(crypto:strong_rand_mpint(Bits, Top - 1, Bottom)).
-%%
%% random/1
%% Generate N random bytes
%%
diff --git a/lib/ssh/src/ssh_math.erl b/lib/ssh/src/ssh_math.erl
index 4aa385b18d..569c1cb58d 100644
--- a/lib/ssh/src/ssh_math.erl
+++ b/lib/ssh/src/ssh_math.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -23,109 +23,19 @@
-module(ssh_math).
--export([ilog2/1, ipow/3, invert/2, ipow2/3]).
+-export([ipow/3]).
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% INTEGER utils
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% number of bits (used) in a integer = isize(N) = |log2(N)|+1
-ilog2(N) ->
- ssh_bits:isize(N) - 1.
-
-
%% calculate A^B mod M
ipow(A, B, M) when M > 0, B >= 0 ->
- crypto:mod_exp(A, B, M).
-
-ipow2(A, B, M) when M > 0, B >= 0 ->
- if A == 1 ->
- 1;
- true ->
- ipow2(A, B, M, 1)
- end.
-
-ipow2(A, 1, M, Prod) ->
- (A*Prod) rem M;
-ipow2(_A, 0, _M, Prod) ->
- Prod;
-ipow2(A, B, M, Prod) ->
- B1 = B bsr 1,
- A1 = (A*A) rem M,
- if B - B1 == B1 ->
- ipow2(A1, B1, M, Prod);
- true ->
- ipow2(A1, B1, M, (A*Prod) rem M)
- end.
-
-%% %%
-%% %% Normal gcd
-%% %%
-%% gcd(R, Q) when abs(Q) < abs(R) -> gcd1(Q,R);
-%% gcd(R, Q) -> gcd1(R,Q).
-
-%% gcd1(0, Q) -> Q;
-%% gcd1(R, Q) ->
-%% gcd1(Q rem R, R).
-
-
-%% %%
-%% %% Least common multiple of (R,Q)
-%% %%
-%% lcm(0, _Q) -> 0;
-%% lcm(_R, 0) -> 0;
-%% lcm(R, Q) ->
-%% (Q div gcd(R, Q)) * R.
-
-%% %%
-%% %% Extended gcd gcd(R,Q) -> {G, {A,B}} such that G == R*A + Q*B
-%% %%
-%% %% Here we could have use for a bif divrem(Q, R) -> {Quote, Remainder}
-%% %%
-%% egcd(R,Q) when abs(Q) < abs(R) -> egcd1(Q,R,1,0,0,1);
-%% egcd(R,Q) -> egcd1(R,Q,0,1,1,0).
-
-%% egcd1(0,Q,_,_,Q1,Q2) -> {Q, {Q2,Q1}};
-%% egcd1(R,Q,R1,R2,Q1,Q2) ->
-%% D = Q div R,
-%% egcd1(Q rem R, R, Q1-D*R1, Q2-D*R2, R1, R2).
-
-%%
-%% Invert an element X mod P
-%% Calculated as {1, {A,B}} = egcd(X,P),
-%% 1 == P*A + X*B == X*B (mod P) i.e B is the inverse element
-%%
-%% X > 0, P > 0, X < P (P should be prime)
-%%
-invert(X,P) when X > 0, P > 0, X < P ->
- I = inv(X,P,1,0),
- if
- I < 0 -> P + I;
- true -> I
- end.
-
-inv(0,_,_,Q) -> Q;
-inv(X,P,R1,Q1) ->
- D = P div X,
- inv(P rem X, X, Q1 - D*R1, R1).
-
+ crypto:bytes_to_integer(crypto:mod_pow(A, B, M)).
-%% %%
-%% %% Integer square root
-%% %%
-%% isqrt(0) -> 0;
-%% isqrt(1) -> 1;
-%% isqrt(X) when X >= 0 ->
-%% R = X div 2,
-%% isqrt(X div R, R, X).
-%% isqrt(Q,R,X) when Q < R ->
-%% R1 = (R+Q) div 2,
-%% isqrt(X div R1, R1, X);
-%% isqrt(_, R, _) -> R.
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 98d59d01de..beaffdc025 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -792,14 +792,14 @@ encrypt(#ssh{encrypt = none} = Ssh, Data) ->
encrypt(#ssh{encrypt = '3des-cbc',
encrypt_keys = {K1,K2,K3},
encrypt_ctx = IV0} = Ssh, Data) ->
- Enc = crypto:des3_cbc_encrypt(K1,K2,K3,IV0,Data),
- IV = crypto:des_cbc_ivec(Enc),
+ Enc = crypto:block_encrypt(des3_cbc, [K1,K2,K3], IV0, Data),
+ IV = crypto:next_iv(des3_cbc, Enc),
{Ssh#ssh{encrypt_ctx = IV}, Enc};
encrypt(#ssh{encrypt = 'aes128-cbc',
encrypt_keys = K,
encrypt_ctx = IV0} = Ssh, Data) ->
- Enc = crypto:aes_cbc_128_encrypt(K,IV0,Data),
- IV = crypto:aes_cbc_ivec(Enc),
+ Enc = crypto:block_encrypt(aes_cbc128, K,IV0,Data),
+ IV = crypto:next_iv(aes_cbc, Enc),
{Ssh#ssh{encrypt_ctx = IV}, Enc}.
@@ -846,13 +846,13 @@ decrypt(#ssh{decrypt = none} = Ssh, Data) ->
decrypt(#ssh{decrypt = '3des-cbc', decrypt_keys = Keys,
decrypt_ctx = IV0} = Ssh, Data) ->
{K1, K2, K3} = Keys,
- Dec = crypto:des3_cbc_decrypt(K1,K2,K3,IV0,Data),
- IV = crypto:des_cbc_ivec(Data),
+ Dec = crypto:block_decrypt(des3_cbc, [K1,K2,K3], IV0, Data),
+ IV = crypto:next_iv(des3_cbc, Data),
{Ssh#ssh{decrypt_ctx = IV}, Dec};
decrypt(#ssh{decrypt = 'aes128-cbc', decrypt_keys = Key,
decrypt_ctx = IV0} = Ssh, Data) ->
- Dec = crypto:aes_cbc_128_decrypt(Key,IV0,Data),
- IV = crypto:aes_cbc_ivec(Data),
+ Dec = crypto:block_decrypt(aes_cbc128, Key,IV0,Data),
+ IV = crypto:next_iv(aes_cbc, Data),
{Ssh#ssh{decrypt_ctx = IV}, Dec}.
@@ -954,22 +954,22 @@ recv_mac_final(SSH) ->
mac(none, _ , _, _) ->
<<>>;
mac('hmac-sha1', Key, SeqNum, Data) ->
- crypto:sha_mac(Key, [<<?UINT32(SeqNum)>>, Data]);
+ crypto:hmac(sha, Key, [<<?UINT32(SeqNum)>>, Data]);
mac('hmac-sha1-96', Key, SeqNum, Data) ->
- crypto:sha_mac_96(Key, [<<?UINT32(SeqNum)>>, Data]);
+ crypto:hmac(sha, Key, [<<?UINT32(SeqNum)>>, Data], mac_digest_size('hmac-sha1-96'));
mac('hmac-md5', Key, SeqNum, Data) ->
- crypto:md5_mac(Key, [<<?UINT32(SeqNum)>>, Data]);
+ crypto:hmac(md5, Key, [<<?UINT32(SeqNum)>>, Data]);
mac('hmac-md5-96', Key, SeqNum, Data) ->
- crypto:md5_mac_96(Key, [<<?UINT32(SeqNum)>>, Data]).
+ crypto:hmac(md5, Key, [<<?UINT32(SeqNum)>>, Data], mac_digest_size('hmac-md5-96')).
%% return N hash bytes (HASH)
hash(SSH, Char, Bits) ->
HASH =
case SSH#ssh.kex of
'diffie-hellman-group1-sha1' ->
- fun(Data) -> crypto:sha(Data) end;
+ fun(Data) -> crypto:hash(sha, Data) end;
'diffie-hellman-group-exchange-sha1' ->
- fun(Data) -> crypto:sha(Data) end;
+ fun(Data) -> crypto:hash(sha, Data) end;
_ ->
exit({bad_algorithm,SSH#ssh.kex})
end,
@@ -998,7 +998,7 @@ kex_h(SSH, K_S, E, F, K) ->
K_S, E,F,K],
[string,string,binary,binary,binary,
mpint,mpint,mpint]),
- crypto:sha(L).
+ crypto:hash(sha,L).
kex_h(SSH, K_S, Min, NBits, Max, Prime, Gen, E, F, K) ->
@@ -1019,7 +1019,7 @@ kex_h(SSH, K_S, Min, NBits, Max, Prime, Gen, E, F, K) ->
K_S, Min, NBits, Max,
Prime, Gen, E,F,K], Ts)
end,
- crypto:sha(L).
+ crypto:hash(sha,L).
mac_key_size('hmac-sha1') -> 20*8;
mac_key_size('hmac-sha1-96') -> 20*8;
@@ -1045,10 +1045,9 @@ peer_name({Host, _}) ->
dh_group1() ->
{2, 16#FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF}.
-dh_gen_key(G, P, _Bits) ->
- Private = ssh_bits:irandom(ssh_bits:isize(P)-1, 1, 1),
- Public = ssh_math:ipow(G, Private, P),
- {Private,Public}.
+dh_gen_key(G, P, _) ->
+ {Public, Private} = crypto:generate_key(dh, [P, G]),
+ {crypto:bytes_to_integer(Private), crypto:bytes_to_integer(Public)}.
trim_tail(Str) ->
lists:reverse(trim_head(lists:reverse(Str))).
@@ -1058,3 +1057,5 @@ trim_head([$\t|Cs]) -> trim_head(Cs);
trim_head([$\n|Cs]) -> trim_head(Cs);
trim_head([$\r|Cs]) -> trim_head(Cs);
trim_head(Cs) -> Cs.
+
+
diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile
index d3ba76d34e..3b8145089e 100644
--- a/lib/ssl/src/Makefile
+++ b/lib/ssl/src/Makefile
@@ -66,7 +66,7 @@ MODULES= \
INTERNAL_HRL_FILES = \
ssl_alert.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_internal.hrl \
- ssl_record.hrl ssl_srp.hrl ssl_srp_primes.hrl
+ ssl_record.hrl ssl_srp.hrl
ERL_FILES= \
$(MODULES:%=%.erl) \
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index f52862729a..fb64a6652f 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -37,7 +37,6 @@
-include("ssl_record.hrl").
-include("ssl_cipher.hrl").
-include("ssl_handshake.hrl").
--include("ssl_srp_primes.hrl").
-include_lib("public_key/include/public_key.hrl").
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index dc413d6dfc..898b421dff 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -1024,30 +1024,32 @@ filter(DerCert, Ciphers) ->
%% Description: filter suites for algorithms
%%-------------------------------------------------------------------
filter_suites(Suites = [{_,_,_}|_]) ->
- Algos = crypto:algorithms(),
+ Algos = crypto:supports(),
lists:filter(fun({KeyExchange, Cipher, Hash}) ->
- is_acceptable_keyexchange(KeyExchange, Algos) andalso
- is_acceptable_cipher(Cipher, Algos) andalso
- is_acceptable_hash(Hash, Algos)
+ is_acceptable_keyexchange(KeyExchange, proplists:get_value(public_keys, Algos)) andalso
+ is_acceptable_cipher(Cipher, proplists:get_value(ciphers, Algos)) andalso
+ is_acceptable_hash(Hash, proplists:get_value(hashs, Algos))
end, Suites);
filter_suites(Suites = [{_,_,_,_}|_]) ->
- Algos = crypto:algorithms(),
+ Algos = crypto:supports(),
+ Hashs = proplists:get_value(hashs, Algos),
lists:filter(fun({KeyExchange, Cipher, Hash, Prf}) ->
- is_acceptable_keyexchange(KeyExchange, Algos) andalso
- is_acceptable_cipher(Cipher, Algos) andalso
- is_acceptable_hash(Hash, Algos) andalso
- is_acceptable_prf(Prf, Algos)
+ is_acceptable_keyexchange(KeyExchange, proplists:get_value(public_keys, Algos)) andalso
+ is_acceptable_cipher(Cipher, proplists:get_value(ciphers, Algos)) andalso
+ is_acceptable_hash(Hash, Hashs) andalso
+ is_acceptable_prf(Prf, Hashs)
end, Suites);
filter_suites(Suites) ->
- Algos = crypto:algorithms(),
+ Algos = crypto:supports(),
+ Hashs = proplists:get_value(hashs, Algos),
lists:filter(fun(Suite) ->
{KeyExchange, Cipher, Hash, Prf} = ssl_cipher:suite_definition(Suite),
- is_acceptable_keyexchange(KeyExchange, Algos) andalso
- is_acceptable_cipher(Cipher, Algos) andalso
- is_acceptable_hash(Hash, Algos) andalso
- is_acceptable_prf(Prf, Algos)
+ is_acceptable_keyexchange(KeyExchange, proplists:get_value(public_keys, Algos)) andalso
+ is_acceptable_cipher(Cipher, proplists:get_value(ciphers, Algos)) andalso
+ is_acceptable_hash(Hash, Hashs) andalso
+ is_acceptable_prf(Prf, Hashs)
end, Suites).
is_acceptable_keyexchange(KeyExchange, Algos)
@@ -1056,7 +1058,7 @@ is_acceptable_keyexchange(KeyExchange, Algos)
KeyExchange == ecdh_rsa;
KeyExchange == ecdhe_rsa;
KeyExchange == ecdh_anon ->
- proplists:get_bool(ec, Algos);
+ proplists:get_bool(ecdh, Algos);
is_acceptable_keyexchange(_, _) ->
true.
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 54eed03d3c..de9260fd8c 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -35,7 +35,6 @@
-include("ssl_cipher.hrl").
-include("ssl_internal.hrl").
-include("ssl_srp.hrl").
--include("ssl_srp_primes.hrl").
-include_lib("public_key/include/public_key.hrl").
%% Internal application API
@@ -2216,7 +2215,7 @@ client_srp_master_secret(Generator, Prime, Salt, ServerPub, ClientKeys,
case ssl_srp_primes:check_srp_params(Generator, Prime) of
ok ->
{Username, Password} = SslOpts#ssl_options.srp_identity,
- DerivedKey = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
+ DerivedKey = crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, Password])]),
case crypto:compute_key(srp, ServerPub, ClientKeys, {user, [DerivedKey, Prime, Generator, '6a']}) of
error ->
?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index e358cbe9bb..24ea86311f 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -840,7 +840,8 @@ select_next_protocol(Protocols, NextProtocolSelector) ->
end.
default_ecc_extensions(Version) ->
- case proplists:get_bool(ec, crypto:algorithms()) of
+ CryptoSupport = proplists:get_value(public_keys, crypto:supports()),
+ case proplists:get_bool(ecdh, CryptoSupport) of
true ->
EcPointFormats = #ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]},
EllipticCurves = #elliptic_curves{elliptic_curve_list = ssl_tls1:ecc_curves(Version)},
@@ -850,7 +851,8 @@ default_ecc_extensions(Version) ->
end.
handle_ecc_extensions(Version, EcPointFormats0, EllipticCurves0) ->
- case proplists:get_bool(ec, crypto:algorithms()) of
+ CryptoSupport = proplists:get_value(public_keys, crypto:supports()),
+ case proplists:get_bool(ecdh, CryptoSupport) of
true ->
EcPointFormats1 = handle_ecc_point_fmt_extension(EcPointFormats0),
EllipticCurves1 = handle_ecc_curves_extension(Version, EllipticCurves0),
@@ -1767,7 +1769,8 @@ default_hash_signs() ->
?TLSEXT_SIGALG(sha),
?TLSEXT_SIGALG_DSA(sha),
?TLSEXT_SIGALG_RSA(md5)],
- HasECC = proplists:get_bool(ec, crypto:algorithms()),
+ CryptoSupport = proplists:get_value(public_keys, crypto:supports()),
+ HasECC = proplists:get_bool(ecdsa, CryptoSupport),
#hash_sign_algos{hash_sign_algos =
lists:filter(fun({_, ecdsa}) -> HasECC;
(_) -> true end, HashSigns)}.
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index 50b1b2cda9..2a3356d60f 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -712,4 +712,5 @@ mac_hash({3, N} = Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment)
Length, Fragment).
sufficient_tlsv1_2_crypto_support() ->
- proplists:get_bool(sha256, crypto:algorithms()).
+ CryptoSupport = crypto:supports(),
+ proplists:get_bool(sha256, proplists:get_value(hashs, CryptoSupport)).
diff --git a/lib/ssl/src/ssl_srp_primes.hrl b/lib/ssl/src/ssl_srp_primes.hrl
deleted file mode 100644
index 4bd534efbf..0000000000
--- a/lib/ssl/src/ssl_srp_primes.hrl
+++ /dev/null
@@ -1 +0,0 @@
--type srp_parameters() :: srp_1024 | srp_1536 | srp_2048 | srp_3072 | srp_4096 | srp_6144 | srp_8192.
diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl
index f8fd9efd07..8ab66d0627 100644
--- a/lib/ssl/src/ssl_tls1.erl
+++ b/lib/ssl/src/ssl_tls1.erl
@@ -184,6 +184,22 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor},
-spec suites(1|2|3) -> [cipher_suite()].
suites(Minor) when Minor == 1; Minor == 2->
+ case sufficent_ec_support() of
+ true ->
+ all_suites(Minor);
+ false ->
+ no_ec_suites(Minor)
+ end;
+
+suites(Minor) when Minor == 3 ->
+ case sufficent_ec_support() of
+ true ->
+ all_suites(3) ++ all_suites(2);
+ false ->
+ no_ec_suites(3) ++ no_ec_suites(2)
+ end.
+
+all_suites(Minor) when Minor == 1; Minor == 2->
[
?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
@@ -208,7 +224,7 @@ suites(Minor) when Minor == 1; Minor == 2->
?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
?TLS_RSA_WITH_AES_128_CBC_SHA,
- %%?TLS_RSA_WITH_IDEA_CBC_SHA,
+
?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
?TLS_ECDHE_RSA_WITH_RC4_128_SHA,
?TLS_RSA_WITH_RC4_128_SHA,
@@ -216,31 +232,55 @@ suites(Minor) when Minor == 1; Minor == 2->
?TLS_DHE_RSA_WITH_DES_CBC_SHA,
?TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
?TLS_ECDH_RSA_WITH_RC4_128_SHA,
+
?TLS_RSA_WITH_DES_CBC_SHA
- ];
-
-suites(Minor) when Minor == 3 ->
+ ];
+all_suites(3) ->
[
?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
-
+
?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
?TLS_RSA_WITH_AES_256_CBC_SHA256,
-
+
?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+
+ ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
+ ?TLS_RSA_WITH_AES_128_CBC_SHA256
+ ].
+no_ec_suites(Minor) when Minor == 1; Minor == 2->
+ [
+ ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+ ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+ ?TLS_RSA_WITH_AES_256_CBC_SHA,
+ ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+ ?TLS_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_RSA_WITH_RC4_128_SHA,
+ ?TLS_RSA_WITH_RC4_128_MD5,
+ ?TLS_DHE_RSA_WITH_DES_CBC_SHA,
+ ?TLS_RSA_WITH_DES_CBC_SHA
+ ];
+no_ec_suites(3) ->
+ [
+ ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
+ ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
+ ?TLS_RSA_WITH_AES_256_CBC_SHA256,
?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
?TLS_RSA_WITH_AES_128_CBC_SHA256
- %% ?TLS_DH_anon_WITH_AES_128_CBC_SHA256,
- %% ?TLS_DH_anon_WITH_AES_256_CBC_SHA256
- ] ++ suites(2).
+ ].
%%--------------------------------------------------------------------
%%% Internal functions
@@ -386,3 +426,7 @@ enum_to_oid(22) -> ?secp256k1;
enum_to_oid(23) -> ?secp256r1;
enum_to_oid(24) -> ?secp384r1;
enum_to_oid(25) -> ?secp521r1.
+
+sufficent_ec_support() ->
+ CryptoSupport = crypto:supports(),
+ proplists:get_bool(ecdh, proplists:get_value(public_keys, CryptoSupport)).
diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl
index 723ccf4496..22dc951ac1 100644
--- a/lib/ssl/test/erl_make_certs.erl
+++ b/lib/ssl/test/erl_make_certs.erl
@@ -391,35 +391,32 @@ gen_dsa2(LSize, NSize) ->
error ->
gen_dsa2(LSize, NSize);
P ->
- G = crypto:mod_exp(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q.
+ G = crypto:mod_pow(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q.
%% such that This may be done by setting g = h^(p-1)/q mod p, commonly h=2 is used.
X = prime(20), %% Choose x by some random method, where 0 < x < q.
- Y = crypto:mod_exp(G, X, P), %% Calculate y = g^x mod p.
+ Y = crypto:mod_pow(G, X, P), %% Calculate y = g^x mod p.
- #'DSAPrivateKey'{version=0, p=P, q=Q, g=G, y=Y, x=X}
+ #'DSAPrivateKey'{version=0, p = P, q = Q,
+ g = crypto:bytes_to_integer(G), y = crypto:bytes_to_integer(Y), x = X}
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% EC key generation (OBS: for testing only)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-int2list(I) ->
- L = (length(integer_to_list(I, 16)) + 1) div 2,
- binary_to_list(<<I:(L*8)>>).
-
gen_ec2(CurveId) ->
- {PrivKey, PubKey} = crypto:generate_key(ecdh, CurveId),
+ {PubKey, PrivKey} = crypto:generate_key(ecdh, CurveId),
#'ECPrivateKey'{version = 1,
- privateKey = int2list(PrivKey),
+ privateKey = binary_to_list(PrivKey),
parameters = {namedCurve, pubkey_cert_records:namedCurves(CurveId)},
publicKey = {0, PubKey}}.
%% See fips_186-3.pdf
dsa_search(T, P0, Q, Iter) when Iter > 0 ->
P = 2*T*Q*P0 + 1,
- case is_prime(crypto:mpint(P), 50) of
+ case is_prime(P, 50) of
true -> P;
false -> dsa_search(T+1, P0, Q, Iter-1)
end;
@@ -430,38 +427,40 @@ dsa_search(_,_,_,_) ->
%%%%%%% Crypto Math %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
prime(ByteSize) ->
Rand = odd_rand(ByteSize),
- crypto:erlint(prime_odd(Rand, 0)).
+ prime_odd(Rand, 0).
prime_odd(Rand, N) ->
case is_prime(Rand, 50) of
true ->
Rand;
false ->
- NotPrime = crypto:erlint(Rand),
- prime_odd(crypto:mpint(NotPrime+2), N+1)
+ prime_odd(Rand+2, N+1)
end.
%% see http://en.wikipedia.org/wiki/Fermat_primality_test
is_prime(_, 0) -> true;
is_prime(Candidate, Test) ->
- CoPrime = odd_rand(<<0,0,0,4, 10000:32>>, Candidate),
- case crypto:mod_exp(CoPrime, Candidate, Candidate) of
- CoPrime -> is_prime(Candidate, Test-1);
- _ -> false
- end.
+ CoPrime = odd_rand(10000, Candidate),
+ Result = crypto:mod_pow(CoPrime, Candidate, Candidate) ,
+ is_prime(CoPrime, crypto:bytes_to_integer(Result), Candidate, Test).
+
+is_prime(CoPrime, CoPrime, Candidate, Test) ->
+ is_prime(Candidate, Test-1);
+is_prime(_,_,_,_) ->
+ false.
odd_rand(Size) ->
Min = 1 bsl (Size*8-1),
Max = (1 bsl (Size*8))-1,
- odd_rand(crypto:mpint(Min), crypto:mpint(Max)).
+ odd_rand(Min, Max).
odd_rand(Min,Max) ->
- Rand = <<Sz:32, _/binary>> = crypto:rand_uniform(Min,Max),
- BitSkip = (Sz+4)*8-1,
- case Rand of
- Odd = <<_:BitSkip, 1:1>> -> Odd;
- Even = <<_:BitSkip, 0:1>> ->
- crypto:mpint(crypto:erlint(Even)+1)
+ Rand = crypto:rand_uniform(Min,Max),
+ case Rand rem 2 of
+ 0 ->
+ Rand + 1;
+ _ ->
+ Rand
end.
extended_gcd(A, B) ->
@@ -480,3 +479,4 @@ pem_to_der(File) ->
der_to_pem(File, Entries) ->
PemBin = public_key:pem_encode(Entries),
file:write_file(File, PemBin).
+
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 165a8a5fcc..c4a6cf1407 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -1549,7 +1549,7 @@ ciphers_rsa_signed_certs(Config) when is_list(Config) ->
Version =
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
- Ciphers = ssl_test_lib:rsa_suites(erlang),
+ Ciphers = ssl_test_lib:rsa_suites(crypto),
ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
run_suites(Ciphers, Version, Config, rsa).
%%-------------------------------------------------------------------
@@ -1559,7 +1559,7 @@ ciphers_rsa_signed_certs_openssl_names() ->
ciphers_rsa_signed_certs_openssl_names(Config) when is_list(Config) ->
Version =
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
- Ciphers = ssl_test_lib:openssl_rsa_suites(),
+ Ciphers = ssl_test_lib:openssl_rsa_suites(crypto),
ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]),
run_suites(Ciphers, Version, Config, rsa).
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index a8ff5187b6..34c52b10b3 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -285,7 +285,7 @@ user_lookup(psk, _Identity, UserState) ->
{ok, UserState};
user_lookup(srp, Username, _UserState) ->
Salt = ssl:random_bytes(16),
- UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, <<"secret">>])]),
+ UserPassHash = crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, <<"secret">>])]),
{ok, {srp_1024, Salt, UserPassHash}}.
cert_options(Config) ->
@@ -405,7 +405,8 @@ make_dsa_cert(Config) ->
| Config].
make_ecdsa_cert(Config) ->
- case proplists:get_bool(ec, crypto:algorithms()) of
+ CryptoSupport = crypto:supports(),
+ case proplists:get_bool(ecdsa, proplists:get_value(public_keys, CryptoSupport)) of
true ->
{ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, ec, ec, ""),
{ClientCaCertFile, ClientCertFile, ClientKeyFile} = make_cert_files("client", Config, ec, ec, ""),
@@ -429,7 +430,8 @@ make_ecdsa_cert(Config) ->
%% This key exchange algorithm is the same as ECDH_ECDSA except that the
%% server's certificate MUST be signed with RSA rather than ECDSA.
make_ecdh_rsa_cert(Config) ->
- case proplists:get_bool(ec, crypto:algorithms()) of
+ CryptoSupport = crypto:supports(),
+ case proplists:get_bool(ecdh, proplists:get_value(public_keys, CryptoSupport)) of
true ->
{ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, rsa, ec, "rsa_"),
{ClientCaCertFile, ClientCertFile, ClientKeyFile} = make_cert_files("client", Config, rsa, ec, "rsa_"),
@@ -754,14 +756,20 @@ ecdh_rsa_suites() ->
end,
ssl:cipher_suites()).
-openssl_rsa_suites() ->
+openssl_rsa_suites(CounterPart) ->
Ciphers = ssl:cipher_suites(openssl),
+ Names = case is_sane_ecc(CounterPart) of
+ true ->
+ "DSS | ECDSA";
+ false ->
+ "DSS | ECDHE | ECDH"
+ end,
lists:filter(fun(Str) ->
- case re:run(Str,"DSS|ECDH-RSA|ECDSA",[]) of
+ case re:run(Str, Names,[]) of
nomatch ->
- true;
+ false;
_ ->
- false
+ true
end
end, Ciphers).
@@ -939,9 +947,11 @@ init_tls_version(Version) ->
ssl:start().
sufficient_crypto_support('tlsv1.2') ->
- proplists:get_bool(sha256, crypto:algorithms());
+ CryptoSupport = crypto:supports(),
+ proplists:get_bool(sha256, proplists:get_value(hashs, CryptoSupport));
sufficient_crypto_support(ciphers_ec) ->
- proplists:get_bool(ec, crypto:algorithms());
+ CryptoSupport = crypto:supports(),
+ proplists:get_bool(ecdh, proplists:get_value(public_keys, CryptoSupport));
sufficient_crypto_support(_) ->
true.
@@ -990,6 +1000,16 @@ is_sane_ecc(openssl) ->
_ ->
true
end;
+is_sane_ecc(crypto) ->
+ [{_,_, Bin}] = crypto:info_lib(),
+ case binary_to_list(Bin) of
+ "OpenSSL 0.9.8" ++ _ -> % Does not support ECC
+ false;
+ "OpenSSL 0.9.7" ++ _ -> % Does not support ECC
+ false;
+ _ ->
+ true
+ end;
is_sane_ecc(_) ->
true.
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index 075b4b1ec4..7f91865a86 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -106,9 +106,9 @@ init_per_suite(Config0) ->
?config(priv_dir, Config0))),
ct:log("Make certs ~p~n", [Result]),
Config1 = ssl_test_lib:make_dsa_cert(Config0),
- Config = ssl_test_lib:cert_options(Config1),
- NewConfig = [{watchdog, Dog} | Config],
- ssl_test_lib:cipher_restriction(NewConfig)
+ Config2 = ssl_test_lib:cert_options(Config1),
+ Config = [{watchdog, Dog} | Config2],
+ ssl_test_lib:cipher_restriction(Config)
catch _:_ ->
{skip, "Crypto did not start"}
end
diff --git a/lib/stdlib/doc/src/c.xml b/lib/stdlib/doc/src/c.xml
index ddae388a1b..9cd4581a89 100644
--- a/lib/stdlib/doc/src/c.xml
+++ b/lib/stdlib/doc/src/c.xml
@@ -140,9 +140,9 @@ compile:file(<anno>File</anno>, <anno>Options</anno> ++ [report_errors, report_w
</func>
<func>
<name name="ls" arity="1"/>
- <fsummary>List files in a directory</fsummary>
+ <fsummary>List files in a directory or a single file</fsummary>
<desc>
- <p>Lists files in directory <c><anno>Dir</anno></c>.</p>
+ <p>Lists files in directory <c><anno>Dir</anno></c> or, if Dir is a file, only list it.</p>
</desc>
</func>
<func>
diff --git a/lib/stdlib/doc/src/erl_eval.xml b/lib/stdlib/doc/src/erl_eval.xml
index d0622594d9..24940f8396 100644
--- a/lib/stdlib/doc/src/erl_eval.xml
+++ b/lib/stdlib/doc/src/erl_eval.xml
@@ -288,10 +288,7 @@ Func(FuncSpec, Arguments) </code>
<section>
<title>Bugs</title>
- <p>The evaluator is not complete. <c>receive</c> cannot be
- handled properly.
- </p>
- <p>Any undocumented functions in <c>erl_eval</c> should not be used.</p>
+ <p>Undocumented functions in <c>erl_eval</c> should not be used.</p>
</section>
</erlref>
diff --git a/lib/stdlib/src/beam_lib.erl b/lib/stdlib/src/beam_lib.erl
index fe7e0f8e60..121f9febed 100644
--- a/lib/stdlib/src/beam_lib.erl
+++ b/lib/stdlib/src/beam_lib.erl
@@ -300,12 +300,12 @@ clear_crypto_key_fun() ->
call_crypto_server(clear_crypto_key_fun).
-spec make_crypto_key(mode(), string()) ->
- {binary(), binary(), binary(), binary()}.
+ {mode(), [binary()], binary(), integer()}.
-make_crypto_key(des3_cbc, String) ->
+make_crypto_key(des3_cbc=Type, String) ->
<<K1:8/binary,K2:8/binary>> = First = erlang:md5(String),
<<K3:8/binary,IVec:8/binary>> = erlang:md5([First|reverse(String)]),
- {K1,K2,K3,IVec}.
+ {Type,[K1,K2,K3],IVec,8}.
%%
%% Local functions
@@ -864,20 +864,20 @@ mandatory_chunks() ->
-define(CRYPTO_KEY_SERVER, beam_lib__crypto_key_server).
-decrypt_abst(Mode, Module, File, Id, AtomTable, Bin) ->
+decrypt_abst(Type, Module, File, Id, AtomTable, Bin) ->
try
- KeyString = get_crypto_key({debug_info, Mode, Module, File}),
- Key = make_crypto_key(des3_cbc, KeyString),
- Term = decrypt_abst_1(Mode, Key, Bin),
+ KeyString = get_crypto_key({debug_info, Type, Module, File}),
+ Key = make_crypto_key(Type, KeyString),
+ Term = decrypt_abst_1(Key, Bin),
{AtomTable, {Id, Term}}
catch
_:_ ->
error({key_missing_or_invalid, File, Id})
end.
-decrypt_abst_1(des3_cbc, {K1, K2, K3, IVec}, Bin) ->
+decrypt_abst_1({Type,Key,IVec,_BlockSize}, Bin) ->
ok = start_crypto(),
- NewBin = crypto:des3_cbc_decrypt(K1, K2, K3, IVec, Bin),
+ NewBin = crypto:block_decrypt(Type, Key, IVec, Bin),
binary_to_term(NewBin).
start_crypto() ->
diff --git a/lib/stdlib/src/c.erl b/lib/stdlib/src/c.erl
index 91d317489c..6e96e3d564 100644
--- a/lib/stdlib/src/c.erl
+++ b/lib/stdlib/src/c.erl
@@ -713,8 +713,10 @@ ls(Dir) ->
case file:list_dir(Dir) of
{ok, Entries} ->
ls_print(sort(Entries));
- {error,_E} ->
- format("Invalid directory\n")
+ {error, enotdir} ->
+ ls_print([Dir]);
+ {error, Error} ->
+ format("~s\n", [file:format_error(Error)])
end.
ls_print([]) -> ok;
diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl
index 0b57af1b6d..73b8da335a 100644
--- a/lib/stdlib/src/erl_eval.erl
+++ b/lib/stdlib/src/erl_eval.erl
@@ -245,10 +245,10 @@ expr({'case',_,E,Cs}, Bs0, Lf, Ef, RBs) ->
expr({'try',_,B,Cases,Catches,AB}, Bs, Lf, Ef, RBs) ->
try_clauses(B, Cases, Catches, AB, Bs, Lf, Ef, RBs);
expr({'receive',_,Cs}, Bs, Lf, Ef, RBs) ->
- receive_clauses(Cs, Bs, Lf, Ef, [], RBs);
+ receive_clauses(Cs, Bs, Lf, Ef, RBs);
expr({'receive',_, Cs, E, TB}, Bs0, Lf, Ef, RBs) ->
{value,T,Bs} = expr(E, Bs0, Lf, Ef, none),
- receive_clauses(T, Cs, {TB,Bs}, Bs0, Lf, Ef, [], RBs);
+ receive_clauses(T, Cs, {TB,Bs}, Bs0, Lf, Ef, RBs);
expr({'fun',_Line,{function,Mod0,Name0,Arity0}}, Bs0, Lf, Ef, RBs) ->
{[Mod,Name,Arity],Bs} = expr_list([Mod0,Name0,Arity0], Bs0, Lf, Ef),
F = erlang:make_fun(Mod, Name, Arity),
@@ -807,66 +807,24 @@ case_clauses(Val, Cs, Bs, Lf, Ef, RBs) ->
end.
%%
-%% receive_clauses(Clauses, Bindings, LocalFuncHnd,ExtFuncHnd, Messages, RBs)
+%% receive_clauses(Clauses, Bindings, LocalFuncHnd,ExtFuncHnd, RBs)
%%
-receive_clauses(Cs, Bs, Lf, Ef, Ms, RBs) ->
- receive
- Val ->
- case match_clause(Cs, [Val], Bs, Lf, Ef) of
- {B, Bs1} ->
- merge_queue(Ms),
- exprs(B, Bs1, Lf, Ef, RBs);
- nomatch ->
- receive_clauses(Cs, Bs, Lf, Ef, [Val|Ms], RBs)
- end
- end.
+receive_clauses(Cs, Bs, Lf, Ef, RBs) ->
+ receive_clauses(infinity, Cs, unused, Bs, Lf, Ef, RBs).
%%
%% receive_clauses(TimeOut, Clauses, TimeoutBody, Bindings,
%% ExternalFuncHandler, LocalFuncHandler, RBs)
%%
-receive_clauses(T, Cs, TB, Bs, Lf, Ef, Ms, RBs) ->
- {_,_} = statistics(runtime),
- receive
- Val ->
- case match_clause(Cs, [Val], Bs, Lf, Ef) of
- {B, Bs1} ->
- merge_queue(Ms),
- exprs(B, Bs1, Lf, Ef, RBs);
- nomatch ->
- {_,T1} = statistics(runtime),
- if
- T =:= infinity ->
- receive_clauses(T, Cs, TB,Bs,Lf,Ef,[Val|Ms],RBs);
- T-T1 =< 0 ->
- receive_clauses(0, Cs, TB,Bs,Lf,Ef,[Val|Ms],RBs);
- true ->
- receive_clauses(T-T1, Cs,TB,Bs,Lf,Ef,[Val|Ms],RBs)
- end
- end
- after T ->
- merge_queue(Ms),
+receive_clauses(T, Cs, TB, Bs, Lf, Ef, RBs) ->
+ F = fun (M) -> match_clause(Cs, [M], Bs, Lf, Ef) end,
+ case prim_eval:'receive'(F, T) of
+ {B, Bs1} ->
+ exprs(B, Bs1, Lf, Ef, RBs);
+ timeout ->
{B, Bs1} = TB,
exprs(B, Bs1, Lf, Ef, RBs)
end.
-merge_queue([]) ->
- true;
-merge_queue(Ms) ->
- send_all(recv_all(Ms), self()).
-
-recv_all(Xs) ->
- receive
- X -> recv_all([X|Xs])
- after 0 ->
- reverse(Xs)
- end.
-
-send_all([X|Xs], Self) ->
- Self ! X,
- send_all(Xs, Self);
-send_all([], _) -> true.
-
-
%% match_clause -> {Body, Bindings} or nomatch
-spec(match_clause(Clauses, ValueList, Bindings, LocalFunctionHandler) ->
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index f2849e50ec..cebc9c91bd 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -75,18 +75,18 @@ obsolete_1(crypto, md5, 1) ->
obsolete_1(crypto, sha, 1) ->
{deprecated, {crypto, hash, 2}};
-obsolete_1(crypto, md4_init, 1) ->
- {deprecated, {crypto, hash_init, 2}};
-obsolete_1(crypto, md5_init, 1) ->
- {deprecated, {crypto, hash_init, 2}};
-obsolete_1(crypto, sha_init, 1) ->
- {deprecated, {crypto, hash_init, 2}};
+obsolete_1(crypto, md4_init, 0) ->
+ {deprecated, {crypto, hash_init, 1}};
+obsolete_1(crypto, md5_init, 0) ->
+ {deprecated, {crypto, hash_init, 1}};
+obsolete_1(crypto, sha_init, 0) ->
+ {deprecated, {crypto, hash_init, 1}};
obsolete_1(crypto, md4_update, 2) ->
{deprecated, {crypto, hash_update, 3}};
obsolete_1(crypto, md5_update, 2) ->
{deprecated, {crypto, hash_update, 3}};
-obsolete_1(crypto, sah_update, 2) ->
+obsolete_1(crypto, sha_update, 2) ->
{deprecated, {crypto, hash_update, 3}};
obsolete_1(crypto, md4_final, 1) ->
@@ -100,16 +100,22 @@ obsolete_1(crypto, md5_mac, 2) ->
{deprecated, {crypto, hmac, 3}};
obsolete_1(crypto, sha_mac, 2) ->
{deprecated, {crypto, hmac, 3}};
+obsolete_1(crypto, sha_mac, 3) ->
+ {deprecated, {crypto, hmac, 4}};
obsolete_1(crypto, sha_mac_96, 2) ->
{deprecated, {crypto, hmac_n, 3}};
obsolete_1(crypto, md5_mac_96, 2) ->
{deprecated, {crypto, hmac_n, 3}};
+obsolete_1(crypto, rsa_sign, 2) ->
+ {deprecated, {crypto, sign, 4}};
obsolete_1(crypto, rsa_sign, 3) ->
{deprecated, {crypto, sign, 4}};
obsolete_1(crypto, rsa_verify, 3) ->
- {deprecated, {crypto, verify, 4}};
+ {deprecated, {crypto, verify, 5}};
+obsolete_1(crypto, rsa_verify, 4) ->
+ {deprecated, {crypto, verify, 5}};
obsolete_1(crypto, dss_sign, 2) ->
{deprecated, {crypto, sign, 4}};
@@ -135,8 +141,8 @@ obsolete_1(crypto, des_cbc_encrypt, 3) ->
{deprecated, {crypto, block_encrypt, 4}};
obsolete_1(crypto, des3_cbc_encrypt, 5) ->
{deprecated, {crypto, block_encrypt, 4}};
-obsolete_1(crypto, des_ecb_encrypt, 3) ->
- {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des_ecb_encrypt, 2) ->
+ {deprecated, {crypto, block_encrypt, 3}};
obsolete_1(crypto, des_ede3_cbc_encrypt, 5) ->
{deprecated, {crypto, block_encrypt, 4}};
obsolete_1(crypto, des_cfb_encrypt, 3) ->
@@ -153,6 +159,8 @@ obsolete_1(crypto, blowfish_ofb64_encrypt, 3) ->
{deprecated, {crypto, block_encrypt, 4}};
obsolete_1(crypto, aes_cfb_128_encrypt, 3) ->
{deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, aes_cbc_128_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
obsolete_1(crypto, aes_cbc_256_encrypt, 3) ->
{deprecated, {crypto, block_encrypt, 4}};
obsolete_1(crypto,rc2_cbc_encrypt, 3) ->
@@ -164,8 +172,8 @@ obsolete_1(crypto, des_cbc_decrypt, 3) ->
{deprecated, {crypto, block_decrypt, 4}};
obsolete_1(crypto, des3_cbc_decrypt, 5) ->
{deprecated, {crypto, block_decrypt, 4}};
-obsolete_1(crypto, des_ecb_decrypt, 3) ->
- {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des_ecb_decrypt, 2) ->
+ {deprecated, {crypto, block_decrypt, 3}};
obsolete_1(crypto, des_ede3_cbc_decrypt, 5) ->
{deprecated, {crypto, block_decrypt, 4}};
obsolete_1(crypto, des_cfb_decrypt, 3) ->
@@ -182,6 +190,8 @@ obsolete_1(crypto, blowfish_ofb64_decrypt, 3) ->
{deprecated, {crypto, block_decrypt, 4}};
obsolete_1(crypto, aes_cfb_128_decrypt, 3) ->
{deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, aes_cbc_128_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
obsolete_1(crypto, aes_cbc_256_decrypt, 3) ->
{deprecated, {crypto, block_decrypt, 4}};
obsolete_1(crypto,rc2_cbc_decrypt, 3) ->
@@ -189,16 +199,50 @@ obsolete_1(crypto,rc2_cbc_decrypt, 3) ->
obsolete_1(crypto,rc2_40_cbc_decrypt, 3) ->
{deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, aes_ctr_stream_decrypt, 2) ->
+ {deprecated, {crypto, stream_decrypt, 2}};
+obsolete_1(crypto, aes_ctr_stream_encrypt, 2) ->
+ {deprecated, {crypto, stream_encrypt, 2}};
+obsolete_1(crypto, aes_ctr_decrypt, 3) ->
+ {deprecated, {crypto, stream_decrypt, 2}};
+obsolete_1(crypto, aes_ctr_encrypt, 3) ->
+ {deprecated, {crypto, stream_encrypt, 2}};
+obsolete_1(crypto, rc4_encrypt, 2) ->
+ {deprecated, {crypto, stream_encrypt, 2}};
+obsolete_1(crypto, rc4_encrypt_with_state, 2) ->
+ {deprecated, {crypto, stream_encrypt, 2}};
+obsolete_1(crypto, aes_ctr_stream_init, 2) ->
+ {deprecated, {crypto, stream_init, 3}};
+obsolete_1(crypto, rc4_set_key, 1) ->
+ {deprecated, {crypto, stream_init, 2}};
+
+obsolete_1(crypto, rsa_private_decrypt, 3) ->
+ {deprecated, {crypto, private_decrypt, 4}};
+obsolete_1(crypto, rsa_public_decrypt, 3) ->
+ {deprecated, {crypto, public_decrypt, 4}};
+obsolete_1(crypto, rsa_private_encrypt, 3) ->
+ {deprecated, {crypto, private_encrypt, 4}};
+obsolete_1(crypto, rsa_public_encrypt, 3) ->
+ {deprecated, {crypto, public_encrypt, 4}};
+
+obsolete_1(crypto, des_cfb_ivec, 2) ->
+ {deprecated, {crypto, next_iv, 3}};
+obsolete_1(crypto,des_cbc_ivec, 1) ->
+ {deprecated, {crypto, next_iv, 2}};
+obsolete_1(crypto, aes_cbc_ivec, 1) ->
+ {deprecated, {crypto, next_iv, 2}};
+
obsolete_1(crypto,info, 0) ->
{deprecated, {crypto, module_info, 0}};
obsolete_1(crypto, strong_rand_mpint, 3) ->
{deprecated, "needed only by deprecated functions"};
-obsolete_1(crypto, erlint, 3) ->
+obsolete_1(crypto, erlint, 1) ->
{deprecated, "needed only by deprecated functions"};
-obsolete_1(crypto, mpint, 3) ->
+obsolete_1(crypto, mpint, 1) ->
{deprecated, "needed only by deprecated functions"};
+
%% *** SNMP ***
obsolete_1(snmp, N, A) ->
@@ -206,10 +250,12 @@ obsolete_1(snmp, N, A) ->
false ->
no;
true ->
- {deprecated,"Deprecated; use snmpa:"++atom_to_list(N)++"/"++
+ {deprecated, "Deprecated (will be removed in R17B); use snmpa:"++atom_to_list(N)++"/"++
integer_to_list(A)++" instead"}
end;
+obsolete_1(snmpa, old_info_format, 1) ->
+ {deprecated, "Deprecated; (will be removed in R17B); use \"new\" format instead"};
obsolete_1(snmpm, agent_info, 3) ->
{removed, {snmpm, agent_info, 2}, "R16B"};
obsolete_1(snmpm, update_agent_info, 5) ->
diff --git a/lib/stdlib/test/c_SUITE.erl b/lib/stdlib/test/c_SUITE.erl
index 25281365be..8c55b616b9 100644
--- a/lib/stdlib/test/c_SUITE.erl
+++ b/lib/stdlib/test/c_SUITE.erl
@@ -20,7 +20,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
-export([c_1/1, c_2/1, c_3/1, c_4/1, nc_1/1, nc_2/1, nc_3/1, nc_4/1,
- memory/1]).
+ ls/1, memory/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -29,7 +29,7 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [c_1, c_2, c_3, c_4, nc_1, nc_2, nc_3, nc_4, memory].
+ [c_1, c_2, c_3, c_4, nc_1, nc_2, nc_3, nc_4, ls, memory].
groups() ->
[].
@@ -147,6 +147,13 @@ nc_4(Config) when is_list(Config) ->
?line Result = nc(R,[{outdir,W}]),
?line {ok, m} = Result.
+ls(Config) when is_list(Config) ->
+ Directory = ?config(data_dir, Config),
+ ok = c:ls(Directory),
+ File = filename:join(Directory, "m.erl"),
+ ok = c:ls(File),
+ ok = c:ls("no_such_file").
+
memory(doc) ->
["Checks that c:memory/[0,1] returns consistent results."];
memory(suite) ->
diff --git a/lib/test_server/src/ts_install_cth.erl b/lib/test_server/src/ts_install_cth.erl
index 9b6e10e7e2..a75cae3c9d 100644
--- a/lib/test_server/src/ts_install_cth.erl
+++ b/lib/test_server/src/ts_install_cth.erl
@@ -103,7 +103,9 @@ pre_init_per_suite(_Suite,Config,State) ->
end,
{add_node_name(Config, State), State}
- catch Error:Reason ->
+ catch error:{badmatch,{error,enoent}} ->
+ {add_node_name(Config, State), State};
+ Error:Reason ->
Stack = erlang:get_stacktrace(),
ct:pal("~p failed! ~p:{~p,~p}",[?MODULE,Error,Reason,Stack]),
{{fail,{?MODULE,{Error,Reason, Stack}}},State}