aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_eval.beambin23220 -> 22692 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_lint.beambin83332 -> 83616 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_pp.beambin24776 -> 25120 bytes
-rw-r--r--erts/configure.in2
-rw-r--r--erts/doc/src/erlang.xml43
-rw-r--r--erts/emulator/Makefile.in4
-rw-r--r--erts/emulator/beam/atom.names4
-rw-r--r--erts/emulator/beam/beam_emu.c22
-rw-r--r--erts/emulator/beam/erl_alloc.types1
-rw-r--r--erts/emulator/beam/erl_bif_trace.c23
-rw-r--r--erts/emulator/beam/erl_lock_check.c5
-rw-r--r--erts/emulator/beam/erl_port_task.c16
-rw-r--r--erts/emulator/beam/erl_process.c1
-rw-r--r--erts/emulator/beam/erl_process.h1
-rw-r--r--erts/emulator/beam/erl_ptab.c2
-rw-r--r--erts/emulator/beam/erl_trace.c128
-rw-r--r--erts/emulator/beam/erl_trace.h2
-rw-r--r--erts/emulator/beam/erl_unicode.c4
-rwxr-xr-xerts/emulator/beam/global.h6
-rw-r--r--erts/emulator/beam/io.c26
-rw-r--r--erts/emulator/beam/utils.c18
-rw-r--r--erts/emulator/drivers/common/efile_drv.c4
-rw-r--r--erts/emulator/sys/common/erl_check_io.c16
-rw-r--r--erts/emulator/sys/common/erl_poll.c166
-rw-r--r--erts/emulator/sys/win32/sys_time.c48
-rw-r--r--erts/emulator/test/port_SUITE.erl15
-rw-r--r--erts/emulator/test/trace_SUITE.erl69
-rw-r--r--erts/etc/unix/cerl.src33
-rw-r--r--erts/preloaded/ebin/erlang.beambin94140 -> 94124 bytes
-rw-r--r--erts/preloaded/ebin/prim_eval.beambin0 -> 1352 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.erl7
-rw-r--r--erts/preloaded/src/prim_eval.S70
-rw-r--r--erts/preloaded/src/prim_eval.erl28
-rw-r--r--erts/test/z_SUITE.erl9
-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.erl599
-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.erl556
-rw-r--r--lib/asn1/src/asn1ct_gen_per_rt2ct.erl946
-rw-r--r--lib/asn1/src/asn1ct_imm.erl92
-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.erl47
-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.asn183
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Extension-Addition-Group.asn19
-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/SeqExtension2.asn1208
-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.erl85
-rw-r--r--lib/asn1/test/asn1_test_lib.erl21
-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.erl92
-rw-r--r--lib/asn1/test/testDeepTConstr.erl59
-rw-r--r--lib/asn1/test/testEnumExt.erl32
-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/testSeqExtension.erl33
-rw-r--r--lib/asn1/test/testSeqOf.erl281
-rw-r--r--lib/common_test/src/ct_config.erl33
-rw-r--r--lib/common_test/src/ct_ftp.erl6
-rw-r--r--lib/common_test/src/ct_gen_conn.erl37
-rw-r--r--lib/common_test/src/ct_netconfc.erl11
-rw-r--r--lib/common_test/src/ct_run.erl6
-rw-r--r--lib/common_test/src/ct_ssh.erl6
-rw-r--r--lib/common_test/src/ct_telnet.erl17
-rw-r--r--lib/common_test/src/ct_testspec.erl70
-rw-r--r--lib/common_test/src/ct_util.erl132
-rw-r--r--lib/common_test/test/Makefile1
-rw-r--r--lib/common_test/test/ct_gen_conn_SUITE.erl135
-rw-r--r--lib/common_test/test/ct_gen_conn_SUITE_data/conn.conf8
-rw-r--r--lib/common_test/test/ct_gen_conn_SUITE_data/conn_SUITE.erl240
-rw-r--r--lib/common_test/test/ct_gen_conn_SUITE_data/proto.erl196
-rw-r--r--lib/common_test/test/ct_testspec_3_SUITE.erl928
-rw-r--r--lib/crypto/c_src/crypto.c72
-rw-r--r--lib/crypto/doc/src/crypto.xml119
-rw-r--r--lib/crypto/src/crypto.appup.src14
-rw-r--r--lib/crypto/src/crypto.erl1648
-rw-r--r--lib/crypto/test/crypto_SUITE.erl258
-rw-r--r--lib/crypto/vsn.mk2
-rw-r--r--lib/erl_interface/vsn.mk2
-rw-r--r--lib/et/vsn.mk2
-rw-r--r--lib/kernel/src/inet.erl41
-rw-r--r--lib/kernel/src/inet_db.erl65
-rw-r--r--lib/kernel/src/inet_hosts.erl9
-rw-r--r--lib/kernel/src/inet_res.erl6
-rw-r--r--lib/kernel/test/file_SUITE.erl17
-rw-r--r--lib/kernel/test/file_name_SUITE.erl16
-rw-r--r--lib/kernel/test/gen_tcp_misc_SUITE.erl2
-rw-r--r--lib/kernel/test/inet_SUITE.erl197
-rw-r--r--lib/kernel/test/inet_res_SUITE.erl198
-rw-r--r--lib/kernel/test/inet_res_SUITE_data/otptest/named_inc.conf6
-rw-r--r--lib/kernel/test/inet_res_SUITE_data/otptest/root.zone6
-rw-r--r--lib/kernel/test/interactive_shell_SUITE.erl6
-rw-r--r--lib/kernel/test/prim_file_SUITE.erl17
-rw-r--r--lib/mnesia/src/mnesia_subscr.erl10
-rw-r--r--lib/mnesia/test/mnesia_evil_coverage_test.erl4
-rw-r--r--lib/mnesia/test/mnesia_isolation_test.erl10
-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/os_mon/vsn.mk2
-rw-r--r--lib/public_key/doc/src/public_key.xml20
-rw-r--r--lib/public_key/src/public_key.app.src2
-rw-r--r--lib/public_key/src/public_key.erl3
-rw-r--r--lib/public_key/test/pkits_SUITE.erl2
-rw-r--r--lib/public_key/test/public_key_SUITE.erl2
-rw-r--r--lib/public_key/vsn.mk2
-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.erl14
-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.erl25
-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.appup.src14
-rw-r--r--lib/ssh/src/ssh.erl2
-rw-r--r--lib/ssl/src/Makefile25
-rw-r--r--lib/ssl/src/dtls.erl (renamed from lib/ssl/src/ssl_debug.hrl)28
-rw-r--r--lib/ssl/src/dtls_connection.erl19
-rw-r--r--lib/ssl/src/dtls_handshake.erl18
-rw-r--r--lib/ssl/src/dtls_handshake.hrl50
-rw-r--r--lib/ssl/src/dtls_record.erl18
-rw-r--r--lib/ssl/src/dtls_record.hrl44
-rw-r--r--lib/ssl/src/ssl.app.src25
-rw-r--r--lib/ssl/src/ssl.appup.src4
-rw-r--r--lib/ssl/src/ssl.erl935
-rw-r--r--lib/ssl/src/ssl_certificate.erl2
-rw-r--r--lib/ssl/src/ssl_cipher.erl12
-rw-r--r--lib/ssl/src/ssl_connection_sup.erl6
-rw-r--r--lib/ssl/src/ssl_handshake.hrl23
-rw-r--r--lib/ssl/src/ssl_manager.erl30
-rw-r--r--lib/ssl/src/ssl_pkix_db.erl (renamed from lib/ssl/src/ssl_certificate_db.erl)2
-rw-r--r--lib/ssl/src/ssl_record.hrl30
-rw-r--r--lib/ssl/src/tls.erl1039
-rw-r--r--lib/ssl/src/tls_connection.erl (renamed from lib/ssl/src/ssl_connection.erl)197
-rw-r--r--lib/ssl/src/tls_handshake.erl (renamed from lib/ssl/src/ssl_handshake.erl)64
-rw-r--r--lib/ssl/src/tls_handshake.hrl45
-rw-r--r--lib/ssl/src/tls_record.erl (renamed from lib/ssl/src/ssl_record.erl)6
-rw-r--r--lib/ssl/src/tls_record.hrl39
-rw-r--r--lib/ssl/test/Makefile4
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl45
-rw-r--r--lib/ssl/test/ssl_certificate_verify_SUITE.erl7
-rw-r--r--lib/ssl/test/ssl_cipher_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_handshake_SUITE.erl8
-rw-r--r--lib/ssl/test/ssl_npn_handshake_SUITE.erl1
-rw-r--r--lib/ssl/test/ssl_npn_hello_SUITE.erl32
-rw-r--r--lib/ssl/test/ssl_packet_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_payload_SUITE.erl1
-rw-r--r--lib/ssl/test/ssl_session_cache_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl39
-rw-r--r--lib/ssl/vsn.mk2
-rw-r--r--lib/stdlib/doc/src/erl_eval.xml5
-rw-r--r--lib/stdlib/src/beam_lib.erl2
-rw-r--r--lib/stdlib/src/erl_eval.erl64
-rw-r--r--lib/stdlib/src/erl_lint.erl137
-rw-r--r--lib/stdlib/src/erl_pp.erl8
-rw-r--r--lib/stdlib/src/otp_internal.erl4
-rw-r--r--lib/stdlib/test/erl_pp_SUITE.erl13
-rw-r--r--lib/stdlib/test/unicode_SUITE.erl147
-rw-r--r--lib/test_server/doc/src/notes.xml2
-rw-r--r--lib/test_server/src/configure.in1
-rw-r--r--lib/test_server/src/test_server.erl13
-rw-r--r--lib/test_server/src/ts_install_cth.erl4
-rw-r--r--lib/tools/doc/src/eprof.xml25
-rw-r--r--lib/tools/emacs/erlang.el1
-rw-r--r--lib/tools/src/eprof.erl217
-rw-r--r--lib/tools/test/eprof_SUITE.erl243
-rw-r--r--lib/tools/test/eprof_SUITE_data/eprof_test.erl15
-rw-r--r--system/doc/reference_manual/introduction.xml2
253 files changed, 17224 insertions, 12563 deletions
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/erl_lint.beam b/bootstrap/lib/stdlib/ebin/erl_lint.beam
index ac593149b8..ee07e7636c 100644
--- a/bootstrap/lib/stdlib/ebin/erl_lint.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_lint.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_pp.beam b/bootstrap/lib/stdlib/ebin/erl_pp.beam
index 8e531126d2..ecc8933bef 100644
--- a/bootstrap/lib/stdlib/ebin/erl_pp.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_pp.beam
Binary files differ
diff --git a/erts/configure.in b/erts/configure.in
index c47c211c4e..b056ba44e2 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -429,7 +429,7 @@ case $host_os in
win32)
# The ethread library requires _WIN32_WINNT of at least 0x0403.
# -D_WIN32_WINNT=* from CPPFLAGS is saved in ETHR_DEFS.
- CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0500 -DWINVER=0x0500"
+ CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0501 -DWINVER=0x0501"
;;
darwin*)
CPPFLAGS="$CPPFLAGS -D_XOPEN_SOURCE"
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index 7dc59ea954..767edc1cc0 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -6058,6 +6058,49 @@ ok
notice.
</p>
</item>
+ <tag><c>{long_schedule, Time}</c></tag>
+ <item>
+ <p>If a process or port in the system runs uninterrupted
+ for at least <c>Time</c> wall clock milliseconds, a
+ message <c>{monitor, PidOrPort, long_schedule, Info}</c>
+ is sent to <c>MonitorPid</c>. <c>PidOrPort</c> is the
+ process or port that was running and <c>Info</c> is a
+ list of two-element tuples describing the event. In case
+ of a <c>pid()</c>, the tuples <c>{timeout, Millis}</c>,
+ <c>{in, Location}</c> and <c>{out, Location}</c> will be
+ present, where <c>Location</c> is either an MFA
+ (<c>{Module, Function, Arity}</c>) describing the
+ function where the process was scheduled in/out, or the
+ atom <c>undefined</c>. In case of a <c>port()</c>, the
+ tuples <c>{timeout, Millis}</c> and <c>{port_op,Op}</c>
+ will be present. <c>Op</c> will be one of <c>proc_sig</c>,
+ <c>timeout</c>, <c>input</c>, <c>output</c>,
+ <c>event</c> or <c>dist_cmd</c>, depending on which
+ driver callback was executing. <c>proc_sig</c> is an
+ internal operation and should never appear, while the
+ others represent the corresponding driver callbacks
+ <c>timeout</c>, <c>ready_input</c>, <c>ready_output</c>,
+ <c>event</c> and finally <c>outputv</c> (when the port
+ is used by distribution). The <c>Millis</c> value in
+ the <c>timeout</c> tuple will tell you the actual
+ uninterrupted execution time of the process or port,
+ which will always be <c>&gt;=</c> the <c>Time</c> value
+ supplied when starting the trace. New tuples may be
+ added to the <c>Info</c> list in the future, and the
+ order of the tuples in the list may be changed at any
+ time without prior notice.
+ </p>
+ <p>This can be used to detect problems with NIF's or
+ drivers that take too long to execute. Generally, 1 ms
+ is considered a good maximum time for a driver callback
+ or a NIF. However, a time sharing system should usually
+ consider everything below 100 ms as "possible" and
+ fairly "normal". Schedule times above that might however
+ indicate swapping or a NIF/driver that is
+ misbehaving. Misbehaving NIF's and drivers could cause
+ bad resource utilization and bad overall performance of
+ the system.</p>
+ </item>
<tag><c>{large_heap, Size}</c></tag>
<item>
<p>If a garbage collection in the system results in
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index fb4cde0e76..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 \
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names
index 7d86e486f1..3ee9eb0f88 100644
--- a/erts/emulator/beam/atom.names
+++ b/erts/emulator/beam/atom.names
@@ -178,6 +178,7 @@ atom disable_trace
atom disabled
atom display_items
atom dist
+atom dist_cmd
atom Div='/'
atom div
atom dlink
@@ -313,6 +314,7 @@ atom load_cancelled
atom load_failure
atom local
atom long_gc
+atom long_schedule
atom low
atom Lt='<'
atom machine
@@ -432,6 +434,7 @@ atom port
atom ports
atom port_count
atom port_limit
+atom port_op
atom print
atom priority
atom private
@@ -443,6 +446,7 @@ atom process_display
atom process_limit
atom process_dump
atom procs
+atom proc_sig
atom profile
atom protected
atom protection
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index 944ed6da81..5781009f58 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -924,6 +924,7 @@ extern int count_instructions;
# define NOINLINE
#endif
+
/*
* The following functions are called directly by process_main().
* Don't inline them.
@@ -1153,6 +1154,9 @@ void process_main(void)
Eterm pt_arity; /* Used by do_put_tuple */
+ Uint64 start_time = 0; /* Monitor long schedule */
+ BeamInstr* start_time_i = NULL;
+
ERL_BITS_DECLARE_STATEP; /* Has to be last declaration */
@@ -1175,6 +1179,16 @@ void process_main(void)
do_schedule:
reds_used = REDS_IN(c_p) - FCALLS;
do_schedule1:
+
+ if (start_time != 0) {
+ Sint64 diff = erts_timestamp_millis() - start_time;
+ if (diff > 0 && (Uint) diff > erts_system_monitor_long_schedule) {
+ BeamInstr *inptr = find_function_from_pc(start_time_i);
+ BeamInstr *outptr = find_function_from_pc(c_p->i);
+ monitor_long_schedule_proc(c_p,inptr,outptr,(Uint) diff);
+ }
+ }
+
PROCESS_MAIN_CHK_LOCKS(c_p);
ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
#if HALFWORD_HEAP
@@ -1183,11 +1197,18 @@ void process_main(void)
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p);
c_p = schedule(c_p, reds_used);
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p);
+ start_time = 0;
#ifdef DEBUG
pid = c_p->common.id; /* Save for debugging purpouses */
#endif
ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
PROCESS_MAIN_CHK_LOCKS(c_p);
+
+ if (erts_system_monitor_long_schedule != 0) {
+ start_time = erts_timestamp_millis();
+ start_time_i = c_p->i;
+ }
+
reg = ERTS_PROC_GET_SCHDATA(c_p)->x_reg_array;
freg = ERTS_PROC_GET_SCHDATA(c_p)->f_reg_array;
#if !HEAP_ON_C_STACK
@@ -6151,6 +6172,7 @@ apply_fun(Process* p, Eterm fun, Eterm args, Eterm* reg)
}
+
static Eterm
new_fun(Process* p, Eterm* reg, ErlFunEntry* fe, int num_free)
{
diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types
index 095ad24387..7e3b3c707d 100644
--- a/erts/emulator/beam/erl_alloc.types
+++ b/erts/emulator/beam/erl_alloc.types
@@ -397,6 +397,7 @@ type POLLSET_UPDREQ SHORT_LIVED SYSTEM pollset_update_req
type POLL_FDS LONG_LIVED SYSTEM poll_fds
type POLL_RES_EVS LONG_LIVED SYSTEM poll_result_events
type FD_STATUS LONG_LIVED SYSTEM fd_status
+type SELECT_FDS LONG_LIVED SYSTEM select_fds
+if unix
diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c
index 559cb3efa1..06fbbea123 100644
--- a/erts/emulator/beam/erl_bif_trace.c
+++ b/erts/emulator/beam/erl_bif_trace.c
@@ -2012,6 +2012,7 @@ void erts_system_monitor_clear(Process *c_p) {
#endif
erts_set_system_monitor(NIL);
erts_system_monitor_long_gc = 0;
+ erts_system_monitor_long_schedule = 0;
erts_system_monitor_large_heap = 0;
erts_system_monitor_flags.busy_port = 0;
erts_system_monitor_flags.busy_dist_port = 0;
@@ -2036,12 +2037,17 @@ static Eterm system_monitor_get(Process *p)
Uint hsz = 3 + (erts_system_monitor_flags.busy_dist_port ? 2 : 0) +
(erts_system_monitor_flags.busy_port ? 2 : 0);
Eterm long_gc = NIL;
+ Eterm long_schedule = NIL;
Eterm large_heap = NIL;
if (erts_system_monitor_long_gc != 0) {
hsz += 2+3;
(void) erts_bld_uint(NULL, &hsz, erts_system_monitor_long_gc);
}
+ if (erts_system_monitor_long_schedule != 0) {
+ hsz += 2+3;
+ (void) erts_bld_uint(NULL, &hsz, erts_system_monitor_long_schedule);
+ }
if (erts_system_monitor_large_heap != 0) {
hsz += 2+3;
(void) erts_bld_uint(NULL, &hsz, erts_system_monitor_large_heap);
@@ -2051,6 +2057,10 @@ static Eterm system_monitor_get(Process *p)
if (erts_system_monitor_long_gc != 0) {
long_gc = erts_bld_uint(&hp, NULL, erts_system_monitor_long_gc);
}
+ if (erts_system_monitor_long_schedule != 0) {
+ long_schedule = erts_bld_uint(&hp, NULL,
+ erts_system_monitor_long_schedule);
+ }
if (erts_system_monitor_large_heap != 0) {
large_heap = erts_bld_uint(&hp, NULL, erts_system_monitor_large_heap);
}
@@ -2059,6 +2069,10 @@ static Eterm system_monitor_get(Process *p)
Eterm t = TUPLE2(hp, am_long_gc, long_gc); hp += 3;
res = CONS(hp, t, res); hp += 2;
}
+ if (long_schedule != NIL) {
+ Eterm t = TUPLE2(hp, am_long_schedule, long_schedule); hp += 3;
+ res = CONS(hp, t, res); hp += 2;
+ }
if (large_heap != NIL) {
Eterm t = TUPLE2(hp, am_large_heap, large_heap); hp += 3;
res = CONS(hp, t, res); hp += 2;
@@ -2113,7 +2127,7 @@ system_monitor(Process *p, Eterm monitor_pid, Eterm list)
}
if (is_not_list(list)) goto error;
else {
- Uint long_gc, large_heap;
+ Uint long_gc, long_schedule, large_heap;
int busy_port, busy_dist_port;
system_blocked = 1;
@@ -2123,7 +2137,8 @@ system_monitor(Process *p, Eterm monitor_pid, Eterm list)
if (!erts_pid2proc(p, ERTS_PROC_LOCK_MAIN, monitor_pid, 0))
goto error;
- for (long_gc = 0, large_heap = 0, busy_port = 0, busy_dist_port = 0;
+ for (long_gc = 0, long_schedule = 0, large_heap = 0,
+ busy_port = 0, busy_dist_port = 0;
is_list(list);
list = CDR(list_val(list))) {
Eterm t = CAR(list_val(list));
@@ -2133,6 +2148,9 @@ system_monitor(Process *p, Eterm monitor_pid, Eterm list)
if (tp[1] == am_long_gc) {
if (! term_to_Uint(tp[2], &long_gc)) goto error;
if (long_gc < 1) long_gc = 1;
+ } else if (tp[1] == am_long_schedule) {
+ if (! term_to_Uint(tp[2], &long_schedule)) goto error;
+ if (long_schedule < 1) long_schedule = 1;
} else if (tp[1] == am_large_heap) {
if (! term_to_Uint(tp[2], &large_heap)) goto error;
if (large_heap < 16384) large_heap = 16384;
@@ -2148,6 +2166,7 @@ system_monitor(Process *p, Eterm monitor_pid, Eterm list)
prev = system_monitor_get(p);
erts_set_system_monitor(monitor_pid);
erts_system_monitor_long_gc = long_gc;
+ erts_system_monitor_long_schedule = long_schedule;
erts_system_monitor_large_heap = large_heap;
erts_system_monitor_flags.busy_port = !!busy_port;
erts_system_monitor_flags.busy_dist_port = !!busy_dist_port;
diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c
index bc59fe55d4..2ac5e24d3a 100644
--- a/erts/emulator/beam/erl_lock_check.c
+++ b/erts/emulator/beam/erl_lock_check.c
@@ -180,6 +180,11 @@ static erts_lc_lock_order_t erts_lock_order[] = {
{ "efile_drv dtrace mutex", NULL },
#endif
{ "mtrace_buf", NULL },
+#ifdef __WIN32__
+#ifdef ERTS_SMP
+ { "sys_gethrtime", NULL },
+#endif
+#endif
{ "erts_alloc_hard_debug", NULL }
};
diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c
index 53cb01a8c6..7d53ce7152 100644
--- a/erts/emulator/beam/erl_port_task.c
+++ b/erts/emulator/beam/erl_port_task.c
@@ -1594,6 +1594,7 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
int fpe_was_unmasked;
erts_aint32_t state;
int active;
+ Uint64 start_time = 0;
ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq));
@@ -1655,6 +1656,10 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
reset_handle(ptp);
+ if (erts_system_monitor_long_schedule != 0) {
+ start_time = erts_timestamp_millis();
+ }
+
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp));
ERTS_SMP_CHK_NO_PROC_LOCKS;
ASSERT(pp->drv_ptr);
@@ -1723,6 +1728,14 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
reds += erts_port_driver_callback_epilogue(pp, &state);
+ if (start_time != 0) {
+ Sint64 diff = erts_timestamp_millis() - start_time;
+ if (diff > 0 && (Uint) diff > erts_system_monitor_long_schedule) {
+ monitor_long_schedule_port(pp,ptp->type,(Uint) diff);
+ }
+ }
+ start_time = 0;
+
aborted_port_task:
schedule_port_task_free(ptp);
@@ -1928,18 +1941,21 @@ begin_port_cleanup(Port *pp, ErtsPortTask **execqp, int *processing_busy_q_p)
break;
case ERTS_PORT_TASK_INPUT:
erts_stale_drv_select(pp->common.id,
+ ERTS_Port2ErlDrvPort(pp),
ptp->u.alive.td.io.event,
DO_READ,
1);
break;
case ERTS_PORT_TASK_OUTPUT:
erts_stale_drv_select(pp->common.id,
+ ERTS_Port2ErlDrvPort(pp),
ptp->u.alive.td.io.event,
DO_WRITE,
1);
break;
case ERTS_PORT_TASK_EVENT:
erts_stale_drv_select(pp->common.id,
+ ERTS_Port2ErlDrvPort(pp),
ptp->u.alive.td.io.event,
0,
1);
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 88eb224f84..3d161f2aa0 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -267,6 +267,7 @@ static Uint last_exact_reductions;
Uint erts_default_process_flags;
Eterm erts_system_monitor;
Eterm erts_system_monitor_long_gc;
+Uint erts_system_monitor_long_schedule;
Eterm erts_system_monitor_large_heap;
struct erts_system_monitor_flags_t erts_system_monitor_flags;
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 865ac6c43f..3c1edfad7a 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -1009,6 +1009,7 @@ extern erts_smp_rwmtx_t erts_cpu_bind_rwmtx;
*/
extern Eterm erts_system_monitor;
extern Uint erts_system_monitor_long_gc;
+extern Uint erts_system_monitor_long_schedule;
extern Uint erts_system_monitor_large_heap;
struct erts_system_monitor_flags_t {
unsigned int busy_port : 1;
diff --git a/erts/emulator/beam/erl_ptab.c b/erts/emulator/beam/erl_ptab.c
index 8da135b2c8..f7b5f25eac 100644
--- a/erts/emulator/beam/erl_ptab.c
+++ b/erts/emulator/beam/erl_ptab.c
@@ -1435,7 +1435,7 @@ erts_ptab_test_next_id(ErtsPTab *ptab, int set, Uint next)
aid_ix = max_ix;
else
aid_ix--;
- ASSERT((aid_ix & max_ix) == (((Uint32) erts_atomic32_read_nob(&ptab->vola.tile.fid_ix)) & max_ix));
+ ASSERT((aid_ix & max_ix) == (((Uint32) erts_smp_atomic32_read_nob(&ptab->vola.tile.fid_ix)) & max_ix));
#endif
}
diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c
index 848877d43e..bb6ed44523 100644
--- a/erts/emulator/beam/erl_trace.c
+++ b/erts/emulator/beam/erl_trace.c
@@ -2268,7 +2268,134 @@ trace_gc(Process *p, Eterm what)
#undef LOCAL_HEAP_SIZE
}
+void
+monitor_long_schedule_proc(Process *p, BeamInstr *in_fp, BeamInstr *out_fp, Uint time)
+{
+ ErlHeapFragment *bp;
+ ErlOffHeap *off_heap;
+#ifndef ERTS_SMP
+ Process *monitor_p;
+#endif
+ Uint hsz;
+ Eterm *hp, list, in_mfa = am_undefined, out_mfa = am_undefined;
+ Eterm in_tpl, out_tpl, tmo_tpl, tmo, msg;
+
+
+#ifndef ERTS_SMP
+ ASSERT(is_internal_pid(system_monitor));
+ monitor_p = erts_proc_lookup(system_monitor);
+ if (!monitor_p || p == monitor_p) {
+ return;
+ }
+#endif
+ /*
+ * Size: {monitor, pid, long_schedule, [{timeout, T}, {in, {M,F,A}},{out,{M,F,A}}]} ->
+ * 5 (top tuple of 4), (3 (elements) * 2 (cons)) + 3 (timeout tuple of 2) + size of Timeout +
+ * (2 * 3 (in/out tuple of 2)) +
+ * 0 (unknown) or 4 (MFA tuple of 3) + 0 (unknown) or 4 (MFA tuple of 3)
+ * = 20 + (in_fp != NULL) ? 4 : 0 + (out_fp != NULL) ? 4 : 0 + size of Timeout
+ */
+ hsz = 20 + ((in_fp != NULL) ? 4 : 0) + ((out_fp != NULL) ? 4 : 0);
+ (void) erts_bld_uint(NULL, &hsz, time);
+ hp = ERTS_ALLOC_SYSMSG_HEAP(hsz, &bp, &off_heap, monitor_p);
+ tmo = erts_bld_uint(&hp, NULL, time);
+ if (in_fp != NULL) {
+ in_mfa = TUPLE3(hp,(Eterm) in_fp[0], (Eterm) in_fp[1], make_small(in_fp[2]));
+ hp +=4;
+ }
+ if (out_fp != NULL) {
+ out_mfa = TUPLE3(hp,(Eterm) out_fp[0], (Eterm) out_fp[1], make_small(out_fp[2]));
+ hp +=4;
+ }
+ tmo_tpl = TUPLE2(hp,am_timeout, tmo);
+ hp += 3;
+ in_tpl = TUPLE2(hp,am_in,in_mfa);
+ hp += 3;
+ out_tpl = TUPLE2(hp,am_out,out_mfa);
+ hp += 3;
+ list = CONS(hp,out_tpl,NIL);
+ hp += 2;
+ list = CONS(hp,in_tpl,list);
+ hp += 2;
+ list = CONS(hp,tmo_tpl,list);
+ hp += 2;
+ msg = TUPLE4(hp, am_monitor, p->common.id, am_long_schedule, list);
+ hp += 5;
+#ifdef ERTS_SMP
+ enqueue_sys_msg(SYS_MSG_TYPE_SYSMON, p->common.id, NIL, msg, bp);
+#else
+ erts_queue_message(monitor_p, NULL, bp, msg, NIL
+#ifdef USE_VM_PROBES
+ , NIL
+#endif
+ );
+#endif
+}
+void
+monitor_long_schedule_port(Port *pp, ErtsPortTaskType type, Uint time)
+{
+ ErlHeapFragment *bp;
+ ErlOffHeap *off_heap;
+#ifndef ERTS_SMP
+ Process *monitor_p;
+#endif
+ Uint hsz;
+ Eterm *hp, list, op;
+ Eterm op_tpl, tmo_tpl, tmo, msg;
+
+
+#ifndef ERTS_SMP
+ ASSERT(is_internal_pid(system_monitor));
+ monitor_p = erts_proc_lookup(system_monitor);
+ if (!monitor_p) {
+ return;
+ }
+#endif
+ /*
+ * Size: {monitor, port, long_schedule, [{timeout, T}, {op, Operation}]} ->
+ * 5 (top tuple of 4), (2 (elements) * 2 (cons)) + 3 (timeout tuple of 2)
+ * + size of Timeout + 3 (op tuple of 2 atoms)
+ * = 15 + size of Timeout
+ */
+ hsz = 15;
+ (void) erts_bld_uint(NULL, &hsz, time);
+
+ hp = ERTS_ALLOC_SYSMSG_HEAP(hsz, &bp, &off_heap, monitor_p);
+ switch (type) {
+ case ERTS_PORT_TASK_PROC_SIG: op = am_proc_sig; break;
+ case ERTS_PORT_TASK_TIMEOUT: op = am_timeout; break;
+ case ERTS_PORT_TASK_INPUT: op = am_input; break;
+ case ERTS_PORT_TASK_OUTPUT: op = am_output; break;
+ case ERTS_PORT_TASK_EVENT: op = am_event; break;
+ case ERTS_PORT_TASK_DIST_CMD: op = am_dist_cmd; break;
+ default: op = am_undefined; break;
+ }
+
+ tmo = erts_bld_uint(&hp, NULL, time);
+
+ op_tpl = TUPLE2(hp,am_port_op,op);
+ hp += 3;
+
+ tmo_tpl = TUPLE2(hp,am_timeout, tmo);
+ hp += 3;
+
+ list = CONS(hp,op_tpl,NIL);
+ hp += 2;
+ list = CONS(hp,tmo_tpl,list);
+ hp += 2;
+ msg = TUPLE4(hp, am_monitor, pp->common.id, am_long_schedule, list);
+ hp += 5;
+#ifdef ERTS_SMP
+ enqueue_sys_msg(SYS_MSG_TYPE_SYSMON, pp->common.id, NIL, msg, bp);
+#else
+ erts_queue_message(monitor_p, NULL, bp, msg, NIL
+#ifdef USE_VM_PROBES
+ , NIL
+#endif
+ );
+#endif
+}
void
monitor_long_gc(Process *p, Uint time) {
@@ -3011,6 +3138,7 @@ sys_msg_disp_failure(ErtsSysMsgQ *smqp, Eterm receiver)
case SYS_MSG_TYPE_SYSMON:
if (receiver == NIL
&& !erts_system_monitor_long_gc
+ && !erts_system_monitor_long_schedule
&& !erts_system_monitor_large_heap
&& !erts_system_monitor_flags.busy_port
&& !erts_system_monitor_flags.busy_dist_port)
diff --git a/erts/emulator/beam/erl_trace.h b/erts/emulator/beam/erl_trace.h
index 50fb27aab0..54d3aafdda 100644
--- a/erts/emulator/beam/erl_trace.h
+++ b/erts/emulator/beam/erl_trace.h
@@ -83,6 +83,8 @@ void erts_system_profile_setup_active_schedulers(void);
/* system_monitor */
void monitor_long_gc(Process *p, Uint time);
+void monitor_long_schedule_proc(Process *p, BeamInstr *in_i, BeamInstr *out_i, Uint time);
+void monitor_long_schedule_port(Port *pp, ErtsPortTaskType type, Uint time);
void monitor_large_heap(Process *p);
void monitor_generic(Process *p, Eterm type, Eterm spec);
Uint erts_trace_flag2bit(Eterm flag);
diff --git a/erts/emulator/beam/erl_unicode.c b/erts/emulator/beam/erl_unicode.c
index ad6f8b993a..e00440b905 100644
--- a/erts/emulator/beam/erl_unicode.c
+++ b/erts/emulator/beam/erl_unicode.c
@@ -1723,14 +1723,14 @@ static BIF_RETTYPE do_bif_utf8_to_list(Process *p,
if (b_sz) {
ErlSubBin *sb;
Eterm orig;
- ERTS_DECLARE_DUMMY(Uint offset);
+ Uint offset;
ASSERT(state != ERTS_UTF8_OK);
hp = HAlloc(p, ERL_SUB_BIN_SIZE);
sb = (ErlSubBin *) hp;
ERTS_GET_REAL_BIN(orig_bin, orig, offset, bitoffs, bitsize);
sb->thing_word = HEADER_SUB_BIN;
sb->size = b_sz;
- sb->offs = num_bytes_to_process + num_processed_bytes;
+ sb->offs = offset + num_bytes_to_process + num_processed_bytes;
sb->orig = orig;
sb->bitoffs = bitoffs;
sb->bitsize = bitsize;
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index 26ed5f82c1..12eb3bfb7c 100755
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -723,10 +723,10 @@ void erts_raw_port_command(Port*, byte*, Uint);
void driver_report_exit(ErlDrvPort, int);
LineBuf* allocate_linebuf(int);
int async_ready(Port *, void*);
-ErtsPortNames *erts_get_port_names(Eterm);
+ErtsPortNames *erts_get_port_names(Eterm, ErlDrvPort);
void erts_free_port_names(ErtsPortNames *);
Uint erts_port_ioq_size(Port *pp);
-void erts_stale_drv_select(Eterm, ErlDrvEvent, int, int);
+void erts_stale_drv_select(Eterm, ErlDrvPort, ErlDrvEvent, int, int);
Port *erts_get_heart_port(void);
@@ -740,6 +740,8 @@ void erl_drv_thr_init(void);
/* utils.c */
void erts_cleanup_offheap(ErlOffHeap *offheap);
+Uint64 erts_timestamp_millis(void);
+
Export* erts_find_function(Eterm, Eterm, unsigned int, ErtsCodeIndex);
Eterm store_external_or_ref_in_proc_(Process *, Eterm);
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index 13cff24b95..c1e66b59af 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -4814,7 +4814,8 @@ int async_ready(Port *p, void* data)
static void
report_missing_drv_callback(Port *p, char *drv_type, char *callback)
{
- ErtsPortNames *pnp = erts_get_port_names(p->common.id);
+ ErtsPortNames *pnp = erts_get_port_names(p->common.id,
+ ERTS_Port2ErlDrvPort(p));
char *unknown = "<unknown>";
char *drv_name = pnp->driver_name ? pnp->driver_name : unknown;
char *prt_name = pnp->name ? pnp->name : unknown;
@@ -4829,15 +4830,25 @@ report_missing_drv_callback(Port *p, char *drv_type, char *callback)
void
erts_stale_drv_select(Eterm port,
+ ErlDrvPort drv_port,
ErlDrvEvent hndl,
int mode,
int deselect)
{
char *type;
- ErlDrvPort drv_port = ERTS_Port2ErlDrvPort(erts_port_lookup_raw(port));
- ErtsPortNames *pnp = erts_get_port_names(port);
+ ErtsPortNames *pnp;
erts_dsprintf_buf_t *dsbufp;
+ if (drv_port == ERTS_INVALID_ERL_DRV_PORT) {
+ Port *prt = erts_port_lookup_raw(port);
+ if (prt)
+ drv_port = ERTS_Port2ErlDrvPort(prt);
+ else
+ drv_port = ERTS_INVALID_ERL_DRV_PORT;
+ }
+
+ pnp = erts_get_port_names(port, drv_port);
+
switch (mode) {
case ERL_DRV_READ | ERL_DRV_WRITE:
type = "Input/Output";
@@ -4872,12 +4883,16 @@ erts_stale_drv_select(Eterm port,
}
ErtsPortNames *
-erts_get_port_names(Eterm id)
+erts_get_port_names(Eterm id, ErlDrvPort drv_port)
{
- Port *prt = erts_port_lookup_raw(id);
+ Port *prt;
ErtsPortNames *pnp;
ASSERT(is_nil(id) || is_internal_port(id));
+ prt = ERTS_ErlDrvPort2Port(drv_port);
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
+ prt = erts_port_lookup_raw(id);
+
if (!prt) {
pnp = erts_alloc(ERTS_ALC_T_PORT_NAMES, sizeof(ErtsPortNames));
pnp->name = NULL;
@@ -4889,6 +4904,7 @@ erts_get_port_names(Eterm id)
size_t pnp_len = sizeof(ErtsPortNames);
#ifndef DEBUG
pnp_len += 100; /* In most cases 100 characters will be enough... */
+ ASSERT(prt->common.id == id);
#endif
pnp = erts_alloc(ERTS_ALC_T_PORT_NAMES, pnp_len);
do {
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index d5d97d748a..0a833f7e66 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -3722,6 +3722,24 @@ erts_smp_ensure_later_interval_acqb(erts_interval_t *icp, Uint64 ic)
}
+/*
+ * A millisecond timestamp without time correction where there's no hrtime
+ * - for tracing on "long" things...
+ */
+Uint64 erts_timestamp_millis(void)
+{
+#ifdef HAVE_GETHRTIME
+ return (Uint64) (sys_gethrtime() / 1000000);
+#else
+ Uint64 res;
+ SysTimeval tv;
+ sys_gettimeofday(&tv);
+ res = (Uint64) tv.tv_sec*1000000;
+ res += (Uint64) tv.tv_usec;
+ return (res / 1000);
+#endif
+}
+
#ifdef DEBUG
/*
* Handy functions when using a debugger - don't use in the code!
diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c
index 6cc1295973..595b0488a8 100644
--- a/erts/emulator/drivers/common/efile_drv.c
+++ b/erts/emulator/drivers/common/efile_drv.c
@@ -1679,10 +1679,10 @@ static void invoke_pwritev(void *data) {
d->again = 0;
}
} else
- ASSERT(written == FILE_SEGMENT_WRITE);
+ ASSERT(written >= FILE_SEGMENT_WRITE);
MUTEX_LOCK(d->c.writev.q_mtx);
- driver_deq(d->c.pwritev.port, size);
+ driver_deq(d->c.pwritev.port, written);
MUTEX_UNLOCK(d->c.writev.q_mtx);
done:
EF_FREE(iov); /* Free our copy of the vector, nothing to restore */
diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c
index 853dd90c34..7035dc77df 100644
--- a/erts/emulator/sys/common/erl_check_io.c
+++ b/erts/emulator/sys/common/erl_check_io.c
@@ -874,7 +874,7 @@ need2steal(ErtsDrvEventState *state, int mode)
static void
print_driver_name(erts_dsprintf_buf_t *dsbufp, Eterm id)
{
- ErtsPortNames *pnp = erts_get_port_names(id);
+ ErtsPortNames *pnp = erts_get_port_names(id, ERTS_INVALID_ERL_DRV_PORT);
if (!pnp->name && !pnp->driver_name)
erts_dsprintf(dsbufp, "%s ", "<unknown>");
else {
@@ -1357,8 +1357,8 @@ bad_fd_in_pollset(ErtsDrvEventState *state, Eterm inport,
"Bad %s fd in erts_poll()! fd=%d, ",
io_str, (int) state->fd);
if (is_nil(port)) {
- ErtsPortNames *ipnp = erts_get_port_names(inport);
- ErtsPortNames *opnp = erts_get_port_names(outport);
+ ErtsPortNames *ipnp = erts_get_port_names(inport, ERTS_INVALID_ERL_DRV_PORT);
+ ErtsPortNames *opnp = erts_get_port_names(outport, ERTS_INVALID_ERL_DRV_PORT);
erts_dsprintf(dsbufp, "ports=%T/%T, drivers=%s/%s, names=%s/%s\n",
is_nil(inport) ? am_undefined : inport,
is_nil(outport) ? am_undefined : outport,
@@ -1370,7 +1370,7 @@ bad_fd_in_pollset(ErtsDrvEventState *state, Eterm inport,
erts_free_port_names(opnp);
}
else {
- ErtsPortNames *pnp = erts_get_port_names(port);
+ ErtsPortNames *pnp = erts_get_port_names(port, ERTS_INVALID_ERL_DRV_PORT);
erts_dsprintf(dsbufp, "port=%T, driver=%s, name=%s\n",
is_nil(port) ? am_undefined : port,
pnp->driver_name ? pnp->driver_name : "<unknown>",
@@ -1390,7 +1390,7 @@ bad_fd_in_pollset(ErtsDrvEventState *state, Eterm inport,
static void
stale_drv_select(Eterm id, ErtsDrvEventState *state, int mode)
{
- erts_stale_drv_select(id, (ErlDrvEvent) state->fd, mode, 0);
+ erts_stale_drv_select(id, ERTS_INVALID_ERL_DRV_PORT, (ErlDrvEvent) state->fd, mode, 0);
deselect(state, mode);
}
@@ -1774,7 +1774,7 @@ static void doit_erts_check_io_debug(void *vstate, void *vcounters)
err = 1;
}
else {
- ErtsPortNames *pnp = erts_get_port_names(id);
+ ErtsPortNames *pnp = erts_get_port_names(id, ERTS_INVALID_ERL_DRV_PORT);
erts_printf(" inport=%T inname=%s indrv=%s ",
id,
pnp->name ? pnp->name : "unknown",
@@ -1791,7 +1791,7 @@ static void doit_erts_check_io_debug(void *vstate, void *vcounters)
err = 1;
}
else {
- ErtsPortNames *pnp = erts_get_port_names(id);
+ ErtsPortNames *pnp = erts_get_port_names(id, ERTS_INVALID_ERL_DRV_PORT);
erts_printf(" outport=%T outname=%s outdrv=%s ",
id,
pnp->name ? pnp->name : "unknown",
@@ -1827,7 +1827,7 @@ static void doit_erts_check_io_debug(void *vstate, void *vcounters)
err = 1;
}
else {
- ErtsPortNames *pnp = erts_get_port_names(id);
+ ErtsPortNames *pnp = erts_get_port_names(id, ERTS_INVALID_ERL_DRV_PORT);
erts_printf(" port=%T name=%s drv=%s ",
id,
pnp->name ? pnp->name : "unknown",
diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c
index a523d67158..7d292a304a 100644
--- a/erts/emulator/sys/common/erl_poll.c
+++ b/erts/emulator/sys/common/erl_poll.c
@@ -40,6 +40,13 @@
# include "config.h"
#endif
+#if defined(__DARWIN__) || defined(__APPLE__) && defined(__MACH__)
+/* Setting _DARWIN_UNLIMITED_SELECT before including sys/select.h enables
+ * the version of select() that does not place a limit on the fd_set.
+ */
+# define _DARWIN_UNLIMITED_SELECT
+#endif
+
#ifndef WANT_NONBLOCKING
# define WANT_NONBLOCKING
#endif
@@ -90,6 +97,52 @@
#define HARD_DEBUG
#endif
+#ifdef _DARWIN_UNLIMITED_SELECT
+typedef struct {
+ size_t sz;
+ fd_set* ptr;
+}ERTS_fd_set;
+# define ERTS_FD_CLR(fd, fds) FD_CLR((fd), (fds)->ptr)
+# define ERTS_FD_SET(fd, fds) FD_SET((fd), (fds)->ptr)
+# define ERTS_FD_ISSET(fd,fds) FD_ISSET((fd), (fds)->ptr)
+# define ERTS_FD_ZERO(fds) memset((fds)->ptr, 0, (fds)->sz)
+# define ERTS_FD_SIZE(n) ((((n)+NFDBITS-1)/NFDBITS)*sizeof(fd_mask))
+
+static void ERTS_FD_COPY(ERTS_fd_set *src, ERTS_fd_set *dst)
+{
+ if (dst->sz != src->sz) {
+ dst->ptr = dst->ptr
+ ? erts_realloc(ERTS_ALC_T_SELECT_FDS, dst->ptr, src->sz)
+ : erts_alloc(ERTS_ALC_T_SELECT_FDS, src->sz);
+ dst->sz = src->sz;
+ }
+ memcpy(dst->ptr, src->ptr, src->sz);
+}
+
+static ERTS_INLINE
+int ERTS_SELECT(int nfds, ERTS_fd_set *readfds, ERTS_fd_set *writefds,
+ ERTS_fd_set *exceptfds, struct timeval *timeout)
+{
+ ASSERT(!readfds || readfds->sz >= nfds);
+ ASSERT(!writefds || writefds->sz >= nfds);
+ ASSERT(!exceptfds);
+ return select(nfds,
+ (readfds ? readfds->ptr : NULL ),
+ (writefds ? writefds->ptr : NULL),
+ NULL,
+ timeout);
+}
+
+#else /* !_DARWIN_UNLIMITED_SELECT */
+# define ERTS_fd_set fd_set
+# define ERTS_FD_CLR FD_CLR
+# define ERTS_FD_ISSET FD_ISSET
+# define ERTS_FD_SET FD_SET
+# define ERTS_FD_ZERO FD_ZERO
+# define ERTS_FD_COPY(src,dst) (*(dst) = *(src))
+# define ERTS_SELECT select
+#endif
+
#define ERTS_POLL_USE_BATCH_UPDATE_POLLSET (ERTS_POLL_USE_DEVPOLL \
|| ERTS_POLL_USE_KQUEUE)
#define ERTS_POLL_USE_UPDATE_REQUESTS_QUEUE \
@@ -244,10 +297,10 @@ struct ErtsPollSet_ {
#if ERTS_POLL_USE_FALLBACK
int no_select_fds;
#endif
- fd_set input_fds;
- fd_set res_input_fds;
- fd_set output_fds;
- fd_set res_output_fds;
+ ERTS_fd_set input_fds;
+ ERTS_fd_set res_input_fds;
+ ERTS_fd_set output_fds;
+ ERTS_fd_set res_output_fds;
#endif
#if ERTS_POLL_USE_UPDATE_REQUESTS_QUEUE
ErtsPollSetUpdateRequestsBlock update_requests;
@@ -624,6 +677,33 @@ grow_poll_fds(ErtsPollSet ps, int min_ix)
}
#endif
+#ifdef _DARWIN_UNLIMITED_SELECT
+static void
+grow_select_fds(int fd, ERTS_fd_set* fds)
+{
+ int new_len = ERTS_POLL_EXPORT(erts_poll_get_table_len)(fd + 1);
+ if (new_len > max_fds)
+ new_len = max_fds;
+ new_len = ERTS_FD_SIZE(new_len);
+ fds->ptr = fds->sz
+ ? erts_realloc(ERTS_ALC_T_SELECT_FDS, fds->ptr, new_len)
+ : erts_alloc(ERTS_ALC_T_SELECT_FDS, new_len);
+ memset((char*)fds->ptr + fds->sz, 0, new_len - fds->sz);
+ fds->sz = new_len;
+}
+static ERTS_INLINE void
+ensure_select_fds(int fd, ERTS_fd_set* in, ERTS_fd_set* out)
+{
+ ASSERT(in->sz == out->sz);
+ if (ERTS_FD_SIZE(fd+1) > in->sz) {
+ grow_select_fds(fd, in);
+ grow_select_fds(fd, out);
+ }
+}
+#else
+# define ensure_select_fds(fd, in, out) do {} while(0)
+#endif /* _DARWIN_UNLIMITED_SELECT */
+
static void
grow_fds_status(ErtsPollSet ps, int min_fd)
{
@@ -1290,22 +1370,23 @@ static int update_pollset(ErtsPollSet ps, int fd)
#elif ERTS_POLL_USE_SELECT /* --- select ------------------------------ */
{
ErtsPollEvents events = ps->fds_status[fd].events;
+ ensure_select_fds(fd, &ps->input_fds, &ps->output_fds);
if ((ERTS_POLL_EV_IN & events)
!= (ERTS_POLL_EV_IN & ps->fds_status[fd].used_events)) {
if (ERTS_POLL_EV_IN & events) {
- FD_SET(fd, &ps->input_fds);
+ ERTS_FD_SET(fd, &ps->input_fds);
}
else {
- FD_CLR(fd, &ps->input_fds);
+ ERTS_FD_CLR(fd, &ps->input_fds);
}
}
if ((ERTS_POLL_EV_OUT & events)
!= (ERTS_POLL_EV_OUT & ps->fds_status[fd].used_events)) {
if (ERTS_POLL_EV_OUT & events) {
- FD_SET(fd, &ps->output_fds);
+ ERTS_FD_SET(fd, &ps->output_fds);
}
else {
- FD_CLR(fd, &ps->output_fds);
+ ERTS_FD_CLR(fd, &ps->output_fds);
}
}
@@ -1789,7 +1870,7 @@ save_poll_result(ErtsPollSet ps, ErtsPollResFd pr[], int max_res,
while (fd < end_fd && res < max_res) {
pr[res].events = (ErtsPollEvents) 0;
- if (FD_ISSET(fd, &ps->res_input_fds)) {
+ if (ERTS_FD_ISSET(fd, &ps->res_input_fds)) {
#if ERTS_POLL_USE_FALLBACK
if (fd == ps->kp_fd) {
res += get_kp_results(ps, &pr[res], max_res-res);
@@ -1805,7 +1886,7 @@ save_poll_result(ErtsPollSet ps, ErtsPollResFd pr[], int max_res,
#endif
pr[res].events |= ERTS_POLL_EV_IN;
}
- if (FD_ISSET(fd, &ps->res_output_fds))
+ if (ERTS_FD_ISSET(fd, &ps->res_output_fds))
pr[res].events |= ERTS_POLL_EV_OUT;
if (pr[res].events) {
pr[res].fd = fd;
@@ -1832,24 +1913,23 @@ save_poll_result(ErtsPollSet ps, ErtsPollResFd pr[], int max_res,
while (fd < end_fd && res < max_res) {
if (ps->fds_status[fd].events) {
int sres;
- fd_set *iset = NULL;
- fd_set *oset = NULL;
+ ERTS_fd_set *iset = NULL;
+ ERTS_fd_set *oset = NULL;
if (ps->fds_status[fd].events & ERTS_POLL_EV_IN) {
iset = &ps->res_input_fds;
- FD_ZERO(iset);
- FD_SET(fd, iset);
+ ERTS_FD_ZERO(iset);
+ ERTS_FD_SET(fd, iset);
}
if (ps->fds_status[fd].events & ERTS_POLL_EV_OUT) {
oset = &ps->res_output_fds;
- FD_ZERO(oset);
- FD_SET(fd, oset);
-
+ ERTS_FD_ZERO(oset);
+ ERTS_FD_SET(fd, oset);
}
do {
/* Initiate 'tv' each time;
select() may modify it */
SysTimeval tv = {0, 0};
- sres = select(ps->max_fd+1, iset, oset, NULL, &tv);
+ sres = ERTS_SELECT(ps->max_fd+1, iset, oset, NULL, &tv);
} while (sres < 0 && errno == EINTR);
if (sres < 0) {
#if ERTS_POLL_USE_FALLBACK
@@ -1873,7 +1953,7 @@ save_poll_result(ErtsPollSet ps, ErtsPollResFd pr[], int max_res,
}
else if (sres > 0) {
pr[res].fd = fd;
- if (iset && FD_ISSET(fd, iset)) {
+ if (iset && ERTS_FD_ISSET(fd, iset)) {
#if ERTS_POLL_USE_FALLBACK
if (fd == ps->kp_fd) {
res += get_kp_results(ps,
@@ -1891,7 +1971,7 @@ save_poll_result(ErtsPollSet ps, ErtsPollResFd pr[], int max_res,
#endif
pr[res].events |= ERTS_POLL_EV_IN;
}
- if (oset && FD_ISSET(fd, oset)) {
+ if (oset && ERTS_FD_ISSET(fd, oset)) {
pr[res].events |= ERTS_POLL_EV_OUT;
}
ASSERT(pr[res].events);
@@ -1992,14 +2072,14 @@ check_fd_events(ErtsPollSet ps, SysTimeval *tv, int max_res)
#elif ERTS_POLL_USE_SELECT /* --- select ------------------------------ */
SysTimeval to = *tv;
- ps->res_input_fds = ps->input_fds;
- ps->res_output_fds = ps->output_fds;
-
+ ERTS_FD_COPY(&ps->input_fds, &ps->res_input_fds);
+ ERTS_FD_COPY(&ps->output_fds, &ps->res_output_fds);
+
#ifdef ERTS_SMP
if (to.tv_sec || to.tv_usec)
erts_thr_progress_prepare_wait(NULL);
#endif
- res = select(ps->max_fd + 1,
+ res = ERTS_SELECT(ps->max_fd + 1,
&ps->res_input_fds,
&ps->res_output_fds,
NULL,
@@ -2027,7 +2107,7 @@ check_fd_events(ErtsPollSet ps, SysTimeval *tv, int max_res)
ERTS_POLLSET_LOCK(ps);
handle_update_requests(ps);
ERTS_POLLSET_UNLOCK(ps);
- res = select(ps->max_fd + 1,
+ res = ERTS_SELECT(ps->max_fd + 1,
&ps->res_input_fds,
&ps->res_output_fds,
NULL,
@@ -2233,7 +2313,8 @@ ERTS_POLL_EXPORT(erts_poll_init)(void)
max_fds = OPEN_MAX;
#endif
-#if ERTS_POLL_USE_SELECT && defined(FD_SETSIZE)
+#if ERTS_POLL_USE_SELECT && defined(FD_SETSIZE) && \
+ !defined(_DARWIN_UNLIMITED_SELECT)
if (max_fds > FD_SETSIZE)
max_fds = FD_SETSIZE;
#endif
@@ -2301,10 +2382,21 @@ ERTS_POLL_EXPORT(erts_poll_create_pollset)(void)
#if ERTS_POLL_USE_FALLBACK
ps->no_select_fds = 0;
#endif
- FD_ZERO(&ps->input_fds);
- FD_ZERO(&ps->res_input_fds);
- FD_ZERO(&ps->output_fds);
- FD_ZERO(&ps->res_output_fds);
+#ifdef _DARWIN_UNLIMITED_SELECT
+ ps->input_fds.sz = 0;
+ ps->input_fds.ptr = NULL;
+ ps->res_input_fds.sz = 0;
+ ps->res_input_fds.ptr = NULL;
+ ps->output_fds.sz = 0;
+ ps->output_fds.ptr = NULL;
+ ps->res_output_fds.sz = 0;
+ ps->res_output_fds.ptr = NULL;
+#else
+ ERTS_FD_ZERO(&ps->input_fds);
+ ERTS_FD_ZERO(&ps->res_input_fds);
+ ERTS_FD_ZERO(&ps->output_fds);
+ ERTS_FD_ZERO(&ps->res_output_fds);
+#endif
#endif
#if ERTS_POLL_USE_UPDATE_REQUESTS_QUEUE
ps->update_requests.next = NULL;
@@ -2382,6 +2474,16 @@ ERTS_POLL_EXPORT(erts_poll_destroy_pollset)(ErtsPollSet ps)
if (ps->poll_fds)
erts_free(ERTS_ALC_T_POLL_FDS, (void *) ps->poll_fds);
#elif ERTS_POLL_USE_SELECT
+#ifdef _DARWIN_UNLIMITED_SELECT
+ if (ps->input_fds.ptr)
+ erts_free(ERTS_ALC_T_SELECT_FDS, (void *) ps->input_fds.ptr);
+ if (ps->res_input_fds.ptr)
+ erts_free(ERTS_ALC_T_SELECT_FDS, (void *) ps->res_input_fds.ptr);
+ if (ps->output_fds.ptr)
+ erts_free(ERTS_ALC_T_SELECT_FDS, (void *) ps->output_fds.ptr);
+ if (ps->res_output_fds.ptr)
+ erts_free(ERTS_ALC_T_SELECT_FDS, (void *) ps->res_output_fds.ptr);
+#endif
#endif
#if ERTS_POLL_USE_UPDATE_REQUESTS_QUEUE
{
@@ -2445,6 +2547,10 @@ ERTS_POLL_EXPORT(erts_poll_info)(ErtsPollSet ps, ErtsPollInfo *pip)
#if ERTS_POLL_USE_POLL
size += ps->poll_fds_len*sizeof(struct pollfd);
#elif ERTS_POLL_USE_SELECT
+#ifdef _DARWIN_UNLIMITED_SELECT
+ size += ps->input_fds.sz + ps->res_input_fds.sz
+ + ps->output_fds.sz + ps->res_output_fds.sz;
+#endif
#endif
#if ERTS_POLL_USE_UPDATE_REQUESTS_QUEUE
diff --git a/erts/emulator/sys/win32/sys_time.c b/erts/emulator/sys/win32/sys_time.c
index 2f2dfc8197..f7f0161b58 100644
--- a/erts/emulator/sys/win32/sys_time.c
+++ b/erts/emulator/sys/win32/sys_time.c
@@ -63,6 +63,8 @@
static SysHrTime wrap = 0;
static DWORD last_tick_count = 0;
+static erts_smp_mtx_t wrap_lock;
+static ULONGLONG (WINAPI *pGetTickCount64)(void) = NULL;
/* Getting timezone information is a heavy operation, so we want to do this
only once */
@@ -77,11 +79,23 @@ static int days_in_month[2][13] = {
int
sys_init_time(void)
{
+ char kernel_dll_name[] = "kernel32";
+ HMODULE module;
+
+ module = GetModuleHandle(kernel_dll_name);
+ pGetTickCount64 = (module != NULL) ?
+ (ULONGLONG (WINAPI *)(void))
+ GetProcAddress(module,"GetTickCount64") :
+ NULL;
+
if(GetTimeZoneInformation(&static_tzi) &&
static_tzi.StandardDate.wMonth != 0 &&
static_tzi.DaylightDate.wMonth != 0) {
have_static_tzi = 1;
}
+
+ erts_smp_mtx_init(&wrap_lock, "sys_gethrtime");
+
return 1;
}
@@ -363,15 +377,39 @@ sys_gettimeofday(SysTimeval *tv)
EPOCH_JULIAN_DIFF);
}
+extern int erts_initialized;
SysHrTime
sys_gethrtime(void)
{
- DWORD ticks = (SysHrTime) (GetTickCount() & 0x7FFFFFFF);
- if (ticks < (SysHrTime) last_tick_count) {
- wrap += LL_LITERAL(1) << 31;
+ if (pGetTickCount64 != NULL) {
+ return ((SysHrTime) pGetTickCount64()) * LL_LITERAL(1000000);
+ } else {
+ DWORD ticks;
+ SysHrTime res;
+ erts_smp_mtx_lock(&wrap_lock);
+ ticks = (SysHrTime) (GetTickCount() & 0x7FFFFFFF);
+ if (ticks < (SysHrTime) last_tick_count) {
+ /* Detect a race that should no longer be here... */
+ if ((((SysHrTime) last_tick_count) - ((SysHrTime) ticks)) > 1000) {
+ wrap += LL_LITERAL(1) << 31;
+ } else {
+ /*
+ * XXX Debug: Violates locking order, remove all this,
+ * after testing!
+ */
+ erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
+ erts_dsprintf(dsbufp, "Did not wrap when last_tick %d "
+ "and tick %d",
+ last_tick_count, ticks);
+ erts_send_error_to_logger_nogl(dsbufp);
+ ticks = last_tick_count;
+ }
+ }
+ last_tick_count = ticks;
+ res = ((((LONGLONG) ticks) + wrap) * LL_LITERAL(1000000));
+ erts_smp_mtx_unlock(&wrap_lock);
+ return res;
}
- last_tick_count = ticks;
- return ((((LONGLONG) ticks) + wrap) * LL_LITERAL(1000000));
}
clock_t
diff --git a/erts/emulator/test/port_SUITE.erl b/erts/emulator/test/port_SUITE.erl
index 13aa0f4c00..ced8b41c4b 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]).
@@ -628,16 +628,23 @@ iter_max_ports(Config) when is_list(Config) ->
iter_max_ports_test(Config) ->
- Dog = test_server:timetrap(test_server:minutes(20)),
+ Dog = test_server:timetrap(test_server:minutes(30)),
PortTest = port_test(Config),
Command = lists:concat([PortTest, " -h0 -q"]),
Iters = case os:type() of
{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/trace_SUITE.erl b/erts/emulator/test/trace_SUITE.erl
index 221b65309a..caa58ae281 100644
--- a/erts/emulator/test/trace_SUITE.erl
+++ b/erts/emulator/test/trace_SUITE.erl
@@ -34,6 +34,7 @@
system_monitor_args/1, more_system_monitor_args/1,
system_monitor_long_gc_1/1, system_monitor_long_gc_2/1,
system_monitor_large_heap_1/1, system_monitor_large_heap_2/1,
+ system_monitor_long_schedule/1,
bad_flag/1, trace_delivered/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -52,6 +53,7 @@ all() ->
set_on_first_spawn, system_monitor_args,
more_system_monitor_args, system_monitor_long_gc_1,
system_monitor_long_gc_2, system_monitor_large_heap_1,
+ system_monitor_long_schedule,
system_monitor_large_heap_2, bad_flag, trace_delivered].
groups() ->
@@ -508,6 +510,65 @@ try_l(Val) ->
?line {Self,Comb1} = erlang:system_monitor(undefined),
?line [{large_heap,Val},{long_gc,Arbitrary2}] = lists:sort(Comb1).
+monitor_sys(Parent) ->
+ receive
+ {monitor,Pid,long_schedule,Data} when is_pid(Pid) ->
+ io:format("Long schedule of ~w: ~w~n",[Pid,Data]),
+ Parent ! {Pid,Data},
+ monitor_sys(Parent);
+ {monitor,Port,long_schedule,Data} when is_port(Port) ->
+ {name,Name} = erlang:port_info(Port,name),
+ io:format("Long schedule of ~w (~p): ~w~n",[Port,Name,Data]),
+ Parent ! {Port,Data},
+ monitor_sys(Parent);
+ Other ->
+ erlang:display(Other)
+ end.
+
+start_monitor() ->
+ Parent = self(),
+ Mpid = spawn_link(fun() -> monitor_sys(Parent) end),
+ erlang:system_monitor(Mpid,[{long_schedule,100}]),
+ erlang:yield(), % Need to be rescheduled for the trace to take
+ ok.
+
+system_monitor_long_schedule(suite) ->
+ [];
+system_monitor_long_schedule(doc) ->
+ ["Tests erlang:system_monitor(Pid, [{long_schedule,Time}])"];
+system_monitor_long_schedule(Config) when is_list(Config) ->
+ Path = ?config(data_dir, Config),
+ erl_ddll:start(),
+ case (catch load_driver(Path, slow_drv)) of
+ ok ->
+ do_system_monitor_long_schedule();
+ _Error ->
+ {skip, "Unable to load slow_drv (windows or no usleep()?)"}
+ end.
+do_system_monitor_long_schedule() ->
+ start_monitor(),
+ Port = open_port({spawn_driver,slow_drv}, []),
+ "ok" = erlang:port_control(Port,0,[]),
+ Self = self(),
+ receive
+ {Self,L} when is_list(L) ->
+ ok
+ after 1000 ->
+ ?t:fail(no_trace_of_pid)
+ end,
+ "ok" = erlang:port_control(Port,1,[]),
+ "ok" = erlang:port_control(Port,2,[]),
+ receive
+ {Port,LL} when is_list(LL) ->
+ ok
+ after 1000 ->
+ ?t:fail(no_trace_of_port)
+ end,
+ port_close(Port),
+ erlang:system_monitor(undefined),
+ ok.
+
+
-define(LONG_GC_SLEEP, 670).
system_monitor_long_gc_1(suite) ->
@@ -1521,3 +1582,11 @@ issue_non_empty_runq_warning(DeadLine, RQLen) ->
" Processes info: ~p~n",
[DeadLine div 1000, RQLen, self(), PIs]),
receive after 1000 -> ok end.
+
+load_driver(Dir, Driver) ->
+ case erl_ddll:load_driver(Dir, Driver) of
+ ok -> ok;
+ {error, Error} = Res ->
+ io:format("~s\n", [erl_ddll:format_error(Error)]),
+ Res
+ end.
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 947fbe7c24..cdc13a656d 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/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 a8a4425b63..e016a50c4c 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -188,6 +188,7 @@
'busy_port' |
'busy_dist_port' |
{'long_gc', non_neg_integer()} |
+ {'long_schedule', non_neg_integer()} |
{'large_heap', non_neg_integer()}.
@@ -3553,10 +3554,8 @@ sched_wall_time(Ref, N, Acc) ->
{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().
+-spec erlang:gather_gc_info_result(Ref) ->
+ {number(),number(),0} when Ref :: reference().
gather_gc_info_result(Ref) when erlang:is_reference(Ref) ->
gc_info(Ref, erlang:system_info(schedulers), {0,0}).
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/test/z_SUITE.erl b/erts/test/z_SUITE.erl
index 78968ed405..9abc73c081 100644
--- a/erts/test/z_SUITE.erl
+++ b/erts/test/z_SUITE.erl
@@ -190,8 +190,13 @@ file_inspect(#core_search_conf{file = File}, Core) ->
probably_a_core
end.
-mk_readable(F) ->
- catch file:write_file_info(F, #file_info{mode = 8#00444}).
+mk_readable(F) ->
+ try
+ {ok, Old} = file:read_file_info(F),
+ file:write_file_info(F, Old#file_info{mode = 8#00444})
+ catch
+ _:_ -> io:format("Failed to \"chmod\" core file ~p\n", [F])
+ end.
ignore_core(C) ->
filelib:is_regular(filename:join([filename:dirname(C),
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..d279e9697f 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,21 +345,16 @@ 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),
demit({"Result = "}), %dbg
%% return value as record
- RecordName = lists:concat([get_record_name_prefix(),
- asn1ct_gen:list2rname(Typename)]),
+ RecordName = record_name(Typename),
case Typename of
['EXTERNAL'] ->
emit({" OldFormat={'",RecordName,
@@ -401,6 +376,29 @@ gen_dec_constructed_imm_2(Typename, CompList,
end,
emit({{curr,bytes},"}"}).
+%% record_name([TypeName]) -> RecordNameString
+%% Construct a record name for the constructed type, ignoring any
+%% fake sequences that are used to represent an extension addition
+%% group. Such fake sequences never appear as a top type, and their
+%% name always start with "ExtAddGroup".
+
+record_name(Typename0) ->
+ [TopType|Typename1] = lists:reverse(Typename0),
+ Typename = filter_ext_add_groups(Typename1, [TopType]),
+ lists:concat([get_record_name_prefix(),
+ asn1ct_gen:list2rname(Typename)]).
+
+filter_ext_add_groups([H|T], Acc) when is_atom(H) ->
+ case atom_to_list(H) of
+ "ExtAddGroup"++_ ->
+ filter_ext_add_groups(T, Acc);
+ _ ->
+ filter_ext_add_groups(T, [H|Acc])
+ end;
+filter_ext_add_groups([H|T], Acc) ->
+ filter_ext_add_groups(T, [H|Acc]);
+filter_ext_add_groups([], Acc) -> Acc.
+
textual_order([#'ComponentType'{textual_order=undefined}|_],TermList) ->
TermList;
textual_order(CompList,TermList) when is_list(CompList) ->
@@ -489,7 +487,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 +501,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 +514,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 +552,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 +563,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 +576,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 +606,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 +618,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 +644,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 +652,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 +976,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 +997,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 +1026,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 +1192,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 +1280,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 +1299,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 +1343,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 +1375,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 +1389,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 +1406,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 +1426,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 +1438,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 +1461,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 +1486,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,40 +1541,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,
- EncObj =
- case asn1ct_gen:get_constraint(Type#type.constraint,
- componentrelation) of
- no ->
- 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,
+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
@@ -1646,106 +1556,157 @@ gen_enc_choice2(Erule,TopType,[H1|T], Pos, Ext)
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 +1777,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 +1788,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..69d9d51bf1 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) ->
@@ -268,19 +250,10 @@ emit_enc_enumerated_case(Erules, C, EnumName, Count) ->
enc_ext_and_val(per, E, F, Args) ->
[E|apply(asn1ct_eval_per, F, Args)];
enc_ext_and_val(uper, E, F, Args) ->
- <<E:1,(apply(asn1ct_eval_uper, F, Args))/bitstring>>.
+ Bs = list_to_bitstring([apply(asn1ct_eval_uper, F, Args)]),
+ <<E:1,Bs/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 +274,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 +301,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 +394,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 +405,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 +425,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 +436,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 +447,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 +466,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 +480,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 +527,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 +561,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 +570,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 +629,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 +637,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 +701,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 +774,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 +795,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 +842,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 +891,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 +922,6 @@ gen_internal_funcs(Erules,[TypeDef|Rest]) ->
%% DECODING *****************************
%%***************************************
-
gen_decode(Erules,Type) when is_record(Type,typedef) ->
D = Type,
emit({nl,nl}),
@@ -1054,7 +958,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 +970,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 +994,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 +1048,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 +1078,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..bf362db843 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]).
@@ -85,7 +86,7 @@ per_dec_enumerated(BaseNamedList, NamedListExt0, Aligned) ->
bit_case(Base, Ext).
per_dec_extension_map(Aligned) ->
- Len = {add,per_dec_normally_small_number(Aligned),1},
+ Len = per_dec_normally_small_length(Aligned),
{get_bits,Len,[1,bitstring]}.
per_dec_integer(Constraint0, Aligned) ->
@@ -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);
@@ -231,6 +240,11 @@ per_dec_normally_small_number(Aligned) ->
Unlimited = per_decode_semi_constrained(0, Aligned),
bit_case(Small, Unlimited).
+per_dec_normally_small_length(Aligned) ->
+ Small = {add,{get_bits,6,[1]},1},
+ Unlimited = decode_unconstrained_length(false, Aligned),
+ bit_case(Small, Unlimited).
+
per_decode_semi_constrained(Lb, Aligned) ->
add_lb(Lb, {get_bits,decode_unconstrained_length(false, Aligned),[8]}).
@@ -700,7 +714,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..f00b23a8b2 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,
@@ -454,10 +454,13 @@ testSeqDefault(Config, Rule, Opts) ->
testSeqExtension(Config) -> test(Config, fun testSeqExtension/3).
testSeqExtension(Config, Rule, Opts) ->
- asn1_test_lib:compile_all(["External", "SeqExtension"], Config,
+ asn1_test_lib:compile_all(["External",
+ "SeqExtension",
+ "SeqExtension2"],
+ Config,
[Rule|Opts]),
DataDir = ?config(data_dir, Config),
- testSeqExtension:main(DataDir, [Rule|Opts]).
+ testSeqExtension:main(Rule, DataDir, [Rule|Opts]).
testSeqExternal(Config) -> test(Config, fun testSeqExternal/3).
testSeqExternal(Config, Rule, Opts) ->
@@ -655,7 +658,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 +743,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 +857,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 +903,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 +1021,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 +1084,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 +1101,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..8dc5f3d7e1 100644
--- a/lib/asn1/test/asn1_SUITE_data/EnumExt.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/EnumExt.asn1
@@ -1,28 +1,55 @@
-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
+}
+
+EnumExtBig ::= ENUMERATED {
+ base,
+ ...,
+ e00,e01,e02,e03,e04,e05,e06,e07,e08,e09,e0a,e0b,e0c,e0d,e0e,e0f,
+ e10,e11,e12,e13,e14,e15,e16,e17,e18,e19,e1a,e1b,e1c,e1d,e1e,e1f,
+ e20,e21,e22,e23,e24,e25,e26,e27,e28,e29,e2a,e2b,e2c,e2d,e2e,e2f,
+ e30,e31,e32,e33,e34,e35,e36,e37,e38,e39,e3a,e3b,e3c,e3d,e3e,e3f,
+ e40,e41,e42,e43,e44,e45,e46,e47,e48,e49,e4a,e4b,e4c,e4d,e4e,e4f,
+ e50,e51,e52,e53,e54,e55,e56,e57,e58,e59,e5a,e5b,e5c,e5d,e5e,e5f,
+ e60,e61,e62,e63,e64,e65,e66,e67,e68,e69,e6a,e6b,e6c,e6d,e6e,e6f,
+ e70,e71,e72,e73,e74,e75,e76,e77,e78,e79,e7a,e7b,e7c,e7d,e7e,e7f,
+ e80
+}
+
+SeqBig ::= SEQUENCE {
+ b BOOLEAN,
+ e EnumExtBig,
+ i INTEGER
+}
+
+END
+
diff --git a/lib/asn1/test/asn1_SUITE_data/Extension-Addition-Group.asn b/lib/asn1/test/asn1_SUITE_data/Extension-Addition-Group.asn
index b07dcd8baa..0e905d8839 100644
--- a/lib/asn1/test/asn1_SUITE_data/Extension-Addition-Group.asn
+++ b/lib/asn1/test/asn1_SUITE_data/Extension-Addition-Group.asn
@@ -118,4 +118,23 @@ AC-BarringConfig ::= SEQUENCE {
ac-BarringForSpecialAC BIT STRING (SIZE(5))
}
+InlinedSeq ::= SEQUENCE {
+ ...,
+ [[
+ s SEQUENCE {
+ a INTEGER,
+ b BOOLEAN
+ }
+ ]]
+}
+
+-- 'ExtAddGroup1' is used internally to represent fake sequences for
+-- extension addition groups. Make sure that a real sequence with that
+-- name at the top-level doesn't cause a problem.
+
+ExtAddGroup1 ::= SEQUENCE {
+ x INTEGER,
+ y 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/SeqExtension2.asn1 b/lib/asn1/test/asn1_SUITE_data/SeqExtension2.asn1
new file mode 100644
index 0000000000..44900d9d39
--- /dev/null
+++ b/lib/asn1/test/asn1_SUITE_data/SeqExtension2.asn1
@@ -0,0 +1,208 @@
+SeqExtension2 DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+SeqExt66 ::= SEQUENCE {
+ ...,
+ i0 INTEGER (0..127) OPTIONAL,
+ i1 INTEGER (0..127) OPTIONAL,
+ i2 INTEGER (0..127) OPTIONAL,
+ i3 INTEGER (0..127) OPTIONAL,
+ i4 INTEGER (0..127) OPTIONAL,
+ i5 INTEGER (0..127) OPTIONAL,
+ i6 INTEGER (0..127) OPTIONAL,
+ i7 INTEGER (0..127) OPTIONAL,
+ i8 INTEGER (0..127) OPTIONAL,
+ i9 INTEGER (0..127) OPTIONAL,
+ i10 INTEGER (0..127) OPTIONAL,
+ i11 INTEGER (0..127) OPTIONAL,
+ i12 INTEGER (0..127) OPTIONAL,
+ i13 INTEGER (0..127) OPTIONAL,
+ i14 INTEGER (0..127) OPTIONAL,
+ i15 INTEGER (0..127) OPTIONAL,
+ i16 INTEGER (0..127) OPTIONAL,
+ i17 INTEGER (0..127) OPTIONAL,
+ i18 INTEGER (0..127) OPTIONAL,
+ i19 INTEGER (0..127) OPTIONAL,
+ i20 INTEGER (0..127) OPTIONAL,
+ i21 INTEGER (0..127) OPTIONAL,
+ i22 INTEGER (0..127) OPTIONAL,
+ i23 INTEGER (0..127) OPTIONAL,
+ i24 INTEGER (0..127) OPTIONAL,
+ i25 INTEGER (0..127) OPTIONAL,
+ i26 INTEGER (0..127) OPTIONAL,
+ i27 INTEGER (0..127) OPTIONAL,
+ i28 INTEGER (0..127) OPTIONAL,
+ i29 INTEGER (0..127) OPTIONAL,
+ i30 INTEGER (0..127) OPTIONAL,
+ i31 INTEGER (0..127) OPTIONAL,
+ i32 INTEGER (0..127) OPTIONAL,
+ i33 INTEGER (0..127) OPTIONAL,
+ i34 INTEGER (0..127) OPTIONAL,
+ i35 INTEGER (0..127) OPTIONAL,
+ i36 INTEGER (0..127) OPTIONAL,
+ i37 INTEGER (0..127) OPTIONAL,
+ i38 INTEGER (0..127) OPTIONAL,
+ i39 INTEGER (0..127) OPTIONAL,
+ i40 INTEGER (0..127) OPTIONAL,
+ i41 INTEGER (0..127) OPTIONAL,
+ i42 INTEGER (0..127) OPTIONAL,
+ i43 INTEGER (0..127) OPTIONAL,
+ i44 INTEGER (0..127) OPTIONAL,
+ i45 INTEGER (0..127) OPTIONAL,
+ i46 INTEGER (0..127) OPTIONAL,
+ i47 INTEGER (0..127) OPTIONAL,
+ i48 INTEGER (0..127) OPTIONAL,
+ i49 INTEGER (0..127) OPTIONAL,
+ i50 INTEGER (0..127) OPTIONAL,
+ i51 INTEGER (0..127) OPTIONAL,
+ i52 INTEGER (0..127) OPTIONAL,
+ i53 INTEGER (0..127) OPTIONAL,
+ i54 INTEGER (0..127) OPTIONAL,
+ i55 INTEGER (0..127) OPTIONAL,
+ i56 INTEGER (0..127) OPTIONAL,
+ i57 INTEGER (0..127) OPTIONAL,
+ i58 INTEGER (0..127) OPTIONAL,
+ i59 INTEGER (0..127) OPTIONAL,
+ i60 INTEGER (0..127) OPTIONAL,
+ i61 INTEGER (0..127) OPTIONAL,
+ i62 INTEGER (0..127) OPTIONAL,
+ i63 INTEGER (0..127) OPTIONAL,
+ i64 INTEGER (0..127) OPTIONAL,
+ i65 INTEGER (0..127) OPTIONAL
+}
+
+SeqExt130 ::= SEQUENCE {
+ ...,
+ i0 INTEGER (0..255) OPTIONAL,
+ i1 INTEGER (0..255) OPTIONAL,
+ i2 INTEGER (0..255) OPTIONAL,
+ i3 INTEGER (0..255) OPTIONAL,
+ i4 INTEGER (0..255) OPTIONAL,
+ i5 INTEGER (0..255) OPTIONAL,
+ i6 INTEGER (0..255) OPTIONAL,
+ i7 INTEGER (0..255) OPTIONAL,
+ i8 INTEGER (0..255) OPTIONAL,
+ i9 INTEGER (0..255) OPTIONAL,
+ i10 INTEGER (0..255) OPTIONAL,
+ i11 INTEGER (0..255) OPTIONAL,
+ i12 INTEGER (0..255) OPTIONAL,
+ i13 INTEGER (0..255) OPTIONAL,
+ i14 INTEGER (0..255) OPTIONAL,
+ i15 INTEGER (0..255) OPTIONAL,
+ i16 INTEGER (0..255) OPTIONAL,
+ i17 INTEGER (0..255) OPTIONAL,
+ i18 INTEGER (0..255) OPTIONAL,
+ i19 INTEGER (0..255) OPTIONAL,
+ i20 INTEGER (0..255) OPTIONAL,
+ i21 INTEGER (0..255) OPTIONAL,
+ i22 INTEGER (0..255) OPTIONAL,
+ i23 INTEGER (0..255) OPTIONAL,
+ i24 INTEGER (0..255) OPTIONAL,
+ i25 INTEGER (0..255) OPTIONAL,
+ i26 INTEGER (0..255) OPTIONAL,
+ i27 INTEGER (0..255) OPTIONAL,
+ i28 INTEGER (0..255) OPTIONAL,
+ i29 INTEGER (0..255) OPTIONAL,
+ i30 INTEGER (0..255) OPTIONAL,
+ i31 INTEGER (0..255) OPTIONAL,
+ i32 INTEGER (0..255) OPTIONAL,
+ i33 INTEGER (0..255) OPTIONAL,
+ i34 INTEGER (0..255) OPTIONAL,
+ i35 INTEGER (0..255) OPTIONAL,
+ i36 INTEGER (0..255) OPTIONAL,
+ i37 INTEGER (0..255) OPTIONAL,
+ i38 INTEGER (0..255) OPTIONAL,
+ i39 INTEGER (0..255) OPTIONAL,
+ i40 INTEGER (0..255) OPTIONAL,
+ i41 INTEGER (0..255) OPTIONAL,
+ i42 INTEGER (0..255) OPTIONAL,
+ i43 INTEGER (0..255) OPTIONAL,
+ i44 INTEGER (0..255) OPTIONAL,
+ i45 INTEGER (0..255) OPTIONAL,
+ i46 INTEGER (0..255) OPTIONAL,
+ i47 INTEGER (0..255) OPTIONAL,
+ i48 INTEGER (0..255) OPTIONAL,
+ i49 INTEGER (0..255) OPTIONAL,
+ i50 INTEGER (0..255) OPTIONAL,
+ i51 INTEGER (0..255) OPTIONAL,
+ i52 INTEGER (0..255) OPTIONAL,
+ i53 INTEGER (0..255) OPTIONAL,
+ i54 INTEGER (0..255) OPTIONAL,
+ i55 INTEGER (0..255) OPTIONAL,
+ i56 INTEGER (0..255) OPTIONAL,
+ i57 INTEGER (0..255) OPTIONAL,
+ i58 INTEGER (0..255) OPTIONAL,
+ i59 INTEGER (0..255) OPTIONAL,
+ i60 INTEGER (0..255) OPTIONAL,
+ i61 INTEGER (0..255) OPTIONAL,
+ i62 INTEGER (0..255) OPTIONAL,
+ i63 INTEGER (0..255) OPTIONAL,
+ i64 INTEGER (0..255) OPTIONAL,
+ i65 INTEGER (0..255) OPTIONAL,
+ i66 INTEGER (0..255) OPTIONAL,
+ i67 INTEGER (0..255) OPTIONAL,
+ i68 INTEGER (0..255) OPTIONAL,
+ i69 INTEGER (0..255) OPTIONAL,
+ i70 INTEGER (0..255) OPTIONAL,
+ i71 INTEGER (0..255) OPTIONAL,
+ i72 INTEGER (0..255) OPTIONAL,
+ i73 INTEGER (0..255) OPTIONAL,
+ i74 INTEGER (0..255) OPTIONAL,
+ i75 INTEGER (0..255) OPTIONAL,
+ i76 INTEGER (0..255) OPTIONAL,
+ i77 INTEGER (0..255) OPTIONAL,
+ i78 INTEGER (0..255) OPTIONAL,
+ i79 INTEGER (0..255) OPTIONAL,
+ i80 INTEGER (0..255) OPTIONAL,
+ i81 INTEGER (0..255) OPTIONAL,
+ i82 INTEGER (0..255) OPTIONAL,
+ i83 INTEGER (0..255) OPTIONAL,
+ i84 INTEGER (0..255) OPTIONAL,
+ i85 INTEGER (0..255) OPTIONAL,
+ i86 INTEGER (0..255) OPTIONAL,
+ i87 INTEGER (0..255) OPTIONAL,
+ i88 INTEGER (0..255) OPTIONAL,
+ i89 INTEGER (0..255) OPTIONAL,
+ i90 INTEGER (0..255) OPTIONAL,
+ i91 INTEGER (0..255) OPTIONAL,
+ i92 INTEGER (0..255) OPTIONAL,
+ i93 INTEGER (0..255) OPTIONAL,
+ i94 INTEGER (0..255) OPTIONAL,
+ i95 INTEGER (0..255) OPTIONAL,
+ i96 INTEGER (0..255) OPTIONAL,
+ i97 INTEGER (0..255) OPTIONAL,
+ i98 INTEGER (0..255) OPTIONAL,
+ i99 INTEGER (0..255) OPTIONAL,
+ i100 INTEGER (0..255) OPTIONAL,
+ i101 INTEGER (0..255) OPTIONAL,
+ i102 INTEGER (0..255) OPTIONAL,
+ i103 INTEGER (0..255) OPTIONAL,
+ i104 INTEGER (0..255) OPTIONAL,
+ i105 INTEGER (0..255) OPTIONAL,
+ i106 INTEGER (0..255) OPTIONAL,
+ i107 INTEGER (0..255) OPTIONAL,
+ i108 INTEGER (0..255) OPTIONAL,
+ i109 INTEGER (0..255) OPTIONAL,
+ i110 INTEGER (0..255) OPTIONAL,
+ i111 INTEGER (0..255) OPTIONAL,
+ i112 INTEGER (0..255) OPTIONAL,
+ i113 INTEGER (0..255) OPTIONAL,
+ i114 INTEGER (0..255) OPTIONAL,
+ i115 INTEGER (0..255) OPTIONAL,
+ i116 INTEGER (0..255) OPTIONAL,
+ i117 INTEGER (0..255) OPTIONAL,
+ i118 INTEGER (0..255) OPTIONAL,
+ i119 INTEGER (0..255) OPTIONAL,
+ i120 INTEGER (0..255) OPTIONAL,
+ i121 INTEGER (0..255) OPTIONAL,
+ i122 INTEGER (0..255) OPTIONAL,
+ i123 INTEGER (0..255) OPTIONAL,
+ i124 INTEGER (0..255) OPTIONAL,
+ i125 INTEGER (0..255) OPTIONAL,
+ i126 INTEGER (0..255) OPTIONAL,
+ i127 INTEGER (0..255) OPTIONAL,
+ i128 INTEGER (0..255) OPTIONAL,
+ i129 INTEGER (0..255) OPTIONAL
+}
+
+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..8e21e6ca84 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,41 @@
%%%-------------------------------------------------------------------
-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),
+
+ roundtrip('InlinedSeq', #'InlinedSeq'{s=#'InlinedSeq_s'{a=42,b=true}}),
+ roundtrip('ExtAddGroup1', #'ExtAddGroup1'{x=42,y=1023}),
+
+ 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 +140,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..7d7364e2a4 100644
--- a/lib/asn1/test/asn1_test_lib.erl
+++ b/lib/asn1/test/asn1_test_lib.erl
@@ -22,6 +22,7 @@
-export([compile/3]).
-export([compile_all/3]).
-export([compile_erlang/3]).
+-export([hex_to_bin/1]).
-export([ticket_7407_compile/2,ticket_7407_code/1, ticket_7678/2,
ticket_7708/2, ticket_7763/1, ticket_7876/3]).
@@ -39,17 +40,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 +60,14 @@ 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]).
+
+hex_to_bin(S) ->
+ << <<(hex2num(C)):4>> || C <- S, C =/= $\s >>.
+
+%%%
+%%% Internal functions.
+%%%
should_load(File, Options) ->
case lists:member(abs, Options) of
@@ -78,6 +87,10 @@ strip_extension(File, Ext) when Ext == ".asn"; Ext == ".set"; Ext == ".asn1"->
strip_extension(File, _Ext) ->
File.
+hex2num(C) when $0 =< C, C =< $9 -> C - $0;
+hex2num(C) when $A =< C, C =< $F -> C - $A + 10;
+hex2num(C) when $a =< C, C =< $f -> C - $a + 10.
+
ticket_7407_compile(Config,Option) ->
?line DataDir = ?config(data_dir,Config),
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..14e508d2b5 100644
--- a/lib/asn1/test/testConstraints.erl
+++ b/lib/asn1/test/testConstraints.erl
@@ -122,32 +122,118 @@ int_constraints(Rules) ->
range_error(Rules, 'X1', 21),
%%==========================================================
+ %% SemiConstrained
+ %%==========================================================
+
+ roundtrip('SemiConstrained', 100),
+ v_roundtrip(Rules, 'SemiConstrained', 100+128),
+ roundtrip('SemiConstrained', 397249742397243),
+ roundtrip('SemiConstrained', 100 + 1 bsl 128*8),
+ roundtrip('SemiConstrained', 100 + 1 bsl 256*8),
+
+ roundtrip('NegSemiConstrained', -128),
+ v_roundtrip(Rules, 'NegSemiConstrained', 0),
+ roundtrip('NegSemiConstrained', -1),
+ roundtrip('NegSemiConstrained', 500),
+
+ roundtrip('SemiConstrainedExt', -65536),
+ roundtrip('SemiConstrainedExt', 0),
+ roundtrip('SemiConstrainedExt', 42),
+ v_roundtrip(Rules, 'SemiConstrainedExt', 42+128),
+ roundtrip('SemiConstrainedExt', 100),
+ roundtrip('SemiConstrainedExt', 47777789),
+ roundtrip('SemiConstrainedExt', 42 + 1 bsl 128*8),
+ roundtrip('SemiConstrainedExt', 42 + 1 bsl 256*8),
+
+ roundtrip('NegSemiConstrainedExt', -1023),
+ roundtrip('NegSemiConstrainedExt', -128),
+ roundtrip('NegSemiConstrainedExt', -1),
+ v_roundtrip(Rules, 'NegSemiConstrainedExt', 0),
+ 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.
+
+%% PER: Ensure that if the lower bound is Lb, Lb+16#80 is encoded
+%% in two bytes as 16#0180. (Not in three bytes as 16#010080.)
+v(ber, 'SemiConstrained', 100+128) -> "020200E4";
+v(per, 'SemiConstrained', 100+128) -> "0180";
+v(uper, 'SemiConstrained', 100+128) -> "0180";
+v(ber, 'NegSemiConstrained', 0) -> "020100";
+v(per, 'NegSemiConstrained', 0) -> "0180";
+v(uper, 'NegSemiConstrained', 0) -> "0180";
+v(ber, 'SemiConstrainedExt', 42+128) -> "020200AA";
+v(per, 'SemiConstrainedExt', 42+128) -> "000180";
+v(uper, 'SemiConstrainedExt', 42+128) -> "00C000";
+v(ber, 'NegSemiConstrainedExt', 0) -> "020100";
+v(per, 'NegSemiConstrainedExt', 0) -> "000180";
+v(uper, 'NegSemiConstrainedExt', 0) -> "00C000".
+
+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),
?line {error,_Reason} =
asn1_wrapper:encode('Constraints','AnotherThing',fred3).
+v_roundtrip(Erule, Type, Value) ->
+ Encoded = asn1_test_lib:hex_to_bin(v(Erule, Type, Value)),
+ Encoded = roundtrip('Constraints', Type, Value).
+
roundtrip(Type, Value) ->
roundtrip('Constraints', Type, Value).
roundtrip(Module, Type, Value) ->
{ok,Encoded} = Module:encode(Type, Value),
{ok,Value} = Module:decode(Type, Encoded),
- ok.
+ Encoded.
+
+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..8779f3b83b 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(Rule);
main(ber) ->
io:format("main(ber)~n",[]),
%% ENUMERATED with extensionmark (value is in root set)
@@ -57,9 +56,38 @@ main(ber) ->
roundtrip('Globalstate', preop),
roundtrip('Globalstate', com),
+ common(ber).
+
+common(Erule) ->
+ 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}),
+
+ [begin
+ S = io_lib:format("e~2.016.0b", [I]),
+ E = list_to_atom(lists:flatten(S)),
+ roundtrip('SeqBig', {'SeqBig',true,E,9357})
+ end || I <- lists:seq(0, 128)],
+
+ v_roundtrip(Erule, 'SeqBig', {'SeqBig',true,e40,9357}),
+ v_roundtrip(Erule, 'SeqBig', {'SeqBig',true,e80,9357}),
ok.
roundtrip(Type, Value) ->
{ok,Encoded} = 'EnumExt':encode(Type, Value),
{ok,Value} = 'EnumExt':decode(Type, Encoded),
Encoded.
+
+v_roundtrip(Erule, Type, Value) ->
+ Encoded = roundtrip(Type, Value),
+ Encoded = asn1_test_lib:hex_to_bin(v(Erule, Value)).
+
+v(ber, {'SeqBig',true,e40,9357}) -> "300A8001 FF810141 8202248D";
+v(ber, {'SeqBig',true,e80,9357}) -> "300B8001 FF810200 81820224 8D";
+v(per, {'SeqBig',true,e40,9357}) -> "E0014002 248D";
+v(per, {'SeqBig',true,e80,9357}) -> "E0018002 248D";
+v(uper, {'SeqBig',true,e40,9357}) -> "E0280044 91A0";
+v(uper, {'SeqBig',true,e80,9357}) -> "E0300044 91A0".
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/testSeqExtension.erl b/lib/asn1/test/testSeqExtension.erl
index 1128d9a7c3..724f485fa0 100644
--- a/lib/asn1/test/testSeqExtension.erl
+++ b/lib/asn1/test/testSeqExtension.erl
@@ -20,7 +20,7 @@
-module(testSeqExtension).
-include("External.hrl").
--export([main/2]).
+-export([main/3]).
-include_lib("test_server/include/test_server.hrl").
@@ -32,7 +32,7 @@
-record('SeqExt6',{i1,i2,i3,i4,i5,i6,i7}).
-record('SuperSeq',{s1,s2,s3,s4,s5,s6,i}).
-main(DataDir, Opts) ->
+main(Erule, DataDir, Opts) ->
roundtrip('SeqExt1', #'SeqExt1'{}),
roundtrip('SeqExt2', #'SeqExt2'{bool=true,int=99}),
@@ -92,9 +92,38 @@ main(DataDir, Opts) ->
s5={'SeqExt5'},
s6={'SeqExt6',531,601,999,777,11953},
i=BigInt} = DecodedSuperSeq,
+
+
+ %% Test more than 64 extensions.
+ roundtrip2('SeqExt66',
+ list_to_tuple(['SeqExt66'|lists:seq(0, 65)])),
+ v_roundtrip2(Erule, 'SeqExt66',
+ list_to_tuple(['SeqExt66'|
+ lists:duplicate(65, asn1_NOVALUE)++[125]])),
+ roundtrip2('SeqExt130',
+ list_to_tuple(['SeqExt130'|lists:seq(0, 129)])),
+ v_roundtrip2(Erule, 'SeqExt130',
+ list_to_tuple(['SeqExt130'|
+ lists:duplicate(129, asn1_NOVALUE)++[199]])),
ok.
roundtrip(Type, Value) ->
{ok,Encoded} = 'SeqExtension':encode(Type, Value),
{ok,Value} = 'SeqExtension':decode(Type, Encoded),
ok.
+
+v_roundtrip2(Erule, Type, Value) ->
+ Encoded = asn1_test_lib:hex_to_bin(v(Erule, Type)),
+ Encoded = roundtrip2(Type, Value).
+
+roundtrip2(Type, Value) ->
+ {ok,Encoded} = 'SeqExtension2':encode(Type, Value),
+ {ok,Value} = 'SeqExtension2':decode(Type, Encoded),
+ Encoded.
+
+v(ber, 'SeqExt66') -> "30049F41 017D";
+v(per, 'SeqExt66') -> "C0420000 00000000 00004001 FA";
+v(uper, 'SeqExt66') -> "D0800000 00000000 00101FA0";
+v(ber, 'SeqExt130') -> "30069F81 010200C7";
+v(per, 'SeqExt130') -> "C0808200 00000000 00000000 00000000 00000040 01C7";
+v(uper, 'SeqExt130') -> "E0208000 00000000 00000000 00000000 0000101C 70".
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 9bb9817001..5c80a299f8 100644
--- a/lib/common_test/src/ct_config.erl
+++ b/lib/common_test/src/ct_config.erl
@@ -46,7 +46,7 @@
decrypt_config_file/2, decrypt_config_file/3,
get_crypt_key_from_file/0, get_crypt_key_from_file/1]).
--export([get_ref_from_name/1, get_name_from_ref/1, get_key_from_name/1]).
+-export([get_key_from_name/1]).
-export([check_config_files/1, add_default_callback/1, prepare_config_list/1]).
@@ -56,7 +56,7 @@
-define(cryptfile, ".ct_config.crypt").
--record(ct_conf,{key,value,handler,config,ref,name='_UNDEF',default=false}).
+-record(ct_conf,{key,value,handler,config,name='_UNDEF',default=false}).
start(Mode) ->
case whereis(ct_config_server) of
@@ -275,7 +275,6 @@ store_config(Config, Callback, File) when is_list(Config) ->
value=Val,
handler=Callback,
config=File,
- ref=ct_util:ct_make_ref(),
default=false}) ||
{Key,Val} <- Config].
@@ -296,13 +295,11 @@ rewrite_config(Config, Callback, File) ->
#ct_conf{key=Key,
value=Value,
handler=Callback,
- config=File,
- ref=ct_util:ct_make_ref()});
+ config=File});
RowsToUpdate ->
Inserter = fun(Row) ->
ets:insert(?attr_table,
- Row#ct_conf{value=Value,
- ref=ct_util:ct_make_ref()})
+ Row#ct_conf{value=Value})
end,
lists:foreach(Inserter, RowsToUpdate)
end
@@ -314,7 +311,7 @@ set_config(Config,Default) ->
set_config(Name,Config,Default) ->
[ets:insert(?attr_table,
- #ct_conf{key=Key,value=Val,ref=ct_util:ct_make_ref(),
+ #ct_conf{key=Key,value=Val,
name=Name,default=Default}) ||
{Key,Val} <- Config].
@@ -559,26 +556,6 @@ encrypt_config_file(SrcFileName, EncryptFileName) ->
encrypt_config_file(SrcFileName, EncryptFileName, {key,Key})
end.
-get_ref_from_name(Name) ->
- case ets:select(?attr_table,[{#ct_conf{name=Name,ref='$1',_='_'},
- [],
- ['$1']}]) of
- [Ref] ->
- {ok,Ref};
- _ ->
- {error,{no_such_name,Name}}
- end.
-
-get_name_from_ref(Ref) ->
- case ets:select(?attr_table,[{#ct_conf{name='$1',ref=Ref,_='_'},
- [],
- ['$1']}]) of
- [Name] ->
- {ok,Name};
- _ ->
- {error,{no_such_ref,Ref}}
- end.
-
get_key_from_name(Name) ->
case ets:select(?attr_table,[{#ct_conf{name=Name,key='$1',_='_'},
[],
diff --git a/lib/common_test/src/ct_ftp.erl b/lib/common_test/src/ct_ftp.erl
index 8790393b36..b91a521bd4 100644
--- a/lib/common_test/src/ct_ftp.erl
+++ b/lib/common_test/src/ct_ftp.erl
@@ -348,10 +348,10 @@ terminate(FtpPid,State) ->
get_handle(Pid) when is_pid(Pid) ->
{ok,Pid};
get_handle(Name) ->
- case ct_util:get_connections(Name,?MODULE) of
- {ok,[{Pid,_}|_]} ->
+ case ct_util:get_connection(Name,?MODULE) of
+ {ok,{Pid,_}} ->
{ok,Pid};
- {ok,[]} ->
+ {error,no_registered_connection} ->
open(Name);
Error ->
Error
diff --git a/lib/common_test/src/ct_gen_conn.erl b/lib/common_test/src/ct_gen_conn.erl
index 2d4b1d1f52..a5b736136f 100644
--- a/lib/common_test/src/ct_gen_conn.erl
+++ b/lib/common_test/src/ct_gen_conn.erl
@@ -26,7 +26,7 @@
-compile(export_all).
--export([start/4, stop/1]).
+-export([start/4, stop/1, get_conn_pid/1]).
-export([call/2, call/3, return/2, do_within_time/2]).
-ifdef(debug).
@@ -120,8 +120,16 @@ start(Name,Address,InitData,CallbackMod) ->
%%% Handle = handle()
%%%
%%% @doc Close the connection and stop the process managing it.
-stop(Pid) ->
- call(Pid,stop,5000).
+stop(Handle) ->
+ call(Handle,stop,5000).
+
+%%%-----------------------------------------------------------------
+%%% @spec get_conn_pid(Handle) -> ok
+%%% Handle = handle()
+%%%
+%%% @doc Return the connection pid associated with Handle
+get_conn_pid(Handle) ->
+ call(Handle,get_conn_pid).
%%%-----------------------------------------------------------------
%%% @spec log(Heading,Format,Args) -> ok
@@ -222,7 +230,8 @@ do_start(Opts) ->
receive
{connected,Pid} ->
erlang:demonitor(MRef, [flush]),
- ct_util:register_connection(Opts#gen_opts.name, Opts#gen_opts.address,
+ ct_util:register_connection(Opts#gen_opts.name,
+ Opts#gen_opts.address,
Opts#gen_opts.callback, Pid),
{ok,Pid};
{Error,Pid} ->
@@ -315,10 +324,12 @@ loop(Opts) ->
{ok, NewPid, NewState} ->
link(NewPid),
put(conn_pid,NewPid),
- loop(Opts#gen_opts{conn_pid=NewPid,cb_state=NewState});
+ loop(Opts#gen_opts{conn_pid=NewPid,
+ cb_state=NewState});
Error ->
ct_util:unregister_connection(self()),
- log("Reconnect failed. Giving up!","Reason: ~p\n",
+ log("Reconnect failed. Giving up!",
+ "Reason: ~p\n",
[Error])
end;
false ->
@@ -338,7 +349,8 @@ loop(Opts) ->
Opts#gen_opts.cb_state),
return(From,ok),
ok;
- {{retry,{Error,_Name,CPid,_Msg}}, From} when CPid == Opts#gen_opts.conn_pid ->
+ {{retry,{Error,_Name,CPid,_Msg}}, From} when
+ CPid == Opts#gen_opts.conn_pid ->
%% only retry if failure is because of a reconnection
Return = case Error of
{error,_} -> Error;
@@ -347,12 +359,16 @@ loop(Opts) ->
return(From, Return),
loop(Opts);
{{retry,{_Error,_Name,_CPid,Msg}}, From} ->
- log("Rerunning command","Connection reestablished. Rerunning command...",[]),
+ log("Rerunning command","Connection reestablished. "
+ "Rerunning command...",[]),
{Return,NewState} =
(Opts#gen_opts.callback):handle_msg(Msg,Opts#gen_opts.cb_state),
return(From, Return),
loop(Opts#gen_opts{cb_state=NewState});
- {Msg,From={Pid,_Ref}} when is_pid(Pid), Opts#gen_opts.old==true ->
+ {get_conn_pid, From} ->
+ return(From, Opts#gen_opts.conn_pid),
+ loop(Opts);
+ {Msg, From={Pid,_Ref}} when is_pid(Pid), Opts#gen_opts.old==true ->
{Return,NewState} =
(Opts#gen_opts.callback):handle_msg(Msg,Opts#gen_opts.cb_state),
return(From, Return),
@@ -372,7 +388,8 @@ loop(Opts) ->
return(From,Reply)
end;
Msg when Opts#gen_opts.forward==true ->
- case (Opts#gen_opts.callback):handle_msg(Msg,Opts#gen_opts.cb_state) of
+ case (Opts#gen_opts.callback):handle_msg(Msg,
+ Opts#gen_opts.cb_state) of
{noreply,NewState} ->
loop(Opts#gen_opts{cb_state=NewState});
{stop,NewState} ->
diff --git a/lib/common_test/src/ct_netconfc.erl b/lib/common_test/src/ct_netconfc.erl
index 1339e53780..e094ee877a 100644
--- a/lib/common_test/src/ct_netconfc.erl
+++ b/lib/common_test/src/ct_netconfc.erl
@@ -1164,13 +1164,11 @@ call(Client, Msg, Timeout, WaitStop) ->
get_handle(Client) when is_pid(Client) ->
{ok,Client};
get_handle(Client) ->
- case ct_util:get_connections(Client, ?MODULE) of
- {ok,[{Pid,_}]} ->
+ case ct_util:get_connection(Client, ?MODULE) of
+ {ok,{Pid,_}} ->
{ok,Pid};
- {ok,[]} ->
+ {error,no_registered_connection} ->
{error,{no_connection_found,Client}};
- {ok,Conns} ->
- {error,{multiple_connections_found,Client,Conns}};
Error ->
Error
end.
@@ -1302,7 +1300,8 @@ handle_data(NewData,#state{connection=Connection,buff=Buff} = State) ->
decode(Simple,State#state{buff=Rest});
{fatal_error,_Loc,Reason,_EndTags,_EventState} ->
?error(Connection#connection.name,[{parse_error,Reason},
- {data,Data}]),
+ {buffer,Buff},
+ {new_data,NewData}]),
case Reason of
{could_not_fetch_data,Msg} ->
handle_msg(Msg,State#state{buff = <<>>});
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 41d53c7b43..266ca73417 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -402,7 +402,8 @@ script_start2(Opts = #opts{vts = undefined,
Relaxed = get_start_opt(allow_user_terms, true, false, Args),
case catch ct_testspec:collect_tests_from_file(Specs1, Relaxed) of
{E,Reason} when E == error ; E == 'EXIT' ->
- {error,Reason};
+ StackTrace = erlang:get_stacktrace(),
+ {error,{invalid_testspec,{Reason,StackTrace}}};
TestSpecData ->
execute_all_specs(TestSpecData, Opts, Args, [])
end;
@@ -1101,7 +1102,8 @@ run_spec_file(Relaxed,
AbsSpecs1 = get_start_opt(join_specs, [AbsSpecs], AbsSpecs, StartOpts),
case catch ct_testspec:collect_tests_from_file(AbsSpecs1, Relaxed) of
{Error,CTReason} when Error == error ; Error == 'EXIT' ->
- exit({error,CTReason});
+ StackTrace = erlang:get_stacktrace(),
+ exit({error,{invalid_testspec,{CTReason,StackTrace}}});
TestSpecData ->
run_all_specs(TestSpecData, Opts, StartOpts, [])
end.
diff --git a/lib/common_test/src/ct_ssh.erl b/lib/common_test/src/ct_ssh.erl
index c6ea27b10e..1adc79d358 100644
--- a/lib/common_test/src/ct_ssh.erl
+++ b/lib/common_test/src/ct_ssh.erl
@@ -1328,10 +1328,10 @@ do_recv_response(SSH, Chn, Data, End, Timeout) ->
get_handle(SSH) when is_pid(SSH) ->
{ok,SSH};
get_handle(SSH) ->
- case ct_util:get_connections(SSH, ?MODULE) of
- {ok,[{Pid,_}]} ->
+ case ct_util:get_connection(SSH, ?MODULE) of
+ {ok,{Pid,_}} ->
{ok,Pid};
- {ok,[]} ->
+ {error,no_registered_connection} ->
connect(SSH);
Error ->
Error
diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl
index 4755d939e0..4092d33bc0 100644
--- a/lib/common_test/src/ct_telnet.erl
+++ b/lib/common_test/src/ct_telnet.erl
@@ -183,7 +183,8 @@ open(KeyOrName,ConnType,TargetMod,Extra) ->
end;
Bool -> Bool
end,
- log(heading(open,{KeyOrName,ConnType}),"Opening connection to: ~p",[Addr1]),
+ log(heading(open,{KeyOrName,ConnType}),
+ "Opening connection to: ~p",[Addr1]),
ct_gen_conn:start(KeyOrName,full_addr(Addr1,ConnType),
{TargetMod,KeepAlive,Extra},?MODULE)
end.
@@ -591,9 +592,9 @@ terminate(TelnPid,State) ->
get_handle(Pid) when is_pid(Pid) ->
{ok,Pid};
get_handle({Name,Type}) when Type==telnet;Type==ts1;Type==ts2 ->
- case ct_util:get_connections(Name,?MODULE) of
- {ok,Conns} when Conns /= [] ->
- case get_handle(Type,Conns) of
+ case ct_util:get_connection(Name,?MODULE) of
+ {ok,Conn} ->
+ case get_handle(Type,Conn) of
{ok,Pid} ->
{ok,Pid};
_Error ->
@@ -608,19 +609,15 @@ get_handle({Name,Type}) when Type==telnet;Type==ts1;Type==ts2 ->
Error
end
end;
- {ok,[]} ->
- {error,already_closed};
Error ->
Error
end;
get_handle(Name) ->
get_handle({Name,telnet}).
-get_handle(Type,[{Pid,{_,_,Type}}|_]) ->
+get_handle(Type,{Pid,{_,_,Type}}) ->
{ok,Pid};
-get_handle(Type,[_H|T]) ->
- get_handle(Type,T);
-get_handle(Type,[]) ->
+get_handle(Type,_) ->
{error,{no_such_connection,Type}}.
full_addr({Ip,Port},Type) ->
diff --git a/lib/common_test/src/ct_testspec.erl b/lib/common_test/src/ct_testspec.erl
index 71b03c0ea6..c07ea323e6 100644
--- a/lib/common_test/src/ct_testspec.erl
+++ b/lib/common_test/src/ct_testspec.erl
@@ -253,7 +253,7 @@ collect_tests_from_file(Specs,Nodes,Relaxed) when is_list(Nodes) ->
Specs2 = [filename:absname(S) || S <- Specs1],
TS0 = #testspec{nodes=NodeRefs},
- try create_specs(Specs2,TS0,Relaxed,Join) of
+ try create_testspecs(Specs2,TS0,Relaxed,Join) of
{{[],_},SeparateTestSpecs} ->
filter_and_convert(SeparateTestSpecs);
{{_,#testspec{tests=[]}},SeparateTestSpecs} ->
@@ -262,8 +262,10 @@ collect_tests_from_file(Specs,Nodes,Relaxed) when is_list(Nodes) ->
[filter_and_convert(Joined) |
filter_and_convert(SeparateTestSpecs)]
catch
+ _:Error={error,_} ->
+ Error;
_:Error ->
- Error
+ {error,Error}
end.
filter_and_convert(Joined) when is_tuple(Joined) ->
@@ -293,9 +295,12 @@ delete_dups1([E|Es],Keep) ->
delete_dups1([],Keep) ->
Keep.
-create_specs(Specs,TestSpec,Relaxed,Join) ->
- SpecsTree = create_spec_tree(Specs,TestSpec,Join,[]),
- create_specs(SpecsTree,TestSpec,Relaxed).
+create_testspecs(Specs,TestSpec,Relaxed,Join) ->
+ %% SpecsTree = {SpecAbsName, TermsInSpec,
+ %% IncludedJoinTree, IncludedSeparateTree,
+ %% JoinSpecWithRest, RestSpecsTree}
+ SpecsTree = create_spec_tree(Specs,TestSpec,Join,[]),
+ create_specs(SpecsTree,TestSpec,TestSpec,Relaxed).
create_spec_tree([Spec|Specs],TS,JoinWithNext,Known) ->
SpecDir = filename:dirname(filename:absname(Spec)),
@@ -325,27 +330,31 @@ create_spec_tree([],_TS,_JoinWithNext,_Known) ->
[].
create_specs({Spec,Terms,InclJoin,InclSep,JoinWithNext,NextSpec},
- TestSpec,Relaxed) ->
+ TestSpec,TestSpec0,Relaxed) ->
SpecDir = filename:dirname(filename:absname(Spec)),
TestSpec1 = create_spec(Terms,TestSpec#testspec{spec_dir=SpecDir},
JoinWithNext,Relaxed),
- {{JoinSpecs1,JoinTS1},Separate1} = create_specs(InclJoin,TestSpec1,Relaxed),
+ {{JoinSpecs1,JoinTS1},Separate1} = create_specs(InclJoin,TestSpec1,
+ TestSpec0,Relaxed),
{{JoinSpecs2,JoinTS2},Separate2} =
case JoinWithNext of
true ->
- create_specs(NextSpec,JoinTS1,Relaxed);
+ create_specs(NextSpec,JoinTS1,
+ TestSpec0,Relaxed);
false ->
{{[],JoinTS1},[]}
end,
- {SepJoinSpecs,Separate3} = create_specs(InclSep,TestSpec,Relaxed),
+ {SepJoinSpecs,Separate3} = create_specs(InclSep,TestSpec0,
+ TestSpec0,Relaxed),
{SepJoinSpecs1,Separate4} =
case JoinWithNext of
true ->
{{[],TestSpec},[]};
false ->
- create_specs(NextSpec,TestSpec,Relaxed)
+ create_specs(NextSpec,TestSpec0,
+ TestSpec0,Relaxed)
end,
SpecInfo = {Spec,TestSpec1#testspec.merge_tests},
@@ -354,7 +363,6 @@ create_specs({Spec,Terms,InclJoin,InclSep,JoinWithNext,NextSpec},
[SepJoinSpecs]++Separate2++
[SepJoinSpecs1]++Separate4,
Ss /= []],
-
case {JoinWithNext,JoinSpecs1} of
{true,_} ->
{{[SpecInfo|(JoinSpecs1++JoinSpecs2)],JoinTS2},
@@ -366,7 +374,7 @@ create_specs({Spec,Terms,InclJoin,InclSep,JoinWithNext,NextSpec},
{{[SpecInfo|(JoinSpecs1++JoinSpecs2)],JoinTS2},
AllSeparate}
end;
-create_specs([],TestSpec,_Relaxed) ->
+create_specs([],TestSpec,_,_Relaxed) ->
{{[],TestSpec},[]}.
create_spec(Terms,TestSpec,JoinedByPrev,Relaxed) ->
@@ -842,7 +850,8 @@ add_tests([{cases,Node,Dir,Suite,Cs}|Ts],Spec) ->
Tests = Spec#testspec.tests,
Tests1 = insert_cases(ref2node(Node,Spec#testspec.nodes),
ref2dir(Dir,Spec),
- Suite,Cs,Tests, Spec#testspec.merge_tests),
+ Suite,Cs,Tests,
+ Spec#testspec.merge_tests),
add_tests(Ts,Spec#testspec{tests=Tests1});
%% --- skip_suites ---
@@ -1246,17 +1255,22 @@ insert_cases(Node,Dir,Suite,Cases,Tests,false) when is_list(Cases) ->
append({{Node,Dir},[{Suite,Cases}]},Tests);
insert_cases(Node,Dir,Suite,Cases,Tests,true) when is_list(Cases) ->
{Tests1,Done} =
- lists:foldr(fun(All={{N,D},[{all,_}]},{Replaced,_}) when N == Node,
+ lists:foldr(fun(All={{N,D},[{all,_}]},{Merged,_}) when N == Node,
D == Dir ->
- {[All|Replaced],true};
- ({{N,D},Suites0},{Replaced,_}) when N == Node,
+ {[All|Merged],true};
+ ({{N,D},Suites0},{Merged,_}) when N == Node,
D == Dir ->
Suites1 = insert_cases1(Suite,Cases,Suites0),
- {[{{N,D},Suites1}|Replaced],true};
- (T,{Replaced,Match}) ->
- {[T|Replaced],Match}
+ {[{{N,D},Suites1}|Merged],true};
+ (T,{Merged,Match}) ->
+ {[T|Merged],Match}
end, {[],false}, Tests),
- if not Done ->
+ if Tests == [] ->
+ %% initial case with length(Cases) > 1, we need to do this
+ %% to merge possible duplicate cases in Cases
+ [{{Node,Dir},insert_cases1(Suite,Cases,[{Suite,[]}])}];
+ not Done ->
+ %% no merging done, simply add these cases to Tests
Tests ++ [{{Node,Dir},[{Suite,Cases}]}];
true ->
Tests1
@@ -1301,14 +1315,14 @@ skip_groups(Node,Dir,Suite,Groups,Cases,Cmt,Tests,false) when
skip_groups(Node,Dir,Suite,Groups,Cases,Cmt,Tests,true) when
((Cases == all) or is_list(Cases)) and is_list(Groups) ->
{Tests1,Done} =
- lists:foldr(fun({{N,D},Suites0},{Replaced,_}) when N == Node,
+ lists:foldr(fun({{N,D},Suites0},{Merged,_}) when N == Node,
D == Dir ->
Suites1 = skip_groups1(Suite,
[{Gr,Cases} || Gr <- Groups],
Cmt,Suites0),
- {[{{N,D},Suites1}|Replaced],true};
- (T,{Replaced,Match}) ->
- {[T|Replaced],Match}
+ {[{{N,D},Suites1}|Merged],true};
+ (T,{Merged,Match}) ->
+ {[T|Merged],Match}
end, {[],false}, Tests),
if not Done ->
Tests ++ [{{Node,Dir},skip_groups1(Suite,
@@ -1339,12 +1353,12 @@ skip_cases(Node,Dir,Suite,Cases,Cmt,Tests,false) when is_list(Cases) ->
append({{Node,Dir},Suites1},Tests);
skip_cases(Node,Dir,Suite,Cases,Cmt,Tests,true) when is_list(Cases) ->
{Tests1,Done} =
- lists:foldr(fun({{N,D},Suites0},{Replaced,_}) when N == Node,
+ lists:foldr(fun({{N,D},Suites0},{Merged,_}) when N == Node,
D == Dir ->
Suites1 = skip_cases1(Suite,Cases,Cmt,Suites0),
- {[{{N,D},Suites1}|Replaced],true};
- (T,{Replaced,Match}) ->
- {[T|Replaced],Match}
+ {[{{N,D},Suites1}|Merged],true};
+ (T,{Merged,Match}) ->
+ {[T|Merged],Match}
end, {[],false}, Tests),
if not Done ->
Tests ++ [{{Node,Dir},skip_cases1(Suite,Cases,Cmt,[])}];
diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl
index b77845eb5b..68e76c2396 100644
--- a/lib/common_test/src/ct_util.erl
+++ b/lib/common_test/src/ct_util.erl
@@ -25,13 +25,13 @@
%%%
-module(ct_util).
--export([start/0,start/1,start/2,start/3,
- stop/1,update_last_run_index/0]).
+-export([start/0, start/1, start/2, start/3,
+ stop/1, update_last_run_index/0]).
--export([register_connection/4,unregister_connection/1,
- does_connection_exist/3,get_key_from_name/1]).
+-export([register_connection/4, unregister_connection/1,
+ does_connection_exist/3, get_key_from_name/1]).
--export([close_connections/0]).
+-export([get_connections/1, close_connections/0]).
-export([save_suite_data/3, save_suite_data/2,
save_suite_data_async/3, save_suite_data_async/2,
@@ -56,11 +56,11 @@
-export([listenv/1]).
--export([get_target_name/1, get_connections/2]).
+-export([get_target_name/1, get_connection/2]).
-export([is_test_dir/1, get_testdir/2]).
--export([kill_attached/2, get_attached/1, ct_make_ref/0]).
+-export([kill_attached/2, get_attached/1]).
-export([warn_duplicates/1]).
@@ -417,7 +417,8 @@ loop(Mode,TestData,StartDir) ->
?MAX_IMPORTANCE,
"CT Error Notification",
"Connection process died: "
- "Pid: ~w, Address: ~p, Callback: ~w\n"
+ "Pid: ~w, Address: ~p, "
+ "Callback: ~w\n"
"Reason: ~p\n\n",
[Pid,A,CB,Reason]),
catch CB:close(Pid),
@@ -426,8 +427,8 @@ loop(Mode,TestData,StartDir) ->
loop(Mode,TestData,StartDir);
_ ->
%% Let process crash in case of error, this shouldn't happen!
- io:format("\n\nct_util_server got EXIT from ~w: ~p\n\n",
- [Pid,Reason]),
+ io:format("\n\nct_util_server got EXIT "
+ "from ~w: ~p\n\n", [Pid,Reason]),
file:set_cwd(StartDir),
exit(Reason)
end
@@ -457,10 +458,13 @@ get_key_from_name(Name)->
%%% table, and ct_util will close all registered connections when the
%%% test is finished by calling <code>Callback:close/1</code>.</p>
register_connection(TargetName,Address,Callback,Handle) ->
+ %% If TargetName is a registered alias for a config
+ %% variable, use it as reference for the connection,
+ %% otherwise use the Handle value.
TargetRef =
- case ct_config:get_ref_from_name(TargetName) of
- {ok,Ref} ->
- Ref;
+ case ct_config:get_key_from_name(TargetName) of
+ {ok,_Key} ->
+ TargetName;
_ ->
%% no config name associated with connection,
%% use handle for identification instead
@@ -496,10 +500,10 @@ unregister_connection(Handle) ->
%%%
%%% @doc Check if a connection already exists.
does_connection_exist(TargetName,Address,Callback) ->
- case ct_config:get_ref_from_name(TargetName) of
- {ok,TargetRef} ->
+ case ct_config:get_key_from_name(TargetName) of
+ {ok,_Key} ->
case ets:select(?conn_table,[{#conn{handle='$1',
- targetref=TargetRef,
+ targetref=TargetName,
address=Address,
callback=Callback},
[],
@@ -514,41 +518,76 @@ does_connection_exist(TargetName,Address,Callback) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec get_connections(TargetName,Callback) ->
-%%% {ok,Connections} | {error,Reason}
+%%% @spec get_connection(TargetName,Callback) ->
+%%% {ok,Connection} | {error,Reason}
%%% TargetName = ct:target_name()
%%% Callback = atom()
-%%% Connections = [Connection]
%%% Connection = {Handle,Address}
%%% Handle = term()
%%% Address = term()
%%%
-%%% @doc Return all connections for the <code>Callback</code> on the
+%%% @doc Return the connection for <code>Callback</code> on the
%%% given target (<code>TargetName</code>).
-get_connections(TargetName,Callback) ->
- case ct_config:get_ref_from_name(TargetName) of
- {ok,Ref} ->
- {ok,ets:select(?conn_table,[{#conn{handle='$1',
- address='$2',
- targetref=Ref,
- callback=Callback},
- [],
- [{{'$1','$2'}}]}])};
+get_connection(TargetName,Callback) ->
+ %% check that TargetName is a registered alias
+ case ct_config:get_key_from_name(TargetName) of
+ {ok,_Key} ->
+ case ets:select(?conn_table,[{#conn{handle='$1',
+ address='$2',
+ targetref=TargetName,
+ callback=Callback},
+ [],
+ [{{'$1','$2'}}]}]) of
+ [Result] ->
+ {ok,Result};
+ [] ->
+ {error,no_registered_connection}
+ end;
Error ->
Error
end.
%%%-----------------------------------------------------------------
+%%% @spec get_connections(ConnPid) ->
+%%% {ok,Connections} | {error,Reason}
+%%% Connections = [Connection]
+%%% Connection = {TargetName,Handle,Callback,Address}
+%%% TargetName = ct:target_name() | undefined
+%%% Handle = term()
+%%% Callback = atom()
+%%% Address = term()
+%%%
+%%% @doc Get data for all connections associated with a particular
+%%% connection pid (see Callback:init/3).
+get_connections(ConnPid) ->
+ Conns = ets:tab2list(?conn_table),
+ lists:flatmap(fun(#conn{targetref=TargetName,
+ handle=Handle,
+ callback=Callback,
+ address=Address}) ->
+ case ct_gen_conn:get_conn_pid(Handle) of
+ ConnPid when is_atom(TargetName) ->
+ [{TargetName,Handle,
+ Callback,Address}];
+ ConnPid ->
+ [{undefined,Handle,
+ Callback,Address}];
+ _ ->
+ []
+ end
+ end, Conns).
+
+%%%-----------------------------------------------------------------
%%% @hidden
%%% @equiv ct:get_target_name/1
-get_target_name(ConnPid) ->
- case ets:select(?conn_table,[{#conn{handle=ConnPid,targetref='$1',_='_'},
+get_target_name(Handle) ->
+ case ets:select(?conn_table,[{#conn{handle=Handle,targetref='$1',_='_'},
[],
['$1']}]) of
- [TargetRef] ->
- ct_config:get_name_from_ref(TargetRef);
- [] ->
- {error,{unknown_connection,ConnPid}}
+ [TargetName] when is_atom(TargetName) ->
+ {ok,TargetName};
+ _ ->
+ {error,{unknown_connection,Handle}}
end.
%%%-----------------------------------------------------------------
@@ -922,29 +961,6 @@ cast(Msg) ->
seconds(T) ->
test_server:seconds(T).
-ct_make_ref() ->
- Pid = case whereis(ct_make_ref) of
- undefined ->
- spawn_link(fun() -> ct_make_ref_init() end);
- P ->
- P
- end,
- Pid ! {self(),ref_req},
- receive
- {Pid,Ref} -> Ref
- end.
-
-ct_make_ref_init() ->
- register(ct_make_ref,self()),
- ct_make_ref_loop(0).
-
-ct_make_ref_loop(N) ->
- receive
- {From,ref_req} ->
- From ! {self(),N},
- ct_make_ref_loop(N+1)
- end.
-
abs_name("/") ->
"/";
abs_name(Dir0) ->
diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile
index 31ab28c41d..9d2edcd653 100644
--- a/lib/common_test/test/Makefile
+++ b/lib/common_test/test/Makefile
@@ -30,6 +30,7 @@ MODULES= \
ct_userconfig_callback \
telnet_server \
ct_smoke_test_SUITE \
+ ct_gen_conn_SUITE \
ct_priv_dir_SUITE \
ct_event_handler_SUITE \
ct_config_info_SUITE \
diff --git a/lib/common_test/test/ct_gen_conn_SUITE.erl b/lib/common_test/test/ct_gen_conn_SUITE.erl
new file mode 100644
index 0000000000..2a2183854e
--- /dev/null
+++ b/lib/common_test/test/ct_gen_conn_SUITE.erl
@@ -0,0 +1,135 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2012. 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%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File: ct_gen_conn_SUITE
+%%%
+%%% Description:
+%%% Test that the generic connection handling in CT works as expected.
+%%%
+%%% The suite used for the test is located in the data directory.
+%%%-------------------------------------------------------------------
+-module(ct_gen_conn_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+-define(eh, ct_test_support_eh).
+
+%%--------------------------------------------------------------------
+%% TEST SERVER CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Description: Since Common Test starts another Test Server
+%% instance, the tests need to be performed on a separate node (or
+%% there will be clashes with logging processes etc).
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ ct_test_support:init_per_suite(Config).
+
+end_per_suite(Config) ->
+ ct_test_support:end_per_suite(Config).
+
+init_per_testcase(TestCase, Config) ->
+ ct_test_support:init_per_testcase(TestCase, Config).
+
+end_per_testcase(TestCase, Config) ->
+ ct_test_support:end_per_testcase(TestCase, Config).
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [handles_to_multi_conn_pids, handles_to_single_conn_pids,
+ names_to_multi_conn_pids, names_to_single_conn_pids].
+
+%%--------------------------------------------------------------------
+%% TEST CASES
+%%--------------------------------------------------------------------
+handles_to_multi_conn_pids(Config) ->
+ run_test(handles_to_multi_conn_pids, Config).
+
+handles_to_single_conn_pids(Config) ->
+ run_test(handles_to_single_conn_pids, Config).
+
+names_to_multi_conn_pids(Config) ->
+ run_test(names_to_multi_conn_pids, Config).
+
+names_to_single_conn_pids(Config) ->
+ run_test(names_to_single_conn_pids, Config).
+
+%%%-----------------------------------------------------------------
+%%% HELP FUNCTIONS
+%%%-----------------------------------------------------------------
+run_test(TestCase, Config) ->
+ DataDir = ?config(data_dir, Config),
+ {Opts,ERPid} = setup_env([{dir,DataDir},
+ {suite,conn_SUITE},
+ {testcase,TestCase},
+ {config,filename:join(DataDir,"conn.conf")}],
+ Config),
+ ok = ct_test_support:run(Opts, Config),
+ TestEvents = ct_test_support:get_events(ERPid, Config),
+ ct_test_support:log_events(TestCase,
+ reformat_events(TestEvents, ?eh),
+ ?config(priv_dir, Config),
+ Opts),
+ ExpEvents = events_to_check(TestCase),
+ ok = ct_test_support:verify_events(ExpEvents, TestEvents, Config).
+
+setup_env(Test, Config) ->
+ Opts0 = ct_test_support:get_opts(Config),
+ Level = ?config(trace_level, Config),
+ EvHArgs = [{cbm,ct_test_support},{trace_level,Level}],
+ Opts = Opts0 ++ [{event_handler,{?eh,EvHArgs}} | Test],
+ ERPid = ct_test_support:start_event_receiver(Config),
+ {Opts,ERPid}.
+
+reformat_events(Events, EH) ->
+ ct_test_support:reformat(Events, EH).
+
+%%%-----------------------------------------------------------------
+%%% TEST EVENTS
+%%%-----------------------------------------------------------------
+events_to_check(Test) ->
+ %% 2 tests (ct:run_test + script_start) is default
+ events_to_check(Test, 2).
+
+events_to_check(_, 0) ->
+ [];
+events_to_check(Test, N) ->
+ test_events(Test) ++ events_to_check(Test, N-1).
+
+test_events(Name) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{1,1,1}},
+ {?eh,tc_start,{conn_SUITE,init_per_suite}},
+ {?eh,tc_done,{conn_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{conn_SUITE,Name}},
+ {?eh,tc_done,{conn_SUITE,Name,ok}},
+ {?eh,test_stats,{1,0,{0,0}}},
+ {?eh,tc_start,{conn_SUITE,end_per_suite}},
+ {?eh,tc_done,{conn_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}
+ ].
diff --git a/lib/common_test/test/ct_gen_conn_SUITE_data/conn.conf b/lib/common_test/test/ct_gen_conn_SUITE_data/conn.conf
new file mode 100644
index 0000000000..09f3c11e10
--- /dev/null
+++ b/lib/common_test/test/ct_gen_conn_SUITE_data/conn.conf
@@ -0,0 +1,8 @@
+{multi_conn_pid, [{addr,"localhost"},
+ {port,8383},
+ {multiple_conn_pids,true}]}.
+
+{single_conn_pid, [{addr,"localhost"},
+ {port,8383},
+ {multiple_conn_pids,false},
+ {conn_mgr_name,conn_mgr}]}.
diff --git a/lib/common_test/test/ct_gen_conn_SUITE_data/conn_SUITE.erl b/lib/common_test/test/ct_gen_conn_SUITE_data/conn_SUITE.erl
new file mode 100644
index 0000000000..6877e0c2d2
--- /dev/null
+++ b/lib/common_test/test/ct_gen_conn_SUITE_data/conn_SUITE.erl
@@ -0,0 +1,240 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2010. 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%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File : conn_SUITE
+%%% Description : Check that the generic connection handling in CT
+%%% works as expected.
+%%%-------------------------------------------------------------------
+-module(conn_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%--------------------------------------------------------------------
+%% COMMON TEST CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+suite() ->
+ [{timetrap,{seconds,5}}].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+end_per_testcase(_TestCase, _Config) ->
+ ok.
+
+all() ->
+ [handles_to_multi_conn_pids, handles_to_single_conn_pids,
+ names_to_multi_conn_pids, names_to_single_conn_pids].
+
+%%--------------------------------------------------------------------
+%% TEST CASES
+%%--------------------------------------------------------------------
+
+handles_to_multi_conn_pids() ->
+ [{require,multi_conn_pid}].
+
+handles_to_multi_conn_pids(_Config) ->
+ application:set_env(ct_test, reconnect, true),
+
+ Handle1 = proto:open(multi_conn_pid),
+ ConnPid1 = ct_gen_conn:get_conn_pid(Handle1),
+ {true,true} = {is_process_alive(Handle1),is_process_alive(ConnPid1)},
+ Handle2 = proto:open(multi_conn_pid),
+ ConnPid2 = ct_gen_conn:get_conn_pid(Handle2),
+ {true,true} = {is_process_alive(Handle2),is_process_alive(ConnPid2)},
+ Handle3 = proto:open(multi_conn_pid),
+ ConnPid3 = ct_gen_conn:get_conn_pid(Handle3),
+ {true,true} = {is_process_alive(Handle3),is_process_alive(ConnPid3)},
+
+ ok = proto:close(Handle1),
+ timer:sleep(100),
+ {false,false} = {is_process_alive(Handle1),is_process_alive(ConnPid1)},
+ {true,true} = {is_process_alive(Handle2),is_process_alive(ConnPid2)},
+
+ ok = proto:kill_conn_proc(Handle2),
+ timer:sleep(100),
+ {true,false} = {is_process_alive(Handle2),is_process_alive(ConnPid2)},
+ ConnPid2x = ct_gen_conn:get_conn_pid(Handle2),
+ true = is_process_alive(ConnPid2x),
+
+ ok = proto:close(Handle2),
+ timer:sleep(100),
+ {false,false} = {is_process_alive(Handle2),is_process_alive(ConnPid2x)},
+
+ application:set_env(ct_test, reconnect, false),
+ ok = proto:kill_conn_proc(Handle3),
+ timer:sleep(100),
+ {false,false} = {is_process_alive(Handle3),is_process_alive(ConnPid3)},
+
+ ok.
+
+handles_to_single_conn_pids() ->
+ [{require,single_conn_pid}].
+
+handles_to_single_conn_pids(_Config) ->
+ application:set_env(ct_test, reconnect, true),
+
+ Handle1 = proto:open(single_conn_pid),
+ ConnPid = ct_gen_conn:get_conn_pid(Handle1),
+ {true,true} = {is_process_alive(Handle1),is_process_alive(ConnPid)},
+ Handle2 = proto:open(single_conn_pid),
+ ConnPid = ct_gen_conn:get_conn_pid(Handle2),
+ {true,true} = {is_process_alive(Handle2),is_process_alive(ConnPid)},
+ Handle3 = proto:open(single_conn_pid),
+ ConnPid = ct_gen_conn:get_conn_pid(Handle3),
+ {true,true} = {is_process_alive(Handle3),is_process_alive(ConnPid)},
+
+ Conns = [{undefined,Handle1,_,_},
+ {undefined,Handle2,_,_},
+ {undefined,Handle3,_,_}] = lists:sort(ct_util:get_connections(ConnPid)),
+ ct:pal("CONNS = ~n~p", [Conns]),
+
+ ok = proto:close(Handle1),
+ timer:sleep(100),
+ {false,true} = {is_process_alive(Handle1),is_process_alive(ConnPid)},
+
+ ok = proto:kill_conn_proc(Handle2),
+ timer:sleep(100),
+ NewConnPid = ct_gen_conn:get_conn_pid(Handle2),
+ NewConnPid = ct_gen_conn:get_conn_pid(Handle3),
+ true = is_process_alive(Handle2),
+ true = is_process_alive(Handle3),
+
+ ok = proto:close(Handle2),
+ timer:sleep(100),
+ {false,true} = {is_process_alive(Handle2),is_process_alive(NewConnPid)},
+
+ application:set_env(ct_test, reconnect, false),
+ ok = proto:kill_conn_proc(Handle3),
+ timer:sleep(100),
+ {false,false} = {is_process_alive(Handle3),is_process_alive(NewConnPid)},
+
+ ok.
+
+names_to_multi_conn_pids() ->
+ [{require,mconn1,multi_conn_pid},
+ {require,mconn2,multi_conn_pid},
+ {require,mconn3,multi_conn_pid}].
+
+names_to_multi_conn_pids(_Config) ->
+ application:set_env(ct_test, reconnect, true),
+
+ Handle1 = proto:open(mconn1),
+ ConnPid1 = ct_gen_conn:get_conn_pid(Handle1),
+ {true,true} = {is_process_alive(Handle1),is_process_alive(ConnPid1)},
+ Handle2 = proto:open(mconn2),
+ ConnPid2 = ct_gen_conn:get_conn_pid(Handle2),
+ {true,true} = {is_process_alive(Handle2),is_process_alive(ConnPid2)},
+ Handle3 = proto:open(mconn3),
+ ConnPid3 = ct_gen_conn:get_conn_pid(Handle3),
+ {true,true} = {is_process_alive(Handle3),is_process_alive(ConnPid3)},
+
+ Handle1 = proto:open(mconn1),
+
+ ok = proto:close(mconn1),
+ timer:sleep(100),
+ {false,false} = {is_process_alive(Handle1),is_process_alive(ConnPid1)},
+
+ ok = proto:kill_conn_proc(Handle2),
+ timer:sleep(100),
+ Handle2 = proto:open(mconn2), % should've been reconnected already
+ {true,false} = {is_process_alive(Handle2),is_process_alive(ConnPid2)},
+ ConnPid2x = ct_gen_conn:get_conn_pid(Handle2),
+ true = is_process_alive(ConnPid2x),
+
+ ok = proto:close(mconn2),
+ timer:sleep(100),
+ {false,false} = {is_process_alive(Handle2),is_process_alive(ConnPid2x)},
+ Handle2y = proto:open(mconn2),
+ ConnPid2y = ct_gen_conn:get_conn_pid(Handle2y),
+ {true,true} = {is_process_alive(Handle2y),is_process_alive(ConnPid2y)},
+ ok = proto:close(mconn2),
+ timer:sleep(100),
+ {false,false} = {is_process_alive(Handle2y),is_process_alive(ConnPid2y)},
+
+ application:set_env(ct_test, reconnect, false),
+ ok = proto:kill_conn_proc(Handle3),
+ timer:sleep(100),
+ {false,false} = {is_process_alive(Handle3),is_process_alive(ConnPid3)},
+
+ ok.
+
+names_to_single_conn_pids() ->
+ [{require,sconn1,single_conn_pid},
+ {require,sconn2,single_conn_pid},
+ {require,sconn3,single_conn_pid}].
+
+names_to_single_conn_pids(_Config) ->
+ application:set_env(ct_test, reconnect, true),
+
+ Handle1 = proto:open(sconn1),
+ ConnPid = ct_gen_conn:get_conn_pid(Handle1),
+ {true,true} = {is_process_alive(Handle1),is_process_alive(ConnPid)},
+ Handle2 = proto:open(sconn2),
+ ConnPid = ct_gen_conn:get_conn_pid(Handle2),
+ {true,true} = {is_process_alive(Handle2),is_process_alive(ConnPid)},
+ Handle3 = proto:open(sconn3),
+ ConnPid = ct_gen_conn:get_conn_pid(Handle3),
+ {true,true} = {is_process_alive(Handle3),is_process_alive(ConnPid)},
+
+ Handle1 = proto:open(sconn1),
+
+ Conns = [{sconn1,Handle1,_,_},
+ {sconn2,Handle2,_,_},
+ {sconn3,Handle3,_,_}] = lists:sort(ct_util:get_connections(ConnPid)),
+ ct:pal("CONNS on ~p = ~n~p", [ConnPid,Conns]),
+
+ ok = proto:close(sconn1),
+ timer:sleep(100),
+ {false,true} = {is_process_alive(Handle1),is_process_alive(ConnPid)},
+
+ ok = proto:kill_conn_proc(Handle2),
+ timer:sleep(100),
+ {true,false} = {is_process_alive(Handle2),is_process_alive(ConnPid)},
+ Handle2 = proto:open(sconn2), % should've been reconnected already
+ NewConnPid = ct_gen_conn:get_conn_pid(Handle2),
+ true = is_process_alive(NewConnPid),
+
+ Conns1 = [{sconn2,Handle2,_,_},
+ {sconn3,Handle3,_,_}] =
+ lists:sort(ct_util:get_connections(NewConnPid)),
+ ct:pal("CONNS on ~p = ~n~p", [NewConnPid,Conns1]),
+
+ ok = proto:close(sconn2),
+ timer:sleep(100),
+ {false,true} = {is_process_alive(Handle2),is_process_alive(NewConnPid)},
+
+ application:set_env(ct_test, reconnect, false),
+ ok = proto:kill_conn_proc(Handle3),
+ timer:sleep(100),
+ {false,false} = {is_process_alive(Handle3),is_process_alive(NewConnPid)},
+
+ ok.
+
+
diff --git a/lib/common_test/test/ct_gen_conn_SUITE_data/proto.erl b/lib/common_test/test/ct_gen_conn_SUITE_data/proto.erl
new file mode 100644
index 0000000000..8fcd35e0a4
--- /dev/null
+++ b/lib/common_test/test/ct_gen_conn_SUITE_data/proto.erl
@@ -0,0 +1,196 @@
+%%% @author Peter Andersson <[email protected]>
+%%% @copyright (C) 2013, Peter Andersson
+%%% @doc
+%%%
+%%% @end
+%%% Created : 24 May 2013 by Peter Andersson <[email protected]>
+
+-module(proto).
+
+-compile(export_all).
+
+-record(conn_state, {id, pid, ref, data}).
+
+%% TEST1: N connections (same key) -> N conn pids
+%% TEST2: N connections (same key) -> 1 conn pid
+%% TEST3: N aliases (same key) -> N conn pids
+%% TEST4: N aliases (same key) -> 1 conn pid
+
+open(KeyOrAlias) ->
+ case ct:get_config(KeyOrAlias) of
+ undefined ->
+ {error,{not_available,KeyOrAlias}};
+ ConnData ->
+ io:format("Opening connection with ~p~n", [ConnData]),
+
+ %% if KeyOrAlias == Key, each call returns unique handle
+ %% if KeyOrAlias == Alias, successive calls return same handle
+ {ok,Handle} = ct_gen_conn:start(ConnData,
+ [],
+ ?MODULE,
+ [{name,KeyOrAlias}]),
+ io:format("Handle for ~p = ~p~n", [KeyOrAlias,Handle]),
+ Handle
+ end.
+
+close(AliasOrHandle) ->
+ Handle = get_handle(AliasOrHandle),
+ io:format("Closing connection for ~p (~p)~n", [AliasOrHandle,Handle]),
+ case ct_gen_conn:stop(Handle) of
+ E = {error,_} ->
+ E;
+ Result ->
+ Result
+ end.
+
+kill_conn_proc(AliasOrHandle) ->
+ ConnPid = ct_gen_conn:get_conn_pid(get_handle(AliasOrHandle)),
+ io:format("Killing connection process ~p~n", [ConnPid]),
+ ConnPid ! fail,
+ ok.
+
+send(_) ->
+ ok.
+
+%%%-----------------------------------------------------------------
+%%%
+
+init(KeyOrAlias, ConnData, []) ->
+ Addr = proplists:get_value(addr, ConnData),
+ Port = proplists:get_value(port, ConnData),
+ Ref = make_ref(),
+ Starter = self(),
+ MultConnPids = proplists:get_value(multiple_conn_pids, ConnData),
+ ConnPid =
+ case MultConnPids of
+ true ->
+ spawn(fun() -> active_conn(Starter, KeyOrAlias, Ref,
+ ConnData) end);
+ _ ->
+ ConnMgr = proplists:get_value(conn_mgr_name, ConnData),
+ case whereis(ConnMgr) of
+ undefined ->
+ MgrPid =
+ spawn(fun() -> active_conn(Starter, KeyOrAlias,
+ Ref, ConnData) end),
+ receive MgrPid ->
+ MgrPid
+ end;
+ MgrPid when is_pid(MgrPid) ->
+ MgrPid ! {connect,Ref},
+ MgrPid
+ end
+ end,
+ io:format("Connection ~p opened on ~p:~p -> ~p (~p)~n",
+ [KeyOrAlias,Addr,Port,ConnPid,Ref]),
+ {ok,ConnPid,#conn_state{id=KeyOrAlias, pid=ConnPid, ref=Ref, data=ConnData}}.
+
+
+terminate(ConnPid, #conn_state{id=Id, pid=ConnPid, ref = Ref, data=Data}) ->
+ case proplists:get_value(multiple_conn_pids, Data) of
+ true ->
+ ConnPid ! close;
+ _ ->
+ ConnPid ! {close,Ref}
+ end,
+ io:format("Connection ~p on ~p (~p) closing!~n", [Id,ConnPid,Ref]),
+ ok.
+
+
+reconnect(ConnData, State = #conn_state{id=Id, ref=DeadRef}) ->
+ io:format("Reconnect for ~p initiated...~n", [DeadRef]),
+ case application:get_env(ct_test, reconnect) of
+ {ok,true} ->
+ ConnMgr = proplists:get_value(conn_mgr_name, ConnData),
+ NewRef = make_ref(),
+ Starter = self(),
+ ConnPid =
+ case proplists:get_value(multiple_conn_pids, ConnData) of
+ true ->
+ spawn(fun() ->
+ active_conn(Starter, Id, NewRef,
+ ConnData)
+ end);
+ _ ->
+ case whereis(ConnMgr) of
+ undefined ->
+ MgrPid =
+ spawn(fun() ->
+ active_conn(Starter, Id,
+ NewRef, ConnData)
+ end),
+ receive MgrPid ->
+ MgrPid
+ end;
+ MgrPid ->
+ MgrPid ! {reconnect,DeadRef,NewRef},
+ MgrPid
+ end
+ end,
+ io:format("Connection ~p reopened on ~p (~p)~n",
+ [Id,ConnPid,NewRef]),
+ {ok,ConnPid,State#conn_state{pid=ConnPid, ref=NewRef}};
+ _ ->
+ {error,no_reconnection_allowed}
+ end.
+
+%%%-----------------------------------------------------------------
+%%%
+
+active_conn(Starter, Id, Ref, ConnData) ->
+ ConnMgr = proplists:get_value(conn_mgr_name, ConnData),
+ case proplists:get_value(multiple_conn_pids, ConnData) of
+ true ->
+ ok;
+ _ ->
+ register(ConnMgr,self()),
+ io:format("Connection manager ~p on ~p started for "
+ "~p and ~p~n",
+ [ConnMgr,self(),Id,Ref])
+ end,
+ Starter ! self(),
+ active_conn_loop(ConnData, [Ref]).
+
+active_conn_loop(ConnData, Conns) ->
+ receive
+ {connect,Ref} ->
+ io:format("Connecting ~p on ~p~n",
+ [Ref,self()]),
+ active_conn_loop(ConnData, [Ref | Conns]);
+ {reconnect,DeadRef,NewRef} ->
+ Conns1 = [NewRef | lists:delete(DeadRef, Conns)],
+ io:format("Reconnecting on ~p: ~p -> ~p~n",
+ [self(),DeadRef,NewRef]),
+ active_conn_loop(ConnData, Conns1);
+ close ->
+ io:format("Conn process ~p shutting down~n", [self()]),
+ ok;
+ {close,Ref} ->
+ io:format("Closing connection ~p on ~p~n", [Ref,self()]),
+ case proplists:delete(Ref, Conns) of
+ [] ->
+ io:format("Last connection on ~p closed, "
+ "now stopping~n", [self()]),
+ ok;
+ Conns1 ->
+ active_conn_loop(ConnData, Conns1)
+ end;
+ fail ->
+ io:format("Connection process not feeling good...~n", []),
+ exit(kaboom);
+ {respond,To} ->
+ To ! {self(),hello},
+ active_conn_loop(ConnData, Conns)
+ end.
+
+%%%-----------------------------------------------------------------
+%%%
+
+get_handle(AliasOrHandle) when is_pid(AliasOrHandle) ->
+ AliasOrHandle;
+
+get_handle(AliasOrHandle) ->
+ {ok,{H,_}} = ct_util:get_connection(AliasOrHandle,
+ ?MODULE),
+ H.
+
diff --git a/lib/common_test/test/ct_testspec_3_SUITE.erl b/lib/common_test/test/ct_testspec_3_SUITE.erl
index 6b4b729552..5fa187e5b4 100644
--- a/lib/common_test/test/ct_testspec_3_SUITE.erl
+++ b/lib/common_test/test/ct_testspec_3_SUITE.erl
@@ -284,6 +284,24 @@ events_to_check(_, 0) ->
events_to_check(Test, N) ->
test_events(Test) ++ events_to_check(Test, N-1).
+
+%%%!
+%%%! IMPORTANT NOTE ABOUT THE TEST ORDER:
+%%%!
+%%%! When merging testspec terms, CT will group the tests by TestDir and
+%%%! Suite, before term order (in testspec). That means that if tests
+%%%! are ordered like e.g:
+%%%! {Dir1,Suite11}, {Dir2,Suite21}, {Dir1,Suite12},
+%%%! the execution order after merge (even if no merge takes place),
+%%%! will be:
+%%%! {Dir1,[Suite11,Suite12]}, {Dir2,Suite21}
+%%%!
+%%%! Also, tests in a tree of included testspecs are always collected
+%%%! and merged in depth-first manner, meaning even if a particular test is
+%%%! on a higher level in the tree, it may be executed later than a test on a
+%%%! lower level.
+%%%!
+
test_events(start_separate) ->
[{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
@@ -300,6 +318,7 @@ test_events(start_separate) ->
{?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
{?eh,test_done,{'DEF','STOP_TIME'}},
{?eh,stop_logging,[]},
+
{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
{?eh,start_info,{3,2,15}},
@@ -415,6 +434,7 @@ test_events(incl_separate1) ->
{?eh,test_done,{'DEF','STOP_TIME'}},
{?eh,stop_logging,[]},
+
{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
{?eh,start_info,{3,2,15}},
@@ -448,6 +468,7 @@ test_events(incl_separate2) ->
{?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
{?eh,test_done,{'DEF','STOP_TIME'}},
{?eh,stop_logging,[]},
+
{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
{?eh,start_info,{3,2,15}},
@@ -468,6 +489,7 @@ test_events(incl_separate2) ->
{?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
{?eh,test_done,{'DEF','STOP_TIME'}},
{?eh,stop_logging,[]},
+
{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
{?eh,start_info,{2,2,10}},
@@ -483,6 +505,7 @@ test_events(incl_separate2) ->
{?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
{?eh,test_done,{'DEF','STOP_TIME'}},
{?eh,stop_logging,[]},
+
{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
{?eh,start_info,{2,2,10}},
@@ -498,6 +521,7 @@ test_events(incl_separate2) ->
{?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
{?eh,test_done,{'DEF','STOP_TIME'}},
{?eh,stop_logging,[]},
+
{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
{?eh,start_info,{3,2,15}},
@@ -545,6 +569,7 @@ test_events(incl_join1) ->
{?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
{?eh,test_done,{'DEF','STOP_TIME'}},
{?eh,stop_logging,[]},
+
{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
{?eh,start_info,{4,4,20}},
@@ -614,6 +639,7 @@ test_events(incl_both1) ->
{?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
{?eh,test_done,{'DEF','STOP_TIME'}},
{?eh,stop_logging,[]},
+
{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
{?eh,start_info,{3,2,15}},
@@ -634,6 +660,7 @@ test_events(incl_both1) ->
{?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
{?eh,test_done,{'DEF','STOP_TIME'}},
{?eh,stop_logging,[]},
+
{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
{?eh,start_info,{2,2,10}},
@@ -649,6 +676,7 @@ test_events(incl_both1) ->
{?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
{?eh,test_done,{'DEF','STOP_TIME'}},
{?eh,stop_logging,[]},
+
{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
{?eh,start_info,{2,2,10}},
@@ -692,6 +720,7 @@ test_events(incl_both2) ->
{?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
{?eh,test_done,{'DEF','STOP_TIME'}},
{?eh,stop_logging,[]},
+
{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
{?eh,start_info,{3,2,15}},
@@ -712,6 +741,7 @@ test_events(incl_both2) ->
{?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
{?eh,test_done,{'DEF','STOP_TIME'}},
{?eh,stop_logging,[]},
+
{?eh,start_logging,{'DEF','RUNDIR'}},
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
{?eh,start_info,{2,2,10}},
@@ -728,18 +758,890 @@ test_events(incl_both2) ->
{?eh,test_done,{'DEF','STOP_TIME'}},
{?eh,stop_logging,[]}];
-test_events(incl_both_and_join1) -> [];
-test_events(incl_both_and_join2) -> [];
-test_events(rec_incl_separate1) -> [];
-test_events(rec_incl_separate2) -> [];
-test_events(rec_incl_join1) -> [];
-test_events(rec_incl_join2) -> [];
-test_events(rec_incl_separate_join1) -> [];
-test_events(rec_incl_separate_join2) -> [];
-test_events(rec_incl_join_separate1) -> [];
-test_events(rec_incl_join_separate2) -> [];
-
-test_events(_) ->
- [].
+test_events(incl_both_and_join1) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{5,3,25}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{3,6,{3,3}}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{4,8,{4,4}}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{5,10,{5,5}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{3,2,15}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{3,6,{3,3}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{4,4,20}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{3,6,{3,3}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{4,8,{4,4}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{2,2,10}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}];
+
+test_events(incl_both_and_join2) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{4,4,20}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{3,6,{3,3}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{4,8,{4,4}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{3,2,15}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{3,6,{3,3}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{2,2,10}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}];
+
+test_events(rec_incl_separate1) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec2_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec1_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{1,1,5}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec1_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec2_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{1,1,5}},
+ {?eh,tc_start,{t23_SUITE,init_per_suite}},
+ {?eh,tc_done,{t23_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t23_SUITE,end_per_suite}},
+ {?eh,tc_done,{t23_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{1,1,5}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec1_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec2_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec2_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec1_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}];
+
+test_events(rec_incl_separate2) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{1,1,5}},
+ {?eh,tc_start,{t23_SUITE,init_per_suite}},
+ {?eh,tc_done,{t23_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t23_SUITE,end_per_suite}},
+ {?eh,tc_done,{t23_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec2_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec1_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{1,1,5}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec1_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec2_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{1,1,5}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec1_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec2_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec2_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec1_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}];
+
+test_events(rec_incl_join1) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{4,4,20}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{4,8,{4,4}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{5,5,25}},
+ {?eh,tc_start,{t23_SUITE,init_per_suite}},
+ {?eh,tc_done,{t23_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t23_SUITE,end_per_suite}},
+ {?eh,tc_done,{t23_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{5,10,{5,5}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}];
+test_events(rec_incl_join2) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{5,5,25}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t23_SUITE,init_per_suite}},
+ {?eh,tc_done,{t23_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{5,10,{5,5}}},
+ {?eh,tc_start,{t23_SUITE,end_per_suite}},
+ {?eh,tc_done,{t23_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}];
+
+test_events(rec_incl_separate_join1) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{4,4,20}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{4,8,{4,4}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{4,4,20}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{4,8,{4,4}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{1,1,5}},
+ {?eh,tc_start,{t23_SUITE,init_per_suite}},
+ {?eh,tc_done,{t23_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t23_SUITE,end_per_suite}},
+ {?eh,tc_done,{t23_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{4,4,20}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{4,8,{4,4}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{4,4,20}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{4,8,{4,4}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}];
+
+test_events(rec_incl_separate_join2) ->
+ [
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{1,1,5}},
+ {?eh,tc_start,{t23_SUITE,init_per_suite}},
+ {?eh,tc_done,{t23_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t23_SUITE,end_per_suite}},
+ {?eh,tc_done,{t23_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{4,4,20}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{4,8,{4,4}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{4,4,20}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{4,8,{4,4}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+
+ {?eh,stop_logging,[]},
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{4,4,20}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{4,8,{4,4}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{4,4,20}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{4,8,{4,4}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}];
+
+test_events(rec_incl_join_separate1) ->
+ [{?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{2,2,10}},
+ {?eh,tc_start,{t23_SUITE,init_per_suite}},
+ {?eh,tc_done,{t23_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t23_SUITE,end_per_suite}},
+ {?eh,tc_done,{t23_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec2_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec1_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec1_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec2_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{2,2,10}},
+ {?eh,tc_start,{t23_SUITE,init_per_suite}},
+ {?eh,tc_done,{t23_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t23_SUITE,end_per_suite}},
+ {?eh,tc_done,{t23_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec1_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec2_events() ++
+
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec2_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec1_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}];
+
+test_events(rec_incl_join_separate2) ->
+ [{?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
+ {?eh,start_info,{2,2,10}},
+ {?eh,tc_start,{t23_SUITE,init_per_suite}},
+ {?eh,tc_done,{t23_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t23_SUITE,end_per_suite}},
+ {?eh,tc_done,{t23_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}},
+ {?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec2_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec1_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec1_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec2_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec1_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec2_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec2_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]},
+
+ {?eh,start_logging,{'DEF','RUNDIR'}},
+ {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}]
+ ++ flat_spec1_events() ++
+ [{?eh,test_done,{'DEF','STOP_TIME'}},
+ {?eh,stop_logging,[]}].
+
+%%%-----------------------------------------------------------------
+
+flat_spec1_events() ->
+ [
+ {?eh,start_info,{2,2,10}},
+ {?eh,tc_start,{t11_SUITE,init_per_suite}},
+ {?eh,tc_done,{t11_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t11_SUITE,ok_tc}},
+ {?eh,tc_done,{t11_SUITE,ok_tc,ok}},
+ {?eh,test_stats,{1,0,{0,0}}},
+ {?eh,tc_start,{t11_SUITE,exit_tc}},
+ {?eh,tc_done,{t11_SUITE,exit_tc,{failed,{error,kaboom}}}},
+ {?eh,test_stats,{1,1,{0,0}}},
+ {?eh,tc_start,{t11_SUITE,to_tc}},
+ {?eh,tc_done,{t11_SUITE,to_tc,{failed,{timetrap_timeout,1}}}},
+ {?eh,test_stats,{1,2,{0,0}}},
+ {?eh,tc_start,{t11_SUITE,autoskip_tc}},
+ {?eh,tc_done,
+ {t11_SUITE,autoskip_tc,{skipped,
+ {failed,
+ {t11_SUITE,init_per_testcase,
+ {kaboom,'_'}}}}}},
+ {?eh,test_stats,{1,2,{0,1}}},
+ {?eh,tc_start,{t11_SUITE,userskip_tc}},
+ {?eh,tc_done,{t11_SUITE,userskip_tc,{skipped,"user skipped"}}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t11_SUITE,end_per_suite}},
+ {?eh,tc_done,{t11_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,init_per_suite}},
+ {?eh,tc_done,{t21_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t21_SUITE,ok_tc}},
+ {?eh,tc_done,{t21_SUITE,ok_tc,ok}},
+ {?eh,test_stats,{2,2,{1,1}}},
+ {?eh,tc_start,{t21_SUITE,exit_tc}},
+ {?eh,tc_done,{t21_SUITE,exit_tc,{failed,{error,kaboom}}}},
+ {?eh,test_stats,{2,3,{1,1}}},
+ {?eh,tc_start,{t21_SUITE,to_tc}},
+ {?eh,tc_done,{t21_SUITE,to_tc,{failed,{timetrap_timeout,1}}}},
+ {?eh,test_stats,{2,4,{1,1}}},
+ {?eh,tc_start,{t21_SUITE,autoskip_tc}},
+ {?eh,tc_done,
+ {t21_SUITE,autoskip_tc,{skipped,
+ {failed,
+ {t21_SUITE,init_per_testcase,
+ {kaboom,'_'}}}}}},
+ {?eh,test_stats,{2,4,{1,2}}},
+ {?eh,tc_start,{t21_SUITE,userskip_tc}},
+ {?eh,tc_done,{t21_SUITE,userskip_tc,{skipped,"user skipped"}}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t21_SUITE,end_per_suite}},
+ {?eh,tc_done,{t21_SUITE,end_per_suite,ok}}].
+
+flat_spec2_events() ->
+ [
+ {?eh,start_info,{3,2,15}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,ok_tc}},
+ {?eh,tc_done,{t12_SUITE,ok_tc,ok}},
+ {?eh,test_stats,{1,0,{0,0}}},
+ {?eh,tc_start,{t12_SUITE,exit_tc}},
+ {?eh,tc_done,{t12_SUITE,exit_tc,{failed,{error,kaboom}}}},
+ {?eh,test_stats,{1,1,{0,0}}},
+ {?eh,tc_start,{t12_SUITE,to_tc}},
+ {?eh,tc_done,{t12_SUITE,to_tc,{failed,{timetrap_timeout,1}}}},
+ {?eh,test_stats,{1,2,{0,0}}},
+ {?eh,tc_start,{t12_SUITE,autoskip_tc}},
+ {?eh,tc_done,
+ {t12_SUITE,autoskip_tc,{skipped,
+ {failed,
+ {t12_SUITE,init_per_testcase,
+ {kaboom,'_'}}}}}},
+ {?eh,test_stats,{1,2,{0,1}}},
+ {?eh,tc_start,{t12_SUITE,userskip_tc}},
+ {?eh,tc_done,{t12_SUITE,userskip_tc,{skipped,"user skipped"}}},
+ {?eh,test_stats,{1,2,{1,1}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,init_per_suite}},
+ {?eh,tc_done,{t12_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t12_SUITE,ok_tc}},
+ {?eh,tc_done,{t12_SUITE,ok_tc,ok}},
+ {?eh,test_stats,{2,2,{1,1}}},
+ {?eh,tc_start,{t12_SUITE,exit_tc}},
+ {?eh,tc_done,{t12_SUITE,exit_tc,{failed,{error,kaboom}}}},
+ {?eh,test_stats,{2,3,{1,1}}},
+ {?eh,tc_start,{t12_SUITE,to_tc}},
+ {?eh,tc_done,{t12_SUITE,to_tc,{failed,{timetrap_timeout,1}}}},
+ {?eh,test_stats,{2,4,{1,1}}},
+ {?eh,tc_start,{t12_SUITE,autoskip_tc}},
+ {?eh,tc_done,
+ {t12_SUITE,autoskip_tc,{skipped,
+ {failed,
+ {t12_SUITE,init_per_testcase,
+ {kaboom,'_'}}}}}},
+ {?eh,test_stats,{2,4,{1,2}}},
+ {?eh,tc_start,{t12_SUITE,userskip_tc}},
+ {?eh,tc_done,{t12_SUITE,userskip_tc,{skipped,"user skipped"}}},
+ {?eh,test_stats,{2,4,{2,2}}},
+ {?eh,tc_start,{t12_SUITE,end_per_suite}},
+ {?eh,tc_done,{t12_SUITE,end_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,init_per_suite}},
+ {?eh,tc_done,{t22_SUITE,init_per_suite,ok}},
+ {?eh,tc_start,{t22_SUITE,ok_tc}},
+ {?eh,tc_done,{t22_SUITE,ok_tc,ok}},
+ {?eh,test_stats,{3,4,{2,2}}},
+ {?eh,tc_start,{t22_SUITE,exit_tc}},
+ {?eh,tc_done,{t22_SUITE,exit_tc,{failed,{error,kaboom}}}},
+ {?eh,test_stats,{3,5,{2,2}}},
+ {?eh,tc_start,{t22_SUITE,to_tc}},
+ {?eh,tc_done,{t22_SUITE,to_tc,{failed,{timetrap_timeout,1}}}},
+ {?eh,test_stats,{3,6,{2,2}}},
+ {?eh,tc_start,{t22_SUITE,autoskip_tc}},
+ {?eh,tc_done,
+ {t22_SUITE,autoskip_tc,{skipped,
+ {failed,
+ {t22_SUITE,init_per_testcase,
+ {kaboom,'_'}}}}}},
+ {?eh,test_stats,{3,6,{2,3}}},
+ {?eh,tc_start,{t22_SUITE,userskip_tc}},
+ {?eh,tc_done,{t22_SUITE,userskip_tc,{skipped,"user skipped"}}},
+ {?eh,test_stats,{3,6,{3,3}}},
+ {?eh,tc_start,{t22_SUITE,end_per_suite}},
+ {?eh,tc_done,{t22_SUITE,end_per_suite,ok}}].
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 98ebb21f29..00abeb9990 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -142,6 +142,19 @@
(s)[3] = (char)((i) & 0xff);\
}
+/* This shall correspond to the similar macro in crypto.erl */
+/* Current value is: erlang:system_info(context_reductions) * 10 */
+#define MAX_BYTES_TO_NIF 20000
+
+#define CONSUME_REDS(NifEnv, Ibin) \
+do { \
+ int _cost = ((Ibin).size * 100) / MAX_BYTES_TO_NIF;\
+ if (_cost) { \
+ (void) enif_consume_timeslice((NifEnv), \
+ (_cost > 100) ? 100 : _cost); \
+ } \
+ } while (0)
+
/* NIF interface declarations */
static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info);
static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info);
@@ -208,7 +221,7 @@ static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
static ERL_NIF_TERM dss_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM do_exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rc4_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rc4_set_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -338,7 +351,7 @@ static ErlNifFunc nif_funcs[] = {
{"dss_verify_nif", 4, dss_verify_nif},
{"rsa_verify_nif", 4, rsa_verify_nif},
{"aes_cbc_crypt", 4, aes_cbc_crypt},
- {"exor", 2, exor},
+ {"do_exor", 2, do_exor},
{"rc4_encrypt", 2, rc4_encrypt},
{"rc4_set_key", 1, rc4_set_key},
{"rc4_encrypt_with_state", 2, rc4_encrypt_with_state},
@@ -778,6 +791,7 @@ static ERL_NIF_TERM md5(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
}
MD5((unsigned char *) ibin.data, ibin.size,
enif_make_new_binary(env,MD5_LEN, &ret));
+ CONSUME_REDS(env,ibin);
return ret;
}
static ERL_NIF_TERM md5_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -799,6 +813,7 @@ static ERL_NIF_TERM md5_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
new_ctx = (MD5_CTX*) enif_make_new_binary(env,MD5_CTX_LEN, &ret);
memcpy(new_ctx, ctx_bin.data, MD5_CTX_LEN);
MD5_Update(new_ctx, data_bin.data, data_bin.size);
+ CONSUME_REDS(env,data_bin);
return ret;
}
static ERL_NIF_TERM md5_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -820,10 +835,11 @@ static ERL_NIF_TERM ripemd160(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
ERL_NIF_TERM ret;
if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) {
- return enif_make_badarg(env);
+ return enif_make_badarg(env);
}
RIPEMD160((unsigned char *) ibin.data, ibin.size,
- enif_make_new_binary(env,RIPEMD160_LEN, &ret));
+ enif_make_new_binary(env,RIPEMD160_LEN, &ret));
+ CONSUME_REDS(env,ibin);
return ret;
}
static ERL_NIF_TERM ripemd160_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -838,13 +854,14 @@ static ERL_NIF_TERM ripemd160_update(ErlNifEnv* env, int argc, const ERL_NIF_TER
ErlNifBinary ctx_bin, data_bin;
ERL_NIF_TERM ret;
if (!enif_inspect_binary(env, argv[0], &ctx_bin)
- || ctx_bin.size != RIPEMD160_CTX_LEN
- || !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) {
- return enif_make_badarg(env);
+ || ctx_bin.size != RIPEMD160_CTX_LEN
+ || !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) {
+ return enif_make_badarg(env);
}
new_ctx = (RIPEMD160_CTX*) enif_make_new_binary(env,RIPEMD160_CTX_LEN, &ret);
memcpy(new_ctx, ctx_bin.data, RIPEMD160_CTX_LEN);
RIPEMD160_Update(new_ctx, data_bin.data, data_bin.size);
+ CONSUME_REDS(env, data_bin);
return ret;
}
static ERL_NIF_TERM ripemd160_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -853,7 +870,7 @@ static ERL_NIF_TERM ripemd160_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM
RIPEMD160_CTX ctx_clone;
ERL_NIF_TERM ret;
if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != RIPEMD160_CTX_LEN) {
- return enif_make_badarg(env);
+ return enif_make_badarg(env);
}
memcpy(&ctx_clone, ctx_bin.data, RIPEMD160_CTX_LEN); /* writable */
RIPEMD160_Final(enif_make_new_binary(env, RIPEMD160_LEN, &ret), &ctx_clone);
@@ -871,6 +888,7 @@ static ERL_NIF_TERM sha(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
}
SHA1((unsigned char *) ibin.data, ibin.size,
enif_make_new_binary(env,SHA_LEN, &ret));
+ CONSUME_REDS(env,ibin);
return ret;
}
static ERL_NIF_TERM sha_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -891,6 +909,7 @@ static ERL_NIF_TERM sha_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
new_ctx = (SHA_CTX*) enif_make_new_binary(env,SHA_CTX_LEN, &ret);
memcpy(new_ctx, ctx_bin.data, SHA_CTX_LEN);
SHA1_Update(new_ctx, data_bin.data, data_bin.size);
+ CONSUME_REDS(env,data_bin);
return ret;
}
static ERL_NIF_TERM sha_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -917,6 +936,7 @@ static ERL_NIF_TERM sha224_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
}
SHA224((unsigned char *) ibin.data, ibin.size,
enif_make_new_binary(env,SHA224_LEN, &ret));
+ CONSUME_REDS(env,ibin);
return ret;
#else
return atom_notsup;
@@ -945,6 +965,7 @@ static ERL_NIF_TERM sha224_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE
new_ctx = (SHA256_CTX*) enif_make_new_binary(env,sizeof(SHA256_CTX), &ret);
memcpy(new_ctx, ctx_bin.data, sizeof(SHA256_CTX));
SHA224_Update(new_ctx, data_bin.data, data_bin.size);
+ CONSUME_REDS(env,data_bin);
return ret;
#else
return atom_notsup;
@@ -978,6 +999,7 @@ static ERL_NIF_TERM sha256_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
}
SHA256((unsigned char *) ibin.data, ibin.size,
enif_make_new_binary(env,SHA256_LEN, &ret));
+ CONSUME_REDS(env,ibin);
return ret;
#else
return atom_notsup;
@@ -1006,6 +1028,7 @@ static ERL_NIF_TERM sha256_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE
new_ctx = (SHA256_CTX*) enif_make_new_binary(env,sizeof(SHA256_CTX), &ret);
memcpy(new_ctx, ctx_bin.data, sizeof(SHA256_CTX));
SHA256_Update(new_ctx, data_bin.data, data_bin.size);
+ CONSUME_REDS(env,data_bin);
return ret;
#else
return atom_notsup;
@@ -1039,6 +1062,7 @@ static ERL_NIF_TERM sha384_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
}
SHA384((unsigned char *) ibin.data, ibin.size,
enif_make_new_binary(env,SHA384_LEN, &ret));
+ CONSUME_REDS(env,ibin);
return ret;
#else
return atom_notsup;
@@ -1067,6 +1091,7 @@ static ERL_NIF_TERM sha384_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE
new_ctx = (SHA512_CTX*) enif_make_new_binary(env,sizeof(SHA512_CTX), &ret);
memcpy(new_ctx, ctx_bin.data, sizeof(SHA512_CTX));
SHA384_Update(new_ctx, data_bin.data, data_bin.size);
+ CONSUME_REDS(env,data_bin);
return ret;
#else
return atom_notsup;
@@ -1100,6 +1125,7 @@ static ERL_NIF_TERM sha512_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
}
SHA512((unsigned char *) ibin.data, ibin.size,
enif_make_new_binary(env,SHA512_LEN, &ret));
+ CONSUME_REDS(env,ibin);
return ret;
#else
return atom_notsup;
@@ -1128,6 +1154,7 @@ static ERL_NIF_TERM sha512_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE
new_ctx = (SHA512_CTX*) enif_make_new_binary(env,sizeof(SHA512_CTX), &ret);
memcpy(new_ctx, ctx_bin.data, sizeof(SHA512_CTX));
SHA512_Update(new_ctx, data_bin.data, data_bin.size);
+ CONSUME_REDS(env,data_bin);
return ret;
#else
return atom_notsup;
@@ -1161,6 +1188,7 @@ static ERL_NIF_TERM md4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
}
MD4((unsigned char *) ibin.data, ibin.size,
enif_make_new_binary(env,MD4_LEN, &ret));
+ CONSUME_REDS(env,ibin);
return ret;
}
static ERL_NIF_TERM md4_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -1181,6 +1209,7 @@ static ERL_NIF_TERM md4_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
new_ctx = (MD4_CTX*) enif_make_new_binary(env,MD4_CTX_LEN, &ret);
memcpy(new_ctx, ctx_bin.data, MD4_CTX_LEN);
MD4_Update(new_ctx, data_bin.data, data_bin.size);
+ CONSUME_REDS(env,data_bin);
return ret;
}
static ERL_NIF_TERM md4_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -1210,6 +1239,7 @@ static ERL_NIF_TERM md5_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
}
hmac_md5(key.data, key.size, data.data, data.size, hmacbuf);
memcpy(enif_make_new_binary(env, mac_sz, &ret), hmacbuf, mac_sz);
+ CONSUME_REDS(env,data);
return ret;
}
@@ -1228,6 +1258,7 @@ static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
hmac_sha1(key.data, key.size, data.data, data.size, hmacbuf);
memcpy(enif_make_new_binary(env, mac_sz, &ret),
hmacbuf, mac_sz);
+ CONSUME_REDS(env,data);
return ret;
}
@@ -1247,6 +1278,7 @@ static ERL_NIF_TERM sha224_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
hmac_sha224(key.data, key.size, data.data, data.size, hmacbuf);
memcpy(enif_make_new_binary(env, mac_sz, &ret),
hmacbuf, mac_sz);
+ CONSUME_REDS(env,data);
return ret;
#else
return atom_notsup;
@@ -1269,6 +1301,7 @@ static ERL_NIF_TERM sha256_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
hmac_sha256(key.data, key.size, data.data, data.size, hmacbuf);
memcpy(enif_make_new_binary(env, mac_sz, &ret),
hmacbuf, mac_sz);
+ CONSUME_REDS(env,data);
return ret;
#else
return atom_notsup;
@@ -1291,6 +1324,7 @@ static ERL_NIF_TERM sha384_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
hmac_sha384(key.data, key.size, data.data, data.size, hmacbuf);
memcpy(enif_make_new_binary(env, mac_sz, &ret),
hmacbuf, mac_sz);
+ CONSUME_REDS(env,data);
return ret;
#else
return atom_notsup;
@@ -1314,6 +1348,7 @@ static ERL_NIF_TERM sha512_mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
hmac_sha512(key.data, key.size, data.data, data.size, hmacbuf);
memcpy(enif_make_new_binary(env, mac_sz, &ret),
hmacbuf, mac_sz);
+ CONSUME_REDS(env,data);
return ret;
#else
return atom_notsup;
@@ -1371,6 +1406,7 @@ static ERL_NIF_TERM hmac_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
ctx_buf = enif_make_new_binary(env, sizeof(HMAC_CTX), &ret);
memcpy(ctx_buf, context.data, context.size);
HMAC_Update((HMAC_CTX *)ctx_buf, data.data, data.size);
+ CONSUME_REDS(env,data);
return ret;
}
@@ -1427,6 +1463,7 @@ static ERL_NIF_TERM des_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
DES_set_key((const_DES_cblock*)key.data, &schedule);
DES_ncbc_encrypt(text.data, enif_make_new_binary(env, text.size, &ret),
text.size, &schedule, &ivec_clone, (argv[3] == atom_true));
+ CONSUME_REDS(env,text);
return ret;
}
@@ -1446,6 +1483,7 @@ static ERL_NIF_TERM des_cfb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
DES_set_key((const_DES_cblock*)key.data, &schedule);
DES_cfb_encrypt(text.data, enif_make_new_binary(env, text.size, &ret),
8, text.size, &schedule, &ivec_clone, (argv[3] == atom_true));
+ CONSUME_REDS(env,text);
return ret;
}
@@ -1462,6 +1500,7 @@ static ERL_NIF_TERM des_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
DES_ecb_encrypt((const_DES_cblock*)text.data,
(DES_cblock*)enif_make_new_binary(env, 8, &ret),
&schedule, (argv[2] == atom_true));
+ CONSUME_REDS(env,text);
return ret;
}
@@ -1488,6 +1527,7 @@ static ERL_NIF_TERM des_ede3_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_T
DES_ede3_cbc_encrypt(text.data, enif_make_new_binary(env,text.size,&ret),
text.size, &schedule1, &schedule2, &schedule3,
&ivec_clone, (argv[5] == atom_true));
+ CONSUME_REDS(env,text);
return ret;
}
@@ -1514,6 +1554,7 @@ static ERL_NIF_TERM des_ede3_cfb_crypt_nif(ErlNifEnv* env, int argc, const ERL_N
DES_ede3_cfb_encrypt(text.data, enif_make_new_binary(env,text.size,&ret),
8, text.size, &schedule1, &schedule2, &schedule3,
&ivec_clone, (argv[5] == atom_true));
+ CONSUME_REDS(env,text);
return ret;
#else
return atom_notsup;
@@ -1540,6 +1581,7 @@ static ERL_NIF_TERM aes_cfb_128_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TE
enif_make_new_binary(env, text.size, &ret),
text.size, &aes_key, ivec_clone, &new_ivlen,
(argv[3] == atom_true));
+ CONSUME_REDS(env,text);
return ret;
}
@@ -1565,6 +1607,7 @@ static ERL_NIF_TERM aes_ctr_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM
AES_ctr128_encrypt((unsigned char *) text.data,
enif_make_new_binary(env, text.size, &ret),
text.size, &aes_key, ivec_clone, ecount_buf, &num);
+ CONSUME_REDS(env,text);
/* To do an incremental {en|de}cryption, the state to to keep between calls
must include ivec_clone, ecount_buf and num. */
@@ -1608,6 +1651,7 @@ static ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_N
num2_term = enif_make_uint(env, num);
new_state_term = enif_make_tuple4(env, state_term[0], ivec2_term, ecount2_term, num2_term);
ret = enif_make_tuple2(env, new_state_term, cipher_term);
+ CONSUME_REDS(env,text_bin);
return ret;
}
@@ -2055,10 +2099,11 @@ static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
ret_ptr = enif_make_new_binary(env, data_bin.size, &ret);
memcpy(ivec, ivec_bin.data, 16); /* writable copy */
AES_cbc_encrypt(data_bin.data, ret_ptr, data_bin.size, &aes_key, ivec, i);
+ CONSUME_REDS(env,data_bin);
return ret;
}
-static ERL_NIF_TERM exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+static ERL_NIF_TERM do_exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Data1, Data2) */
ErlNifBinary d1, d2;
unsigned char* ret_ptr;
@@ -2075,6 +2120,7 @@ static ERL_NIF_TERM exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
for (i=0; i<d1.size; i++) {
ret_ptr[i] = d1.data[i] ^ d2.data[i];
}
+ CONSUME_REDS(env,d1);
return ret;
}
@@ -2091,6 +2137,7 @@ static ERL_NIF_TERM rc4_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
RC4_set_key(&rc4_key, key.size, key.data);
RC4(&rc4_key, data.size, data.data,
enif_make_new_binary(env, data.size, &ret));
+ CONSUME_REDS(env,data);
return ret;
}
@@ -2123,7 +2170,7 @@ static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_N
memcpy(rc4_key, state.data, sizeof(RC4_KEY));
RC4(rc4_key, data.size, data.data,
enif_make_new_binary(env, data.size, &new_data));
-
+ CONSUME_REDS(env,data);
return enif_make_tuple2(env,new_state,new_data);
}
@@ -2150,6 +2197,7 @@ static ERL_NIF_TERM rc2_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
data_bin.size, &rc2_key,
iv_copy,
(argv[3] == atom_true));
+ CONSUME_REDS(env,data_bin);
return ret;
}
@@ -2781,6 +2829,7 @@ static ERL_NIF_TERM bf_cfb64_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM
BF_cfb64_encrypt(data_bin.data, enif_make_new_binary(env,data_bin.size,&ret),
data_bin.size, &bf_key, bf_tkey, &bf_n,
(argv[3] == atom_true ? BF_ENCRYPT : BF_DECRYPT));
+ CONSUME_REDS(env,data_bin);
return ret;
}
@@ -2804,6 +2853,7 @@ static ERL_NIF_TERM bf_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
BF_cbc_encrypt(data_bin.data, enif_make_new_binary(env,data_bin.size,&ret),
data_bin.size, &bf_key, bf_tkey,
(argv[3] == atom_true ? BF_ENCRYPT : BF_DECRYPT));
+ CONSUME_REDS(env,data_bin);
return ret;
}
@@ -2821,6 +2871,7 @@ static ERL_NIF_TERM bf_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
BF_set_key(&bf_key, key_bin.size, key_bin.data);
BF_ecb_encrypt(data_bin.data, enif_make_new_binary(env,data_bin.size,&ret),
&bf_key, (argv[2] == atom_true ? BF_ENCRYPT : BF_DECRYPT));
+ CONSUME_REDS(env,data_bin);
return ret;
}
@@ -2843,6 +2894,7 @@ static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_N
memcpy(bf_tkey, ivec_bin.data, 8);
BF_ofb64_encrypt(data_bin.data, enif_make_new_binary(env,data_bin.size,&ret),
data_bin.size, &bf_key, bf_tkey, &bf_n);
+ CONSUME_REDS(env,data_bin);
return ret;
}
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index bdccfee341..99d167bfa9 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -208,7 +208,7 @@
</type>
<desc>
<p>Computes the shared secret from the private key and the other party's public key.
- See also <seealso marker="public_key:public_key#compute_key/2">public_key:compute_key/2</seealso>
+ See also <seealso marker="public_key:public_key#compute_key-2">public_key:compute_key/2</seealso>
</p>
</desc>
</func>
@@ -240,7 +240,7 @@
</type>
<desc>
<p>Generates public keys of type <c>Type</c>.
- See also <seealso marker="public_key:public_key#generate_key/1">public_key:generate_key/1</seealso>
+ See also <seealso marker="public_key:public_key#generate_key-1">public_key:generate_key/1</seealso>
</p>
</desc>
</func>
@@ -249,7 +249,7 @@
<name>hash(Type, Data) -> Digest</name>
<fsummary></fsummary>
<type>
- <v>Type = md4 | message_digest_algorithms()</v>
+ <v>Type = md4 | hash_algorithms()</v>
<v>Data = iodata()</v>
<v>Digest = binary()</v>
</type>
@@ -264,12 +264,12 @@
<name>hash_init(Type) -> Context</name>
<fsummary></fsummary>
<type>
- <v>Type = md4 | message_digest_algorithms()</v>
+ <v>Type = md4 | hash_algorithms()</v>
</type>
<desc>
<p>Initializes the context for streaming hash operations. <c>Type</c> determines
which digest to use. The returned context should be used as argument
- to <seealso marker="#hash_update/2">hash_update</seealso>.</p>
+ to <seealso marker="#hash_update-2">hash_update</seealso>.</p>
<p>May throw exception <c>notsup</c> in case the chosen <c>Type</c>
is not supported by the underlying OpenSSL implementation.</p>
</desc>
@@ -283,10 +283,10 @@
</type>
<desc>
<p>Updates the digest represented by <c>Context</c> using the given <c>Data</c>. <c>Context</c>
- must have been generated using <seealso marker="#hash_init/1">hash_init</seealso>
+ must have been generated using <seealso marker="#hash_init-1">hash_init</seealso>
or a previous call to this function. <c>Data</c> can be any length. <c>NewContext</c>
must be passed into the next call to <c>hash_update</c>
- or <seealso marker="#hash_final/1">hash_final</seealso>.</p>
+ or <seealso marker="#hash_final-1">hash_final</seealso>.</p>
</desc>
</func>
<func>
@@ -297,7 +297,7 @@
</type>
<desc>
<p>Finalizes the hash operation referenced by <c>Context</c> returned
- from a previous call to <seealso marker="#hash_update/2">hash_update</seealso>.
+ from a previous call to <seealso marker="#hash_update-2">hash_update</seealso>.
The size of <c>Digest</c> is determined by the type of hash
function used to generate it.</p>
</desc>
@@ -308,7 +308,7 @@
<name>hmac(Type, Key, Data, MacLength) -> Mac</name>
<fsummary></fsummary>
<type>
- <v>Type = message_digest_algorithms() </v>
+ <v>Type = hash_algorithms() - except ripemd160</v>
<v>Key = iodata()</v>
<v>Data = iodata()</v>
<v>MacLength = integer()</v>
@@ -325,7 +325,7 @@
<name>hmac_init(Type, Key) -> Context</name>
<fsummary></fsummary>
<type>
- <v>Type = message_digest_algorithms()</v>
+ <v>Type = hash_algorithms() - except ripemd160</v>
<v>Key = iodata()</v>
<v>Context = binary()</v>
</type>
@@ -346,10 +346,10 @@
<desc>
<p>Updates the HMAC represented by <c>Context</c> using the given <c>Data</c>. <c>Context</c>
must have been generated using an HMAC init function (such as
- <seealso marker="#hmac_init/2">hmac_init</seealso>). <c>Data</c> can be any length. <c>NewContext</c>
+ <seealso marker="#hmac_init-2">hmac_init</seealso>). <c>Data</c> can be any length. <c>NewContext</c>
must be passed into the next call to <c>hmac_update</c>
- or to one of the functions <seealso marker="#hmac_final/1">hmac_final</seealso> and
- <seealso marker="#hmac_final_n/1">hmac_final_n</seealso>
+ or to one of the functions <seealso marker="#hmac_final-1">hmac_final</seealso> and
+ <seealso marker="#hmac_final_n-2">hmac_final_n</seealso>
</p>
</desc>
@@ -447,36 +447,36 @@
<v>PlainText = binary()</v>
</type>
<desc>
- <p>Decrypts the <c>ChipherText</c> (usually a session key encrypted with
- <seealso marker="#public_encrypt/3">public_encrypt/3</seealso>)
- using the <c>PrivateKey</c> and returns the
- message. The <c>Padding</c> is the padding mode that was
- used to encrypt the data,
- see <seealso marker="#public_encrypt/3">public_encrypt/3</seealso>.
- See also <seealso marker="public_key:public_key#decrypt_private/2">public_key:decrypt_private/[2,3]</seealso>
+ <p>Decrypts the <c>ChipherText</c>, encrypted with
+ <seealso marker="#public_encrypt-4">public_encrypt/4</seealso> (or equivalent function)
+ using the <c>PrivateKey</c>, and returns the
+ plaintext (message digest). This is a low level signature verification operation
+ used for instance by older versions of the SSL protocol.
+ See also <seealso marker="public_key:public_key#decrypt_private-2">public_key:decrypt_private/[2,3]</seealso>
</p>
</desc>
</func>
-
+
<func>
<name>private_encrypt(Type, PlainText, PrivateKey, Padding) -> ChipherText</name>
- <fsummary>Encrypts Msg using the private Key.</fsummary>
+ <fsummary>Encrypts PlainText using the private Key.</fsummary>
<type>
<v>Type = rsa</v>
<v>PlainText = binary()</v>
+ <d> The size of the <c>PlainText</c> must be less
+ than <c>byte_size(N)-11</c> if <c>rsa_pkcs1_padding</c> is
+ used, and <c>byte_size(N)</c> if <c>rsa_no_padding</c> is
+ used, where N is public modulus of the RSA key.</d>
<v>PrivateKey = rsa_private()</v>
<v>Padding = rsa_pkcs1_padding | rsa_no_padding</v>
<v>ChipherText = binary()</v>
</type>
<desc>
<p>Encrypts the <c>PlainText</c> using the <c>PrivateKey</c>
- and returns the cipher. The <c>Padding</c> decides what padding mode is used,
- <c>rsa_pkcs1_padding</c> is PKCS #1 v1.5 currently the most
- used mode.
- The size of the <c>Msg</c> must be less than <c>byte_size(N)-11</c> if
- <c>rsa_pkcs1_padding</c> is used, and <c>byte_size(N)</c> if <c>rsa_no_padding</c>
- is used.
- See also <seealso marker="public_key:public_key#encrypt_private/2">public_key:encrypt_private/[2,3]</seealso>
+ and returns the ciphertext. This is a low level signature operation
+ used for instance by older versions of the SSL protocol. See
+ also <seealso
+ marker="public_key:public_key#encrypt_private-2">public_key:encrypt_private/[2,3]</seealso>
</p>
</desc>
</func>
@@ -491,40 +491,35 @@
<v>PlainText = binary()</v>
</type>
<desc>
- <p>Decrypts the <c>ChipherText</c> (encrypted with
- <seealso marker="#private_encrypt/3">private_encrypt/3</seealso>)
- using the <c>PrivateKey</c> and returns the
- message. The <c>Padding</c> is the padding mode that was
- used to encrypt the data,
- see <seealso marker="#private_encrypt/3">private_encrypt/3</seealso>.
- See also <seealso marker="public_key:public_key#decrypt_public/2">public_key:decrypt_public/[2,3]</seealso>
+ <p>Decrypts the <c>ChipherText</c>, encrypted with
+ <seealso marker="#private_encrypt-4">private_encrypt/4</seealso>(or equivalent function)
+ using the <c>PrivateKey</c>, and returns the
+ plaintext (message digest). This is a low level signature verification operation
+ used for instance by older versions of the SSL protocol.
+ See also <seealso marker="public_key:public_key#decrypt_public-2">public_key:decrypt_public/[2,3]</seealso>
</p>
</desc>
</func>
<func>
<name>public_encrypt(Type, PlainText, PublicKey, Padding) -> ChipherText</name>
- <fsummary>Encrypts Msg using the public Key.</fsummary>
+ <fsummary>Encrypts PlainText using the public Key.</fsummary>
<type>
<v>Type = rsa</v>
<v>PlainText = binary()</v>
+ <d> The size of the <c>PlainText</c> must be less
+ than <c>byte_size(N)-11</c> if <c>rsa_pkcs1_padding</c> is
+ used, and <c>byte_size(N)</c> if <c>rsa_no_padding</c> is
+ used, where N is public modulus of the RSA key.</d>
<v>PublicKey = rsa_public()</v>
<v>Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding</v>
<v>ChipherText = binary()</v>
</type>
<desc>
- <p>Encrypts the <c>PlainText</c> (usually a session key) using the <c>PublicKey</c>
- and returns the <c>CipherText</c>. The <c>Padding</c> decides what padding mode is used,
- <c>rsa_pkcs1_padding</c> is PKCS #1 v1.5 currently the most
- used mode and <c>rsa_pkcs1_oaep_padding</c> is EME-OAEP as
- defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty encoding
- parameter. This mode is recommended for all new applications.
- The size of the <c>Msg</c> must be less
- than <c>byte_size(N)-11</c> if
- <c>rsa_pkcs1_padding</c> is used, <c>byte_size(N)-41</c> if
- <c>rsa_pkcs1_oaep_padding</c> is used and <c>byte_size(N)</c> if <c>rsa_no_padding</c>
- is used.
- See also <seealso marker="public_key:public_key#encrypt_public/2">public_key:encrypt_public/[2,3]</seealso>
+ <p>Encrypts the <c>PlainText</c> (message digest) using the <c>PublicKey</c>
+ and returns the <c>CipherText</c>. This is a low level signature operation
+ used for instance by older versions of the SSL protocol. See also <seealso
+ marker="public_key:public_key#encrypt_public-2">public_key:encrypt_public/[2,3]</seealso>
</p>
</desc>
</func>
@@ -561,9 +556,9 @@
<type>
<v>Algorithm = rsa | dss | ecdsa </v>
<v>Msg = binary() | {digest,binary()}</v>
- <d>The msg is either the binary "plain text" data to be
- signed or it is the hashed value of "plain text" i.e. the
- digest.</d>
+ <d>The msg is either the binary "cleartext" data to be
+ signed or it is the hashed value of "cleartext" i.e. the
+ digest (plaintext).</d>
<v>DigestType = digest_type()</v>
<v>Key = rsa_private() | dss_private() | [ecdh_private(),ecdh_params()]</v>
</type>
@@ -571,7 +566,7 @@
<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>
+ See also <seealso marker="public_key:public_key#sign-3">public_key:sign/3</seealso>
</desc>
</func>
@@ -615,8 +610,8 @@
</type>
<desc>
<p>Initializes the state for use in RC4 stream encryption
- <seealso marker="#stream_encrypt/2">stream_encrypt</seealso> and
- <seealso marker="#stream_decrypt/2">stream_decrypt</seealso></p>
+ <seealso marker="#stream_encrypt-2">stream_encrypt</seealso> and
+ <seealso marker="#stream_decrypt-2">stream_decrypt</seealso></p>
</desc>
</func>
@@ -633,8 +628,8 @@
<p>Initializes the state for use in streaming AES encryption using Counter mode (CTR).
<c>Key</c> is the AES key and must be either 128, 192, or 256 bts long. <c>IVec</c> is
an arbitrary initializing vector of 128 bits (16 bytes). This state is for use with
- <seealso marker="#stream_encrypt/2">stream_encrypt</seealso> and
- <seealso marker="#stream_decrypt/2">stream_decrypt</seealso>.</p>
+ <seealso marker="#stream_encrypt-2">stream_encrypt</seealso> and
+ <seealso marker="#stream_decrypt-2">stream_decrypt</seealso>.</p>
</desc>
</func>
@@ -648,7 +643,7 @@
<desc>
<p>Encrypts <c>PlainText</c> according to the stream cipher <c>Type</c> specified in stream_init/3.
<c>Text</c> can be any number of bytes. The initial <c>State</c> is created using
- <seealso marker="#stream_init/2">stream_init</seealso>.
+ <seealso marker="#stream_init-2">stream_init</seealso>.
<c>NewState</c> must be passed into the next call to <c>stream_encrypt</c>.</p>
</desc>
</func>
@@ -663,7 +658,7 @@
<desc>
<p>Decrypts <c>CipherText</c> according to the stream cipher <c>Type</c> specified in stream_init/3.
<c>PlainText</c> can be any number of bytes. The initial <c>State</c> is created using
- <seealso marker="#stream_init/2">stream_init</seealso>.
+ <seealso marker="#stream_init-2">stream_init</seealso>.
<c>NewState</c> must be passed into the next call to <c>stream_encrypt</c>.</p>
</desc>
</func>
@@ -690,8 +685,8 @@
<type>
<v> Algorithm = rsa | dss | ecdsa </v>
<v>Msg = binary() | {digest,binary()}</v>
- <d>The msg is either the binary "plain text" data
- or it is the hashed value of "plain text" i.e. the digest.</d>
+ <d>The msg is either the binary "cleartext" data
+ or it is the hashed value of "cleartext" i.e. the digest (plaintext).</d>
<v>DigestType = digest_type()</v>
<v>Signature = binary()</v>
<v>Key = rsa_public() | dss_public() | [ecdh_public(),ecdh_params()]</v>
@@ -701,7 +696,7 @@
<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>
+ See also <seealso marker="public_key:public_key#verify-4">public_key:verify/4</seealso>
</desc>
</func>
diff --git a/lib/crypto/src/crypto.appup.src b/lib/crypto/src/crypto.appup.src
index b39ef734eb..5b4ce5acee 100644
--- a/lib/crypto/src/crypto.appup.src
+++ b/lib/crypto/src/crypto.appup.src
@@ -1,7 +1,8 @@
+%% -*- erlang -*-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2009. 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
@@ -17,6 +18,11 @@
%% %CopyrightEnd%
%%
{"%VSN%",
- [],
- []
-}.
+ [
+ {<<"2\\.*">>, [{restart_application, crypto}]}
+ {<<"1\\.*">>, [{restart_application, crypto}]}
+ ],
+ [
+ {<<"2\\.*">>, [{restart_application, crypto}]}
+ {<<"1\\.*">>, [{restart_application, crypto}]}
+ ]}.
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index e042545094..a093b45410 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -35,7 +35,6 @@
-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]).
@@ -165,60 +164,8 @@
-export([info/0]).
-deprecated({info, 0, next_major_release}).
--define(FUNC_LIST, [hash, hash_init, hash_update, hash_final,
- hmac, hmac_init, hmac_update, hmac_final, hmac_final_n,
- %% deprecated
- md4, md4_init, md4_update, md4_final,
- md5, md5_init, md5_update, md5_final,
- sha, sha_init, sha_update, sha_final,
- md5_mac, md5_mac_96,
- sha_mac, sha_mac_96,
- %%
- block_encrypt, block_decrypt,
- %% deprecated
- des_cbc_encrypt, des_cbc_decrypt,
- des_cfb_encrypt, des_cfb_decrypt,
- des_ecb_encrypt, des_ecb_decrypt,
- des3_cbc_encrypt, des3_cbc_decrypt,
- des3_cfb_encrypt, des3_cfb_decrypt,
- aes_cfb_128_encrypt, aes_cfb_128_decrypt,
- rc2_cbc_encrypt, rc2_cbc_decrypt,
- rc2_40_cbc_encrypt, rc2_40_cbc_decrypt,
- aes_cbc_128_encrypt, aes_cbc_128_decrypt,
- aes_cbc_256_encrypt, aes_cbc_256_decrypt,
- blowfish_cbc_encrypt, blowfish_cbc_decrypt,
- blowfish_cfb64_encrypt, blowfish_cfb64_decrypt,
- blowfish_ecb_encrypt, blowfish_ecb_decrypt, blowfish_ofb64_encrypt,
- %%
- rand_bytes,
- strong_rand_bytes,
- rand_uniform,
- mod_pow,
- exor,
- %% deprecated
- mod_exp,strong_rand_mpint,erlint, mpint,
- %%
- sign, verify, generate_key, compute_key,
- %% deprecated
- dss_verify,dss_sign,
- rsa_verify,rsa_sign,
- rsa_public_encrypt,rsa_private_decrypt,
- rsa_private_encrypt,rsa_public_decrypt,
- dh_generate_key, dh_compute_key,
- %%
- stream_init, stream_encrypt, stream_decrypt,
- %% deprecated
- rc4_encrypt, rc4_set_key, rc4_encrypt_with_state,
- aes_ctr_encrypt, aes_ctr_decrypt,
- aes_ctr_stream_init, aes_ctr_stream_encrypt, aes_ctr_stream_decrypt,
- %%
- next_iv,
- %% deprecated
- aes_cbc_ivec,
- des_cbc_ivec, des_cfb_ivec,
- info,
- %%
- info_lib, supports]).
+%% This should correspond to the similar macro in crypto.c
+-define(MAX_BYTES_TO_NIF, 20000). %% Current value is: erlang:system_info(context_reductions) * 10
-type mpint() :: binary().
-type rsa_digest_type() :: 'md5' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'.
@@ -235,76 +182,27 @@
%%-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)).
-
-on_load(on_load/0).
-
-define(CRYPTO_NIF_VSN,201).
-on_load() ->
- LibBaseName = "crypto",
- PrivDir = code:priv_dir(crypto),
- LibName = case erlang:system_info(build_type) of
- opt ->
- LibBaseName;
- Type ->
- LibTypeName = LibBaseName ++ "." ++ atom_to_list(Type),
- case (filelib:wildcard(
- filename:join(
- [PrivDir,
- "lib",
- LibTypeName ++ "*"])) /= []) orelse
- (filelib:wildcard(
- filename:join(
- [PrivDir,
- "lib",
- erlang:system_info(system_architecture),
- LibTypeName ++ "*"])) /= []) of
- true -> LibTypeName;
- false -> LibBaseName
- end
- end,
- Lib = filename:join([PrivDir, "lib", LibName]),
- Status = case erlang:load_nif(Lib, {?CRYPTO_NIF_VSN,Lib}) of
- ok -> ok;
- {error, {load_failed, _}}=Error1 ->
- ArchLibDir =
- filename:join([PrivDir, "lib",
- erlang:system_info(system_architecture)]),
- Candidate =
- filelib:wildcard(filename:join([ArchLibDir,LibName ++ "*" ])),
- case Candidate of
- [] -> Error1;
- _ ->
- ArchLib = filename:join([ArchLibDir, LibName]),
- erlang:load_nif(ArchLib, {?CRYPTO_NIF_VSN,ArchLib})
- end;
- Error1 -> Error1
- end,
- case Status of
- ok -> ok;
- {error, {E, Str}} ->
- error_logger:error_msg("Unable to load crypto library. Failed with error:~n\"~p, ~s\"~n"
- "OpenSSL might not be installed on this system.~n",[E,Str]),
- Status
- end.
-
+-define(nif_stub,nif_stub_error(?LINE)).
nif_stub_error(Line) ->
erlang:nif_error({nif_not_loaded,module,?MODULE,line,Line}).
+%%--------------------------------------------------------------------
+%%% API
+%%--------------------------------------------------------------------
+%% Crypto app version history:
+%% (no version): Driver implementation
+%% 2.0 : NIF implementation, requires OTP R14
+version() -> ?CRYPTO_VSN.
+
start() ->
application:start(crypto).
stop() ->
application:stop(crypto).
-info() ->
- ?FUNC_LIST.
-
-info_lib() -> ?nif_stub.
-
-algorithms() -> ?nif_stub.
-
supports()->
Algs = algorithms(),
PubKeyAlgs =
@@ -316,32 +214,20 @@ supports()->
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
+ 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
-version() -> ?CRYPTO_VSN.
-
-%% Below Key and Data are binaries or IO-lists. IVec is a binary.
-%% Output is always a binary. Context is a binary.
-
-%%
-%% MESSAGE DIGESTS
-%%
+info_lib() -> ?nif_stub.
-spec hash(_, iodata()) -> binary().
-hash(md5, Data) -> md5(Data);
-hash(md4, Data) -> md4(Data);
-hash(sha, Data) -> sha(Data);
-hash(ripemd160, Data) -> ripemd160(Data);
-hash(sha224, Data) -> sha224(Data);
-hash(sha256, Data) -> sha256(Data);
-hash(sha384, Data) -> sha384(Data);
-hash(sha512, Data) -> sha512(Data).
+
+hash(Hash, Data0) ->
+ Data = iolist_to_binary(Data0),
+ MaxByts = max_bytes(),
+ hash(Hash, Data, erlang:byte_size(Data), MaxByts, initial).
-spec hash_init('md5'|'md4'|'ripemd160'|
'sha'|'sha224'|'sha256'|'sha384'|'sha512') -> any().
@@ -357,14 +243,10 @@ hash_init(sha512) -> {sha512, sha512_init()}.
-spec hash_update(_, iodata()) -> any().
-hash_update({md5,Context}, Data) -> {md5, md5_update(Context,Data)};
-hash_update({md4,Context}, Data) -> {md4, md4_update(Context,Data)};
-hash_update({sha,Context}, Data) -> {sha, sha_update(Context,Data)};
-hash_update({ripemd160,Context}, Data) -> {ripemd160, ripemd160_update(Context,Data)};
-hash_update({sha224,Context}, Data) -> {sha224, sha224_update(Context,Data)};
-hash_update({sha256,Context}, Data) -> {sha256, sha256_update(Context,Data)};
-hash_update({sha384,Context}, Data) -> {sha384, sha384_update(Context,Data)};
-hash_update({sha512,Context}, Data) -> {sha512, sha512_update(Context,Data)}.
+hash_update(State, Data0) ->
+ Data = iolist_to_binary(Data0),
+ MaxBytes = max_bytes(),
+ hash_update(State, Data, erlang:byte_size(Data), MaxBytes).
-spec hash_final(_) -> binary().
@@ -377,6 +259,457 @@ hash_final({sha256,Context}) -> sha256_final(Context);
hash_final({sha384,Context}) -> sha384_final(Context);
hash_final({sha512,Context}) -> sha512_final(Context).
+
+-spec hmac(_, iodata(), iodata()) -> binary().
+-spec hmac(_, iodata(), iodata(), integer()) -> binary().
+-spec hmac_init(atom(), iodata()) -> binary().
+-spec hmac_update(binary(), iodata()) -> binary().
+-spec hmac_final(binary()) -> binary().
+-spec hmac_final_n(binary(), integer()) -> binary().
+
+hmac(Type, Key, Data0) ->
+ Data = iolist_to_binary(Data0),
+ hmac(Type, Key, Data, undefined, erlang:byte_size(Data), max_bytes(), initial).
+hmac(Type, Key, Data0, MacSize) ->
+ Data = iolist_to_binary(Data0),
+ hmac(Type, Key, Data, MacSize, erlang:byte_size(Data), max_bytes(), initial).
+
+
+hmac_init(_Type, _Key) -> ?nif_stub.
+
+hmac_update(State, Data0) ->
+ Data = iolist_to_binary(Data0),
+ hmac_update(State, Data, erlang:byte_size(Data), max_bytes()).
+hmac_final(_Context) -> ? nif_stub.
+hmac_final_n(_Context, _HashLen) -> ? nif_stub.
+
+%% Ecrypt/decrypt %%%
+
+-spec block_encrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc |
+ blowfish_cfb64 | aes_cbc128 | aes_cfb128 | aes_cbc256 | rc2_cbc,
+ Key::iodata(), Ivec::binary(), Data::iodata()) -> binary().
+
+block_encrypt(des_cbc, Key, Ivec, Data) ->
+ des_cbc_encrypt(Key, Ivec, Data);
+block_encrypt(des_cfb, Key, Ivec, Data) ->
+ des_cfb_encrypt(Key, Ivec, Data);
+block_encrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) ->
+ des3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data);
+block_encrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) ->
+ des3_cfb_encrypt(Key1, Key2, Key3, Ivec, Data);
+block_encrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) ->
+ des_ede3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data);
+block_encrypt(blowfish_cbc, Key, Ivec, Data) ->
+ blowfish_cbc_encrypt(Key, Ivec, Data);
+block_encrypt(blowfish_cfb64, Key, Ivec, Data) ->
+ blowfish_cfb64_encrypt(Key, Ivec, Data);
+block_encrypt(blowfish_ofb64, Key, Ivec, Data) ->
+ blowfish_ofb64_encrypt(Key, Ivec, Data);
+block_encrypt(aes_cbc128, Key, Ivec, Data) ->
+ aes_cbc_128_encrypt(Key, Ivec, Data);
+block_encrypt(aes_cbc256, Key, Ivec, Data) ->
+ aes_cbc_256_encrypt(Key, Ivec, Data);
+block_encrypt(aes_cfb128, Key, Ivec, Data) ->
+ aes_cfb_128_encrypt(Key, Ivec, Data);
+block_encrypt(rc2_cbc, Key, Ivec, Data) ->
+ rc2_cbc_encrypt(Key, Ivec, Data).
+
+-spec block_decrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc |
+ blowfish_cfb64 | blowfish_ofb64 | aes_cbc128 | aes_cbc256 | aes_cfb128 | rc2_cbc,
+ Key::iodata(), Ivec::binary(), Data::iodata()) -> binary().
+
+block_decrypt(des_cbc, Key, Ivec, Data) ->
+ des_cbc_decrypt(Key, Ivec, Data);
+block_decrypt(des_cfb, Key, Ivec, Data) ->
+ des_cfb_decrypt(Key, Ivec, Data);
+block_decrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) ->
+ des3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data);
+block_decrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) ->
+ des3_cfb_decrypt(Key1, Key2, Key3, Ivec, Data);
+block_decrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) ->
+ des_ede3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data);
+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_ofb64, Key, Ivec, Data) ->
+ blowfish_ofb64_decrypt(Key, Ivec, Data);
+block_decrypt(aes_cbc128, Key, Ivec, Data) ->
+ aes_cbc_128_decrypt(Key, Ivec, Data);
+block_decrypt(aes_cbc256, Key, Ivec, Data) ->
+ aes_cbc_256_decrypt(Key, Ivec, Data);
+block_decrypt(aes_cfb128, Key, Ivec, Data) ->
+ aes_cfb_128_decrypt(Key, Ivec, Data);
+block_decrypt(rc2_cbc, Key, Ivec, Data) ->
+ rc2_cbc_decrypt(Key, Ivec, Data).
+
+-spec block_encrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary().
+
+block_encrypt(des_ecb, Key, Data) ->
+ des_ecb_encrypt(Key, Data);
+block_encrypt(blowfish_ecb, Key, Data) ->
+ blowfish_ecb_encrypt(Key, Data).
+
+-spec block_decrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary().
+
+block_decrypt(des_ecb, Key, Data) ->
+ des_ecb_decrypt(Key, Data);
+block_decrypt(blowfish_ecb, Key, Data) ->
+ blowfish_ecb_decrypt(Key, Data).
+
+-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_cfb, Data::iodata(), Ivec::binary()) -> binary().
+
+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(State, Data0) ->
+ Data = iolist_to_binary(Data0),
+ MaxByts = max_bytes(),
+ stream_crypt(fun do_stream_encrypt/2, State, Data, erlang:byte_size(Data), MaxByts, []).
+
+stream_decrypt(State, Data0) ->
+ Data = iolist_to_binary(Data0),
+ MaxByts = max_bytes(),
+ stream_crypt(fun do_stream_decrypt/2, State, Data, erlang:byte_size(Data), MaxByts, []).
+
+%%
+%% RAND - pseudo random numbers using RN_ functions in crypto lib
+%%
+-spec rand_bytes(non_neg_integer()) -> binary().
+-spec strong_rand_bytes(non_neg_integer()) -> binary().
+-spec rand_uniform(crypto_integer(), crypto_integer()) ->
+ crypto_integer().
+
+rand_bytes(_Bytes) -> ?nif_stub.
+
+strong_rand_bytes(Bytes) ->
+ case strong_rand_bytes_nif(Bytes) of
+ false -> erlang:error(low_entropy);
+ Bin -> Bin
+ end.
+strong_rand_bytes_nif(_Bytes) -> ?nif_stub.
+
+rand_bytes(_Bytes, _Topmask, _Bottommask) -> ?nif_stub.
+
+
+rand_uniform(From,To) when is_binary(From), is_binary(To) ->
+ case rand_uniform_nif(From,To) of
+ <<Len:32/integer, MSB, Rest/binary>> when MSB > 127 ->
+ <<(Len + 1):32/integer, 0, MSB, Rest/binary>>;
+ Whatever ->
+ Whatever
+ end;
+rand_uniform(From,To) when is_integer(From),is_integer(To) ->
+ if From < 0 ->
+ rand_uniform_pos(0, To - From) + From;
+ true ->
+ rand_uniform_pos(From, To)
+ end.
+
+rand_uniform_pos(From,To) when From < To ->
+ BinFrom = mpint(From),
+ BinTo = mpint(To),
+ case rand_uniform(BinFrom, BinTo) of
+ Result when is_binary(Result) ->
+ erlint(Result);
+ Other ->
+ Other
+ end;
+rand_uniform_pos(_,_) ->
+ error(badarg).
+
+rand_uniform_nif(_From,_To) -> ?nif_stub.
+
+
+-spec mod_pow(binary()|integer(), binary()|integer(), binary()|integer()) -> binary() | error.
+mod_pow(Base, Exponent, Prime) ->
+ case mod_exp_nif(ensure_int_as_bin(Base), ensure_int_as_bin(Exponent), ensure_int_as_bin(Prime), 0) of
+ <<0>> -> error;
+ R -> R
+ end.
+verify(dss, none, Data, Signature, Key) when is_binary(Data) ->
+ verify(dss, sha, {digest, Data}, Signature, Key);
+verify(Alg, Type, Data, Signature, Key) when is_binary(Data) ->
+ verify(Alg, Type, {digest, hash(Type, Data)}, Signature, Key);
+verify(dss, Type, Data, Signature, Key) ->
+ dss_verify_nif(Type, Data, Signature, map_ensure_int_as_bin(Key));
+verify(rsa, Type, DataOrDigest, Signature, Key) ->
+ case rsa_verify_nif(Type, DataOrDigest, Signature, map_ensure_int_as_bin(Key)) of
+ notsup -> erlang:error(notsup);
+ 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
+ notsup -> erlang:error(notsup);
+ Bool -> Bool
+ end.
+sign(dss, none, Data, Key) when is_binary(Data) ->
+ sign(dss, sha, {digest, Data}, Key);
+sign(Alg, Type, Data, Key) when is_binary(Data) ->
+ sign(Alg, Type, {digest, hash(Type, Data)}, Key);
+sign(rsa, Type, DataOrDigest, Key) ->
+ case rsa_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of
+ error -> erlang:error(badkey, [Type,DataOrDigest,Key]);
+ Sign -> Sign
+ end;
+sign(dss, Type, DataOrDigest, Key) ->
+ case dss_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of
+ error -> erlang:error(badkey, [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
+ error -> erlang:error(badkey, [Type,DataOrDigest,Key]);
+ Sign -> Sign
+ end.
+
+-spec public_encrypt(rsa, binary(), [binary()], rsa_padding()) ->
+ binary().
+-spec public_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) ->
+ binary().
+-spec private_encrypt(rsa, binary(), [integer() | binary()], rsa_padding()) ->
+ binary().
+-spec private_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) ->
+ binary().
+
+public_encrypt(rsa, BinMesg, Key, Padding) ->
+ case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of
+ error ->
+ erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
+
+%% Binary, Key = [E,N,D]
+private_decrypt(rsa, BinMesg, Key, Padding) ->
+ case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of
+ error ->
+ erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
+
+
+%% Binary, Key = [E,N,D]
+private_encrypt(rsa, BinMesg, Key, Padding) ->
+ case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of
+ error ->
+ erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
+
+%% Binary, Key = [E,N]
+public_decrypt(rsa, BinMesg, Key, Padding) ->
+ case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of
+ error ->
+ erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
+
+%%
+%% XOR - xor to iolists and return a binary
+%% NB doesn't check that they are the same size, just concatenates
+%% them and sends them to the driver
+%%
+-spec exor(iodata(), iodata()) -> binary().
+
+exor(Bin1, Bin2) ->
+ Data1 = iolist_to_binary(Bin1),
+ Data2 = iolist_to_binary(Bin2),
+ MaxBytes = max_bytes(),
+ exor(Data1, Data2, erlang:byte_size(Data1), MaxBytes, []).
+
+generate_key(Type, Params) ->
+ generate_key(Type, Params, undefined).
+
+generate_key(dh, DHParameters, PrivateKey) ->
+ 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);
+ _ -> ensure_int_as_bin(PrivArg)
+ end,
+ host_srp_gen_key(Private, Verifier, Generator, Prime, Version);
+
+generate_key(srp, {user, [Generator, Prime, Version]}, PrivateArg)
+ when is_binary(Generator), is_binary(Prime), is_atom(Version) ->
+ Private = case PrivateArg of
+ undefined -> random_bytes(32);
+ _ -> PrivateArg
+ end,
+ user_srp_gen_key(Private, Generator, Prime);
+
+generate_key(ecdh, Curve, undefined) ->
+ ec_key_to_term_nif(ec_key_generate(Curve)).
+
+
+compute_key(dh, OthersPublicKey, MyPrivateKey, DHParameters) ->
+ 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
+ end;
+
+compute_key(srp, HostPublic, {UserPublic, UserPrivate},
+ {user, [DerivedKey, Prime, Generator, Version | ScramblerArg]}) when
+ is_binary(Prime),
+ is_binary(Generator),
+ is_atom(Version) ->
+ HostPubBin = ensure_int_as_bin(HostPublic),
+ Multiplier = srp_multiplier(Version, Generator, Prime),
+ Scrambler = case ScramblerArg of
+ [] -> srp_scrambler(Version, ensure_int_as_bin(UserPublic),
+ HostPubBin, Prime);
+ [S] -> S
+ end,
+ 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_atom(Version) ->
+ UserPubBin = ensure_int_as_bin(UserPublic),
+ Scrambler = case ScramblerArg of
+ [] -> srp_scrambler(Version, UserPubBin, ensure_int_as_bin(HostPublic), Prime);
+ [S] -> S
+ end,
+ srp_host_secret_nif(Verifier, ensure_int_as_bin(HostPrivate), Scrambler,
+ UserPubBin, Prime);
+
+compute_key(ecdh, Others, My, Curve) ->
+ ecdh_compute_key_nif(ensure_int_as_bin(Others),
+ term_to_ec_key(Curve,My,undefined)).
+
+
+random_bytes(N) ->
+ try strong_rand_bytes(N) of
+ RandBytes ->
+ RandBytes
+ catch
+ error:low_entropy ->
+ rand_bytes(N)
+ end.
+
+%%--------------------------------------------------------------------
+%%% On load
+%%--------------------------------------------------------------------
+
+on_load() ->
+ LibBaseName = "crypto",
+ PrivDir = code:priv_dir(crypto),
+ LibName = case erlang:system_info(build_type) of
+ opt ->
+ LibBaseName;
+ Type ->
+ LibTypeName = LibBaseName ++ "." ++ atom_to_list(Type),
+ case (filelib:wildcard(
+ filename:join(
+ [PrivDir,
+ "lib",
+ LibTypeName ++ "*"])) /= []) orelse
+ (filelib:wildcard(
+ filename:join(
+ [PrivDir,
+ "lib",
+ erlang:system_info(system_architecture),
+ LibTypeName ++ "*"])) /= []) of
+ true -> LibTypeName;
+ false -> LibBaseName
+ end
+ end,
+ Lib = filename:join([PrivDir, "lib", LibName]),
+ Status = case erlang:load_nif(Lib, {?CRYPTO_NIF_VSN,Lib}) of
+ ok -> ok;
+ {error, {load_failed, _}}=Error1 ->
+ ArchLibDir =
+ filename:join([PrivDir, "lib",
+ erlang:system_info(system_architecture)]),
+ Candidate =
+ filelib:wildcard(filename:join([ArchLibDir,LibName ++ "*" ])),
+ case Candidate of
+ [] -> Error1;
+ _ ->
+ ArchLib = filename:join([ArchLibDir, LibName]),
+ erlang:load_nif(ArchLib, {?CRYPTO_NIF_VSN,ArchLib})
+ end;
+ Error1 -> Error1
+ end,
+ case Status of
+ ok -> ok;
+ {error, {E, Str}} ->
+ error_logger:error_msg("Unable to load crypto library. Failed with error:~n\"~p, ~s\"~n"
+ "OpenSSL might not be installed on this system.~n",[E,Str]),
+ Status
+ end.
+%%--------------------------------------------------------------------
+%%% Internal functions (some internal API functions are part of the deprecated API)
+%%--------------------------------------------------------------------
+max_bytes() ->
+ ?MAX_BYTES_TO_NIF.
+
+%% HASH --------------------------------------------------------------------
+hash(Hash, Data, Size, Max, initial) when Size =< Max ->
+ do_hash(Hash, Data);
+hash(State0, Data, Size, Max, continue) when Size =< Max ->
+ State = do_hash_update(State0, Data),
+ hash_final(State);
+hash(Hash, Data, _Size, Max, initial) ->
+ <<Increment:Max/binary, Rest/binary>> = Data,
+ State0 = hash_init(Hash),
+ State = do_hash_update(State0, Increment),
+ hash(State, Rest, erlang:byte_size(Rest), max_bytes(), continue);
+hash(State0, Data, _Size, MaxByts, continue) ->
+ <<Increment:MaxByts/binary, Rest/binary>> = Data,
+ State = do_hash_update(State0, Increment),
+ hash(State, Rest, erlang:byte_size(Rest), max_bytes(), continue).
+
+do_hash(md5, Data) -> md5(Data);
+do_hash(md4, Data) -> md4(Data);
+do_hash(sha, Data) -> sha(Data);
+do_hash(ripemd160, Data) -> ripemd160(Data);
+do_hash(sha224, Data) -> sha224(Data);
+do_hash(sha256, Data) -> sha256(Data);
+do_hash(sha384, Data) -> sha384(Data);
+do_hash(sha512, Data) -> sha512(Data).
+
+hash_update(State, Data, Size, MaxBytes) when Size =< MaxBytes ->
+ do_hash_update(State, Data);
+hash_update(State0, Data, _, MaxBytes) ->
+ <<Increment:MaxBytes/binary, Rest/binary>> = Data,
+ State = do_hash_update(State0, Increment),
+ hash_update(State, Rest, erlang:byte_size(Rest), MaxBytes).
+
+do_hash_update({md5,Context}, Data) -> {md5, md5_update(Context,Data)};
+do_hash_update({md4,Context}, Data) -> {md4, md4_update(Context,Data)};
+do_hash_update({sha,Context}, Data) -> {sha, sha_update(Context,Data)};
+do_hash_update({ripemd160,Context}, Data) -> {ripemd160, ripemd160_update(Context,Data)};
+do_hash_update({sha224,Context}, Data) -> {sha224, sha224_update(Context,Data)};
+do_hash_update({sha256,Context}, Data) -> {sha256, sha256_update(Context,Data)};
+do_hash_update({sha384,Context}, Data) -> {sha384, sha384_update(Context,Data)};
+do_hash_update({sha512,Context}, Data) -> {sha512, sha512_update(Context,Data)}.
+
+
%%
%% MD5
%%
@@ -567,40 +900,56 @@ sha512_init_nif() -> ?nif_stub.
sha512_update_nif(_Context, _Data) -> ?nif_stub.
sha512_final_nif(_Context) -> ?nif_stub.
-%%
-%% MESSAGE AUTHENTICATION CODES
-%%
-
-%%
-%% HMAC (multiple hash options)
-%%
+%% HMAC --------------------------------------------------------------------
--spec hmac(_, iodata(), iodata()) -> binary().
--spec hmac(_, iodata(), iodata(), integer()) -> binary().
--spec hmac_init(atom(), iodata()) -> binary().
--spec hmac_update(binary(), iodata()) -> binary().
--spec hmac_final(binary()) -> binary().
--spec hmac_final_n(binary(), integer()) -> binary().
-
-hmac(md5, Key, Data) -> md5_mac(Key, Data);
-hmac(sha, Key, Data) -> sha_mac(Key, Data);
-hmac(sha224, Key, Data) -> sha224_mac(Key, Data);
-hmac(sha256, Key, Data) -> sha256_mac(Key, Data);
-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_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);
-hmac(sha512, Key, Data, Size) -> sha512_mac(Key, Data, Size).
+hmac(Type, Key, Data, MacSize, Size, MaxBytes, initial) when Size =< MaxBytes ->
+ case MacSize of
+ undefined ->
+ do_hmac(Type, Key, Data);
+ _ ->
+ do_hmac(Type, Key, Data, MacSize)
+ end;
+hmac(Type, Key, Data, MacSize, _, MaxBytes, initial) ->
+ <<Increment:MaxBytes/binary, Rest/binary>> = Data,
+ State0 = hmac_init(Type, Key),
+ State = hmac_update(State0, Increment),
+ hmac(State, Rest, MacSize, erlang:byte_size(Rest), max_bytes(), continue).
+hmac(State0, Data, MacSize, Size, MaxBytes, continue) when Size =< MaxBytes ->
+ State = hmac_update(State0, Data),
+ case MacSize of
+ undefined ->
+ hmac_final(State);
+ _ ->
+ hmac_final_n(State, MacSize)
+ end;
+hmac(State0, Data, MacSize, _Size, MaxBytes, continue) ->
+ <<Increment:MaxBytes/binary, Rest/binary>> = Data,
+ State = hmac_update(State0, Increment),
+ hmac(State, Rest, MacSize, erlang:byte_size(Rest), max_bytes(), continue).
+
+hmac_update(State, Data, Size, MaxBytes) when Size =< MaxBytes ->
+ do_hmac_update(State, Data);
+hmac_update(State0, Data, _, MaxBytes) ->
+ <<Increment:MaxBytes/binary, Rest/binary>> = Data,
+ State = do_hmac_update(State0, Increment),
+ hmac_update(State, Rest, erlang:byte_size(Rest), MaxBytes).
+
+do_hmac(md5, Key, Data) -> md5_mac(Key, Data);
+do_hmac(sha, Key, Data) -> sha_mac(Key, Data);
+do_hmac(sha224, Key, Data) -> sha224_mac(Key, Data);
+do_hmac(sha256, Key, Data) -> sha256_mac(Key, Data);
+do_hmac(sha384, Key, Data) -> sha384_mac(Key, Data);
+do_hmac(sha512, Key, Data) -> sha512_mac(Key, Data).
+
+do_hmac(md5, Key, Data, Size) -> md5_mac_n(Key, Data, Size);
+do_hmac(sha, Key, Data, Size) -> sha_mac_n(Key, Data, Size);
+do_hmac(sha224, Key, Data, Size) -> sha224_mac(Key, Data, Size);
+do_hmac(sha256, Key, Data, Size) -> sha256_mac(Key, Data, Size);
+do_hmac(sha384, Key, Data, Size) -> sha384_mac(Key, Data, Size);
+do_hmac(sha512, Key, Data, Size) -> sha512_mac(Key, Data, Size).
+
+do_hmac_update(_Context, _Data) -> ? nif_stub.
-hmac_init(_Type, _Key) -> ?nif_stub.
-hmac_update(_Context, _Data) -> ? nif_stub.
-hmac_final(_Context) -> ? nif_stub.
-hmac_final_n(_Context, _HashLen) -> ? nif_stub.
-
%%
%% MD5_MAC
%%
@@ -696,172 +1045,7 @@ sha512_mac(Key, Data, MacSz) ->
sha512_mac_nif(_Key,_Data,_MacSz) -> ?nif_stub.
-
-%% Ecrypt/decrypt %%%
-
--spec block_encrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc |
- blowfish_cfb64 | aes_cbc128 | aes_cfb128 | aes_cbc256 | rc2_cbc,
- Key::iodata(), Ivec::binary(), Data::iodata()) -> binary().
-
-block_encrypt(des_cbc, Key, Ivec, Data) ->
- des_cbc_encrypt(Key, Ivec, Data);
-block_encrypt(des_cfb, Key, Ivec, Data) ->
- des_cfb_encrypt(Key, Ivec, Data);
-block_encrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) ->
- des3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data);
-block_encrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) ->
- des3_cfb_encrypt(Key1, Key2, Key3, Ivec, Data);
-block_encrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) ->
- des_ede3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data);
-block_encrypt(blowfish_cbc, Key, Ivec, Data) ->
- blowfish_cbc_encrypt(Key, Ivec, Data);
-block_encrypt(blowfish_cfb64, Key, Ivec, Data) ->
- blowfish_cfb64_encrypt(Key, Ivec, Data);
-block_encrypt(blowfish_ofb64, Key, Ivec, Data) ->
- blowfish_ofb64_encrypt(Key, Ivec, Data);
-block_encrypt(aes_cbc128, Key, Ivec, Data) ->
- aes_cbc_128_encrypt(Key, Ivec, Data);
-block_encrypt(aes_cbc256, Key, Ivec, Data) ->
- aes_cbc_256_encrypt(Key, Ivec, Data);
-block_encrypt(aes_cfb128, Key, Ivec, Data) ->
- aes_cfb_128_encrypt(Key, Ivec, Data);
-block_encrypt(rc2_cbc, Key, Ivec, Data) ->
- rc2_cbc_encrypt(Key, Ivec, Data).
-
--spec block_decrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc |
- blowfish_cfb64 | blowfish_ofb64 | aes_cbc128 | aes_cbc256 | aes_cfb128 | rc2_cbc,
- Key::iodata(), Ivec::binary(), Data::iodata()) -> binary().
-
-block_decrypt(des_cbc, Key, Ivec, Data) ->
- des_cbc_decrypt(Key, Ivec, Data);
-block_decrypt(des_cfb, Key, Ivec, Data) ->
- des_cfb_decrypt(Key, Ivec, Data);
-block_decrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) ->
- des3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data);
-block_decrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) ->
- des3_cfb_decrypt(Key1, Key2, Key3, Ivec, Data);
-block_decrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) ->
- des_ede3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data);
-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_ofb64, Key, Ivec, Data) ->
- blowfish_ofb64_decrypt(Key, Ivec, Data);
-block_decrypt(aes_cbc128, Key, Ivec, Data) ->
- aes_cbc_128_decrypt(Key, Ivec, Data);
-block_decrypt(aes_cbc256, Key, Ivec, Data) ->
- aes_cbc_256_decrypt(Key, Ivec, Data);
-block_decrypt(aes_cfb128, Key, Ivec, Data) ->
- aes_cfb_128_decrypt(Key, Ivec, Data);
-block_decrypt(rc2_cbc, Key, Ivec, Data) ->
- rc2_cbc_decrypt(Key, Ivec, Data).
-
--spec block_encrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary().
-
-block_encrypt(des_ecb, Key, Data) ->
- des_ecb_encrypt(Key, Data);
-block_encrypt(blowfish_ecb, Key, Data) ->
- blowfish_ecb_encrypt(Key, Data).
-
--spec block_decrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary().
-
-block_decrypt(des_ecb, Key, Data) ->
- des_ecb_decrypt(Key, Data);
-block_decrypt(blowfish_ecb, Key, Data) ->
- blowfish_ecb_decrypt(Key, Data).
-
--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_cfb, Data::iodata(), Ivec::binary()) -> binary().
-
-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, 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),
- {{rc4, State}, Cipher}.
-stream_decrypt({aes_ctr, State0}, Data) ->
- {State, Text} = aes_ctr_stream_decrypt(State0, Data),
- {{aes_ctr, State}, Text};
-stream_decrypt({rc4, State0}, Data) ->
- {State, Text} = rc4_encrypt_with_state (State0, Data),
- {{rc4, State}, Text}.
-
-%%
-%% CRYPTO FUNCTIONS
-%%
-
-%%
-%% DES - in cipher block chaining mode (CBC)
-%%
--spec des_cbc_encrypt(iodata(), binary(), iodata()) -> binary().
--spec des_cbc_decrypt(iodata(), binary(), iodata()) -> binary().
-
-des_cbc_encrypt(Key, IVec, Data) ->
- des_cbc_crypt(Key, IVec, Data, true).
-
-des_cbc_decrypt(Key, IVec, Data) ->
- des_cbc_crypt(Key, IVec, Data, false).
-
-des_cbc_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
-
-%%
-%% dec_cbc_ivec(Data) -> binary()
-%%
-%% Returns the IVec to be used in the next iteration of
-%% des_cbc_[encrypt|decrypt].
-%%
--spec des_cbc_ivec(iodata()) -> binary().
-
-des_cbc_ivec(Data) when is_binary(Data) ->
- {_, IVec} = split_binary(Data, size(Data) - 8),
- IVec;
-des_cbc_ivec(Data) when is_list(Data) ->
- des_cbc_ivec(list_to_binary(Data)).
-
-%%
-%% DES - in 8-bits cipher feedback mode (CFB)
-%%
--spec des_cfb_encrypt(iodata(), binary(), iodata()) -> binary().
--spec des_cfb_decrypt(iodata(), binary(), iodata()) -> binary().
-
-des_cfb_encrypt(Key, IVec, Data) ->
- des_cfb_crypt(Key, IVec, Data, true).
-
-des_cfb_decrypt(Key, IVec, Data) ->
- des_cfb_crypt(Key, IVec, Data, false).
-
-des_cfb_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
-
-%%
-%% dec_cfb_ivec(IVec, Data) -> binary()
-%%
-%% Returns the IVec to be used in the next iteration of
-%% des_cfb_[encrypt|decrypt].
-%%
--spec des_cfb_ivec(iodata(), iodata()) -> binary().
-
-des_cfb_ivec(IVec, Data) ->
- IVecAndData = list_to_binary([IVec, Data]),
- {_, NewIVec} = split_binary(IVecAndData, byte_size(IVecAndData) - 8),
- NewIVec.
+%% CIPHERS --------------------------------------------------------------------
%%
%% DES - in electronic codebook mode (ECB)
@@ -973,292 +1157,63 @@ aes_cfb_128_decrypt(Key, IVec, Data) ->
aes_cfb_128_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
-%%
-%% RAND - pseudo random numbers using RN_ functions in crypto lib
%%
--spec rand_bytes(non_neg_integer()) -> binary().
--spec strong_rand_bytes(non_neg_integer()) -> binary().
--spec rand_uniform(crypto_integer(), crypto_integer()) ->
- crypto_integer().
--spec strong_rand_mpint(Bits::non_neg_integer(),
- Top::-1..1,
- Bottom::0..1) -> binary().
-
-rand_bytes(_Bytes) -> ?nif_stub.
-
-strong_rand_bytes(Bytes) ->
- case strong_rand_bytes_nif(Bytes) of
- false -> erlang:error(low_entropy);
- Bin -> Bin
- end.
-strong_rand_bytes_nif(_Bytes) -> ?nif_stub.
-
-rand_bytes(_Bytes, _Topmask, _Bottommask) -> ?nif_stub.
-
-strong_rand_mpint(Bits, Top, Bottom) ->
- case strong_rand_mpint_nif(Bits,Top,Bottom) of
- false -> erlang:error(low_entropy);
- Bin -> Bin
- end.
-strong_rand_mpint_nif(_Bits, _Top, _Bottom) -> ?nif_stub.
-
+%% DES - in cipher block chaining mode (CBC)
+%%
+-spec des_cbc_encrypt(iodata(), binary(), iodata()) -> binary().
+-spec des_cbc_decrypt(iodata(), binary(), iodata()) -> binary().
-rand_uniform(From,To) when is_binary(From), is_binary(To) ->
- case rand_uniform_nif(From,To) of
- <<Len:32/integer, MSB, Rest/binary>> when MSB > 127 ->
- <<(Len + 1):32/integer, 0, MSB, Rest/binary>>;
- Whatever ->
- Whatever
- end;
-rand_uniform(From,To) when is_integer(From),is_integer(To) ->
- if From < 0 ->
- rand_uniform_pos(0, To - From) + From;
- true ->
- rand_uniform_pos(From, To)
- end.
+des_cbc_encrypt(Key, IVec, Data) ->
+ des_cbc_crypt(Key, IVec, Data, true).
-rand_uniform_pos(From,To) when From < To ->
- BinFrom = mpint(From),
- BinTo = mpint(To),
- case rand_uniform(BinFrom, BinTo) of
- Result when is_binary(Result) ->
- erlint(Result);
- Other ->
- Other
- end;
-rand_uniform_pos(_,_) ->
- error(badarg).
+des_cbc_decrypt(Key, IVec, Data) ->
+ des_cbc_crypt(Key, IVec, Data, false).
-rand_uniform_nif(_From,_To) -> ?nif_stub.
+des_cbc_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
%%
-%% mod_exp - utility for rsa generation and SRP
+%% dec_cbc_ivec(Data) -> binary()
%%
-mod_exp(Base, Exponent, Modulo)
- when is_integer(Base), is_integer(Exponent), is_integer(Modulo) ->
- bin_to_int(mod_exp_nif(int_to_bin(Base), int_to_bin(Exponent), int_to_bin(Modulo), 0));
-
-mod_exp(Base, Exponent, Modulo) ->
- mod_exp_nif(mpint_to_bin(Base),mpint_to_bin(Exponent),mpint_to_bin(Modulo), 4).
-
--spec mod_pow(binary()|integer(), binary()|integer(), binary()|integer()) -> binary() | error.
-mod_pow(Base, Exponent, Prime) ->
- case mod_exp_nif(ensure_int_as_bin(Base), ensure_int_as_bin(Exponent), ensure_int_as_bin(Prime), 0) of
- <<0>> -> error;
- R -> R
- end.
-
+%% Returns the IVec to be used in the next iteration of
+%% des_cbc_[encrypt|decrypt].
+%%
+-spec des_cbc_ivec(iodata()) -> binary().
-mod_exp_nif(_Base,_Exp,_Mod,_bin_hdr) -> ?nif_stub.
+des_cbc_ivec(Data) when is_binary(Data) ->
+ {_, IVec} = split_binary(Data, size(Data) - 8),
+ IVec;
+des_cbc_ivec(Data) when is_list(Data) ->
+ des_cbc_ivec(list_to_binary(Data)).
%%
-%% DSS, RSA - verify
+%% DES - in 8-bits cipher feedback mode (CFB)
%%
--spec dss_verify(data_or_digest(), binary(), [binary()]) -> boolean().
--spec dss_verify(dss_digest_type(), data_or_digest(), binary(), [binary()]) -> boolean().
--spec rsa_verify(data_or_digest(), binary(), [binary()]) -> boolean().
--spec rsa_verify(rsa_digest_type(), data_or_digest(), binary(), [binary()]) ->
- boolean().
-
-%% Key = [P,Q,G,Y] P,Q,G=DSSParams Y=PublicKey
-dss_verify(Data,Signature,Key) ->
- dss_verify(sha, Data, Signature, Key).
-
-dss_verify(Type,Data,Signature,Key) when is_binary(Data), Type=/=none ->
- verify(dss,Type,mpint_to_bin(Data),mpint_to_bin(Signature),map_mpint_to_bin(Key));
-dss_verify(Type,Digest,Signature,Key) ->
- verify(dss,Type,Digest,mpint_to_bin(Signature),map_mpint_to_bin(Key)).
-
-% Key = [E,N] E=PublicExponent N=PublicModulus
-rsa_verify(Data,Signature,Key) ->
- rsa_verify(sha, Data,Signature,Key).
-rsa_verify(Type, Data, Signature, Key) when is_binary(Data) ->
- verify(rsa, Type, mpint_to_bin(Data), mpint_to_bin(Signature), map_mpint_to_bin(Key));
-rsa_verify(Type, Digest, Signature, Key) ->
- verify(rsa, Type, Digest, mpint_to_bin(Signature), map_mpint_to_bin(Key)).
-
-
-verify(dss, Type, Data, Signature, Key) ->
- dss_verify_nif(Type, Data, Signature, map_ensure_int_as_bin(Key));
-
-verify(rsa, Type, DataOrDigest, Signature, Key) ->
- case rsa_verify_nif(Type, DataOrDigest, Signature, map_ensure_int_as_bin(Key)) of
- notsup -> erlang:error(notsup);
- 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
- notsup -> erlang:error(notsup);
- Bool -> Bool
- end.
+-spec des_cfb_encrypt(iodata(), binary(), iodata()) -> binary().
+-spec des_cfb_decrypt(iodata(), binary(), iodata()) -> binary().
+des_cfb_encrypt(Key, IVec, Data) ->
+ des_cfb_crypt(Key, IVec, Data, true).
-dss_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub.
-rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub.
-ecdsa_verify_nif(_Type, _DataOrDigest, _Signature, _Key) -> ?nif_stub.
+des_cfb_decrypt(Key, IVec, Data) ->
+ des_cfb_crypt(Key, IVec, Data, false).
+des_cfb_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
%%
-%% DSS, RSA - sign
+%% dec_cfb_ivec(IVec, Data) -> binary()
%%
-%% Key = [P,Q,G,X] P,Q,G=DSSParams X=PrivateKey
--spec dss_sign(data_or_digest(), [binary()]) -> binary().
--spec dss_sign(dss_digest_type(), data_or_digest(), [binary()]) -> binary().
--spec rsa_sign(data_or_digest(), [binary()]) -> binary().
--spec rsa_sign(rsa_digest_type(), data_or_digest(), [binary()]) -> binary().
-
-dss_sign(DataOrDigest,Key) ->
- dss_sign(sha,DataOrDigest,Key).
-dss_sign(Type, Data, Key) when is_binary(Data), Type=/=none ->
- sign(dss, Type, mpint_to_bin(Data), map_mpint_to_bin(Key));
-dss_sign(Type, Digest, Key) ->
- sign(dss, Type, Digest, map_mpint_to_bin(Key)).
-
-
-%% Key = [E,N,D] E=PublicExponent N=PublicModulus D=PrivateExponent
-rsa_sign(DataOrDigest,Key) ->
- rsa_sign(sha, DataOrDigest, Key).
-
-rsa_sign(Type, Data, Key) when is_binary(Data) ->
- sign(rsa, Type, mpint_to_bin(Data), map_mpint_to_bin(Key));
-rsa_sign(Type, Digest, Key) ->
- sign(rsa, Type, Digest, map_mpint_to_bin(Key)).
-
-map_mpint_to_bin(List) ->
- lists:map(fun(E) -> mpint_to_bin(E) end, List ).
-
-map_ensure_int_as_bin([H|_]=List) when is_integer(H) ->
- lists:map(fun(E) -> int_to_bin(E) end, List);
-map_ensure_int_as_bin(List) ->
- List.
-
-ensure_int_as_bin(Int) when is_integer(Int) ->
- int_to_bin(Int);
-ensure_int_as_bin(Bin) ->
- Bin.
-
-map_to_norm_bin([H|_]=List) when is_integer(H) ->
- lists:map(fun(E) -> int_to_bin(E) end, List);
-map_to_norm_bin(List) ->
- lists:map(fun(E) -> mpint_to_bin(E) end, List).
-
-
-sign(rsa, Type, DataOrDigest, Key) ->
- case rsa_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of
- error -> erlang:error(badkey, [Type,DataOrDigest,Key]);
- Sign -> Sign
- end;
-sign(dss, Type, DataOrDigest, Key) ->
- case dss_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of
- error -> erlang:error(badkey, [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
- error -> erlang:error(badkey, [Type,DataOrDigest,Key]);
- Sign -> Sign
- end.
-
-rsa_sign_nif(_Type,_Data,_Key) -> ?nif_stub.
-dss_sign_nif(_Type,_Data,_Key) -> ?nif_stub.
-ecdsa_sign_nif(_Type, _DataOrDigest, _Key) -> ?nif_stub.
-
-
-
-
--spec public_encrypt(rsa, binary(), [binary()], rsa_padding()) ->
- binary().
--spec public_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) ->
- binary().
--spec private_encrypt(rsa, binary(), [integer() | binary()], rsa_padding()) ->
- binary().
--spec private_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) ->
- binary().
-
-public_encrypt(rsa, BinMesg, Key, Padding) ->
- case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of
- error ->
- erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
- Sign -> Sign
- end.
-
-%% Binary, Key = [E,N,D]
-private_decrypt(rsa, BinMesg, Key, Padding) ->
- case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of
- error ->
- erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
- Sign -> Sign
- end.
-
-
-%% Binary, Key = [E,N,D]
-private_encrypt(rsa, BinMesg, Key, Padding) ->
- case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of
- error ->
- erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
- Sign -> Sign
- end.
-
-%% Binary, Key = [E,N]
-public_decrypt(rsa, BinMesg, Key, Padding) ->
- case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of
- error ->
- erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
- Sign -> Sign
- end.
-
-
+%% Returns the IVec to be used in the next iteration of
+%% des_cfb_[encrypt|decrypt].
%%
-%% rsa_public_encrypt
-%% rsa_private_decrypt
--type rsa_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' | 'rsa_no_padding'.
-
--spec rsa_public_encrypt(binary(), [binary()], rsa_padding()) ->
- binary().
--spec rsa_public_decrypt(binary(), [integer() | mpint()], rsa_padding()) ->
- binary().
--spec rsa_private_encrypt(binary(), [integer() | mpint()], rsa_padding()) ->
- binary().
--spec rsa_private_decrypt(binary(), [integer() | mpint()], rsa_padding()) ->
- binary().
-%% Binary, Key = [E,N]
-rsa_public_encrypt(BinMesg, Key, Padding) ->
- case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of
- error ->
- erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
- Sign -> Sign
- end.
-
-rsa_public_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub.
+-spec des_cfb_ivec(iodata(), iodata()) -> binary().
-%% Binary, Key = [E,N,D]
-rsa_private_decrypt(BinMesg, Key, Padding) ->
- case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of
- error ->
- erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
- Sign -> Sign
- end.
+des_cfb_ivec(IVec, Data) ->
+ IVecAndData = list_to_binary([IVec, Data]),
+ {_, NewIVec} = split_binary(IVecAndData, byte_size(IVecAndData) - 8),
+ NewIVec.
-rsa_private_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub.
-
-%% Binary, Key = [E,N,D]
-rsa_private_encrypt(BinMesg, Key, Padding) ->
- case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of
- error ->
- erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
- Sign -> Sign
- end.
-
-%% Binary, Key = [E,N]
-rsa_public_decrypt(BinMesg, Key, Padding) ->
- case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of
- error ->
- erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
- Sign -> Sign
- end.
-
%%
%% AES - with 128 or 256 bit key in cipher block chaining mode (CBC)
%%
@@ -1298,6 +1253,33 @@ aes_cbc_ivec(Data) when is_binary(Data) ->
aes_cbc_ivec(Data) when is_list(Data) ->
aes_cbc_ivec(list_to_binary(Data)).
+
+%% Stream ciphers --------------------------------------------------------------------
+
+stream_crypt(Fun, State, Data, Size, MaxByts, []) when Size =< MaxByts ->
+ Fun(State, Data);
+stream_crypt(Fun, State0, Data, Size, MaxByts, Acc) when Size =< MaxByts ->
+ {State, Cipher} = Fun(State0, Data),
+ {State, list_to_binary(lists:reverse([Cipher | Acc]))};
+stream_crypt(Fun, State0, Data, _, MaxByts, Acc) ->
+ <<Increment:MaxByts/binary, Rest/binary>> = Data,
+ {State, CipherText} = Fun(State0, Increment),
+ stream_crypt(Fun, State, Rest, erlang:byte_size(Rest), MaxByts, [CipherText | Acc]).
+
+do_stream_encrypt({aes_ctr, State0}, Data) ->
+ {State, Cipher} = aes_ctr_stream_encrypt(State0, Data),
+ {{aes_ctr, State}, Cipher};
+do_stream_encrypt({rc4, State0}, Data) ->
+ {State, Cipher} = rc4_encrypt_with_state(State0, Data),
+ {{rc4, State}, Cipher}.
+
+do_stream_decrypt({aes_ctr, State0}, Data) ->
+ {State, Text} = aes_ctr_stream_decrypt(State0, Data),
+ {{aes_ctr, State}, Text};
+do_stream_decrypt({rc4, State0}, Data) ->
+ {State, Text} = rc4_encrypt_with_state(State0, Data),
+ {{rc4, State}, Text}.
+
%%
%% AES - in counter mode (CTR)
%%
@@ -1305,7 +1287,7 @@ aes_cbc_ivec(Data) when is_list(Data) ->
binary().
-spec aes_ctr_decrypt(iodata(), binary(), iodata()) ->
binary().
-
+
aes_ctr_encrypt(_Key, _IVec, _Data) -> ?nif_stub.
aes_ctr_decrypt(_Key, _IVec, _Cipher) -> ?nif_stub.
@@ -1326,15 +1308,6 @@ aes_ctr_stream_encrypt({_Key, _IVec, _ECount, _Num}=_State, _Data) -> ?nif_stub.
aes_ctr_stream_decrypt({_Key, _IVec, _ECount, _Num}=_State, _Cipher) -> ?nif_stub.
%%
-%% XOR - xor to iolists and return a binary
-%% NB doesn't check that they are the same size, just concatenates
-%% them and sends them to the driver
-%%
--spec exor(iodata(), iodata()) -> binary().
-
-exor(_A, _B) -> ?nif_stub.
-
-%%
%% RC4 - symmetric stream cipher
%%
-spec rc4_encrypt(iodata(), iodata()) -> binary().
@@ -1363,7 +1336,76 @@ rc2_40_cbc_encrypt(Key, IVec, Data) when erlang:byte_size(Key) == 5 ->
rc2_40_cbc_decrypt(Key, IVec, Data) when erlang:byte_size(Key) == 5 ->
rc2_cbc_crypt(Key,IVec,Data,false).
-%%
+
+%% Secure remote password -------------------------------------------------------------------
+
+user_srp_gen_key(Private, Generator, Prime) ->
+ case mod_pow(Generator, Private, Prime) of
+ error ->
+ error;
+ Public ->
+ {Public, Private}
+ end.
+
+host_srp_gen_key(Private, Verifier, Generator, Prime, Version) ->
+ Multiplier = srp_multiplier(Version, Generator, Prime),
+ case srp_value_B_nif(Multiplier, Verifier, Generator, Private, Prime) of
+ error ->
+ error;
+ Public ->
+ {Public, Private}
+ end.
+
+srp_multiplier('6a', Generator, Prime) ->
+ %% k = SHA1(N | PAD(g)) from http://srp.stanford.edu/design.html
+ C0 = sha_init(),
+ C1 = sha_update(C0, Prime),
+ C2 = sha_update(C1, srp_pad_to(erlang:byte_size(Prime), Generator)),
+ sha_final(C2);
+srp_multiplier('6', _, _) ->
+ <<3/integer>>;
+srp_multiplier('3', _, _) ->
+ <<1/integer>>.
+
+srp_scrambler(Version, UserPublic, HostPublic, Prime) when Version == '6'; Version == '6a'->
+ %% SHA1(PAD(A) | PAD(B)) from http://srp.stanford.edu/design.html
+ PadLength = erlang:byte_size(Prime),
+ C0 = sha_init(),
+ C1 = sha_update(C0, srp_pad_to(PadLength, UserPublic)),
+ C2 = sha_update(C1, srp_pad_to(PadLength, HostPublic)),
+ sha_final(C2);
+srp_scrambler('3', _, HostPublic, _Prime) ->
+ %% The parameter u is a 32-bit unsigned integer which takes its value
+ %% from the first 32 bits of the SHA1 hash of B, MSB first.
+ <<U:32/bits, _/binary>> = sha(HostPublic),
+ U.
+
+srp_pad_length(Width, Length) ->
+ (Width - Length rem Width) rem Width.
+
+srp_pad_to(Width, Binary) ->
+ case srp_pad_length(Width, size(Binary)) of
+ 0 -> Binary;
+ N -> << 0:(N*8), Binary/binary>>
+ end.
+
+srp_host_secret_nif(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub.
+
+srp_user_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub.
+
+srp_value_B_nif(_Multiplier, _Verifier, _Generator, _Exponent, _Prime) -> ?nif_stub.
+
+
+%% Digital signatures --------------------------------------------------------------------
+rsa_sign_nif(_Type,_Data,_Key) -> ?nif_stub.
+dss_sign_nif(_Type,_Data,_Key) -> ?nif_stub.
+ecdsa_sign_nif(_Type, _DataOrDigest, _Key) -> ?nif_stub.
+
+dss_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub.
+rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub.
+ecdsa_verify_nif(_Type, _DataOrDigest, _Signature, _Key) -> ?nif_stub.
+
+%% Public Keys --------------------------------------------------------------------
%% DH Diffie-Hellman functions
%%
@@ -1412,80 +1454,10 @@ dh_compute_key(OthersPublicKey, MyPrivateKey, DHParameters) ->
dh_compute_key_nif(_OthersPublicKey, _MyPrivateKey, _DHParameters) -> ?nif_stub.
-generate_key(Type, Params) ->
- generate_key(Type, Params, undefined).
-
-generate_key(dh, DHParameters, PrivateKey) ->
- 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);
- _ -> ensure_int_as_bin(PrivArg)
- end,
- host_srp_gen_key(Private, Verifier, Generator, Prime, Version);
-
-generate_key(srp, {user, [Generator, Prime, Version]}, PrivateArg)
- when is_binary(Generator), is_binary(Prime), is_atom(Version) ->
- Private = case PrivateArg of
- undefined -> random_bytes(32);
- _ -> PrivateArg
- end,
- user_srp_gen_key(Private, Generator, Prime);
-
-generate_key(ecdh, Curve, undefined) ->
- 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(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
- end;
-
-compute_key(srp, HostPublic, {UserPublic, UserPrivate},
- {user, [DerivedKey, Prime, Generator, Version | ScramblerArg]}) when
- is_binary(Prime),
- is_binary(Generator),
- is_atom(Version) ->
- HostPubBin = ensure_int_as_bin(HostPublic),
- Multiplier = srp_multiplier(Version, Generator, Prime),
- Scrambler = case ScramblerArg of
- [] -> srp_scrambler(Version, ensure_int_as_bin(UserPublic),
- HostPubBin, Prime);
- [S] -> S
- end,
- 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_atom(Version) ->
- UserPubBin = ensure_int_as_bin(UserPublic),
- Scrambler = case ScramblerArg of
- [] -> srp_scrambler(Version, UserPubBin, ensure_int_as_bin(HostPublic), Prime);
- [S] -> S
- end,
- srp_host_secret_nif(Verifier, ensure_int_as_bin(HostPrivate), Scrambler,
- UserPubBin, Prime);
-
-compute_key(ecdh, Others, My, Curve) ->
- ecdh_compute_key_nif(ensure_int_as_bin(Others),
- term_to_ec_key(Curve,My,undefined)).
-
ecdh_compute_key_nif(_Others, _My) -> ?nif_stub.
-
%%
%% EC
%%
@@ -1511,65 +1483,181 @@ term_to_ec_key(Curve, PrivKey, PubKey) ->
term_to_ec_key_nif(_Curve, _PrivKey, _PubKey) -> ?nif_stub.
+%% MISC --------------------------------------------------------------------
+
+exor(Data1, Data2, Size, MaxByts, []) when Size =< MaxByts ->
+ do_exor(Data1, Data2);
+exor(Data1, Data2, Size, MaxByts, Acc) when Size =< MaxByts ->
+ Result = do_exor(Data1, Data2),
+ list_to_binary(lists:reverse([Result | Acc]));
+exor(Data1, Data2, _Size, MaxByts, Acc) ->
+ <<Increment1:MaxByts/binary, Rest1/binary>> = Data1,
+ <<Increment2:MaxByts/binary, Rest2/binary>> = Data2,
+ Result = do_exor(Increment1, Increment2),
+ exor(Rest1, Rest2, erlang:byte_size(Rest1), MaxByts, [Result | Acc]).
+
+do_exor(_A, _B) -> ?nif_stub.
-%% LOCAL FUNCTIONS
+algorithms() -> ?nif_stub.
+
+int_to_bin(X) when X < 0 -> int_to_bin_neg(X, []);
+int_to_bin(X) -> int_to_bin_pos(X, []).
+
+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]).
+
+bytes_to_integer(Bin) ->
+ bin_to_int(Bin).
+
+bin_to_int(Bin) when is_binary(Bin) ->
+ Bits = bit_size(Bin),
+ <<Integer:Bits/integer>> = Bin,
+ Integer;
+bin_to_int(undefined) ->
+ undefined.
+
+map_ensure_int_as_bin([H|_]=List) when is_integer(H) ->
+ lists:map(fun(E) -> int_to_bin(E) end, List);
+map_ensure_int_as_bin(List) ->
+ List.
+
+ensure_int_as_bin(Int) when is_integer(Int) ->
+ int_to_bin(Int);
+ensure_int_as_bin(Bin) ->
+ Bin.
+
+map_to_norm_bin([H|_]=List) when is_integer(H) ->
+ lists:map(fun(E) -> int_to_bin(E) end, List);
+map_to_norm_bin(List) ->
+ lists:map(fun(E) -> mpint_to_bin(E) end, List).
+
+%%--------------------------------------------------------------------
+%%% Deprecated
+%%--------------------------------------------------------------------
%%
+%% rsa_public_encrypt
+%% rsa_private_decrypt
+-type rsa_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' | 'rsa_no_padding'.
-user_srp_gen_key(Private, Generator, Prime) ->
- case mod_pow(Generator, Private, Prime) of
+-spec rsa_public_encrypt(binary(), [binary()], rsa_padding()) ->
+ binary().
+-spec rsa_public_decrypt(binary(), [integer() | mpint()], rsa_padding()) ->
+ binary().
+-spec rsa_private_encrypt(binary(), [integer() | mpint()], rsa_padding()) ->
+ binary().
+-spec rsa_private_decrypt(binary(), [integer() | mpint()], rsa_padding()) ->
+ binary().
+
+%% Binary, Key = [E,N]
+rsa_public_encrypt(BinMesg, Key, Padding) ->
+ case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of
error ->
- error;
- Public ->
- {Public, Private}
+ erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
end.
-host_srp_gen_key(Private, Verifier, Generator, Prime, Version) ->
- Multiplier = srp_multiplier(Version, Generator, Prime),
- case srp_value_B_nif(Multiplier, Verifier, Generator, Private, Prime) of
- error ->
- error;
- Public ->
- {Public, Private}
- end.
+rsa_public_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub.
-srp_multiplier('6a', Generator, Prime) ->
- %% k = SHA1(N | PAD(g)) from http://srp.stanford.edu/design.html
- C0 = sha_init(),
- C1 = sha_update(C0, Prime),
- C2 = sha_update(C1, srp_pad_to(erlang:byte_size(Prime), Generator)),
- sha_final(C2);
-srp_multiplier('6', _, _) ->
- <<3/integer>>;
-srp_multiplier('3', _, _) ->
- <<1/integer>>.
+%% Binary, Key = [E,N,D]
+rsa_private_decrypt(BinMesg, Key, Padding) ->
+ case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of
+ error ->
+ erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
-srp_scrambler(Version, UserPublic, HostPublic, Prime) when Version == '6'; Version == '6a'->
- %% SHA1(PAD(A) | PAD(B)) from http://srp.stanford.edu/design.html
- PadLength = erlang:byte_size(Prime),
- C0 = sha_init(),
- C1 = sha_update(C0, srp_pad_to(PadLength, UserPublic)),
- C2 = sha_update(C1, srp_pad_to(PadLength, HostPublic)),
- sha_final(C2);
-srp_scrambler('3', _, HostPublic, _Prime) ->
- %% The parameter u is a 32-bit unsigned integer which takes its value
- %% from the first 32 bits of the SHA1 hash of B, MSB first.
- <<U:32/bits, _/binary>> = sha(HostPublic),
- U.
+rsa_private_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub.
-srp_pad_length(Width, Length) ->
- (Width - Length rem Width) rem Width.
-srp_pad_to(Width, Binary) ->
- case srp_pad_length(Width, size(Binary)) of
- 0 -> Binary;
- N -> << 0:(N*8), Binary/binary>>
+%% Binary, Key = [E,N,D]
+rsa_private_encrypt(BinMesg, Key, Padding) ->
+ case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of
+ error ->
+ erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
end.
-srp_host_secret_nif(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub.
+%% Binary, Key = [E,N]
+rsa_public_decrypt(BinMesg, Key, Padding) ->
+ case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of
+ error ->
+ erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
-srp_user_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub.
+map_mpint_to_bin(List) ->
+ lists:map(fun(E) -> mpint_to_bin(E) end, List ).
+
+%%
+%% DSS, RSA - sign
+%%
+%% Key = [P,Q,G,X] P,Q,G=DSSParams X=PrivateKey
+-spec dss_sign(data_or_digest(), [binary()]) -> binary().
+-spec dss_sign(dss_digest_type(), data_or_digest(), [binary()]) -> binary().
+-spec rsa_sign(data_or_digest(), [binary()]) -> binary().
+-spec rsa_sign(rsa_digest_type(), data_or_digest(), [binary()]) -> binary().
+
+dss_sign(DataOrDigest,Key) ->
+ dss_sign(sha,DataOrDigest,Key).
+dss_sign(Type, Data, Key) when is_binary(Data), Type=/=none ->
+ sign(dss, Type, mpint_to_bin(Data), map_mpint_to_bin(Key));
+dss_sign(Type, Digest, Key) ->
+ sign(dss, Type, Digest, map_mpint_to_bin(Key)).
+
+
+%% Key = [E,N,D] E=PublicExponent N=PublicModulus D=PrivateExponent
+rsa_sign(DataOrDigest,Key) ->
+ rsa_sign(sha, DataOrDigest, Key).
+
+rsa_sign(Type, Data, Key) when is_binary(Data) ->
+ sign(rsa, Type, mpint_to_bin(Data), map_mpint_to_bin(Key));
+rsa_sign(Type, Digest, Key) ->
+ sign(rsa, Type, Digest, map_mpint_to_bin(Key)).
+
+%%
+%% DSS, RSA - verify
+%%
+-spec dss_verify(data_or_digest(), binary(), [binary()]) -> boolean().
+-spec dss_verify(dss_digest_type(), data_or_digest(), binary(), [binary()]) -> boolean().
+-spec rsa_verify(data_or_digest(), binary(), [binary()]) -> boolean().
+-spec rsa_verify(rsa_digest_type(), data_or_digest(), binary(), [binary()]) ->
+ boolean().
+
+%% Key = [P,Q,G,Y] P,Q,G=DSSParams Y=PublicKey
+dss_verify(Data,Signature,Key) ->
+ dss_verify(sha, Data, Signature, Key).
+
+dss_verify(Type,Data,Signature,Key) when is_binary(Data), Type=/=none ->
+ verify(dss,Type,mpint_to_bin(Data),mpint_to_bin(Signature),map_mpint_to_bin(Key));
+dss_verify(Type,Digest,Signature,Key) ->
+ verify(dss,Type,Digest,mpint_to_bin(Signature),map_mpint_to_bin(Key)).
+
+% Key = [E,N] E=PublicExponent N=PublicModulus
+rsa_verify(Data,Signature,Key) ->
+ rsa_verify(sha, Data,Signature,Key).
+rsa_verify(Type, Data, Signature, Key) when is_binary(Data) ->
+ verify(rsa, Type, mpint_to_bin(Data), mpint_to_bin(Signature), map_mpint_to_bin(Key));
+rsa_verify(Type, Digest, Signature, Key) ->
+ verify(rsa, Type, Digest, mpint_to_bin(Signature), map_mpint_to_bin(Key)).
+
+-spec strong_rand_mpint(Bits::non_neg_integer(),
+ Top::-1..1,
+ Bottom::0..1) -> binary().
+
+strong_rand_mpint(Bits, Top, Bottom) ->
+ case strong_rand_mpint_nif(Bits,Top,Bottom) of
+ false -> erlang:error(low_entropy);
+ Bin -> Bin
+ end.
+strong_rand_mpint_nif(_Bits, _Top, _Bottom) -> ?nif_stub.
-srp_value_B_nif(_Multiplier, _Verifier, _Generator, _Exponent, _Prime) -> ?nif_stub.
%% large integer in a binary with 32bit length
%% MP representaion (SSH2)
@@ -1594,32 +1682,6 @@ mpint_pos(X) ->
<<?UINT32(Sz), Bin/binary>>
end.
-int_to_bin(X) when X < 0 -> int_to_bin_neg(X, []);
-int_to_bin(X) -> int_to_bin_pos(X, []).
-
-%%int_to_bin_pos(X) when X >= 0 ->
-%% int_to_bin_pos(X, []).
-
-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]).
-
-bytes_to_integer(Bin) ->
- bin_to_int(Bin).
-
-bin_to_int(Bin) when is_binary(Bin) ->
- Bits = bit_size(Bin),
- <<Integer:Bits/integer>> = Bin,
- Integer;
-bin_to_int(undefined) ->
- undefined.
-
%% int from integer in a binary with 32bit length
erlint(<<MPIntSize:32/integer,MPIntValue/binary>>) ->
Bits= MPIntSize * 8,
@@ -1629,11 +1691,71 @@ erlint(<<MPIntSize:32/integer,MPIntValue/binary>>) ->
mpint_to_bin(<<Len:32, Bin:Len/binary>>) ->
Bin.
-random_bytes(N) ->
- try strong_rand_bytes(N) of
- RandBytes ->
- RandBytes
- catch
- error:low_entropy ->
- rand_bytes(N)
- end.
+%%
+%% mod_exp - utility for rsa generation and SRP
+%%
+mod_exp(Base, Exponent, Modulo)
+ when is_integer(Base), is_integer(Exponent), is_integer(Modulo) ->
+ bin_to_int(mod_exp_nif(int_to_bin(Base), int_to_bin(Exponent), int_to_bin(Modulo), 0));
+
+mod_exp(Base, Exponent, Modulo) ->
+ mod_exp_nif(mpint_to_bin(Base),mpint_to_bin(Exponent),mpint_to_bin(Modulo), 4).
+
+mod_exp_nif(_Base,_Exp,_Mod,_bin_hdr) -> ?nif_stub.
+
+-define(FUNC_LIST, [hash, hash_init, hash_update, hash_final,
+ hmac, hmac_init, hmac_update, hmac_final, hmac_final_n,
+ %% deprecated
+ md4, md4_init, md4_update, md4_final,
+ md5, md5_init, md5_update, md5_final,
+ sha, sha_init, sha_update, sha_final,
+ md5_mac, md5_mac_96,
+ sha_mac, sha_mac_96,
+ %%
+ block_encrypt, block_decrypt,
+ %% deprecated
+ des_cbc_encrypt, des_cbc_decrypt,
+ des_cfb_encrypt, des_cfb_decrypt,
+ des_ecb_encrypt, des_ecb_decrypt,
+ des3_cbc_encrypt, des3_cbc_decrypt,
+ des3_cfb_encrypt, des3_cfb_decrypt,
+ aes_cfb_128_encrypt, aes_cfb_128_decrypt,
+ rc2_cbc_encrypt, rc2_cbc_decrypt,
+ rc2_40_cbc_encrypt, rc2_40_cbc_decrypt,
+ aes_cbc_128_encrypt, aes_cbc_128_decrypt,
+ aes_cbc_256_encrypt, aes_cbc_256_decrypt,
+ blowfish_cbc_encrypt, blowfish_cbc_decrypt,
+ blowfish_cfb64_encrypt, blowfish_cfb64_decrypt,
+ blowfish_ecb_encrypt, blowfish_ecb_decrypt, blowfish_ofb64_encrypt,
+ %%
+ rand_bytes,
+ strong_rand_bytes,
+ rand_uniform,
+ mod_pow,
+ exor,
+ %% deprecated
+ mod_exp,strong_rand_mpint,erlint, mpint,
+ %%
+ sign, verify, generate_key, compute_key,
+ %% deprecated
+ dss_verify,dss_sign,
+ rsa_verify,rsa_sign,
+ rsa_public_encrypt,rsa_private_decrypt,
+ rsa_private_encrypt,rsa_public_decrypt,
+ dh_generate_key, dh_compute_key,
+ %%
+ stream_init, stream_encrypt, stream_decrypt,
+ %% deprecated
+ rc4_encrypt, rc4_set_key, rc4_encrypt_with_state,
+ aes_ctr_encrypt, aes_ctr_decrypt,
+ aes_ctr_stream_init, aes_ctr_stream_encrypt, aes_ctr_stream_decrypt,
+ %%
+ next_iv,
+ %% deprecated
+ aes_cbc_ivec,
+ des_cbc_ivec, des_cfb_ivec,
+ info,
+ %%
+ info_lib, supports]).
+info() ->
+ ?FUNC_LIST.
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index c007ecac86..58aaa78d28 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -48,7 +48,7 @@ all() ->
{group, des_cfb},
{group, des3_cbc},
{group, des3_cbf},
- %%{group, des_ede3},
+ {group, des_ede3},
{group, blowfish_cbc},
{group, blowfish_ecb},
{group, blowfish_cfb64},
@@ -60,7 +60,8 @@ all() ->
{group, rc4},
{group, aes_ctr},
mod_pow,
- exor
+ exor,
+ rand_uniform
].
groups() ->
@@ -83,6 +84,7 @@ groups() ->
{des_cbc, [], [block]},
{des_cfb, [], [block]},
{des3_cbc,[], [block]},
+ {des_ede3,[], [block]},
{des3_cbf,[], [block]},
{rc2_cbc,[], [block]},
{aes_cbc128,[], [block]},
@@ -210,21 +212,19 @@ mod_pow(Config) when is_list(Config) ->
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).
+ do_exor(<<1, 2, 3, 4, 5, 6, 7, 8, 9, 10>>),
+ do_exor(term_to_binary(lists:seq(1, 1000000))).
+%%--------------------------------------------------------------------
+rand_uniform() ->
+ [{doc, "rand_uniform and random_bytes testing"}].
+rand_uniform(Config) when is_list(Config) ->
+ rand_uniform_aux_test(10),
+ 10 = byte_size(crypto:rand_bytes(10)),
+ 10 = byte_size(crypto:strong_rand_bytes(10)).
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
-
hash(_, [], []) ->
ok;
hash(Type, [Msg | RestMsg], [Digest| RestDigest]) ->
@@ -398,16 +398,19 @@ negative_verify(Type, Hash, Msg, Signature, Public) ->
end.
do_public_encrypt({Type, Public, Private, Msg, Padding}) ->
- PublicEcn = crypto:public_encrypt(Type, Msg, Public, Padding),
+ PublicEcn = (catch 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, rsa_pkcs1_oaep_padding}) ->
+ ok; %% Not supported by openssl
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
+ PrivEcn = (catch crypto:private_encrypt(Type, Msg, Private, Padding)),
+ case crypto:public_decrypt(rsa, PrivEcn, Public, Padding) of
Msg ->
ok;
Other ->
@@ -451,8 +454,6 @@ mkint(C) when $A =< C, C =< $F ->
mkint(C) when $a =< C, C =< $f ->
C - $a + 10.
-is_supported(cipher) ->
- true;
is_supported(Group) ->
lists:member(Group, lists:append([Algo || {_, Algo} <- crypto:supports()])).
@@ -472,6 +473,8 @@ 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({des_ede3 = 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}) ->
@@ -480,7 +483,7 @@ do_block_iolistify({Type, Key, IV, PlainText}) ->
iolistify(<<"Test With Truncation">>)->
%% Do not iolistify as it spoils this special case
<<"Test With Truncation">>;
-iolistify(Msg)->
+iolistify(Msg) when is_binary(Msg) ->
Length = erlang:byte_size(Msg),
Split = Length div 2,
List0 = binary_to_list(Msg),
@@ -489,7 +492,9 @@ iolistify(Msg)->
[[Element], List1, List2];
{List1, List2}->
[List1, List2]
- end.
+ end;
+iolistify(Msg) ->
+ iolistify(list_to_binary(Msg)).
des_iolistify(Msg) ->
des_iolist(erlang:byte_size(Msg) div 8, Msg, []).
@@ -529,6 +534,17 @@ ipow(A, B, M, Prod) ->
ipow(A1, B1, M, (A*Prod) rem M)
end.
+do_exor(B) ->
+ 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).
+
zero_bin(N) when is_integer(N) ->
N8 = N * 8,
<<0:N8/integer>>;
@@ -545,6 +561,25 @@ xor_bytes([], [], Acc) ->
lists:reverse(Acc);
xor_bytes([N1 | Tl1], [N2 | Tl2], Acc) ->
xor_bytes(Tl1, Tl2, [N1 bxor N2 | Acc]).
+rand_uniform_aux_test(0) ->
+ ok;
+rand_uniform_aux_test(N) ->
+ L = N*1000,
+ H = N*100000+1,
+ crypto_rand_uniform(L, H),
+ crypto_rand_uniform(-L, L),
+ crypto_rand_uniform(-H, -L),
+ crypto_rand_uniform(-H, L),
+ rand_uniform_aux_test(N-1).
+
+crypto_rand_uniform(L,H) ->
+ R1 = crypto:rand_uniform(L, H),
+ case (R1 >= L) and (R1 < H) of
+ true ->
+ ok;
+ false ->
+ ct:fail({"Not in interval", R1, L, H})
+ end.
%%--------------------------------------------------------------------
%% Test data ------------------------------------------------
@@ -556,20 +591,20 @@ group_config(md4 = Type, 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(),
+ Keys = rfc_2202_md5_keys() ++ [long_hmac_key(md5)],
+ Data = rfc_2202_msgs() ++ [long_msg()],
+ Hmac = rfc_2202_hmac_md5() ++ [long_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(),
+ Msgs = [rfc_4634_test1(), rfc_4634_test2_1(),long_msg()],
+ Digests = rfc_4634_sha_digests() ++ [long_sha_digest()],
+ Keys = rfc_2202_sha_keys() ++ [long_hmac_key(sha)],
+ Data = rfc_2202_msgs() ++ [long_msg()],
+ Hmac = rfc_2202_hmac_sha() ++ [long_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()],
@@ -579,41 +614,37 @@ group_config(sha224 = Type, Config) ->
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(),
+ Msgs = [rfc_4634_test1(), rfc_4634_test2_1(), long_msg()],
+ Digests = rfc_4634_sha256_digests() ++ [long_sha256_digest()],
+ Keys = rfc_4231_keys() ++ [long_hmac_key(sha256)],
+ Data = rfc_4231_msgs() ++ [long_msg()],
+ Hmac = rfc4231_hmac_sha256() ++ [long_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(),
+ Msgs = [rfc_4634_test1(), rfc_4634_test2(), long_msg()],
+ Digests = rfc_4634_sha384_digests() ++ [long_sha384_digest()],
+ Keys = rfc_4231_keys() ++ [long_hmac_key(sha384)],
+ Data = rfc_4231_msgs() ++ [long_msg()],
+ Hmac = rfc4231_hmac_sha384() ++ [long_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(),
+ Msgs = [rfc_4634_test1(), rfc_4634_test2(), long_msg()],
+ Digests = rfc_4634_sha512_digests() ++ [long_sha512_digest()],
+ Keys = rfc_4231_keys() ++ [long_hmac_key(sha512)],
+ Data = rfc_4231_msgs() ++ [long_msg()],
+ Hmac = rfc4231_hmac_sha512() ++ [long_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}
- ],
+ PublicS = rsa_public_stronger(),
+ PrivateS = rsa_private_stronger(),
+ SignVerify = sign_verify_tests(Type, Msg, Public, Private, PublicS, PrivateS),
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}
+ PubPrivEnc = [{rsa, Public, Private, MsgPubEnc, rsa_pkcs1_padding},
+ rsa_oaep(),
+ no_padding()
],
[{sign_verify, SignVerify}, {pub_priv_encrypt, PubPrivEnc} | Config];
group_config(dss = Type, Config) ->
@@ -649,6 +680,9 @@ group_config(des3_cbc, Config) ->
group_config(des3_cbf, Config) ->
Block = des3_cbf(),
[{block, Block} | Config];
+group_config(des_ede3, Config) ->
+ Block = des_ede3(),
+ [{block, Block} | Config];
group_config(rc2_cbc, Config) ->
Block = rc2_cbc(),
[{block, Block} | Config];
@@ -682,6 +716,20 @@ group_config(aes_ctr, Config) ->
group_config(_, Config) ->
Config.
+sign_verify_tests(Type, Msg, Public, Private, PublicS, PrivateS) ->
+ sign_verify_tests(Type, [md5, sha, sha224, sha256], Msg, Public, Private) ++
+ sign_verify_tests(Type, [sha384, sha512], Msg, PublicS, PrivateS).
+
+sign_verify_tests(Type, Hashs, Msg, Public, Private) ->
+ lists:foldl(fun(Hash, Acc) ->
+ case is_supported(Hash) of
+ true ->
+ [{Type, Hash, Public, Private, Msg}|Acc];
+ false ->
+ Acc
+ end
+ end, [], Hashs).
+
rfc_1321_msgs() ->
[<<"">>,
<<"a">>,
@@ -746,6 +794,23 @@ rfc_4634_sha512_digests() ->
"454D4423643CE80E2A9AC94FA54CA49F"),
hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA17299AEADB6889018501D289E4900F7E4331B99DEC4B5433AC7D329EEB6DD26545E96E55B874BE909")].
+long_msg() ->
+ lists:duplicate(1000000, $a).
+
+long_sha_digest() ->
+ hexstr2bin("34aa973c" "d4c4daa4" "f61eeb2b" "dbad2731" "6534016f").
+
+long_sha256_digest() ->
+ hexstr2bin("cdc76e5c" "9914fb92" "81a1c7e2" "84d73e67" "f1809a48" "a497200e" "046d39cc" "c7112cd0").
+
+long_sha384_digest() ->
+ hexstr2bin("9d0e1809716474cb" "086e834e310a4a1c" "ed149e9c00f24852" "7972cec5704c2a5b"
+ "07b8b3dc38ecc4eb" "ae97ddd87f3d8985").
+
+long_sha512_digest() ->
+ hexstr2bin("e718483d0ce76964" "4e2e42c7bc15b463" "8e1f98b13b204428" "5632a803afa973eb"
+ "de0ff244877ea60a" "4cb0432ce577c31b" "eb009c5c2c49aa2e" "4eadb217ad8cc09b").
+
ripemd160_msgs() ->
[<<"">>,
<<"a">>,
@@ -809,6 +874,35 @@ hmac_key(_) ->
hmac_inc(_) ->
[<<"Sampl">>, <<"e #1">>].
+%% https://www.cosic.esat.kuleuven.be/nessie/testvectors/
+long_hmac_key(Type) when Type == sha384;
+ Type == sha512 ->
+ hexstr2bin("00112233445566778899AABBCCDDEEFF"
+ "0123456789ABCDEF0011223344556677"
+ "8899AABBCCDDEEFF0123456789ABCDEF"
+ "00112233445566778899AABBCCDDEEFF");
+long_hmac_key(_) ->
+ hexstr2bin("0123456789ABCDEF0123456789ABCDEF"
+ "0123456789ABCDEF0123456789ABCDEF"
+ "0123456789ABCDEF0123456789ABCDEF"
+ "0123456789ABCDEF0123456789ABCDEF").
+long_hmac(md5) ->
+ hexstr2bin("82FDDA30202CB6ACC6F24D4F8A50EB7A");
+long_hmac(sha) ->
+ hexstr2bin("61D1D0B6459860755FDA892938C23DD401E54A7E");
+long_hmac(sha256) ->
+ hexstr2bin("50008B8DC7ED3926936347FDC1A01E9D"
+ "5220C6CC4B038B482C0F28A4CD88CA37");
+long_hmac(sha384) ->
+ hexstr2bin("C1EB08DAFA015833D3FC6B29A387558B"
+ "3F6FA1524AA1A8EB64798D5A76A39D6E"
+ "A1465525342E060EE996277B4FFCDDC9");
+long_hmac(sha512) ->
+ hexstr2bin("D116BF471AAE1264854F1906025E846A"
+ "61618A965FCA30B695220EA2D6E547E3"
+ "F3B5A4B54E6778928C26D5D3D810498E"
+ "8DF86CB3CC1E9F66A00419B13B6B0C9A").
+
rfc_2202_hmac_md5() ->
[
hexstr2bin("9294727a3638bb1c13f48ef8158bfc9d"),
@@ -950,6 +1044,15 @@ des3_cbc() ->
<<"Now is the time for all ">>
}].
+des_ede3() ->
+ [{des_ede3,
+ [hexstr2bin("8000000000000000"),
+ hexstr2bin("4000000000000000"),
+ hexstr2bin("2000000000000000")],
+ hexstr2bin("7AD16FFB79C45926"),
+ hexstr2bin("0000000000000000")
+ }].
+
des3_cbf() ->
[{des3_cbf,
[hexstr2bin("0123456789abcdef"),
@@ -1141,7 +1244,8 @@ blowfish_ofb64() ->
rc4() ->
[{rc4, <<"apaapa">>, <<"Yo baby yo">>},
- {rc4, <<"apaapa">>, list_to_binary(lists:seq(0, 255))}
+ {rc4, <<"apaapa">>, list_to_binary(lists:seq(0, 255))},
+ {rc4, <<"apaapa">>, lists:duplicate(1000000, $a)}
].
aes_ctr() ->
@@ -1185,7 +1289,11 @@ aes_ctr() ->
hexstr2bin("30c81c46a35ce411e5fbc1191a0a52ef")},
{aes_ctr, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdff02"),
- hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")}
+ hexstr2bin("f69f2445df4f9b17ad2b417be66c3710")},
+
+ {aes_ctr, hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
+ lists:duplicate(1000000, $a)}
].
rsa_plain() ->
@@ -1196,6 +1304,12 @@ rsa_public() ->
rsa_private() ->
rsa_public() ++ [7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945].
+rsa_public_stronger() ->
+ [65537, 24629450921918866883077380602720734920775458960049554761386137065662137652635369332143446151320538248280934442179850504891395344346514465469955766163141133564033962851182759993807898821114734943339732032639891483186089941567854227407119560631150779000222837755424893038740314247760600374970909894211201220612920040986106639419467243909950276018045907029941478599124238353052062083560294570722081552510960894164859765695309596889747541376908786225647625736062865138957717982693312699025417086612046330464651009693307624955796202070510577399561730651967517158452930742355327167632521808183383868100102455048819375344881].
+
+rsa_private_stronger() ->
+ rsa_public_stronger() ++ [13565232776562604620467234237694854016819673873109064019820773052201665024482754648718278717031083946624786145611240731564761987114634269887293030432042088547345315212418830656522115993209293567218379960177754901461542373481136856927955012596579314262051109321754382091434920473734937991286600905464814063189230779981494358415076362038786197620360127262110530926733754185204773610295221669711309000953136320804528874719105049753061737780710448207922456570922652651354760939379096788728229638142403068102990416717272880560951246813789730402978652924934794503277969128609831043469924881848849409122972426787999886557185].
+
dss_plain() ->
rsa_plain().
dss_public() ->
@@ -1355,3 +1469,37 @@ ecdh() ->
dh() ->
{dh, 0087761979513264537414556992123116644042638206717762626089877284926656954974893442000747478454809111207351620687968672207938731607963470779396984752680274820156266685080223616226905101126463253150237669547023934604953898814222890239130021414026118792251620881355456432549881723310342870016961804255746630219, 2}.
+
+rsa_oaep() ->
+ %% ftp://ftp.rsa.com/pub/rsalabs/tmp/pkcs1v15crypt-vectors.txt
+ Public = [hexstr2bin("010001"),
+ hexstr2bin("a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8ae4811a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0cbc64a742c6c630f533c8cc72f62ae833c40bf25842e984bb78bdbf97c0107d55bdb662f5c4e0fab9845cb5148ef7392dd3aaff93ae1e6b667bb3d4247616d4f5ba10d4cfd226de88d39f16fb")],
+ Private = Public ++ [hexstr2bin("53339cfdb79fc8466a655c7316aca85c55fd8f6dd898fdaf119517ef4f52e8fd8e258df93fee180fa0e4ab29693cd83b152a553d4ac4d1812b8b9fa5af0e7f55fe7304df41570926f3311f15c4d65a732c483116ee3d3d2d0af3549ad9bf7cbfb78ad884f84d5beb04724dc7369b31def37d0cf539e9cfcdd3de653729ead5d1"),
+ hexstr2bin("d32737e7267ffe1341b2d5c0d150a81b586fb3132bed2f8d5262864a9cb9f30af38be448598d413a172efb802c21acf1c11c520c2f26a471dcad212eac7ca39d"),
+ hexstr2bin("cc8853d1d54da630fac004f471f281c7b8982d8224a490edbeb33d3e3d5cc93c4765703d1dd791642f1f116a0dd852be2419b2af72bfe9a030e860b0288b5d77"),
+ hexstr2bin("0e12bf1718e9cef5599ba1c3882fe8046a90874eefce8f2ccc20e4f2741fb0a33a3848aec9c9305fbecbd2d76819967d4671acc6431e4037968db37878e695c1"),
+ hexstr2bin("95297b0f95a2fa67d00707d609dfd4fc05c89dafc2ef6d6ea55bec771ea333734d9251e79082ecda866efef13c459e1a631386b7e354c899f5f112ca85d71583"),
+ hexstr2bin("4f456c502493bdc0ed2ab756a3a6ed4d67352a697d4216e93212b127a63d5411ce6fa98d5dbefd73263e3728142743818166ed7dd63687dd2a8ca1d2f4fbd8e1")],
+ %%Msg = hexstr2bin("6628194e12073db03ba94cda9ef9532397d50dba79b987004afefe34"),
+ Msg = hexstr2bin("750c4047f547e8e41411856523298ac9bae245efaf1397fbe56f9dd5"),
+ {rsa, Public, Private, Msg, rsa_pkcs1_oaep_padding}.
+
+no_padding() ->
+ Public = [_, Mod] = rsa_public(),
+ Private = rsa_private(),
+ MsgLen = erlang:byte_size(int_to_bin(Mod)),
+ Msg = list_to_binary(lists:duplicate(MsgLen, $X)),
+ {rsa, Public, Private, Msg, rsa_no_padding}.
+
+int_to_bin(X) when X < 0 -> int_to_bin_neg(X, []);
+int_to_bin(X) -> int_to_bin_pos(X, []).
+
+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/crypto/vsn.mk b/lib/crypto/vsn.mk
index 2a0cb57aa9..d5d7c8a128 100644
--- a/lib/crypto/vsn.mk
+++ b/lib/crypto/vsn.mk
@@ -1 +1 @@
-CRYPTO_VSN = 2.3
+CRYPTO_VSN = 3.0
diff --git a/lib/erl_interface/vsn.mk b/lib/erl_interface/vsn.mk
index 9287e105df..6f08d380ca 100644
--- a/lib/erl_interface/vsn.mk
+++ b/lib/erl_interface/vsn.mk
@@ -1 +1 @@
-EI_VSN = 3.7.12
+EI_VSN = 3.7.13
diff --git a/lib/et/vsn.mk b/lib/et/vsn.mk
index 99532ee3f3..40cdc2b298 100644
--- a/lib/et/vsn.mk
+++ b/lib/et/vsn.mk
@@ -1 +1 @@
-ET_VSN = 1.4.4.3
+ET_VSN = 1.4.4.4
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index aada1252ad..3ea530a366 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -947,21 +947,34 @@ gethostbyname_self(Name, Type) when is_atom(Name) ->
gethostbyname_self(Name, Type)
when is_list(Name), Type =:= inet;
is_list(Name), Type =:= inet6 ->
- case inet_db:gethostname() of
- Name ->
- {ok,make_hostent(Name,
- [translate_ip(loopback, Type)],
- [], Type)};
- Self ->
+ N = inet_db:tolower(Name),
+ Self = inet_db:gethostname(),
+ %%
+ %% This is the final fallback that pretends /etc/hosts has got
+ %% a line for the hostname on the loopback address.
+ %% Lookups into /etc/hosts are case insensitive and return
+ %% what is in the file. Therefore the letter case may differ between
+ %% the returned hostent record and the hostname that was asked for.
+ %%
+ case inet_db:tolower(Self) of
+ N ->
+ {ok,
+ make_hostent(
+ Self, [translate_ip(loopback, Type)], [], Type)};
+ _ ->
case inet_db:res_option(domain) of
- "" -> {error,nxdomain};
+ "" ->
+ {error,nxdomain};
Domain ->
- case lists:append([Self,".",Domain]) of
- Name ->
- {ok,make_hostent(Name,
- [translate_ip(loopback, Type)],
- [], Type)};
- _ -> {error,nxdomain}
+ FQDN = lists:append([Self,".",Domain]),
+ case inet_db:tolower(FQDN) of
+ N ->
+ {ok,
+ make_hostent(
+ FQDN,
+ [translate_ip(loopback, Type)], [], Type)};
+ _ ->
+ {error,nxdomain}
end
end
end;
diff --git a/lib/kernel/src/inet_db.erl b/lib/kernel/src/inet_db.erl
index d4749b9756..a7679c531b 100644
--- a/lib/kernel/src/inet_db.erl
+++ b/lib/kernel/src/inet_db.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -845,7 +845,8 @@ init([]) ->
process_flag(trap_exit, true),
Db = ets:new(inet_db, [public, named_table]),
reset_db(Db),
- Cache = ets:new(inet_cache, [public, bag, {keypos,2}, named_table]),
+ CacheOpts = [public, bag, {keypos,#dns_rr.domain}, named_table],
+ Cache = ets:new(inet_cache, CacheOpts),
BynameOpts = [protected, bag, named_table, {keypos,1}],
ByaddrOpts = [protected, bag, named_table, {keypos,3}],
HostsByname = ets:new(inet_hosts_byname, BynameOpts),
@@ -901,15 +902,21 @@ reset_db(Db) ->
handle_call(Request, From, #state{db=Db}=State) ->
case Request of
{load_hosts_file,IPNmAs} when is_list(IPNmAs) ->
- NIPs = lists:flatten([ [{N,if tuple_size(IP) =:= 4 -> inet;
- tuple_size(IP) =:= 8 -> inet6
- end,IP} || N <- [Nm|As]]
- || {IP,Nm,As} <- IPNmAs]),
+ NIPs =
+ lists:flatten(
+ [ [{N,
+ if tuple_size(IP) =:= 4 -> inet;
+ tuple_size(IP) =:= 8 -> inet6
+ end,IP} || N <- [Nm|As]]
+ || {IP,Nm,As} <- IPNmAs]),
Byname = State#state.hosts_file_byname,
Byaddr = State#state.hosts_file_byaddr,
ets:delete_all_objects(Byname),
ets:delete_all_objects(Byaddr),
- ets:insert(Byname, NIPs),
+ %% Byname has lowercased names while Byaddr keep the name casing.
+ %% This is to be able to reconstruct the original
+ %% /etc/hosts entry.
+ ets:insert(Byname, [{tolower(N),Type,IP} || {N,Type,IP} <- NIPs]),
ets:insert(Byaddr, NIPs),
{reply, ok, State};
@@ -938,16 +945,14 @@ handle_call(Request, From, #state{db=Db}=State) ->
{reply, ok, State};
{add_rr, RR} when is_record(RR, dns_rr) ->
- RR1 = lower_rr(RR),
- ?dbg("add_rr: ~p~n", [RR1]),
- do_add_rr(RR1, Db, State),
+ ?dbg("add_rr: ~p~n", [RR]),
+ do_add_rr(RR, Db, State),
{reply, ok, State};
{del_rr, RR} when is_record(RR, dns_rr) ->
- RR1 = lower_rr(RR),
%% note. del_rr will handle wildcards !!!
Cache = State#state.cache,
- ets:match_delete(Cache, RR1),
+ ets:match_delete(Cache, RR),
{reply, ok, State};
{lookup_rr, Domain, Class, Type} ->
@@ -1225,15 +1230,18 @@ handle_set_file(ParseFun, Bin, From, State) ->
handle_rc_list(Opts, From, State)
end.
+%% Byname has lowercased names while Byaddr keep the name casing.
+%% This is to be able to reconstruct the original /etc/hosts entry.
+
do_add_host(Byname, Byaddr, Names, Type, IP) ->
do_del_host(Byname, Byaddr, IP),
- NIPs = [{tolower(N),Type,IP} || N <- Names],
- ets:insert(Byname, NIPs),
- ets:insert(Byaddr, NIPs),
+ ets:insert(Byname, [{tolower(N),Type,IP} || N <- Names]),
+ ets:insert(Byaddr, [{N,Type,IP} || N <- Names]),
ok.
do_del_host(Byname, Byaddr, IP) ->
- [ets:delete_object(Byname, NIP) || NIP <- ets:lookup(Byaddr, IP)],
+ [ets:delete_object(Byname, {tolower(Name),Type,Addr}) ||
+ {Name,Type,Addr} <- ets:lookup(Byaddr, IP)],
ets:delete(Byaddr, IP),
ok.
@@ -1369,7 +1377,7 @@ times() ->
%% lookup and remove old entries
do_lookup_rr(Domain, Class, Type) ->
- match_rr(#dns_rr{domain = tolower(Domain), class = Class,type = Type,
+ match_rr(#dns_rr{domain = Domain, class = Class,type = Type,
cnt = '_', tm = '_', ttl = '_',
bm = '_', func = '_', data = '_'}).
@@ -1393,23 +1401,20 @@ filter_rr([], _Time) -> [].
%%
-%% Lower case the domain name before storage
-%%
-lower_rr(RR) ->
- Dn = RR#dns_rr.domain,
- if is_list(Dn) ->
- RR#dns_rr { domain = tolower(Dn) };
- true -> RR
- end.
-
+%% Case fold upper-case to lower-case according to RFC 4343
+%% "Domain Name System (DNS) Case Insensitivity Clarification".
%%
-%% Map upper-case to lower-case
%% NOTE: this code is in kernel and we don't want to relay
-%% to much on stdlib
+%% to much on stdlib. Furthermore string:to_lower/1
+%% does not follow RFC 4343.
%%
tolower([]) -> [];
-tolower([C|Cs]) when C >= $A, C =< $Z -> [(C-$A)+$a|tolower(Cs)];
-tolower([C|Cs]) -> [C|tolower(Cs)].
+tolower([C|Cs]) when is_integer(C) ->
+ if C >= $A, C =< $Z ->
+ [(C-$A)+$a|tolower(Cs)];
+ true ->
+ [C|tolower(Cs)]
+ end.
dn_ip6_int(A,B,C,D,E,F,G,H) ->
dnib(H) ++ dnib(G) ++ dnib(F) ++ dnib(E) ++
diff --git a/lib/kernel/src/inet_hosts.erl b/lib/kernel/src/inet_hosts.erl
index df1d4fc0be..6e9719b4aa 100644
--- a/lib/kernel/src/inet_hosts.erl
+++ b/lib/kernel/src/inet_hosts.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -38,9 +38,12 @@ gethostbyname(_) -> {error, formerr}.
gethostbyname(Name, Type) when is_list(Name), is_atom(Type) ->
- case gethostbyname(Name, Type, inet_hosts_byname, inet_hosts_byaddr) of
+ %% Byname has lowercased names while Byaddr keep the name casing.
+ %% This is to be able to reconstruct the original /etc/hosts entry.
+ N = inet_db:tolower(Name),
+ case gethostbyname(N, Type, inet_hosts_byname, inet_hosts_byaddr) of
false ->
- case gethostbyname(Name, Type,
+ case gethostbyname(N, Type,
inet_hosts_file_byname,
inet_hosts_file_byaddr) of
false -> {error,nxdomain};
diff --git a/lib/kernel/src/inet_res.erl b/lib/kernel/src/inet_res.erl
index 59ba408d7a..94a9f7c64d 100644
--- a/lib/kernel/src/inet_res.erl
+++ b/lib/kernel/src/inet_res.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -181,8 +181,8 @@ lookup(Name, Class, Type, Opts, Timeout) ->
lookup_filter({ok,#dns_rec{anlist=Answers}}, Class, Type) ->
[A#dns_rr.data || A <- Answers,
- A#dns_rr.class =:= Class,
- A#dns_rr.type =:= Type];
+ Class =:= any orelse A#dns_rr.class =:= Class,
+ Type =:= any orelse A#dns_rr.type =:= Type];
lookup_filter({error,_}, _, _) -> [].
%% --------------------------------------------------------------------------
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index 4218cfa646..e4c8f0ffaf 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -2651,6 +2651,8 @@ symlinks(Config) when is_list(Config) ->
?line #file_info{links=1, type=symlink} = Info2,
?line {ok, Name} = ?FILE_MODULE:read_link(Alias),
{ok, Name} = ?FILE_MODULE:read_link_all(Alias),
+ %% If all is good, delete dir again (avoid hanging dir on windows)
+ rm_rf(?FILE_MODULE,NewDir),
ok
end,
@@ -4304,3 +4306,18 @@ disc_free(Path) ->
memsize() ->
{Tot,_Used,_} = memsup:get_memory_data(),
Tot.
+
+%%%-----------------------------------------------------------------
+%%% Utilities
+rm_rf(Mod,Dir) ->
+ case Mod:read_link_info(Dir) of
+ {ok, #file_info{type = directory}} ->
+ {ok, Content} = Mod:list_dir_all(Dir),
+ [ rm_rf(Mod,filename:join(Dir,C)) || C <- Content ],
+ Mod:del_dir(Dir),
+ ok;
+ {ok, #file_info{}} ->
+ Mod:delete(Dir);
+ _ ->
+ ok
+ end.
diff --git a/lib/kernel/test/file_name_SUITE.erl b/lib/kernel/test/file_name_SUITE.erl
index a6728564e4..0c8082026a 100644
--- a/lib/kernel/test/file_name_SUITE.erl
+++ b/lib/kernel/test/file_name_SUITE.erl
@@ -197,7 +197,10 @@ normal(Config) when is_list(Config) ->
put(file_module,prim_file),
ok = check_normal(prim_file),
put(file_module,file),
- ok = check_normal(file)
+ ok = check_normal(file),
+ %% If all is good, delete dir again (avoid hanging dir on windows)
+ rm_rf(file,"normal_dir"),
+ ok
after
file:set_cwd(Dir)
end.
@@ -219,7 +222,10 @@ icky(Config) when is_list(Config) ->
put(file_module,prim_file),
ok = check_icky(prim_file),
put(file_module,file),
- ok = check_icky(file)
+ ok = check_icky(file),
+ %% If all is good, delete dir again (avoid hanging dir on windows)
+ rm_rf(file,"icky_dir"),
+ ok
after
file:set_cwd(Dir)
end
@@ -243,7 +249,11 @@ very_icky(Config) when is_list(Config) ->
{skipped,"VM needs to be started in Unicode filename mode"};
ok ->
put(file_module,file),
- ok = check_very_icky(file)
+ ok = check_very_icky(file),
+ %% If all is good, delete dir again
+ %% (avoid hanging dir on windows)
+ rm_rf(file,"very_icky_dir"),
+ ok
end
after
file:set_cwd(Dir)
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/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl
index 1f7724d0dc..62ba95e1a3 100644
--- a/lib/kernel/test/inet_SUITE.erl
+++ b/lib/kernel/test/inet_SUITE.erl
@@ -183,80 +183,74 @@ t_gethostbyname(Config) when is_list(Config) ->
h_addr_list = [IP]},
?line HEntF_ = HEntF,
?line check_elems([{HEnt#hostent.h_aliases,[[],Aliases]}]),
+ %%
+ ?line FullNameU = toupper(FullName),
+ ?line {ok,HEntU} = inet:gethostbyname(FullNameU),
+ ?line FullNameU = toupper(HEntU#hostent.h_name),
+ ?line #hostent{
+ h_addrtype = inet,
+ h_length = 4,
+ h_addr_list = [IP]} = HEntU,
+ ?line check_elems(
+ [{[toupper(H) || H <- HEntU#hostent.h_aliases],
+ [[],[toupper(A) || A <- Aliases]]}]),
?line {DName, _DFullName, _DIPStr, _DIP, _, _, _} =
ct:get_config(test_dummy_host),
?line {error,nxdomain} = inet:gethostbyname(DName),
- ?line {error,nxdomain} = inet:gethostbyname(IP_46_Str).
+ ?line {error,nxdomain} = inet:gethostbyname(IP_46_Str),
+ ok.
t_gethostbyname_v6() -> required(v6).
t_gethostbyname_v6(doc) -> "Test the inet:gethostbyname/1 inet6 function.";
t_gethostbyname_v6(suite) -> [];
t_gethostbyname_v6(Config) when is_list(Config) ->
- ?line {Name, _, _, _,Aliases,IP_46_Str,IP_46} =
- ct:get_config(test_host_ipv4_only),
+ {Name, FullName, IPStr, IP, Aliases} =
+ ct:get_config(test_host_ipv6_only),
- case {inet:gethostbyname(IP_46_Str, inet6),
- inet:gethostbyname(Name, inet6)} of
- {{ok,HEnt46},{ok,_}} ->
- ?line HEnt46_ = HEnt46#hostent{h_name = IP_46_Str,
- h_addrtype = inet6,
- h_length = 16,
- h_addr_list = [IP_46]},
- ?line HEnt46_ = HEnt46,
- ?line check_elems([{HEnt46#hostent.h_aliases,[[],Aliases]}]),
-
- ?line {Name6, FullName6, IPStr6, IP6, Aliases6} =
- ct:get_config(test_host_ipv6_only),
- ?line {ok,_} = inet:gethostbyname(IPStr6, inet6),
- ?line {ok,HEnt6} = inet:gethostbyname(Name6, inet6),
- ?line {ok,HEnt6} = inet:gethostbyname(list_to_atom(Name6), inet6),
- ?line case HEnt6#hostent.h_addr_list of
- [IP6] -> % ipv6 ok
- ?line HEnt6_ = HEnt6#hostent{h_addrtype = inet6,
- h_length = 16,
- h_addr_list = [IP6]},
- ?line HEnt6_ = HEnt6,
- ?line check_elems([{HEnt6#hostent.h_name,[Name6,FullName6]},
- {HEnt6#hostent.h_aliases,[[],Aliases6]}]);
- _ -> % ipv4 compatible addr
- ?line {ok,HEnt4} = inet:gethostbyname(Name6, inet),
- ?line [IP4] = HEnt4#hostent.h_addr_list,
- ?line {ok,IP46_2} =
- inet_parse:ipv6_address("::ffff:"++inet_parse:ntoa(IP4)),
- ?line HEnt6_ = HEnt6#hostent{h_addrtype = inet6,
- h_length = 16,
- h_addr_list = [IP46_2]},
- ?line HEnt6_ = HEnt6,
- ?line check_elems([{HEnt6#hostent.h_name,[Name6,FullName6]}])
- end,
-
- ?line {ok,HEntF6} = inet:gethostbyname(FullName6, inet6),
- ?line case HEntF6#hostent.h_addr_list of
- [IP6] -> % ipv6 ok
- ?line HEntF6_ = HEntF6#hostent{h_name = FullName6,
- h_addrtype = inet6,
- h_length = 16,
- h_addr_list = [IP6]},
- ?line HEntF6_ = HEntF6,
- ?line check_elems([{HEntF6#hostent.h_aliases,[[],Aliases6]}]);
- _ -> % ipv4 compatible addr
- ?line {ok,HEntF4} = inet:gethostbyname(FullName6, inet),
- ?line [IPF4] = HEntF4#hostent.h_addr_list,
- ?line {ok,IPF46_2} =
- inet_parse:ipv6_address("::ffff:"++inet_parse:ntoa(IPF4)),
- ?line HEntF6_ = HEntF6#hostent{h_addrtype = inet6,
- h_length = 16,
- h_addr_list = [IPF46_2]},
- ?line HEntF6_ = HEntF6,
- ?line check_elems([{HEntF6#hostent.h_name,[Name6,FullName6]}])
- end,
-
- ?line {DName6, _DFullName6, _DIPStr6, _DIP6, _} =
- ct:get_config(test_dummy_ipv6_host),
- ?line {error,nxdomain} = inet:gethostbyname(DName6, inet6),
- ok;
- {_,_} ->
+ case inet:gethostbyname(Name, inet6) of
+ {ok,HEnt} ->
+ {ok,_} = inet:gethostbyname(IPStr, inet6),
+ {ok,HEnt} = inet:gethostbyname(list_to_atom(Name), inet6),
+ case HEnt#hostent.h_addr_list of
+ [IP] -> % IPv6 address
+ #hostent{h_addrtype = inet6,
+ h_length = 16} = HEnt,
+ check_elems(
+ [{HEnt#hostent.h_name,[Name,FullName]},
+ {HEnt#hostent.h_aliases,[[],Aliases]}]);
+ [IP46] -> % IPv4 compatible address
+ {ok,HEnt4} = inet:gethostbyname(Name, inet),
+ #hostent{h_addrtype = inet,
+ h_length = 4,
+ h_addr_list = [IP4]} = HEnt4,
+ {ok,IP46} =
+ inet_parse:ipv6_address(
+ "::ffff:" ++ inet_parse:ntoa(IP4)),
+ check_elems(
+ [{HEnt#hostent.h_name,[Name,FullName]}])
+ end,
+
+ {ok,HEntF} = inet:gethostbyname(FullName, inet6),
+ case HEntF#hostent.h_addr_list of
+ [IP] -> % IPv6 address
+ #hostent{h_name = FullName,
+ h_addrtype = inet6,
+ h_length = 16} = HEntF,
+ check_elems(
+ [{HEnt#hostent.h_aliases,[[],Aliases]}]);
+ [IP46F] -> % IPv4 compatible address
+ {ok,HEnt4F} = inet:gethostbyname(FullName, inet),
+ #hostent{h_addrtype = inet,
+ h_length = 4,
+ h_addr_list = [IP4F]} = HEnt4F,
+ {ok,IP46F} =
+ inet_parse:ipv6_address(
+ "::ffff:" ++ inet_parse:ntoa(IP4F)),
+ check_elems(
+ [{HEntF#hostent.h_name,[Name,FullName]}])
+ end;
+ _ ->
{skip, "IPv6 is not supported on this host"}
end.
@@ -290,47 +284,35 @@ t_getaddr(Config) when is_list(Config) ->
?line {error,nxdomain} = inet:getaddr(DName, inet),
?line {error,nxdomain} = inet:getaddr(DFullName, inet),
?line {ok,DIP} = inet:getaddr(DIPStr, inet),
- ?line {ok,DIP} = inet:getaddr(DIP, inet).
+ ?line {ok,DIP} = inet:getaddr(DIP, inet),
+ ok.
t_getaddr_v6() -> required(v4) ++ required(v6).
t_getaddr_v6(doc) -> "Test the inet:getaddr/2 function.";
t_getaddr_v6(suite) -> [];
t_getaddr_v6(Config) when is_list(Config) ->
- ?line {Name,FullName,IPStr,_IP,_,IP_46_Str,IP46} =
- ct:get_config(test_host_ipv4_only),
- case {inet:getaddr(IP_46_Str, inet6),inet:getaddr(Name, inet6)} of
- {{ok,IP46},{ok,V4Addr}} when V4Addr /= {0,0,0,0,0,0,0,1} ->
- %% Since we suceeded in parsing an IPv6 address string and
- %% look up the name, this computer fully supports IPv6.
- ?line {ok,IP46} = inet:getaddr(IP46, inet6),
- ?line {ok,IP46} = inet:getaddr(Name, inet6),
- ?line {ok,IP46} = inet:getaddr(FullName, inet6),
- ?line {ok,IP46} = inet:getaddr(IPStr, inet6),
-%% ?line IP4toIP6 = inet:getaddr(IPStr, inet6),
-%% ?line case IP4toIP6 of
-%% {ok,IP46} ->
-%% ?line ok;
-%% {error,nxdomain} ->
-%% ?line false =
-%% lists:member(native,
-%% inet_db:res_option(lookup))
-%% end,
- ?line {Name6, FullName6, IPStr6, IP6, _} =
- ct:get_config(test_host_ipv6_only),
- ?line {ok,_} = inet:getaddr(list_to_atom(Name6), inet6),
- ?line {ok,_} = inet:getaddr(Name6, inet6),
- ?line {ok,_} = inet:getaddr(FullName6, inet6),
- ?line {ok,IP6} = inet:getaddr(IP6, inet6),
- ?line {ok,IP6} = inet:getaddr(IPStr6, inet6),
-
- ?line {DName6, DFullName6, DIPStr6, DIP6, _} =
+ {Name,FullName,IPStr,IP,_} =
+ ct:get_config(test_host_ipv6_only),
+
+ case inet:getaddr(Name, inet6) of
+ {ok,Addr} ->
+ IP = Addr,
+ {ok,IP} = inet:getaddr(toupper(Name), inet6),
+ {ok,IP} = inet:getaddr(list_to_atom(Name), inet6),
+ {ok,IP} = inet:getaddr(list_to_atom(toupper(Name)), inet6),
+ {ok,IP} = inet:getaddr(FullName, inet6),
+ {ok,IP} = inet:getaddr(toupper(FullName), inet6),
+ {ok,IP} = inet:getaddr(IP, inet6),
+ {ok,IP} = inet:getaddr(IPStr, inet6),
+ %%
+ {DName,DFullName,DIPStr,DIP,_} =
ct:get_config(test_dummy_ipv6_host),
- ?line {error,nxdomain} = inet:getaddr(DName6, inet6),
- ?line {error,nxdomain} = inet:getaddr(DFullName6, inet6),
- ?line {ok,DIP6} = inet:getaddr(DIPStr6, inet6),
- ?line {ok,DIP6} = inet:getaddr(DIP6, inet6),
+ {error,nxdomain} = inet:getaddr(DName, inet6),
+ {error,nxdomain} = inet:getaddr(DFullName, inet6),
+ {ok,DIP} = inet:getaddr(DIPStr, inet6),
+ {ok,DIP} = inet:getaddr(DIP, inet6),
ok;
- {_,_} ->
+ _ ->
{skip, "IPv6 is not supported on this host"}
end.
@@ -608,8 +590,12 @@ t_parse_address(Func, [String|L]) ->
t_parse_address(Func, L).
parse_strict_address(Config) when is_list(Config) ->
- {ok, Ipv4} = inet:parse_strict_address("127.0.0.1"),
- {ok, Ipv6} = inet:parse_strict_address("c11:0c22:5c33:c440:55c0:c66c:77:0088").
+ {ok, {127,0,0,1}} =
+ inet:parse_strict_address("127.0.0.1"),
+ {ok, {3089,3106,23603,50240,21952,50796,119,136}} =
+ inet:parse_strict_address("c11:0c22:5c33:c440:55c0:c66c:77:0088"),
+ {ok, {3089,3106,23603,50240,0,0,119,136}} =
+ inet:parse_strict_address("c11:0c22:5c33:c440::077:0088").
t_gethostnative(suite) ->[];
t_gethostnative(doc) ->[];
@@ -1102,3 +1088,14 @@ ip_member({127,_,_,_}, [{127,_,_,_}|_]) -> true;
ip_member(K, [K|_]) -> true;
ip_member(K, [_|T]) -> ip_member(K, T);
ip_member(_, []) -> false.
+
+%% Case fold to upper case according to RFC 4343
+%%
+toupper([C|Cs]) when is_integer(C) ->
+ if $a =< C, C =< $z ->
+ [(C - $a + $A)|toupper(Cs)];
+ true ->
+ [C|toupper(Cs)]
+ end;
+toupper([]) ->
+ [].
diff --git a/lib/kernel/test/inet_res_SUITE.erl b/lib/kernel/test/inet_res_SUITE.erl
index f3ba28e4f9..1bc93e3138 100644
--- a/lib/kernel/test/inet_res_SUITE.erl
+++ b/lib/kernel/test/inet_res_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-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
@@ -282,6 +282,7 @@ basic(doc) ->
basic(Config) when is_list(Config) ->
NS = ns(Config),
Name = "ns.otptest",
+ NameC = caseflip(Name),
IP = {127,0,0,254},
%%
%% nslookup
@@ -292,6 +293,17 @@ basic(Config) when is_list(Config) ->
Bin1 = inet_dns:encode(Msg1),
%%io:format("Bin1 = ~w~n", [Bin1]),
{ok,Msg1} = inet_dns:decode(Bin1),
+ %% Now with scrambled case
+ {ok,Msg1b} = inet_res:nslookup(NameC, in, a, [NS]),
+ io:format("~p~n", [Msg1b]),
+ [RR1b] = inet_dns:msg(Msg1b, anlist),
+ IP = inet_dns:rr(RR1b, data),
+ Bin1b = inet_dns:encode(Msg1b),
+ %%io:format("Bin1b = ~w~n", [Bin1b]),
+ {ok,Msg1b} = inet_dns:decode(Bin1b),
+ true =
+ (tolower(inet_dns:rr(RR1, domain))
+ =:= tolower(inet_dns:rr(RR1b, domain))),
%%
%% resolve
{ok,Msg2} = inet_res:resolve(Name, in, a, [{nameservers,[NS]},verbose]),
@@ -301,15 +313,29 @@ basic(Config) when is_list(Config) ->
Bin2 = inet_dns:encode(Msg2),
%%io:format("Bin2 = ~w~n", [Bin2]),
{ok,Msg2} = inet_dns:decode(Bin2),
+ %% Now with scrambled case
+ {ok,Msg2b} = inet_res:resolve(NameC, in, a, [{nameservers,[NS]},verbose]),
+ io:format("~p~n", [Msg2b]),
+ [RR2b] = inet_dns:msg(Msg2b, anlist),
+ IP = inet_dns:rr(RR2b, data),
+ Bin2b = inet_dns:encode(Msg2b),
+ %%io:format("Bin2b = ~w~n", [Bin2b]),
+ {ok,Msg2b} = inet_dns:decode(Bin2b),
+ true =
+ (tolower(inet_dns:rr(RR2, domain))
+ =:= tolower(inet_dns:rr(RR2b, domain))),
%%
%% lookup
[IP] = inet_res:lookup(Name, in, a, [{nameservers,[NS]},verbose]),
+ [IP] = inet_res:lookup(NameC, in, a, [{nameservers,[NS]},verbose]),
%%
%% gethostbyname
{ok,#hostent{h_addr_list=[IP]}} = inet_res:gethostbyname(Name),
+ {ok,#hostent{h_addr_list=[IP]}} = inet_res:gethostbyname(NameC),
%%
%% getbyname
{ok,#hostent{h_addr_list=[IP]}} = inet_res:getbyname(Name, a),
+ {ok,#hostent{h_addr_list=[IP]}} = inet_res:getbyname(NameC, a),
ok.
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -317,63 +343,115 @@ basic(Config) when is_list(Config) ->
resolve(doc) ->
["Lookup different records using resolve/2..4"];
resolve(Config) when is_list(Config) ->
+ Class = in,
NS = ns(Config),
Domain = "otptest",
RDomain4 = "0.0.127.in-addr.arpa",
RDomain6 = "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa",
Name = "resolve."++Domain,
- L = [{in,a,Name,[{127,0,0,28}],undefined},
- {in,aaaa,Name,[{0,0,0,0,0,0,32512,28}],undefined},
- {in,cname,"cname."++Name,[Name],undefined},
- {in,a,"cname."++Name,[Name,{127,0,0,28}],undefined},
- {in,ns,"ns."++Name,[],[Name]},
- {in,soa,Domain,[],[{"ns.otptest","lsa.otptest",1,60,10,300,30}]},
+ L = [{a,Name,[{a,{127,0,0,28}}],undefined},
+ {aaaa,Name,[{aaaa,{0,0,0,0,0,0,32512,28}}],undefined},
+ {cname,"cname."++Name,[{cname,Name}],undefined},
+ {a,"cname."++Name,[{cname,Name},{a,{127,0,0,28}}],undefined},
+ {ns,"ns."++Name,[],[{ns,Name}]},
+ {soa,Domain,[],[{soa,{"ns.otptest","lsa.otptest",1,60,10,300,30}}]},
%% WKS: protocol TCP (6), services (bits) TELNET (23) and SMTP (25)
- {in,wks,"wks."++Name,[{{127,0,0,28},6,<<0,0,1,64>>}],undefined},
- {in,ptr,"28."++RDomain4,[Name],undefined},
- {in,ptr,"c.1.0.0.0.0.f.7."++RDomain6,[Name],undefined},
- {in,hinfo,Name,[{"BEAM","Erlang/OTP"}],undefined},
- {in,mx,RDomain4,[{10,"mx."++Domain}],undefined},
- {in,srv,"_srv._tcp."++Name,[{10,3,4711,Name}],undefined},
- {in,naptr,"naptr."++Name,
- [{10,5,"s","http","","_srv._tcp."++Name}],undefined},
- {in,txt,"txt."++Name,
- [["Hej ","du ","glade "],["ta ","en ","spade!"]],undefined},
- {in,mb,"mb."++Name,["mx."++Name],undefined},
- {in,mg,"mg."++Name,["lsa."++Domain],undefined},
- {in,mr,"mr."++Name,["lsa."++Domain],undefined},
- {in,minfo,"minfo."++Name,
- [{"minfo-owner."++Name,"minfo-bounce."++Name}],undefined},
- {in,any,"cname."++Name,[Name],undefined},
- {in,any,Name,[{127,0,0,28},
- {0,0,0,0,0,0,32512,28},
- {"BEAM","Erlang/OTP"}],undefined}
+ {wks,"wks."++Name,[{wks,{{127,0,0,28},6,<<0,0,1,64>>}}],undefined},
+ {ptr,"28."++RDomain4,[{ptr,Name}],undefined},
+ {ptr,"c.1.0.0.0.0.f.7."++RDomain6,[{ptr,Name}],undefined},
+ {hinfo,Name,[{hinfo,{"BEAM","Erlang/OTP"}}],undefined},
+ {mx,RDomain4,[{mx,{10,"mx."++Domain}}],undefined},
+ {srv,"_srv._tcp."++Name,[{srv,{10,3,4711,Name}}],undefined},
+ {naptr,"naptr."++Name,
+ [{naptr,{10,5,"s","http","","_srv._tcp."++Name}}],
+ undefined},
+ {txt,"txt."++Name,
+ [{txt,["Hej ","du ","glade "]},{txt,["ta ","en ","spade!"]}],
+ undefined},
+ {mb,"mb."++Name,[{mb,"mx."++Name}],undefined},
+ {mg,"mg."++Name,[{mg,"Lsa."++Domain}],undefined},
+ {mr,"mr."++Name,[{mr,"LSA."++Domain}],undefined},
+ {minfo,"minfo."++Name,
+ [{minfo,{"minfo-OWNER."++Name,"MinfoBounce."++Name}}],
+ undefined},
+ {any,"cname."++Name,[{cname,Name}],undefined},
+ {any,Name,
+ [{a,{127,0,0,28}},
+ {aaaa,{0,0,0,0,0,0,32512,28}},
+ {hinfo,{"BEAM","Erlang/OTP"}}],
+ undefined}
],
- resolve([{edns,false},{nameservers,[NS]}], L),
- resolve([{edns,0},{nameservers,[NS]}], L).
-
-resolve(_Opts, []) -> ok;
-resolve(Opts, [{Class,Type,Name,Answers,Authority}=Q|Qs]) ->
+ resolve(Class, [{edns,0},{nameservers,[NS]}], L),
+ resolve(Class, [{edns,false},{nameservers,[NS]}], L),
+ %% Again, to see ensure the cache does not mess things up
+ resolve(Class, [{edns,0},{nameservers,[NS]}], L),
+ resolve(Class, [{edns,false},{nameservers,[NS]}], L).
+
+resolve(_Class, _Opts, []) ->
+ ok;
+resolve(Class, Opts, [{Type,Nm,Answers,Authority}=Q|Qs]) ->
io:format("Query: ~p~nOptions: ~p~n", [Q,Opts]),
- {ok,Msg} = inet_res:resolve(Name, Class, Type, Opts),
+ {Name,NameC} =
+ case erlang:phash2(Q) band 4 of
+ 0 ->
+ {Nm,caseflip(Nm)};
+ _ ->
+ {caseflip(Nm),Nm}
+ end,
AnList =
if
Answers =/= undefined ->
- lists:sort(Answers);
+ normalize_answers(Answers);
true ->
undefined
end,
NsList =
if
Authority =/= undefined ->
- lists:sort(Authority);
+ normalize_answers(Authority);
true ->
undefined
end,
- case {lists:sort
- ([inet_dns:rr(RR, data) || RR <- inet_dns:msg(Msg, anlist)]),
- lists:sort
- ([inet_dns:rr(RR, data) || RR <- inet_dns:msg(Msg, nslist)])} of
+ {ok,Msg} = inet_res:resolve(Name, Class, Type, Opts),
+ check_msg(Class, Type, Msg, AnList, NsList),
+ {ok,MsgC} = inet_res:resolve(NameC, Class, Type, Opts),
+ check_msg(Class, Type, MsgC, AnList, NsList),
+ resolve(Class, Opts, Qs).
+
+
+
+normalize_answers(AnList) ->
+ lists:sort([normalize_answer(Answer) || Answer <- AnList]).
+
+normalize_answer({soa,{NS,HM,Ser,Ref,Ret,Exp,Min}}) ->
+ {tolower(NS),tolower_email(HM),Ser,Ref,Ret,Exp,Min};
+normalize_answer({mx,{Prio,DN}}) ->
+ {Prio,tolower(DN)};
+normalize_answer({srv,{Prio,Weight,Port,DN}}) ->
+ {Prio,Weight,Port,tolower(DN)};
+normalize_answer({naptr,{Order,Pref,Flags,Service,RE,Repl}}) ->
+ {Order,Pref,Flags,Service,RE,tolower(Repl)};
+normalize_answer({minfo,{RespM,ErrM}}) ->
+ {tolower_email(RespM),tolower_email(ErrM)};
+normalize_answer({T,MN}) when T =:= mg; T =:= mr ->
+ tolower_email(MN);
+normalize_answer({T,DN}) when T =:= cname; T =:= ns; T =:= ptr; T =:= mb ->
+ tolower(DN);
+normalize_answer(Answer) ->
+ Answer.
+
+check_msg(Class, Type, Msg, AnList, NsList) ->
+ io:format("check_msg Type: ~p, Msg: ~p~n.", [Type,Msg]),
+ case {normalize_answers(
+ [begin
+ Class = inet_dns:rr(RR, class),
+ {inet_dns:rr(RR, type),inet_dns:rr(RR, data)}
+ end || RR <- inet_dns:msg(Msg, anlist)]),
+ normalize_answers(
+ [begin
+ Class = inet_dns:rr(RR, class),
+ {inet_dns:rr(RR, type),inet_dns:rr(RR, data)}
+ end || RR <- inet_dns:msg(Msg, nslist)])} of
{AnList,NsList} ->
ok;
{NsList,AnList} when Type =:= ns ->
@@ -389,7 +467,7 @@ resolve(Opts, [{Class,Type,Name,Answers,Authority}=Q|Qs]) ->
end,
Buf = inet_dns:encode(Msg),
{ok,Msg} = inet_dns:decode(Buf),
- resolve(Opts, Qs).
+ ok.
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -497,6 +575,7 @@ files_monitor(Config) when is_list(Config) ->
do_files_monitor(Config) ->
Dir = ?config(priv_dir, Config),
{ok,Hostname} = inet:gethostname(),
+ io:format("Hostname = ~p.~n", [Hostname]),
FQDN =
case inet_db:res_option(domain) of
"" ->
@@ -504,11 +583,13 @@ do_files_monitor(Config) ->
_ ->
Hostname++"."++inet_db:res_option(domain)
end,
+ io:format("FQDN = ~p.~n", [FQDN]),
HostsFile = filename:join(Dir, "files_monitor_hosts"),
ResolvConf = filename:join(Dir, "files_monitor_resolv.conf"),
ok = inet_db:res_option(resolv_conf, ResolvConf),
ok = inet_db:res_option(hosts_file, HostsFile),
[] = inet_db:res_option(search),
+ %% The inet function will use its final fallback to find this host
{ok,#hostent{h_name = Hostname,
h_addrtype = inet,
h_length = 4,
@@ -521,6 +602,7 @@ do_files_monitor(Config) ->
{error,nxdomain} = inet_res:gethostbyname(FQDN),
{ok,{127,0,0,10}} = inet:getaddr("mx.otptest", inet),
{ok,{0,0,0,0,0,0,32512,28}} = inet:getaddr("resolve.otptest", inet6),
+ %% The inet function will use its final fallback to find this host
{ok,#hostent{h_name = Hostname,
h_addrtype = inet6,
h_length = 16,
@@ -603,3 +685,41 @@ ipv4_to_ipv6() -> inet_SUITE:ipv4_to_ipv6().
ipv4_to_ipv6(Config) -> inet_SUITE:ipv4_to_ipv6(Config).
host_and_addr() -> inet_SUITE:host_and_addr().
host_and_addr(Config) -> inet_SUITE:host_and_addr(Config).
+
+
+
+%% Case flip helper
+
+caseflip([C|Cs]) when is_integer(C), $a =< C, C =< $z ->
+ [(C - $a + $A)|caseflip_skip(Cs)];
+caseflip([C|Cs]) when is_integer(C), $A =< C, C =< $Z ->
+ [(C - $A + $a)|caseflip_skip(Cs)];
+caseflip([C|Cs]) ->
+ [C|caseflip(Cs)];
+caseflip([]) ->
+ [].
+
+caseflip_skip([C|Cs]) when is_integer(C), $a =< C, C =< $z ->
+ [C|caseflip(Cs)];
+caseflip_skip([C|Cs]) when is_integer(C), $A =< C, C =< $Z ->
+ [C|caseflip(Cs)];
+caseflip_skip([C|Cs]) ->
+ [C|caseflip_skip(Cs)];
+caseflip_skip([]) ->
+ [].
+
+tolower_email([$.|Cs]) ->
+ [$.|tolower(Cs)];
+tolower_email([C|Cs]) ->
+ [C|tolower_email(Cs)].
+
+%% Case fold to lower case according to RFC 4343
+%%
+tolower([C|Cs]) when is_integer(C) ->
+ if $A =< C, C =< $Z ->
+ [(C - $A + $a)|tolower(Cs)];
+ true ->
+ [C|tolower(Cs)]
+ end;
+tolower([]) ->
+ [].
diff --git a/lib/kernel/test/inet_res_SUITE_data/otptest/named_inc.conf b/lib/kernel/test/inet_res_SUITE_data/otptest/named_inc.conf
index 0b01b25204..2d68f6e59c 100644
--- a/lib/kernel/test/inet_res_SUITE_data/otptest/named_inc.conf
+++ b/lib/kernel/test/inet_res_SUITE_data/otptest/named_inc.conf
@@ -2,11 +2,11 @@ zone "." in {
type master;
file "root.zone";
};
-zone "0.0.127.in-addr.arpa" in {
+zone "0.0.127.in-addr.arpa." in {
type master;
file "0.0.127.in-addr.arpa.zone";
};
-zone "0.0.0.0.f.7.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa" in {
+zone "0.0.0.0.f.7.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa." in {
type master;
file "0.0.0.0.f.7.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.zone";
-}; \ No newline at end of file
+};
diff --git a/lib/kernel/test/inet_res_SUITE_data/otptest/root.zone b/lib/kernel/test/inet_res_SUITE_data/otptest/root.zone
index 11cba18d45..5a56eac95c 100644
--- a/lib/kernel/test/inet_res_SUITE_data/otptest/root.zone
+++ b/lib/kernel/test/inet_res_SUITE_data/otptest/root.zone
@@ -43,8 +43,8 @@ naptr.resolve.otptest IN NAPTR 10 5 "S" "HTTP" "" _srv._tcp.resolve.otptest
txt.resolve.otptest IN TXT "Hej " "du " "glade "
txt.resolve.otptest IN TXT "ta " "en " "spade!"
mb.resolve.otptest IN MB mx.resolve.otptest
-mg.resolve.otptest IN MG lsa.otptest
-mr.resolve.otptest IN MR lsa.otptest
-minfo.resolve.otptest IN MINFO minfo-owner.resolve.otptest minfo-bounce.resolve.otptest
+mg.resolve.otptest IN MG Lsa.otptest
+mr.resolve.otptest IN MR LSA.otptest
+minfo.resolve.otptest IN MINFO minfo-OWNER.resolve.otptest MinfoBounce.resolve.otptest
ns.otptest IN A 127.0.0.254
diff --git a/lib/kernel/test/interactive_shell_SUITE.erl b/lib/kernel/test/interactive_shell_SUITE.erl
index dac021c6c6..d7d9434b1f 100644
--- a/lib/kernel/test/interactive_shell_SUITE.erl
+++ b/lib/kernel/test/interactive_shell_SUITE.erl
@@ -211,7 +211,7 @@ job_control_remote(Config) when is_list(Config) ->
{sleep,timeout(short)},
{putline,""},
{getline," -->"},
- {putline,"r "++MyNode},
+ {putline,"r '"++MyNode++"'"},
{putline,"c"},
{putline_raw,""},
{getline,"Eshell"},
@@ -265,7 +265,7 @@ job_control_remote_noshell(Config) when is_list(Config) ->
{sleep,timeout(short)},
{putline,""},
{getline," -->"},
- {putline,"r "++NSNodeStr},
+ {putline,"r '"++NSNodeStr++"'"},
{putline,"c"},
{putline_raw,""},
{getline,"Eshell"},
@@ -721,4 +721,4 @@ get_default_shell() ->
end.
atom2list(A) ->
- lists:flatten(io_lib:format("~w", [A])).
+ lists:flatten(io_lib:format("~s", [A])).
diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl
index ac75037536..199e597e78 100644
--- a/lib/kernel/test/prim_file_SUITE.erl
+++ b/lib/kernel/test/prim_file_SUITE.erl
@@ -2039,6 +2039,8 @@ symlinks(Config, Handle, Suffix) ->
?PRIM_FILE_call(read_link, Handle, [Alias]),
{ok, Name} =
?PRIM_FILE_call(read_link_all, Handle, [Alias]),
+ %% If all is good, delete dir again (avoid hanging dir on windows)
+ rm_rf(?PRIM_FILE,NewDir),
ok
end,
@@ -2245,3 +2247,18 @@ zip_data([], Bs) ->
Bs;
zip_data(As, []) ->
As.
+
+%%%-----------------------------------------------------------------
+%%% Utilities
+rm_rf(Mod,Dir) ->
+ case Mod:read_link_info(Dir) of
+ {ok, #file_info{type = directory}} ->
+ {ok, Content} = Mod:list_dir_all(Dir),
+ [ rm_rf(Mod,filename:join(Dir,C)) || C <- Content ],
+ Mod:del_dir(Dir),
+ ok;
+ {ok, #file_info{}} ->
+ Mod:delete(Dir);
+ _ ->
+ ok
+ end.
diff --git a/lib/mnesia/src/mnesia_subscr.erl b/lib/mnesia/src/mnesia_subscr.erl
index 415c69d508..8f78dc55e8 100644
--- a/lib/mnesia/src/mnesia_subscr.erl
+++ b/lib/mnesia/src/mnesia_subscr.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -447,8 +447,12 @@ deactivate(ClientPid, What, Var, SubscrTab) ->
{'EXIT', _} ->
unlink(ClientPid)
end,
- del_subscr(Var, What, ClientPid),
- {ok, node()}.
+ try
+ del_subscr(Var, What, ClientPid),
+ {ok, node()}
+ catch _:_ ->
+ {error, badarg}
+ end.
del_subscr(subscribers, _What, Pid) ->
mnesia_lib:del(subscribers, Pid);
diff --git a/lib/mnesia/test/mnesia_evil_coverage_test.erl b/lib/mnesia/test/mnesia_evil_coverage_test.erl
index 0df245b75d..db23a39943 100644
--- a/lib/mnesia/test/mnesia_evil_coverage_test.erl
+++ b/lib/mnesia/test/mnesia_evil_coverage_test.erl
@@ -1985,6 +1985,10 @@ subscribe_standard(Config) when is_list(Config)->
?match({atomic, ok}, mnesia:create_table(Tab, Def)),
%% Check system events
+ ?match({error, {badarg, foo}}, mnesia:unsubscribe(foo)),
+ ?match({error, badarg}, mnesia:unsubscribe({table, foo})),
+ ?match(_, mnesia:unsubscribe(activity)),
+
?match({ok, N1}, mnesia:subscribe(system)),
?match({ok, N1}, mnesia:subscribe(activity)),
diff --git a/lib/mnesia/test/mnesia_isolation_test.erl b/lib/mnesia/test/mnesia_isolation_test.erl
index 3273bc4d40..d57f976d1f 100644
--- a/lib/mnesia/test/mnesia_isolation_test.erl
+++ b/lib/mnesia/test/mnesia_isolation_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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
@@ -613,11 +613,11 @@ unbound2(Config) when is_list(Config) ->
?match_receive({B, continuing}),
%% B should now be in lock queue.
- A ! continue,
- ?match_receive({A, {atomic, ok}}),
- ?match_receive({B, {atomic, [{ul,{key,{17,42}},val}]}}),
+ A ! continue,
+ ?match_multi_receive([{A, {atomic, ok}},
+ {B, {atomic, [{ul,{key,{17,42}},val}]}}]),
ok.
-
+
receiver() ->
receive
{_Pid, begin_trans} ->
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/os_mon/vsn.mk b/lib/os_mon/vsn.mk
index 7d6c5484a7..e3acea0258 100644
--- a/lib/os_mon/vsn.mk
+++ b/lib/os_mon/vsn.mk
@@ -1 +1 @@
-OS_MON_VSN = 2.2.11
+OS_MON_VSN = 2.2.12
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index 10c95a39ac..bce6d58682 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -43,7 +43,8 @@
<title>public_key</title>
<list type="bulleted">
- <item>public_key requires the crypto application.</item>
+ <item>public_key requires the crypto and asn1 applications, the latter since R16 (hopefully the runtime dependency on asn1 will
+ be removed again in the future).</item>
<item>Supports <url href="http://www.ietf.org/rfc/rfc5280.txt">RFC 5280 </url> -
Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile </item>
@@ -154,8 +155,8 @@
<funcs>
<func>
- <name> compute_key(OthersKey, MyKey)-></name>
- <name> compute_key(OthersKey, MyKey, Params)-></name>
+ <name>compute_key(OthersKey, MyKey)-></name>
+ <name>compute_key(OthersKey, MyKey, Params)-></name>
<fsummary> Compute shared secret</fsummary>
<type>
<v>OthersKey = #'ECPoint'{} | binary(), MyKey = #'ECPrivateKey'{} | binary()</v>
@@ -176,7 +177,8 @@
<v>Options = public_crypt_options()</v>
</type>
<desc>
- <p>Public key decryption using the private key.</p>
+ <p>Public key decryption using the private key. See also <seealso
+ marker="crypto:crypto#private_decrypt/4">crypto:private_decrypt/4</seealso></p>
</desc>
</func>
@@ -190,7 +192,8 @@
<v>Options = public_crypt_options()</v>
</type>
<desc>
- <p> Public key decryption using the public key.</p>
+ <p> Public key decryption using the public key. See also <seealso
+ marker="crypto:crypto#public_decrypt/4">crypto:public_decrypt/4</seealso></p>
</desc>
</func>
@@ -304,7 +307,9 @@
<v>Key = rsa_private_key()</v>
</type>
<desc>
- <p> Public key encryption using the private key.</p>
+ <p> Public key encryption using the private key.
+ See also <seealso
+ marker="crypto:crypto#private_encrypt/4">crypto:private_encrypt/4</seealso></p>
</desc>
</func>
@@ -316,7 +321,8 @@
<v>Key = rsa_public_key()</v>
</type>
<desc>
- <p> Public key encryption using the public key.</p>
+ <p> Public key encryption using the public key. See also <seealso
+ marker="crypto:crypto#public_encrypt/4">crypto:public_encrypt/4</seealso></p>
</desc>
</func>
diff --git a/lib/public_key/src/public_key.app.src b/lib/public_key/src/public_key.app.src
index 9f0677606d..736a778a4b 100644
--- a/lib/public_key/src/public_key.app.src
+++ b/lib/public_key/src/public_key.app.src
@@ -11,7 +11,7 @@
'OTP-PUB-KEY',
'PKCS-FRAME'
]},
- {applications, [crypto, kernel, stdlib]},
+ {applications, [asn1, crypto, kernel, stdlib]},
{registered, []},
{env, []}
]
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 3eea6f6ec4..cdbfe6e07c 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -252,8 +252,7 @@ decrypt_private(CipherText, Key) ->
decrypt_private(CipherText, Key, []).
decrypt_private(CipherText,
- #'RSAPrivateKey'{modulus = N, publicExponent = E,
- privateExponent = D} = Key,
+ #'RSAPrivateKey'{} = Key,
Options)
when is_binary(CipherText),
is_list(Options) ->
diff --git a/lib/public_key/test/pkits_SUITE.erl b/lib/public_key/test/pkits_SUITE.erl
index c490493e13..9180fa968b 100644
--- a/lib/public_key/test/pkits_SUITE.erl
+++ b/lib/public_key/test/pkits_SUITE.erl
@@ -113,12 +113,14 @@ groups() ->
init_per_suite(Config) ->
try crypto:start() of
ok ->
+ application:start(asn1),
crypto_support_check(Config)
catch _:_ ->
{skip, "Crypto did not start"}
end.
end_per_suite(_Config) ->
+ application:stop(asn1),
application:stop(crypto).
%%--------------------------------------------------------------------
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index 5a64140c67..f2596e3d85 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -58,12 +58,14 @@ groups() ->
init_per_suite(Config) ->
try crypto:start() of
ok ->
+ application:start(asn1),
Config
catch _:_ ->
{skip, "Crypto did not start"}
end.
end_per_suite(_Config) ->
+ application:stop(asn1),
application:stop(crypto).
%%-------------------------------------------------------------------
diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk
index bd20a5546b..b820f24d2a 100644
--- a/lib/public_key/vsn.mk
+++ b/lib/public_key/vsn.mk
@@ -1 +1 @@
-PUBLIC_KEY_VSN = 0.18
+PUBLIC_KEY_VSN = 0.19
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 e675cf1b83..223d3f7218 100644
--- a/lib/snmp/src/agent/snmp_user_based_sm_mib.erl
+++ b/lib/snmp/src/agent/snmp_user_based_sm_mib.erl
@@ -1219,16 +1219,10 @@ split(N, [H | T], FirstRev) when N > 0 ->
split(N-1, T, [H | FirstRev]).
-is_crypto_supported(Algo) ->
- %% The 'catch' handles the case when 'crypto' is
- %% not present in the system (or not started).
- Supported = crypto:supports(),
- Hashs = proplists:get_value(hashs, Supported),
- Ciphers = proplists:get_value(ciphers, Supported),
- case catch lists:member(Algo, Hashs ++ Ciphers) of
- true -> true;
- _ -> false
- end.
+-compile({inline, [{is_crypto_supported,1}]}).
+is_crypto_supported(Func) ->
+ 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 53c291ca0e..67e3476816 100644
--- a/lib/snmp/src/misc/snmp_usm.erl
+++ b/lib/snmp/src/misc/snmp_usm.erl
@@ -142,32 +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:hmac(md5, AuthKey, Packet, 12)),
- ?vtrace("md5_auth_out -> entry with"
- "~n Packet: ~w"
- "~n AuthKey: ~w"
- "~n MAC: ~w"
- , [Packet, AuthKey, MAC]),
+ %% ?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: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
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.appup.src b/lib/ssh/src/ssh.appup.src
index b25e0c9e37..32f7cc470b 100644
--- a/lib/ssh/src/ssh.appup.src
+++ b/lib/ssh/src/ssh.appup.src
@@ -19,22 +19,12 @@
{"%VSN%",
[
- {<<"2.1.4">>, [{load_module, ssh_sftp, soft_purge, soft_purge, []},
- {load_module, ssh_connection_handler, soft_purge, soft_purge, []}]},
- {<<"2.1.3">>, [{restart_application, ssh}]},
- {<<"2.1.2">>, [{restart_application, ssh}]},
- {<<"2.1.1">>, [{restart_application, ssh}]},
- {<<"2.1">>, [{restart_application, ssh}]},
+ {<<"2.1\\.*">>, [{restart_application, ssh}]},
{<<"2.0\\.*">>, [{restart_application, ssh}]},
{<<"1\\.*">>, [{restart_application, ssh}]}
],
[
- {<<"2.1.4">>, [{load_module, ssh_sftp, soft_purge, soft_purge, []},
- {load_module, ssh_connection_handler, soft_purge, soft_purge, []}]},
- {<<"2.1.3">>, [{restart_application, ssh}]},
- {<<"2.1.2">>, [{restart_application, ssh}]},
- {<<"2.1.1">>, [{restart_application, ssh}]},
- {<<"2.1">>,[{restart_application, ssh}]},
+ {<<"2.1\\.*">>,[{restart_application, ssh}]},
{<<"2.0\\.*">>, [{restart_application, ssh}]},
{<<"1\\.*">>, [{restart_application, ssh}]}
]
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 3a7aa79d16..7d5478c3f6 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -41,11 +41,13 @@
%%--------------------------------------------------------------------
start() ->
application:start(crypto),
+ application:start(asn1),
application:start(public_key),
application:start(ssh).
start(Type) ->
application:start(crypto, Type),
+ application:start(asn1),
application:start(public_key, Type),
application:start(ssh, Type).
diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile
index 3b8145089e..cf9f7d5001 100644
--- a/lib/ssl/src/Makefile
+++ b/lib/ssl/src/Makefile
@@ -42,31 +42,37 @@ BEHAVIOUR_MODULES= \
MODULES= \
ssl \
+ tls \
+ dtls \
ssl_alert \
ssl_app \
ssl_dist_sup\
ssl_sup \
inet_tls_dist \
ssl_certificate\
- ssl_certificate_db\
+ ssl_pkix_db\
ssl_cipher \
ssl_srp_primes \
- ssl_connection \
+ tls_connection \
+ dtls_connection \
ssl_connection_sup \
- ssl_handshake \
+ tls_handshake \
+ dtls_handshake\
ssl_manager \
ssl_session \
ssl_session_cache \
ssl_socket \
- ssl_record \
+ tls_record \
+ dtls_record \
ssl_ssl2 \
ssl_ssl3 \
ssl_tls1 \
ssl_tls_dist_proxy
INTERNAL_HRL_FILES = \
- ssl_alert.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_internal.hrl \
- ssl_record.hrl ssl_srp.hrl
+ ssl_alert.hrl ssl_cipher.hrl ssl_handshake.hrl tls_handshake.hrl \
+ dtls_handshake.hrl ssl_internal.hrl \
+ ssl_record.hrl tls_record.hrl dtls_record.hrl ssl_srp.hrl
ERL_FILES= \
$(MODULES:%=%.erl) \
@@ -134,13 +140,14 @@ release_docs_spec:
# Dependencies
# ----------------------------------------------------
$(EBIN)/inet_tls_dist.$(EMULATOR): ../../kernel/include/net_address.hrl ../../kernel/include/dist.hrl ../../kernel/include/dist_util.hrl
-$(EBIN)/ssl.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ../../public_key/include/public_key.hrl
+$(EBIN)/tls.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ../../public_key/include/public_key.hrl
$(EBIN)/ssl_alert.$(EMULATOR): ssl_alert.hrl ssl_record.hrl
$(EBIN)/ssl_certificate.$(EMULATOR): ssl_internal.hrl ssl_alert.hrl ssl_handshake.hrl ../../public_key/include/public_key.hrl
$(EBIN)/ssl_certificate_db.$(EMULATOR): ssl_internal.hrl ../../public_key/include/public_key.hrl ../../kernel/include/file.hrl
$(EBIN)/ssl_cipher.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl
-$(EBIN)/ssl_connection.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl
-$(EBIN)/ssl_handshake.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl
+$(EBIN)/tls_connection.$(EMULATOR): ssl_internal.hrl tls_record.hrl ssl_cipher.hrl tls_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl
+$(EBIN)/dtls_connection.$(EMULATOR): ssl_internal.hrl dtls_record.hrl ssl_cipher.hrl dtls_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl
+$(EBIN)/tls_handshake.$(EMULATOR): ssl_internal.hrl tls_record.hrl ssl_cipher.hrl tls_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl
$(EBIN)/ssl_manager.$(EMULATOR): ssl_internal.hrl ssl_handshake.hrl ../../kernel/include/file.hrl
$(EBIN)/ssl_record.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_alert.hrl
$(EBIN)/ssl_session.$(EMULATOR): ssl_internal.hrl ssl_handshake.hrl
diff --git a/lib/ssl/src/ssl_debug.hrl b/lib/ssl/src/dtls.erl
index e88cef441f..013286c9bd 100644
--- a/lib/ssl/src/ssl_debug.hrl
+++ b/lib/ssl/src/dtls.erl
@@ -1,39 +1,25 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2007-2009. 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
%% 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%
%%
%%
+%%% Purpose : API for DTLS.
--ifndef(ssl_debug).
--define(ssl_debug, true).
-
--ifdef(SSL_DEBUG).
--define(DBG_HEX(V), ssl_debug:hex_data(??V, V, ?MODULE, ?LINE)).
--define(DBG_TERM(T), ssl_debug:term_data(??T, T, ?MODULE, ?LINE)).
--else.
--define(DBG_HEX(V), ok).
--define(DBG_TERM(T), ok).
--endif.
-
--endif. % -ifdef(ssl_debug).
-
-
-
-
+-module(dtls).
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
new file mode 100644
index 0000000000..ac2ee0d09f
--- /dev/null
+++ b/lib/ssl/src/dtls_connection.erl
@@ -0,0 +1,19 @@
+%%
+%% %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(dtls_connection).
diff --git a/lib/ssl/src/dtls_handshake.erl b/lib/ssl/src/dtls_handshake.erl
new file mode 100644
index 0000000000..b25daa59d9
--- /dev/null
+++ b/lib/ssl/src/dtls_handshake.erl
@@ -0,0 +1,18 @@
+%%
+%% %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(dtls_handshake).
diff --git a/lib/ssl/src/dtls_handshake.hrl b/lib/ssl/src/dtls_handshake.hrl
new file mode 100644
index 0000000000..db7b8596ae
--- /dev/null
+++ b/lib/ssl/src/dtls_handshake.hrl
@@ -0,0 +1,50 @@
+%%
+%% %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%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Record and constant defenitions for the DTLS-handshake protocol
+%% that differs from TLS see RFC 6347
+%%----------------------------------------------------------------------
+-ifndef(dtls_handshake).
+-define(dtls_handshake, true).
+
+-include("ssl_handshake.hrl"). %% Common TLS and DTLS records and Constantes
+
+-record(client_hello, {
+ client_version,
+ random,
+ session_id, % opaque SessionID<0..32>
+ cookie, % opaque<2..2^16-1>
+ cipher_suites, % cipher_suites<2..2^16-1>
+ compression_methods, % compression_methods<1..2^8-1>,
+ %% Extensions
+ renegotiation_info,
+ hash_signs, % supported combinations of hashes/signature algos
+ next_protocol_negotiation = undefined % [binary()]
+ }).
+
+-record(hello_verify_request {
+ protocol_version,
+ cookie
+ }).
+
+-define(HELLO_VERIFY_REQUEST, 3).
+
+-endif. % -ifdef(dtls_handshake).
diff --git a/lib/ssl/src/dtls_record.erl b/lib/ssl/src/dtls_record.erl
new file mode 100644
index 0000000000..2469a7d26c
--- /dev/null
+++ b/lib/ssl/src/dtls_record.erl
@@ -0,0 +1,18 @@
+%%
+%% %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(dtls_record).
diff --git a/lib/ssl/src/dtls_record.hrl b/lib/ssl/src/dtls_record.hrl
new file mode 100644
index 0000000000..e935d84bdf
--- /dev/null
+++ b/lib/ssl/src/dtls_record.hrl
@@ -0,0 +1,44 @@
+%%
+%% %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%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Record and constant defenitions for the DTLS-record protocol
+%% see RFC 6347
+%%----------------------------------------------------------------------
+
+-ifndef(dtls_record).
+-define(dtls_record, true).
+
+-include("ssl_record.hrl"). %% Common TLS and DTLS records and Constantes
+
+%% Used to handle tls_plain_text, tls_compressed and tls_cipher_text
+
+-record(ssl_tls, {
+ type,
+ version,
+ record_seq, % used in plain_text
+ epoch, % used in plain_text
+ message_seq,
+ fragment_offset,
+ fragment_length,
+ fragment
+ }).
+
+-endif. % -ifdef(dtls_record).
diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src
index 5c34de905e..582a60635f 100644
--- a/lib/ssl/src/ssl.app.src
+++ b/lib/ssl/src/ssl.app.src
@@ -1,7 +1,20 @@
{application, ssl,
[{description, "Erlang/OTP SSL application"},
{vsn, "%VSN%"},
- {modules, [ssl,
+ {modules, [
+ %% TLS/SSL
+ tls,
+ tls_connection,
+ tls_handshake,
+ tls_record,
+ %% DTLS
+ dtls_record,
+ dtls_handshake,
+ dtls_connection,
+ dtls,
+ %% Backwards compatibility
+ ssl,
+ %% Both TLS/SSL and DTLS
ssl_app,
ssl_sup,
inet_tls_dist,
@@ -14,14 +27,14 @@
ssl_session_cache_api,
ssl_session_cache,
ssl_socket,
- ssl_record,
+ %%ssl_record,
ssl_manager,
- ssl_handshake,
+ %%ssl_handshake,
ssl_connection_sup,
- ssl_connection,
+ %%ssl_connection,
ssl_cipher,
ssl_srp_primes,
- ssl_certificate_db,
+ ssl_pkix_db,
ssl_certificate,
ssl_alert
]},
@@ -31,5 +44,3 @@
{mod, {ssl_app, []}}]}.
-
-
diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src
index a8a494b2fc..9e5bec26f1 100644
--- a/lib/ssl/src/ssl.appup.src
+++ b/lib/ssl/src/ssl.appup.src
@@ -1,14 +1,14 @@
%% -*- erlang -*-
{"%VSN%",
[
- {<<"5.2">>, [{restart_application, ssl}]},
+ {<<"5.2\\*">>, [{restart_application, ssl}]},
{<<"5.1\\*">>, [{restart_application, ssl}]},
{<<"5.0\\*">>, [{restart_application, ssl}]},
{<<"4\\.*">>, [{restart_application, ssl}]},
{<<"3\\.*">>, [{restart_application, ssl}]}
],
[
- {<<"5.2">>, [{restart_application, ssl}]},
+ {<<"5.2\\*">>, [{restart_application, ssl}]},
{<<"5.1\\*">>, [{restart_application, ssl}]},
{<<"5.0\\*">>, [{restart_application, ssl}]},
{<<"4\\.*">>, [{restart_application, ssl}]},
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index fb64a6652f..0c1e47311d 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -19,7 +19,7 @@
%%
-%%% Purpose : Main API module for SSL.
+%%% Purpose : Backwards compatibility
-module(ssl).
@@ -46,13 +46,6 @@
tls_atom_version/0, %% From ssl_internal.hrl
prf_random/0, sslsocket/0]).
--record(config, {ssl, %% SSL parameters
- inet_user, %% User set inet options
- emulated, %% #socket_option{} emulated
- inet_ssl, %% inet options for internal ssl socket
- cb %% Callback info
- }).
-
-type sslsocket() :: #sslsocket{}.
-type connect_option() :: socket_connect_option() | ssl_option() | transport_option().
-type socket_connect_option() :: gen_tcp:connect_option().
@@ -92,241 +85,65 @@
%% is temporary. see application(3)
%%--------------------------------------------------------------------
start() ->
- application:start(crypto),
- application:start(public_key),
- application:start(ssl).
-
+ tls:start().
start(Type) ->
- application:start(crypto, Type),
- application:start(public_key, Type),
- application:start(ssl, Type).
+ tls:start(Type).
-%%--------------------------------------------------------------------
--spec stop() -> ok.
-%%
-%% Description: Stops the ssl application.
-%%--------------------------------------------------------------------
stop() ->
- application:stop(ssl).
+ tls:stop().
-%%--------------------------------------------------------------------
--spec connect(host() | port(), [connect_option()]) -> {ok, #sslsocket{}} |
- {error, reason()}.
--spec connect(host() | port(), [connect_option()] | inet:port_number(),
- timeout() | list()) ->
- {ok, #sslsocket{}} | {error, reason()}.
--spec connect(host() | port(), inet:port_number(), list(), timeout()) ->
- {ok, #sslsocket{}} | {error, reason()}.
+connect(Socket, SslOptions) ->
+ tls:connect(Socket, SslOptions).
-%%
-%% Description: Connect to an ssl server.
-%%--------------------------------------------------------------------
-connect(Socket, SslOptions) when is_port(Socket) ->
- connect(Socket, SslOptions, infinity).
-
-connect(Socket, SslOptions0, Timeout) when is_port(Socket) ->
- {Transport,_,_,_} = proplists:get_value(cb_info, SslOptions0,
- {gen_tcp, tcp, tcp_closed, tcp_error}),
- EmulatedOptions = emulated_options(),
- {ok, SocketValues} = ssl_socket:getopts(Transport, Socket, EmulatedOptions),
- try handle_options(SslOptions0 ++ SocketValues, client) of
- {ok, #config{cb = CbInfo, ssl = SslOptions, emulated = EmOpts}} ->
-
- ok = ssl_socket:setopts(Transport, Socket, internal_inet_values()),
- case ssl_socket:peername(Transport, Socket) of
- {ok, {Address, Port}} ->
- ssl_connection:connect(Address, Port, Socket,
- {SslOptions, EmOpts},
- self(), CbInfo, Timeout);
- {error, Error} ->
- {error, Error}
- end
- catch
- _:{error, Reason} ->
- {error, Reason}
- end;
-
-connect(Host, Port, Options) ->
- connect(Host, Port, Options, infinity).
+connect(Socket, SslOptions0, TimeoutOrOpts) ->
+ tls:connect(Socket, SslOptions0, TimeoutOrOpts).
connect(Host, Port, Options, Timeout) ->
- try handle_options(Options, client) of
- {ok, Config} ->
- do_connect(Host,Port,Config,Timeout)
- catch
- throw:Error ->
- Error
- end.
+ tls:connect(Host, Port, Options, Timeout).
-%%--------------------------------------------------------------------
--spec listen(inet:port_number(), [listen_option()]) ->{ok, #sslsocket{}} | {error, reason()}.
-
-%%
-%% Description: Creates an ssl listen socket.
-%%--------------------------------------------------------------------
-listen(_Port, []) ->
- {error, nooptions};
-listen(Port, Options0) ->
- try
- {ok, Config} = handle_options(Options0, server),
- #config{cb = {Transport, _, _, _}, inet_user = Options} = Config,
- case Transport:listen(Port, Options) of
- {ok, ListenSocket} ->
- {ok, #sslsocket{pid = {ListenSocket, Config}}};
- Err = {error, _} ->
- Err
- end
- catch
- Error = {error, _} ->
- Error
- end.
-%%--------------------------------------------------------------------
--spec transport_accept(#sslsocket{}) -> {ok, #sslsocket{}} |
- {error, reason()}.
--spec transport_accept(#sslsocket{}, timeout()) -> {ok, #sslsocket{}} |
- {error, reason()}.
-%%
-%% Description: Performs transport accept on an ssl listen socket
-%%--------------------------------------------------------------------
-transport_accept(ListenSocket) ->
- transport_accept(ListenSocket, infinity).
+listen(Port, Options) ->
+ tls:listen(Port, Options).
-transport_accept(#sslsocket{pid = {ListenSocket, #config{cb = CbInfo, ssl = SslOpts}}}, Timeout) ->
-
- %% The setopt could have been invoked on the listen socket
- %% and options should be inherited.
- EmOptions = emulated_options(),
- {Transport,_,_, _} = CbInfo,
- {ok, SocketValues} = ssl_socket:getopts(Transport, ListenSocket, EmOptions),
- ok = ssl_socket:setopts(Transport, ListenSocket, internal_inet_values()),
- case Transport:accept(ListenSocket, Timeout) of
- {ok, Socket} ->
- ok = ssl_socket:setopts(Transport, ListenSocket, SocketValues),
- {ok, Port} = ssl_socket:port(Transport, Socket),
- ConnArgs = [server, "localhost", Port, Socket,
- {SslOpts, socket_options(SocketValues)}, self(), CbInfo],
- case ssl_connection_sup:start_child(ConnArgs) of
- {ok, Pid} ->
- ssl_connection:socket_control(Socket, Pid, Transport);
- {error, Reason} ->
- {error, Reason}
- end;
- {error, Reason} ->
- {error, Reason}
- end.
+transport_accept(ListenSocket) ->
+ tls:transport_accept(ListenSocket).
-%%--------------------------------------------------------------------
--spec ssl_accept(#sslsocket{}) -> ok | {error, reason()}.
--spec ssl_accept(#sslsocket{} | port(), timeout()| [ssl_option()
- | transport_option()]) ->
- ok | {ok, #sslsocket{}} | {error, reason()}.
--spec ssl_accept(port(), [ssl_option()| transport_option()], timeout()) ->
- {ok, #sslsocket{}} | {error, reason()}.
-%%
-%% Description: Performs accept on an ssl listen socket. e.i. performs
-%% ssl handshake.
-%%--------------------------------------------------------------------
+transport_accept(ListenSocket, Timeout) ->
+ tls:transport_accept(ListenSocket, Timeout).
+
ssl_accept(ListenSocket) ->
- ssl_accept(ListenSocket, infinity).
+ tls:ssl_accept(ListenSocket, infinity).
ssl_accept(#sslsocket{} = Socket, Timeout) ->
- ssl_connection:handshake(Socket, Timeout);
+ tls:ssl_accept(Socket, Timeout);
ssl_accept(ListenSocket, SslOptions) when is_port(ListenSocket) ->
- ssl_accept(ListenSocket, SslOptions, infinity).
+ tls:ssl_accept(ListenSocket, SslOptions, infinity).
ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) ->
- {Transport,_,_,_} =
- proplists:get_value(cb_info, SslOptions, {gen_tcp, tcp, tcp_closed, tcp_error}),
- EmulatedOptions = emulated_options(),
- {ok, SocketValues} = ssl_socket:getopts(Transport, Socket, EmulatedOptions),
- try handle_options(SslOptions ++ SocketValues, server) of
- {ok, #config{cb = CbInfo, ssl = SslOpts, emulated = EmOpts}} ->
- ok = ssl_socket:setopts(Transport, Socket, internal_inet_values()),
- {ok, Port} = ssl_socket:port(Transport, Socket),
- ssl_connection:ssl_accept(Port, Socket,
- {SslOpts, EmOpts},
- self(), CbInfo, Timeout)
- catch
- Error = {error, _Reason} -> Error
- end.
+ tls:ssl_accept(Socket, SslOptions, Timeout).
-%%--------------------------------------------------------------------
--spec close(#sslsocket{}) -> term().
-%%
-%% Description: Close an ssl connection
-%%--------------------------------------------------------------------
-close(#sslsocket{pid = Pid}) when is_pid(Pid) ->
- ssl_connection:close(Pid);
-close(#sslsocket{pid = {ListenSocket, #config{cb={Transport,_, _, _}}}}) ->
- Transport:close(ListenSocket).
+close(Socket) ->
+ tls:close(Socket).
-%%--------------------------------------------------------------------
--spec send(#sslsocket{}, iodata()) -> ok | {error, reason()}.
-%%
-%% Description: Sends data over the ssl connection
-%%--------------------------------------------------------------------
-send(#sslsocket{pid = Pid}, Data) when is_pid(Pid) ->
- ssl_connection:send(Pid, Data);
-send(#sslsocket{pid = {ListenSocket, #config{cb={Transport, _, _, _}}}}, Data) ->
- Transport:send(ListenSocket, Data). %% {error,enotconn}
+send(Socket, Data) ->
+ tls:send(Socket, Data).
-%%--------------------------------------------------------------------
--spec recv(#sslsocket{}, integer()) -> {ok, binary()| list()} | {error, reason()}.
--spec recv(#sslsocket{}, integer(), timeout()) -> {ok, binary()| list()} | {error, reason()}.
-%%
-%% Description: Receives data when active = false
-%%--------------------------------------------------------------------
recv(Socket, Length) ->
- recv(Socket, Length, infinity).
-recv(#sslsocket{pid = Pid}, Length, Timeout) when is_pid(Pid) ->
- ssl_connection:recv(Pid, Length, Timeout);
-recv(#sslsocket{pid = {Listen,
- #config{cb={Transport, _, _, _}}}}, _,_) when is_port(Listen)->
- Transport:recv(Listen, 0). %% {error,enotconn}
-
-%%--------------------------------------------------------------------
--spec controlling_process(#sslsocket{}, pid()) -> ok | {error, reason()}.
-%%
-%% Description: Changes process that receives the messages when active = true
-%% or once.
-%%--------------------------------------------------------------------
-controlling_process(#sslsocket{pid = Pid}, NewOwner) when is_pid(Pid), is_pid(NewOwner) ->
- ssl_connection:new_user(Pid, NewOwner);
-controlling_process(#sslsocket{pid = {Listen,
- #config{cb={Transport, _, _, _}}}},
- NewOwner) when is_port(Listen),
- is_pid(NewOwner) ->
- Transport:controlling_process(Listen, NewOwner).
+ tls:recv(Socket, Length, infinity).
+recv(Socket, Length, Timeout) ->
+ tls:recv(Socket, Length, Timeout).
-%%--------------------------------------------------------------------
--spec connection_info(#sslsocket{}) -> {ok, {tls_atom_version(), erl_cipher_suite()}} |
- {error, reason()}.
-%%
-%% Description: Returns ssl protocol and cipher used for the connection
-%%--------------------------------------------------------------------
-connection_info(#sslsocket{pid = Pid}) when is_pid(Pid) ->
- ssl_connection:info(Pid);
-connection_info(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
- {error, enotconn}.
+controlling_process(Socket, NewOwner) ->
+ tls:controlling_process(Socket, NewOwner).
+
+connection_info(Socket) ->
+ tls:connection_info(Socket).
-%%--------------------------------------------------------------------
--spec peername(#sslsocket{}) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
-%%
-%% Description: same as inet:peername/1.
-%%--------------------------------------------------------------------
-peername(#sslsocket{pid = Pid, fd = {Transport, Socket}}) when is_pid(Pid)->
- ssl_socket:peername(Transport, Socket);
-peername(#sslsocket{pid = {ListenSocket, #config{cb = {Transport,_,_,_}}}}) ->
- ssl_socket:peername(Transport, ListenSocket). %% Will return {error, enotconn}
+peername(Socket) ->
+ tls:peername(Socket).
-%%--------------------------------------------------------------------
--spec peercert(#sslsocket{}) ->{ok, DerCert::binary()} | {error, reason()}.
-%%
-%% Description: Returns the peercert.
-%%--------------------------------------------------------------------
peercert(#sslsocket{pid = Pid}) when is_pid(Pid) ->
- case ssl_connection:peer_certificate(Pid) of
+ case tls_connection:peer_certificate(Pid) of
{ok, undefined} ->
{error, no_peercert};
Result ->
@@ -335,701 +152,71 @@ peercert(#sslsocket{pid = Pid}) when is_pid(Pid) ->
peercert(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
{error, enotconn}.
-%%--------------------------------------------------------------------
--spec suite_definition(cipher_suite()) -> erl_cipher_suite().
-%%
-%% Description: Return erlang cipher suite definition.
-%%--------------------------------------------------------------------
suite_definition(S) ->
{KeyExchange, Cipher, Hash, _} = ssl_cipher:suite_definition(S),
{KeyExchange, Cipher, Hash}.
-%%--------------------------------------------------------------------
--spec negotiated_next_protocol(#sslsocket{}) -> {ok, binary()} | {error, reason()}.
-%%
-%% Description: Returns the next protocol that has been negotiated. If no
-%% protocol has been negotiated will return {error, next_protocol_not_negotiated}
-%%--------------------------------------------------------------------
negotiated_next_protocol(#sslsocket{pid = Pid}) ->
- ssl_connection:negotiated_next_protocol(Pid).
+ tls_connection:negotiated_next_protocol(Pid).
+%%%--------------------------------------------------------------------
-spec cipher_suites() -> [erl_cipher_suite()].
-spec cipher_suites(erlang | openssl | all ) -> [erl_cipher_suite()] | [string()].
%% Description: Returns all supported cipher suites.
%%--------------------------------------------------------------------
+
cipher_suites() ->
cipher_suites(erlang).
cipher_suites(erlang) ->
- Version = ssl_record:highest_protocol_version([]),
- [suite_definition(S) || S <- cipher_suites(Version, [])];
+ Version = tls_record:highest_protocol_version([]),
+ [suite_definition(S) || S <- ssl_cipher:suites(Version)];
cipher_suites(openssl) ->
- Version = ssl_record:highest_protocol_version([]),
- [ssl_cipher:openssl_suite_name(S) || S <- cipher_suites(Version, [])];
+ Version = tls_record:highest_protocol_version([]),
+ [ssl_cipher:openssl_suite_name(S) || S <- ssl_cipher:suites(Version)];
cipher_suites(all) ->
- Version = ssl_record:highest_protocol_version([]),
+ Version = tls_record:highest_protocol_version([]),
Supported = ssl_cipher:suites(Version)
++ ssl_cipher:anonymous_suites()
++ ssl_cipher:psk_suites(Version)
++ ssl_cipher:srp_suites(),
[suite_definition(S) || S <- Supported].
-%%--------------------------------------------------------------------
--spec getopts(#sslsocket{}, [gen_tcp:option_name()]) ->
- {ok, [gen_tcp:option()]} | {error, reason()}.
-%%
-%% Description: Gets options
-%%--------------------------------------------------------------------
-getopts(#sslsocket{pid = Pid}, OptionTags) when is_pid(Pid), is_list(OptionTags) ->
- ssl_connection:get_opts(Pid, OptionTags);
-getopts(#sslsocket{pid = {ListenSocket, #config{cb = {Transport,_,_,_}}}},
- OptionTags) when is_list(OptionTags) ->
- try ssl_socket:getopts(Transport, ListenSocket, OptionTags) of
- {ok, _} = Result ->
- Result;
- {error, InetError} ->
- {error, {options, {socket_options, OptionTags, InetError}}}
- catch
- _:_ ->
- {error, {options, {socket_options, OptionTags}}}
- end;
-getopts(#sslsocket{}, OptionTags) ->
- {error, {options, {socket_options, OptionTags}}}.
-
-%%--------------------------------------------------------------------
--spec setopts(#sslsocket{}, [gen_tcp:option()]) -> ok | {error, reason()}.
-%%
-%% Description: Sets options
-%%--------------------------------------------------------------------
-setopts(#sslsocket{pid = Pid}, Options0) when is_pid(Pid), is_list(Options0) ->
- try proplists:expand([{binary, [{mode, binary}]},
- {list, [{mode, list}]}], Options0) of
- Options ->
- ssl_connection:set_opts(Pid, Options)
- catch
- _:_ ->
- {error, {options, {not_a_proplist, Options0}}}
- end;
-setopts(#sslsocket{pid = {ListenSocket, #config{cb = {Transport,_,_,_}}}}, Options) when is_list(Options) ->
- try ssl_socket:setopts(Transport, ListenSocket, Options) of
- ok ->
- ok;
- {error, InetError} ->
- {error, {options, {socket_options, Options, InetError}}}
- catch
- _:Error ->
- {error, {options, {socket_options, Options, Error}}}
- end;
-setopts(#sslsocket{}, Options) ->
- {error, {options,{not_a_proplist, Options}}}.
+getopts(Socket, OptionTags) ->
+ tls:getopts(Socket, OptionTags).
-%%---------------------------------------------------------------
--spec shutdown(#sslsocket{}, read | write | read_write) -> ok | {error, reason()}.
-%%
-%% Description: Same as gen_tcp:shutdown/2
-%%--------------------------------------------------------------------
-shutdown(#sslsocket{pid = {Listen, #config{cb={Transport,_, _, _}}}},
- How) when is_port(Listen) ->
- Transport:shutdown(Listen, How);
-shutdown(#sslsocket{pid = Pid}, How) ->
- ssl_connection:shutdown(Pid, How).
+setopts(Socket, Options) ->
+ tls:setopts(Socket, Options).
-%%--------------------------------------------------------------------
--spec sockname(#sslsocket{}) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
-%%
-%% Description: Same as inet:sockname/1
-%%--------------------------------------------------------------------
-sockname(#sslsocket{pid = {Listen, #config{cb={Transport,_, _, _}}}}) when is_port(Listen) ->
- ssl_socket:sockname(Transport, Listen);
+shutdown(Socket, How) ->
+ tls:shutdown(Socket, How).
-sockname(#sslsocket{pid = Pid, fd = {Transport, Socket}}) when is_pid(Pid) ->
- ssl_socket:sockname(Transport, Socket).
+sockname(Socket) ->
+ tls:sockname(Socket).
-%%---------------------------------------------------------------
--spec session_info(#sslsocket{}) -> {ok, list()} | {error, reason()}.
-%%
-%% Description: Returns list of session info currently [{session_id, session_id(),
-%% {cipher_suite, cipher_suite()}]
-%%--------------------------------------------------------------------
session_info(#sslsocket{pid = Pid}) when is_pid(Pid) ->
- ssl_connection:session_info(Pid);
+ tls_connection:session_info(Pid);
session_info(#sslsocket{pid = {Listen,_}}) when is_port(Listen) ->
{error, enotconn}.
-%%---------------------------------------------------------------
--spec versions() -> [{ssl_app, string()} | {supported, [tls_atom_version()]} |
- {available, [tls_atom_version()]}].
-%%
-%% Description: Returns a list of relevant versions.
-%%--------------------------------------------------------------------
versions() ->
- Vsns = ssl_record:supported_protocol_versions(),
- SupportedVsns = [ssl_record:protocol_version(Vsn) || Vsn <- Vsns],
- AvailableVsns = ?ALL_SUPPORTED_VERSIONS,
- [{ssl_app, ?VSN}, {supported, SupportedVsns}, {available, AvailableVsns}].
+ tls:versions().
+renegotiate(Socket) ->
+ tls:renegotiate(Socket).
-%%---------------------------------------------------------------
--spec renegotiate(#sslsocket{}) -> ok | {error, reason()}.
-%%
-%% Description: Initiates a renegotiation.
-%%--------------------------------------------------------------------
-renegotiate(#sslsocket{pid = Pid}) when is_pid(Pid) ->
- ssl_connection:renegotiation(Pid);
-renegotiate(#sslsocket{pid = {Listen,_}}) when is_port(Listen) ->
- {error, enotconn}.
+prf(Socket, Secret, Label, Seed, WantedLength) ->
+ tls:prf(Socket, Secret, Label, Seed, WantedLength).
-%%--------------------------------------------------------------------
--spec prf(#sslsocket{}, binary() | 'master_secret', binary(),
- binary() | prf_random(), non_neg_integer()) ->
- {ok, binary()} | {error, reason()}.
-%%
-%% Description: use a ssl sessions TLS PRF to generate key material
-%%--------------------------------------------------------------------
-prf(#sslsocket{pid = Pid},
- Secret, Label, Seed, WantedLength) when is_pid(Pid) ->
- ssl_connection:prf(Pid, Secret, Label, Seed, WantedLength);
-prf(#sslsocket{pid = {Listen,_}}, _,_,_,_) when is_port(Listen) ->
- {error, enotconn}.
-
-%%--------------------------------------------------------------------
--spec clear_pem_cache() -> ok.
-%%
-%% Description: Clear the PEM cache
-%%--------------------------------------------------------------------
clear_pem_cache() ->
- ssl_manager:clear_pem_cache().
-
-%%---------------------------------------------------------------
--spec format_error({error, term()}) -> list().
-%%
-%% Description: Creates error string.
-%%--------------------------------------------------------------------
-format_error({error, Reason}) ->
- format_error(Reason);
-format_error(Reason) when is_list(Reason) ->
- Reason;
-format_error(closed) ->
- "TLS connection is closed";
-format_error({tls_alert, Description}) ->
- "TLS Alert: " ++ Description;
-format_error({options,{FileType, File, Reason}}) when FileType == cacertfile;
- FileType == certfile;
- FileType == keyfile;
- FileType == dhfile ->
- Error = file_error_format(Reason),
- file_desc(FileType) ++ File ++ ": " ++ Error;
-format_error({options, {socket_options, Option, Error}}) ->
- lists:flatten(io_lib:format("Invalid transport socket option ~p: ~s", [Option, format_error(Error)]));
-format_error({options, {socket_options, Option}}) ->
- lists:flatten(io_lib:format("Invalid socket option: ~p", [Option]));
-format_error({options, Options}) ->
- lists:flatten(io_lib:format("Invalid TLS option: ~p", [Options]));
+ tls:clear_pem_cache().
-format_error(Error) ->
- case inet:format_error(Error) of
- "unknown POSIX" ++ _ ->
- unexpected_format(Error);
- Other ->
- Other
- end.
+format_error(Error) ->
+ tls:format_error(Error).
-%%--------------------------------------------------------------------
--spec random_bytes(integer()) -> binary().
-
-%%
-%% Description: Generates cryptographically secure random sequence if possible
-%% fallbacks on pseudo random function
-%%--------------------------------------------------------------------
random_bytes(N) ->
- try crypto:strong_rand_bytes(N) of
- RandBytes ->
- RandBytes
- catch
- error:low_entropy ->
- crypto:rand_bytes(N)
- end.
-
-%%%--------------------------------------------------------------
-%%% Internal functions
-%%%--------------------------------------------------------------------
-do_connect(Address, Port,
- #config{cb=CbInfo, inet_user=UserOpts, ssl=SslOpts,
- emulated=EmOpts,inet_ssl=SocketOpts},
- Timeout) ->
- {Transport, _, _, _} = CbInfo,
- try Transport:connect(Address, Port, SocketOpts, Timeout) of
- {ok, Socket} ->
- ssl_connection:connect(Address, Port, Socket, {SslOpts,EmOpts},
- self(), CbInfo, Timeout);
- {error, Reason} ->
- {error, Reason}
- catch
- exit:{function_clause, _} ->
- {error, {options, {cb_info, CbInfo}}};
- exit:badarg ->
- {error, {options, {socket_options, UserOpts}}};
- exit:{badarg, _} ->
- {error, {options, {socket_options, UserOpts}}}
- end.
-
-handle_options(Opts0, _Role) ->
- Opts = proplists:expand([{binary, [{mode, binary}]},
- {list, [{mode, list}]}], Opts0),
- ReuseSessionFun = fun(_, _, _, _) -> true end,
-
- DefaultVerifyNoneFun =
- {fun(_,{bad_cert, _}, UserState) ->
- {valid, UserState};
- (_,{extension, _}, UserState) ->
- {unknown, UserState};
- (_, valid, UserState) ->
- {valid, UserState};
- (_, valid_peer, UserState) ->
- {valid, UserState}
- end, []},
-
- VerifyNoneFun = handle_option(verify_fun, Opts, DefaultVerifyNoneFun),
-
- UserFailIfNoPeerCert = handle_option(fail_if_no_peer_cert, Opts, false),
- UserVerifyFun = handle_option(verify_fun, Opts, undefined),
- CaCerts = handle_option(cacerts, Opts, undefined),
-
- {Verify, FailIfNoPeerCert, CaCertDefault, VerifyFun} =
- %% Handle 0, 1, 2 for backwards compatibility
- case proplists:get_value(verify, Opts, verify_none) of
- 0 ->
- {verify_none, false,
- ca_cert_default(verify_none, VerifyNoneFun, CaCerts), VerifyNoneFun};
- 1 ->
- {verify_peer, false,
- ca_cert_default(verify_peer, UserVerifyFun, CaCerts), UserVerifyFun};
- 2 ->
- {verify_peer, true,
- ca_cert_default(verify_peer, UserVerifyFun, CaCerts), UserVerifyFun};
- verify_none ->
- {verify_none, false,
- ca_cert_default(verify_none, VerifyNoneFun, CaCerts), VerifyNoneFun};
- verify_peer ->
- {verify_peer, UserFailIfNoPeerCert,
- ca_cert_default(verify_peer, UserVerifyFun, CaCerts), UserVerifyFun};
- Value ->
- throw({error, {options, {verify, Value}}})
- end,
-
- CertFile = handle_option(certfile, Opts, <<>>),
-
- Versions = case handle_option(versions, Opts, []) of
- [] ->
- ssl_record:supported_protocol_versions();
- Vsns ->
- [ssl_record:protocol_version(Vsn) || Vsn <- Vsns]
- end,
-
- SSLOptions = #ssl_options{
- versions = Versions,
- verify = validate_option(verify, Verify),
- verify_fun = VerifyFun,
- fail_if_no_peer_cert = FailIfNoPeerCert,
- verify_client_once = handle_option(verify_client_once, Opts, false),
- depth = handle_option(depth, Opts, 1),
- cert = handle_option(cert, Opts, undefined),
- certfile = CertFile,
- key = handle_option(key, Opts, undefined),
- keyfile = handle_option(keyfile, Opts, CertFile),
- password = handle_option(password, Opts, ""),
- cacerts = CaCerts,
- cacertfile = handle_option(cacertfile, Opts, CaCertDefault),
- dh = handle_option(dh, Opts, undefined),
- dhfile = handle_option(dhfile, Opts, undefined),
- user_lookup_fun = handle_option(user_lookup_fun, Opts, undefined),
- psk_identity = handle_option(psk_identity, Opts, undefined),
- srp_identity = handle_option(srp_identity, Opts, undefined),
- ciphers = handle_option(ciphers, Opts, []),
- %% Server side option
- reuse_session = handle_option(reuse_session, Opts, ReuseSessionFun),
- reuse_sessions = handle_option(reuse_sessions, Opts, true),
- secure_renegotiate = handle_option(secure_renegotiate, Opts, false),
- renegotiate_at = handle_option(renegotiate_at, Opts, ?DEFAULT_RENEGOTIATE_AT),
- hibernate_after = handle_option(hibernate_after, Opts, undefined),
- erl_dist = handle_option(erl_dist, Opts, false),
- next_protocols_advertised =
- handle_option(next_protocols_advertised, Opts, undefined),
- next_protocol_selector =
- make_next_protocol_selector(
- handle_option(client_preferred_next_protocols, Opts, undefined))
- },
-
- CbInfo = proplists:get_value(cb_info, Opts, {gen_tcp, tcp, tcp_closed, tcp_error}),
- SslOptions = [versions, verify, verify_fun,
- fail_if_no_peer_cert, verify_client_once,
- depth, cert, certfile, key, keyfile,
- password, cacerts, cacertfile, dh, dhfile,
- user_lookup_fun, psk_identity, srp_identity, ciphers,
- reuse_session, reuse_sessions, ssl_imp,
- cb_info, renegotiate_at, secure_renegotiate, hibernate_after,
- erl_dist, next_protocols_advertised,
- client_preferred_next_protocols],
-
- SockOpts = lists:foldl(fun(Key, PropList) ->
- proplists:delete(Key, PropList)
- end, Opts, SslOptions),
-
- {SSLsock, Emulated} = emulated_options(SockOpts),
- {ok, #config{ssl=SSLOptions, emulated=Emulated, inet_ssl=SSLsock,
- inet_user=SockOpts, cb=CbInfo}}.
-
-handle_option(OptionName, Opts, Default) ->
- validate_option(OptionName,
- proplists:get_value(OptionName, Opts, Default)).
-
-
-validate_option(versions, Versions) ->
- validate_versions(Versions, Versions);
-validate_option(verify, Value)
- when Value == verify_none; Value == verify_peer ->
- Value;
-validate_option(verify_fun, undefined) ->
- undefined;
-%% Backwards compatibility
-validate_option(verify_fun, Fun) when is_function(Fun) ->
- {fun(_,{bad_cert, _} = Reason, OldFun) ->
- case OldFun([Reason]) of
- true ->
- {valid, OldFun};
- false ->
- {fail, Reason}
- end;
- (_,{extension, _}, UserState) ->
- {unknown, UserState};
- (_, valid, UserState) ->
- {valid, UserState};
- (_, valid_peer, UserState) ->
- {valid, UserState}
- end, Fun};
-validate_option(verify_fun, {Fun, _} = Value) when is_function(Fun) ->
- Value;
-validate_option(fail_if_no_peer_cert, Value)
- when Value == true; Value == false ->
- Value;
-validate_option(verify_client_once, Value)
- when Value == true; Value == false ->
- Value;
-validate_option(depth, Value) when is_integer(Value),
- Value >= 0, Value =< 255->
- Value;
-validate_option(cert, Value) when Value == undefined;
- is_binary(Value) ->
- Value;
-validate_option(certfile, undefined = Value) ->
- Value;
-validate_option(certfile, Value) when is_binary(Value) ->
- Value;
-validate_option(certfile, Value) when is_list(Value) ->
- list_to_binary(Value);
-
-validate_option(key, undefined) ->
- undefined;
-validate_option(key, {KeyType, Value}) when is_binary(Value),
- KeyType == rsa; %% Backwards compatibility
- KeyType == dsa; %% Backwards compatibility
- KeyType == 'RSAPrivateKey';
- KeyType == 'DSAPrivateKey';
- KeyType == 'ECPrivateKey';
- KeyType == 'PrivateKeyInfo' ->
- {KeyType, Value};
-
-validate_option(keyfile, undefined) ->
- <<>>;
-validate_option(keyfile, Value) when is_binary(Value) ->
- Value;
-validate_option(keyfile, Value) when is_list(Value), Value =/= "" ->
- list_to_binary(Value);
-validate_option(password, Value) when is_list(Value) ->
- Value;
-
-validate_option(cacerts, Value) when Value == undefined;
- is_list(Value) ->
- Value;
-%% certfile must be present in some cases otherwhise it can be set
-%% to the empty string.
-validate_option(cacertfile, undefined) ->
- <<>>;
-validate_option(cacertfile, Value) when is_binary(Value) ->
- Value;
-validate_option(cacertfile, Value) when is_list(Value), Value =/= ""->
- list_to_binary(Value);
-validate_option(dh, Value) when Value == undefined;
- is_binary(Value) ->
- Value;
-validate_option(dhfile, undefined = Value) ->
- Value;
-validate_option(dhfile, Value) when is_binary(Value) ->
- Value;
-validate_option(dhfile, Value) when is_list(Value), Value =/= "" ->
- list_to_binary(Value);
-validate_option(psk_identity, undefined) ->
- undefined;
-validate_option(psk_identity, Identity)
- when is_list(Identity), Identity =/= "", length(Identity) =< 65535 ->
- list_to_binary(Identity);
-validate_option(user_lookup_fun, undefined) ->
- undefined;
-validate_option(user_lookup_fun, {Fun, _} = Value) when is_function(Fun, 3) ->
- Value;
-validate_option(srp_identity, undefined) ->
- undefined;
-validate_option(srp_identity, {Username, Password})
- when is_list(Username), is_list(Password), Username =/= "", length(Username) =< 255 ->
- {list_to_binary(Username), list_to_binary(Password)};
-validate_option(ciphers, Value) when is_list(Value) ->
- Version = ssl_record:highest_protocol_version([]),
- try cipher_suites(Version, Value)
- catch
- exit:_ ->
- throw({error, {options, {ciphers, Value}}});
- error:_->
- throw({error, {options, {ciphers, Value}}})
- end;
-validate_option(reuse_session, Value) when is_function(Value) ->
- Value;
-validate_option(reuse_sessions, Value) when Value == true;
- Value == false ->
- Value;
-
-validate_option(secure_renegotiate, Value) when Value == true;
- Value == false ->
- Value;
-validate_option(renegotiate_at, Value) when is_integer(Value) ->
- erlang:min(Value, ?DEFAULT_RENEGOTIATE_AT);
-
-validate_option(hibernate_after, undefined) ->
- undefined;
-validate_option(hibernate_after, Value) when is_integer(Value), Value >= 0 ->
- Value;
-validate_option(erl_dist,Value) when Value == true;
- Value == false ->
- Value;
-validate_option(client_preferred_next_protocols = Opt, {Precedence, PreferredProtocols} = Value)
- when is_list(PreferredProtocols) ->
- case ssl_record:highest_protocol_version([]) of
- {3,0} ->
- throw({error, {options, {not_supported_in_sslv3, {Opt, Value}}}});
- _ ->
- validate_binary_list(client_preferred_next_protocols, PreferredProtocols),
- validate_npn_ordering(Precedence),
- {Precedence, PreferredProtocols, ?NO_PROTOCOL}
- end;
-validate_option(client_preferred_next_protocols = Opt, {Precedence, PreferredProtocols, Default} = Value)
- when is_list(PreferredProtocols), is_binary(Default),
- byte_size(Default) > 0, byte_size(Default) < 256 ->
- case ssl_record:highest_protocol_version([]) of
- {3,0} ->
- throw({error, {options, {not_supported_in_sslv3, {Opt, Value}}}});
- _ ->
- validate_binary_list(client_preferred_next_protocols, PreferredProtocols),
- validate_npn_ordering(Precedence),
- Value
- end;
-
-validate_option(client_preferred_next_protocols, undefined) ->
- undefined;
-validate_option(next_protocols_advertised = Opt, Value) when is_list(Value) ->
- case ssl_record:highest_protocol_version([]) of
- {3,0} ->
- throw({error, {options, {not_supported_in_sslv3, {Opt, Value}}}});
- _ ->
- validate_binary_list(next_protocols_advertised, Value),
- Value
- end;
-
-validate_option(next_protocols_advertised, undefined) ->
- undefined;
-validate_option(Opt, Value) ->
- throw({error, {options, {Opt, Value}}}).
-
-validate_npn_ordering(client) ->
- ok;
-validate_npn_ordering(server) ->
- ok;
-validate_npn_ordering(Value) ->
- throw({error, {options, {client_preferred_next_protocols, {invalid_precedence, Value}}}}).
-
-validate_binary_list(Opt, List) ->
- lists:foreach(
- fun(Bin) when is_binary(Bin),
- byte_size(Bin) > 0,
- byte_size(Bin) < 256 ->
- ok;
- (Bin) ->
- throw({error, {options, {Opt, {invalid_protocol, Bin}}}})
- end, List).
-
-validate_versions([], Versions) ->
- Versions;
-validate_versions([Version | Rest], Versions) when Version == 'tlsv1.2';
- Version == 'tlsv1.1';
- Version == tlsv1;
- Version == sslv3 ->
- validate_versions(Rest, Versions);
-validate_versions([Ver| _], Versions) ->
- throw({error, {options, {Ver, {versions, Versions}}}}).
-
-validate_inet_option(mode, Value)
- when Value =/= list, Value =/= binary ->
- throw({error, {options, {mode,Value}}});
-validate_inet_option(packet, Value)
- when not (is_atom(Value) orelse is_integer(Value)) ->
- throw({error, {options, {packet,Value}}});
-validate_inet_option(packet_size, Value)
- when not is_integer(Value) ->
- throw({error, {options, {packet_size,Value}}});
-validate_inet_option(header, Value)
- when not is_integer(Value) ->
- throw({error, {options, {header,Value}}});
-validate_inet_option(active, Value)
- when Value =/= true, Value =/= false, Value =/= once ->
- throw({error, {options, {active,Value}}});
-validate_inet_option(_, _) ->
- ok.
-
-%% The option cacerts overrides cacertsfile
-ca_cert_default(_,_, [_|_]) ->
- undefined;
-ca_cert_default(verify_none, _, _) ->
- undefined;
-ca_cert_default(verify_peer, {Fun,_}, _) when is_function(Fun) ->
- undefined;
-%% Server that wants to verify_peer and has no verify_fun must have
-%% some trusted certs.
-ca_cert_default(verify_peer, undefined, _) ->
- "".
-
-emulated_options() ->
- [mode, packet, active, header, packet_size].
-
-internal_inet_values() ->
- [{packet_size,0},{packet, 0},{header, 0},{active, false},{mode,binary}].
-
-socket_options(InetValues) ->
- #socket_options{
- mode = proplists:get_value(mode, InetValues, lists),
- header = proplists:get_value(header, InetValues, 0),
- active = proplists:get_value(active, InetValues, active),
- packet = proplists:get_value(packet, InetValues, 0),
- packet_size = proplists:get_value(packet_size, InetValues)
- }.
-
-emulated_options(Opts) ->
- emulated_options(Opts, internal_inet_values(), #socket_options{}).
-
-emulated_options([{mode,Opt}|Opts], Inet, Emulated) ->
- validate_inet_option(mode,Opt),
- emulated_options(Opts, Inet, Emulated#socket_options{mode=Opt});
-emulated_options([{header,Opt}|Opts], Inet, Emulated) ->
- validate_inet_option(header,Opt),
- emulated_options(Opts, Inet, Emulated#socket_options{header=Opt});
-emulated_options([{active,Opt}|Opts], Inet, Emulated) ->
- validate_inet_option(active,Opt),
- emulated_options(Opts, Inet, Emulated#socket_options{active=Opt});
-emulated_options([{packet,Opt}|Opts], Inet, Emulated) ->
- validate_inet_option(packet,Opt),
- emulated_options(Opts, Inet, Emulated#socket_options{packet=Opt});
-emulated_options([{packet_size,Opt}|Opts], Inet, Emulated) ->
- validate_inet_option(packet_size,Opt),
- emulated_options(Opts, Inet, Emulated#socket_options{packet_size=Opt});
-emulated_options([Opt|Opts], Inet, Emulated) ->
- emulated_options(Opts, [Opt|Inet], Emulated);
-emulated_options([], Inet,Emulated) ->
- {Inet, Emulated}.
-
-cipher_suites(Version, []) ->
- ssl_cipher:filter_suites(ssl_cipher:suites(Version));
-cipher_suites(Version, [{_,_,_,_}| _] = Ciphers0) -> %% Backwards compatibility
- Ciphers = [{KeyExchange, Cipher, Hash} || {KeyExchange, Cipher, Hash, _} <- Ciphers0],
- ssl_cipher:filter_suites(cipher_suites(Version, Ciphers));
-cipher_suites(Version, [{_,_,_}| _] = Ciphers0) ->
- Ciphers = [ssl_cipher:suite(C) || C <- Ciphers0],
- ssl_cipher:filter_suites(cipher_suites(Version, Ciphers));
-cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) ->
- Supported0 = ssl_cipher:suites(Version)
- ++ ssl_cipher:anonymous_suites()
- ++ ssl_cipher:psk_suites(Version)
- ++ ssl_cipher:srp_suites(),
- Supported1 = ssl_cipher:filter_suites(Supported0),
- case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported1)] of
- [] ->
- Supported1;
- Ciphers ->
- Ciphers
- end;
-cipher_suites(Version, [Head | _] = Ciphers0) when is_list(Head) ->
- %% Format: ["RC4-SHA","RC4-MD5"]
- Ciphers = [ssl_cipher:openssl_suite(C) || C <- Ciphers0],
- cipher_suites(Version, Ciphers);
-cipher_suites(Version, Ciphers0) ->
- %% Format: "RC4-SHA:RC4-MD5"
- Ciphers = [ssl_cipher:openssl_suite(C) || C <- string:tokens(Ciphers0, ":")],
- cipher_suites(Version, Ciphers).
-
-unexpected_format(Error) ->
- lists:flatten(io_lib:format("Unexpected error: ~p", [Error])).
-
-file_error_format({error, Error})->
- case file:format_error(Error) of
- "unknown POSIX error" ->
- "decoding error";
- Str ->
- Str
- end;
-file_error_format(_) ->
- "decoding error".
-
-file_desc(cacertfile) ->
- "Invalid CA certificate file ";
-file_desc(certfile) ->
- "Invalid certificate file ";
-file_desc(keyfile) ->
- "Invalid key file ";
-file_desc(dhfile) ->
- "Invalid DH params file ".
-
-detect(_Pred, []) ->
- undefined;
-detect(Pred, [H|T]) ->
- case Pred(H) of
- true ->
- H;
- _ ->
- detect(Pred, T)
- end.
-
-make_next_protocol_selector(undefined) ->
- undefined;
-make_next_protocol_selector({client, AllProtocols, DefaultProtocol}) ->
- fun(AdvertisedProtocols) ->
- case detect(fun(PreferredProtocol) ->
- lists:member(PreferredProtocol, AdvertisedProtocols)
- end, AllProtocols) of
- undefined ->
- DefaultProtocol;
- PreferredProtocol ->
- PreferredProtocol
- end
- end;
+ tls:random_bytes(N).
-make_next_protocol_selector({server, AllProtocols, DefaultProtocol}) ->
- fun(AdvertisedProtocols) ->
- case detect(fun(PreferredProtocol) ->
- lists:member(PreferredProtocol, AllProtocols)
- end,
- AdvertisedProtocols) of
- undefined ->
- DefaultProtocol;
- PreferredProtocol ->
- PreferredProtocol
- end
- end.
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index 9e1c3a09bf..b186a1015a 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -240,7 +240,7 @@ find_issuer(OtpCert, CertDbHandle) ->
Acc
end,
- try ssl_certificate_db:foldl(IsIssuerFun, issuer_not_found, CertDbHandle) of
+ try ssl_pkix_db:foldl(IsIssuerFun, issuer_not_found, CertDbHandle) of
issuer_not_found ->
{error, issuer_not_found}
catch
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 898b421dff..ec5d793d65 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -1190,14 +1190,16 @@ hash_size(md5) ->
16;
hash_size(sha) ->
20;
-hash_size(sha224) ->
- 28;
+%% Uncomment when adding cipher suite that needs it
+%% hash_size(sha224) ->
+%% 28;
hash_size(sha256) ->
32;
hash_size(sha384) ->
- 48;
-hash_size(sha512) ->
- 64.
+ 48.
+%% Uncomment when adding cipher suite that needs it
+%% hash_size(sha512) ->
+%% 64.
%% RFC 5246: 6.2.3.2. CBC Block Cipher
%%
diff --git a/lib/ssl/src/ssl_connection_sup.erl b/lib/ssl/src/ssl_connection_sup.erl
index 78cfda5e63..fb1c6e11a6 100644
--- a/lib/ssl/src/ssl_connection_sup.erl
+++ b/lib/ssl/src/ssl_connection_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2007-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
@@ -56,10 +56,10 @@ init(_O) ->
MaxT = 3600,
Name = undefined, % As simple_one_for_one is used.
- StartFunc = {ssl_connection, start_link, []},
+ StartFunc = {tls_connection, start_link, []},
Restart = temporary, % E.g. should not be restarted
Shutdown = 4000,
- Modules = [ssl_connection],
+ Modules = [tls_connection],
Type = worker,
ChildSpec = {Name, StartFunc, Restart, Shutdown, Type, Modules},
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index b2387a0ee7..eb1a1dbf62 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -20,7 +20,7 @@
%%
%%----------------------------------------------------------------------
%% Purpose: Record and constant defenitions for the SSL-handshake protocol
-%% see RFC 4346
+%% see RFC 5246. Also includes supported hello extensions.
%%----------------------------------------------------------------------
-ifndef(ssl_handshake).
@@ -91,21 +91,10 @@
% -define(NULL, 0). %% Already defined by ssl_internal.hrl
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%% Hello messages - RFC 4346 section 7.4.2
+%%% Hello messages - RFC 5246 section 7.4.1
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--record(client_hello, {
- client_version,
- random,
- session_id, % opaque SessionID<0..32>
- cipher_suites, % cipher_suites<2..2^16-1>
- compression_methods, % compression_methods<1..2^8-1>,
- renegotiation_info,
- srp, % srp username to send
- hash_signs, % supported combinations of hashes/signature algos
- ec_point_formats, % supported ec point formats
- elliptic_curves, % supported elliptic curver
- next_protocol_negotiation = undefined % [binary()]
- }).
+
+%% client_hello defined in tls_handshake.hrl and dtls_handshake.hrl
-record(server_hello, {
server_version,
@@ -121,7 +110,7 @@
}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%% Server authentication and key exchange messages - RFC 4346 section 7.4.3
+%%% Server authentication and key exchange messages - RFC 5246 section 7.4.3
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% opaque ASN.1Cert<2^24-1>;
@@ -193,7 +182,7 @@
-record(server_hello_done, {}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%% Certificate request - RFC 4346 section 7.4.4
+%%% Certificate request - RFC 5246 section 7.4.4
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% enum {
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index caea528a08..7af4a68461 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -104,7 +104,7 @@ connection_init(Trustedcerts, Role) ->
%%--------------------------------------------------------------------
cache_pem_file(File, DbHandle) ->
MD5 = crypto:hash(md5, File),
- case ssl_certificate_db:lookup_cached_pem(DbHandle, MD5) of
+ case ssl_pkix_db:lookup_cached_pem(DbHandle, MD5) of
[{Content,_}] ->
{ok, Content};
[Content] ->
@@ -132,7 +132,7 @@ clear_pem_cache() ->
%% serialnumber(), issuer()}.
%% --------------------------------------------------------------------
lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer) ->
- ssl_certificate_db:lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer).
+ ssl_pkix_db:lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer).
%%--------------------------------------------------------------------
-spec new_session_id(integer()) -> session_id().
@@ -194,7 +194,7 @@ init([Name, Opts]) ->
CacheCb = proplists:get_value(session_cb, Opts, ssl_session_cache),
SessionLifeTime =
proplists:get_value(session_lifetime, Opts, ?'24H_in_sec'),
- CertDb = ssl_certificate_db:create(),
+ CertDb = ssl_pkix_db:create(),
SessionCache = CacheCb:init(proplists:get_value(session_cb_init_args, Opts, [])),
Timer = erlang:send_after(SessionLifeTime * 1000 + 5000,
self(), validate_sessions),
@@ -227,7 +227,7 @@ handle_call({{connection_init, Trustedcerts, _Role}, Pid}, _From,
session_cache = Cache} = State) ->
Result =
try
- {ok, Ref} = ssl_certificate_db:add_trusted_certs(Pid, Trustedcerts, Db),
+ {ok, Ref} = ssl_pkix_db:add_trusted_certs(Pid, Trustedcerts, Db),
{ok, Ref, CertDb, FileRefDb, PemChace, Cache}
catch
_:Reason ->
@@ -244,7 +244,7 @@ handle_call({{new_session_id,Port}, _},
handle_call({{cache_pem, File}, _Pid}, _,
#state{certificate_db = Db} = State) ->
- try ssl_certificate_db:cache_pem_file(File, Db) of
+ try ssl_pkix_db:cache_pem_file(File, Db) of
Result ->
{reply, Result, State}
catch
@@ -252,7 +252,7 @@ handle_call({{cache_pem, File}, _Pid}, _,
{reply, {error, Reason}, State}
end;
handle_call({unconditionally_clear_pem_cache, _},_, #state{certificate_db = [_,_,PemChace]} = State) ->
- ssl_certificate_db:clear(PemChace),
+ ssl_pkix_db:clear(PemChace),
{reply, ok, State}.
%%--------------------------------------------------------------------
@@ -315,11 +315,11 @@ handle_info({delayed_clean_session, Key}, #state{session_cache = Cache,
{noreply, State};
handle_info(clear_pem_cache, #state{certificate_db = [_,_,PemChace]} = State) ->
- case ssl_certificate_db:db_size(PemChace) of
+ case ssl_pkix_db:db_size(PemChace) of
N when N < ?NOT_TO_BIG ->
ok;
_ ->
- ssl_certificate_db:clear(PemChace)
+ ssl_pkix_db:clear(PemChace)
end,
erlang:send_after(?CLEAR_PEM_CACHE, self(), clear_pem_cache),
{noreply, State};
@@ -328,7 +328,7 @@ handle_info(clear_pem_cache, #state{certificate_db = [_,_,PemChace]} = State) ->
handle_info({clean_cert_db, Ref, File},
#state{certificate_db = [CertDb,RefDb, PemCache]} = State) ->
- case ssl_certificate_db:lookup(Ref, RefDb) of
+ case ssl_pkix_db:lookup(Ref, RefDb) of
undefined -> %% Alredy cleaned
ok;
_ ->
@@ -357,7 +357,7 @@ terminate(_Reason, #state{certificate_db = Db,
session_cache_cb = CacheCb,
session_validation_timer = Timer}) ->
erlang:cancel_timer(Timer),
- ssl_certificate_db:remove(Db),
+ ssl_pkix_db:remove(Db),
CacheCb:terminate(SessionCache),
ok.
@@ -466,17 +466,17 @@ new_id(Port, Tries, Cache, CacheCb) ->
end.
clean_cert_db(Ref, CertDb, RefDb, PemCache, File) ->
- case ssl_certificate_db:ref_count(Ref, RefDb, 0) of
+ case ssl_pkix_db:ref_count(Ref, RefDb, 0) of
0 ->
MD5 = crypto:hash(md5, File),
- case ssl_certificate_db:lookup_cached_pem(PemCache, MD5) of
+ case ssl_pkix_db:lookup_cached_pem(PemCache, MD5) of
[{Content, Ref}] ->
- ssl_certificate_db:insert(MD5, Content, PemCache);
+ ssl_pkix_db:insert(MD5, Content, PemCache);
_ ->
ok
end,
- ssl_certificate_db:remove(Ref, RefDb),
- ssl_certificate_db:remove_trusted_certs(Ref, CertDb);
+ ssl_pkix_db:remove(Ref, RefDb),
+ ssl_pkix_db:remove_trusted_certs(Ref, CertDb);
_ ->
ok
end.
diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_pkix_db.erl
index cdff73336e..9de50c8f26 100644
--- a/lib/ssl/src/ssl_certificate_db.erl
+++ b/lib/ssl/src/ssl_pkix_db.erl
@@ -21,7 +21,7 @@
%% Purpose: Storage for trusted certificates
%%----------------------------------------------------------------------
--module(ssl_certificate_db).
+-module(ssl_pkix_db).
-include("ssl_internal.hrl").
-include_lib("public_key/include/public_key.hrl").
diff --git a/lib/ssl/src/ssl_record.hrl b/lib/ssl/src/ssl_record.hrl
index f73da92a52..2fd17f9c35 100644
--- a/lib/ssl/src/ssl_record.hrl
+++ b/lib/ssl/src/ssl_record.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-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
@@ -143,34 +143,6 @@
-define(LOWEST_MAJOR_SUPPORTED_VERSION, 3).
--record(ssl_tls, { %% From inet driver
- port,
- type,
- version,
- fragment
- }).
-
-%% -record(tls_plain_text, {
-%% type,
-%% version, % #protocol_version{}
-%% length, % unit 16
-%% fragment % opaque
-%% }).
-
-%% -record(tls_compressed, {
-%% type,
-%% version,
-%% length, % unit 16
-%% fragment % opaque
-%% }).
-
-%% -record(tls_cipher_text, {
-%% type,
-%% version,
-%% length,
-%% cipher,
-%% fragment
-%% }).
-record(generic_stream_cipher, {
content, % opaque content[TLSCompressed.length];
diff --git a/lib/ssl/src/tls.erl b/lib/ssl/src/tls.erl
new file mode 100644
index 0000000000..bb02695c12
--- /dev/null
+++ b/lib/ssl/src/tls.erl
@@ -0,0 +1,1039 @@
+%%
+%% %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%
+%%
+
+%%
+
+%%% Purpose : Main API module for SSL.
+
+-module(tls).
+
+-export([start/0, start/1, stop/0, transport_accept/1,
+ transport_accept/2, ssl_accept/1, ssl_accept/2, ssl_accept/3,
+ cipher_suites/0, cipher_suites/1, suite_definition/1,
+ close/1, shutdown/2,
+ connect/3, connect/2, connect/4, connection_info/1,
+ controlling_process/2, listen/2, peername/1, peercert/1,
+ recv/2, recv/3, send/2, getopts/2, setopts/2, sockname/1,
+ versions/0, session_info/1, format_error/1,
+ renegotiate/1, prf/5, clear_pem_cache/0, random_bytes/1, negotiated_next_protocol/1]).
+
+-include("ssl_internal.hrl").
+-include("ssl_record.hrl").
+-include("ssl_cipher.hrl").
+-include("ssl_handshake.hrl").
+-include("ssl_srp.hrl").
+
+-include_lib("public_key/include/public_key.hrl").
+
+%% Visible in API
+-export_type([connect_option/0, listen_option/0, ssl_option/0, transport_option/0,
+ erl_cipher_suite/0, %% From ssl_cipher.hrl
+ tls_atom_version/0, %% From ssl_internal.hrl
+ prf_random/0, sslsocket/0]).
+
+-record(config, {ssl, %% SSL parameters
+ inet_user, %% User set inet options
+ emulated, %% #socket_option{} emulated
+ inet_ssl, %% inet options for internal ssl socket
+ cb %% Callback info
+ }).
+
+-type sslsocket() :: #sslsocket{}.
+-type connect_option() :: socket_connect_option() | ssl_option() | transport_option().
+-type socket_connect_option() :: gen_tcp:connect_option().
+-type listen_option() :: socket_listen_option() | ssl_option() | transport_option().
+-type socket_listen_option() :: gen_tcp:listen_option().
+
+-type ssl_option() :: {verify, verify_type()} |
+ {verify_fun, {fun(), InitialUserState::term()}} |
+ {fail_if_no_peer_cert, boolean()} | {depth, integer()} |
+ {cert, Der::binary()} | {certfile, path()} | {key, Der::binary()} |
+ {keyfile, path()} | {password, string()} | {cacerts, [Der::binary()]} |
+ {cacertfile, path()} | {dh, Der::binary()} | {dhfile, path()} |
+ {user_lookup_fun, {fun(), InitialUserState::term()}} |
+ {psk_identity, string()} |
+ {srp_identity, {string(), string()}} |
+ {ciphers, ciphers()} | {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} |
+ {reuse_session, fun()} | {hibernate_after, integer()|undefined} |
+ {next_protocols_advertised, list(binary())} |
+ {client_preferred_next_protocols, binary(), client | server, list(binary())}.
+
+-type verify_type() :: verify_none | verify_peer.
+-type path() :: string().
+-type ciphers() :: [erl_cipher_suite()] |
+ string(). % (according to old API)
+-type ssl_imp() :: new | old.
+
+-type transport_option() :: {cb_info, {CallbackModule::atom(), DataTag::atom(),
+ ClosedTag::atom(), ErrTag::atom()}}.
+-type prf_random() :: client_random | server_random.
+
+%%--------------------------------------------------------------------
+-spec start() -> ok | {error, reason()}.
+-spec start(permanent | transient | temporary) -> ok | {error, reason()}.
+%%
+%% Description: Utility function that starts the ssl,
+%% crypto and public_key applications. Default type
+%% is temporary. see application(3)
+%%--------------------------------------------------------------------
+start() ->
+ application:start(crypto),
+ application:start(asn1),
+ application:start(public_key),
+ application:start(ssl).
+
+start(Type) ->
+ application:start(crypto, Type),
+ application:start(asn1),
+ application:start(public_key, Type),
+ application:start(ssl, Type).
+
+%%--------------------------------------------------------------------
+-spec stop() -> ok.
+%%
+%% Description: Stops the ssl application.
+%%--------------------------------------------------------------------
+stop() ->
+ application:stop(ssl).
+
+%%--------------------------------------------------------------------
+-spec connect(host() | port(), [connect_option()]) -> {ok, #sslsocket{}} |
+ {error, reason()}.
+-spec connect(host() | port(), [connect_option()] | inet:port_number(),
+ timeout() | list()) ->
+ {ok, #sslsocket{}} | {error, reason()}.
+-spec connect(host() | port(), inet:port_number(), list(), timeout()) ->
+ {ok, #sslsocket{}} | {error, reason()}.
+
+%%
+%% Description: Connect to an ssl server.
+%%--------------------------------------------------------------------
+connect(Socket, SslOptions) when is_port(Socket) ->
+ connect(Socket, SslOptions, infinity).
+
+connect(Socket, SslOptions0, Timeout) when is_port(Socket) ->
+ {Transport,_,_,_} = proplists:get_value(cb_info, SslOptions0,
+ {gen_tcp, tcp, tcp_closed, tcp_error}),
+ EmulatedOptions = emulated_options(),
+ {ok, SocketValues} = ssl_socket:getopts(Transport, Socket, EmulatedOptions),
+ try handle_options(SslOptions0 ++ SocketValues, client) of
+ {ok, #config{cb = CbInfo, ssl = SslOptions, emulated = EmOpts}} ->
+
+ ok = ssl_socket:setopts(Transport, Socket, internal_inet_values()),
+ case ssl_socket:peername(Transport, Socket) of
+ {ok, {Address, Port}} ->
+ tls_connection:connect(Address, Port, Socket,
+ {SslOptions, EmOpts},
+ self(), CbInfo, Timeout);
+ {error, Error} ->
+ {error, Error}
+ end
+ catch
+ _:{error, Reason} ->
+ {error, Reason}
+ end;
+
+connect(Host, Port, Options) ->
+ connect(Host, Port, Options, infinity).
+
+connect(Host, Port, Options, Timeout) ->
+ try handle_options(Options, client) of
+ {ok, Config} ->
+ do_connect(Host,Port,Config,Timeout)
+ catch
+ throw:Error ->
+ Error
+ end.
+
+%%--------------------------------------------------------------------
+-spec listen(inet:port_number(), [listen_option()]) ->{ok, #sslsocket{}} | {error, reason()}.
+
+%%
+%% Description: Creates an ssl listen socket.
+%%--------------------------------------------------------------------
+listen(_Port, []) ->
+ {error, nooptions};
+listen(Port, Options0) ->
+ try
+ {ok, Config} = handle_options(Options0, server),
+ #config{cb = {Transport, _, _, _}, inet_user = Options} = Config,
+ case Transport:listen(Port, Options) of
+ {ok, ListenSocket} ->
+ {ok, #sslsocket{pid = {ListenSocket, Config}}};
+ Err = {error, _} ->
+ Err
+ end
+ catch
+ Error = {error, _} ->
+ Error
+ end.
+%%--------------------------------------------------------------------
+-spec transport_accept(#sslsocket{}) -> {ok, #sslsocket{}} |
+ {error, reason()}.
+-spec transport_accept(#sslsocket{}, timeout()) -> {ok, #sslsocket{}} |
+ {error, reason()}.
+%%
+%% Description: Performs transport accept on an ssl listen socket
+%%--------------------------------------------------------------------
+transport_accept(ListenSocket) ->
+ transport_accept(ListenSocket, infinity).
+
+transport_accept(#sslsocket{pid = {ListenSocket, #config{cb = CbInfo, ssl = SslOpts}}}, Timeout) ->
+
+ %% The setopt could have been invoked on the listen socket
+ %% and options should be inherited.
+ EmOptions = emulated_options(),
+ {Transport,_,_, _} = CbInfo,
+ {ok, SocketValues} = ssl_socket:getopts(Transport, ListenSocket, EmOptions),
+ ok = ssl_socket:setopts(Transport, ListenSocket, internal_inet_values()),
+ case Transport:accept(ListenSocket, Timeout) of
+ {ok, Socket} ->
+ ok = ssl_socket:setopts(Transport, ListenSocket, SocketValues),
+ {ok, Port} = ssl_socket:port(Transport, Socket),
+ ConnArgs = [server, "localhost", Port, Socket,
+ {SslOpts, socket_options(SocketValues)}, self(), CbInfo],
+ case ssl_connection_sup:start_child(ConnArgs) of
+ {ok, Pid} ->
+ tls_connection:socket_control(Socket, Pid, Transport);
+ {error, Reason} ->
+ {error, Reason}
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+%%--------------------------------------------------------------------
+-spec ssl_accept(#sslsocket{}) -> ok | {error, reason()}.
+-spec ssl_accept(#sslsocket{} | port(), timeout()| [ssl_option()
+ | transport_option()]) ->
+ ok | {ok, #sslsocket{}} | {error, reason()}.
+-spec ssl_accept(port(), [ssl_option()| transport_option()], timeout()) ->
+ {ok, #sslsocket{}} | {error, reason()}.
+%%
+%% Description: Performs accept on an ssl listen socket. e.i. performs
+%% ssl handshake.
+%%--------------------------------------------------------------------
+ssl_accept(ListenSocket) ->
+ ssl_accept(ListenSocket, infinity).
+
+ssl_accept(#sslsocket{} = Socket, Timeout) ->
+ tls_connection:handshake(Socket, Timeout);
+
+ssl_accept(ListenSocket, SslOptions) when is_port(ListenSocket) ->
+ ssl_accept(ListenSocket, SslOptions, infinity).
+
+ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) ->
+ {Transport,_,_,_} =
+ proplists:get_value(cb_info, SslOptions, {gen_tcp, tcp, tcp_closed, tcp_error}),
+ EmulatedOptions = emulated_options(),
+ {ok, SocketValues} = ssl_socket:getopts(Transport, Socket, EmulatedOptions),
+ try handle_options(SslOptions ++ SocketValues, server) of
+ {ok, #config{cb = CbInfo, ssl = SslOpts, emulated = EmOpts}} ->
+ ok = ssl_socket:setopts(Transport, Socket, internal_inet_values()),
+ {ok, Port} = ssl_socket:port(Transport, Socket),
+ tls_connection:ssl_accept(Port, Socket,
+ {SslOpts, EmOpts},
+ self(), CbInfo, Timeout)
+ catch
+ Error = {error, _Reason} -> Error
+ end.
+
+%%--------------------------------------------------------------------
+-spec close(#sslsocket{}) -> term().
+%%
+%% Description: Close an ssl connection
+%%--------------------------------------------------------------------
+close(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+ tls_connection:close(Pid);
+close(#sslsocket{pid = {ListenSocket, #config{cb={Transport,_, _, _}}}}) ->
+ Transport:close(ListenSocket).
+
+%%--------------------------------------------------------------------
+-spec send(#sslsocket{}, iodata()) -> ok | {error, reason()}.
+%%
+%% Description: Sends data over the ssl connection
+%%--------------------------------------------------------------------
+send(#sslsocket{pid = Pid}, Data) when is_pid(Pid) ->
+ tls_connection:send(Pid, Data);
+send(#sslsocket{pid = {ListenSocket, #config{cb={Transport, _, _, _}}}}, Data) ->
+ Transport:send(ListenSocket, Data). %% {error,enotconn}
+
+%%--------------------------------------------------------------------
+-spec recv(#sslsocket{}, integer()) -> {ok, binary()| list()} | {error, reason()}.
+-spec recv(#sslsocket{}, integer(), timeout()) -> {ok, binary()| list()} | {error, reason()}.
+%%
+%% Description: Receives data when active = false
+%%--------------------------------------------------------------------
+recv(Socket, Length) ->
+ recv(Socket, Length, infinity).
+recv(#sslsocket{pid = Pid}, Length, Timeout) when is_pid(Pid) ->
+ tls_connection:recv(Pid, Length, Timeout);
+recv(#sslsocket{pid = {Listen,
+ #config{cb={Transport, _, _, _}}}}, _,_) when is_port(Listen)->
+ Transport:recv(Listen, 0). %% {error,enotconn}
+
+%%--------------------------------------------------------------------
+-spec controlling_process(#sslsocket{}, pid()) -> ok | {error, reason()}.
+%%
+%% Description: Changes process that receives the messages when active = true
+%% or once.
+%%--------------------------------------------------------------------
+controlling_process(#sslsocket{pid = Pid}, NewOwner) when is_pid(Pid), is_pid(NewOwner) ->
+ tls_connection:new_user(Pid, NewOwner);
+controlling_process(#sslsocket{pid = {Listen,
+ #config{cb={Transport, _, _, _}}}},
+ NewOwner) when is_port(Listen),
+ is_pid(NewOwner) ->
+ Transport:controlling_process(Listen, NewOwner).
+
+%%--------------------------------------------------------------------
+-spec connection_info(#sslsocket{}) -> {ok, {tls_atom_version(), erl_cipher_suite()}} |
+ {error, reason()}.
+%%
+%% Description: Returns ssl protocol and cipher used for the connection
+%%--------------------------------------------------------------------
+connection_info(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+ tls_connection:info(Pid);
+connection_info(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
+ {error, enotconn}.
+
+%%--------------------------------------------------------------------
+-spec peername(#sslsocket{}) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
+%%
+%% Description: same as inet:peername/1.
+%%--------------------------------------------------------------------
+peername(#sslsocket{pid = Pid, fd = {Transport, Socket}}) when is_pid(Pid)->
+ ssl_socket:peername(Transport, Socket);
+peername(#sslsocket{pid = {ListenSocket, #config{cb = {Transport,_,_,_}}}}) ->
+ ssl_socket:peername(Transport, ListenSocket). %% Will return {error, enotconn}
+
+%%--------------------------------------------------------------------
+-spec peercert(#sslsocket{}) ->{ok, DerCert::binary()} | {error, reason()}.
+%%
+%% Description: Returns the peercert.
+%%--------------------------------------------------------------------
+peercert(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+ case tls_connection:peer_certificate(Pid) of
+ {ok, undefined} ->
+ {error, no_peercert};
+ Result ->
+ Result
+ end;
+peercert(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
+ {error, enotconn}.
+
+%%--------------------------------------------------------------------
+-spec suite_definition(cipher_suite()) -> erl_cipher_suite().
+%%
+%% Description: Return erlang cipher suite definition.
+%%--------------------------------------------------------------------
+suite_definition(S) ->
+ {KeyExchange, Cipher, Hash, _} = ssl_cipher:suite_definition(S),
+ {KeyExchange, Cipher, Hash}.
+
+%%--------------------------------------------------------------------
+-spec negotiated_next_protocol(#sslsocket{}) -> {ok, binary()} | {error, reason()}.
+%%
+%% Description: Returns the next protocol that has been negotiated. If no
+%% protocol has been negotiated will return {error, next_protocol_not_negotiated}
+%%--------------------------------------------------------------------
+negotiated_next_protocol(#sslsocket{pid = Pid}) ->
+ tls_connection:negotiated_next_protocol(Pid).
+
+-spec cipher_suites() -> [erl_cipher_suite()].
+-spec cipher_suites(erlang | openssl | all) -> [erl_cipher_suite()] | [string()].
+
+%% Description: Returns all supported cipher suites.
+%%--------------------------------------------------------------------
+cipher_suites() ->
+ cipher_suites(erlang).
+
+cipher_suites(erlang) ->
+ Version = tls_record:highest_protocol_version([]),
+ [suite_definition(S) || S <- ssl_cipher:suites(Version)];
+
+cipher_suites(openssl) ->
+ Version = tls_record:highest_protocol_version([]),
+ [ssl_cipher:openssl_suite_name(S) || S <- ssl_cipher:suites(Version)];
+cipher_suites(all) ->
+ Version = tls_record:highest_protocol_version([]),
+ Supported = ssl_cipher:suites(Version)
+ ++ ssl_cipher:anonymous_suites()
+ ++ ssl_cipher:psk_suites(Version)
+ ++ ssl_cipher:srp_suites(),
+ [suite_definition(S) || S <- Supported].
+
+%%--------------------------------------------------------------------
+-spec getopts(#sslsocket{}, [gen_tcp:option_name()]) ->
+ {ok, [gen_tcp:option()]} | {error, reason()}.
+%%
+%% Description: Gets options
+%%--------------------------------------------------------------------
+getopts(#sslsocket{pid = Pid}, OptionTags) when is_pid(Pid), is_list(OptionTags) ->
+ tls_connection:get_opts(Pid, OptionTags);
+getopts(#sslsocket{pid = {ListenSocket, #config{cb = {Transport,_,_,_}}}},
+ OptionTags) when is_list(OptionTags) ->
+ try ssl_socket:getopts(Transport, ListenSocket, OptionTags) of
+ {ok, _} = Result ->
+ Result;
+ {error, InetError} ->
+ {error, {options, {socket_options, OptionTags, InetError}}}
+ catch
+ _:_ ->
+ {error, {options, {socket_options, OptionTags}}}
+ end;
+getopts(#sslsocket{}, OptionTags) ->
+ {error, {options, {socket_options, OptionTags}}}.
+
+%%--------------------------------------------------------------------
+-spec setopts(#sslsocket{}, [gen_tcp:option()]) -> ok | {error, reason()}.
+%%
+%% Description: Sets options
+%%--------------------------------------------------------------------
+setopts(#sslsocket{pid = Pid}, Options0) when is_pid(Pid), is_list(Options0) ->
+ try proplists:expand([{binary, [{mode, binary}]},
+ {list, [{mode, list}]}], Options0) of
+ Options ->
+ tls_connection:set_opts(Pid, Options)
+ catch
+ _:_ ->
+ {error, {options, {not_a_proplist, Options0}}}
+ end;
+
+setopts(#sslsocket{pid = {ListenSocket, #config{cb = {Transport,_,_,_}}}}, Options) when is_list(Options) ->
+ try ssl_socket:setopts(Transport, ListenSocket, Options) of
+ ok ->
+ ok;
+ {error, InetError} ->
+ {error, {options, {socket_options, Options, InetError}}}
+ catch
+ _:Error ->
+ {error, {options, {socket_options, Options, Error}}}
+ end;
+setopts(#sslsocket{}, Options) ->
+ {error, {options,{not_a_proplist, Options}}}.
+
+%%---------------------------------------------------------------
+-spec shutdown(#sslsocket{}, read | write | read_write) -> ok | {error, reason()}.
+%%
+%% Description: Same as gen_tcp:shutdown/2
+%%--------------------------------------------------------------------
+shutdown(#sslsocket{pid = {Listen, #config{cb={Transport,_, _, _}}}},
+ How) when is_port(Listen) ->
+ Transport:shutdown(Listen, How);
+shutdown(#sslsocket{pid = Pid}, How) ->
+ tls_connection:shutdown(Pid, How).
+
+%%--------------------------------------------------------------------
+-spec sockname(#sslsocket{}) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
+%%
+%% Description: Same as inet:sockname/1
+%%--------------------------------------------------------------------
+sockname(#sslsocket{pid = {Listen, #config{cb={Transport,_, _, _}}}}) when is_port(Listen) ->
+ ssl_socket:sockname(Transport, Listen);
+
+sockname(#sslsocket{pid = Pid, fd = {Transport, Socket}}) when is_pid(Pid) ->
+ ssl_socket:sockname(Transport, Socket).
+
+%%---------------------------------------------------------------
+-spec session_info(#sslsocket{}) -> {ok, list()} | {error, reason()}.
+%%
+%% Description: Returns list of session info currently [{session_id, session_id(),
+%% {cipher_suite, cipher_suite()}]
+%%--------------------------------------------------------------------
+session_info(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+ tls_connection:session_info(Pid);
+session_info(#sslsocket{pid = {Listen,_}}) when is_port(Listen) ->
+ {error, enotconn}.
+
+%%---------------------------------------------------------------
+-spec versions() -> [{ssl_app, string()} | {supported, [tls_atom_version()]} |
+ {available, [tls_atom_version()]}].
+%%
+%% Description: Returns a list of relevant versions.
+%%--------------------------------------------------------------------
+versions() ->
+ Vsns = tls_record:supported_protocol_versions(),
+ SupportedVsns = [tls_record:protocol_version(Vsn) || Vsn <- Vsns],
+ AvailableVsns = ?ALL_SUPPORTED_VERSIONS,
+ [{ssl_app, ?VSN}, {supported, SupportedVsns}, {available, AvailableVsns}].
+
+
+%%---------------------------------------------------------------
+-spec renegotiate(#sslsocket{}) -> ok | {error, reason()}.
+%%
+%% Description: Initiates a renegotiation.
+%%--------------------------------------------------------------------
+renegotiate(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+ tls_connection:renegotiation(Pid);
+renegotiate(#sslsocket{pid = {Listen,_}}) when is_port(Listen) ->
+ {error, enotconn}.
+
+%%--------------------------------------------------------------------
+-spec prf(#sslsocket{}, binary() | 'master_secret', binary(),
+ binary() | prf_random(), non_neg_integer()) ->
+ {ok, binary()} | {error, reason()}.
+%%
+%% Description: use a ssl sessions TLS PRF to generate key material
+%%--------------------------------------------------------------------
+prf(#sslsocket{pid = Pid},
+ Secret, Label, Seed, WantedLength) when is_pid(Pid) ->
+ tls_connection:prf(Pid, Secret, Label, Seed, WantedLength);
+prf(#sslsocket{pid = {Listen,_}}, _,_,_,_) when is_port(Listen) ->
+ {error, enotconn}.
+
+%%--------------------------------------------------------------------
+-spec clear_pem_cache() -> ok.
+%%
+%% Description: Clear the PEM cache
+%%--------------------------------------------------------------------
+clear_pem_cache() ->
+ ssl_manager:clear_pem_cache().
+
+%%---------------------------------------------------------------
+-spec format_error({error, term()}) -> list().
+%%
+%% Description: Creates error string.
+%%--------------------------------------------------------------------
+format_error({error, Reason}) ->
+ format_error(Reason);
+format_error(Reason) when is_list(Reason) ->
+ Reason;
+format_error(closed) ->
+ "TLS connection is closed";
+format_error({tls_alert, Description}) ->
+ "TLS Alert: " ++ Description;
+format_error({options,{FileType, File, Reason}}) when FileType == cacertfile;
+ FileType == certfile;
+ FileType == keyfile;
+ FileType == dhfile ->
+ Error = file_error_format(Reason),
+ file_desc(FileType) ++ File ++ ": " ++ Error;
+format_error({options, {socket_options, Option, Error}}) ->
+ lists:flatten(io_lib:format("Invalid transport socket option ~p: ~s", [Option, format_error(Error)]));
+format_error({options, {socket_options, Option}}) ->
+ lists:flatten(io_lib:format("Invalid socket option: ~p", [Option]));
+format_error({options, Options}) ->
+ lists:flatten(io_lib:format("Invalid TLS option: ~p", [Options]));
+
+format_error(Error) ->
+ case inet:format_error(Error) of
+ "unknown POSIX" ++ _ ->
+ unexpected_format(Error);
+ Other ->
+ Other
+ end.
+
+%%--------------------------------------------------------------------
+-spec random_bytes(integer()) -> binary().
+
+%%
+%% Description: Generates cryptographically secure random sequence if possible
+%% fallbacks on pseudo random function
+%%--------------------------------------------------------------------
+random_bytes(N) ->
+ try crypto:strong_rand_bytes(N) of
+ RandBytes ->
+ RandBytes
+ catch
+ error:low_entropy ->
+ crypto:rand_bytes(N)
+ end.
+
+%%%--------------------------------------------------------------
+%%% Internal functions
+%%%--------------------------------------------------------------------
+do_connect(Address, Port,
+ #config{cb=CbInfo, inet_user=UserOpts, ssl=SslOpts,
+ emulated=EmOpts,inet_ssl=SocketOpts},
+ Timeout) ->
+ {Transport, _, _, _} = CbInfo,
+ try Transport:connect(Address, Port, SocketOpts, Timeout) of
+ {ok, Socket} ->
+ tls_connection:connect(Address, Port, Socket, {SslOpts,EmOpts},
+ self(), CbInfo, Timeout);
+ {error, Reason} ->
+ {error, Reason}
+ catch
+ exit:{function_clause, _} ->
+ {error, {options, {cb_info, CbInfo}}};
+ exit:badarg ->
+ {error, {options, {socket_options, UserOpts}}};
+ exit:{badarg, _} ->
+ {error, {options, {socket_options, UserOpts}}}
+ end.
+
+handle_options(Opts0, _Role) ->
+ Opts = proplists:expand([{binary, [{mode, binary}]},
+ {list, [{mode, list}]}], Opts0),
+ ReuseSessionFun = fun(_, _, _, _) -> true end,
+
+ DefaultVerifyNoneFun =
+ {fun(_,{bad_cert, _}, UserState) ->
+ {valid, UserState};
+ (_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (_, valid, UserState) ->
+ {valid, UserState};
+ (_, valid_peer, UserState) ->
+ {valid, UserState}
+ end, []},
+
+ VerifyNoneFun = handle_option(verify_fun, Opts, DefaultVerifyNoneFun),
+
+ UserFailIfNoPeerCert = handle_option(fail_if_no_peer_cert, Opts, false),
+ UserVerifyFun = handle_option(verify_fun, Opts, undefined),
+ CaCerts = handle_option(cacerts, Opts, undefined),
+
+ {Verify, FailIfNoPeerCert, CaCertDefault, VerifyFun} =
+ %% Handle 0, 1, 2 for backwards compatibility
+ case proplists:get_value(verify, Opts, verify_none) of
+ 0 ->
+ {verify_none, false,
+ ca_cert_default(verify_none, VerifyNoneFun, CaCerts), VerifyNoneFun};
+ 1 ->
+ {verify_peer, false,
+ ca_cert_default(verify_peer, UserVerifyFun, CaCerts), UserVerifyFun};
+ 2 ->
+ {verify_peer, true,
+ ca_cert_default(verify_peer, UserVerifyFun, CaCerts), UserVerifyFun};
+ verify_none ->
+ {verify_none, false,
+ ca_cert_default(verify_none, VerifyNoneFun, CaCerts), VerifyNoneFun};
+ verify_peer ->
+ {verify_peer, UserFailIfNoPeerCert,
+ ca_cert_default(verify_peer, UserVerifyFun, CaCerts), UserVerifyFun};
+ Value ->
+ throw({error, {options, {verify, Value}}})
+ end,
+
+ CertFile = handle_option(certfile, Opts, <<>>),
+
+ Versions = case handle_option(versions, Opts, []) of
+ [] ->
+ tls_record:supported_protocol_versions();
+ Vsns ->
+ [tls_record:protocol_version(Vsn) || Vsn <- Vsns]
+ end,
+
+ SSLOptions = #ssl_options{
+ versions = Versions,
+ verify = validate_option(verify, Verify),
+ verify_fun = VerifyFun,
+ fail_if_no_peer_cert = FailIfNoPeerCert,
+ verify_client_once = handle_option(verify_client_once, Opts, false),
+ depth = handle_option(depth, Opts, 1),
+ cert = handle_option(cert, Opts, undefined),
+ certfile = CertFile,
+ key = handle_option(key, Opts, undefined),
+ keyfile = handle_option(keyfile, Opts, CertFile),
+ password = handle_option(password, Opts, ""),
+ cacerts = CaCerts,
+ cacertfile = handle_option(cacertfile, Opts, CaCertDefault),
+ dh = handle_option(dh, Opts, undefined),
+ dhfile = handle_option(dhfile, Opts, undefined),
+ user_lookup_fun = handle_option(user_lookup_fun, Opts, undefined),
+ psk_identity = handle_option(psk_identity, Opts, undefined),
+ srp_identity = handle_option(srp_identity, Opts, undefined),
+ ciphers = handle_option(ciphers, Opts, []),
+ %% Server side option
+ reuse_session = handle_option(reuse_session, Opts, ReuseSessionFun),
+ reuse_sessions = handle_option(reuse_sessions, Opts, true),
+ secure_renegotiate = handle_option(secure_renegotiate, Opts, false),
+ renegotiate_at = handle_option(renegotiate_at, Opts, ?DEFAULT_RENEGOTIATE_AT),
+ hibernate_after = handle_option(hibernate_after, Opts, undefined),
+ erl_dist = handle_option(erl_dist, Opts, false),
+ next_protocols_advertised =
+ handle_option(next_protocols_advertised, Opts, undefined),
+ next_protocol_selector =
+ make_next_protocol_selector(
+ handle_option(client_preferred_next_protocols, Opts, undefined))
+ },
+
+ CbInfo = proplists:get_value(cb_info, Opts, {gen_tcp, tcp, tcp_closed, tcp_error}),
+ SslOptions = [versions, verify, verify_fun,
+ fail_if_no_peer_cert, verify_client_once,
+ depth, cert, certfile, key, keyfile,
+ password, cacerts, cacertfile, dh, dhfile,
+ user_lookup_fun, psk_identity, srp_identity, ciphers,
+ reuse_session, reuse_sessions, ssl_imp,
+ cb_info, renegotiate_at, secure_renegotiate, hibernate_after,
+ erl_dist, next_protocols_advertised,
+ client_preferred_next_protocols],
+
+ SockOpts = lists:foldl(fun(Key, PropList) ->
+ proplists:delete(Key, PropList)
+ end, Opts, SslOptions),
+
+ {SSLsock, Emulated} = emulated_options(SockOpts),
+ {ok, #config{ssl=SSLOptions, emulated=Emulated, inet_ssl=SSLsock,
+ inet_user=SockOpts, cb=CbInfo}}.
+
+handle_option(OptionName, Opts, Default) ->
+ validate_option(OptionName,
+ proplists:get_value(OptionName, Opts, Default)).
+
+
+validate_option(versions, Versions) ->
+ validate_versions(Versions, Versions);
+validate_option(verify, Value)
+ when Value == verify_none; Value == verify_peer ->
+ Value;
+validate_option(verify_fun, undefined) ->
+ undefined;
+%% Backwards compatibility
+validate_option(verify_fun, Fun) when is_function(Fun) ->
+ {fun(_,{bad_cert, _} = Reason, OldFun) ->
+ case OldFun([Reason]) of
+ true ->
+ {valid, OldFun};
+ false ->
+ {fail, Reason}
+ end;
+ (_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (_, valid, UserState) ->
+ {valid, UserState};
+ (_, valid_peer, UserState) ->
+ {valid, UserState}
+ end, Fun};
+validate_option(verify_fun, {Fun, _} = Value) when is_function(Fun) ->
+ Value;
+validate_option(fail_if_no_peer_cert, Value)
+ when Value == true; Value == false ->
+ Value;
+validate_option(verify_client_once, Value)
+ when Value == true; Value == false ->
+ Value;
+validate_option(depth, Value) when is_integer(Value),
+ Value >= 0, Value =< 255->
+ Value;
+validate_option(cert, Value) when Value == undefined;
+ is_binary(Value) ->
+ Value;
+validate_option(certfile, undefined = Value) ->
+ Value;
+validate_option(certfile, Value) when is_binary(Value) ->
+ Value;
+validate_option(certfile, Value) when is_list(Value) ->
+ list_to_binary(Value);
+
+validate_option(key, undefined) ->
+ undefined;
+validate_option(key, {KeyType, Value}) when is_binary(Value),
+ KeyType == rsa; %% Backwards compatibility
+ KeyType == dsa; %% Backwards compatibility
+ KeyType == 'RSAPrivateKey';
+ KeyType == 'DSAPrivateKey';
+ KeyType == 'PrivateKeyInfo' ->
+ {KeyType, Value};
+
+validate_option(keyfile, undefined) ->
+ <<>>;
+validate_option(keyfile, Value) when is_binary(Value) ->
+ Value;
+validate_option(keyfile, Value) when is_list(Value), Value =/= "" ->
+ list_to_binary(Value);
+validate_option(password, Value) when is_list(Value) ->
+ Value;
+
+validate_option(cacerts, Value) when Value == undefined;
+ is_list(Value) ->
+ Value;
+%% certfile must be present in some cases otherwhise it can be set
+%% to the empty string.
+validate_option(cacertfile, undefined) ->
+ <<>>;
+validate_option(cacertfile, Value) when is_binary(Value) ->
+ Value;
+validate_option(cacertfile, Value) when is_list(Value), Value =/= ""->
+ list_to_binary(Value);
+validate_option(dh, Value) when Value == undefined;
+ is_binary(Value) ->
+ Value;
+validate_option(dhfile, undefined = Value) ->
+ Value;
+validate_option(dhfile, Value) when is_binary(Value) ->
+ Value;
+validate_option(dhfile, Value) when is_list(Value), Value =/= "" ->
+ list_to_binary(Value);
+validate_option(psk_identity, undefined) ->
+ undefined;
+validate_option(psk_identity, Identity)
+ when is_list(Identity), Identity =/= "", length(Identity) =< 65535 ->
+ list_to_binary(Identity);
+validate_option(user_lookup_fun, undefined) ->
+ undefined;
+validate_option(user_lookup_fun, {Fun, _} = Value) when is_function(Fun, 3) ->
+ Value;
+validate_option(srp_identity, undefined) ->
+ undefined;
+validate_option(srp_identity, {Username, Password})
+ when is_list(Username), is_list(Password), Username =/= "", length(Username) =< 255 ->
+ {list_to_binary(Username), list_to_binary(Password)};
+
+validate_option(ciphers, Value) when is_list(Value) ->
+ Version = tls_record:highest_protocol_version([]),
+ try cipher_suites(Version, Value)
+ catch
+ exit:_ ->
+ throw({error, {options, {ciphers, Value}}});
+ error:_->
+ throw({error, {options, {ciphers, Value}}})
+ end;
+validate_option(reuse_session, Value) when is_function(Value) ->
+ Value;
+validate_option(reuse_sessions, Value) when Value == true;
+ Value == false ->
+ Value;
+
+validate_option(secure_renegotiate, Value) when Value == true;
+ Value == false ->
+ Value;
+validate_option(renegotiate_at, Value) when is_integer(Value) ->
+ erlang:min(Value, ?DEFAULT_RENEGOTIATE_AT);
+
+validate_option(hibernate_after, undefined) ->
+ undefined;
+validate_option(hibernate_after, Value) when is_integer(Value), Value >= 0 ->
+ Value;
+validate_option(erl_dist,Value) when Value == true;
+ Value == false ->
+ Value;
+validate_option(client_preferred_next_protocols = Opt, {Precedence, PreferredProtocols} = Value)
+ when is_list(PreferredProtocols) ->
+ case tls_record:highest_protocol_version([]) of
+ {3,0} ->
+ throw({error, {options, {not_supported_in_sslv3, {Opt, Value}}}});
+ _ ->
+ validate_binary_list(client_preferred_next_protocols, PreferredProtocols),
+ validate_npn_ordering(Precedence),
+ {Precedence, PreferredProtocols, ?NO_PROTOCOL}
+ end;
+validate_option(client_preferred_next_protocols = Opt, {Precedence, PreferredProtocols, Default} = Value)
+ when is_list(PreferredProtocols), is_binary(Default),
+ byte_size(Default) > 0, byte_size(Default) < 256 ->
+ case tls_record:highest_protocol_version([]) of
+ {3,0} ->
+ throw({error, {options, {not_supported_in_sslv3, {Opt, Value}}}});
+ _ ->
+ validate_binary_list(client_preferred_next_protocols, PreferredProtocols),
+ validate_npn_ordering(Precedence),
+ Value
+ end;
+
+validate_option(client_preferred_next_protocols, undefined) ->
+ undefined;
+validate_option(next_protocols_advertised = Opt, Value) when is_list(Value) ->
+ case tls_record:highest_protocol_version([]) of
+ {3,0} ->
+ throw({error, {options, {not_supported_in_sslv3, {Opt, Value}}}});
+ _ ->
+ validate_binary_list(next_protocols_advertised, Value),
+ Value
+ end;
+
+validate_option(next_protocols_advertised, undefined) ->
+ undefined;
+validate_option(Opt, Value) ->
+ throw({error, {options, {Opt, Value}}}).
+
+validate_npn_ordering(client) ->
+ ok;
+validate_npn_ordering(server) ->
+ ok;
+validate_npn_ordering(Value) ->
+ throw({error, {options, {client_preferred_next_protocols, {invalid_precedence, Value}}}}).
+
+validate_binary_list(Opt, List) ->
+ lists:foreach(
+ fun(Bin) when is_binary(Bin),
+ byte_size(Bin) > 0,
+ byte_size(Bin) < 256 ->
+ ok;
+ (Bin) ->
+ throw({error, {options, {Opt, {invalid_protocol, Bin}}}})
+ end, List).
+
+validate_versions([], Versions) ->
+ Versions;
+validate_versions([Version | Rest], Versions) when Version == 'tlsv1.2';
+ Version == 'tlsv1.1';
+ Version == tlsv1;
+ Version == sslv3 ->
+ validate_versions(Rest, Versions);
+validate_versions([Ver| _], Versions) ->
+ throw({error, {options, {Ver, {versions, Versions}}}}).
+
+validate_inet_option(mode, Value)
+ when Value =/= list, Value =/= binary ->
+ throw({error, {options, {mode,Value}}});
+validate_inet_option(packet, Value)
+ when not (is_atom(Value) orelse is_integer(Value)) ->
+ throw({error, {options, {packet,Value}}});
+validate_inet_option(packet_size, Value)
+ when not is_integer(Value) ->
+ throw({error, {options, {packet_size,Value}}});
+validate_inet_option(header, Value)
+ when not is_integer(Value) ->
+ throw({error, {options, {header,Value}}});
+validate_inet_option(active, Value)
+ when Value =/= true, Value =/= false, Value =/= once ->
+ throw({error, {options, {active,Value}}});
+validate_inet_option(_, _) ->
+ ok.
+
+%% The option cacerts overrides cacertsfile
+ca_cert_default(_,_, [_|_]) ->
+ undefined;
+ca_cert_default(verify_none, _, _) ->
+ undefined;
+ca_cert_default(verify_peer, {Fun,_}, _) when is_function(Fun) ->
+ undefined;
+%% Server that wants to verify_peer and has no verify_fun must have
+%% some trusted certs.
+ca_cert_default(verify_peer, undefined, _) ->
+ "".
+
+emulated_options() ->
+ [mode, packet, active, header, packet_size].
+
+internal_inet_values() ->
+ [{packet_size,0},{packet, 0},{header, 0},{active, false},{mode,binary}].
+
+socket_options(InetValues) ->
+ #socket_options{
+ mode = proplists:get_value(mode, InetValues, lists),
+ header = proplists:get_value(header, InetValues, 0),
+ active = proplists:get_value(active, InetValues, active),
+ packet = proplists:get_value(packet, InetValues, 0),
+ packet_size = proplists:get_value(packet_size, InetValues)
+ }.
+
+emulated_options(Opts) ->
+ emulated_options(Opts, internal_inet_values(), #socket_options{}).
+
+emulated_options([{mode,Opt}|Opts], Inet, Emulated) ->
+ validate_inet_option(mode,Opt),
+ emulated_options(Opts, Inet, Emulated#socket_options{mode=Opt});
+emulated_options([{header,Opt}|Opts], Inet, Emulated) ->
+ validate_inet_option(header,Opt),
+ emulated_options(Opts, Inet, Emulated#socket_options{header=Opt});
+emulated_options([{active,Opt}|Opts], Inet, Emulated) ->
+ validate_inet_option(active,Opt),
+ emulated_options(Opts, Inet, Emulated#socket_options{active=Opt});
+emulated_options([{packet,Opt}|Opts], Inet, Emulated) ->
+ validate_inet_option(packet,Opt),
+ emulated_options(Opts, Inet, Emulated#socket_options{packet=Opt});
+emulated_options([{packet_size,Opt}|Opts], Inet, Emulated) ->
+ validate_inet_option(packet_size,Opt),
+ emulated_options(Opts, Inet, Emulated#socket_options{packet_size=Opt});
+emulated_options([Opt|Opts], Inet, Emulated) ->
+ emulated_options(Opts, [Opt|Inet], Emulated);
+emulated_options([], Inet,Emulated) ->
+ {Inet, Emulated}.
+
+cipher_suites(Version, []) ->
+ ssl_cipher:suites(Version);
+cipher_suites(Version, [{_,_,_,_}| _] = Ciphers0) -> %% Backwards compatibility
+ Ciphers = [{KeyExchange, Cipher, Hash} || {KeyExchange, Cipher, Hash, _} <- Ciphers0],
+ cipher_suites(Version, Ciphers);
+cipher_suites(Version, [{_,_,_}| _] = Ciphers0) ->
+ Ciphers = [ssl_cipher:suite(C) || C <- Ciphers0],
+ cipher_suites(Version, Ciphers);
+
+cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) ->
+ Supported0 = ssl_cipher:suites(Version)
+ ++ ssl_cipher:anonymous_suites()
+ ++ ssl_cipher:psk_suites(Version)
+ ++ ssl_cipher:srp_suites(),
+ Supported = ssl_cipher:filter_suites(Supported0),
+ case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported)] of
+ [] ->
+ Supported;
+ Ciphers ->
+ Ciphers
+ end;
+cipher_suites(Version, [Head | _] = Ciphers0) when is_list(Head) ->
+ %% Format: ["RC4-SHA","RC4-MD5"]
+ Ciphers = [ssl_cipher:openssl_suite(C) || C <- Ciphers0],
+ cipher_suites(Version, Ciphers);
+cipher_suites(Version, Ciphers0) ->
+ %% Format: "RC4-SHA:RC4-MD5"
+ Ciphers = [ssl_cipher:openssl_suite(C) || C <- string:tokens(Ciphers0, ":")],
+ cipher_suites(Version, Ciphers).
+
+unexpected_format(Error) ->
+ lists:flatten(io_lib:format("Unexpected error: ~p", [Error])).
+
+file_error_format({error, Error})->
+ case file:format_error(Error) of
+ "unknown POSIX error" ->
+ "decoding error";
+ Str ->
+ Str
+ end;
+file_error_format(_) ->
+ "decoding error".
+
+file_desc(cacertfile) ->
+ "Invalid CA certificate file ";
+file_desc(certfile) ->
+ "Invalid certificate file ";
+file_desc(keyfile) ->
+ "Invalid key file ";
+file_desc(dhfile) ->
+ "Invalid DH params file ".
+
+detect(_Pred, []) ->
+ undefined;
+detect(Pred, [H|T]) ->
+ case Pred(H) of
+ true ->
+ H;
+ _ ->
+ detect(Pred, T)
+ end.
+
+make_next_protocol_selector(undefined) ->
+ undefined;
+make_next_protocol_selector({client, AllProtocols, DefaultProtocol}) ->
+ fun(AdvertisedProtocols) ->
+ case detect(fun(PreferredProtocol) ->
+ lists:member(PreferredProtocol, AdvertisedProtocols)
+ end, AllProtocols) of
+ undefined ->
+ DefaultProtocol;
+ PreferredProtocol ->
+ PreferredProtocol
+ end
+ end;
+
+make_next_protocol_selector({server, AllProtocols, DefaultProtocol}) ->
+ fun(AdvertisedProtocols) ->
+ case detect(fun(PreferredProtocol) ->
+ lists:member(PreferredProtocol, AllProtocols)
+ end,
+ AdvertisedProtocols) of
+ undefined ->
+ DefaultProtocol;
+ PreferredProtocol ->
+ PreferredProtocol
+ end
+ end.
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/tls_connection.erl
index de9260fd8c..246fecf34a 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -25,13 +25,13 @@
%% sent according to the SSL-record protocol.
%%----------------------------------------------------------------------
--module(ssl_connection).
+-module(tls_connection).
-behaviour(gen_fsm).
--include("ssl_handshake.hrl").
+-include("tls_handshake.hrl").
-include("ssl_alert.hrl").
--include("ssl_record.hrl").
+-include("tls_record.hrl").
-include("ssl_cipher.hrl").
-include("ssl_internal.hrl").
-include("ssl_srp.hrl").
@@ -70,7 +70,7 @@
tls_handshake_history, % tls_handshake_history()
tls_cipher_texts, % list() received but not deciphered yet
cert_db, %
- session, % #session{} from ssl_handshake.hrl
+ session, % #session{} from tls_handshake.hrl
session_cache, %
session_cache_cb, %
negotiated_version, % tls_version()
@@ -302,7 +302,7 @@ start_link(Role, Host, Port, Socket, Options, User, CbInfo) ->
init([Role, Host, Port, Socket, {SSLOpts0, _} = Options, User, CbInfo]) ->
State0 = initial_state(Role, Host, Port, Socket, Options, User, CbInfo),
- Handshake = ssl_handshake:init_handshake_history(),
+ Handshake = tls_handshake:init_handshake_history(),
TimeStamp = calendar:datetime_to_gregorian_seconds({date(), time()}),
try ssl_init(SSLOpts0, Role) of
{ok, Ref, CertDbHandle, FileRefHandle, CacheHandle, OwnCert, Key, DHParams} ->
@@ -342,11 +342,11 @@ hello(start, #state{host = Host, port = Port, role = client,
transport_cb = Transport, socket = Socket,
connection_states = ConnectionStates0,
renegotiation = {Renegotiation, _}} = State0) ->
- Hello = ssl_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
+ Hello = tls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
Cache, CacheCb, Renegotiation, Cert),
Version = Hello#client_hello.client_version,
- Handshake0 = ssl_handshake:init_handshake_history(),
+ Handshake0 = tls_handshake:init_handshake_history(),
{BinMsg, ConnectionStates, Handshake} =
encode_handshake(Hello, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
@@ -374,7 +374,7 @@ hello(#server_hello{cipher_suite = CipherSuite,
negotiated_version = ReqVersion,
renegotiation = {Renegotiation, _},
ssl_options = SslOptions} = State0) ->
- case ssl_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of
+ case tls_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of
#alert{} = Alert ->
handle_own_alert(Alert, ReqVersion, hello, State0);
{Version, NewId, ConnectionStates, NextProtocol} ->
@@ -414,7 +414,7 @@ hello(Hello = #client_hello{client_version = ClientVersion},
session_cache = Cache,
session_cache_cb = CacheCb,
ssl_options = SslOpts}) ->
- case ssl_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
+ case tls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
ConnectionStates0, Cert}, Renegotiation) of
{Version, {Type, Session}, ConnectionStates, ProtocolsToAdvertise,
EcPointFormats, EllipticCurves} ->
@@ -448,11 +448,11 @@ abbreviated(#finished{verify_data = Data} = Finished,
session = #session{master_secret = MasterSecret},
connection_states = ConnectionStates0} =
State) ->
- case ssl_handshake:verify_connection(Version, Finished, client,
+ case tls_handshake:verify_connection(Version, Finished, client,
get_current_connection_state_prf(ConnectionStates0, write),
MasterSecret, Handshake) of
verified ->
- ConnectionStates = ssl_record:set_client_verify_data(current_both, Data, ConnectionStates0),
+ ConnectionStates = tls_record:set_client_verify_data(current_both, Data, ConnectionStates0),
next_state_connection(abbreviated,
ack_connection(State#state{connection_states = ConnectionStates}));
#alert{} = Alert ->
@@ -464,11 +464,11 @@ abbreviated(#finished{verify_data = Data} = Finished,
session = #session{master_secret = MasterSecret},
negotiated_version = Version,
connection_states = ConnectionStates0} = State) ->
- case ssl_handshake:verify_connection(Version, Finished, server,
+ case tls_handshake:verify_connection(Version, Finished, server,
get_pending_connection_state_prf(ConnectionStates0, write),
MasterSecret, Handshake0) of
verified ->
- ConnectionStates1 = ssl_record:set_server_verify_data(current_read, Data, ConnectionStates0),
+ ConnectionStates1 = tls_record:set_server_verify_data(current_read, Data, ConnectionStates0),
{ConnectionStates, Handshake} =
finalize_handshake(State#state{connection_states = ConnectionStates1}, abbreviated),
next_state_connection(abbreviated,
@@ -523,7 +523,7 @@ certify(#certificate{} = Cert,
cert_db = CertDbHandle,
cert_db_ref = CertDbRef,
ssl_options = Opts} = State) ->
- case ssl_handshake:certify(Cert, CertDbHandle, CertDbRef, Opts#ssl_options.depth,
+ case tls_handshake:certify(Cert, CertDbHandle, CertDbRef, Opts#ssl_options.depth,
Opts#ssl_options.verify,
Opts#ssl_options.verify_fun, Role) of
{PeerCert, PublicKeyInfo} ->
@@ -603,7 +603,7 @@ certify(#server_hello_done{},
negotiated_version = Version,
premaster_secret = undefined,
role = client} = State0) ->
- case ssl_handshake:master_secret(Version, Session,
+ case tls_handshake:master_secret(Version, Session,
ConnectionStates0, client) of
{MasterSecret, ConnectionStates} ->
State = State0#state{connection_states = ConnectionStates},
@@ -619,7 +619,7 @@ certify(#server_hello_done{},
negotiated_version = Version,
premaster_secret = PremasterSecret,
role = client} = State0) ->
- case ssl_handshake:master_secret(Version, PremasterSecret,
+ case tls_handshake:master_secret(Version, PremasterSecret,
ConnectionStates0, client) of
{MasterSecret, ConnectionStates} ->
Session = Session0#session{master_secret = MasterSecret},
@@ -640,7 +640,7 @@ certify(#client_key_exchange{} = Msg,
certify(#client_key_exchange{exchange_keys = Keys},
State = #state{key_algorithm = KeyAlg, negotiated_version = Version}) ->
try
- certify_client_key_exchange(ssl_handshake:decode_client_key(Keys, KeyAlg, Version), State)
+ certify_client_key_exchange(tls_handshake:decode_client_key(Keys, KeyAlg, Version), State)
catch
#alert{} = Alert ->
handle_own_alert(Alert, Version, certify, State)
@@ -658,8 +658,8 @@ certify_client_key_exchange(#encrypted_premaster_secret{premaster_secret= EncPMS
connection_states = ConnectionStates0,
session = Session0,
private_key = Key} = State0) ->
- PremasterSecret = ssl_handshake:decrypt_premaster_secret(EncPMS, Key),
- case ssl_handshake:master_secret(Version, PremasterSecret,
+ PremasterSecret = tls_handshake:decrypt_premaster_secret(EncPMS, Key),
+ case tls_handshake:master_secret(Version, PremasterSecret,
ConnectionStates0, server) of
{MasterSecret, ConnectionStates} ->
Session = Session0#session{master_secret = MasterSecret},
@@ -673,8 +673,7 @@ certify_client_key_exchange(#encrypted_premaster_secret{premaster_secret= EncPMS
certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPublicDhKey},
#state{negotiated_version = Version,
- diffie_hellman_params = #'DHParameter'{prime = P,
- base = G} = Params,
+ diffie_hellman_params = #'DHParameter'{} = Params,
diffie_hellman_keys = {_, ServerDhPrivateKey}} = State0) ->
case dh_master_secret(Params, ClientPublicDhKey, ServerDhPrivateKey, State0) of
#state{} = State1 ->
@@ -726,7 +725,7 @@ certify_client_key_exchange(#client_rsa_psk_identity{
#encrypted_premaster_secret{premaster_secret= EncPMS}},
#state{negotiated_version = Version,
private_key = Key} = State0) ->
- PremasterSecret = ssl_handshake:decrypt_premaster_secret(EncPMS, Key),
+ PremasterSecret = tls_handshake:decrypt_premaster_secret(EncPMS, Key),
case server_rsa_psk_master_secret(PskIdentity, PremasterSecret, State0) of
#state{} = State1 ->
{Record, State} = next_record(State1),
@@ -769,7 +768,7 @@ cipher(#certificate_verify{signature = Signature, hashsign_algorithm = CertHashS
{_, _} -> CertHashSign;
_ -> ConnectionHashSign
end,
- case ssl_handshake:certificate_verify(Signature, PublicKeyInfo,
+ case tls_handshake:certificate_verify(Signature, PublicKeyInfo,
Version, HashSign, MasterSecret, Handshake) of
valid ->
{Record, State} = next_record(State0),
@@ -792,7 +791,7 @@ cipher(#finished{verify_data = Data} = Finished,
= Session0,
connection_states = ConnectionStates0,
tls_handshake_history = Handshake0} = State) ->
- case ssl_handshake:verify_connection(Version, Finished,
+ case tls_handshake:verify_connection(Version, Finished,
opposite_role(Role),
get_current_connection_state_prf(ConnectionStates0, read),
MasterSecret, Handshake0) of
@@ -830,7 +829,7 @@ connection(#hello_request{}, #state{host = Host, port = Port,
connection_states = ConnectionStates0,
renegotiation = {Renegotiation, _},
tls_handshake_history = Handshake0} = State0) ->
- Hello = ssl_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
+ Hello = tls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
Cache, CacheCb, Renegotiation, Cert),
{BinMsg, ConnectionStates, Handshake} =
@@ -1025,7 +1024,7 @@ handle_sync_event({prf, Secret, Label, Seed, WantedLength}, _, StateName,
#state{connection_states = ConnectionStates,
negotiated_version = Version} = State) ->
ConnectionState =
- ssl_record:current_connection_state(ConnectionStates, read),
+ tls_record:current_connection_state(ConnectionStates, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{master_secret = MasterSecret,
client_random = ClientRandom,
@@ -1040,7 +1039,7 @@ handle_sync_event({prf, Secret, Label, Seed, WantedLength}, _, StateName,
(client_random, Acc) -> [ClientRandom|Acc];
(server_random, Acc) -> [ServerRandom|Acc]
end, [], Seed)),
- ssl_handshake:prf(Version, SecretToUse, Label, SeedToUse, WantedLength)
+ tls_handshake:prf(Version, SecretToUse, Label, SeedToUse, WantedLength)
catch
exit:_ -> {error, badarg};
error:Reason -> {error, Reason}
@@ -1051,7 +1050,7 @@ handle_sync_event(info, _, StateName,
#state{negotiated_version = Version,
session = #session{cipher_suite = Suite}} = State) ->
- AtomVersion = ssl_record:protocol_version(Version),
+ AtomVersion = tls_record:protocol_version(Version),
{reply, {ok, {AtomVersion, ssl:suite_definition(Suite)}},
StateName, State, get_timeout(State)};
@@ -1397,7 +1396,7 @@ certify_client(#state{client_certificate_requested = true, role = client,
session = #session{own_certificate = OwnCert},
socket = Socket,
tls_handshake_history = Handshake0} = State) ->
- Certificate = ssl_handshake:certificate(OwnCert, CertDbHandle, CertDbRef, client),
+ Certificate = tls_handshake:certificate(OwnCert, CertDbHandle, CertDbRef, client),
{BinCert, ConnectionStates, Handshake} =
encode_handshake(Certificate, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinCert),
@@ -1418,7 +1417,7 @@ verify_client_cert(#state{client_certificate_requested = true, role = client,
tls_handshake_history = Handshake0} = State) ->
%%TODO: for TLS 1.2 we can choose a different/stronger HashSign combination for this.
- case ssl_handshake:client_certificate_verify(OwnCert, MasterSecret,
+ case tls_handshake:client_certificate_verify(OwnCert, MasterSecret,
Version, HashSign, PrivateKey, Handshake0) of
#certificate_verify{} = Verified ->
{BinVerified, ConnectionStates, Handshake} =
@@ -1444,7 +1443,7 @@ do_server_hello(Type, NextProtocolsToSend,
= State0) when is_atom(Type) ->
ServerHello =
- ssl_handshake:server_hello(SessId, Version,
+ tls_handshake:server_hello(SessId, Version,
ConnectionStates0, Renegotiation,
NextProtocolsToSend, EcPointFormats, EllipticCurves),
State = server_hello(ServerHello,
@@ -1480,7 +1479,7 @@ resumed_server_hello(#state{session = Session,
connection_states = ConnectionStates0,
negotiated_version = Version} = State0) ->
- case ssl_handshake:master_secret(Version, Session,
+ case tls_handshake:master_secret(Version, Session,
ConnectionStates0, server) of
{_, ConnectionStates1} ->
State1 = State0#state{connection_states = ConnectionStates1,
@@ -1509,7 +1508,7 @@ handle_resumed_session(SessId, #state{connection_states = ConnectionStates0,
session_cache = Cache,
session_cache_cb = CacheCb} = State0) ->
Session = CacheCb:lookup(Cache, {{Host, Port}, SessId}),
- case ssl_handshake:master_secret(Version, Session,
+ case tls_handshake:master_secret(Version, Session,
ConnectionStates0, client) of
{_, ConnectionStates} ->
{Record, State} =
@@ -1569,7 +1568,7 @@ server_hello_done(#state{transport_cb = Transport,
connection_states = ConnectionStates0,
tls_handshake_history = Handshake0} = State) ->
- HelloDone = ssl_handshake:server_hello_done(),
+ HelloDone = tls_handshake:server_hello_done(),
{BinHelloDone, ConnectionStates, Handshake} =
encode_handshake(HelloDone, Version, ConnectionStates0, Handshake0),
@@ -1589,7 +1588,7 @@ certify_server(#state{transport_cb = Transport,
cert_db = CertDbHandle,
cert_db_ref = CertDbRef,
session = #session{own_certificate = OwnCert}} = State) ->
- case ssl_handshake:certificate(OwnCert, CertDbHandle, CertDbRef, server) of
+ case tls_handshake:certificate(OwnCert, CertDbHandle, CertDbRef, server) of
CertMsg = #certificate{} ->
{BinCertMsg, ConnectionStates, Handshake} =
encode_handshake(CertMsg, Version, ConnectionStates0, Handshake0),
@@ -1618,11 +1617,11 @@ key_exchange(#state{role = server, key_algorithm = Algo,
Algo == dh_anon ->
DHKeys = public_key:generate_key(Params),
ConnectionState =
- ssl_record:pending_connection_state(ConnectionStates0, read),
+ tls_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {dh, DHKeys, Params,
+ Msg = tls_handshake:key_exchange(server, Version, {dh, DHKeys, Params,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
@@ -1650,11 +1649,11 @@ key_exchange(#state{role = server, key_algorithm = Algo,
ECDHKeys = public_key:generate_key(select_curve(State)),
ConnectionState =
- ssl_record:pending_connection_state(ConnectionStates0, read),
+ tls_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {ecdh, ECDHKeys,
+ Msg = tls_handshake:key_exchange(server, Version, {ecdh, ECDHKeys,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
@@ -1679,14 +1678,14 @@ key_exchange(#state{role = server, key_algorithm = psk,
transport_cb = Transport
} = State) ->
ConnectionState =
- ssl_record:pending_connection_state(ConnectionStates0, read),
+ tls_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {psk, PskIdentityHint,
- HashSignAlgo, ClientRandom,
- ServerRandom,
- PrivateKey}),
+ Msg = tls_handshake:key_exchange(server, Version, {psk, PskIdentityHint,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
{BinMsg, ConnectionStates, Handshake} =
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
@@ -1706,11 +1705,11 @@ key_exchange(#state{role = server, key_algorithm = dhe_psk,
} = State) ->
DHKeys = public_key:generate_key(Params),
ConnectionState =
- ssl_record:pending_connection_state(ConnectionStates0, read),
+ tls_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {dhe_psk, PskIdentityHint, DHKeys, Params,
+ Msg = tls_handshake:key_exchange(server, Version, {dhe_psk, PskIdentityHint, DHKeys, Params,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
@@ -1735,11 +1734,11 @@ key_exchange(#state{role = server, key_algorithm = rsa_psk,
transport_cb = Transport
} = State) ->
ConnectionState =
- ssl_record:pending_connection_state(ConnectionStates0, read),
+ tls_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {psk, PskIdentityHint,
+ Msg = tls_handshake:key_exchange(server, Version, {psk, PskIdentityHint,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
@@ -1771,11 +1770,11 @@ key_exchange(#state{role = server, key_algorithm = Algo,
Keys0
end,
ConnectionState =
- ssl_record:pending_connection_state(ConnectionStates0, read),
+ tls_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {srp, Keys, SrpParams,
+ Msg = tls_handshake:key_exchange(server, Version, {srp, Keys, SrpParams,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
@@ -1811,7 +1810,7 @@ key_exchange(#state{role = client,
when Algorithm == dhe_dss;
Algorithm == dhe_rsa;
Algorithm == dh_anon ->
- Msg = ssl_handshake:key_exchange(client, Version, {dh, DhPubKey}),
+ Msg = tls_handshake:key_exchange(client, Version, {dh, DhPubKey}),
{BinMsg, ConnectionStates, Handshake} =
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
@@ -1828,7 +1827,7 @@ key_exchange(#state{role = client,
when Algorithm == ecdhe_ecdsa; Algorithm == ecdhe_rsa;
Algorithm == ecdh_ecdsa; Algorithm == ecdh_rsa;
Algorithm == ecdh_anon ->
- Msg = ssl_handshake:key_exchange(client, Version, {ecdh, Keys}),
+ Msg = tls_handshake:key_exchange(client, Version, {ecdh, Keys}),
{BinMsg, ConnectionStates, Handshake} =
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
@@ -1842,7 +1841,7 @@ key_exchange(#state{role = client,
negotiated_version = Version,
socket = Socket, transport_cb = Transport,
tls_handshake_history = Handshake0} = State) ->
- Msg = ssl_handshake:key_exchange(client, Version, {psk, SslOpts#ssl_options.psk_identity}),
+ Msg = tls_handshake:key_exchange(client, Version, {psk, SslOpts#ssl_options.psk_identity}),
{BinMsg, ConnectionStates, Handshake} =
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
@@ -1857,7 +1856,7 @@ key_exchange(#state{role = client,
diffie_hellman_keys = {DhPubKey, _},
socket = Socket, transport_cb = Transport,
tls_handshake_history = Handshake0} = State) ->
- Msg = ssl_handshake:key_exchange(client, Version, {dhe_psk, SslOpts#ssl_options.psk_identity, DhPubKey}),
+ Msg = tls_handshake:key_exchange(client, Version, {dhe_psk, SslOpts#ssl_options.psk_identity, DhPubKey}),
{BinMsg, ConnectionStates, Handshake} =
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
@@ -1890,7 +1889,7 @@ key_exchange(#state{role = client,
when Algorithm == srp_dss;
Algorithm == srp_rsa;
Algorithm == srp_anon ->
- Msg = ssl_handshake:key_exchange(client, Version, {srp, ClientPubKey}),
+ Msg = tls_handshake:key_exchange(client, Version, {srp, ClientPubKey}),
{BinMsg, ConnectionStates, Handshake} =
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
@@ -1907,7 +1906,7 @@ rsa_key_exchange(Version, PremasterSecret, PublicKeyInfo = {Algorithm, _, _})
Algorithm == ?sha384WithRSAEncryption;
Algorithm == ?sha512WithRSAEncryption
->
- ssl_handshake:key_exchange(client, Version,
+ tls_handshake:key_exchange(client, Version,
{premaster_secret, PremasterSecret,
PublicKeyInfo});
rsa_key_exchange(_, _, _) ->
@@ -1923,7 +1922,7 @@ rsa_psk_key_exchange(Version, PskIdentity, PremasterSecret, PublicKeyInfo = {Alg
Algorithm == ?sha384WithRSAEncryption;
Algorithm == ?sha512WithRSAEncryption
->
- ssl_handshake:key_exchange(client, Version,
+ tls_handshake:key_exchange(client, Version,
{psk_premaster_secret, PskIdentity, PremasterSecret,
PublicKeyInfo});
rsa_psk_key_exchange(_, _, _, _) ->
@@ -1937,7 +1936,7 @@ request_client_cert(#state{ssl_options = #ssl_options{verify = verify_peer},
negotiated_version = Version,
socket = Socket,
transport_cb = Transport} = State) ->
- Msg = ssl_handshake:certificate_request(ConnectionStates0, CertDbHandle, CertDbRef),
+ Msg = tls_handshake:certificate_request(ConnectionStates0, CertDbHandle, CertDbRef),
{BinMsg, ConnectionStates, Handshake} =
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
@@ -1952,7 +1951,7 @@ finalize_handshake(State, StateName) ->
ConnectionStates0 = cipher_protocol(State),
ConnectionStates =
- ssl_record:activate_pending_connection_state(ConnectionStates0,
+ tls_record:activate_pending_connection_state(ConnectionStates0,
write),
State1 = State#state{connection_states = ConnectionStates},
@@ -1970,7 +1969,7 @@ next_protocol(#state{transport_cb = Transport, socket = Socket,
next_protocol = NextProtocol,
connection_states = ConnectionStates0,
tls_handshake_history = Handshake0} = State) ->
- NextProtocolMessage = ssl_handshake:next_protocol(NextProtocol),
+ NextProtocolMessage = tls_handshake:next_protocol(NextProtocol),
{BinMsg, ConnectionStates, Handshake} = encode_handshake(NextProtocolMessage, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
State#state{connection_states = ConnectionStates,
@@ -1992,7 +1991,7 @@ finished(#state{role = Role, socket = Socket, negotiated_version = Version,
connection_states = ConnectionStates0,
tls_handshake_history = Handshake0}, StateName) ->
MasterSecret = Session#session.master_secret,
- Finished = ssl_handshake:finished(Version, Role,
+ Finished = tls_handshake:finished(Version, Role,
get_current_connection_state_prf(ConnectionStates0, write),
MasterSecret, Handshake0),
ConnectionStates1 = save_verify_data(Role, Finished, ConnectionStates0, StateName),
@@ -2002,18 +2001,18 @@ finished(#state{role = Role, socket = Socket, negotiated_version = Version,
{ConnectionStates, Handshake}.
save_verify_data(client, #finished{verify_data = Data}, ConnectionStates, certify) ->
- ssl_record:set_client_verify_data(current_write, Data, ConnectionStates);
+ tls_record:set_client_verify_data(current_write, Data, ConnectionStates);
save_verify_data(server, #finished{verify_data = Data}, ConnectionStates, cipher) ->
- ssl_record:set_server_verify_data(current_both, Data, ConnectionStates);
+ tls_record:set_server_verify_data(current_both, Data, ConnectionStates);
save_verify_data(client, #finished{verify_data = Data}, ConnectionStates, abbreviated) ->
- ssl_record:set_client_verify_data(current_both, Data, ConnectionStates);
+ tls_record:set_client_verify_data(current_both, Data, ConnectionStates);
save_verify_data(server, #finished{verify_data = Data}, ConnectionStates, abbreviated) ->
- ssl_record:set_server_verify_data(current_write, Data, ConnectionStates).
+ tls_record:set_server_verify_data(current_write, Data, ConnectionStates).
handle_server_key(#server_key_exchange{exchange_keys = Keys},
#state{key_algorithm = KeyAlg,
negotiated_version = Version} = State) ->
- Params = ssl_handshake:decode_server_key(Keys, KeyAlg, Version),
+ Params = tls_handshake:decode_server_key(Keys, KeyAlg, Version),
HashSign = connection_hashsign(Params#server_key_params.hashsign, State),
case HashSign of
{_, SignAlgo} when SignAlgo == anon; SignAlgo == ecdh_anon ->
@@ -2030,15 +2029,15 @@ verify_server_key(#server_key_params{params = Params,
public_key_info = PubKeyInfo,
connection_states = ConnectionStates} = State) ->
ConnectionState =
- ssl_record:pending_connection_state(ConnectionStates, read),
+ tls_record:pending_connection_state(ConnectionStates, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Hash = ssl_handshake:server_key_exchange_hash(HashAlgo,
+ Hash = tls_handshake:server_key_exchange_hash(HashAlgo,
<<ClientRandom/binary,
ServerRandom/binary,
EncParams/binary>>),
- case ssl_handshake:verify_signature(Version, Hash, HashSign, Signature, PubKeyInfo) of
+ case tls_handshake:verify_signature(Version, Hash, HashSign, Signature, PubKeyInfo) of
true ->
server_master_secret(Params, State);
false ->
@@ -2074,7 +2073,7 @@ master_from_premaster_secret(PremasterSecret,
#state{session = Session,
negotiated_version = Version, role = Role,
connection_states = ConnectionStates0} = State) ->
- case ssl_handshake:master_secret(Version, PremasterSecret,
+ case tls_handshake:master_secret(Version, PremasterSecret,
ConnectionStates0, Role) of
{MasterSecret, ConnectionStates} ->
State#state{
@@ -2227,12 +2226,12 @@ client_srp_master_secret(Generator, Prime, Salt, ServerPub, ClientKeys,
end.
cipher_role(client, Data, Session, #state{connection_states = ConnectionStates0} = State) ->
- ConnectionStates = ssl_record:set_server_verify_data(current_both, Data, ConnectionStates0),
+ ConnectionStates = tls_record:set_server_verify_data(current_both, Data, ConnectionStates0),
next_state_connection(cipher, ack_connection(State#state{session = Session,
connection_states = ConnectionStates}));
cipher_role(server, Data, Session, #state{connection_states = ConnectionStates0} = State) ->
- ConnectionStates1 = ssl_record:set_client_verify_data(current_read, Data, ConnectionStates0),
+ ConnectionStates1 = tls_record:set_client_verify_data(current_read, Data, ConnectionStates0),
{ConnectionStates, Handshake} =
finalize_handshake(State#state{connection_states = ConnectionStates1,
session = Session}, cipher),
@@ -2242,16 +2241,16 @@ cipher_role(server, Data, Session, #state{connection_states = ConnectionStates0
tls_handshake_history =
Handshake})).
encode_alert(#alert{} = Alert, Version, ConnectionStates) ->
- ssl_record:encode_alert_record(Alert, Version, ConnectionStates).
+ tls_record:encode_alert_record(Alert, Version, ConnectionStates).
encode_change_cipher(#change_cipher_spec{}, Version, ConnectionStates) ->
- ssl_record:encode_change_cipher_spec(Version, ConnectionStates).
+ tls_record:encode_change_cipher_spec(Version, ConnectionStates).
encode_handshake(HandshakeRec, Version, ConnectionStates0, Handshake0) ->
- Frag = ssl_handshake:encode_handshake(HandshakeRec, Version),
- Handshake1 = ssl_handshake:update_handshake_history(Handshake0, Frag),
+ Frag = tls_handshake:encode_handshake(HandshakeRec, Version),
+ Handshake1 = tls_handshake:update_handshake_history(Handshake0, Frag),
{E, ConnectionStates1} =
- ssl_record:encode_handshake(Frag, Version, ConnectionStates0),
+ tls_record:encode_handshake(Frag, Version, ConnectionStates0),
{E, ConnectionStates1, Handshake1}.
encode_packet(Data, #socket_options{packet=Packet}) ->
@@ -2346,7 +2345,7 @@ write_application_data(Data0, From, #state{socket = Socket,
renegotiate(State#state{send_queue = queue:in_r({From, Data}, SendQueue),
renegotiation = {true, internal}});
false ->
- {Msgs, ConnectionStates} = ssl_record:encode_data(Data, Version, ConnectionStates0),
+ {Msgs, ConnectionStates} = tls_record:encode_data(Data, Version, ConnectionStates0),
Result = Transport:send(Socket, Msgs),
{reply, Result,
connection, State#state{connection_states = ConnectionStates}, get_timeout(State)}
@@ -2514,7 +2513,7 @@ next_state(Current, Next, #ssl_tls{type = ?HANDSHAKE, fragment = Data},
fun({#hello_request{} = Packet, _}, {next_state, connection = SName, State}) ->
%% This message should not be included in handshake
%% message hashes. Starts new handshake (renegotiation)
- Hs0 = ssl_handshake:init_handshake_history(),
+ Hs0 = tls_handshake:init_handshake_history(),
?MODULE:SName(Packet, State#state{tls_handshake_history=Hs0,
renegotiation = {true, peer}});
({#hello_request{} = Packet, _}, {next_state, SName, State}) ->
@@ -2523,17 +2522,17 @@ next_state(Current, Next, #ssl_tls{type = ?HANDSHAKE, fragment = Data},
?MODULE:SName(Packet, State);
({#client_hello{} = Packet, Raw}, {next_state, connection = SName, State}) ->
Version = Packet#client_hello.client_version,
- Hs0 = ssl_handshake:init_handshake_history(),
- Hs1 = ssl_handshake:update_handshake_history(Hs0, Raw),
+ Hs0 = tls_handshake:init_handshake_history(),
+ Hs1 = tls_handshake:update_handshake_history(Hs0, Raw),
?MODULE:SName(Packet, State#state{tls_handshake_history=Hs1,
renegotiation = {true, peer}});
({Packet, Raw}, {next_state, SName, State = #state{tls_handshake_history=Hs0}}) ->
- Hs1 = ssl_handshake:update_handshake_history(Hs0, Raw),
+ Hs1 = tls_handshake:update_handshake_history(Hs0, Raw),
?MODULE:SName(Packet, State#state{tls_handshake_history=Hs1});
(_, StopState) -> StopState
end,
try
- {Packets, Buf} = ssl_handshake:get_tls_handshake(Version,Data,Buf0),
+ {Packets, Buf} = tls_handshake:get_tls_handshake(Version,Data,Buf0),
State = State0#state{tls_packets = Packets, tls_handshake_buffer = Buf},
handle_tls_handshake(Handle, Next, State)
catch throw:#alert{} = Alert ->
@@ -2551,7 +2550,7 @@ next_state(Current, Next, #ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = <<1>>}
_ChangeCipher,
#state{connection_states = ConnectionStates0} = State0) ->
ConnectionStates1 =
- ssl_record:activate_pending_connection_state(ConnectionStates0, read),
+ tls_record:activate_pending_connection_state(ConnectionStates0, read),
{Record, State} = next_record(State0#state{connection_states = ConnectionStates1}),
next_state(Current, Next, Record, State);
next_state(Current, Next, #ssl_tls{type = _Unknown}, State0) ->
@@ -2561,7 +2560,7 @@ next_state(Current, Next, #ssl_tls{type = _Unknown}, State0) ->
next_tls_record(Data, #state{tls_record_buffer = Buf0,
tls_cipher_texts = CT0} = State0) ->
- case ssl_record:get_tls_records(Data, Buf0) of
+ case tls_record:get_tls_records(Data, Buf0) of
{Records, Buf1} ->
CT1 = CT0 ++ Records,
next_record(State0#state{tls_record_buffer = Buf1,
@@ -2576,7 +2575,7 @@ next_record(#state{tls_packets = [], tls_cipher_texts = [], socket = Socket,
{no_record, State};
next_record(#state{tls_packets = [], tls_cipher_texts = [CT | Rest],
connection_states = ConnStates0} = State) ->
- case ssl_record:decode_cipher_text(CT, ConnStates0) of
+ case tls_record:decode_cipher_text(CT, ConnStates0) of
{Plain, ConnStates} ->
{Plain, State#state{tls_cipher_texts = Rest, connection_states = ConnStates}};
#alert{} = Alert ->
@@ -2603,7 +2602,7 @@ next_state_connection(StateName, #state{send_queue = Queue0,
case queue:out(Queue0) of
{{value, {From, Data}}, Queue} ->
{Msgs, ConnectionStates} =
- ssl_record:encode_data(Data, Version, ConnectionStates0),
+ tls_record:encode_data(Data, Version, ConnectionStates0),
Result = Transport:send(Socket, Msgs),
gen_fsm:reply(From, Result),
next_state_connection(StateName,
@@ -2622,13 +2621,13 @@ next_state_is_connection(_, State =
#socket_options{active = false}}) when RecvFrom =/= undefined ->
passive_receive(State#state{premaster_secret = undefined,
public_key_info = undefined,
- tls_handshake_history = ssl_handshake:init_handshake_history()}, connection);
+ tls_handshake_history = tls_handshake:init_handshake_history()}, connection);
next_state_is_connection(StateName, State0) ->
{Record, State} = next_record_if_active(State0),
next_state(StateName, connection, Record, State#state{premaster_secret = undefined,
public_key_info = undefined,
- tls_handshake_history = ssl_handshake:init_handshake_history()}).
+ tls_handshake_history = tls_handshake:init_handshake_history()}).
register_session(client, Host, Port, #session{is_resumable = new} = Session0) ->
Session = Session0#session{is_resumable = true},
@@ -2648,7 +2647,7 @@ invalidate_session(server, _, Port, Session) ->
initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions}, User,
{CbModule, DataTag, CloseTag, ErrorTag}) ->
- ConnectionStates = ssl_record:init_connection_states(Role),
+ ConnectionStates = tls_record:init_connection_states(Role),
SessionCacheCb = case application:get_env(ssl, session_cb) of
{ok, Cb} when is_atom(Cb) ->
@@ -2905,18 +2904,18 @@ ack_connection(State) ->
renegotiate(#state{role = client} = State) ->
%% Handle same way as if server requested
%% the renegotiation
- Hs0 = ssl_handshake:init_handshake_history(),
+ Hs0 = tls_handshake:init_handshake_history(),
connection(#hello_request{}, State#state{tls_handshake_history = Hs0});
renegotiate(#state{role = server,
socket = Socket,
transport_cb = Transport,
negotiated_version = Version,
connection_states = ConnectionStates0} = State0) ->
- HelloRequest = ssl_handshake:hello_request(),
- Frag = ssl_handshake:encode_handshake(HelloRequest, Version),
- Hs0 = ssl_handshake:init_handshake_history(),
+ HelloRequest = tls_handshake:hello_request(),
+ Frag = tls_handshake:encode_handshake(HelloRequest, Version),
+ Hs0 = tls_handshake:init_handshake_history(),
{BinMsg, ConnectionStates} =
- ssl_record:encode_handshake(Frag, Version, ConnectionStates0),
+ tls_record:encode_handshake(Frag, Version, ConnectionStates0),
Transport:send(Socket, BinMsg),
{Record, State} = next_record(State0#state{connection_states =
ConnectionStates,
@@ -2976,14 +2975,14 @@ handle_trusted_certs_db(#state{cert_db_ref = Ref,
ssl_options = #ssl_options{cacertfile = undefined}}) ->
%% Certs provided as DER directly can not be shared
%% with other connections and it is safe to delete them when the connection ends.
- ssl_certificate_db:remove_trusted_certs(Ref, CertDb);
+ ssl_pkix_db:remove_trusted_certs(Ref, CertDb);
handle_trusted_certs_db(#state{file_ref_db = undefined}) ->
%% Something went wrong early (typically cacertfile does not exist) so there is nothing to handle
ok;
handle_trusted_certs_db(#state{cert_db_ref = Ref,
file_ref_db = RefDb,
ssl_options = #ssl_options{cacertfile = File}}) ->
- case ssl_certificate_db:ref_count(Ref, RefDb, -1) of
+ case ssl_pkix_db:ref_count(Ref, RefDb, -1) of
0 ->
ssl_manager:clean_cert_db(Ref, File);
_ ->
@@ -2991,10 +2990,10 @@ handle_trusted_certs_db(#state{cert_db_ref = Ref,
end.
get_current_connection_state_prf(CStates, Direction) ->
- CS = ssl_record:current_connection_state(CStates, Direction),
+ CS = tls_record:current_connection_state(CStates, Direction),
CS#connection_state.security_parameters#security_parameters.prf_algorithm.
get_pending_connection_state_prf(CStates, Direction) ->
- CS = ssl_record:pending_connection_state(CStates, Direction),
+ CS = tls_record:pending_connection_state(CStates, Direction),
CS#connection_state.security_parameters#security_parameters.prf_algorithm.
connection_hashsign(HashSign = {_, _}, _State) ->
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/tls_handshake.erl
index 24ea86311f..51fd2e1dc9 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/tls_handshake.erl
@@ -21,10 +21,10 @@
%% Purpose: Help funtions for handling the SSL-handshake protocol
%%----------------------------------------------------------------------
--module(ssl_handshake).
+-module(tls_handshake).
--include("ssl_handshake.hrl").
--include("ssl_record.hrl").
+-include("tls_handshake.hrl").
+-include("tls_record.hrl").
-include("ssl_cipher.hrl").
-include("ssl_alert.hrl").
-include("ssl_internal.hrl").
@@ -64,8 +64,8 @@ client_hello(Host, Port, ConnectionStates,
ciphers = UserSuites
} = SslOpts,
Cache, CacheCb, Renegotiation, OwnCert) ->
- Version = ssl_record:highest_protocol_version(Versions),
- Pending = ssl_record:pending_connection_state(ConnectionStates, read),
+ Version = tls_record:highest_protocol_version(Versions),
+ Pending = tls_record:pending_connection_state(ConnectionStates, read),
SecParams = Pending#connection_state.security_parameters,
Ciphers = available_suites(UserSuites, Version),
SRP = srp_user(SslOpts),
@@ -76,7 +76,7 @@ client_hello(Host, Port, ConnectionStates,
#client_hello{session_id = Id,
client_version = Version,
cipher_suites = cipher_suites(Ciphers, Renegotiation),
- compression_methods = ssl_record:compressions(),
+ compression_methods = tls_record:compressions(),
random = SecParams#security_parameters.client_random,
renegotiation_info =
@@ -109,7 +109,7 @@ encode_protocols_advertised_on_server(Protocols) ->
%%--------------------------------------------------------------------
server_hello(SessionId, Version, ConnectionStates, Renegotiation,
ProtocolsAdvertisedOnServer, EcPointFormats, EllipticCurves) ->
- Pending = ssl_record:pending_connection_state(ConnectionStates, read),
+ Pending = tls_record:pending_connection_state(ConnectionStates, read),
SecParams = Pending#connection_state.security_parameters,
#server_hello{server_version = Version,
cipher_suite = SecParams#security_parameters.cipher_suite,
@@ -153,7 +153,7 @@ hello(#server_hello{cipher_suite = CipherSuite, server_version = Version,
versions = SupportedVersions},
ConnectionStates0, Renegotiation) ->
%%TODO: select hash and signature algorigthm
- case ssl_record:is_acceptable_version(Version, SupportedVersions) of
+ case tls_record:is_acceptable_version(Version, SupportedVersions) of
true ->
case handle_renegotiation_info(client, Info, ConnectionStates0,
Renegotiation, SecureRenegotation, []) of
@@ -179,7 +179,7 @@ hello(#client_hello{client_version = ClientVersion} = Hello,
{Port, Session0, Cache, CacheCb, ConnectionStates0, Cert}, Renegotiation) ->
%% TODO: select hash and signature algorithm
Version = select_version(ClientVersion, Versions),
- case ssl_record:is_acceptable_version(Version, Versions) of
+ case tls_record:is_acceptable_version(Version, Versions) of
true ->
%% TODO: need to take supported Curves into Account when selecting the CipherSuite....
%% if whe have an ECDSA cert with an unsupported curve, we need to drop ECDSA ciphers
@@ -357,7 +357,7 @@ verify_signature(_Version, Hash, {HashAlgo, ecdsa}, Signature, {?'id-ecPublicKey
certificate_request(ConnectionStates, CertDbHandle, CertDbRef) ->
#connection_state{security_parameters =
#security_parameters{cipher_suite = CipherSuite}} =
- ssl_record:pending_connection_state(ConnectionStates, read),
+ tls_record:pending_connection_state(ConnectionStates, read),
Types = certificate_types(CipherSuite),
HashSigns = default_hash_signs(),
Authorities = certificate_authorities(CertDbHandle, CertDbRef),
@@ -499,7 +499,7 @@ enc_server_key_exchange(Version, Params, {HashAlgo, SignAlgo},
master_secret(Version, #session{master_secret = Mastersecret},
ConnectionStates, Role) ->
ConnectionState =
- ssl_record:pending_connection_state(ConnectionStates, read),
+ tls_record:pending_connection_state(ConnectionStates, read),
SecParams = ConnectionState#connection_state.security_parameters,
try master_secret(Version, Mastersecret, SecParams,
ConnectionStates, Role)
@@ -513,7 +513,7 @@ master_secret(Version, #session{master_secret = Mastersecret},
master_secret(Version, PremasterSecret, ConnectionStates, Role) ->
ConnectionState =
- ssl_record:pending_connection_state(ConnectionStates, read),
+ tls_record:pending_connection_state(ConnectionStates, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{prf_algorithm = PrfAlgo,
client_random = ClientRandom,
@@ -760,7 +760,7 @@ srp_user(_) ->
renegotiation_info(client, _, false) ->
#renegotiation_info{renegotiated_connection = undefined};
renegotiation_info(server, ConnectionStates, false) ->
- CS = ssl_record:current_connection_state(ConnectionStates, read),
+ CS = tls_record:current_connection_state(ConnectionStates, read),
case CS#connection_state.secure_renegotiation of
true ->
#renegotiation_info{renegotiated_connection = ?byte(0)};
@@ -768,7 +768,7 @@ renegotiation_info(server, ConnectionStates, false) ->
#renegotiation_info{renegotiated_connection = undefined}
end;
renegotiation_info(client, ConnectionStates, true) ->
- CS = ssl_record:current_connection_state(ConnectionStates, read),
+ CS = tls_record:current_connection_state(ConnectionStates, read),
case CS#connection_state.secure_renegotiation of
true ->
Data = CS#connection_state.client_verify_data,
@@ -778,7 +778,7 @@ renegotiation_info(client, ConnectionStates, true) ->
end;
renegotiation_info(server, ConnectionStates, true) ->
- CS = ssl_record:current_connection_state(ConnectionStates, read),
+ CS = tls_record:current_connection_state(ConnectionStates, read),
case CS#connection_state.secure_renegotiation of
true ->
CData = CS#connection_state.client_verify_data,
@@ -866,29 +866,29 @@ handle_ecc_point_fmt_extension(undefined) ->
handle_ecc_point_fmt_extension(_) ->
#ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]}.
-handle_ecc_curves_extension(Version, undefined) ->
+handle_ecc_curves_extension(_Version, undefined) ->
undefined;
handle_ecc_curves_extension(Version, _) ->
#elliptic_curves{elliptic_curve_list = ssl_tls1:ecc_curves(Version)}.
handle_renegotiation_info(_, #renegotiation_info{renegotiated_connection = ?byte(0)},
ConnectionStates, false, _, _) ->
- {ok, ssl_record:set_renegotiation_flag(true, ConnectionStates)};
+ {ok, tls_record:set_renegotiation_flag(true, ConnectionStates)};
handle_renegotiation_info(server, undefined, ConnectionStates, _, _, CipherSuites) ->
case is_member(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV, CipherSuites) of
true ->
- {ok, ssl_record:set_renegotiation_flag(true, ConnectionStates)};
+ {ok, tls_record:set_renegotiation_flag(true, ConnectionStates)};
false ->
- {ok, ssl_record:set_renegotiation_flag(false, ConnectionStates)}
+ {ok, tls_record:set_renegotiation_flag(false, ConnectionStates)}
end;
handle_renegotiation_info(_, undefined, ConnectionStates, false, _, _) ->
- {ok, ssl_record:set_renegotiation_flag(false, ConnectionStates)};
+ {ok, tls_record:set_renegotiation_flag(false, ConnectionStates)};
handle_renegotiation_info(client, #renegotiation_info{renegotiated_connection = ClientServerVerify},
ConnectionStates, true, _, _) ->
- CS = ssl_record:current_connection_state(ConnectionStates, read),
+ CS = tls_record:current_connection_state(ConnectionStates, read),
CData = CS#connection_state.client_verify_data,
SData = CS#connection_state.server_verify_data,
case <<CData/binary, SData/binary>> == ClientServerVerify of
@@ -904,7 +904,7 @@ handle_renegotiation_info(server, #renegotiation_info{renegotiated_connection =
true ->
?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE);
false ->
- CS = ssl_record:current_connection_state(ConnectionStates, read),
+ CS = tls_record:current_connection_state(ConnectionStates, read),
Data = CS#connection_state.client_verify_data,
case Data == ClientVerify of
true ->
@@ -926,7 +926,7 @@ handle_renegotiation_info(server, undefined, ConnectionStates, true, SecureReneg
end.
handle_renegotiation_info(ConnectionStates, SecureRenegotation) ->
- CS = ssl_record:current_connection_state(ConnectionStates, read),
+ CS = tls_record:current_connection_state(ConnectionStates, read),
case {SecureRenegotation, CS#connection_state.secure_renegotiation} of
{_, true} ->
?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE);
@@ -943,9 +943,9 @@ handle_renegotiation_info(ConnectionStates, SecureRenegotation) ->
hello_pending_connection_states(Role, Version, CipherSuite, Random, Compression,
ConnectionStates) ->
ReadState =
- ssl_record:pending_connection_state(ConnectionStates, read),
+ tls_record:pending_connection_state(ConnectionStates, read),
WriteState =
- ssl_record:pending_connection_state(ConnectionStates, write),
+ tls_record:pending_connection_state(ConnectionStates, write),
NewReadSecParams =
hello_security_parameters(Role, Version, ReadState, CipherSuite,
@@ -955,7 +955,7 @@ hello_pending_connection_states(Role, Version, CipherSuite, Random, Compression,
hello_security_parameters(Role, Version, WriteState, CipherSuite,
Random, Compression),
- ssl_record:update_security_params(NewReadSecParams,
+ tls_record:update_security_params(NewReadSecParams,
NewWriteSecParams,
ConnectionStates).
@@ -978,8 +978,8 @@ hello_security_parameters(server, Version, ConnectionState, CipherSuite, Random,
}.
select_version(ClientVersion, Versions) ->
- ServerVersion = ssl_record:highest_protocol_version(Versions),
- ssl_record:lowest_protocol_version(ClientVersion, ServerVersion).
+ ServerVersion = tls_record:highest_protocol_version(Versions),
+ tls_record:lowest_protocol_version(ClientVersion, ServerVersion).
select_cipher_suite([], _) ->
no_suite;
@@ -1011,15 +1011,15 @@ master_secret(Version, MasterSecret, #security_parameters{
setup_keys(Version, PrfAlgo, MasterSecret, ServerRandom,
ClientRandom, HashSize, KML, EKML, IVS),
- ConnStates1 = ssl_record:set_master_secret(MasterSecret, ConnectionStates),
+ ConnStates1 = tls_record:set_master_secret(MasterSecret, ConnectionStates),
ConnStates2 =
- ssl_record:set_mac_secret(ClientWriteMacSecret, ServerWriteMacSecret,
+ tls_record:set_mac_secret(ClientWriteMacSecret, ServerWriteMacSecret,
Role, ConnStates1),
ClientCipherState = #cipher_state{iv = ClientIV, key = ClientWriteKey},
ServerCipherState = #cipher_state{iv = ServerIV, key = ServerWriteKey},
{MasterSecret,
- ssl_record:set_pending_cipher_state(ConnStates2, ClientCipherState,
+ tls_record:set_pending_cipher_state(ConnStates2, ClientCipherState,
ServerCipherState, Role)}.
@@ -1685,7 +1685,7 @@ certificate_authorities_from_db(CertDbHandle, CertDbRef) ->
(_, Acc) ->
Acc
end,
- ssl_certificate_db:foldl(ConnectionCerts, [], CertDbHandle).
+ ssl_pkix_db:foldl(ConnectionCerts, [], CertDbHandle).
digitally_signed({3, Minor}, Hash, HashAlgo, Key) when Minor >= 3 ->
diff --git a/lib/ssl/src/tls_handshake.hrl b/lib/ssl/src/tls_handshake.hrl
new file mode 100644
index 0000000000..abf1b5abb6
--- /dev/null
+++ b/lib/ssl/src/tls_handshake.hrl
@@ -0,0 +1,45 @@
+%%
+%% %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%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Record and constant defenitions for the TLS-handshake protocol
+%% see RFC 5246.
+%%----------------------------------------------------------------------
+-ifndef(tls_handshake).
+-define(tls_handshake, true).
+
+-include("ssl_handshake.hrl"). %% Common TLS and DTLS records and Constantes
+
+-record(client_hello, {
+ client_version,
+ random,
+ session_id, % opaque SessionID<0..32>
+ cipher_suites, % cipher_suites<2..2^16-1>
+ compression_methods, % compression_methods<1..2^8-1>,
+ %% Extensions
+ renegotiation_info,
+ hash_signs, % supported combinations of hashes/signature algos
+ next_protocol_negotiation = undefined, % [binary()]
+ srp,
+ ec_point_formats,
+ elliptic_curves
+ }).
+
+-endif. % -ifdef(tls_handshake).
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/tls_record.erl
index 2a3356d60f..1409a04763 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/tls_record.erl
@@ -23,12 +23,12 @@
%%
%%----------------------------------------------------------------------
--module(ssl_record).
+-module(tls_record).
--include("ssl_record.hrl").
+-include("tls_record.hrl").
-include("ssl_internal.hrl").
-include("ssl_alert.hrl").
--include("ssl_handshake.hrl").
+-include("tls_handshake.hrl").
-include("ssl_cipher.hrl").
%% Connection state handling
diff --git a/lib/ssl/src/tls_record.hrl b/lib/ssl/src/tls_record.hrl
new file mode 100644
index 0000000000..c9350fa137
--- /dev/null
+++ b/lib/ssl/src/tls_record.hrl
@@ -0,0 +1,39 @@
+%%
+%% %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%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Record and constant defenitions for the TLS-record protocol
+%% see RFC 5246
+%%----------------------------------------------------------------------
+
+-ifndef(tls_record).
+-define(tls_record, true).
+
+-include("ssl_record.hrl"). %% Common TLS and DTLS records and Constantes
+
+%% Used to handle tls_plain_text, tls_compressed and tls_cipher_text
+
+-record(ssl_tls, {
+ type,
+ version,
+ fragment
+ }).
+
+-endif. % -ifdef(tls_record).
diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile
index 847907cde8..39aa22ffb4 100644
--- a/lib/ssl/test/Makefile
+++ b/lib/ssl/test/Makefile
@@ -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
@@ -58,8 +58,10 @@ HRL_FILES =
HRL_FILES_SRC = \
ssl_internal.hrl\
ssl_alert.hrl \
+ tls_handshake.hrl \
ssl_handshake.hrl \
ssl_cipher.hrl \
+ tls_record.hrl \
ssl_record.hrl
HRL_FILES_INC =
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index c4a6cf1407..b5cf6d1212 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -30,8 +30,8 @@
-include("ssl_internal.hrl").
-include("ssl_alert.hrl").
-include("ssl_internal.hrl").
--include("ssl_record.hrl").
--include("ssl_handshake.hrl").
+-include("tls_record.hrl").
+-include("tls_handshake.hrl").
-define('24H_in_sec', 86400).
-define(TIMEOUT, 60000).
@@ -190,8 +190,7 @@ init_per_suite(Config0) ->
catch crypto:stop(),
try crypto:start() of
ok ->
- application:start(public_key),
-
+ ssl:start(),
%% make rsa certs using oppenssl
Result =
(catch make_certs:all(?config(data_dir, Config0),
@@ -266,7 +265,7 @@ init_per_testcase(empty_protocol_versions, Config) ->
%% ssl_test_lib:make_mix_cert(Config0);
init_per_testcase(_TestCase, Config0) ->
- ct:log("TLS/SSL version ~p~n ", [ssl_record:supported_protocol_versions()]),
+ ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]),
Config = lists:keydelete(watchdog, 1, Config0),
Dog = ct:timetrap(?TIMEOUT),
[{watchdog, Dog} | Config].
@@ -333,7 +332,7 @@ connection_info(Config) when is_list(Config) ->
[self(), Client, Server]),
Version =
- ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ tls_record:protocol_version(tls_record:highest_protocol_version([])),
ServerMsg = ClientMsg = {ok, {Version, {rsa,rc4_128,sha}}},
@@ -1547,7 +1546,7 @@ ciphers_rsa_signed_certs() ->
ciphers_rsa_signed_certs(Config) when is_list(Config) ->
Version =
- ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ tls_record:protocol_version(tls_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:rsa_suites(crypto),
ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
@@ -1558,7 +1557,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([])),
+ tls_record:protocol_version(tls_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:openssl_rsa_suites(crypto),
ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]),
run_suites(Ciphers, Version, Config, rsa).
@@ -1569,7 +1568,7 @@ ciphers_dsa_signed_certs() ->
ciphers_dsa_signed_certs(Config) when is_list(Config) ->
Version =
- ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ tls_record:protocol_version(tls_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:dsa_suites(),
ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
@@ -1580,7 +1579,7 @@ ciphers_dsa_signed_certs_openssl_names() ->
ciphers_dsa_signed_certs_openssl_names(Config) when is_list(Config) ->
Version =
- ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ tls_record:protocol_version(tls_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:openssl_dsa_suites(),
ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]),
@@ -1589,56 +1588,56 @@ ciphers_dsa_signed_certs_openssl_names(Config) when is_list(Config) ->
anonymous_cipher_suites()->
[{doc,"Test the anonymous ciphersuites"}].
anonymous_cipher_suites(Config) when is_list(Config) ->
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:anonymous_suites(),
run_suites(Ciphers, Version, Config, anonymous).
%%-------------------------------------------------------------------
psk_cipher_suites() ->
[{doc, "Test the PSK ciphersuites WITHOUT server supplied identity hint"}].
psk_cipher_suites(Config) when is_list(Config) ->
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:psk_suites(),
run_suites(Ciphers, Version, Config, psk).
%%-------------------------------------------------------------------
psk_with_hint_cipher_suites()->
[{doc, "Test the PSK ciphersuites WITH server supplied identity hint"}].
psk_with_hint_cipher_suites(Config) when is_list(Config) ->
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:psk_suites(),
run_suites(Ciphers, Version, Config, psk_with_hint).
%%-------------------------------------------------------------------
psk_anon_cipher_suites() ->
[{doc, "Test the anonymous PSK ciphersuites WITHOUT server supplied identity hint"}].
psk_anon_cipher_suites(Config) when is_list(Config) ->
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:psk_anon_suites(),
run_suites(Ciphers, Version, Config, psk_anon).
%%-------------------------------------------------------------------
psk_anon_with_hint_cipher_suites()->
[{doc, "Test the anonymous PSK ciphersuites WITH server supplied identity hint"}].
psk_anon_with_hint_cipher_suites(Config) when is_list(Config) ->
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:psk_anon_suites(),
run_suites(Ciphers, Version, Config, psk_anon_with_hint).
%%-------------------------------------------------------------------
srp_cipher_suites()->
[{doc, "Test the SRP ciphersuites"}].
srp_cipher_suites(Config) when is_list(Config) ->
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:srp_suites(),
run_suites(Ciphers, Version, Config, srp).
%%-------------------------------------------------------------------
srp_anon_cipher_suites()->
[{doc, "Test the anonymous SRP ciphersuites"}].
srp_anon_cipher_suites(Config) when is_list(Config) ->
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:srp_anon_suites(),
run_suites(Ciphers, Version, Config, srp_anon).
%%-------------------------------------------------------------------
srp_dsa_cipher_suites()->
[{doc, "Test the SRP DSA ciphersuites"}].
srp_dsa_cipher_suites(Config) when is_list(Config) ->
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:srp_dss_suites(),
run_suites(Ciphers, Version, Config, srp_dsa).
%%--------------------------------------------------------------------
@@ -1671,7 +1670,7 @@ ciphers_ecdsa_signed_certs() ->
ciphers_ecdsa_signed_certs(Config) when is_list(Config) ->
Version =
- ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ tls_record:protocol_version(tls_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:ecdsa_suites(),
ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
@@ -1682,7 +1681,7 @@ ciphers_ecdsa_signed_certs_openssl_names() ->
ciphers_ecdsa_signed_certs_openssl_names(Config) when is_list(Config) ->
Version =
- ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ tls_record:protocol_version(tls_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:openssl_ecdsa_suites(),
ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]),
run_suites(Ciphers, Version, Config, ecdsa).
@@ -1692,7 +1691,7 @@ ciphers_ecdh_rsa_signed_certs() ->
ciphers_ecdh_rsa_signed_certs(Config) when is_list(Config) ->
Version =
- ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ tls_record:protocol_version(tls_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:ecdh_rsa_suites(),
ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
@@ -1703,7 +1702,7 @@ ciphers_ecdh_rsa_signed_certs_openssl_names() ->
ciphers_ecdh_rsa_signed_certs_openssl_names(Config) when is_list(Config) ->
Version =
- ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ tls_record:protocol_version(tls_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:openssl_ecdh_rsa_suites(),
ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]),
run_suites(Ciphers, Version, Config, ecdh_rsa).
@@ -2084,7 +2083,7 @@ client_no_wrap_sequence_number(Config) when is_list(Config) ->
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
- Version = ssl_record:highest_protocol_version(ssl_record:supported_protocol_versions()),
+ Version = tls_record:highest_protocol_version(tls_record:supported_protocol_versions()),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
index 2703d2d79c..f76c55f670 100644
--- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl
+++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
@@ -29,8 +29,8 @@
-include("ssl_internal.hrl").
-include("ssl_alert.hrl").
-include("ssl_internal.hrl").
--include("ssl_record.hrl").
--include("ssl_handshake.hrl").
+-include("tls_record.hrl").
+-include("tls_handshake.hrl").
-define(LONG_TIMEOUT, 600000).
@@ -80,8 +80,7 @@ init_per_suite(Config0) ->
catch crypto:stop(),
try crypto:start() of
ok ->
- application:start(public_key),
- application:start(ssl),
+ ssl:start(),
%% make rsa certs using oppenssl
Result =
(catch make_certs:all(?config(data_dir, Config0),
diff --git a/lib/ssl/test/ssl_cipher_SUITE.erl b/lib/ssl/test/ssl_cipher_SUITE.erl
index 9869812e6e..45e91786d4 100644
--- a/lib/ssl/test/ssl_cipher_SUITE.erl
+++ b/lib/ssl/test/ssl_cipher_SUITE.erl
@@ -25,7 +25,7 @@
-include_lib("common_test/include/ct.hrl").
-include("ssl_internal.hrl").
--include("ssl_record.hrl").
+-include("tls_record.hrl").
-include("ssl_cipher.hrl").
-include("ssl_alert.hrl").
diff --git a/lib/ssl/test/ssl_handshake_SUITE.erl b/lib/ssl/test/ssl_handshake_SUITE.erl
index aff0e0fbbc..a40f07fd07 100644
--- a/lib/ssl/test/ssl_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_handshake_SUITE.erl
@@ -25,7 +25,7 @@
-include_lib("common_test/include/ct.hrl").
-include("ssl_internal.hrl").
--include("ssl_handshake.hrl").
+-include("tls_handshake.hrl").
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
@@ -55,20 +55,20 @@ decode_hello_handshake(_Config) ->
16#70, 16#64, 16#79, 16#2f, 16#32>>,
Version = {3, 0},
- {Records, _Buffer} = ssl_handshake:get_tls_handshake(Version, HelloPacket, <<>>),
+ {Records, _Buffer} = tls_handshake:get_tls_handshake(Version, HelloPacket, <<>>),
{Hello, _Data} = hd(Records),
#renegotiation_info{renegotiated_connection = <<0>>} = Hello#server_hello.renegotiation_info.
decode_single_hello_extension_correctly(_Config) ->
Renegotiation = <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(1), 0>>,
- Extensions = ssl_handshake:dec_hello_extensions(Renegotiation, []),
+ Extensions = tls_handshake:dec_hello_extensions(Renegotiation, []),
[{renegotiation_info,#renegotiation_info{renegotiated_connection = <<0>>}}] = Extensions.
decode_unknown_hello_extension_correctly(_Config) ->
FourByteUnknown = <<16#CA,16#FE, ?UINT16(4), 3, 0, 1, 2>>,
Renegotiation = <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(1), 0>>,
- Extensions = ssl_handshake:dec_hello_extensions(<<FourByteUnknown/binary, Renegotiation/binary>>, []),
+ Extensions = tls_handshake:dec_hello_extensions(<<FourByteUnknown/binary, Renegotiation/binary>>, []),
[{renegotiation_info,#renegotiation_info{renegotiated_connection = <<0>>}}] = Extensions.
diff --git a/lib/ssl/test/ssl_npn_handshake_SUITE.erl b/lib/ssl/test/ssl_npn_handshake_SUITE.erl
index 7b271c4d5d..30c0a67a36 100644
--- a/lib/ssl/test/ssl_npn_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_handshake_SUITE.erl
@@ -69,7 +69,6 @@ init_per_suite(Config) ->
catch crypto:stop(),
try crypto:start() of
ok ->
- application:start(public_key),
ssl:start(),
Result =
(catch make_certs:all(?config(data_dir, Config),
diff --git a/lib/ssl/test/ssl_npn_hello_SUITE.erl b/lib/ssl/test/ssl_npn_hello_SUITE.erl
index 43fa72ea28..ef5a02abef 100644
--- a/lib/ssl/test/ssl_npn_hello_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_hello_SUITE.erl
@@ -23,10 +23,10 @@
%% Note: This directive should only be used in test suites.
-compile(export_all).
--include("ssl_handshake.hrl").
--include("ssl_record.hrl").
-include("ssl_cipher.hrl").
-include("ssl_internal.hrl").
+-include("tls_handshake.hrl").
+-include("tls_record.hrl").
-include_lib("common_test/include/ct.hrl").
%%--------------------------------------------------------------------
@@ -49,54 +49,52 @@ all() ->
encode_and_decode_client_hello_test(_Config) ->
HandShakeData = create_client_handshake(undefined),
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
{[{DecodedHandshakeMessage, _Raw}], _} =
- ssl_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>),
+ tls_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>),
NextProtocolNegotiation = DecodedHandshakeMessage#client_hello.next_protocol_negotiation,
NextProtocolNegotiation = undefined.
%%--------------------------------------------------------------------
encode_and_decode_npn_client_hello_test(_Config) ->
HandShakeData = create_client_handshake(#next_protocol_negotiation{extension_data = <<>>}),
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
{[{DecodedHandshakeMessage, _Raw}], _} =
- ssl_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>),
+ tls_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>),
NextProtocolNegotiation = DecodedHandshakeMessage#client_hello.next_protocol_negotiation,
NextProtocolNegotiation = #next_protocol_negotiation{extension_data = <<>>}.
%%--------------------------------------------------------------------
encode_and_decode_server_hello_test(_Config) ->
HandShakeData = create_server_handshake(undefined),
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
{[{DecodedHandshakeMessage, _Raw}], _} =
- ssl_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>),
+ tls_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>),
NextProtocolNegotiation = DecodedHandshakeMessage#server_hello.next_protocol_negotiation,
NextProtocolNegotiation = undefined.
%%--------------------------------------------------------------------
encode_and_decode_npn_server_hello_test(_Config) ->
HandShakeData = create_server_handshake(#next_protocol_negotiation{extension_data = <<6, "spdy/2">>}),
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
{[{DecodedHandshakeMessage, _Raw}], _} =
- ssl_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>),
+ tls_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>),
NextProtocolNegotiation = DecodedHandshakeMessage#server_hello.next_protocol_negotiation,
ct:log("~p ~n", [NextProtocolNegotiation]),
NextProtocolNegotiation = #next_protocol_negotiation{extension_data = <<6, "spdy/2">>}.
%%--------------------------------------------------------------------
create_server_hello_with_no_advertised_protocols_test(_Config) ->
- Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), false,
- undefined, undefined, undefined),
+ Hello = tls_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), false, undefined, undefined, undefined),
undefined = Hello#server_hello.next_protocol_negotiation.
%%--------------------------------------------------------------------
create_server_hello_with_advertised_protocols_test(_Config) ->
- Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(),
- false, [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>],
- undefined, undefined),
+ Hello = tls_handshake:server_hello(<<>>, {3, 0}, create_connection_states(),
+ false, [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>], undefined, undefined),
#next_protocol_negotiation{extension_data = <<6, "spdy/1", 8, "http/1.0", 8, "http/1.1">>} =
Hello#server_hello.next_protocol_negotiation.
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
create_client_handshake(Npn) ->
- ssl_handshake:encode_handshake(#client_hello{
+ tls_handshake:encode_handshake(#client_hello{
client_version = {1, 2},
random = <<1:256>>,
session_id = <<>>,
@@ -107,7 +105,7 @@ create_client_handshake(Npn) ->
}, vsn).
create_server_handshake(Npn) ->
- ssl_handshake:encode_handshake(#server_hello{
+ tls_handshake:encode_handshake(#server_hello{
server_version = {1, 2},
random = <<1:256>>,
session_id = <<>>,
diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl
index 5a374e234d..36f7af784d 100644
--- a/lib/ssl/test/ssl_packet_SUITE.erl
+++ b/lib/ssl/test/ssl_packet_SUITE.erl
@@ -139,7 +139,7 @@ init_per_suite(Config) ->
catch crypto:stop(),
try crypto:start() of
ok ->
- application:start(public_key),
+ ssl:start(),
Result =
(catch make_certs:all(?config(data_dir, Config),
?config(priv_dir, Config))),
diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl
index 5f5166391f..f95eae51b7 100644
--- a/lib/ssl/test/ssl_payload_SUITE.erl
+++ b/lib/ssl/test/ssl_payload_SUITE.erl
@@ -71,7 +71,6 @@ init_per_suite(Config) ->
catch crypto:stop(),
try crypto:start() of
ok ->
- application:start(public_key),
ssl:start(),
make_certs:all(?config(data_dir, Config), ?config(priv_dir, Config)),
ssl_test_lib:cert_options(Config)
diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl
index 6cc6c4bdb2..c31f6c2d7d 100644
--- a/lib/ssl/test/ssl_session_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_session_cache_SUITE.erl
@@ -56,9 +56,7 @@ init_per_suite(Config0) ->
catch crypto:stop(),
try crypto:start() of
ok ->
- application:start(public_key),
ssl:start(),
-
%% make rsa certs using oppenssl
Result =
(catch make_certs:all(?config(data_dir, Config0),
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index 7f91865a86..019ed58b1b 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -99,7 +99,6 @@ init_per_suite(Config0) ->
catch crypto:stop(),
try crypto:start() of
ok ->
- application:start(public_key),
ssl:start(),
Result =
(catch make_certs:all(?config(data_dir, Config0),
@@ -269,7 +268,7 @@ erlang_client_openssl_server(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(node()),
CertFile = proplists:get_value(certfile, ServerOpts),
KeyFile = proplists:get_value(keyfile, ServerOpts),
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
@@ -310,7 +309,7 @@ erlang_server_openssl_client(Config) when is_list(Config) ->
{mfa, {?MODULE, erlang_ssl_receive, [Data]}},
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost",
@@ -344,7 +343,7 @@ erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) ->
CaCertFile = proplists:get_value(cacertfile, ServerOpts),
CertFile = proplists:get_value(certfile, ServerOpts),
KeyFile = proplists:get_value(keyfile, ServerOpts),
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile
@@ -392,7 +391,7 @@ erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) ->
{mfa, {?MODULE, erlang_ssl_receive, [Data]}},
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost " ++ " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile
++ " -key " ++ KeyFile ++ " -msg",
@@ -428,7 +427,7 @@ erlang_server_openssl_client_reuse_session(Config) when is_list(Config) ->
{reconnect_times, 5},
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost -reconnect",
@@ -463,7 +462,7 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(node()),
CertFile = proplists:get_value(certfile, ServerOpts),
KeyFile = proplists:get_value(keyfile, ServerOpts),
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg",
@@ -513,7 +512,7 @@ erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(node()),
CertFile = proplists:get_value(certfile, ServerOpts),
KeyFile = proplists:get_value(keyfile, ServerOpts),
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg",
@@ -559,7 +558,7 @@ erlang_server_openssl_client_nowrap_seqnum(Config) when is_list(Config) ->
trigger_renegotiate, [[Data, N+2]]}},
{options, [{renegotiate_at, N}, {reuse_sessions, false} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost -msg",
@@ -594,7 +593,7 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(node()),
CertFile = proplists:get_value(certfile, ServerOpts),
KeyFile = proplists:get_value(keyfile, ServerOpts),
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg",
@@ -636,7 +635,7 @@ erlang_client_openssl_server_client_cert(Config) when is_list(Config) ->
CertFile = proplists:get_value(certfile, ServerOpts),
CaCertFile = proplists:get_value(cacertfile, ServerOpts),
KeyFile = proplists:get_value(keyfile, ServerOpts),
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile
++ " -key " ++ KeyFile ++ " -Verify 2",
@@ -687,7 +686,7 @@ erlang_server_openssl_client_client_cert(Config) when is_list(Config) ->
CaCertFile = proplists:get_value(cacertfile, ClientOpts),
CertFile = proplists:get_value(certfile, ClientOpts),
KeyFile = proplists:get_value(keyfile, ClientOpts),
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Cmd = "openssl s_client -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile
++ " -key " ++ KeyFile ++ " -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost",
@@ -712,7 +711,7 @@ erlang_server_erlang_client_client_cert(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ?config(server_verification_opts, Config),
ClientOpts = ?config(client_verification_opts, Config),
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Data = "From erlang to erlang",
@@ -748,7 +747,7 @@ ciphers_rsa_signed_certs() ->
[{doc,"Test cipher suites that uses rsa certs"}].
ciphers_rsa_signed_certs(Config) when is_list(Config) ->
Version =
- ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ tls_record:protocol_version(tls_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:rsa_suites(openssl),
run_suites(Ciphers, Version, Config, rsa).
@@ -758,7 +757,7 @@ ciphers_dsa_signed_certs() ->
[{doc,"Test cipher suites that uses dsa certs"}].
ciphers_dsa_signed_certs(Config) when is_list(Config) ->
Version =
- ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ tls_record:protocol_version(tls_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:dsa_suites(),
run_suites(Ciphers, Version, Config, dsa).
@@ -776,7 +775,7 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(node()),
CertFile = proplists:get_value(certfile, ServerOpts),
KeyFile = proplists:get_value(keyfile, ServerOpts),
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
@@ -1095,7 +1094,7 @@ start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, Opens
Port = ssl_test_lib:inet_port(node()),
CertFile = proplists:get_value(certfile, ServerOpts),
KeyFile = proplists:get_value(keyfile, ServerOpts),
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Cmd = "openssl s_server " ++ OpensslServerOpts ++ " -accept " ++
integer_to_list(Port) ++ version_flag(Version) ++
@@ -1135,7 +1134,7 @@ start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callbac
Port = ssl_test_lib:inet_port(node()),
CertFile = proplists:get_value(certfile, ServerOpts),
KeyFile = proplists:get_value(keyfile, ServerOpts),
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Cmd = "openssl s_server -msg -nextprotoneg http/1.1,spdy/2 -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
@@ -1174,7 +1173,7 @@ start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, Callbac
{mfa, {?MODULE, erlang_ssl_receive_and_assert_npn, [<<"spdy/2">>, Data]}},
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Cmd = "openssl s_client -nextprotoneg http/1.0,spdy/2 -msg -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost",
@@ -1203,7 +1202,7 @@ start_erlang_server_and_openssl_client_with_opts(Config, ErlangServerOpts, OpenS
{mfa, {?MODULE, erlang_ssl_receive, [Data]}},
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
- Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
Cmd = "openssl s_client " ++ OpenSSLClientOpts ++ " -msg -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost",
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index 1f3bef83c8..9dd151553c 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -1 +1 @@
-SSL_VSN = 5.2.1
+SSL_VSN = 5.3
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 2e9ebece0e..121f9febed 100644
--- a/lib/stdlib/src/beam_lib.erl
+++ b/lib/stdlib/src/beam_lib.erl
@@ -300,7 +300,7 @@ 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=Type, String) ->
<<K1:8/binary,K2:8/binary>> = First = erlang:md5(String),
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/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index 68a8534f15..08b8541014 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -522,8 +522,7 @@ start(File, Opts) ->
warn_format = value_option(warn_format, 1, warn_format, 1,
nowarn_format, 0, Opts),
enabled_warnings = Enabled,
- file = File,
- types = default_types()
+ file = File
}.
%% is_warn_enabled(Category, St) -> boolean().
@@ -1007,7 +1006,10 @@ check_undefined_functions(#lint{called=Called0,defined=Def0}=St0) ->
check_undefined_types(#lint{usage=Usage,types=Def}=St0) ->
Used = Usage#usage.used_types,
UTAs = dict:fetch_keys(Used),
- Undef = [{TA,dict:fetch(TA, Used)} || TA <- UTAs, not dict:is_key(TA, Def)],
+ Undef = [{TA,dict:fetch(TA, Used)} ||
+ TA <- UTAs,
+ not dict:is_key(TA, Def),
+ not is_default_type(TA)],
foldl(fun ({TA,L}, St) ->
add_error(L, {undefined_type,TA}, St)
end, St0, Undef).
@@ -2440,7 +2442,7 @@ type_def(Attr, Line, TypeName, ProtoType, Args, St0) ->
end,
case (dict:is_key(TypePair, TypeDefs) orelse is_var_arity_type(TypeName)) of
true ->
- case dict:is_key(TypePair, default_types()) of
+ case is_default_type(TypePair) of
true ->
case is_newly_introduced_builtin_type(TypePair) of
%% allow some types just for bootstrapping
@@ -2488,8 +2490,8 @@ check_type({paren_type, _L, [Type]}, SeenVars, St) ->
check_type({remote_type, L, [{atom, _, Mod}, {atom, _, Name}, Args]},
SeenVars, #lint{module=CurrentMod} = St) ->
St1 =
- case (dict:is_key({Name, length(Args)}, default_types())
- orelse is_var_arity_type(Name)) of
+ case is_default_type({Name, length(Args)})
+ orelse is_var_arity_type(Name) of
true -> add_error(L, {imported_predefined_type, Name}, St);
false -> St
end,
@@ -2606,63 +2608,62 @@ is_var_arity_type(union) -> true;
is_var_arity_type(record) -> true;
is_var_arity_type(_) -> false.
-default_types() ->
- DefTypes = [{any, 0},
- {arity, 0},
- {array, 0},
- {atom, 0},
- {atom, 1},
- {binary, 0},
- {binary, 2},
- {bitstring, 0},
- {bool, 0},
- {boolean, 0},
- {byte, 0},
- {char, 0},
- {dict, 0},
- {digraph, 0},
- {float, 0},
- {'fun', 0},
- {'fun', 2},
- {function, 0},
- {gb_set, 0},
- {gb_tree, 0},
- {identifier, 0},
- {integer, 0},
- {integer, 1},
- {iodata, 0},
- {iolist, 0},
- {list, 0},
- {list, 1},
- {maybe_improper_list, 0},
- {maybe_improper_list, 2},
- {mfa, 0},
- {module, 0},
- {neg_integer, 0},
- {nil, 0},
- {no_return, 0},
- {node, 0},
- {non_neg_integer, 0},
- {none, 0},
- {nonempty_list, 0},
- {nonempty_list, 1},
- {nonempty_improper_list, 2},
- {nonempty_maybe_improper_list, 0},
- {nonempty_maybe_improper_list, 2},
- {nonempty_string, 0},
- {number, 0},
- {pid, 0},
- {port, 0},
- {pos_integer, 0},
- {queue, 0},
- {range, 2},
- {reference, 0},
- {set, 0},
- {string, 0},
- {term, 0},
- {timeout, 0},
- {var, 1}],
- dict:from_list([{T, -1} || T <- DefTypes]).
+is_default_type({any, 0}) -> true;
+is_default_type({arity, 0}) -> true;
+is_default_type({array, 0}) -> true;
+is_default_type({atom, 0}) -> true;
+is_default_type({atom, 1}) -> true;
+is_default_type({binary, 0}) -> true;
+is_default_type({binary, 2}) -> true;
+is_default_type({bitstring, 0}) -> true;
+is_default_type({bool, 0}) -> true;
+is_default_type({boolean, 0}) -> true;
+is_default_type({byte, 0}) -> true;
+is_default_type({char, 0}) -> true;
+is_default_type({dict, 0}) -> true;
+is_default_type({digraph, 0}) -> true;
+is_default_type({float, 0}) -> true;
+is_default_type({'fun', 0}) -> true;
+is_default_type({'fun', 2}) -> true;
+is_default_type({function, 0}) -> true;
+is_default_type({gb_set, 0}) -> true;
+is_default_type({gb_tree, 0}) -> true;
+is_default_type({identifier, 0}) -> true;
+is_default_type({integer, 0}) -> true;
+is_default_type({integer, 1}) -> true;
+is_default_type({iodata, 0}) -> true;
+is_default_type({iolist, 0}) -> true;
+is_default_type({list, 0}) -> true;
+is_default_type({list, 1}) -> true;
+is_default_type({maybe_improper_list, 0}) -> true;
+is_default_type({maybe_improper_list, 2}) -> true;
+is_default_type({mfa, 0}) -> true;
+is_default_type({module, 0}) -> true;
+is_default_type({neg_integer, 0}) -> true;
+is_default_type({nil, 0}) -> true;
+is_default_type({no_return, 0}) -> true;
+is_default_type({node, 0}) -> true;
+is_default_type({non_neg_integer, 0}) -> true;
+is_default_type({none, 0}) -> true;
+is_default_type({nonempty_list, 0}) -> true;
+is_default_type({nonempty_list, 1}) -> true;
+is_default_type({nonempty_improper_list, 2}) -> true;
+is_default_type({nonempty_maybe_improper_list, 0}) -> true;
+is_default_type({nonempty_maybe_improper_list, 2}) -> true;
+is_default_type({nonempty_string, 0}) -> true;
+is_default_type({number, 0}) -> true;
+is_default_type({pid, 0}) -> true;
+is_default_type({port, 0}) -> true;
+is_default_type({pos_integer, 0}) -> true;
+is_default_type({queue, 0}) -> true;
+is_default_type({range, 2}) -> true;
+is_default_type({reference, 0}) -> true;
+is_default_type({set, 0}) -> true;
+is_default_type({string, 0}) -> true;
+is_default_type({term, 0}) -> true;
+is_default_type({timeout, 0}) -> true;
+is_default_type({var, 1}) -> true;
+is_default_type(_) -> false.
%% R13
is_newly_introduced_builtin_type({arity, 0}) -> true;
@@ -2776,10 +2777,7 @@ check_unused_types(Forms, #lint{usage=Usage, types=Ts, exp_types=ExpTs}=St) ->
L = gb_sets:to_list(ExpTs) ++ dict:fetch_keys(D),
UsedTypes = gb_sets:from_list(L),
FoldFun =
- fun(_Type, -1, AccSt) ->
- %% Default type
- AccSt;
- (Type, #typeinfo{line = FileLine}, AccSt) ->
+ fun(Type, #typeinfo{line = FileLine}, AccSt) ->
case loc(FileLine) of
{FirstFile, _} ->
case gb_sets:is_member(Type, UsedTypes) of
@@ -2801,10 +2799,7 @@ check_unused_types(Forms, #lint{usage=Usage, types=Ts, exp_types=ExpTs}=St) ->
check_local_opaque_types(St) ->
#lint{types=Ts, exp_types=ExpTs} = St,
FoldFun =
- fun(_Type, -1, AccSt) ->
- %% Default type
- AccSt;
- (_Type, #typeinfo{attr = type}, AccSt) ->
+ fun(_Type, #typeinfo{attr = type}, AccSt) ->
AccSt;
(Type, #typeinfo{attr = opaque, line = FileLine}, AccSt) ->
case gb_sets:is_element(Type, ExpTs) of
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index c0596e5ba6..657cb5d34c 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -214,7 +214,9 @@ lattribute({attribute,_Line,type,Type}, Opts, _State) ->
lattribute({attribute,_Line,opaque,Type}, Opts, _State) ->
[typeattr(opaque, Type, Opts),leaf(".\n")];
lattribute({attribute,_Line,spec,Arg}, _Opts, _State) ->
- [specattr(Arg),leaf(".\n")];
+ [specattr(spec, Arg),leaf(".\n")];
+lattribute({attribute,_Line,callback,Arg}, _Opts, _State) ->
+ [specattr(callback, Arg),leaf(".\n")];
lattribute({attribute,_Line,Name,Arg}, Opts, State) ->
[lattribute(Name, Arg, Opts, State),leaf(".\n")].
@@ -311,14 +313,14 @@ union_elem(T) ->
tuple_type(Ts, F) ->
{seq,${,$},[$,],ltypes(Ts, F)}.
-specattr({FuncSpec,TypeSpecs}) ->
+specattr(SpecKind, {FuncSpec,TypeSpecs}) ->
Func = case FuncSpec of
{F,_A} ->
format("~w", [F]);
{M,F,_A} ->
format("~w:~w", [M, F])
end,
- {first,leaf("-spec "),
+ {first,leaf(lists:concat(["-", SpecKind, " "])),
{list,[{first,leaf(Func),spec_clauses(TypeSpecs)}]}}.
spec_clauses(TypeSpecs) ->
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index 42a42b7fd7..cebc9c91bd 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -250,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/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl
index ff3470349e..2b7cec87df 100644
--- a/lib/stdlib/test/erl_pp_SUITE.erl
+++ b/lib/stdlib/test/erl_pp_SUITE.erl
@@ -43,7 +43,7 @@
receive_after/1, bits/1, head_tail/1,
cond1/1, block/1, case1/1, ops/1, messages/1,
old_mnemosyne_syntax/1,
- import_export/1, misc_attrs/1,
+ import_export/1, misc_attrs/1, dialyzer_attrs/1,
hook/1,
neg_indent/1,
@@ -77,7 +77,7 @@ groups() ->
[func, call, recs, try_catch, if_then, receive_after,
bits, head_tail, cond1, block, case1, ops,
messages, old_mnemosyne_syntax]},
- {attributes, [], [misc_attrs, import_export]},
+ {attributes, [], [misc_attrs, import_export, dialyzer_attrs]},
{tickets, [],
[otp_6321, otp_6911, otp_6914, otp_8150, otp_8238,
otp_8473, otp_8522, otp_8567, otp_8664, otp_9147,
@@ -597,6 +597,15 @@ misc_attrs(Config) when is_list(Config) ->
ok.
+dialyzer_attrs(suite) ->
+ [];
+dialyzer_attrs(Config) when is_list(Config) ->
+ ok = pp_forms(<<"-type foo() :: #bar{}. ">>),
+ ok = pp_forms(<<"-opaque foo() :: {bar, fun((X, [42,...]) -> X)}. ">>),
+ ok = pp_forms(<<"-spec foo(bar(), qux()) -> [T | baz(T)]. ">>),
+ ok = pp_forms(<<"-callback foo(<<_:32,_:_*4>>, T) -> T. ">>),
+ ok.
+
hook(suite) ->
[];
hook(Config) when is_list(Config) ->
diff --git a/lib/stdlib/test/unicode_SUITE.erl b/lib/stdlib/test/unicode_SUITE.erl
index 4055af2741..6106a8c444 100644
--- a/lib/stdlib/test/unicode_SUITE.erl
+++ b/lib/stdlib/test/unicode_SUITE.erl
@@ -29,7 +29,7 @@
random_lists/1,
roundtrips/1,
latin1/1,
- exceptions/1]).
+ exceptions/1, binaries_errors/1]).
init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
Dog=?t:timetrap(?t:minutes(20)),
@@ -44,7 +44,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[utf8_illegal_sequences_bif,
utf16_illegal_sequences_bif, random_lists, roundtrips,
- latin1, exceptions].
+ latin1, exceptions, binaries_errors].
groups() ->
[].
@@ -61,6 +61,149 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
+binaries_errors(Config) when is_list(Config) ->
+ setlimit(10),
+ ex_binaries_errors_utf8(Config),
+ setlimit(default),
+ ex_binaries_errors_utf8(Config),
+ ex_binaries_errors_utf16_little(Config),
+ ex_binaries_errors_utf16_big(Config),
+ ex_binaries_errors_utf32_little(Config),
+ ex_binaries_errors_utf32_big(Config).
+
+ex_binaries_errors_utf8(Config) when is_list(Config) ->
+ %% Original smoke test, we should not forget the original offset...
+ <<_:8,_:8,RR2/binary>> = <<$a,$b,164,165,$c>>,
+ {error,[],<<164,165,$c>>} = unicode:characters_to_list(RR2),
+ %% Now, try with longer binary (trapping)
+ BrokenPart = list_to_binary(lists:seq(128,255)),
+ BrokenSz = byte_size(BrokenPart),
+ [ begin
+ OKList = lists:flatten(lists:duplicate(N,lists:seq(1,255))),
+ OKBin = unicode:characters_to_binary(OKList),
+ OKLen = length(OKList),
+ %% Copy to avoid that the binary get's writable
+ PartlyBroken = binary:copy(<<OKBin/binary, BrokenPart/binary>>),
+ PBSz = byte_size(PartlyBroken),
+ {error,OKList,DeepBrokenPart} =
+ unicode:characters_to_list(PartlyBroken),
+ BrokenPart = iolist_to_binary(DeepBrokenPart),
+ [ begin
+ NewList = lists:nthtail(X, OKList),
+ NewSz = byte_size(unicode:characters_to_binary(NewList)) +
+ BrokenSz,
+ Chomped = binary:part(PartlyBroken,PBSz - NewSz, NewSz),
+ true = (binary:referenced_byte_size(Chomped) =:= PBSz),
+ {error,NewList,DeepBrokenPart2} =
+ unicode:characters_to_list(Chomped),
+ BrokenPart = iolist_to_binary(DeepBrokenPart2)
+ end || X <- lists:seq(1,OKLen) ]
+ end || N <- lists:seq(1,20) ],
+ ok.
+
+ex_binaries_errors_utf16_little(Config) when is_list(Config) ->
+ BrokenPart = << <<X:16/little>> || X <- lists:seq(16#DC00,16#DFFF) >>,
+ BrokenSz = byte_size(BrokenPart),
+ [ begin
+ OKList = lists:flatten(lists:duplicate(N,lists:seq(1,255))),
+ OKBin = unicode:characters_to_binary(OKList,unicode,{utf16,little}),
+ OKLen = length(OKList),
+ %% Copy to avoid that the binary get's writable
+ PartlyBroken = binary:copy(<<OKBin/binary, BrokenPart/binary>>),
+ PBSz = byte_size(PartlyBroken),
+ {error,OKList,DeepBrokenPart} =
+ unicode:characters_to_list(PartlyBroken,{utf16,little}),
+ BrokenPart = iolist_to_binary(DeepBrokenPart),
+ [ begin
+ NewList = lists:nthtail(X, OKList),
+ NewSz = byte_size(unicode:characters_to_binary(NewList,unicode,{utf16,little})) +
+ BrokenSz,
+ Chomped = binary:part(PartlyBroken,PBSz - NewSz, NewSz),
+ true = (binary:referenced_byte_size(Chomped) =:= PBSz),
+ {error,NewList,DeepBrokenPart2} =
+ unicode:characters_to_list(Chomped,{utf16,little}),
+ BrokenPart = iolist_to_binary(DeepBrokenPart2)
+ end || X <- lists:seq(1,OKLen) ]
+ end || N <- lists:seq(1,15) ],
+ ok.
+ex_binaries_errors_utf16_big(Config) when is_list(Config) ->
+ BrokenPart = << <<X:16/big>> || X <- lists:seq(16#DC00,16#DFFF) >>,
+ BrokenSz = byte_size(BrokenPart),
+ [ begin
+ OKList = lists:flatten(lists:duplicate(N,lists:seq(1,255))),
+ OKBin = unicode:characters_to_binary(OKList,unicode,{utf16,big}),
+ OKLen = length(OKList),
+ %% Copy to avoid that the binary get's writable
+ PartlyBroken = binary:copy(<<OKBin/binary, BrokenPart/binary>>),
+ PBSz = byte_size(PartlyBroken),
+ {error,OKList,DeepBrokenPart} =
+ unicode:characters_to_list(PartlyBroken,{utf16,big}),
+ BrokenPart = iolist_to_binary(DeepBrokenPart),
+ [ begin
+ NewList = lists:nthtail(X, OKList),
+ NewSz = byte_size(unicode:characters_to_binary(NewList,unicode,{utf16,big})) +
+ BrokenSz,
+ Chomped = binary:part(PartlyBroken,PBSz - NewSz, NewSz),
+ true = (binary:referenced_byte_size(Chomped) =:= PBSz),
+ {error,NewList,DeepBrokenPart2} =
+ unicode:characters_to_list(Chomped,{utf16,big}),
+ BrokenPart = iolist_to_binary(DeepBrokenPart2)
+ end || X <- lists:seq(1,OKLen) ]
+ end || N <- lists:seq(1,15) ],
+ ok.
+
+ex_binaries_errors_utf32_big(Config) when is_list(Config) ->
+ BrokenPart = << <<X:32/big>> || X <- lists:seq(16#DC00,16#DFFF) >>,
+ BrokenSz = byte_size(BrokenPart),
+ [ begin
+ OKList = lists:flatten(lists:duplicate(N,lists:seq(1,255))),
+ OKBin = unicode:characters_to_binary(OKList,unicode,{utf32,big}),
+ OKLen = length(OKList),
+ %% Copy to avoid that the binary get's writable
+ PartlyBroken = binary:copy(<<OKBin/binary, BrokenPart/binary>>),
+ PBSz = byte_size(PartlyBroken),
+ {error,OKList,DeepBrokenPart} =
+ unicode:characters_to_list(PartlyBroken,{utf32,big}),
+ BrokenPart = iolist_to_binary(DeepBrokenPart),
+ [ begin
+ NewList = lists:nthtail(X, OKList),
+ NewSz = byte_size(unicode:characters_to_binary(NewList,unicode,{utf32,big})) +
+ BrokenSz,
+ Chomped = binary:part(PartlyBroken,PBSz - NewSz, NewSz),
+ true = (binary:referenced_byte_size(Chomped) =:= PBSz),
+ {error,NewList,DeepBrokenPart2} =
+ unicode:characters_to_list(Chomped,{utf32,big}),
+ BrokenPart = iolist_to_binary(DeepBrokenPart2)
+ end || X <- lists:seq(1,OKLen) ]
+ end || N <- lists:seq(1,15) ],
+ ok.
+
+ex_binaries_errors_utf32_little(Config) when is_list(Config) ->
+ BrokenPart = << <<X:32/little>> || X <- lists:seq(16#DC00,16#DFFF) >>,
+ BrokenSz = byte_size(BrokenPart),
+ [ begin
+ OKList = lists:flatten(lists:duplicate(N,lists:seq(1,255))),
+ OKBin = unicode:characters_to_binary(OKList,unicode,{utf32,little}),
+ OKLen = length(OKList),
+ %% Copy to avoid that the binary get's writable
+ PartlyBroken = binary:copy(<<OKBin/binary, BrokenPart/binary>>),
+ PBSz = byte_size(PartlyBroken),
+ {error,OKList,DeepBrokenPart} =
+ unicode:characters_to_list(PartlyBroken,{utf32,little}),
+ BrokenPart = iolist_to_binary(DeepBrokenPart),
+ [ begin
+ NewList = lists:nthtail(X, OKList),
+ NewSz = byte_size(unicode:characters_to_binary(NewList,unicode,{utf32,little})) +
+ BrokenSz,
+ Chomped = binary:part(PartlyBroken,PBSz - NewSz, NewSz),
+ true = (binary:referenced_byte_size(Chomped) =:= PBSz),
+ {error,NewList,DeepBrokenPart2} =
+ unicode:characters_to_list(Chomped,{utf32,little}),
+ BrokenPart = iolist_to_binary(DeepBrokenPart2)
+ end || X <- lists:seq(1,OKLen) ]
+ end || N <- lists:seq(1,15) ],
+ ok.
+
exceptions(Config) when is_list(Config) ->
diff --git a/lib/test_server/doc/src/notes.xml b/lib/test_server/doc/src/notes.xml
index b35929f1e6..0eab939a46 100644
--- a/lib/test_server/doc/src/notes.xml
+++ b/lib/test_server/doc/src/notes.xml
@@ -226,8 +226,6 @@
unicode:characters_to_binary for conversion between
binaries and strings instead of binary_to_list and
list_to_binary. </item> </list></p>
- <p>
- Own Id: OTP-10783</p>
</item>
</list>
</section>
diff --git a/lib/test_server/src/configure.in b/lib/test_server/src/configure.in
index 785bab395c..b8fddf1481 100644
--- a/lib/test_server/src/configure.in
+++ b/lib/test_server/src/configure.in
@@ -276,6 +276,7 @@ AC_CHECK_FUNC(gethostbyname, , AC_CHECK_LIB(nsl, main, [LIBS="$LIBS -lnsl"]))
dnl Checks for library functions.
AC_CHECK_FUNCS(strerror)
AC_CHECK_FUNCS(vsnprintf)
+AC_CHECK_FUNCS(usleep)
# First check if the library is available, then if we can choose between
# two versions of gethostbyname
diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl
index 8b0be51be3..c350f758ce 100644
--- a/lib/test_server/src/test_server.erl
+++ b/lib/test_server/src/test_server.erl
@@ -716,6 +716,16 @@ end_conf_timeout(_, _) ->
call_end_conf(Mod,Func,TCPid,TCExitReason,Loc,Conf,TVal) ->
Starter = self(),
Data = {Mod,Func,TCPid,TCExitReason,Loc},
+ case erlang:function_exported(Mod,end_per_testcase,2) of
+ false ->
+ spawn_link(fun() ->
+ Starter ! {self(),{call_end_conf,Data,ok}}
+ end);
+ true ->
+ do_call_end_conf(Starter,Mod,Func,Data,Conf,TVal)
+ end.
+
+do_call_end_conf(Starter,Mod,Func,Data,Conf,TVal) ->
EndConfProc =
fun() ->
process_flag(trap_exit,true), % to catch timetraps
@@ -753,7 +763,8 @@ call_end_conf(Mod,Func,TCPid,TCExitReason,Loc,Conf,TVal) ->
end,
spawn_link(EndConfProc).
-spawn_fw_call(Mod,{init_per_testcase,Func},CurrConf,Pid,{timetrap_timeout,TVal}=Why,
+spawn_fw_call(Mod,{init_per_testcase,Func},CurrConf,Pid,
+ {timetrap_timeout,TVal}=Why,
Loc,SendTo) ->
FwCall =
fun() ->
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}
diff --git a/lib/tools/doc/src/eprof.xml b/lib/tools/doc/src/eprof.xml
index 82eb8dd284..8397204a43 100644
--- a/lib/tools/doc/src/eprof.xml
+++ b/lib/tools/doc/src/eprof.xml
@@ -52,12 +52,14 @@
<func>
<name>start_profiling(Rootset) -> profiling | {error, Reason}</name>
<name>start_profiling(Rootset,Pattern) -> profiling | {error, Reason}</name>
+ <name>start_profiling(Rootset,Pattern,Options) -> profiling | {error, Reason}</name>
<fsummary>Start profiling.</fsummary>
<type>
<v>Rootset = [atom() | pid()]</v>
- <v>Pattern = {Module, Function, Arity}</v>
- <v>Module = Function = atom()</v>
- <v>Arity = integer()</v>
+ <v>Pattern = {Module, Function, Arity}</v>
+ <v>Module = Function = atom()</v>
+ <v>Arity = integer()</v>
+ <v>Options = [set_on_spawn]</v>
<v>Reason = term()</v>
</type>
<desc>
@@ -70,6 +72,9 @@
<p>A pattern can be selected to narrow the profiling. For instance a
specific module can be selected, and only the code executed in that
module will be profiled.</p>
+ <p>The <c>set_on_spawn</c> option will active call time tracing for
+ all processes spawned by processes in the rootset. This is
+ the default behaviour.</p>
</desc>
</func>
<func>
@@ -82,19 +87,22 @@
</func>
<func>
<name>profile(Fun) -> profiling | {error, Reason}</name>
+ <name>profile(Fun, Options) -> profiling | {error, Reason}</name>
<name>profile(Rootset) -> profiling | {error, Reason}</name>
<name>profile(Rootset,Fun) -> {ok, Value} | {error,Reason}</name>
<name>profile(Rootset,Fun,Pattern) -> {ok, Value} | {error, Reason}</name>
<name>profile(Rootset,Module,Function,Args) -> {ok, Value} | {error, Reason}</name>
<name>profile(Rootset,Module,Function,Args,Pattern) -> {ok, Value} | {error, Reason}</name>
+ <name>profile(Rootset,Module,Function,Args,Pattern,Options) -> {ok, Value} | {error, Reason}</name>
<fsummary>Start profiling.</fsummary>
<type>
<v>Rootset = [atom() | pid()]</v>
- <v>Fun = fun() -> term()</v>
- <v>Pattern = {Module, Function, Arity}</v>
+ <v>Fun = fun() -> term() end</v>
+ <v>Pattern = {Module, Function, Arity}</v>
<v>Module = Function = atom()</v>
<v>Args = [term()]</v>
- <v>Arity = integer()</v>
+ <v>Arity = integer()</v>
+ <v>Options = [set_on_spawn]</v>
<v>Value = Reason = term()</v>
</type>
<desc>
@@ -108,8 +116,11 @@
<c>Rootset</c>, the function returns <c>{ok,Value}</c> when
<c>Fun()</c>/<c>apply</c> returns with the value <c>Value</c>, or
<c>{error,Reason}</c> if <c>Fun()</c>/<c>apply</c> fails with
- exit reason <c>Reason</c>. Otherwise it returns <c>{error, Reason}</c>
+ exit reason <c>Reason</c>. Otherwise it returns <c>{error, Reason}</c>
immediately.</p>
+ <p>The <c>set_on_spawn</c> option will active call time tracing for
+ all processes spawned by processes in the rootset. This is
+ the default behaviour.</p>
<p>The programmer must ensure that the function given as argument
is truly synchronous and that no work continues after
the function has returned a value.</p>
diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el
index ddd22707dd..f3bc95e3e5 100644
--- a/lib/tools/emacs/erlang.el
+++ b/lib/tools/emacs/erlang.el
@@ -883,6 +883,7 @@ resulting regexp is surrounded by \\_< and \\_>."
"fun_to_list"
"function_exported"
"garbage_collect_message_area"
+ "gather_gc_info_result"
"gather_sched_wall_time_result"
"get_cookie"
"get_module_info"
diff --git a/lib/tools/src/eprof.erl b/lib/tools/src/eprof.erl
index 87fdc1fa34..bc9345fa62 100644
--- a/lib/tools/src/eprof.erl
+++ b/lib/tools/src/eprof.erl
@@ -26,7 +26,7 @@
-export([start/0,
stop/0,
dump/0,
- start_profiling/1, start_profiling/2,
+ start_profiling/1, start_profiling/2, start_profiling/3,
profile/1, profile/2, profile/3, profile/4, profile/5,
stop_profiling/0,
analyze/0, analyze/1, analyze/2,
@@ -39,6 +39,8 @@
handle_info/2,
terminate/2,
code_change/3]).
+
+
-record(bpd, {
n = 0, % number of total calls
us = 0, % sum of uS for all calls
@@ -46,14 +48,18 @@
mfa = [] % list of {Mfa, {Count, Us}}
}).
+-define(default_options, [{set_on_spawn, true}]).
+-define(default_pattern, {'_','_','_'}).
+
-record(state, {
- profiling = false,
- pattern = {'_','_','_'},
- rootset = [],
- fd = undefined,
- start_ts = undefined,
- reply = undefined,
- bpd = #bpd{}
+ profiling = false,
+ pattern = ?default_pattern,
+ rootset = [],
+ trace_opts = [],
+ fd = undefined,
+ start_ts = undefined,
+ reply = undefined,
+ bpd = #bpd{}
}).
@@ -67,26 +73,6 @@
start() -> gen_server:start({local, ?MODULE}, ?MODULE, [], []).
stop() -> gen_server:call(?MODULE, stop, infinity).
-profile(Fun) when is_function(Fun) ->
- profile([], Fun);
-profile(Rs) when is_list(Rs) ->
- start_profiling(Rs).
-
-profile(Pids, Fun) ->
- profile(Pids, Fun, {'_','_','_'}).
-
-profile(Pids, Fun, Pattern) ->
- profile(Pids, erlang, apply, [Fun,[]], Pattern).
-
-profile(Pids, M, F, A) ->
- profile(Pids, M, F, A, {'_','_','_'}).
-
-profile(Pids, M, F, A, Pattern) ->
- start(),
- gen_server:call(?MODULE, {profile,Pids,Pattern,M,F,A},infinity).
-
-dump() ->
- gen_server:call(?MODULE, dump, infinity).
analyze() ->
analyze(procs).
@@ -98,17 +84,53 @@ analyze(Opts) when is_list(Opts) ->
analyze(Type, Opts) when is_list(Opts) ->
gen_server:call(?MODULE, {analyze, Type, Opts}, infinity).
+%% odd duck, should only been start_profiling/1
+profile(Rootset) when is_list(Rootset) ->
+ start_profiling(Rootset);
+
+profile(Fun) when is_function(Fun) ->
+ profile([], Fun).
+
+profile(Fun, Opts) when is_function(Fun), is_list(Opts) ->
+ profile([], erlang, apply, [Fun, []], ?default_pattern, Opts);
+
+profile(Rootset, Fun) when is_list(Rootset), is_function(Fun) ->
+ profile(Rootset, Fun, ?default_pattern).
+
+profile(Rootset, Fun, Pattern) when is_list(Rootset), is_function(Fun) ->
+ profile(Rootset, Fun, Pattern, ?default_options).
+
+profile(Rootset, Fun, Pattern, Options) when is_list(Rootset), is_function(Fun), is_list(Options) ->
+ profile(Rootset, erlang, apply, [Fun,[]], Pattern, Options);
+
+profile(Rootset, M, F, A) when is_list(Rootset), is_atom(M), is_atom(F), is_list(A) ->
+ profile(Rootset, M, F, A, ?default_pattern).
+
+profile(Rootset, M, F, A, Pattern) when is_list(Rootset), is_atom(M), is_atom(F), is_list(A) ->
+ profile(Rootset, M, F, A, Pattern, ?default_options).
+
+%% Returns when M:F/A has terminated
+profile(Rootset, M, F, A, Pattern, Options) ->
+ start(),
+ gen_server:call(?MODULE, {profile_start, Rootset, Pattern, {M,F,A}, Options}, infinity).
+
+dump() ->
+ gen_server:call(?MODULE, dump, infinity).
+
log(File) ->
gen_server:call(?MODULE, {logfile, File}, infinity).
+%% Does not block
start_profiling(Rootset) ->
- start_profiling(Rootset, {'_','_','_'}).
+ start_profiling(Rootset, ?default_pattern).
start_profiling(Rootset, Pattern) ->
+ start_profiling(Rootset, Pattern, ?default_options).
+start_profiling(Rootset, Pattern, Options) ->
start(),
- gen_server:call(?MODULE, {profile, Rootset, Pattern}, infinity).
+ gen_server:call(?MODULE, {profile_start, Rootset, Pattern, undefined, Options}, infinity).
stop_profiling() ->
- gen_server:call(?MODULE, stop_profiling, infinity).
+ gen_server:call(?MODULE, profile_stop, infinity).
%% -------------------------------------------------------------------- %%
@@ -151,74 +173,75 @@ handle_call({analyze, Type, _Opts}, _, S) ->
%% profile
-handle_call({profile, _Rootset, _Pattern, _M,_F,_A}, _From, #state{ profiling = true } = S) ->
+handle_call({profile_start, _Rootset, _Pattern, _MFA, _Opts}, _From, #state{ profiling = true } = S) ->
{reply, {error, already_profiling}, S};
-handle_call({profile, Rootset, Pattern, M,F,A}, From, #state{fd = Fd } = S) ->
+handle_call({profile_start, Rootset, Pattern, {M,F,A}, Opts}, From, #state{fd = Fd } = S) ->
+
+ ok = set_pattern_trace(false, S#state.pattern),
+ _ = set_process_trace(false, S#state.rootset, S#state.trace_opts),
- set_pattern_trace(false, S#state.pattern),
- set_process_trace(false, S#state.rootset),
+ Topts = get_trace_options(Opts),
+ Pid = setup_profiling(M,F,A),
- Pid = setup_profiling(M,F,A),
- case set_process_trace(true, [Pid|Rootset]) of
+ case set_process_trace(true, [Pid|Rootset], Topts) of
true ->
- set_pattern_trace(true, Pattern),
+ ok = set_pattern_trace(true, Pattern),
T0 = now(),
- execute_profiling(Pid),
+ ok = execute_profiling(Pid),
{noreply, #state{
- profiling = true,
- rootset = [Pid|Rootset],
- start_ts = T0,
- reply = From,
- fd = Fd,
- pattern = Pattern
+ profiling = true,
+ rootset = [Pid|Rootset],
+ start_ts = T0,
+ reply = From,
+ fd = Fd,
+ trace_opts = Topts,
+ pattern = Pattern
}};
false ->
exit(Pid, eprof_kill),
{reply, error, #state{ fd = Fd}}
end;
-handle_call({profile, _Rootset, _Pattern}, _From, #state{ profiling = true } = S) ->
- {reply, {error, already_profiling}, S};
-
-handle_call({profile, Rootset, Pattern}, From, #state{ fd = Fd } = S) ->
+handle_call({profile_start, Rootset, Pattern, undefined, Opts}, From, #state{ fd = Fd } = S) ->
- set_pattern_trace(false, S#state.pattern),
- set_process_trace(false, S#state.rootset),
+ ok = set_pattern_trace(false, S#state.pattern),
+ true = set_process_trace(false, S#state.rootset, S#state.trace_opts),
+ Topts = get_trace_options(Opts),
- case set_process_trace(true, Rootset) of
+ case set_process_trace(true, Rootset, Topts) of
true ->
T0 = now(),
- set_pattern_trace(true, Pattern),
+ ok = set_pattern_trace(true, Pattern),
{reply, profiling, #state{
- profiling = true,
- rootset = Rootset,
- start_ts = T0,
- reply = From,
- fd = Fd,
- pattern = Pattern
+ profiling = true,
+ rootset = Rootset,
+ start_ts = T0,
+ reply = From,
+ fd = Fd,
+ trace_opts = Topts,
+ pattern = Pattern
}};
false ->
{reply, error, #state{ fd = Fd }}
end;
-handle_call(stop_profiling, _From, #state{ profiling = false } = S) ->
+handle_call(profile_stop, _From, #state{ profiling = false } = S) ->
{reply, profiling_already_stopped, S};
-handle_call(stop_profiling, _From, #state{ profiling = true } = S) ->
-
- set_pattern_trace(pause, S#state.pattern),
+handle_call(profile_stop, _From, #state{ profiling = true } = S) ->
+ ok = set_pattern_trace(pause, S#state.pattern),
Bpd = collect_bpd(),
-
- set_process_trace(false, S#state.rootset),
- set_pattern_trace(false, S#state.pattern),
+ _ = set_process_trace(false, S#state.rootset, S#state.trace_opts),
+ ok = set_pattern_trace(false, S#state.pattern),
{reply, profiling_stopped, S#state{
- profiling = false,
- rootset = [],
- pattern = {'_','_','_'},
- bpd = Bpd
+ profiling = false,
+ rootset = [],
+ trace_opts = [],
+ pattern = ?default_pattern,
+ bpd = Bpd
}};
%% logfile
@@ -261,33 +284,33 @@ handle_info({'EXIT', _, eprof_kill}, S) ->
{noreply, S};
handle_info({'EXIT', _, Reason}, #state{ reply = FromTag } = S) ->
- set_process_trace(false, S#state.rootset),
- set_pattern_trace(false, S#state.pattern),
+ _ = set_process_trace(false, S#state.rootset, S#state.trace_opts),
+ ok = set_pattern_trace(false, S#state.pattern),
gen_server:reply(FromTag, {error, Reason}),
{noreply, S#state{
- profiling = false,
- rootset = [],
- pattern = {'_','_','_'}
+ profiling = false,
+ rootset = [],
+ trace_opts = [],
+ pattern = ?default_pattern
}};
% check if Pid is spawned process?
handle_info({_Pid, {answer, Result}}, #state{ reply = {From,_} = FromTag} = S) ->
- set_pattern_trace(pause, S#state.pattern),
-
- Bpd = collect_bpd(),
-
- set_process_trace(false, S#state.rootset),
- set_pattern_trace(false, S#state.pattern),
+ ok = set_pattern_trace(pause, S#state.pattern),
+ Bpd = collect_bpd(),
+ _ = set_process_trace(false, S#state.rootset, S#state.trace_opts),
+ ok = set_pattern_trace(false, S#state.pattern),
catch unlink(From),
gen_server:reply(FromTag, {ok, Result}),
{noreply, S#state{
- profiling = false,
- rootset = [],
- pattern = {'_','_','_'},
- bpd = Bpd
+ profiling = false,
+ rootset = [],
+ trace_opts = [],
+ pattern = ?default_pattern,
+ bpd = Bpd
}}.
%% -------------------------------------------------------------------- %%
@@ -297,11 +320,11 @@ handle_info({_Pid, {answer, Result}}, #state{ reply = {From,_} = FromTag} = S) -
%% -------------------------------------------------------------------- %%
terminate(_Reason, #state{ fd = undefined }) ->
- set_pattern_trace(false, {'_','_','_'}),
+ ok = set_pattern_trace(false, ?default_pattern),
ok;
terminate(_Reason, #state{ fd = Fd }) ->
- file:close(Fd),
- set_pattern_trace(false, {'_','_','_'}),
+ ok = file:close(Fd),
+ ok = set_pattern_trace(false, ?default_pattern),
ok.
%% -------------------------------------------------------------------- %%
@@ -330,7 +353,19 @@ spin_profile(M, F, A) ->
end.
execute_profiling(Pid) ->
- Pid ! {self(), execute}.
+ Pid ! {self(), execute},
+ ok.
+
+
+get_trace_options([]) ->
+ [call];
+get_trace_options([{set_on_spawn, true}|Opts]) ->
+ [set_on_spawn | get_trace_options(Opts)];
+get_trace_options([set_on_spawn|Opts]) ->
+ [set_on_spawn | get_trace_options(Opts)];
+get_trace_options([_|Opts]) ->
+ get_trace_options(Opts).
+
set_pattern_trace(Flag, Pattern) ->
erlang:system_flag(multi_scheduling, block),
@@ -339,10 +374,6 @@ set_pattern_trace(Flag, Pattern) ->
erlang:system_flag(multi_scheduling, unblock),
ok.
-set_process_trace(Flag, Pids) ->
- % do we need procs for meta info?
- % could be useful
- set_process_trace(Flag, Pids, [call, set_on_spawn]).
set_process_trace(_, [], _) -> true;
set_process_trace(Flag, [Pid|Pids], Options) when is_pid(Pid) ->
try
diff --git a/lib/tools/test/eprof_SUITE.erl b/lib/tools/test/eprof_SUITE.erl
index 3283fa571f..148622cf07 100644
--- a/lib/tools/test/eprof_SUITE.erl
+++ b/lib/tools/test/eprof_SUITE.erl
@@ -21,12 +21,14 @@
-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,tiny/1,eed/1,basic/1]).
+ init_per_group/2,end_per_group/2]).
+
+-export([tiny/1,eed/1,basic/1,basic_option/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [basic, tiny, eed].
+ [basic, basic_option, tiny, eed].
groups() ->
[].
@@ -49,140 +51,185 @@ basic(Config) when is_list(Config) ->
%% load eprof_test and change directory
- ?line {ok, OldCurDir} = file:get_cwd(),
+ {ok, OldCurDir} = file:get_cwd(),
Datadir = ?config(data_dir, Config),
Privdir = ?config(priv_dir, Config),
- ?line {ok,eprof_test} = compile:file(filename:join(Datadir, "eprof_test"),
+ {ok,eprof_test} = compile:file(filename:join(Datadir, "eprof_test"),
[trace,{outdir, Privdir}]),
- ?line ok = file:set_cwd(Privdir),
- ?line code:purge(eprof_test),
- ?line {module,eprof_test} = code:load_file(eprof_test),
+ ok = file:set_cwd(Privdir),
+ code:purge(eprof_test),
+ {module,eprof_test} = code:load_file(eprof_test),
%% rootset profiling
- ?line ensure_eprof_stopped(),
- ?line profiling = eprof:profile([self()]),
- ?line {error, already_profiling} = eprof:profile([self()]),
- ?line profiling_stopped = eprof:stop_profiling(),
- ?line profiling_already_stopped = eprof:stop_profiling(),
- ?line profiling = eprof:start_profiling([self(),self(),self()]),
- ?line profiling_stopped = eprof:stop_profiling(),
+ ensure_eprof_stopped(),
+ profiling = eprof:profile([self()]),
+ {error, already_profiling} = eprof:profile([self()]),
+ profiling_stopped = eprof:stop_profiling(),
+ profiling_already_stopped = eprof:stop_profiling(),
+ profiling = eprof:start_profiling([self(),self(),self()]),
+ profiling_stopped = eprof:stop_profiling(),
%% with patterns
- ?line profiling = eprof:start_profiling([self()], {?MODULE, '_', '_'}),
- ?line {error, already_profiling} = eprof:start_profiling([self()], {?MODULE, '_', '_'}),
- ?line profiling_stopped = eprof:stop_profiling(),
- ?line profiling = eprof:start_profiling([self()], {?MODULE, start_stop, '_'}),
- ?line profiling_stopped = eprof:stop_profiling(),
- ?line profiling = eprof:start_profiling([self()], {?MODULE, start_stop, 1}),
- ?line profiling_stopped = eprof:stop_profiling(),
+ profiling = eprof:start_profiling([self()], {?MODULE, '_', '_'}),
+ {error, already_profiling} = eprof:start_profiling([self()], {?MODULE, '_', '_'}),
+ profiling_stopped = eprof:stop_profiling(),
+ profiling = eprof:start_profiling([self()], {?MODULE, start_stop, '_'}),
+ profiling_stopped = eprof:stop_profiling(),
+ profiling = eprof:start_profiling([self()], {?MODULE, start_stop, 1}),
+ profiling_stopped = eprof:stop_profiling(),
%% with fun
- ?line {ok, _} = eprof:profile(fun() -> eprof_test:go(10) end),
- ?line profiling = eprof:profile([self()]),
- ?line {error, already_profiling} = eprof:profile(fun() -> eprof_test:go(10) end),
- ?line profiling_stopped = eprof:stop_profiling(),
- ?line {ok, _} = eprof:profile(fun() -> eprof_test:go(10) end),
- ?line {ok, _} = eprof:profile([], fun() -> eprof_test:go(10) end),
- ?line Pid = whereis(eprof),
- ?line {ok, _} = eprof:profile(erlang:processes() -- [Pid], fun() -> eprof_test:go(10) end),
- ?line {ok, _} = eprof:profile([], fun() -> eprof_test:go(10) end, {eprof_test, '_', '_'}),
- ?line {ok, _} = eprof:profile([], fun() -> eprof_test:go(10) end, {eprof_test, go, '_'}),
- ?line {ok, _} = eprof:profile([], fun() -> eprof_test:go(10) end, {eprof_test, go, 1}),
- ?line {ok, _} = eprof:profile([], fun() -> eprof_test:go(10) end, {eprof_test, dec, 1}),
+ {ok, _} = eprof:profile(fun() -> eprof_test:go(10) end),
+ profiling = eprof:profile([self()]),
+ {error, already_profiling} = eprof:profile(fun() -> eprof_test:go(10) end),
+ profiling_stopped = eprof:stop_profiling(),
+ {ok, _} = eprof:profile(fun() -> eprof_test:go(10) end),
+ {ok, _} = eprof:profile([], fun() -> eprof_test:go(10) end),
+ Pid = whereis(eprof),
+ {ok, _} = eprof:profile(erlang:processes() -- [Pid], fun() -> eprof_test:go(10) end),
+ {ok, _} = eprof:profile([], fun() -> eprof_test:go(10) end, {eprof_test, '_', '_'}),
+ {ok, _} = eprof:profile([], fun() -> eprof_test:go(10) end, {eprof_test, go, '_'}),
+ {ok, _} = eprof:profile([], fun() -> eprof_test:go(10) end, {eprof_test, go, 1}),
+ {ok, _} = eprof:profile([], fun() -> eprof_test:go(10) end, {eprof_test, dec, 1}),
%% error case
- ?line error = eprof:profile([Pid], fun() -> eprof_test:go(10) end),
- ?line Pid = whereis(eprof),
- ?line error = eprof:profile([Pid], fun() -> eprof_test:go(10) end),
- ?line A = spawn(fun() -> receive _ -> ok end end),
- ?line profiling = eprof:profile([A]),
- ?line true = exit(A, kill_it),
- ?line profiling_stopped = eprof:stop_profiling(),
- ?line {error,_} = eprof:profile(fun() -> a = b end),
+ error = eprof:profile([Pid], fun() -> eprof_test:go(10) end),
+ Pid = whereis(eprof),
+ error = eprof:profile([Pid], fun() -> eprof_test:go(10) end),
+ A = spawn(fun() -> receive _ -> ok end end),
+ profiling = eprof:profile([A]),
+ true = exit(A, kill_it),
+ profiling_stopped = eprof:stop_profiling(),
+ {error,_} = eprof:profile(fun() -> a = b end),
%% with mfa
- ?line {ok, _} = eprof:profile([], eprof_test, go, [10]),
- ?line {ok, _} = eprof:profile([], eprof_test, go, [10], {eprof_test, dec, 1}),
+ {ok, _} = eprof:profile([], eprof_test, go, [10]),
+ {ok, _} = eprof:profile([], eprof_test, go, [10], {eprof_test, dec, 1}),
%% dump
- ?line {ok, _} = eprof:profile([], fun() -> eprof_test:go(10) end, {eprof_test, '_', '_'}),
- ?line [{_, Mfas}] = eprof:dump(),
- ?line Dec_mfa = {eprof_test, dec, 1},
- ?line Go_mfa = {eprof_test, go, 1},
- ?line {value, {Go_mfa, { 1, _Time1}}} = lists:keysearch(Go_mfa, 1, Mfas),
- ?line {value, {Dec_mfa, {11, _Time2}}} = lists:keysearch(Dec_mfa, 1, Mfas),
+ {ok, _} = eprof:profile([], fun() -> eprof_test:go(10) end, {eprof_test, '_', '_'}),
+ [{_, Mfas}] = eprof:dump(),
+ Dec_mfa = {eprof_test, dec, 1},
+ Go_mfa = {eprof_test, go, 1},
+ {value, {Go_mfa, { 1, _Time1}}} = lists:keysearch(Go_mfa, 1, Mfas),
+ {value, {Dec_mfa, {11, _Time2}}} = lists:keysearch(Dec_mfa, 1, Mfas),
%% change current working directory
- ?line ok = file:set_cwd(OldCurDir),
- ?line stopped = eprof:stop(),
+ ok = file:set_cwd(OldCurDir),
+ stopped = eprof:stop(),
+ ok.
+
+basic_option(Config) when is_list(Config) ->
+ %% load eprof_test and change directory
+
+ {ok, OldCurDir} = file:get_cwd(),
+ Datadir = ?config(data_dir, Config),
+ Privdir = ?config(priv_dir, Config),
+ {ok,eprof_test} = compile:file(filename:join(Datadir, "eprof_test"),
+ [trace,{outdir, Privdir}]),
+ ok = file:set_cwd(Privdir),
+ code:purge(eprof_test),
+ {module,eprof_test} = code:load_file(eprof_test),
+
+ % vanilla
+ {ok, _} = eprof:profile(fun() -> eprof_test:do(10) end, [{set_on_spawn, true}]),
+
+ [{_, MfasDo1},{_, MfasLists1}] = eprof:dump(),
+ Mfas1 = MfasDo1 ++ MfasLists1,
+
+ {value, {_, {11, _}}} = lists:keysearch({eprof_test,dec,1}, 1, Mfas1),
+ {value, {_, { 1, _}}} = lists:keysearch({eprof_test, go,1}, 1, Mfas1),
+ {value, {_, { 9, _}}} = lists:keysearch({lists, split_2,5}, 1, Mfas1),
+ {value, {_, { 4, _}}} = lists:keysearch({lists, seq_loop,3}, 1, Mfas1),
+
+ {ok, _} = eprof:profile(fun() -> eprof_test:do(10) end, [set_on_spawn]),
+
+ [{_, MfasDo2},{_, MfasLists2}] = eprof:dump(),
+ Mfas2 = MfasDo2 ++ MfasLists2,
+ {value, {_, {11, _}}} = lists:keysearch({eprof_test,dec,1}, 1, Mfas2),
+ {value, {_, { 1, _}}} = lists:keysearch({eprof_test, go,1}, 1, Mfas2),
+ {value, {_, { 9, _}}} = lists:keysearch({lists, split_2,5}, 1, Mfas2),
+ {value, {_, { 4, _}}} = lists:keysearch({lists, seq_loop,3}, 1, Mfas2),
+
+ % disable trace set_on_spawn
+ {ok, _} = eprof:profile(fun() -> eprof_test:do(10) end, []),
+ [{_, Mfas3}] = eprof:dump(),
+ {value, {_, {11, _}}} = lists:keysearch({eprof_test,dec,1}, 1, Mfas3),
+ {value, {_, { 1, _}}} = lists:keysearch({eprof_test, go,1}, 1, Mfas3),
+ false = lists:keysearch({lists, split_2,5}, 1, Mfas3),
+ false = lists:keysearch({lists, seq_loop,3}, 1, Mfas3),
+
+ %% change current working directory
+ ok = file:set_cwd(OldCurDir),
+ stopped = eprof:stop(),
ok.
tiny(suite) -> [];
tiny(Config) when is_list(Config) ->
- ?line ensure_eprof_stopped(),
- ?line {ok, OldCurDir} = file:get_cwd(),
+ ensure_eprof_stopped(),
+ {ok, OldCurDir} = file:get_cwd(),
Datadir = ?config(data_dir, Config),
Privdir = ?config(priv_dir, Config),
- ?line TTrap=?t:timetrap(60*1000),
+ TTrap=?t:timetrap(60*1000),
% (Trace)Compile to priv_dir and make sure the correct version is loaded.
- ?line {ok,eprof_suite_test} = compile:file(filename:join(Datadir,
+ {ok,eprof_suite_test} = compile:file(filename:join(Datadir,
"eprof_suite_test"),
[trace,{outdir, Privdir}]),
- ?line ok = file:set_cwd(Privdir),
- ?line code:purge(eprof_suite_test),
- ?line {module,eprof_suite_test} = code:load_file(eprof_suite_test),
- ?line {ok,_Pid} = eprof:start(),
- ?line nothing_to_analyze = eprof:analyze(),
- ?line nothing_to_analyze = eprof:analyze(total),
- ?line eprof:profile([], eprof_suite_test, test, [Config]),
- ?line ok = eprof:analyze(),
- ?line ok = eprof:analyze(total),
- ?line ok = eprof:log("eprof_SUITE_logfile"),
- ?line stopped = eprof:stop(),
- ?line ?t:timetrap_cancel(TTrap),
- ?line ok = file:set_cwd(OldCurDir),
+ ok = file:set_cwd(Privdir),
+ code:purge(eprof_suite_test),
+ {module,eprof_suite_test} = code:load_file(eprof_suite_test),
+ {ok,_Pid} = eprof:start(),
+ nothing_to_analyze = eprof:analyze(),
+ nothing_to_analyze = eprof:analyze(total),
+ eprof:profile([], eprof_suite_test, test, [Config]),
+ ok = eprof:analyze(),
+ ok = eprof:analyze(total),
+ ok = eprof:log("eprof_SUITE_logfile"),
+ stopped = eprof:stop(),
+ ?t:timetrap_cancel(TTrap),
+ ok = file:set_cwd(OldCurDir),
ok.
eed(suite) -> [];
eed(Config) when is_list(Config) ->
- ?line ensure_eprof_stopped(),
- ?line Datadir = ?config(data_dir, Config),
- ?line Privdir = ?config(priv_dir, Config),
- ?line TTrap=?t:timetrap(5*60*1000),
+ ensure_eprof_stopped(),
+ Datadir = ?config(data_dir, Config),
+ Privdir = ?config(priv_dir, Config),
+ TTrap=?t:timetrap(5*60*1000),
%% (Trace)Compile to priv_dir and make sure the correct version is loaded.
- ?line code:purge(eed),
- ?line {ok,eed} = c:c(filename:join(Datadir, "eed"), [trace,{outdir,Privdir}]),
- ?line {ok,_Pid} = eprof:start(),
- ?line Script = filename:join(Datadir, "ed.script"),
- ?line ok = file:set_cwd(Datadir),
- ?line {T1,_} = statistics(runtime),
- ?line ok = eed:file(Script),
- ?line ok = eed:file(Script),
- ?line ok = eed:file(Script),
- ?line ok = eed:file(Script),
- ?line ok = eed:file(Script),
- ?line ok = eed:file(Script),
- ?line ok = eed:file(Script),
- ?line ok = eed:file(Script),
- ?line ok = eed:file(Script),
- ?line ok = eed:file(Script),
- ?line {T2,_} = statistics(runtime),
- ?line {ok,ok} = eprof:profile([], eed, file, [Script]),
- ?line {T3,_} = statistics(runtime),
- ?line profiling_already_stopped = eprof:stop_profiling(),
- ?line ok = eprof:analyze(),
- ?line ok = eprof:analyze(total),
- ?line ok = eprof:log("eprof_SUITE_logfile"),
- ?line stopped = eprof:stop(),
- ?line ?t:timetrap_cancel(TTrap),
+ code:purge(eed),
+ {ok,eed} = c:c(filename:join(Datadir, "eed"), [trace,{outdir,Privdir}]),
+ {ok,_Pid} = eprof:start(),
+ Script = filename:join(Datadir, "ed.script"),
+ ok = file:set_cwd(Datadir),
+ {T1,_} = statistics(runtime),
+ ok = eed:file(Script),
+ ok = eed:file(Script),
+ ok = eed:file(Script),
+ ok = eed:file(Script),
+ ok = eed:file(Script),
+ ok = eed:file(Script),
+ ok = eed:file(Script),
+ ok = eed:file(Script),
+ ok = eed:file(Script),
+ ok = eed:file(Script),
+ {T2,_} = statistics(runtime),
+ {ok,ok} = eprof:profile([], eed, file, [Script]),
+ {T3,_} = statistics(runtime),
+ profiling_already_stopped = eprof:stop_profiling(),
+ ok = eprof:analyze(),
+ ok = eprof:analyze(total),
+ ok = eprof:log("eprof_SUITE_logfile"),
+ stopped = eprof:stop(),
+ ?t:timetrap_cancel(TTrap),
try
S = lists:flatten(io_lib:format("~p times slower",
[10*(T3-T2)/(T2-T1)])),
@@ -198,5 +245,5 @@ ensure_eprof_stopped() ->
undefined ->
ok;
Pid ->
- ?line stopped=eprof:stop()
+ stopped=eprof:stop()
end.
diff --git a/lib/tools/test/eprof_SUITE_data/eprof_test.erl b/lib/tools/test/eprof_SUITE_data/eprof_test.erl
index 33c428e893..2d9e4c2945 100644
--- a/lib/tools/test/eprof_SUITE_data/eprof_test.erl
+++ b/lib/tools/test/eprof_SUITE_data/eprof_test.erl
@@ -1,5 +1,5 @@
-module(eprof_test).
--export([go/1]).
+-export([go/1, do/1]).
go(N) ->
0 = dec(N),
@@ -7,3 +7,16 @@ go(N) ->
dec(0) -> 0;
dec(N) -> dec(N - 1).
+
+
+
+load(N, Pid) ->
+ _ = lists:sort(lists:reverse(lists:seq(1, N))),
+ Pid ! {self(), ok}.
+
+
+do(N) ->
+ Me = self(),
+ Pid = spawn_link(fun() -> load(N, Me) end),
+ ok = go(N),
+ receive {Pid, ok} -> ok end.
diff --git a/system/doc/reference_manual/introduction.xml b/system/doc/reference_manual/introduction.xml
index 7737c34469..678b1964a6 100644
--- a/system/doc/reference_manual/introduction.xml
+++ b/system/doc/reference_manual/introduction.xml
@@ -75,7 +75,7 @@
<title>Reserved Words</title>
<p>The following are reserved words in Erlang:</p>
<p>after and andalso band begin bnot bor bsl bsr bxor case catch
- cond div end fun if let not of or orelse query receive rem try
+ cond div end fun if let not of or orelse receive rem try
when xor</p>
</section>